mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-20 08:01:38 +02:00
Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
c6c5f4669c | ||
|
397b9c4505 |
154
bsnes.cfg
154
bsnes.cfg
@@ -1,57 +1,135 @@
|
||||
#[bsnes v0.009 configuration file]
|
||||
# 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
|
||||
|
||||
#[apu enable]
|
||||
apu.enabled = 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
|
||||
|
||||
#[video mode]
|
||||
# 0: 256x224w
|
||||
# 1: 512x448w
|
||||
# 2: 960x720w
|
||||
# 3: 640x480f
|
||||
# 4: 1024x768f
|
||||
# Mutes SNES audio output when enabled
|
||||
# (default = true)
|
||||
snes.mute = true
|
||||
|
||||
# Video mode
|
||||
# 0 = 256x224w
|
||||
# 1 = 512x448w
|
||||
# 2 = 960x720w
|
||||
# 3 = 640x480f
|
||||
# 4 = 1024x768f
|
||||
# (default = 1)
|
||||
video.mode = 1
|
||||
|
||||
#[video memory type]
|
||||
# true: video ram (VRAM)
|
||||
# false: system ram (SRAM)
|
||||
#
|
||||
# VRAM results in the image being stretched in hardware,
|
||||
# which is generally much faster, and automatically adds
|
||||
# bilinear filtering (if the card supports it).
|
||||
#
|
||||
# However, some video cards end up taking a major speed
|
||||
# loss when this option is enabled. It is also the only
|
||||
# way to guarantee that the output image will not be
|
||||
# filtered.
|
||||
# Use Video RAM instead of System RAM
|
||||
# (default = true)
|
||||
video.use_vram = true
|
||||
|
||||
#[color curve]
|
||||
# gives a more NTSC TV-style feel to the color palette
|
||||
# by darkening the image contrast.
|
||||
video.color_curve = enabled
|
||||
|
||||
#[show fps]
|
||||
# true: show fps in titlebar
|
||||
# false: do not show fps in titlebar
|
||||
gui.show_fps = true
|
||||
|
||||
#[wait for vertical retrace]
|
||||
# Wait for vertical retrace when updating screen
|
||||
# (default = false)
|
||||
video.vblank = false
|
||||
|
||||
#[joypad 1 configuration]
|
||||
# Key numbers are standard windows VK_* keys.
|
||||
# Unfortunately, I don't have a table of common
|
||||
# key mappings to list here... use GUI joypad
|
||||
# configuration utility to edit these.
|
||||
# Show framerate in window title
|
||||
# (default = true)
|
||||
gui.show_fps = true
|
||||
|
||||
# Joypad1 up
|
||||
# (default = 0x26)
|
||||
input.joypad1.up = 0x26
|
||||
|
||||
# Joypad1 down
|
||||
# (default = 0x28)
|
||||
input.joypad1.down = 0x28
|
||||
|
||||
# Joypad1 left
|
||||
# (default = 0x25)
|
||||
input.joypad1.left = 0x25
|
||||
|
||||
# Joypad1 right
|
||||
# (default = 0x27)
|
||||
input.joypad1.right = 0x27
|
||||
|
||||
# Joypad1 A
|
||||
# (default = 0x58)
|
||||
input.joypad1.a = 0x58
|
||||
|
||||
# Joypad1 B
|
||||
# (default = 0x5a)
|
||||
input.joypad1.b = 0x5a
|
||||
|
||||
# Joypad1 X
|
||||
# (default = 0x53)
|
||||
input.joypad1.x = 0x53
|
||||
|
||||
# Joypad1 Y
|
||||
# (default = 0x41)
|
||||
input.joypad1.y = 0x41
|
||||
|
||||
# Joypad1 L
|
||||
# (default = 0x44)
|
||||
input.joypad1.l = 0x44
|
||||
|
||||
# Joypad1 R
|
||||
# (default = 0x43)
|
||||
input.joypad1.r = 0x43
|
||||
|
||||
# Joypad1 select
|
||||
# (default = 0x10)
|
||||
input.joypad1.select = 0x10
|
||||
input.joypad1.start = 0x0d
|
||||
|
||||
# Joypad1 start
|
||||
# (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
|
||||
|
||||
|
@@ -17,5 +17,10 @@ emulators.
|
||||
The Simple DirectMedia Layer library source code is available from:
|
||||
http://www.libsdl.org/
|
||||
|
||||
This library is distributed under the terms of the GNU LGPL license:
|
||||
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.
|
||||
|
@@ -1,2 +1,3 @@
|
||||
#include "../base.h"
|
||||
#include "iplrom.h"
|
||||
#include "dapu.cpp"
|
||||
|
@@ -1,10 +1,9 @@
|
||||
#define _APU_IPLROM
|
||||
#include "iplrom.h"
|
||||
#include "apuregs.h"
|
||||
|
||||
class APU {
|
||||
public:
|
||||
APURegs regs;
|
||||
static const uint8 iplrom[64];
|
||||
enum {
|
||||
FLAG_N = 0x80, FLAG_V = 0x40,
|
||||
FLAG_P = 0x20, FLAG_B = 0x10,
|
||||
@@ -18,6 +17,7 @@ APURegs regs;
|
||||
virtual uint8 port_read (uint8 port) = 0;
|
||||
virtual void port_write(uint8 port, uint8 value) = 0;
|
||||
|
||||
virtual uint8 *get_spcram_handle() = 0;
|
||||
virtual void run() = 0;
|
||||
virtual uint32 cycles_executed() = 0;
|
||||
virtual void power() = 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;
|
||||
};
|
||||
};
|
||||
|
||||
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;
|
||||
|
@@ -24,7 +24,7 @@ uint8 r;
|
||||
break;
|
||||
case 0xf3: //DSPDATA
|
||||
//0x80-0xff is a read-only mirror of 0x00-0x7f
|
||||
r = dsp_regs[status.dsp_addr & 0x7f];
|
||||
r = dsp->read(status.dsp_addr & 0x7f);
|
||||
break;
|
||||
case 0xf4: //CPUIO0
|
||||
case 0xf5: //CPUIO1
|
||||
@@ -111,7 +111,7 @@ void bAPU::spcram_write(uint16 addr, uint8 value) {
|
||||
case 0xf3: //DSPDATA
|
||||
//0x80-0xff is a read-only mirror of 0x00-0x7f
|
||||
if(status.dsp_addr < 0x80) {
|
||||
dsp_regs[status.dsp_addr & 0x7f] = value;
|
||||
dsp->write(status.dsp_addr & 0x7f, value);
|
||||
}
|
||||
break;
|
||||
case 0xf4: //CPUIO0
|
||||
@@ -209,6 +209,14 @@ void bAPU::stack_write(uint8 value) {
|
||||
regs.sp--;
|
||||
}
|
||||
|
||||
uint8 *bAPU::get_spcram_handle() {
|
||||
if(!spcram) {
|
||||
alert("bAPU::get_spcram_handle() -- spcram uninitialized");
|
||||
}
|
||||
|
||||
return spcram;
|
||||
}
|
||||
|
||||
void bAPU::run() {
|
||||
exec_cycle();
|
||||
}
|
||||
@@ -247,15 +255,12 @@ void bAPU::reset() {
|
||||
t0.stage3_ticks = 0;
|
||||
t1.stage3_ticks = 0;
|
||||
t2.stage3_ticks = 0;
|
||||
|
||||
memset(dsp_regs, 0, 128);
|
||||
}
|
||||
|
||||
bAPU::bAPU() {
|
||||
init_op_table();
|
||||
|
||||
spcram = (uint8*)malloc(65536);
|
||||
memcpy(iplrom, spc700_iplrom, 64);
|
||||
|
||||
t0.cycle_frequency = 128; //1.024mhz / 8khz = 128
|
||||
t1.cycle_frequency = 128; //1.024mhz / 8khz = 128
|
||||
|
@@ -29,12 +29,13 @@ struct {
|
||||
|
||||
bAPUTimer t0, t1, t2;
|
||||
|
||||
uint8 *spcram, iplrom[64], dsp_regs[128];
|
||||
uint8 *spcram;
|
||||
inline uint8 spcram_read (uint16 addr);
|
||||
inline void spcram_write(uint16 addr, uint8 value);
|
||||
inline uint8 port_read (uint8 port);
|
||||
inline void port_write(uint8 port, uint8 value);
|
||||
|
||||
inline uint8 *get_spcram_handle();
|
||||
inline void run();
|
||||
inline uint32 cycles_executed();
|
||||
inline void power();
|
||||
|
@@ -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;
|
||||
|
Binary file not shown.
@@ -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();
|
||||
|
@@ -1,4 +1,7 @@
|
||||
class bAPUSkip : public APU {
|
||||
private:
|
||||
uint8 spcram[65536];
|
||||
|
||||
public:
|
||||
|
||||
struct _apu_port {
|
||||
@@ -26,6 +29,7 @@ enum {
|
||||
uint8 port_read (uint8 port);
|
||||
void port_write (uint8 port, uint8 value);
|
||||
|
||||
uint8 *get_spcram_handle() { return spcram; }
|
||||
void run();
|
||||
uint32 cycles_executed() { return 12 * 24; }
|
||||
void power();
|
||||
|
@@ -3,12 +3,8 @@
|
||||
//allow writing to the IPLROM, all writes are
|
||||
//instead mapped to the extended SPC700 RAM region,
|
||||
//accessible when $f1 bit 7 is clear.
|
||||
//If you use this buffer directly, make sure not
|
||||
//to write to it, as this will break other APU
|
||||
//implementations that attempt to use this buffer.
|
||||
|
||||
#ifdef _APU_IPLROM
|
||||
const uint8 spc700_iplrom[64] = {
|
||||
const uint8 APU::iplrom[64] = {
|
||||
/*ffc0*/ 0xcd, 0xef, //mov x,#$ef
|
||||
/*ffc2*/ 0xbd, //mov sp,x
|
||||
/*ffc3*/ 0xe8, 0x00, //mov a,#$00
|
||||
@@ -43,6 +39,3 @@ const uint8 spc700_iplrom[64] = {
|
||||
/*fffb*/ 0x1f, 0x00, 0x00, //jmp ($0000+x)
|
||||
/*fffe*/ 0xc0, 0xff //---reset vector location ($ffc0)
|
||||
};
|
||||
#else
|
||||
extern const uint8 spc700_iplrom[64];
|
||||
#endif
|
||||
|
27
src/base.h
27
src/base.h
@@ -1,5 +1,26 @@
|
||||
//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_
|
||||
@@ -11,12 +32,6 @@
|
||||
#error "unknown architecture"
|
||||
#endif
|
||||
|
||||
//structs
|
||||
typedef struct {
|
||||
uint8 *data;
|
||||
uint32 size;
|
||||
}lfile;
|
||||
|
||||
//platform-specific global functions
|
||||
void *memalloc(uint32 size, char *name = 0, ...);
|
||||
void memfree(void *mem, char *name = 0, ...);
|
||||
|
@@ -1,6 +1,15 @@
|
||||
#include "../../base.h"
|
||||
#include "sdd1emu.cpp"
|
||||
|
||||
void SDD1::init() {
|
||||
}
|
||||
|
||||
void SDD1::enable() {
|
||||
for(int i=0x4800;i<=0x4807;i++) {
|
||||
mem_bus->set_mmio_mapper(i, mmio);
|
||||
}
|
||||
}
|
||||
|
||||
void SDD1::power() {
|
||||
reset();
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@ struct {
|
||||
bool dma_active;
|
||||
}sdd1;
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
uint32 offset(uint32 addr);
|
||||
|
@@ -74,6 +74,14 @@ tm *t;
|
||||
srtc.data[12] = t->tm_wday;
|
||||
}
|
||||
|
||||
void SRTC::init() {
|
||||
}
|
||||
|
||||
void SRTC::enable() {
|
||||
mem_bus->set_mmio_mapper(0x2800, mmio);
|
||||
mem_bus->set_mmio_mapper(0x2801, mmio);
|
||||
}
|
||||
|
||||
void SRTC::power() {
|
||||
memset(&srtc, 0, sizeof(srtc));
|
||||
reset();
|
||||
|
@@ -41,11 +41,13 @@ Index Description Range
|
||||
12 Day of week 0-6 (0=Sunday, ...)
|
||||
******************************/
|
||||
struct {
|
||||
int8 index;
|
||||
uint8 mode;
|
||||
uint8 data[MAX_SRTC_INDEX + 1];
|
||||
}srtc;
|
||||
int8 index;
|
||||
uint8 mode;
|
||||
uint8 data[MAX_SRTC_INDEX + 1];
|
||||
} srtc;
|
||||
void set_time();
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
void write(uint8 data);
|
||||
|
28
src/config/config.cpp
Normal file
28
src/config/config.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
Config config_file;
|
||||
|
||||
namespace config {
|
||||
|
||||
SNES::VideoColorAdjust SNES::video_color_curve(&config_file, "snes.video_color_curve",
|
||||
"Applies contrast adjust filter to video output when enabled\n"
|
||||
"Works by lowering the brightness of darker colors,\n"
|
||||
"while leaving brighter colors alone; thus reducing saturation",
|
||||
true, Setting::TRUE_FALSE);
|
||||
|
||||
SNES::VideoColorAdjust SNES::video_color_adjust_mode(&config_file, "snes.video_color_adjust_mode",
|
||||
"Selects color adjustment filter for video output\n"
|
||||
" 0 = Normal (no filter, rgb555)\n"
|
||||
" 1 = Grayscale mode (l5)\n"
|
||||
" 2 = VGA mode (rgb332)\n"
|
||||
" 3 = Genesis mode (rgb333)",
|
||||
0, Setting::DEC);
|
||||
|
||||
void SNES::VideoColorAdjust::set(uint32 _data) {
|
||||
data = _data;
|
||||
::snes->update_color_lookup_table();
|
||||
}
|
||||
|
||||
Setting SNES::mute(&config_file, "snes.mute",
|
||||
"Mutes SNES audio output when enabled",
|
||||
true, Setting::TRUE_FALSE);
|
||||
|
||||
};
|
15
src/config/config.h
Normal file
15
src/config/config.h
Normal file
@@ -0,0 +1,15 @@
|
||||
extern Config config_file;
|
||||
|
||||
namespace config {
|
||||
|
||||
extern struct SNES {
|
||||
static class VideoColorAdjust : public Setting {
|
||||
public:
|
||||
void set(uint32 _data);
|
||||
SettingOperators(VideoColorAdjust);
|
||||
} video_color_curve, video_color_adjust_mode;
|
||||
|
||||
static Setting mute;
|
||||
} snes;
|
||||
|
||||
};
|
@@ -13,190 +13,77 @@
|
||||
|
||||
#include "bcpu_timing.cpp"
|
||||
|
||||
uint8 bCPU::pio_status() {
|
||||
return status.pio;
|
||||
}
|
||||
#include "bcpu_int.cpp"
|
||||
|
||||
/***********
|
||||
*** IRQ ***
|
||||
***********
|
||||
cycles:
|
||||
[1] pbr,pc ; io/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
|
||||
*/
|
||||
void bCPU::irq(uint16 addr) {
|
||||
if(status.cpu_state == CPUSTATE_WAI) {
|
||||
status.cpu_state = CPUSTATE_RUN;
|
||||
regs.pc.w++;
|
||||
}
|
||||
|
||||
//GTE 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);
|
||||
}
|
||||
|
||||
//vcounter range verified on real hardware,
|
||||
//HDMA runs on the very first scanline of vblank
|
||||
bool bCPU::hdma_test() {
|
||||
if(status.hdma_triggered == false) {
|
||||
if(vcounter() <= (overscan()?239:224) && hcounter() >= 278) {
|
||||
status.hdma_triggered = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//NMI range: V==225/240,H>=12 ; V>225/240
|
||||
bool bCPU::nmi_test() {
|
||||
if(status.nmi_exec == true)return false;
|
||||
|
||||
//[status.cycle_count index]
|
||||
// 6->12
|
||||
// 8->14
|
||||
int hc = status.cycle_count + 6;
|
||||
if(vcounter() == ((overscan()?239:224) + 1) && hcycles() < hc) {
|
||||
//dprintf("* miss at %3d,%4d,%3x : %d x=%0.4x", vcounter(), hcycles(), hcounter(), status.cycle_count, regs.x.w);
|
||||
}
|
||||
|
||||
if(
|
||||
(vcounter() == ((overscan()?239:224) + 1) && hcycles() >= hc) ||
|
||||
(vcounter() > ((overscan()?239:224) + 1))
|
||||
) {
|
||||
//dprintf("* %3d,%4d,%3x : %d x=%0.4x", vcounter(), hcycles(), hcounter(), status.cycle_count, regs.x.w);
|
||||
status.nmi_exec = true;
|
||||
return status.nmi_enabled;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bCPU::irq_test() {
|
||||
int vpos, hpos;
|
||||
if(regs.p.i)return false; //no interrupt can occur with I flag set
|
||||
if(status.irq_read == true)return false; //same as above
|
||||
if(status.virq_enabled == false && status.hirq_enabled == false)return false;
|
||||
|
||||
//if irq_exec is true, then an IRQ occurred already.
|
||||
//IRQs will continue to fire until $4211 is read from, or
|
||||
//$4200 is written to, where irq_exec is set back to false.
|
||||
if(status.irq_exec == true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//calculate V/H positions required for IRQ to trigger
|
||||
vpos = status.virq_pos;
|
||||
hpos = (status.hirq_enabled) ? status.hirq_pos : 0;
|
||||
|
||||
//positions that can never be latched
|
||||
//region_scanlines() = 262/NTSC, 312/PAL
|
||||
//PAL results are unverified on hardware
|
||||
if(vpos == 240 && hpos == 339 && interlace() == false && interlace_field() == 1)return false;
|
||||
if(vpos == (region_scanlines() - 1) && hpos == 339 && interlace() == false)return false;
|
||||
if(vpos == region_scanlines() && interlace() == false)return false;
|
||||
if(vpos == region_scanlines() && hpos == 339)return false;
|
||||
if(vpos > region_scanlines())return false;
|
||||
if(hpos > 339)return false;
|
||||
|
||||
if(hpos == 0) {
|
||||
hpos = status.cycle_count + 14;
|
||||
} else {
|
||||
hpos <<= 2;
|
||||
hpos += status.cycle_count + 18;
|
||||
//it should be OK to use the current line cycles/frame lines,
|
||||
//as the IRQ will only trigger on the correct scanline anyway...
|
||||
if(hpos >= time.line_cycles) {
|
||||
hpos -= time.line_cycles;
|
||||
vpos++;
|
||||
if(vpos >= time.frame_lines) {
|
||||
vpos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(status.virq_enabled == true && vcounter() != vpos)return false;
|
||||
|
||||
if(hcycles() >= hpos) {
|
||||
status.irq_exec = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
uint8 bCPU::pio_status() { return status.pio; }
|
||||
|
||||
void bCPU::run() {
|
||||
switch(status.cpu_state) {
|
||||
case CPUSTATE_DMA:
|
||||
dma_run();
|
||||
break;
|
||||
case CPUSTATE_RUN:
|
||||
case CPUSTATE_WAI:
|
||||
if(status.cycle_pos == 0) {
|
||||
//interrupts only trigger on opcode edges
|
||||
if(nmi_test() == true) {
|
||||
irq(0xffea);
|
||||
break;
|
||||
}
|
||||
if(irq_test() == true) {
|
||||
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;
|
||||
}
|
||||
|
||||
if(status.virq_enabled == false) {
|
||||
status.irq_read = false;
|
||||
status.joypad2_read_pos = 16;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::frame() {
|
||||
hdma_initialize();
|
||||
time.nmi_read = 1;
|
||||
time.nmi_line = 1;
|
||||
time.nmi_transition = 0;
|
||||
|
||||
status.nmi_read = false;
|
||||
status.nmi_exec = false;
|
||||
|
||||
status.irq_read = false;
|
||||
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() {
|
||||
@@ -225,27 +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;
|
||||
|
||||
status.nmi_read = false;
|
||||
status.nmi_exec = false;
|
||||
|
||||
status.irq_read = false;
|
||||
status.irq_exec = 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) {
|
||||
@@ -258,43 +145,49 @@ void bCPU::port_write(uint8 port, uint8 value) {
|
||||
|
||||
void bCPU::cpu_c2() {
|
||||
if(regs.d.l != 0x00) {
|
||||
status.cycle_count = 6;
|
||||
add_cycles(6);
|
||||
cpu_io();
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::cpu_c4(uint16 x, uint16 y) {
|
||||
if(!regs.p.x && (x & 0xff00) != (y & 0xff00)) {
|
||||
status.cycle_count = 6;
|
||||
add_cycles(6);
|
||||
cpu_io();
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::cpu_c6(uint16 addr) {
|
||||
if(regs.e && (regs.pc.w & 0xff00) != (addr & 0xff00)) {
|
||||
status.cycle_count = 6;
|
||||
add_cycles(6);
|
||||
cpu_io();
|
||||
}
|
||||
}
|
||||
|
||||
/* The next 3 functions control bus timing for the CPU.
|
||||
* 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.d0 FastROM enable bit.
|
||||
*/
|
||||
|
||||
void bCPU::cpu_io() {
|
||||
status.cycle_count = 6;
|
||||
pre_exec_cycle();
|
||||
add_cycles(6);
|
||||
}
|
||||
|
||||
uint8 bCPU::mem_read(uint32 addr) {
|
||||
status.cycle_count = mem_bus->speed(addr);
|
||||
add_cycles(2);
|
||||
pre_exec_cycle();
|
||||
add_cycles(status.cycle_count - 4);
|
||||
regs.mdr = mem_bus->read(addr);
|
||||
add_cycles(status.cycle_count - 2);
|
||||
add_cycles(4);
|
||||
return regs.mdr;
|
||||
}
|
||||
|
||||
void bCPU::mem_write(uint32 addr, uint8 value) {
|
||||
status.cycle_count = mem_bus->speed(addr);
|
||||
add_cycles(6);
|
||||
pre_exec_cycle();
|
||||
add_cycles(status.cycle_count);
|
||||
mem_bus->write(addr, value);
|
||||
add_cycles(status.cycle_count - 6);
|
||||
}
|
||||
|
||||
uint32 bCPU::op_addr(uint8 mode, uint32 addr) {
|
||||
@@ -306,12 +199,11 @@ uint32 bCPU::op_addr(uint8 mode, uint32 addr) {
|
||||
addr &= 0xffffff;
|
||||
break;
|
||||
case OPMODE_DBR:
|
||||
addr &= 0xffffff;
|
||||
addr = (regs.db << 16) + addr;
|
||||
addr = ((regs.db << 16) + addr) & 0xffffff;
|
||||
break;
|
||||
case OPMODE_PBR:
|
||||
addr &= 0xffff;
|
||||
addr = (regs.pc.b << 16) | addr;
|
||||
addr = (regs.pc.b << 16) + addr;
|
||||
break;
|
||||
case OPMODE_DP:
|
||||
addr &= 0xffff;
|
||||
|
@@ -10,8 +10,7 @@ bCPU *cpu;
|
||||
|
||||
class bCPU : public CPU {
|
||||
private:
|
||||
typedef void (bCPU::*op)();
|
||||
op optbl[256];
|
||||
void (bCPU::*optbl[256])();
|
||||
|
||||
enum { NTSC = 0, PAL = 1 };
|
||||
uint8 region;
|
||||
@@ -33,49 +32,49 @@ 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;
|
||||
|
||||
uint8 dma_state;
|
||||
uint32 dma_cycle_count;
|
||||
bool hdma_triggered;
|
||||
uint8 dma_state, hdma_state;
|
||||
uint32 dma_cycle_count, hdma_cycle_count;
|
||||
|
||||
//used by $4210 read bit 7
|
||||
bool nmi_read;
|
||||
//used by NMI test, set when NMI executed this frame
|
||||
bool nmi_exec;
|
||||
|
||||
//IRQ is level-sensitive, so $4211 must be read to
|
||||
//prevent multiple interrupts from occurring
|
||||
bool irq_read;
|
||||
//this is used to return $4211 bit 7
|
||||
bool irq_exec;
|
||||
//$4207-$420a
|
||||
uint16 virq_trigger, hirq_trigger;
|
||||
|
||||
//$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;
|
||||
@@ -98,7 +97,13 @@ struct {
|
||||
//$4214-$4216
|
||||
uint16 r4214;
|
||||
uint16 r4216;
|
||||
}status;
|
||||
} status;
|
||||
|
||||
//$43x0.d7
|
||||
enum {
|
||||
DMA_CPUTOMMIO = 0,
|
||||
DMA_MMIOTOCPU = 1
|
||||
};
|
||||
|
||||
struct {
|
||||
uint32 read_index; //set to 0 at beginning of DMA/HDMA
|
||||
@@ -121,7 +126,10 @@ struct {
|
||||
//$43x4
|
||||
uint8 srcbank;
|
||||
//$43x5-$43x6
|
||||
uint16 xfersize;
|
||||
union {
|
||||
uint16 xfersize;
|
||||
uint16 hdma_iaddr;
|
||||
};
|
||||
//$43x7
|
||||
uint8 hdma_ibank;
|
||||
//$43x8-$43x9
|
||||
@@ -132,16 +140,13 @@ struct {
|
||||
uint8 hdma_unknown;
|
||||
|
||||
//hdma-specific
|
||||
bool hdma_first_line;
|
||||
bool hdma_repeat;
|
||||
uint16 hdma_iaddr;
|
||||
bool hdma_active;
|
||||
}channel[8];
|
||||
bool hdma_do_transfer;
|
||||
} channel[8];
|
||||
|
||||
inline bool hdma_test();
|
||||
inline bool nmi_test();
|
||||
inline bool irq_test();
|
||||
inline void irq(uint16 addr);
|
||||
|
||||
inline uint8 pio_status();
|
||||
inline void run();
|
||||
@@ -151,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
|
||||
@@ -179,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);
|
||||
@@ -196,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);
|
||||
@@ -224,8 +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 cycle_edge();
|
||||
inline void last_cycle();
|
||||
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 hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
|
||||
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,50 +1,157 @@
|
||||
inline void bCPU::cycle_edge() {
|
||||
int c, n, z;
|
||||
if(status.dma_state != DMASTATE_STOP) {
|
||||
void bCPU::last_cycle() {
|
||||
time.nmi_pending = nmi_test();
|
||||
time.irq_pending = irq_test();
|
||||
}
|
||||
|
||||
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) {
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_BEGIN);
|
||||
status.opcode = op_read();
|
||||
status.cycle_pos = 1;
|
||||
} else {
|
||||
(this->*optbl[status.opcode])();
|
||||
if(status.cycle_pos == 0) {
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_END);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
(this->*optbl[status.opcode])();
|
||||
if(status.cycle_pos == 0) {
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_END);
|
||||
}
|
||||
}
|
||||
|
||||
|
67
src/cpu/bcpu/bcpu_int.cpp
Normal file
67
src/cpu/bcpu/bcpu_int.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
[IRQ cycles]
|
||||
[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_run() {
|
||||
//WDC documentation is incorrect, first cycle
|
||||
//is a memory read fetch from PBR:PC
|
||||
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;
|
||||
|
||||
run_state.wai = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bCPU::irq_test() {
|
||||
if(time.irq_transition == 1)goto _true;
|
||||
|
||||
if(time.irq_read == 0) {
|
||||
if(time.irq_line == 1 && (irq_trigger_pos_match(0) || irq_trigger_pos_match(2))) {
|
||||
return false;
|
||||
}
|
||||
goto _true;
|
||||
}
|
||||
|
||||
if(time.irq_line == 0) {
|
||||
time.irq_line = 1;
|
||||
goto _true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
_true:
|
||||
time.irq_transition = 0;
|
||||
|
||||
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;
|
||||
@@ -42,18 +44,17 @@ uint8 r;
|
||||
}
|
||||
|
||||
//JOYSER0
|
||||
/*
|
||||
The joypad contains a small bit shifter that has 16 bits.
|
||||
Reading from 4016 reads one bit from this buffer, then moves
|
||||
the buffer left one, and adds a '1' to the rightmost bit.
|
||||
Writing a one to $4016 will fill the buffer with the current
|
||||
joypad button states, and lock the bit shifter at position
|
||||
zero. All reads will be the first buffer state, or 'B'.
|
||||
A zero must be written back to $4016 to unlock the buffer,
|
||||
so that reads will increment the bit shifting position.
|
||||
*/
|
||||
//7-2 = MDR
|
||||
//1-0 = Joypad serial data
|
||||
/* The joypad contains a small bit shifter that has 16 bits.
|
||||
* Reading from 4016 reads one bit from this buffer, then moves
|
||||
* the buffer left one, and adds a '1' to the rightmost bit.
|
||||
* Writing a one to $4016 will fill the buffer with the current
|
||||
* joypad button states, and lock the bit shifter at position
|
||||
* zero. All reads will be the first buffer state, or 'B'.
|
||||
* A zero must be written back to $4016 to unlock the buffer,
|
||||
* so that reads will increment the bit shifting position.
|
||||
*/
|
||||
uint8 bCPU::mmio_r4016() {
|
||||
uint8 r;
|
||||
r = regs.mdr & 0xfc;
|
||||
@@ -92,48 +93,45 @@ 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;
|
||||
}
|
||||
|
||||
//RDNMI
|
||||
/* $4210 bit 7 (NMI triggered bit) is set at:
|
||||
* V=225/240,HC>=2,
|
||||
* V>225
|
||||
* The bit is only set once per NMI trigger, so
|
||||
* subsequent reads return this bit as being clear.
|
||||
* There is but one exception: if the $4210 read
|
||||
* occurs at *exactly* V=225/240,HC==2, then $4210
|
||||
* bit 7 will be set, and the next read will also
|
||||
* have this bit set.
|
||||
*/
|
||||
//7 = NMI acknowledge
|
||||
//6-4 = MDR
|
||||
//3-0 = CPU (5a22) version
|
||||
uint8 bCPU::mmio_r4210() {
|
||||
uint8 r;
|
||||
uint16 v, h, hc, vs;
|
||||
r = regs.mdr & 0x70;
|
||||
uint8 r;
|
||||
r = regs.mdr & 0x70;
|
||||
r |= uint8(!time.nmi_read) << 7;
|
||||
|
||||
v = vcounter();
|
||||
h = hcounter();
|
||||
hc = hcycles();
|
||||
vs = (overscan()?239:224);
|
||||
|
||||
if(status.nmi_read == false) {
|
||||
if(
|
||||
(v == (vs + 1) && hc >= 2) ||
|
||||
(v > (vs + 1))
|
||||
) {
|
||||
r |= 0x80;
|
||||
|
||||
//test for special case where NMI read not raised
|
||||
if(v != (vs + 1) || hc != 2) {
|
||||
status.nmi_read = true;
|
||||
}
|
||||
}
|
||||
if(!nmi_trigger_pos_match(0) && !nmi_trigger_pos_match(2)) {
|
||||
time.nmi_read = 1;
|
||||
}
|
||||
|
||||
r |= 0x02; //cpu version number
|
||||
r |= (cpu_version & 0x0f);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -142,10 +140,15 @@ uint16 v, h, hc, vs;
|
||||
//6-0 = MDR
|
||||
uint8 bCPU::mmio_r4211() {
|
||||
uint8 r;
|
||||
r = regs.mdr & 0x7f;
|
||||
if(status.irq_exec == true)r |= 0x80;
|
||||
status.irq_exec = false;
|
||||
status.irq_read = true;
|
||||
r = regs.mdr & 0x7f;
|
||||
r |= uint8(!time.irq_read) << 7;
|
||||
|
||||
if(!irq_trigger_pos_match(0) && !irq_trigger_pos_match(2)) {
|
||||
time.irq_read = 1;
|
||||
time.irq_line = 1;
|
||||
time.irq_transition = 0;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -155,23 +158,20 @@ uint8 r;
|
||||
//5-1 = MDR
|
||||
//0 = joypad ready
|
||||
uint8 bCPU::mmio_r4212() {
|
||||
uint8 r;
|
||||
uint16 v, h, hc, vs;
|
||||
uint8 r;
|
||||
r = regs.mdr & 0x3e;
|
||||
|
||||
v = vcounter();
|
||||
h = hcounter();
|
||||
hc = hcycles();
|
||||
vs = (overscan()?239:224);
|
||||
uint16 vs = overscan() ? 240 : 225;
|
||||
|
||||
//auto joypad polling
|
||||
if(v >= (vs + 1) && v <= (vs + 3))r |= 0x01;
|
||||
if(time.v >= vs && time.v <= (vs + 2))r |= 0x01;
|
||||
|
||||
//hblank
|
||||
if(hc <= 2 || hc >= 1096)r |= 0x40;
|
||||
if(time.hc <= 2 || time.hc >= 1096)r |= 0x40;
|
||||
|
||||
//vblank
|
||||
if(v >= (vs + 1))r |= 0x80;
|
||||
if(time.v >= vs)r |= 0x80;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -230,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;
|
||||
@@ -291,9 +321,7 @@ uint8 bCPU::mmio_r43xb(uint8 i) {
|
||||
}
|
||||
|
||||
uint8 bCPUMMIO::read(uint32 addr) {
|
||||
uint8 i;
|
||||
//cpu->sync();
|
||||
|
||||
uint i;
|
||||
//APU
|
||||
if(addr >= 0x2140 && addr <= 0x217f) {
|
||||
return apu->port_read(addr & 3);
|
||||
@@ -336,7 +364,9 @@ uint8 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 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;
|
||||
@@ -369,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);
|
||||
@@ -383,14 +422,20 @@ void bCPU::mmio_w4200(uint8 value) {
|
||||
status.hirq_enabled = !!(value & 0x10);
|
||||
status.auto_joypad_poll = !!(value & 0x01);
|
||||
|
||||
if(status.nmi_enabled == false) {
|
||||
status.nmi_read = false;
|
||||
if(time.nmi_read == 0) {
|
||||
if(time.nmi_line == 1 && !status.nmi_enabled == 0) {
|
||||
time.nmi_transition = 1;
|
||||
}
|
||||
time.nmi_line = !status.nmi_enabled;
|
||||
}
|
||||
|
||||
status.irq_exec = false;
|
||||
if(status.virq_enabled == true || status.hirq_enabled == true) {
|
||||
status.irq_read = false;
|
||||
if(status.virq_enabled == false && status.hirq_enabled == false) {
|
||||
time.irq_line = 1;
|
||||
time.irq_read = 1;
|
||||
time.irq_transition = 0;
|
||||
}
|
||||
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//WRIO
|
||||
@@ -424,38 +469,39 @@ void bCPU::mmio_w4205(uint8 value) {
|
||||
//WRDIVB
|
||||
void bCPU::mmio_w4206(uint8 value) {
|
||||
status.div_b = value;
|
||||
status.r4214 = (status.div_b)?status.div_a / status.div_b : 0xffff;
|
||||
status.r4216 = (status.div_b)?status.div_a % status.div_b : status.div_a;
|
||||
status.r4214 = (status.div_b) ? status.div_a / status.div_b : 0xffff;
|
||||
status.r4216 = (status.div_b) ? status.div_a % status.div_b : status.div_a;
|
||||
}
|
||||
|
||||
//HTIMEL
|
||||
void bCPU::mmio_w4207(uint8 value) {
|
||||
status.hirq_pos = (status.hirq_pos & 0xff00) | value;
|
||||
status.irq_read = false;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//HTIMEH
|
||||
void bCPU::mmio_w4208(uint8 value) {
|
||||
status.hirq_pos = (status.hirq_pos & 0x00ff) | (value << 8);
|
||||
status.irq_read = false;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//VTIMEL
|
||||
void bCPU::mmio_w4209(uint8 value) {
|
||||
status.virq_pos = (status.virq_pos & 0xff00) | value;
|
||||
status.irq_read = false;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//VTIMEH
|
||||
void bCPU::mmio_w420a(uint8 value) {
|
||||
status.virq_pos = (status.virq_pos & 0x00ff) | (value << 8);
|
||||
status.irq_read = false;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//DMAEN
|
||||
void bCPU::mmio_w420b(uint8 value) {
|
||||
int len;
|
||||
if(value != 0x00) {
|
||||
run_state.dma = true;
|
||||
status.dma_state = DMASTATE_DMASYNC;
|
||||
}
|
||||
|
||||
@@ -479,7 +525,7 @@ void bCPU::mmio_w420c(uint8 value) {
|
||||
|
||||
//MEMSEL
|
||||
void bCPU::mmio_w420d(uint8 value) {
|
||||
mem_bus->fastROM = value & 1;
|
||||
mem_bus->set_speed(value & 1);
|
||||
}
|
||||
|
||||
//DMAPx
|
||||
@@ -549,8 +595,6 @@ void bCPU::mmio_w43xb(uint8 value, uint8 i) {
|
||||
|
||||
void bCPUMMIO::write(uint32 addr, uint8 value) {
|
||||
uint8 i;
|
||||
//cpu->sync();
|
||||
|
||||
//APU
|
||||
if(addr >= 0x2140 && addr <= 0x217f) {
|
||||
cpu->port_write(addr & 3, value);
|
||||
@@ -586,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
|
||||
|
@@ -186,7 +186,6 @@ void op_sta_idpy();
|
||||
void op_sta_ildpy();
|
||||
void op_sta_sr();
|
||||
void op_sta_isry();
|
||||
void op_bra();
|
||||
void op_bcc();
|
||||
void op_bcs();
|
||||
void op_bne();
|
||||
@@ -195,6 +194,7 @@ void op_bpl();
|
||||
void op_bmi();
|
||||
void op_bvc();
|
||||
void op_bvs();
|
||||
void op_bra();
|
||||
void op_brl();
|
||||
void op_jmp_addr();
|
||||
void op_jmp_long();
|
||||
|
@@ -1,6 +1,7 @@
|
||||
void bCPU::op_nop() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -10,6 +11,7 @@ void bCPU::op_nop() {
|
||||
void bCPU::op_wdm() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
op_read();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -22,6 +24,7 @@ void bCPU::op_xba() {
|
||||
cpu_io();
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.a.l ^= regs.a.h;
|
||||
regs.a.h ^= regs.a.l;
|
||||
@@ -54,6 +57,7 @@ void bCPU::op_mvn() {
|
||||
else { regs.x.w++; regs.y.w++; }
|
||||
break;
|
||||
case 6:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.a.w--)regs.pc.w -= 3;
|
||||
status.cycle_pos = 0;
|
||||
@@ -82,6 +86,7 @@ void bCPU::op_mvp() {
|
||||
else { regs.x.w--; regs.y.w--; }
|
||||
break;
|
||||
case 6:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.a.w--)regs.pc.w -= 3;
|
||||
status.cycle_pos = 0;
|
||||
@@ -111,6 +116,7 @@ void bCPU::op_brk() {
|
||||
rd.l = op_read(OPMODE_LONG, (regs.e)?0xfffe:0xffe6);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
rd.h = op_read(OPMODE_LONG, (regs.e)?0xffff:0xffe7);
|
||||
regs.pc.b = 0x00;
|
||||
regs.pc.w = rd.w;
|
||||
@@ -143,6 +149,7 @@ void bCPU::op_cop() {
|
||||
rd.l = op_read(OPMODE_LONG, (regs.e)?0xfff4:0xffe4);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
rd.h = op_read(OPMODE_LONG, (regs.e)?0xfff5:0xffe5);
|
||||
regs.pc.b = 0x00;
|
||||
regs.pc.w = rd.w;
|
||||
@@ -157,9 +164,10 @@ 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();
|
||||
cpu_io();
|
||||
regs.pc.w--;
|
||||
status.cycle_pos = 0;
|
||||
@@ -171,11 +179,15 @@ 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();
|
||||
regs.pc.w--;
|
||||
if(run_state.wai) {
|
||||
//this can be cleared within last_cycle()
|
||||
regs.pc.w--;
|
||||
}
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
@@ -184,6 +196,7 @@ void bCPU::op_wai() {
|
||||
void bCPU::op_xce() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
bool c = regs.p.c;
|
||||
regs.p.c = regs.e;
|
||||
@@ -202,6 +215,7 @@ void bCPU::op_xce() {
|
||||
void bCPU::op_clc() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.p.c = 0;
|
||||
status.cycle_pos = 0;
|
||||
@@ -212,6 +226,7 @@ void bCPU::op_clc() {
|
||||
void bCPU::op_cld() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.p.d = 0;
|
||||
status.cycle_pos = 0;
|
||||
@@ -222,6 +237,7 @@ void bCPU::op_cld() {
|
||||
void bCPU::op_cli() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.p.i = 0;
|
||||
status.cycle_pos = 0;
|
||||
@@ -232,6 +248,7 @@ void bCPU::op_cli() {
|
||||
void bCPU::op_clv() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.p.v = 0;
|
||||
status.cycle_pos = 0;
|
||||
@@ -242,6 +259,7 @@ void bCPU::op_clv() {
|
||||
void bCPU::op_sec() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.p.c = 1;
|
||||
status.cycle_pos = 0;
|
||||
@@ -252,6 +270,7 @@ void bCPU::op_sec() {
|
||||
void bCPU::op_sed() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.p.d = 1;
|
||||
status.cycle_pos = 0;
|
||||
@@ -262,6 +281,7 @@ void bCPU::op_sed() {
|
||||
void bCPU::op_sei() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.p.i = 1;
|
||||
status.cycle_pos = 0;
|
||||
@@ -275,6 +295,7 @@ void bCPU::op_rep() {
|
||||
rd.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.p &=~ rd.l;
|
||||
if(regs.e)regs.p |= 0x30;
|
||||
@@ -293,6 +314,7 @@ void bCPU::op_sep() {
|
||||
rd.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.p |= rd.l;
|
||||
if(regs.e)regs.p |= 0x30;
|
||||
@@ -308,6 +330,7 @@ void bCPU::op_sep() {
|
||||
void bCPU::op_tax() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.x.l = regs.a.l;
|
||||
@@ -326,6 +349,7 @@ void bCPU::op_tax() {
|
||||
void bCPU::op_tay() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.y.l = regs.a.l;
|
||||
@@ -344,6 +368,7 @@ void bCPU::op_tay() {
|
||||
void bCPU::op_txa() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.m) {
|
||||
regs.a.l = regs.x.l;
|
||||
@@ -362,6 +387,7 @@ void bCPU::op_txa() {
|
||||
void bCPU::op_txy() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.y.l = regs.x.l;
|
||||
@@ -380,6 +406,7 @@ void bCPU::op_txy() {
|
||||
void bCPU::op_tya() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.m) {
|
||||
regs.a.l = regs.y.l;
|
||||
@@ -398,6 +425,7 @@ void bCPU::op_tya() {
|
||||
void bCPU::op_tyx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.x.l = regs.y.l;
|
||||
@@ -416,6 +444,7 @@ void bCPU::op_tyx() {
|
||||
void bCPU::op_tcd() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.d.w = regs.a.w;
|
||||
regs.p.n = !!(regs.d.w & 0x8000);
|
||||
@@ -428,6 +457,7 @@ void bCPU::op_tcd() {
|
||||
void bCPU::op_tcs() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.s.w = regs.a.w;
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
@@ -439,6 +469,7 @@ void bCPU::op_tcs() {
|
||||
void bCPU::op_tdc() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.a.w = regs.d.w;
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
@@ -451,6 +482,7 @@ void bCPU::op_tdc() {
|
||||
void bCPU::op_tsc() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.a.w = regs.s.w;
|
||||
if(regs.e) {
|
||||
@@ -468,6 +500,7 @@ void bCPU::op_tsc() {
|
||||
void bCPU::op_tsx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.x.l = regs.s.l;
|
||||
@@ -486,6 +519,7 @@ void bCPU::op_tsx() {
|
||||
void bCPU::op_txs() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.e) {
|
||||
regs.s.l = regs.x.l;
|
||||
@@ -511,6 +545,7 @@ void bCPU::op_pha() {
|
||||
stack_write(regs.a.h);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
stack_write(regs.a.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -527,6 +562,7 @@ void bCPU::op_phx() {
|
||||
stack_write(regs.x.h);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
stack_write(regs.x.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -543,6 +579,7 @@ void bCPU::op_phy() {
|
||||
stack_write(regs.y.h);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
stack_write(regs.y.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -559,6 +596,7 @@ void bCPU::op_phd() {
|
||||
stack_write(regs. d.h);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
stack_write(regs. d.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -571,6 +609,7 @@ void bCPU::op_phb() {
|
||||
cpu_io();
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
stack_write(regs.db);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -583,6 +622,7 @@ void bCPU::op_phk() {
|
||||
cpu_io();
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
stack_write(regs.pc.b);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -595,6 +635,7 @@ void bCPU::op_php() {
|
||||
cpu_io();
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
stack_write(regs.p);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -610,6 +651,7 @@ void bCPU::op_pla() {
|
||||
cpu_io();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.m)last_cycle();
|
||||
regs.a.l = stack_read();
|
||||
if(regs.p.m) {
|
||||
regs.p.n = !!(regs.a.l & 0x80);
|
||||
@@ -618,6 +660,7 @@ void bCPU::op_pla() {
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
regs.a.h = stack_read();
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
@@ -635,6 +678,7 @@ void bCPU::op_plx() {
|
||||
cpu_io();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.x)last_cycle();
|
||||
regs.x.l = stack_read();
|
||||
if(regs.p.x) {
|
||||
regs.p.n = !!(regs.x.l & 0x80);
|
||||
@@ -643,6 +687,7 @@ void bCPU::op_plx() {
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
regs.x.h = stack_read();
|
||||
regs.p.n = !!(regs.x.w & 0x8000);
|
||||
regs.p.z = (regs.x.w == 0);
|
||||
@@ -660,6 +705,7 @@ void bCPU::op_ply() {
|
||||
cpu_io();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.x)last_cycle();
|
||||
regs.y.l = stack_read();
|
||||
if(regs.p.x) {
|
||||
regs.p.n = !!(regs.y.l & 0x80);
|
||||
@@ -668,6 +714,7 @@ void bCPU::op_ply() {
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
regs.y.h = stack_read();
|
||||
regs.p.n = !!(regs.y.w & 0x8000);
|
||||
regs.p.z = (regs.y.w == 0);
|
||||
@@ -685,6 +732,7 @@ void bCPU::op_pld() {
|
||||
cpu_io();
|
||||
break;
|
||||
case 3:
|
||||
if(0)last_cycle();
|
||||
regs. d.l = stack_read();
|
||||
if(0) {
|
||||
regs.p.n = !!(regs. d.l & 0x80);
|
||||
@@ -693,6 +741,7 @@ void bCPU::op_pld() {
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
regs. d.h = stack_read();
|
||||
regs.p.n = !!(regs. d.w & 0x8000);
|
||||
regs.p.z = (regs. d.w == 0);
|
||||
@@ -710,6 +759,7 @@ void bCPU::op_plb() {
|
||||
cpu_io();
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
regs.db = stack_read();
|
||||
regs.p.n = !!(regs.db & 0x80);
|
||||
regs.p.z = (regs.db == 0);
|
||||
@@ -727,6 +777,7 @@ void bCPU::op_plp() {
|
||||
cpu_io();
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
regs.p = stack_read();
|
||||
if(regs.e)regs.p |= 0x30;
|
||||
if(regs.p.x) {
|
||||
@@ -750,6 +801,7 @@ void bCPU::op_pea() {
|
||||
stack_write(aa.h);
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
stack_write(aa.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -774,6 +826,7 @@ void bCPU::op_pei() {
|
||||
stack_write(aa.h);
|
||||
break;
|
||||
case 6:
|
||||
last_cycle();
|
||||
stack_write(aa.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -796,6 +849,7 @@ void bCPU::op_per() {
|
||||
stack_write(rd.h);
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
stack_write(rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@@ -1,27 +1,7 @@
|
||||
void bCPU::op_bra() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
rd.l = op_read();
|
||||
if(1) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
status.cycle_pos = 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_bcc() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
if(!!regs.p.c)last_cycle();
|
||||
rd.l = op_read();
|
||||
if(!regs.p.c) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
@@ -34,6 +14,7 @@ void bCPU::op_bcc() {
|
||||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -43,6 +24,7 @@ void bCPU::op_bcc() {
|
||||
void bCPU::op_bcs() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
if(!regs.p.c)last_cycle();
|
||||
rd.l = op_read();
|
||||
if(regs.p.c) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
@@ -55,6 +37,7 @@ void bCPU::op_bcs() {
|
||||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -64,6 +47,7 @@ void bCPU::op_bcs() {
|
||||
void bCPU::op_bne() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
if(!!regs.p.z)last_cycle();
|
||||
rd.l = op_read();
|
||||
if(!regs.p.z) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
@@ -76,6 +60,7 @@ void bCPU::op_bne() {
|
||||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -85,6 +70,7 @@ void bCPU::op_bne() {
|
||||
void bCPU::op_beq() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
if(!regs.p.z)last_cycle();
|
||||
rd.l = op_read();
|
||||
if(regs.p.z) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
@@ -97,6 +83,7 @@ void bCPU::op_beq() {
|
||||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -106,6 +93,7 @@ void bCPU::op_beq() {
|
||||
void bCPU::op_bpl() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
if(!!regs.p.n)last_cycle();
|
||||
rd.l = op_read();
|
||||
if(!regs.p.n) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
@@ -118,6 +106,7 @@ void bCPU::op_bpl() {
|
||||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -127,6 +116,7 @@ void bCPU::op_bpl() {
|
||||
void bCPU::op_bmi() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
if(!regs.p.n)last_cycle();
|
||||
rd.l = op_read();
|
||||
if(regs.p.n) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
@@ -139,6 +129,7 @@ void bCPU::op_bmi() {
|
||||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -148,6 +139,7 @@ void bCPU::op_bmi() {
|
||||
void bCPU::op_bvc() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
if(!!regs.p.v)last_cycle();
|
||||
rd.l = op_read();
|
||||
if(!regs.p.v) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
@@ -160,6 +152,7 @@ void bCPU::op_bvc() {
|
||||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -169,6 +162,7 @@ void bCPU::op_bvc() {
|
||||
void bCPU::op_bvs() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
if(!regs.p.v)last_cycle();
|
||||
rd.l = op_read();
|
||||
if(regs.p.v) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
@@ -181,6 +175,25 @@ void bCPU::op_bvs() {
|
||||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_bra() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
rd.l = op_read();
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
break;
|
||||
case 2:
|
||||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -196,6 +209,7 @@ void bCPU::op_brl() {
|
||||
rd.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.pc.w = regs.pc.d + (int16)rd.w;
|
||||
status.cycle_pos = 0;
|
||||
@@ -209,6 +223,7 @@ void bCPU::op_jmp_addr() {
|
||||
rd.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
rd.h = op_read();
|
||||
regs.pc.w = rd.w;
|
||||
status.cycle_pos = 0;
|
||||
@@ -225,6 +240,7 @@ void bCPU::op_jmp_long() {
|
||||
rd.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
rd.b = op_read();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
status.cycle_pos = 0;
|
||||
@@ -244,6 +260,7 @@ void bCPU::op_jmp_iaddr() {
|
||||
rd.l = op_read(OPMODE_ADDR, aa.w);
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
status.cycle_pos = 0;
|
||||
@@ -266,6 +283,7 @@ void bCPU::op_jmp_iaddrx() {
|
||||
rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
status.cycle_pos = 0;
|
||||
@@ -288,6 +306,7 @@ void bCPU::op_jmp_iladdr() {
|
||||
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
rd.b = op_read(OPMODE_ADDR, aa.w + 2);
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
status.cycle_pos = 0;
|
||||
@@ -311,6 +330,7 @@ void bCPU::op_jsr_addr() {
|
||||
stack_write(regs.pc.h);
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
stack_write(regs.pc.l);
|
||||
regs.pc.w = aa.w;
|
||||
status.cycle_pos = 0;
|
||||
@@ -340,6 +360,7 @@ void bCPU::op_jsr_long() {
|
||||
stack_write(regs.pc.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
stack_write(regs.pc.l);
|
||||
regs.pc.d = aa.d & 0xffffff;
|
||||
status.cycle_pos = 0;
|
||||
@@ -368,6 +389,7 @@ void bCPU::op_jsr_iaddrx() {
|
||||
rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
status.cycle_pos = 0;
|
||||
@@ -402,6 +424,7 @@ void bCPU::op_rti() {
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
last_cycle();
|
||||
rd.b = stack_read();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
status.cycle_pos = 0;
|
||||
@@ -424,6 +447,7 @@ void bCPU::op_rts() {
|
||||
rd.h = stack_read();
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.pc.w = rd.w;
|
||||
regs.pc.w++;
|
||||
@@ -447,6 +471,7 @@ void bCPU::op_rtl() {
|
||||
rd.h = stack_read();
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
rd.b = stack_read();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
regs.pc.w++;
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
void bCPU::op_inc() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.m) {
|
||||
regs.a.l++;
|
||||
@@ -19,6 +20,7 @@ void bCPU::op_inc() {
|
||||
void bCPU::op_inx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.x.l++;
|
||||
@@ -37,6 +39,7 @@ void bCPU::op_inx() {
|
||||
void bCPU::op_iny() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.y.l++;
|
||||
@@ -55,6 +58,7 @@ void bCPU::op_iny() {
|
||||
void bCPU::op_dec() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.m) {
|
||||
regs.a.l--;
|
||||
@@ -73,6 +77,7 @@ void bCPU::op_dec() {
|
||||
void bCPU::op_dex() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.x.l--;
|
||||
@@ -91,6 +96,7 @@ void bCPU::op_dex() {
|
||||
void bCPU::op_dey() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.y.l--;
|
||||
@@ -109,6 +115,7 @@ void bCPU::op_dey() {
|
||||
void bCPU::op_asl() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.m) {
|
||||
regs.p.c = !!(regs.a.l & 0x80);
|
||||
@@ -129,6 +136,7 @@ void bCPU::op_asl() {
|
||||
void bCPU::op_lsr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.m) {
|
||||
regs.p.c = regs.a.l & 1;
|
||||
@@ -149,6 +157,7 @@ void bCPU::op_lsr() {
|
||||
void bCPU::op_rol() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
uint16 c = regs.p.c;
|
||||
if(regs.p.m) {
|
||||
@@ -172,6 +181,7 @@ void bCPU::op_rol() {
|
||||
void bCPU::op_ror() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
uint16 c;
|
||||
if(regs.p.m) {
|
||||
@@ -218,6 +228,7 @@ void bCPU::op_inc_addr() {
|
||||
op_write(OPMODE_DBR, aa.w + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -248,6 +259,7 @@ void bCPU::op_dec_addr() {
|
||||
op_write(OPMODE_DBR, aa.w + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -278,6 +290,7 @@ void bCPU::op_asl_addr() {
|
||||
op_write(OPMODE_DBR, aa.w + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -308,6 +321,7 @@ void bCPU::op_lsr_addr() {
|
||||
op_write(OPMODE_DBR, aa.w + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -338,6 +352,7 @@ void bCPU::op_rol_addr() {
|
||||
op_write(OPMODE_DBR, aa.w + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -368,6 +383,7 @@ void bCPU::op_ror_addr() {
|
||||
op_write(OPMODE_DBR, aa.w + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -398,6 +414,7 @@ void bCPU::op_trb_addr() {
|
||||
op_write(OPMODE_DBR, aa.w + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -428,6 +445,7 @@ void bCPU::op_tsb_addr() {
|
||||
op_write(OPMODE_DBR, aa.w + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -461,6 +479,7 @@ void bCPU::op_inc_addrx() {
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -494,6 +513,7 @@ void bCPU::op_dec_addrx() {
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -527,6 +547,7 @@ void bCPU::op_asl_addrx() {
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -560,6 +581,7 @@ void bCPU::op_lsr_addrx() {
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -593,6 +615,7 @@ void bCPU::op_rol_addrx() {
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -626,6 +649,7 @@ void bCPU::op_ror_addrx() {
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -656,6 +680,7 @@ void bCPU::op_inc_dp() {
|
||||
op_write(OPMODE_DP, dp + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -686,6 +711,7 @@ void bCPU::op_dec_dp() {
|
||||
op_write(OPMODE_DP, dp + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -716,6 +742,7 @@ void bCPU::op_asl_dp() {
|
||||
op_write(OPMODE_DP, dp + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -746,6 +773,7 @@ void bCPU::op_lsr_dp() {
|
||||
op_write(OPMODE_DP, dp + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -776,6 +804,7 @@ void bCPU::op_rol_dp() {
|
||||
op_write(OPMODE_DP, dp + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -806,6 +835,7 @@ void bCPU::op_ror_dp() {
|
||||
op_write(OPMODE_DP, dp + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -836,6 +866,7 @@ void bCPU::op_trb_dp() {
|
||||
op_write(OPMODE_DP, dp + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -866,6 +897,7 @@ void bCPU::op_tsb_dp() {
|
||||
op_write(OPMODE_DP, dp + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -899,6 +931,7 @@ void bCPU::op_inc_dpx() {
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -932,6 +965,7 @@ void bCPU::op_dec_dpx() {
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -965,6 +999,7 @@ void bCPU::op_asl_dpx() {
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -998,6 +1033,7 @@ void bCPU::op_lsr_dpx() {
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -1031,6 +1067,7 @@ void bCPU::op_rol_dpx() {
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -1064,6 +1101,7 @@ void bCPU::op_ror_dpx() {
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@@ -7,10 +7,12 @@ void bCPU::op_sta_addr() {
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, regs.a.w);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.a.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -26,10 +28,12 @@ void bCPU::op_stx_addr() {
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, regs.x.w);
|
||||
if(regs.p.x)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.x.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -45,10 +49,12 @@ void bCPU::op_sty_addr() {
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, regs.y.w);
|
||||
if(regs.p.x)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.y.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -64,10 +70,12 @@ void bCPU::op_stz_addr() {
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, 0x0000);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, 0x0000 >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -86,10 +94,12 @@ void bCPU::op_sta_addrx() {
|
||||
cpu_c4(aa.w, aa.w + regs.x.w);
|
||||
break;
|
||||
case 4:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, regs.a.w);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, regs.a.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -108,10 +118,12 @@ void bCPU::op_stz_addrx() {
|
||||
cpu_c4(aa.w, aa.w + regs.x.w);
|
||||
break;
|
||||
case 4:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, 0x0000);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, 0x0000 >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -130,10 +142,12 @@ void bCPU::op_sta_addry() {
|
||||
cpu_c4(aa.w, aa.w + regs.y.w);
|
||||
break;
|
||||
case 4:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -152,10 +166,12 @@ void bCPU::op_sta_long() {
|
||||
aa.b = op_read();
|
||||
break;
|
||||
case 4:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -174,10 +190,12 @@ void bCPU::op_sta_longx() {
|
||||
aa.b = op_read();
|
||||
break;
|
||||
case 4:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.x.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.x.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -193,10 +211,12 @@ void bCPU::op_sta_dp() {
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DP, dp, regs.a.w);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + 1, regs.a.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -212,10 +232,12 @@ void bCPU::op_stx_dp() {
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DP, dp, regs.x.w);
|
||||
if(regs.p.x)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + 1, regs.x.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -231,10 +253,12 @@ void bCPU::op_sty_dp() {
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DP, dp, regs.y.w);
|
||||
if(regs.p.x)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + 1, regs.y.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -250,10 +274,12 @@ void bCPU::op_stz_dp() {
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DP, dp, 0x0000);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + 1, 0x0000 >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -272,10 +298,12 @@ void bCPU::op_sta_dpx() {
|
||||
cpu_io();
|
||||
break;
|
||||
case 4:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, regs.a.w);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, regs.a.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -294,10 +322,12 @@ void bCPU::op_sty_dpx() {
|
||||
cpu_io();
|
||||
break;
|
||||
case 4:
|
||||
if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, regs.y.w);
|
||||
if(regs.p.x)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, regs.y.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -316,10 +346,12 @@ void bCPU::op_stz_dpx() {
|
||||
cpu_io();
|
||||
break;
|
||||
case 4:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, 0x0000);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, 0x0000 >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -338,10 +370,12 @@ void bCPU::op_stx_dpy() {
|
||||
cpu_io();
|
||||
break;
|
||||
case 4:
|
||||
if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.y.w, regs.x.l);
|
||||
if(regs.p.x)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.y.w + 1, regs.x.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -363,10 +397,12 @@ void bCPU::op_sta_idp() {
|
||||
aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
break;
|
||||
case 5:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 6:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -391,10 +427,12 @@ void bCPU::op_sta_ildp() {
|
||||
aa.b = op_read(OPMODE_DP, dp + 2);
|
||||
break;
|
||||
case 6:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -419,10 +457,12 @@ void bCPU::op_sta_idpx() {
|
||||
aa.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
|
||||
break;
|
||||
case 6:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -447,10 +487,12 @@ void bCPU::op_sta_idpy() {
|
||||
cpu_c4(aa.w, aa.w + regs.y.w);
|
||||
break;
|
||||
case 6:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -475,10 +517,12 @@ void bCPU::op_sta_ildpy() {
|
||||
aa.b = op_read(OPMODE_DP, dp + 2);
|
||||
break;
|
||||
case 6:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.y.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -494,10 +538,12 @@ void bCPU::op_sta_sr() {
|
||||
cpu_io();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_SP, sp, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
op_write(OPMODE_SP, sp + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
@@ -522,10 +568,12 @@ void bCPU::op_sta_isry() {
|
||||
cpu_io();
|
||||
break;
|
||||
case 6:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@@ -186,7 +186,6 @@ optbl[0x91] = &bCPU::op_sta_idpy;
|
||||
optbl[0x97] = &bCPU::op_sta_ildpy;
|
||||
optbl[0x83] = &bCPU::op_sta_sr;
|
||||
optbl[0x93] = &bCPU::op_sta_isry;
|
||||
optbl[0x80] = &bCPU::op_bra;
|
||||
optbl[0x90] = &bCPU::op_bcc;
|
||||
optbl[0xb0] = &bCPU::op_bcs;
|
||||
optbl[0xd0] = &bCPU::op_bne;
|
||||
@@ -195,6 +194,7 @@ optbl[0x10] = &bCPU::op_bpl;
|
||||
optbl[0x30] = &bCPU::op_bmi;
|
||||
optbl[0x50] = &bCPU::op_bvc;
|
||||
optbl[0x70] = &bCPU::op_bvs;
|
||||
optbl[0x80] = &bCPU::op_bra;
|
||||
optbl[0x82] = &bCPU::op_brl;
|
||||
optbl[0x4c] = &bCPU::op_jmp_addr;
|
||||
optbl[0x5c] = &bCPU::op_jmp_long;
|
||||
|
@@ -25,19 +25,158 @@
|
||||
* 4 cycles short?
|
||||
*/
|
||||
|
||||
uint16 bCPU::vcounter() { return time.v; }
|
||||
uint16 bCPU::hcounter() { return get_hcounter(); }
|
||||
uint16 bCPU::hcycles() { return time.hc; }
|
||||
uint16 bCPU::vcounter() { return time.v; }
|
||||
uint16 bCPU::hcounter() { return get_hcounter(); }
|
||||
uint16 bCPU::hcycles() { return time.hc; }
|
||||
|
||||
bool bCPU::interlace() { return time.interlace; }
|
||||
bool bCPU::interlace_field() { return time.interlace_field; }
|
||||
bool bCPU::overscan() { return time.overscan; }
|
||||
uint16 bCPU::region_scanlines() { return time.region_scanlines; }
|
||||
|
||||
void bCPU::set_interlace(bool r) { time.interlace = r; }
|
||||
void bCPU::set_overscan(bool r) { time.overscan = r; }
|
||||
void bCPU::set_interlace(bool r) { time.interlace = r; update_interrupts(); }
|
||||
void bCPU::set_overscan (bool r) { time.overscan = r; update_interrupts(); }
|
||||
|
||||
uint8 bCPU::dma_counter() { return (time.dma_counter + time.hc) & 6; }
|
||||
|
||||
bool bCPU::nmi_trigger_pos_match(uint32 offset) {
|
||||
uint16 v = overscan() ? 240 : 225;
|
||||
uint16 hc = 2 + offset;
|
||||
return (time.v == v && time.hc == hc);
|
||||
}
|
||||
|
||||
bool bCPU::irq_trigger_pos_match(uint32 offset) {
|
||||
uint16 v = status.virq_pos;
|
||||
uint16 hc = (status.hirq_enabled) ? status.hirq_pos : 0;
|
||||
|
||||
//positions that can never be latched
|
||||
//region_scanlines() = 262/NTSC, 312/PAL
|
||||
//PAL results are unverified on hardware
|
||||
if(v == 240 && hc == 339 && interlace() == false && interlace_field() == 1)return false;
|
||||
if(v == (region_scanlines() - 1) && hc == 339 && interlace() == false)return false;
|
||||
if(v == region_scanlines() && interlace() == false)return false;
|
||||
if(v == region_scanlines() && hc == 339)return false;
|
||||
if(v > region_scanlines())return false;
|
||||
if(hc > 339)return false;
|
||||
|
||||
hc = (hc != 0) ? ((hc << 2) + 14) : 10;
|
||||
hc += offset;
|
||||
if(hc >= time.line_cycles) {
|
||||
hc -= time.line_cycles;
|
||||
if(++v >= time.frame_lines) {
|
||||
v = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if((status.virq_enabled == true && time.v == v) || status.virq_enabled == false) {
|
||||
return (time.hc == hc);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void bCPU::update_nmi() {
|
||||
if(time.v == (overscan() ? 240 : 225)) {
|
||||
time.nmi_read_trigger_pos = 2;
|
||||
time.nmi_line_trigger_pos = 6;
|
||||
} else {
|
||||
time.nmi_read_trigger_pos = -64;
|
||||
time.nmi_line_trigger_pos = -64;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::update_irq() {
|
||||
int vpos = status.virq_pos;
|
||||
int hpos = (status.hirq_enabled) ? status.hirq_pos : 0;
|
||||
|
||||
//positions that can never be latched
|
||||
//region_scanlines() = 262/NTSC, 312/PAL
|
||||
//PAL results are unverified on hardware
|
||||
if(vpos == 240 && hpos == 339 && interlace() == false && interlace_field() == 1)goto _nolatch;
|
||||
if(vpos == (region_scanlines() - 1) && hpos == 339 && interlace() == false)goto _nolatch;
|
||||
if(vpos == region_scanlines() && interlace() == false)goto _nolatch;
|
||||
if(vpos == region_scanlines() && hpos == 339)goto _nolatch;
|
||||
if(vpos > region_scanlines())goto _nolatch;
|
||||
if(hpos > 339)goto _nolatch;
|
||||
|
||||
hpos = (hpos != 0) ? ((hpos << 2) + 14) : 10;
|
||||
if(hpos >= time.line_cycles) {
|
||||
hpos -= time.line_cycles;
|
||||
if(++vpos >= time.frame_lines) {
|
||||
vpos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if((status.virq_enabled == true && time.v == vpos) || status.virq_enabled == false) {
|
||||
time.irq_read_trigger_pos = hpos;
|
||||
} else {
|
||||
time.irq_read_trigger_pos = -64;
|
||||
}
|
||||
|
||||
hpos += 4;
|
||||
if(hpos >= time.line_cycles) {
|
||||
hpos -= time.line_cycles;
|
||||
if(++vpos >= time.frame_lines) {
|
||||
vpos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if((status.virq_enabled == true && time.v == vpos) || status.virq_enabled == false) {
|
||||
time.irq_line_trigger_pos = hpos;
|
||||
} else {
|
||||
time.irq_line_trigger_pos = -64;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
_nolatch:
|
||||
time.irq_read_trigger_pos = -64;
|
||||
time.irq_line_trigger_pos = -64;
|
||||
}
|
||||
|
||||
void bCPU::update_interrupts() {
|
||||
update_nmi();
|
||||
update_irq();
|
||||
}
|
||||
|
||||
void bCPU::poll_interrupts(int cycles) {
|
||||
int16 hc, hc_end;
|
||||
if(time.hc == 0) {
|
||||
hc = -1;
|
||||
hc_end = cycles;
|
||||
} else {
|
||||
hc = time.hc;
|
||||
hc_end = time.hc + cycles;
|
||||
}
|
||||
|
||||
if(hc < time.nmi_read_trigger_pos && time.nmi_read_trigger_pos <= hc_end) {
|
||||
//nmi_read can go low even with NMI interrupts disabled in $4200.d7
|
||||
time.nmi_read = 0;
|
||||
}
|
||||
|
||||
if(hc < time.nmi_line_trigger_pos && time.nmi_line_trigger_pos <= hc_end) {
|
||||
if(status.nmi_enabled == true) {
|
||||
if(time.nmi_line == 1) {
|
||||
time.nmi_transition = 1;
|
||||
}
|
||||
time.nmi_line = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(hc < time.irq_read_trigger_pos && time.irq_read_trigger_pos <= hc_end) {
|
||||
if(status.virq_enabled == true || status.hirq_enabled == true) {
|
||||
time.irq_read = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(hc < time.irq_line_trigger_pos && time.irq_line_trigger_pos <= hc_end) {
|
||||
if(status.virq_enabled == true || status.hirq_enabled == true) {
|
||||
time.irq_line = 0;
|
||||
time.irq_transition = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//all scanlines are 1364 cycles long, except scanline 240
|
||||
//on non-interlace odd-frames, which is 1360 cycles long.
|
||||
//[NTSC]
|
||||
@@ -68,14 +207,15 @@ void bCPU::inc_vcounter() {
|
||||
}
|
||||
}
|
||||
|
||||
time.hc = 0;
|
||||
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 {
|
||||
time.line_cycles = 1364;
|
||||
}
|
||||
time.dram_refreshed = false;
|
||||
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//all dots are 4 cycles long, except dots 323 and 327. dots 323 and 327
|
||||
@@ -93,16 +233,6 @@ uint16 bCPU::get_hcounter() {
|
||||
return (time.hc - ((time.hc > 1292) << 1) - ((time.hc > 1310) << 1)) >> 2;
|
||||
}
|
||||
|
||||
void bCPU::dram_refresh() {
|
||||
time.dram_refreshed = true;
|
||||
add_cycles(40);
|
||||
if(time.v != 240 || time.interlace != false || time.interlace_field != 1) {
|
||||
//alternate between 534 and 538 every scanline except 240ni1
|
||||
//in reality, this is probably based on frame cycle length...
|
||||
time.dram_refresh_pos ^= 12;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 bCPU::cycles_executed() {
|
||||
uint32 r = status.cycles_executed;
|
||||
status.cycles_executed = 0;
|
||||
@@ -112,36 +242,79 @@ uint32 r = status.cycles_executed;
|
||||
void bCPU::add_cycles(int cycles) {
|
||||
status.cycles_executed += cycles;
|
||||
|
||||
cycles >>= 1;
|
||||
while(cycles--) {
|
||||
time.hc += 2;
|
||||
poll_interrupts(cycles);
|
||||
|
||||
if(time.hc >= time.line_cycles) {
|
||||
inc_vcounter();
|
||||
if(time.v == 0) {
|
||||
frame();
|
||||
ppu->frame();
|
||||
}
|
||||
scanline();
|
||||
ppu->scanline();
|
||||
if(time.hc + cycles >= time.line_cycles) {
|
||||
cycles = (time.hc + cycles) - time.line_cycles;
|
||||
time.hc = 0;
|
||||
|
||||
inc_vcounter();
|
||||
poll_interrupts(cycles);
|
||||
|
||||
if(time.v == 0) {
|
||||
frame();
|
||||
ppu->frame();
|
||||
snes->frame();
|
||||
}
|
||||
|
||||
if(time.dram_refreshed == false && time.hc >= time.dram_refresh_pos) {
|
||||
dram_refresh();
|
||||
}
|
||||
scanline();
|
||||
ppu->scanline();
|
||||
snes->scanline();
|
||||
time.line_rendered = false;
|
||||
}
|
||||
|
||||
if(hdma_test() == true) {
|
||||
hdma_run();
|
||||
if(time.hdmainit_triggered == false) {
|
||||
if(time.hc + cycles >= time.hdmainit_trigger_pos || time.v) {
|
||||
time.hdmainit_triggered = true;
|
||||
hdmainit_activate();
|
||||
}
|
||||
}
|
||||
|
||||
if(time.dram_refreshed == false) {
|
||||
if(time.hc + cycles >= time.dram_refresh_pos) {
|
||||
time.dram_refreshed = true;
|
||||
status.cycles_executed += 40;
|
||||
cycles = (time.hc + cycles) - time.dram_refresh_pos;
|
||||
time.hc = time.dram_refresh_pos + 40;
|
||||
|
||||
if(cpu_version == 2) {
|
||||
if(time.v != 240 || time.interlace != false || time.interlace_field != 1) {
|
||||
if(time.dram_refresh_pos == 534) {
|
||||
time.dram_refresh_pos = 538;
|
||||
} else {
|
||||
time.dram_refresh_pos = 534;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 >= 1106) {
|
||||
time.hdma_triggered = true;
|
||||
hdma_activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
time.hc += 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;
|
||||
@@ -150,10 +323,26 @@ void bCPU::time_reset() {
|
||||
time.line_cycles = 1364;
|
||||
|
||||
time.dram_refreshed = false;
|
||||
time.dram_refresh_pos = 538;
|
||||
time.dram_refresh_pos = (cpu_version == 2) ? 538 : 530;
|
||||
|
||||
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;
|
||||
time.irq_line = time.irq_read = 1;
|
||||
|
||||
time.nmi_transition = 0;
|
||||
time.irq_transition = 0;
|
||||
|
||||
update_interrupts();
|
||||
|
||||
switch(region) {
|
||||
case NTSC:
|
||||
time.region_scanlines = 262;
|
||||
|
@@ -4,13 +4,47 @@ struct {
|
||||
bool interlace, interlace_field, overscan;
|
||||
uint16 line_cycles, frame_lines;
|
||||
|
||||
bool line_rendered;
|
||||
|
||||
bool dram_refreshed;
|
||||
uint16 dram_refresh_pos;
|
||||
|
||||
uint8 dma_counter;
|
||||
|
||||
uint16 hdmainit_trigger_pos;
|
||||
bool hdmainit_triggered;
|
||||
|
||||
bool hdma_triggered;
|
||||
|
||||
uint16 region_scanlines;
|
||||
}time;
|
||||
|
||||
//nmi_pending, irq_pending are used by last_cycle()
|
||||
//nmi_line = /NMI, nmi_read = $4210.7
|
||||
//irq_line = /IRQ, irq_read = $4211.7
|
||||
bool nmi_pending, nmi_line, nmi_read;
|
||||
bool irq_pending, irq_line, irq_read;
|
||||
|
||||
//NMI is edge-sensitive, meaning it triggers when /NMI
|
||||
//transitions from high to low. This value is set to 1
|
||||
//when that happens, and cleared after the nmi_test()
|
||||
//routine acknowledges it and invokes the NMI interrupt
|
||||
bool nmi_transition;
|
||||
|
||||
//IRQ is level-sensitive, so it does not need to keep
|
||||
//track of transitions from high to low. IRQs will
|
||||
//continue to fire as long as /IRQ stays low.
|
||||
//However, if a write to $4200 forces IRQs high at the
|
||||
//exact same clock cycle that /IRQ goes low, the /IRQ
|
||||
//will still occur. Hence the need for this variable.
|
||||
bool irq_transition;
|
||||
|
||||
//position is relative to time.hc, set at start of each scanline
|
||||
//-64 means no trigger point on this scanline
|
||||
//$4210/$4211 status bits get set before /NMI and /IRQ go low,
|
||||
//hence the need for two variables for each.
|
||||
int32 nmi_read_trigger_pos, nmi_line_trigger_pos;
|
||||
int32 irq_read_trigger_pos, irq_line_trigger_pos;
|
||||
} time;
|
||||
|
||||
inline uint16 vcounter();
|
||||
inline uint16 hcounter();
|
||||
@@ -20,6 +54,14 @@ inline bool interlace_field();
|
||||
inline bool overscan();
|
||||
inline uint16 region_scanlines();
|
||||
|
||||
inline bool nmi_trigger_pos_match(uint32 offset);
|
||||
inline bool irq_trigger_pos_match(uint32 offset);
|
||||
|
||||
inline void update_nmi();
|
||||
inline void update_irq();
|
||||
inline void update_interrupts();
|
||||
inline void poll_interrupts(int cycles);
|
||||
|
||||
inline void set_interlace(bool r);
|
||||
inline void set_overscan (bool r);
|
||||
|
||||
@@ -27,6 +69,5 @@ inline uint8 dma_counter();
|
||||
|
||||
inline void inc_vcounter();
|
||||
inline uint16 get_hcounter();
|
||||
inline void dram_refresh();
|
||||
inline void add_cycles(int cycles);
|
||||
inline void time_reset();
|
||||
|
@@ -53,7 +53,6 @@ char t[4096];
|
||||
|
||||
void update_line(int i, int n) {
|
||||
char t[4096];
|
||||
sprintf(t, "goto l%d;", n + 2);
|
||||
replace(line[i], "end;", "status.cycle_pos = 0;");
|
||||
replace(line[i], "skip;", "status.cycle_pos++;");
|
||||
}
|
||||
@@ -88,7 +87,11 @@ char t[4096];
|
||||
|
||||
i++;
|
||||
}
|
||||
if(!strcmp(line[i], "}"))strcat(output_op, " status.cycle_pos = 0;\r\n");
|
||||
|
||||
if(!strcmp(line[i], "}")) {
|
||||
strcat(output_op, " status.cycle_pos = 0;\r\n");
|
||||
}
|
||||
|
||||
strcat(output_op, " break;\r\n");
|
||||
}
|
||||
strcat(output_op, " }\r\n}");
|
||||
|
Binary file not shown.
@@ -1,14 +1,17 @@
|
||||
nop(0xea) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
}
|
||||
|
||||
wdm(0x42) {
|
||||
1:op_read();
|
||||
1:last_cycle();
|
||||
op_read();
|
||||
}
|
||||
|
||||
xba(0xeb) {
|
||||
1:cpu_io();
|
||||
2:cpu_io();
|
||||
2:last_cycle();
|
||||
cpu_io();
|
||||
regs.a.l ^= regs.a.h;
|
||||
regs.a.h ^= regs.a.l;
|
||||
regs.a.l ^= regs.a.h;
|
||||
@@ -26,7 +29,8 @@ mvp(0x44, --) {
|
||||
5:cpu_io();
|
||||
if(regs.p.x) { regs.x.l$1; regs.y.l$1; }
|
||||
else { regs.x.w$1; regs.y.w$1; }
|
||||
6:cpu_io();
|
||||
6:last_cycle();
|
||||
cpu_io();
|
||||
if(regs.a.w--)regs.pc.w -= 3;
|
||||
}
|
||||
|
||||
@@ -39,7 +43,8 @@ cop(0x02, 0xfff4, 0xfff5, 0xffe4, 0xffe5) {
|
||||
4:stack_write(regs.pc.l);
|
||||
5:stack_write(regs.p);
|
||||
6:rd.l = op_read(OPMODE_LONG, (regs.e)?$1:$3);
|
||||
7:rd.h = op_read(OPMODE_LONG, (regs.e)?$2:$4);
|
||||
7:last_cycle();
|
||||
rd.h = op_read(OPMODE_LONG, (regs.e)?$2:$4);
|
||||
regs.pc.b = 0x00;
|
||||
regs.pc.w = rd.w;
|
||||
regs.p.i = 1;
|
||||
@@ -48,20 +53,26 @@ cop(0x02, 0xfff4, 0xfff5, 0xffe4, 0xffe5) {
|
||||
|
||||
stp(0xdb) {
|
||||
1:cpu_io();
|
||||
status.cpu_state = CPUSTATE_STP;
|
||||
2:cpu_io();
|
||||
run_state.stp = true;
|
||||
2:last_cycle();
|
||||
cpu_io();
|
||||
regs.pc.w--;
|
||||
}
|
||||
|
||||
wai(0xcb) {
|
||||
1:cpu_io();
|
||||
status.cpu_state = CPUSTATE_WAI;
|
||||
2:cpu_io();
|
||||
regs.pc.w--;
|
||||
run_state.wai = true;
|
||||
2:last_cycle();
|
||||
cpu_io();
|
||||
if(run_state.wai) {
|
||||
//this can be cleared within last_cycle()
|
||||
regs.pc.w--;
|
||||
}
|
||||
}
|
||||
|
||||
xce(0xfb) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
bool c = regs.p.c;
|
||||
regs.p.c = regs.e;
|
||||
regs.e = c;
|
||||
@@ -80,14 +91,16 @@ clv(0xb8, regs.p.v = 0),
|
||||
sec(0x38, regs.p.c = 1),
|
||||
sed(0xf8, regs.p.d = 1),
|
||||
sei(0x78, regs.p.i = 1) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
$1;
|
||||
}
|
||||
|
||||
rep(0xc2, &=~),
|
||||
sep(0xe2, |=) {
|
||||
1:rd.l = op_read();
|
||||
2:cpu_io();
|
||||
2:last_cycle();
|
||||
cpu_io();
|
||||
regs.p $1 rd.l;
|
||||
if(regs.e)regs.p |= 0x30;
|
||||
if(regs.p.x) {
|
||||
@@ -102,7 +115,8 @@ txa(0x8a, regs.p.m, a, x),
|
||||
txy(0x9b, regs.p.x, y, x),
|
||||
tya(0x98, regs.p.m, a, y),
|
||||
tyx(0xbb, regs.p.x, x, y) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
if($1) {
|
||||
regs.$2.l = regs.$3.l;
|
||||
regs.p.n = !!(regs.$2.l & 0x80);
|
||||
@@ -115,27 +129,31 @@ tyx(0xbb, regs.p.x, x, y) {
|
||||
}
|
||||
|
||||
tcd(0x5b) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
regs.d.w = regs.a.w;
|
||||
regs.p.n = !!(regs.d.w & 0x8000);
|
||||
regs.p.z = (regs.d.w == 0);
|
||||
}
|
||||
|
||||
tcs(0x1b) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
regs.s.w = regs.a.w;
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
}
|
||||
|
||||
tdc(0x7b) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
regs.a.w = regs.d.w;
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
|
||||
tsc(0x3b) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
regs.a.w = regs.s.w;
|
||||
if(regs.e) {
|
||||
regs.p.n = !!(regs.a.l & 0x80);
|
||||
@@ -147,7 +165,8 @@ tsc(0x3b) {
|
||||
}
|
||||
|
||||
tsx(0xba) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.x.l = regs.s.l;
|
||||
regs.p.n = !!(regs.x.l & 0x80);
|
||||
@@ -160,7 +179,8 @@ tsx(0xba) {
|
||||
}
|
||||
|
||||
txs(0x9a) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
if(regs.e) {
|
||||
regs.s.l = regs.x.l;
|
||||
regs.p.n = !!(regs.s.l & 0x80);
|
||||
@@ -179,14 +199,16 @@ phd(0x0b, 0, d) {
|
||||
1:cpu_io();
|
||||
if($1)skip;
|
||||
2:stack_write(regs.$2.h);
|
||||
3:stack_write(regs.$2.l);
|
||||
3:last_cycle();
|
||||
stack_write(regs.$2.l);
|
||||
}
|
||||
|
||||
phb(0x8b, regs.db),
|
||||
phk(0x4b, regs.pc.b),
|
||||
php(0x08, regs.p) {
|
||||
1:cpu_io();
|
||||
2:stack_write($1);
|
||||
2:last_cycle();
|
||||
stack_write($1);
|
||||
}
|
||||
|
||||
pla(0x68, regs.p.m, a),
|
||||
@@ -195,13 +217,15 @@ ply(0x7a, regs.p.x, y),
|
||||
pld(0x2b, 0, d) {
|
||||
1:cpu_io();
|
||||
2:cpu_io();
|
||||
3:regs.$2.l = stack_read();
|
||||
3:if($1)last_cycle();
|
||||
regs.$2.l = stack_read();
|
||||
if($1) {
|
||||
regs.p.n = !!(regs.$2.l & 0x80);
|
||||
regs.p.z = (regs.$2.l == 0);
|
||||
end;
|
||||
}
|
||||
4:regs.$2.h = stack_read();
|
||||
4:last_cycle();
|
||||
regs.$2.h = stack_read();
|
||||
regs.p.n = !!(regs.$2.w & 0x8000);
|
||||
regs.p.z = (regs.$2.w == 0);
|
||||
}
|
||||
@@ -209,7 +233,8 @@ pld(0x2b, 0, d) {
|
||||
plb(0xab) {
|
||||
1:cpu_io();
|
||||
2:cpu_io();
|
||||
3:regs.db = stack_read();
|
||||
3:last_cycle();
|
||||
regs.db = stack_read();
|
||||
regs.p.n = !!(regs.db & 0x80);
|
||||
regs.p.z = (regs.db == 0);
|
||||
}
|
||||
@@ -217,7 +242,8 @@ plb(0xab) {
|
||||
plp(0x28) {
|
||||
1:cpu_io();
|
||||
2:cpu_io();
|
||||
3:regs.p = stack_read();
|
||||
3:last_cycle();
|
||||
regs.p = stack_read();
|
||||
if(regs.e)regs.p |= 0x30;
|
||||
if(regs.p.x) {
|
||||
regs.x.h = 0x00;
|
||||
@@ -229,7 +255,8 @@ pea(0xf4) {
|
||||
1:aa.l = op_read();
|
||||
2:aa.h = op_read();
|
||||
3:stack_write(aa.h);
|
||||
4:stack_write(aa.l);
|
||||
4:last_cycle();
|
||||
stack_write(aa.l);
|
||||
}
|
||||
|
||||
pei(0xd4) {
|
||||
@@ -238,7 +265,8 @@ pei(0xd4) {
|
||||
3:aa.l = op_read(OPMODE_DP, dp);
|
||||
4:aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
5:stack_write(aa.h);
|
||||
6:stack_write(aa.l);
|
||||
6:last_cycle();
|
||||
stack_write(aa.l);
|
||||
}
|
||||
|
||||
per(0x62) {
|
||||
@@ -247,5 +275,6 @@ per(0x62) {
|
||||
3:cpu_io();
|
||||
rd.w = regs.pc.d + (int16)aa.w;
|
||||
4:stack_write(rd.h);
|
||||
5:stack_write(rd.l);
|
||||
5:last_cycle();
|
||||
stack_write(rd.l);
|
||||
}
|
||||
|
@@ -1,4 +1,3 @@
|
||||
bra(0x80, 1),
|
||||
bcc(0x90, !regs.p.c),
|
||||
bcs(0xb0, regs.p.c),
|
||||
bne(0xd0, !regs.p.z),
|
||||
@@ -7,7 +6,8 @@ bpl(0x10, !regs.p.n),
|
||||
bmi(0x30, regs.p.n),
|
||||
bvc(0x50, !regs.p.v),
|
||||
bvs(0x70, regs.p.v) {
|
||||
1:rd.l = op_read();
|
||||
1:if(!$1)last_cycle();
|
||||
rd.l = op_read();
|
||||
if($1) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
@@ -15,26 +15,39 @@ bvs(0x70, regs.p.v) {
|
||||
end;
|
||||
}
|
||||
2:cpu_c6(aa.w);
|
||||
3:cpu_io();
|
||||
3:last_cycle();
|
||||
cpu_io();
|
||||
}
|
||||
|
||||
bra(0x80) {
|
||||
1:rd.l = op_read();
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
2:cpu_c6(aa.w);
|
||||
3:last_cycle();
|
||||
cpu_io();
|
||||
}
|
||||
|
||||
brl(0x82) {
|
||||
1:rd.l = op_read();
|
||||
2:rd.h = op_read();
|
||||
3:cpu_io();
|
||||
3:last_cycle();
|
||||
cpu_io();
|
||||
regs.pc.w = regs.pc.d + (int16)rd.w;
|
||||
}
|
||||
|
||||
jmp_addr(0x4c) {
|
||||
1:rd.l = op_read();
|
||||
2:rd.h = op_read();
|
||||
2:last_cycle();
|
||||
rd.h = op_read();
|
||||
regs.pc.w = rd.w;
|
||||
}
|
||||
|
||||
jmp_long(0x5c) {
|
||||
1:rd.l = op_read();
|
||||
2:rd.h = op_read();
|
||||
3:rd.b = op_read();
|
||||
3:last_cycle();
|
||||
rd.b = op_read();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
}
|
||||
|
||||
@@ -42,7 +55,8 @@ jmp_iaddr(0x6c) {
|
||||
1:aa.l = op_read();
|
||||
2:aa.h = op_read();
|
||||
3:rd.l = op_read(OPMODE_ADDR, aa.w);
|
||||
4:rd.h = op_read(OPMODE_ADDR, aa.w + 1);
|
||||
4:last_cycle();
|
||||
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
}
|
||||
|
||||
@@ -51,7 +65,8 @@ jmp_iaddrx(0x7c) {
|
||||
2:aa.h = op_read();
|
||||
3:cpu_io();
|
||||
4:rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
|
||||
5:rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
|
||||
5:last_cycle();
|
||||
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
}
|
||||
|
||||
@@ -60,7 +75,8 @@ jmp_iladdr(0xdc) {
|
||||
2:aa.h = op_read();
|
||||
3:rd.l = op_read(OPMODE_ADDR, aa.w);
|
||||
4:rd.h = op_read(OPMODE_ADDR, aa.w + 1);
|
||||
5:rd.b = op_read(OPMODE_ADDR, aa.w + 2);
|
||||
5:last_cycle();
|
||||
rd.b = op_read(OPMODE_ADDR, aa.w + 2);
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
}
|
||||
|
||||
@@ -70,7 +86,8 @@ jsr_addr(0x20) {
|
||||
3:cpu_io();
|
||||
4:regs.pc.w--;
|
||||
stack_write(regs.pc.h);
|
||||
5:stack_write(regs.pc.l);
|
||||
5:last_cycle();
|
||||
stack_write(regs.pc.l);
|
||||
regs.pc.w = aa.w;
|
||||
}
|
||||
|
||||
@@ -82,7 +99,8 @@ jsr_long(0x22) {
|
||||
5:aa.b = op_read();
|
||||
6:regs.pc.w--;
|
||||
stack_write(regs.pc.h);
|
||||
7:stack_write(regs.pc.l);
|
||||
7:last_cycle();
|
||||
stack_write(regs.pc.l);
|
||||
regs.pc.d = aa.d & 0xffffff;
|
||||
}
|
||||
|
||||
@@ -93,7 +111,8 @@ jsr_iaddrx(0xfc) {
|
||||
4:aa.h = op_read();
|
||||
5:cpu_io();
|
||||
6:rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
|
||||
7:rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
|
||||
7:last_cycle();
|
||||
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
}
|
||||
|
||||
@@ -112,7 +131,8 @@ rti(0x40) {
|
||||
regs.pc.w = rd.w;
|
||||
end;
|
||||
}
|
||||
6:rd.b = stack_read();
|
||||
6:last_cycle();
|
||||
rd.b = stack_read();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
}
|
||||
|
||||
@@ -121,7 +141,8 @@ rts(0x60) {
|
||||
2:cpu_io();
|
||||
3:rd.l = stack_read();
|
||||
4:rd.h = stack_read();
|
||||
5:cpu_io();
|
||||
5:last_cycle();
|
||||
cpu_io();
|
||||
regs.pc.w = rd.w;
|
||||
regs.pc.w++;
|
||||
}
|
||||
@@ -131,7 +152,8 @@ rtl(0x6b) {
|
||||
2:cpu_io();
|
||||
3:rd.l = stack_read();
|
||||
4:rd.h = stack_read();
|
||||
5:rd.b = stack_read();
|
||||
5:last_cycle();
|
||||
rd.b = stack_read();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
regs.pc.w++;
|
||||
}
|
||||
|
@@ -9,9 +9,11 @@ ldx_const(0xa2, ldx, regs.p.x),
|
||||
ldy_const(0xa0, ldy, regs.p.x),
|
||||
ora_const(0x09, ora, regs.p.m),
|
||||
sbc_const(0xe9, sbc, regs.p.m) {
|
||||
1:rd.l = op_read();
|
||||
1:if($2)last_cycle();
|
||||
rd.l = op_read();
|
||||
if($2) { op_$1_b(); end; }
|
||||
2:rd.h = op_read();
|
||||
2:last_cycle();
|
||||
rd.h = op_read();
|
||||
op_$1_w();
|
||||
}
|
||||
|
||||
@@ -29,9 +31,11 @@ ora_addr(0x0d, ora, regs.p.m),
|
||||
sbc_addr(0xed, sbc, regs.p.m) {
|
||||
1:aa.l = op_read();
|
||||
2:aa.h = op_read();
|
||||
3:rd.l = op_read(OPMODE_DBR, aa.w);
|
||||
3:if($2)last_cycle();
|
||||
rd.l = op_read(OPMODE_DBR, aa.w);
|
||||
if($2) { op_$1_b(); end; }
|
||||
4:rd.h = op_read(OPMODE_DBR, aa.w + 1);
|
||||
4:last_cycle();
|
||||
rd.h = op_read(OPMODE_DBR, aa.w + 1);
|
||||
op_$1_w();
|
||||
}
|
||||
|
||||
@@ -47,9 +51,11 @@ sbc_addrx(0xfd, sbc, regs.p.m) {
|
||||
1:aa.l = op_read();
|
||||
2:aa.h = op_read();
|
||||
3:cpu_c4(aa.w, aa.w + regs.x.w);
|
||||
4:rd.l = op_read(OPMODE_DBR, aa.w + regs.x.w);
|
||||
4:if($2)last_cycle();
|
||||
rd.l = op_read(OPMODE_DBR, aa.w + regs.x.w);
|
||||
if($2) { op_$1_b(); end; }
|
||||
5:rd.h = op_read(OPMODE_DBR, aa.w + regs.x.w + 1);
|
||||
5:last_cycle();
|
||||
rd.h = op_read(OPMODE_DBR, aa.w + regs.x.w + 1);
|
||||
op_$1_w();
|
||||
}
|
||||
|
||||
@@ -64,9 +70,11 @@ sbc_addry(0xf9, sbc, regs.p.m) {
|
||||
1:aa.l = op_read();
|
||||
2:aa.h = op_read();
|
||||
3:cpu_c4(aa.w, aa.w + regs.y.w);
|
||||
4:rd.l = op_read(OPMODE_DBR, aa.w + regs.y.w);
|
||||
4:if($2)last_cycle();
|
||||
rd.l = op_read(OPMODE_DBR, aa.w + regs.y.w);
|
||||
if($2) { op_$1_b(); end; }
|
||||
5:rd.h = op_read(OPMODE_DBR, aa.w + regs.y.w + 1);
|
||||
5:last_cycle();
|
||||
rd.h = op_read(OPMODE_DBR, aa.w + regs.y.w + 1);
|
||||
op_$1_w();
|
||||
}
|
||||
|
||||
@@ -80,9 +88,11 @@ sbc_long(0xef, sbc, regs.p.m) {
|
||||
1:aa.l = op_read();
|
||||
2:aa.h = op_read();
|
||||
3:aa.b = op_read();
|
||||
4:rd.l = op_read(OPMODE_LONG, aa.d);
|
||||
4:if($2)last_cycle();
|
||||
rd.l = op_read(OPMODE_LONG, aa.d);
|
||||
if($2) { op_$1_b(); end; }
|
||||
5:rd.h = op_read(OPMODE_LONG, aa.d + 1);
|
||||
5:last_cycle();
|
||||
rd.h = op_read(OPMODE_LONG, aa.d + 1);
|
||||
op_$1_w();
|
||||
}
|
||||
|
||||
@@ -96,9 +106,11 @@ sbc_longx(0xff, sbc, regs.p.m) {
|
||||
1:aa.l = op_read();
|
||||
2:aa.h = op_read();
|
||||
3:aa.b = op_read();
|
||||
4:rd.l = op_read(OPMODE_LONG, aa.d + regs.x.w);
|
||||
4:if($2)last_cycle();
|
||||
rd.l = op_read(OPMODE_LONG, aa.d + regs.x.w);
|
||||
if($2) { op_$1_b(); end; }
|
||||
5:rd.h = op_read(OPMODE_LONG, aa.d + regs.x.w + 1);
|
||||
5:last_cycle();
|
||||
rd.h = op_read(OPMODE_LONG, aa.d + regs.x.w + 1);
|
||||
op_$1_w();
|
||||
}
|
||||
|
||||
@@ -116,9 +128,11 @@ ora_dp(0x05, ora, regs.p.m),
|
||||
sbc_dp(0xe5, sbc, regs.p.m) {
|
||||
1:dp = op_read();
|
||||
2:cpu_c2();
|
||||
3:rd.l = op_read(OPMODE_DP, dp);
|
||||
3:if($2)last_cycle();
|
||||
rd.l = op_read(OPMODE_DP, dp);
|
||||
if($2) { op_$1_b(); end; }
|
||||
4:rd.h = op_read(OPMODE_DP, dp + 1);
|
||||
4:last_cycle();
|
||||
rd.h = op_read(OPMODE_DP, dp + 1);
|
||||
op_$1_w();
|
||||
}
|
||||
|
||||
@@ -134,9 +148,11 @@ sbc_dpx(0xf5, sbc, regs.p.m) {
|
||||
1:dp = op_read();
|
||||
2:cpu_c2();
|
||||
3:cpu_io();
|
||||
4:rd.l = op_read(OPMODE_DP, dp + regs.x.w);
|
||||
4:if($2)last_cycle();
|
||||
rd.l = op_read(OPMODE_DP, dp + regs.x.w);
|
||||
if($2) { op_$1_b(); end; }
|
||||
5:rd.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
|
||||
5:last_cycle();
|
||||
rd.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
|
||||
op_$1_w();
|
||||
}
|
||||
|
||||
@@ -144,9 +160,11 @@ ldx_dpy(0xb6, ldx, regs.p.x) {
|
||||
1:dp = op_read();
|
||||
2:cpu_c2();
|
||||
3:cpu_io();
|
||||
4:rd.l = op_read(OPMODE_DP, dp + regs.y.w);
|
||||
4:if($2)last_cycle();
|
||||
rd.l = op_read(OPMODE_DP, dp + regs.y.w);
|
||||
if($2) { op_$1_b(); end; }
|
||||
5:rd.h = op_read(OPMODE_DP, dp + regs.y.w + 1);
|
||||
5:last_cycle();
|
||||
rd.h = op_read(OPMODE_DP, dp + regs.y.w + 1);
|
||||
op_$1_w();
|
||||
}
|
||||
|
||||
@@ -161,9 +179,11 @@ sbc_idp(0xf2, sbc, regs.p.m) {
|
||||
2:cpu_c2();
|
||||
3:aa.l = op_read(OPMODE_DP, dp);
|
||||
4:aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
5:rd.l = op_read(OPMODE_DBR, aa.w);
|
||||
5:if($2)last_cycle();
|
||||
rd.l = op_read(OPMODE_DBR, aa.w);
|
||||
if($2) { op_$1_b(); end; }
|
||||
6:rd.h = op_read(OPMODE_DBR, aa.w + 1);
|
||||
6:last_cycle();
|
||||
rd.h = op_read(OPMODE_DBR, aa.w + 1);
|
||||
op_$1_w();
|
||||
}
|
||||
|
||||
@@ -179,9 +199,11 @@ sbc_idpx(0xe1, sbc, regs.p.m) {
|
||||
3:cpu_io();
|
||||
4:aa.l = op_read(OPMODE_DP, dp + regs.x.w);
|
||||
5:aa.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
|
||||
6:rd.l = op_read(OPMODE_DBR, aa.w);
|
||||
6:if($2)last_cycle();
|
||||
rd.l = op_read(OPMODE_DBR, aa.w);
|
||||
if($2) { op_$1_b(); end; }
|
||||
7:rd.h = op_read(OPMODE_DBR, aa.w + 1);
|
||||
7:last_cycle();
|
||||
rd.h = op_read(OPMODE_DBR, aa.w + 1);
|
||||
op_$1_w();
|
||||
}
|
||||
|
||||
@@ -197,9 +219,11 @@ sbc_idpy(0xf1, sbc, regs.p.m) {
|
||||
3:aa.l = op_read(OPMODE_DP, dp);
|
||||
4:aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
5:cpu_c4(aa.w, aa.w + regs.y.w);
|
||||
6:rd.l = op_read(OPMODE_DBR, aa.w + regs.y.w);
|
||||
6:if($2)last_cycle();
|
||||
rd.l = op_read(OPMODE_DBR, aa.w + regs.y.w);
|
||||
if($2) { op_$1_b(); end; }
|
||||
7:rd.h = op_read(OPMODE_DBR, aa.w + regs.y.w + 1);
|
||||
7:last_cycle();
|
||||
rd.h = op_read(OPMODE_DBR, aa.w + regs.y.w + 1);
|
||||
op_$1_w();
|
||||
}
|
||||
|
||||
@@ -215,9 +239,11 @@ sbc_ildp(0xe7, sbc, regs.p.m) {
|
||||
3:aa.l = op_read(OPMODE_DP, dp);
|
||||
4:aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
5:aa.b = op_read(OPMODE_DP, dp + 2);
|
||||
6:rd.l = op_read(OPMODE_LONG, aa.d);
|
||||
6:if($2)last_cycle();
|
||||
rd.l = op_read(OPMODE_LONG, aa.d);
|
||||
if($2) { op_$1_b(); end; }
|
||||
7:rd.h = op_read(OPMODE_LONG, aa.d + 1);
|
||||
7:last_cycle();
|
||||
rd.h = op_read(OPMODE_LONG, aa.d + 1);
|
||||
op_$1_w();
|
||||
}
|
||||
|
||||
@@ -233,9 +259,11 @@ sbc_ildpy(0xf7, sbc, regs.p.m) {
|
||||
3:aa.l = op_read(OPMODE_DP, dp);
|
||||
4:aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
5:aa.b = op_read(OPMODE_DP, dp + 2);
|
||||
6:rd.l = op_read(OPMODE_LONG, aa.d + regs.y.w);
|
||||
6:if($2)last_cycle();
|
||||
rd.l = op_read(OPMODE_LONG, aa.d + regs.y.w);
|
||||
if($2) { op_$1_b(); end; }
|
||||
7:rd.h = op_read(OPMODE_LONG, aa.d + regs.y.w + 1);
|
||||
7:last_cycle();
|
||||
rd.h = op_read(OPMODE_LONG, aa.d + regs.y.w + 1);
|
||||
op_$1_w();
|
||||
}
|
||||
|
||||
@@ -248,9 +276,11 @@ ora_sr(0x03, ora, regs.p.m),
|
||||
sbc_sr(0xe3, sbc, regs.p.m) {
|
||||
1:sp = op_read();
|
||||
2:cpu_io();
|
||||
3:rd.l = op_read(OPMODE_SP, sp);
|
||||
3:if($2)last_cycle();
|
||||
rd.l = op_read(OPMODE_SP, sp);
|
||||
if($2) { op_$1_b(); end; }
|
||||
4:rd.h = op_read(OPMODE_SP, sp + 1);
|
||||
4:last_cycle();
|
||||
rd.h = op_read(OPMODE_SP, sp + 1);
|
||||
op_$1_w();
|
||||
}
|
||||
|
||||
@@ -266,18 +296,22 @@ sbc_isry(0xf3, sbc) {
|
||||
3:aa.l = op_read(OPMODE_SP, sp);
|
||||
4:aa.h = op_read(OPMODE_SP, sp + 1);
|
||||
5:cpu_io();
|
||||
6:rd.l = op_read(OPMODE_DBR, aa.w + regs.y.w);
|
||||
6:if(regs.p.m)last_cycle();
|
||||
rd.l = op_read(OPMODE_DBR, aa.w + regs.y.w);
|
||||
if(regs.p.m) { op_$1_b(); end; }
|
||||
7:rd.h = op_read(OPMODE_DBR, aa.w + regs.y.w + 1);
|
||||
7:last_cycle();
|
||||
rd.h = op_read(OPMODE_DBR, aa.w + regs.y.w + 1);
|
||||
op_$1_w();
|
||||
}
|
||||
|
||||
bit_const(0x89) {
|
||||
1:rd.l = op_read();
|
||||
1:if(regs.p.m)last_cycle();
|
||||
rd.l = op_read();
|
||||
if(regs.p.m) {
|
||||
regs.p.z = ((rd.l & regs.a.l) == 0);
|
||||
end;
|
||||
}
|
||||
2:rd.h = op_read();
|
||||
2:last_cycle();
|
||||
rd.h = op_read();
|
||||
regs.p.z = ((rd.w & regs.a.w) == 0);
|
||||
}
|
||||
|
@@ -1,7 +1,8 @@
|
||||
inc(0x1a, regs.p.m, a),
|
||||
inx(0xe8, regs.p.x, x),
|
||||
iny(0xc8, regs.p.x, y) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
if($1) {
|
||||
regs.$2.l++;
|
||||
regs.p.n = !!(regs.$2.l & 0x80);
|
||||
@@ -16,7 +17,8 @@ iny(0xc8, regs.p.x, y) {
|
||||
dec(0x3a, regs.p.m, a),
|
||||
dex(0xca, regs.p.x, x),
|
||||
dey(0x88, regs.p.x, y) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
if($1) {
|
||||
regs.$2.l--;
|
||||
regs.p.n = !!(regs.$2.l & 0x80);
|
||||
@@ -29,7 +31,8 @@ dey(0x88, regs.p.x, y) {
|
||||
}
|
||||
|
||||
asl(0x0a) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.m) {
|
||||
regs.p.c = !!(regs.a.l & 0x80);
|
||||
regs.a.l <<= 1;
|
||||
@@ -44,7 +47,8 @@ asl(0x0a) {
|
||||
}
|
||||
|
||||
lsr(0x4a) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.m) {
|
||||
regs.p.c = regs.a.l & 1;
|
||||
regs.a.l >>= 1;
|
||||
@@ -59,7 +63,8 @@ lsr(0x4a) {
|
||||
}
|
||||
|
||||
rol(0x2a) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
uint16 c = regs.p.c;
|
||||
if(regs.p.m) {
|
||||
regs.p.c = !!(regs.a.l & 0x80);
|
||||
@@ -77,7 +82,8 @@ rol(0x2a) {
|
||||
}
|
||||
|
||||
ror(0x6a) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
uint16 c;
|
||||
if(regs.p.m) {
|
||||
c = (regs.p.c)?0x80:0;
|
||||
@@ -113,7 +119,8 @@ tsb_addr(0x0c, tsb) {
|
||||
if(regs.p.m) { op_$1_b(); skip; }
|
||||
else op_$1_w();
|
||||
6:op_write(OPMODE_DBR, aa.w + 1, rd.h);
|
||||
7:op_write(OPMODE_DBR, aa.w, rd.l);
|
||||
7:last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, rd.l);
|
||||
}
|
||||
|
||||
inc_addrx(0xfe, inc),
|
||||
@@ -132,7 +139,8 @@ ror_addrx(0x7e, ror) {
|
||||
if(regs.p.m) { op_$1_b(); skip; }
|
||||
else op_$1_w();
|
||||
7:op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
|
||||
8:op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
|
||||
8:last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
|
||||
}
|
||||
|
||||
inc_dp(0xe6, inc),
|
||||
@@ -152,7 +160,8 @@ tsb_dp(0x04, tsb) {
|
||||
if(regs.p.m) { op_$1_b(); skip; }
|
||||
else op_$1_w();
|
||||
6:op_write(OPMODE_DP, dp + 1, rd.h);
|
||||
7:op_write(OPMODE_DP, dp, rd.l);
|
||||
7:last_cycle();
|
||||
op_write(OPMODE_DP, dp, rd.l);
|
||||
}
|
||||
|
||||
inc_dpx(0xf6, inc),
|
||||
@@ -171,5 +180,6 @@ ror_dpx(0x76, ror) {
|
||||
if(regs.p.m) { op_$1_b(); skip; }
|
||||
else op_$1_w();
|
||||
7:op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
|
||||
8:op_write(OPMODE_DP, dp + regs.x.w, rd.l);
|
||||
8:last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
|
||||
}
|
||||
|
@@ -4,9 +4,11 @@ sty_addr(0x8c, regs.p.x, regs.y.w),
|
||||
stz_addr(0x9c, regs.p.m, 0x0000) {
|
||||
1:aa.l = op_read();
|
||||
2:aa.h = op_read();
|
||||
3:op_write(OPMODE_DBR, aa.w, $2);
|
||||
3:if($1)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, $2);
|
||||
if($1)end;
|
||||
4:op_write(OPMODE_DBR, aa.w + 1, $2 >> 8);
|
||||
4:last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, $2 >> 8);
|
||||
}
|
||||
|
||||
sta_addrx(0x9d, regs.p.m, regs.a.w),
|
||||
@@ -14,36 +16,44 @@ stz_addrx(0x9e, regs.p.m, 0x0000) {
|
||||
1:aa.l = op_read();
|
||||
2:aa.h = op_read();
|
||||
3:cpu_c4(aa.w, aa.w + regs.x.w);
|
||||
4:op_write(OPMODE_DBR, aa.w + regs.x.w, $2);
|
||||
4:if($1)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, $2);
|
||||
if($1)end;
|
||||
5:op_write(OPMODE_DBR, aa.w + regs.x.w + 1, $2 >> 8);
|
||||
5:last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, $2 >> 8);
|
||||
}
|
||||
|
||||
sta_addry(0x99) {
|
||||
1:aa.l = op_read();
|
||||
2:aa.h = op_read();
|
||||
3:cpu_c4(aa.w, aa.w + regs.y.w);
|
||||
4:op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
4:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
5:op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
5:last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
}
|
||||
|
||||
sta_long(0x8f) {
|
||||
1:aa.l = op_read();
|
||||
2:aa.h = op_read();
|
||||
3:aa.b = op_read();
|
||||
4:op_write(OPMODE_LONG, aa.d, regs.a.l);
|
||||
4:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
5:op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
|
||||
5:last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
|
||||
}
|
||||
|
||||
sta_longx(0x9f) {
|
||||
1:aa.l = op_read();
|
||||
2:aa.h = op_read();
|
||||
3:aa.b = op_read();
|
||||
4:op_write(OPMODE_LONG, aa.d + regs.x.w, regs.a.l);
|
||||
4:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.x.w, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
5:op_write(OPMODE_LONG, aa.d + regs.x.w + 1, regs.a.h);
|
||||
5:last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.x.w + 1, regs.a.h);
|
||||
}
|
||||
|
||||
sta_dp(0x85, regs.p.m, regs.a.w),
|
||||
@@ -52,9 +62,11 @@ sty_dp(0x84, regs.p.x, regs.y.w),
|
||||
stz_dp(0x64, regs.p.m, 0x0000) {
|
||||
1:dp = op_read();
|
||||
2:cpu_c2();
|
||||
3:op_write(OPMODE_DP, dp, $2);
|
||||
3:if($1)last_cycle();
|
||||
op_write(OPMODE_DP, dp, $2);
|
||||
if($1)end;
|
||||
4:op_write(OPMODE_DP, dp + 1, $2 >> 8);
|
||||
4:last_cycle();
|
||||
op_write(OPMODE_DP, dp + 1, $2 >> 8);
|
||||
}
|
||||
|
||||
sta_dpx(0x95, regs.p.m, regs.a.w),
|
||||
@@ -63,18 +75,22 @@ stz_dpx(0x74, regs.p.m, 0x0000) {
|
||||
1:dp = op_read();
|
||||
2:cpu_c2();
|
||||
3:cpu_io();
|
||||
4:op_write(OPMODE_DP, dp + regs.x.w, $2);
|
||||
4:if($1)last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, $2);
|
||||
if($1)end;
|
||||
5:op_write(OPMODE_DP, dp + regs.x.w + 1, $2 >> 8);
|
||||
5:last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, $2 >> 8);
|
||||
}
|
||||
|
||||
stx_dpy(0x96) {
|
||||
1:dp = op_read();
|
||||
2:cpu_c2();
|
||||
3:cpu_io();
|
||||
4:op_write(OPMODE_DP, dp + regs.y.w, regs.x.l);
|
||||
4:if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.y.w, regs.x.l);
|
||||
if(regs.p.x)end;
|
||||
5:op_write(OPMODE_DP, dp + regs.y.w + 1, regs.x.h);
|
||||
5:last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.y.w + 1, regs.x.h);
|
||||
}
|
||||
|
||||
sta_idp(0x92) {
|
||||
@@ -82,9 +98,11 @@ sta_idp(0x92) {
|
||||
2:cpu_c2();
|
||||
3:aa.l = op_read(OPMODE_DP, dp);
|
||||
4:aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
5:op_write(OPMODE_DBR, aa.w, regs.a.l);
|
||||
5:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
6:op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
|
||||
6:last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
|
||||
}
|
||||
|
||||
sta_ildp(0x87) {
|
||||
@@ -93,9 +111,11 @@ sta_ildp(0x87) {
|
||||
3:aa.l = op_read(OPMODE_DP, dp);
|
||||
4:aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
5:aa.b = op_read(OPMODE_DP, dp + 2);
|
||||
6:op_write(OPMODE_LONG, aa.d, regs.a.l);
|
||||
6:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
7:op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
|
||||
7:last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
|
||||
}
|
||||
|
||||
sta_idpx(0x81) {
|
||||
@@ -104,9 +124,11 @@ sta_idpx(0x81) {
|
||||
3:cpu_io();
|
||||
4:aa.l = op_read(OPMODE_DP, dp + regs.x.w);
|
||||
5:aa.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
|
||||
6:op_write(OPMODE_DBR, aa.w, regs.a.l);
|
||||
6:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
7:op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
|
||||
7:last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
|
||||
}
|
||||
|
||||
sta_idpy(0x91) {
|
||||
@@ -115,9 +137,11 @@ sta_idpy(0x91) {
|
||||
3:aa.l = op_read(OPMODE_DP, dp);
|
||||
4:aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
5:cpu_c4(aa.w, aa.w + regs.y.w);
|
||||
6:op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
6:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
7:op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
7:last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
}
|
||||
|
||||
sta_ildpy(0x97) {
|
||||
@@ -126,17 +150,21 @@ sta_ildpy(0x97) {
|
||||
3:aa.l = op_read(OPMODE_DP, dp);
|
||||
4:aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
5:aa.b = op_read(OPMODE_DP, dp + 2);
|
||||
6:op_write(OPMODE_LONG, aa.d + regs.y.w, regs.a.l);
|
||||
6:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
7:op_write(OPMODE_LONG, aa.d + regs.y.w + 1, regs.a.h);
|
||||
7:last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.y.w + 1, regs.a.h);
|
||||
}
|
||||
|
||||
sta_sr(0x83) {
|
||||
1:sp = op_read();
|
||||
2:cpu_io();
|
||||
3:op_write(OPMODE_SP, sp, regs.a.l);
|
||||
3:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_SP, sp, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
4:op_write(OPMODE_SP, sp + 1, regs.a.h);
|
||||
4:last_cycle();
|
||||
op_write(OPMODE_SP, sp + 1, regs.a.h);
|
||||
}
|
||||
|
||||
sta_isry(0x93) {
|
||||
@@ -145,7 +173,9 @@ sta_isry(0x93) {
|
||||
3:aa.l = op_read(OPMODE_SP, sp);
|
||||
4:aa.h = op_read(OPMODE_SP, sp + 1);
|
||||
5:cpu_io();
|
||||
6:op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
6:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
7:op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
7:last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
}
|
||||
|
@@ -2,5 +2,6 @@
|
||||
#include "dcpu.cpp"
|
||||
|
||||
CPU::CPU() {
|
||||
cpu_version = 1;
|
||||
mmio = &mmio_unmapped;
|
||||
}
|
||||
|
@@ -2,6 +2,12 @@
|
||||
|
||||
class CPU {
|
||||
public:
|
||||
//CPU version number
|
||||
//* 1 and 2 are known
|
||||
//* reported by $4210
|
||||
//* affects DRAM refresh behavior
|
||||
uint8 cpu_version;
|
||||
|
||||
//timing
|
||||
virtual uint16 vcounter() = 0;
|
||||
virtual uint16 hcounter() = 0;
|
||||
@@ -9,7 +15,7 @@ public:
|
||||
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); }
|
||||
|
586
src/dsp/bdsp/bdsp.cpp
Normal file
586
src/dsp/bdsp/bdsp.cpp
Normal file
@@ -0,0 +1,586 @@
|
||||
#include "../../base.h"
|
||||
#include "bdsp_tables.cpp"
|
||||
|
||||
uint8 bDSP::read_8 (uint16 addr) { return (spcram[addr]); }
|
||||
uint16 bDSP::read_16 (uint16 addr) { return (spcram[(addr + 1) & 0xffff] << 8) + (spcram[addr]); }
|
||||
void bDSP::write_8 (uint16 addr, uint8 data) { spcram[addr] = data; }
|
||||
void bDSP::write_16(uint16 addr, uint16 data) { spcram[addr++] = data; spcram[addr] = data >> 8; }
|
||||
|
||||
uint8 bDSP::read(uint8 addr) {
|
||||
int i, v, n;
|
||||
addr &= 127;
|
||||
v = addr >> 4;
|
||||
n = addr & 15;
|
||||
|
||||
switch(addr) {
|
||||
case 0x00:case 0x10:case 0x20:case 0x30:
|
||||
case 0x40:case 0x50:case 0x60:case 0x70:
|
||||
return voice[v].VOLL;
|
||||
case 0x01:case 0x11:case 0x21:case 0x31:
|
||||
case 0x41:case 0x51:case 0x61:case 0x71:
|
||||
return voice[v].VOLR;
|
||||
case 0x02:case 0x12:case 0x22:case 0x32:
|
||||
case 0x42:case 0x52:case 0x62:case 0x72:
|
||||
return voice[v].PITCH >> 8;
|
||||
case 0x03:case 0x13:case 0x23:case 0x33:
|
||||
case 0x43:case 0x53:case 0x63:case 0x73:
|
||||
return voice[v].PITCH;
|
||||
case 0x04:case 0x14:case 0x24:case 0x34:
|
||||
case 0x44:case 0x54:case 0x64:case 0x74:
|
||||
return voice[v].SRCN;
|
||||
case 0x05:case 0x15:case 0x25:case 0x35:
|
||||
case 0x45:case 0x55:case 0x65:case 0x75:
|
||||
return voice[v].ADSR1;
|
||||
case 0x06:case 0x16:case 0x26:case 0x36:
|
||||
case 0x46:case 0x56:case 0x66:case 0x76:
|
||||
return voice[v].ADSR2;
|
||||
case 0x07:case 0x17:case 0x27:case 0x37:
|
||||
case 0x47:case 0x57:case 0x67:case 0x77:
|
||||
return voice[v].GAIN;
|
||||
case 0x08:case 0x18:case 0x28:case 0x38:
|
||||
case 0x48:case 0x58:case 0x68:case 0x78:
|
||||
return voice[v].ENVX;
|
||||
case 0x09:case 0x19:case 0x29:case 0x39:
|
||||
case 0x49:case 0x59:case 0x69:case 0x79:
|
||||
return voice[v].OUTX;
|
||||
|
||||
case 0x0f:case 0x1f:case 0x2f:case 0x3f:
|
||||
case 0x4f:case 0x5f:case 0x6f:case 0x7f:
|
||||
return status.FIR[v];
|
||||
|
||||
case 0x0c:return status.MVOLL;
|
||||
case 0x1c:return status.MVOLR;
|
||||
case 0x2c:return status.EVOLL;
|
||||
case 0x3c:return status.EVOLR;
|
||||
case 0x4c:return status.KON;
|
||||
case 0x5c:return status.KOFF;
|
||||
case 0x6c:return status.FLG;
|
||||
case 0x7c:return status.ENDX;
|
||||
|
||||
case 0x0d:return status.EFB;
|
||||
case 0x2d:return status.PMON;
|
||||
case 0x3d:return status.NON;
|
||||
case 0x4d:return status.EON;
|
||||
case 0x5d:return status.DIR;
|
||||
case 0x6d:return status.ESA;
|
||||
case 0x7d:return status.EDL;
|
||||
}
|
||||
|
||||
return dspram[addr];
|
||||
}
|
||||
|
||||
void bDSP::write(uint8 addr, uint8 data) {
|
||||
int i, v, n;
|
||||
//0x80-0xff is a read-only mirror of 0x00-0x7f
|
||||
if(addr & 0x80)return;
|
||||
|
||||
v = addr >> 4;
|
||||
n = addr & 15;
|
||||
|
||||
switch(addr) {
|
||||
case 0x00:case 0x10:case 0x20:case 0x30:
|
||||
case 0x40:case 0x50:case 0x60:case 0x70:
|
||||
voice[v].VOLL = data;
|
||||
break;
|
||||
case 0x01:case 0x11:case 0x21:case 0x31:
|
||||
case 0x41:case 0x51:case 0x61:case 0x71:
|
||||
voice[v].VOLR = data;
|
||||
break;
|
||||
case 0x02:case 0x12:case 0x22:case 0x32:
|
||||
case 0x42:case 0x52:case 0x62:case 0x72:
|
||||
voice[v].PITCH &= 0xff00;
|
||||
voice[v].PITCH |= data;
|
||||
break;
|
||||
case 0x03:case 0x13:case 0x23:case 0x33:
|
||||
case 0x43:case 0x53:case 0x63:case 0x73:
|
||||
voice[v].PITCH &= 0x00ff;
|
||||
voice[v].PITCH |= data << 8;
|
||||
break;
|
||||
case 0x04:case 0x14:case 0x24:case 0x34:
|
||||
case 0x44:case 0x54:case 0x64:case 0x74:
|
||||
//voice[v].SRCN = data;
|
||||
//below is anomie's code, but TRAC says writing SRCN doesn't affect anything until a
|
||||
//BRR-with-end block is encountered, where it loads the loop address from the new SRCN
|
||||
if(voice[v].SRCN != data) {
|
||||
voice[v].SRCN = data;
|
||||
voice[v].brr_ptr = read_16((status.DIR << 8) + (voice[v].SRCN << 2) + ((voice[v].brr_looped)?2:0));
|
||||
voice[v].brr_index = 0;
|
||||
}
|
||||
break;
|
||||
case 0x05:case 0x15:case 0x25:case 0x35:
|
||||
case 0x45:case 0x55:case 0x65:case 0x75:
|
||||
voice[v].ADSR1 = data;
|
||||
voice[v].AdjustEnvelope();
|
||||
break;
|
||||
case 0x06:case 0x16:case 0x26:case 0x36:
|
||||
case 0x46:case 0x56:case 0x66:case 0x76:
|
||||
voice[v].ADSR2 = data;
|
||||
//sustain_level = 0-7, 7 is a special case handled by ATTACK envx mode
|
||||
voice[v].env_sustain = (voice[v].ADSR_sus_level() + 1) << 8;
|
||||
voice[v].AdjustEnvelope();
|
||||
break;
|
||||
case 0x07:case 0x17:case 0x27:case 0x37:
|
||||
case 0x47:case 0x57:case 0x67:case 0x77:
|
||||
voice[v].GAIN = data;
|
||||
voice[v].AdjustEnvelope();
|
||||
break;
|
||||
case 0x08:case 0x18:case 0x28:case 0x38:
|
||||
case 0x48:case 0x58:case 0x68:case 0x78:
|
||||
voice[v].ENVX = data;
|
||||
break;
|
||||
case 0x09:case 0x19:case 0x29:case 0x39:
|
||||
case 0x49:case 0x59:case 0x69:case 0x79:
|
||||
voice[v].OUTX = data;
|
||||
break;
|
||||
|
||||
case 0x0f:case 0x1f:case 0x2f:case 0x3f:
|
||||
case 0x4f:case 0x5f:case 0x6f:case 0x7f:
|
||||
status.FIR[v] = data;
|
||||
break;
|
||||
|
||||
case 0x0c:status.MVOLL = data;break;
|
||||
case 0x1c:status.MVOLR = data;break;
|
||||
case 0x2c:status.EVOLL = data;break;
|
||||
case 0x3c:status.EVOLR = data;break;
|
||||
|
||||
case 0x4c:
|
||||
status.KON = data;
|
||||
// status.kon = data;
|
||||
status.key_flag = true;
|
||||
break;
|
||||
|
||||
case 0x5c:
|
||||
status.KOFF = data;
|
||||
status.key_flag = true;
|
||||
break;
|
||||
|
||||
case 0x6c:
|
||||
status.FLG = data;
|
||||
status.key_flag = true;
|
||||
status.noise_rate = RateTable[data & 0x1f];
|
||||
break;
|
||||
|
||||
case 0x7c:
|
||||
//read-only register, writes clear all bits of ENDX
|
||||
status.ENDX = 0;
|
||||
break;
|
||||
|
||||
case 0x0d:status.EFB = data;break;
|
||||
case 0x2d:status.PMON = data;break;
|
||||
case 0x3d:status.NON = data;break;
|
||||
case 0x4d:status.EON = data;break;
|
||||
case 0x5d:status.DIR = data;break;
|
||||
case 0x6d:status.ESA = data;break;
|
||||
|
||||
case 0x7d:
|
||||
status.EDL = data;
|
||||
status.echo_size = (data & 0x0f) << 11;
|
||||
break;
|
||||
}
|
||||
|
||||
dspram[addr] = data;
|
||||
}
|
||||
|
||||
void bDSP::power() {
|
||||
int v;
|
||||
spcram = apu->get_spcram_handle();
|
||||
memset(dspram, 0x00, 128);
|
||||
|
||||
for(v=0;v<8;v++) {
|
||||
voice[v].VOLL = 0;
|
||||
voice[v].VOLR = 0;
|
||||
voice[v].PITCH = 0;
|
||||
voice[v].SRCN = 0;
|
||||
voice[v].ADSR1 = 0;
|
||||
voice[v].ADSR2 = 0;
|
||||
voice[v].GAIN = 0;
|
||||
|
||||
status.FIR[v] = 0;
|
||||
}
|
||||
|
||||
status.MVOLL = status.MVOLR = 0;
|
||||
status.EVOLL = status.EVOLR = 0;
|
||||
status.ENDX = 0;
|
||||
status.EFB = 0;
|
||||
status.PMON = 0;
|
||||
status.NON = 0;
|
||||
status.EON = 0;
|
||||
status.DIR = 0;
|
||||
status.ESA = 0;
|
||||
status.EDL = 0;
|
||||
|
||||
status.echo_size = 0;
|
||||
status.echo_target = 0;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void bDSP::reset() {
|
||||
int v;
|
||||
status.KON = 0x00;
|
||||
status.KOFF = 0x00;
|
||||
status.FLG |= 0xe0;
|
||||
|
||||
//status.kon = 0x00;
|
||||
status.key_flag = false;
|
||||
|
||||
status.noise_ctr = 0;
|
||||
status.noise_rate = 0;
|
||||
status.noise_sample = 0x4000;
|
||||
|
||||
status.echo_index = 0;
|
||||
status.fir_buffer_index = 0;
|
||||
|
||||
for(v=0;v<8;v++) {
|
||||
voice[v].ENVX = 0;
|
||||
voice[v].OUTX = 0;
|
||||
|
||||
voice[v].pitch_ctr = 0;
|
||||
|
||||
voice[v].brr_index = 0;
|
||||
voice[v].brr_ptr = read_16((status.DIR << 8) + (voice[v].SRCN << 2));
|
||||
voice[v].brr_looped = false;
|
||||
voice[v].brr_data[0] = 0;
|
||||
voice[v].brr_data[1] = 0;
|
||||
voice[v].brr_data[2] = 0;
|
||||
voice[v].brr_data[3] = 0;
|
||||
voice[v].brr_data_index = 0;
|
||||
|
||||
voice[v].envx = 0;
|
||||
voice[v].env_ctr = 0;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_state = SILENCE;
|
||||
voice[v].env_mode = DIRECT;
|
||||
|
||||
status.fir_buffer[0][v] = 0;
|
||||
status.fir_buffer[1][v] = 0;
|
||||
}
|
||||
|
||||
dsp_counter = 0;
|
||||
}
|
||||
|
||||
int32 bDSP::clamp(int32 bits, int32 x) {
|
||||
int32 b = 1 << (bits - 1);
|
||||
if(x > (b - 1)) {
|
||||
return (b - 1);
|
||||
} else if(x < -b) {
|
||||
return -b;
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int32 bDSP::clip(int32 bits, int32 x) {
|
||||
int32 b = 1 << (bits - 1);
|
||||
if(x & b) {
|
||||
return x | ~(b - 1);
|
||||
} else {
|
||||
return x & (b - 1);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 bDSP::run() {
|
||||
int v, d;
|
||||
uint8 pmon;
|
||||
int32 sample;
|
||||
int32 msamplel, msampler;
|
||||
int32 esamplel, esampler;
|
||||
int32 fir_samplel, fir_sampler;
|
||||
pmon = status.PMON & ~status.NON & ~1;
|
||||
|
||||
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 & mask) {
|
||||
if(voice[v].env_state != SILENCE && voice[v].env_state != RELEASE) {
|
||||
voice[v].env_state = RELEASE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
} 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;
|
||||
voice[v].brr_data[0] = 0;
|
||||
voice[v].brr_data[1] = 0;
|
||||
voice[v].brr_data[2] = 0;
|
||||
voice[v].brr_data[3] = 0;
|
||||
voice[v].envx = 0;
|
||||
voice[v].env_state = ATTACK;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
}
|
||||
// status.ENDX &= ~status.kon;
|
||||
// status.kon = 0;
|
||||
status.key_flag = false;
|
||||
}
|
||||
|
||||
//update noise
|
||||
status.noise_ctr += status.noise_rate;
|
||||
if(status.noise_ctr >= 0x7800) {
|
||||
status.noise_ctr -= 0x7800;
|
||||
status.noise_sample = (status.noise_sample >> 1) |
|
||||
(((status.noise_sample << 14) ^ (status.noise_sample << 13)) & 0x4000);
|
||||
}
|
||||
|
||||
msamplel = msampler = 0;
|
||||
esamplel = esampler = 0;
|
||||
|
||||
for(v=0;v<8;v++) {
|
||||
if(voice[v].brr_index < -1) {
|
||||
voice[v].brr_index++;
|
||||
voice[v].OUTX = voice[v].outx = 0;
|
||||
voice[v].ENVX = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(voice[v].brr_index >= 0) {
|
||||
if(pmon & (1 << v)) {
|
||||
voice[v].pitch_ctr += (voice[v].pitch_rate() * (voice[v - 1].outx + 0x8000)) >> 15;
|
||||
} else {
|
||||
voice[v].pitch_ctr += voice[v].pitch_rate();
|
||||
}
|
||||
} else {
|
||||
voice[v].pitch_ctr = 0x3000;
|
||||
voice[v].brr_index = 0;
|
||||
}
|
||||
|
||||
//decode BRR samples
|
||||
while(voice[v].pitch_ctr >= 0) {
|
||||
voice[v].pitch_ctr -= 0x1000;
|
||||
|
||||
voice[v].brr_data_index++;
|
||||
voice[v].brr_data_index &= 3;
|
||||
|
||||
if(voice[v].brr_index == 0) {
|
||||
voice[v].brr_header = read_8(voice[v].brr_ptr);
|
||||
|
||||
if(voice[v].brr_header_flags() & BRR_END) {
|
||||
status.ENDX |= (1 << v);
|
||||
}
|
||||
|
||||
if(voice[v].brr_header_flags() == BRR_END) {
|
||||
voice[v].env_state = SILENCE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
}
|
||||
|
||||
#define S(x) voice[v].brr_data[(voice[v].brr_data_index + (x)) & 3]
|
||||
if(voice[v].env_state != SILENCE) {
|
||||
sample = read_8(voice[v].brr_ptr + 1 + (voice[v].brr_index >> 1));
|
||||
if(voice[v].brr_index & 1) {
|
||||
sample = clip(4, sample);
|
||||
} else {
|
||||
sample = clip(4, sample >> 4);
|
||||
}
|
||||
|
||||
if(voice[v].brr_header_shift() <= 12) {
|
||||
sample = (sample << voice[v].brr_header_shift() >> 1);
|
||||
} else {
|
||||
sample &= ~0x7ff;
|
||||
}
|
||||
|
||||
switch(voice[v].brr_header_filter()) {
|
||||
case 0: //direct
|
||||
break;
|
||||
case 1: //15/16
|
||||
sample += S(-1) + ((-S(-1)) >> 4);
|
||||
break;
|
||||
case 2: //61/32 - 15/16
|
||||
sample += (S(-1) << 1) + ((-((S(-1) << 1) + S(-1))) >> 5)
|
||||
- S(-2) + (S(-2) >> 4);
|
||||
break;
|
||||
case 3: //115/64 - 13/16
|
||||
sample += (S(-1) << 1) + ((-(S(-1) + (S(-1) << 2) + (S(-1) << 3))) >> 6)
|
||||
- S(-2) + (((S(-2) << 1) + S(-2)) >> 4);
|
||||
break;
|
||||
}
|
||||
|
||||
S(0) = sample = clip(15, clamp(16, sample));
|
||||
} else {
|
||||
S(0) = sample = 0;
|
||||
}
|
||||
|
||||
if(++voice[v].brr_index > 15) {
|
||||
voice[v].brr_index = 0;
|
||||
if(voice[v].brr_header_flags() & BRR_END) {
|
||||
voice[v].brr_ptr = read_16((status.DIR << 8) + (voice[v].SRCN << 2) + 2);
|
||||
voice[v].brr_looped = true;
|
||||
} else {
|
||||
voice[v].brr_ptr += 9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//volume envelope adjust
|
||||
voice[v].env_ctr += voice[v].env_rate;
|
||||
|
||||
if(voice[v].env_ctr >= 0x7800) {
|
||||
voice[v].env_ctr -= 0x7800;
|
||||
switch(voice[v].env_mode) {
|
||||
case DIRECT:
|
||||
voice[v].env_rate = 0;
|
||||
break;
|
||||
case LINEAR_DEC:
|
||||
voice[v].envx -= 32;
|
||||
if(voice[v].envx <= 0) {
|
||||
voice[v].envx = 0;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_mode = DIRECT;
|
||||
}
|
||||
break;
|
||||
case LINEAR_INC:
|
||||
voice[v].envx += 32;
|
||||
if(voice[v].envx >= 0x7ff) {
|
||||
voice[v].envx = 0x7ff;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_mode = DIRECT;
|
||||
if(voice[v].ADSR_enabled() && voice[v].env_state == ATTACK) {
|
||||
voice[v].env_state = ((voice[v].env_sustain == 0x800) ? SUSTAIN : DECAY);
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EXP_DEC:
|
||||
//multiply by 255/256ths
|
||||
voice[v].envx -= ((voice[v].envx - 1) >> 8) + 1;
|
||||
if(voice[v].ADSR_enabled() && voice[v].env_state == DECAY && voice[v].envx <= voice[v].env_sustain) {
|
||||
voice[v].env_state = SUSTAIN;
|
||||
voice[v].AdjustEnvelope();
|
||||
} else if(voice[v].envx <= 0) {
|
||||
voice[v].envx = 0;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_mode = DIRECT;
|
||||
}
|
||||
break;
|
||||
case BENT_INC:
|
||||
if(voice[v].envx < 0x600) {
|
||||
voice[v].envx += 32;
|
||||
} else {
|
||||
voice[v].envx += 8;
|
||||
|
||||
if(voice[v].envx >= 0x7ff) {
|
||||
voice[v].envx = 0x7ff;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_mode = DIRECT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FAST_ATTACK:
|
||||
voice[v].envx += 0x400;
|
||||
if(voice[v].envx >= 0x7ff) {
|
||||
voice[v].envx = 0x7ff;
|
||||
|
||||
//attack raises to max. envx, if sustain is also set to max. envx, skip decay phase
|
||||
voice[v].env_state = ((voice[v].env_sustain == 0x800) ? SUSTAIN : DECAY);
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
break;
|
||||
case RELEASE_DEC:
|
||||
voice[v].envx -= 8;
|
||||
if(voice[v].envx <= 0) {
|
||||
voice[v].env_state = SILENCE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
voice[v].ENVX = voice[v].envx >> 4;
|
||||
|
||||
//gaussian interpolation / noise
|
||||
if(status.NON & (1 << v)) {
|
||||
sample = status.noise_sample;
|
||||
} else {
|
||||
d = voice[v].pitch_ctr >> 4; //-256 <= sample <= -1
|
||||
sample = ((GaussTable[ -1-d] * S(-3)) >> 11);
|
||||
sample += ((GaussTable[255-d] * S(-2)) >> 11);
|
||||
sample += ((GaussTable[512+d] * S(-1)) >> 11);
|
||||
sample = clip (15, sample);
|
||||
sample += ((GaussTable[256+d] * S( 0)) >> 11);
|
||||
sample = clamp(15, sample);
|
||||
}
|
||||
#undef S
|
||||
|
||||
//envelope / volume adjust
|
||||
sample = (sample * voice[v].envx) >> 11;
|
||||
voice[v].outx = sample << 1;
|
||||
voice[v].OUTX = sample >> 7;
|
||||
|
||||
if(!status.mute()) {
|
||||
msamplel += ((sample * voice[v].VOLL) >> 7) << 1;
|
||||
msampler += ((sample * voice[v].VOLR) >> 7) << 1;
|
||||
}
|
||||
|
||||
if((status.EON & (1 << v)) && status.echo_write()) {
|
||||
esamplel += ((sample * voice[v].VOLL) >> 7) << 1;
|
||||
esampler += ((sample * voice[v].VOLR) >> 7) << 1;
|
||||
}
|
||||
}
|
||||
|
||||
//echo (FIR) adjust
|
||||
#define F(c,x) status.fir_buffer[c][(status.fir_buffer_index+(x)) & 7]
|
||||
status.fir_buffer_index++;
|
||||
F(0,0) = read_16((status.ESA << 8) + status.echo_index);
|
||||
F(1,0) = read_16((status.ESA << 8) + status.echo_index + 2);
|
||||
|
||||
fir_samplel = (F(0,-0) * status.FIR[7] +
|
||||
F(0,-1) * status.FIR[6] +
|
||||
F(0,-2) * status.FIR[5] +
|
||||
F(0,-3) * status.FIR[4] +
|
||||
F(0,-4) * status.FIR[3] +
|
||||
F(0,-5) * status.FIR[2] +
|
||||
F(0,-6) * status.FIR[1] +
|
||||
F(0,-7) * status.FIR[0]);
|
||||
|
||||
fir_sampler = (F(1,-0) * status.FIR[7] +
|
||||
F(1,-1) * status.FIR[6] +
|
||||
F(1,-2) * status.FIR[5] +
|
||||
F(1,-3) * status.FIR[4] +
|
||||
F(1,-4) * status.FIR[3] +
|
||||
F(1,-5) * status.FIR[2] +
|
||||
F(1,-6) * status.FIR[1] +
|
||||
F(1,-7) * status.FIR[0]);
|
||||
#undef F
|
||||
|
||||
//update echo buffer
|
||||
if(status.echo_write()) {
|
||||
esamplel += (fir_samplel * status.EFB) >> 14;
|
||||
esampler += (fir_sampler * status.EFB) >> 14;
|
||||
|
||||
esamplel = clamp(16, esamplel);
|
||||
esampler = clamp(16, esampler);
|
||||
|
||||
write_16((status.ESA << 8) + status.echo_index, esamplel);
|
||||
write_16((status.ESA << 8) + status.echo_index + 2, esampler);
|
||||
}
|
||||
|
||||
status.echo_index += 4;
|
||||
if(status.echo_index >= status.echo_target) {
|
||||
status.echo_index = 0;
|
||||
status.echo_target = status.echo_size;
|
||||
}
|
||||
|
||||
//main output adjust
|
||||
if(!status.mute()) {
|
||||
msamplel = (msamplel * status.MVOLL) >> 7;
|
||||
msampler = (msampler * status.MVOLR) >> 7;
|
||||
|
||||
msamplel += (fir_samplel * status.EVOLL) >> 14;
|
||||
msampler += (fir_sampler * status.EVOLR) >> 14;
|
||||
|
||||
msamplel = clamp(16, msamplel);
|
||||
msampler = clamp(16, msampler);
|
||||
}
|
||||
|
||||
return (uint32)(((uint16)msamplel) | ((uint16)msampler << 16));
|
||||
}
|
||||
|
||||
bDSP::bDSP() {}
|
||||
bDSP::~bDSP() {}
|
176
src/dsp/bdsp/bdsp.h
Normal file
176
src/dsp/bdsp/bdsp.h
Normal file
@@ -0,0 +1,176 @@
|
||||
class bDSP : public DSP {
|
||||
private:
|
||||
uint8 dspram[128];
|
||||
uint8 *spcram;
|
||||
|
||||
uint32 dsp_counter;
|
||||
|
||||
enum {
|
||||
BRR_END = 1,
|
||||
BRR_LOOP = 2
|
||||
};
|
||||
|
||||
uint8 read_8 (uint16 addr);
|
||||
uint16 read_16 (uint16 addr);
|
||||
void write_8 (uint16 addr, uint8 data);
|
||||
void write_16(uint16 addr, uint16 data);
|
||||
|
||||
public:
|
||||
static const uint16 RateTable[32];
|
||||
static const int16 GaussTable[512];
|
||||
|
||||
enum EnvelopeStates {
|
||||
ATTACK,
|
||||
DECAY,
|
||||
SUSTAIN,
|
||||
RELEASE,
|
||||
SILENCE
|
||||
};
|
||||
|
||||
enum EnvelopeModes {
|
||||
DIRECT,
|
||||
LINEAR_DEC,
|
||||
EXP_DEC,
|
||||
LINEAR_INC,
|
||||
BENT_INC,
|
||||
|
||||
FAST_ATTACK,
|
||||
RELEASE_DEC
|
||||
};
|
||||
|
||||
private:
|
||||
struct Status {
|
||||
//$0c,$1c
|
||||
int8 MVOLL, MVOLR;
|
||||
//$2c,$3c
|
||||
int8 EVOLL, EVOLR;
|
||||
//$4c,$5c
|
||||
uint8 KON, KOFF;
|
||||
//$6c
|
||||
uint8 FLG;
|
||||
//$7c
|
||||
uint8 ENDX;
|
||||
//$0d
|
||||
int8 EFB;
|
||||
//$2d,$3d,$4d
|
||||
uint8 PMON, NON, EON;
|
||||
//$5d
|
||||
uint8 DIR;
|
||||
//$6d,$7d
|
||||
uint8 ESA, EDL;
|
||||
|
||||
//$xf
|
||||
int8 FIR[8];
|
||||
|
||||
//internal variables
|
||||
//uint8 kon;
|
||||
bool key_flag;
|
||||
|
||||
int16 noise_ctr, noise_rate;
|
||||
uint16 noise_sample;
|
||||
|
||||
uint16 echo_index, echo_size, echo_target;
|
||||
int16 fir_buffer[2][8];
|
||||
uint8 fir_buffer_index;
|
||||
|
||||
//functions
|
||||
bool soft_reset() { return !!(FLG & 0x80); }
|
||||
bool mute() { return !!(FLG & 0x40); }
|
||||
bool echo_write() { return !(FLG & 0x20); }
|
||||
} status;
|
||||
|
||||
struct Voice {
|
||||
//$x0-$x1
|
||||
int8 VOLL, VOLR;
|
||||
//$x2-$x3
|
||||
int16 PITCH;
|
||||
//$x4
|
||||
uint8 SRCN;
|
||||
//$x5-$x7
|
||||
uint8 ADSR1, ADSR2, GAIN;
|
||||
//$x8-$x9
|
||||
uint8 ENVX, OUTX;
|
||||
|
||||
//internal variables
|
||||
int16 pitch_ctr;
|
||||
|
||||
int8 brr_index;
|
||||
uint16 brr_ptr;
|
||||
uint8 brr_header;
|
||||
bool brr_looped;
|
||||
|
||||
int16 brr_data[4];
|
||||
uint8 brr_data_index;
|
||||
|
||||
int16 envx;
|
||||
uint16 env_ctr, env_rate, env_sustain;
|
||||
enum EnvelopeStates env_state;
|
||||
enum EnvelopeModes env_mode;
|
||||
|
||||
int16 outx;
|
||||
|
||||
//functions
|
||||
int16 pitch_rate() { return PITCH & 0x3fff; }
|
||||
|
||||
uint8 brr_header_shift() { return brr_header >> 4; }
|
||||
uint8 brr_header_filter() { return (brr_header >> 2) & 3; }
|
||||
uint8 brr_header_flags() { return brr_header & 3; }
|
||||
|
||||
bool ADSR_enabled() { return !!(ADSR1 & 0x80); }
|
||||
uint8 ADSR_decay() { return (ADSR1 >> 4) & 7; }
|
||||
uint8 ADSR_attack() { return ADSR1 & 15; }
|
||||
uint8 ADSR_sus_level() { return ADSR2 >> 5; }
|
||||
uint8 ADSR_sus_rate() { return ADSR2 & 31; }
|
||||
|
||||
void AdjustEnvelope() {
|
||||
if(env_state == SILENCE) {
|
||||
env_mode = DIRECT;
|
||||
env_rate = 0;
|
||||
envx = 0;
|
||||
} else if(env_state == RELEASE) {
|
||||
env_mode = RELEASE_DEC;
|
||||
env_rate = 0x7800;
|
||||
} else if(ADSR_enabled()) {
|
||||
switch(env_state) {
|
||||
case ATTACK:
|
||||
env_rate = RateTable[(ADSR_attack() << 1) + 1];
|
||||
env_mode = (env_rate == 0x7800) ? FAST_ATTACK : LINEAR_INC;
|
||||
break;
|
||||
case DECAY:
|
||||
env_rate = RateTable[(ADSR_decay() << 1) + 0x10];
|
||||
env_mode = EXP_DEC;
|
||||
break;
|
||||
case SUSTAIN:
|
||||
env_rate = RateTable[ADSR_sus_rate()];
|
||||
env_mode = (env_rate == 0) ? DIRECT : EXP_DEC;
|
||||
break;
|
||||
}
|
||||
} else if(GAIN & 0x80) {
|
||||
switch(GAIN & 0x60) {
|
||||
case 0x00:env_mode = LINEAR_DEC; break;
|
||||
case 0x20:env_mode = EXP_DEC; break;
|
||||
case 0x40:env_mode = LINEAR_INC; break;
|
||||
case 0x60:env_mode = BENT_INC; break;
|
||||
}
|
||||
env_rate = RateTable[GAIN & 0x1f];
|
||||
} else {
|
||||
env_mode = DIRECT;
|
||||
env_rate = 0;
|
||||
envx = (GAIN & 0x7f) << 4;
|
||||
}
|
||||
}
|
||||
} voice[8];
|
||||
|
||||
int32 clamp(int32 bits, int32 x);
|
||||
int32 clip (int32 bits, int32 x);
|
||||
public:
|
||||
uint8 read (uint8 addr);
|
||||
void write(uint8 addr, uint8 data);
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
uint32 run();
|
||||
|
||||
bDSP();
|
||||
~bDSP();
|
||||
};
|
73
src/dsp/bdsp/bdsp_tables.cpp
Normal file
73
src/dsp/bdsp/bdsp_tables.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
const uint16 bDSP::RateTable[32] = {
|
||||
0x0000, 0x000F, 0x0014, 0x0018, 0x001E, 0x0028, 0x0030, 0x003C,
|
||||
0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180,
|
||||
0x01E0, 0x0280, 0x0300, 0x03C0, 0x0500, 0x0600, 0x0780, 0x0A00,
|
||||
0x0C00, 0x0F00, 0x1400, 0x1800, 0x1E00, 0x2800, 0x3C00, 0x7800
|
||||
};
|
||||
|
||||
const int16 bDSP::GaussTable[512] = {
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001,
|
||||
0x001, 0x001, 0x001, 0x002, 0x002, 0x002, 0x002, 0x002,
|
||||
0x002, 0x002, 0x003, 0x003, 0x003, 0x003, 0x003, 0x004,
|
||||
0x004, 0x004, 0x004, 0x004, 0x005, 0x005, 0x005, 0x005,
|
||||
0x006, 0x006, 0x006, 0x006, 0x007, 0x007, 0x007, 0x008,
|
||||
0x008, 0x008, 0x009, 0x009, 0x009, 0x00A, 0x00A, 0x00A,
|
||||
0x00B, 0x00B, 0x00B, 0x00C, 0x00C, 0x00D, 0x00D, 0x00E,
|
||||
0x00E, 0x00F, 0x00F, 0x00F, 0x010, 0x010, 0x011, 0x011,
|
||||
0x012, 0x013, 0x013, 0x014, 0x014, 0x015, 0x015, 0x016,
|
||||
0x017, 0x017, 0x018, 0x018, 0x019, 0x01A, 0x01B, 0x01B,
|
||||
0x01C, 0x01D, 0x01D, 0x01E, 0x01F, 0x020, 0x020, 0x021,
|
||||
0x022, 0x023, 0x024, 0x024, 0x025, 0x026, 0x027, 0x028,
|
||||
0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F, 0x030,
|
||||
0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038,
|
||||
0x03A, 0x03B, 0x03C, 0x03D, 0x03E, 0x040, 0x041, 0x042,
|
||||
0x043, 0x045, 0x046, 0x047, 0x049, 0x04A, 0x04C, 0x04D,
|
||||
0x04E, 0x050, 0x051, 0x053, 0x054, 0x056, 0x057, 0x059,
|
||||
0x05A, 0x05C, 0x05E, 0x05F, 0x061, 0x063, 0x064, 0x066,
|
||||
0x068, 0x06A, 0x06B, 0x06D, 0x06F, 0x071, 0x073, 0x075,
|
||||
0x076, 0x078, 0x07A, 0x07C, 0x07E, 0x080, 0x082, 0x084,
|
||||
0x086, 0x089, 0x08B, 0x08D, 0x08F, 0x091, 0x093, 0x096,
|
||||
0x098, 0x09A, 0x09C, 0x09F, 0x0A1, 0x0A3, 0x0A6, 0x0A8,
|
||||
0x0AB, 0x0AD, 0x0AF, 0x0B2, 0x0B4, 0x0B7, 0x0BA, 0x0BC,
|
||||
0x0BF, 0x0C1, 0x0C4, 0x0C7, 0x0C9, 0x0CC, 0x0CF, 0x0D2,
|
||||
0x0D4, 0x0D7, 0x0DA, 0x0DD, 0x0E0, 0x0E3, 0x0E6, 0x0E9,
|
||||
0x0EC, 0x0EF, 0x0F2, 0x0F5, 0x0F8, 0x0FB, 0x0FE, 0x101,
|
||||
0x104, 0x107, 0x10B, 0x10E, 0x111, 0x114, 0x118, 0x11B,
|
||||
0x11E, 0x122, 0x125, 0x129, 0x12C, 0x130, 0x133, 0x137,
|
||||
0x13A, 0x13E, 0x141, 0x145, 0x148, 0x14C, 0x150, 0x153,
|
||||
0x157, 0x15B, 0x15F, 0x162, 0x166, 0x16A, 0x16E, 0x172,
|
||||
0x176, 0x17A, 0x17D, 0x181, 0x185, 0x189, 0x18D, 0x191,
|
||||
0x195, 0x19A, 0x19E, 0x1A2, 0x1A6, 0x1AA, 0x1AE, 0x1B2,
|
||||
0x1B7, 0x1BB, 0x1BF, 0x1C3, 0x1C8, 0x1CC, 0x1D0, 0x1D5,
|
||||
0x1D9, 0x1DD, 0x1E2, 0x1E6, 0x1EB, 0x1EF, 0x1F3, 0x1F8,
|
||||
0x1FC, 0x201, 0x205, 0x20A, 0x20F, 0x213, 0x218, 0x21C,
|
||||
0x221, 0x226, 0x22A, 0x22F, 0x233, 0x238, 0x23D, 0x241,
|
||||
0x246, 0x24B, 0x250, 0x254, 0x259, 0x25E, 0x263, 0x267,
|
||||
0x26C, 0x271, 0x276, 0x27B, 0x280, 0x284, 0x289, 0x28E,
|
||||
0x293, 0x298, 0x29D, 0x2A2, 0x2A6, 0x2AB, 0x2B0, 0x2B5,
|
||||
0x2BA, 0x2BF, 0x2C4, 0x2C9, 0x2CE, 0x2D3, 0x2D8, 0x2DC,
|
||||
0x2E1, 0x2E6, 0x2EB, 0x2F0, 0x2F5, 0x2FA, 0x2FF, 0x304,
|
||||
0x309, 0x30E, 0x313, 0x318, 0x31D, 0x322, 0x326, 0x32B,
|
||||
0x330, 0x335, 0x33A, 0x33F, 0x344, 0x349, 0x34E, 0x353,
|
||||
0x357, 0x35C, 0x361, 0x366, 0x36B, 0x370, 0x374, 0x379,
|
||||
0x37E, 0x383, 0x388, 0x38C, 0x391, 0x396, 0x39B, 0x39F,
|
||||
0x3A4, 0x3A9, 0x3AD, 0x3B2, 0x3B7, 0x3BB, 0x3C0, 0x3C5,
|
||||
0x3C9, 0x3CE, 0x3D2, 0x3D7, 0x3DC, 0x3E0, 0x3E5, 0x3E9,
|
||||
0x3ED, 0x3F2, 0x3F6, 0x3FB, 0x3FF, 0x403, 0x408, 0x40C,
|
||||
0x410, 0x415, 0x419, 0x41D, 0x421, 0x425, 0x42A, 0x42E,
|
||||
0x432, 0x436, 0x43A, 0x43E, 0x442, 0x446, 0x44A, 0x44E,
|
||||
0x452, 0x455, 0x459, 0x45D, 0x461, 0x465, 0x468, 0x46C,
|
||||
0x470, 0x473, 0x477, 0x47A, 0x47E, 0x481, 0x485, 0x488,
|
||||
0x48C, 0x48F, 0x492, 0x496, 0x499, 0x49C, 0x49F, 0x4A2,
|
||||
0x4A6, 0x4A9, 0x4AC, 0x4AF, 0x4B2, 0x4B5, 0x4B7, 0x4BA,
|
||||
0x4BD, 0x4C0, 0x4C3, 0x4C5, 0x4C8, 0x4CB, 0x4CD, 0x4D0,
|
||||
0x4D2, 0x4D5, 0x4D7, 0x4D9, 0x4DC, 0x4DE, 0x4E0, 0x4E3,
|
||||
0x4E5, 0x4E7, 0x4E9, 0x4EB, 0x4ED, 0x4EF, 0x4F1, 0x4F3,
|
||||
0x4F5, 0x4F6, 0x4F8, 0x4FA, 0x4FB, 0x4FD, 0x4FF, 0x500,
|
||||
0x502, 0x503, 0x504, 0x506, 0x507, 0x508, 0x50A, 0x50B,
|
||||
0x50C, 0x50D, 0x50E, 0x50F, 0x510, 0x511, 0x511, 0x512,
|
||||
0x513, 0x514, 0x514, 0x515, 0x516, 0x516, 0x517, 0x517,
|
||||
0x517, 0x518, 0x518, 0x518, 0x518, 0x518, 0x519, 0x519
|
||||
};
|
9
src/dsp/dsp.h
Normal file
9
src/dsp/dsp.h
Normal file
@@ -0,0 +1,9 @@
|
||||
class DSP {
|
||||
public:
|
||||
virtual uint8 read (uint8 addr) = 0;
|
||||
virtual void write(uint8 addr, uint8 data) = 0;
|
||||
|
||||
virtual void power() = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual uint32 run() = 0;
|
||||
};
|
@@ -1,3 +1,6 @@
|
||||
#define BSNES_VERSION "0.013"
|
||||
#define BSNES_TITLE "bsnes v" BSNES_VERSION
|
||||
|
||||
#include "reader/reader.h"
|
||||
|
||||
#include "memory/memory.h"
|
||||
@@ -14,6 +17,10 @@ extern CPU *cpu;
|
||||
#include "apu/bapuskip/bapuskip.h"
|
||||
extern APU *apu;
|
||||
|
||||
#include "dsp/dsp.h"
|
||||
#include "dsp/bdsp/bdsp.h"
|
||||
extern DSP *dsp;
|
||||
|
||||
#include "ppu/ppu.h"
|
||||
#include "ppu/bppu/bppu.h"
|
||||
extern PPU *ppu;
|
||||
@@ -26,10 +33,14 @@ extern SNES *snes;
|
||||
extern SRTC *srtc;
|
||||
extern SDD1 *sdd1;
|
||||
|
||||
#include "config/config.h"
|
||||
|
||||
#ifdef INTERFACE_MAIN
|
||||
#include "config/config.cpp"
|
||||
MemBus *mem_bus;
|
||||
CPU *cpu;
|
||||
APU *apu;
|
||||
DSP *dsp;
|
||||
PPU *ppu;
|
||||
SNES *snes;
|
||||
|
||||
|
@@ -18,6 +18,8 @@
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define zerofree(__n) if(__n) { free(__n); __n = 0; }
|
||||
|
||||
typedef unsigned int uint;
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
@@ -1,273 +1,161 @@
|
||||
#include "libbase.h"
|
||||
#include "libconfig.h"
|
||||
|
||||
config_item::config_item() {
|
||||
strcpy(name, "");
|
||||
strcpy(strdef, "");
|
||||
is_string = false;
|
||||
source = 0;
|
||||
strsource = 0;
|
||||
def = 0;
|
||||
type = 0;
|
||||
void Setting::toggle() {
|
||||
data ^= 1;
|
||||
set(data);
|
||||
}
|
||||
|
||||
void config::add(uint32 *variable, char *name, uint32 def, uint32 type) {
|
||||
int n;
|
||||
if(item_count >= 4096)return;
|
||||
n = item_count;
|
||||
|
||||
item[n] = new config_item();
|
||||
strcpy(item[n]->name, name);
|
||||
item[n]->is_string = false;
|
||||
item[n]->def = def;
|
||||
item[n]->source = variable;
|
||||
*item[n]->source = item[n]->def;
|
||||
item[n]->type = type;
|
||||
|
||||
item_count++;
|
||||
uint Setting::get() {
|
||||
return data;
|
||||
}
|
||||
|
||||
void config::add(string *variable, char *name, char *def, uint32 type) {
|
||||
int n;
|
||||
if(item_count >= 4096)return;
|
||||
n = item_count;
|
||||
void Setting::set(uint _data) {
|
||||
printf("%s %d\n", name, _data);
|
||||
data = _data;
|
||||
|
||||
item[n] = new config_item();
|
||||
strcpy(item[n]->name, name);
|
||||
item[n]->is_string = true;
|
||||
strcpy(item[n]->strdef, def);
|
||||
item[n]->strsource = variable;
|
||||
strcpy(*item[n]->strsource, item[n]->strdef);
|
||||
item[n]->type = type;
|
||||
|
||||
item_count++;
|
||||
}
|
||||
|
||||
uint32 config::find(char *name) {
|
||||
for(int i=0;i<item_count;i++) {
|
||||
if(!strcmp(item[i]->name, name)) {
|
||||
return i;
|
||||
}
|
||||
if(type != DEC && type != HEX) {
|
||||
//data is a boolean type
|
||||
data &= 1;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void config::load(char *fn) {
|
||||
Setting::Setting(Config *_parent, char *_name, char *_desc, uint _data, uint _type) {
|
||||
int s;
|
||||
if(_parent) {
|
||||
_parent->add(this);
|
||||
}
|
||||
|
||||
s = strlen(_name);
|
||||
name = (char*)malloc(s + 1);
|
||||
strcpy(name, _name);
|
||||
|
||||
if(_desc) {
|
||||
s = strlen(_desc);
|
||||
desc = (char*)malloc(s + 1);
|
||||
strcpy(desc, _desc);
|
||||
} else {
|
||||
desc = (char*)malloc(1);
|
||||
*desc = 0;
|
||||
}
|
||||
|
||||
data = _data;
|
||||
def = _data;
|
||||
type = _type;
|
||||
}
|
||||
|
||||
void Config::add(Setting *setting) {
|
||||
list[list_count++] = setting;
|
||||
}
|
||||
|
||||
uint Config::string_to_uint(uint type, char *input) {
|
||||
if(!strcmp(input, "true") ||
|
||||
!strcmp(input, "enabled") ||
|
||||
!strcmp(input, "on") ||
|
||||
!strcmp(input, "yes")
|
||||
) {
|
||||
return (uint)true;
|
||||
}
|
||||
|
||||
if(!strcmp(input, "false") ||
|
||||
!strcmp(input, "disabled") ||
|
||||
!strcmp(input, "off") ||
|
||||
!strcmp(input, "no")
|
||||
) {
|
||||
return (uint)false;
|
||||
}
|
||||
|
||||
if(!strbegin(input, "0x")) {
|
||||
return strhex(input + 2);
|
||||
}
|
||||
|
||||
return strdec(input);
|
||||
}
|
||||
|
||||
char *Config::uint_to_string(uint type, uint input) {
|
||||
static char output[512];
|
||||
switch(type) {
|
||||
case Setting::TRUE_FALSE:
|
||||
sprintf(output, "%s", (input & 1)?"true":"false");
|
||||
break;
|
||||
case Setting::ENABLED_DISABLED:
|
||||
sprintf(output, "%s", (input & 1)?"enabled":"disabled");
|
||||
break;
|
||||
case Setting::ON_OFF:
|
||||
sprintf(output, "%s", (input & 1)?"on":"off");
|
||||
break;
|
||||
case Setting::YES_NO:
|
||||
sprintf(output, "%s", (input & 1)?"yes":"no");
|
||||
break;
|
||||
case Setting::DEC:
|
||||
sprintf(output, "%d", input);
|
||||
break;
|
||||
case Setting::HEX:
|
||||
sprintf(output, "0x%x", input);
|
||||
break;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
bool Config::load(char *fn) {
|
||||
FILE *fp;
|
||||
char *buffer;
|
||||
int i, fsize;
|
||||
uint32 l;
|
||||
fp = fopen(fn, "rb");
|
||||
//file doesn't exist yet, do nothing
|
||||
if(!fp)return;
|
||||
if(!fp)return false;
|
||||
|
||||
//load the config file into memory
|
||||
fseek(fp, 0, SEEK_END);
|
||||
fsize = ftell(fp);
|
||||
int fsize = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
//blank file, do nothing
|
||||
if(fsize == 0) {
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
buffer = (char*)malloc(fsize + 1);
|
||||
char *buffer = (char*)malloc(fsize + 1);
|
||||
fread(buffer, 1, fsize, fp);
|
||||
fclose(fp);
|
||||
buffer[fsize] = 0;
|
||||
|
||||
*(buffer + fsize) = 0;
|
||||
strcpy(data, buffer);
|
||||
free(buffer);
|
||||
replace(data, "\r\n", "\n");
|
||||
qreplace(data, "\t", " ");
|
||||
|
||||
//split the file into lines
|
||||
replace(data, "\r\n", "\n");
|
||||
qreplace(data, "\t", "");
|
||||
qreplace(data, " ", "");
|
||||
split(line, "\n", data);
|
||||
|
||||
for(i=0;i<count(line);i++) {
|
||||
qreplace(line[i], " ", "");
|
||||
|
||||
//remove comment, if it exists
|
||||
if(qstrpos(line[i], "#") != null) {
|
||||
strset(line[i], qstrpos(line[i], "#"), 0);
|
||||
}
|
||||
|
||||
//ignore blank lines
|
||||
for(int i=0;i<count(line);i++) {
|
||||
if(strlen(line[i]) == 0)continue;
|
||||
if(*strptr(line[i]) == '#')continue;
|
||||
|
||||
qsplit(part, "=", line[i]);
|
||||
|
||||
l = find(strptr(part[0]));
|
||||
if(l != null) {
|
||||
//if the config item name is valid... update item value
|
||||
if(item[l]->is_string == true) {
|
||||
strunquote(part[1]);
|
||||
strcpy(*item[l]->strsource, part[1]);
|
||||
} else {
|
||||
if(!strcmp(part[1], "true") || !strcmp(part[1], "yes") ||
|
||||
!strcmp(part[1], "on") || !strcmp(part[1], "enabled")) {
|
||||
*item[l]->source = 1;
|
||||
} else if(!strcmp(part[1], "false") || !strcmp(part[1], "no") ||
|
||||
!strcmp(part[1], "off") || !strcmp(part[1], "disabled")) {
|
||||
*item[l]->source = 0;
|
||||
} else if(item[l]->type == HEX) {
|
||||
*item[l]->source = strhex(strptr(part[1]) + 2); //skip 0x prefix
|
||||
} else { /* fall back on DEC */
|
||||
*item[l]->source = strdec(part[1]);
|
||||
}
|
||||
split(part, "=", line[i]);
|
||||
for(int l=0;l<list_count;l++) {
|
||||
if(!strcmp(list[l]->name, part[0])) {
|
||||
list[l]->set(string_to_uint(list[l]->type, strptr(part[1])));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void config::load(substring &fn) { load(strptr(fn)); }
|
||||
|
||||
//create a text string from config item[i] to be output via config->save()
|
||||
void config::set_newline(int i) {
|
||||
char t[16];
|
||||
if(item[i]->is_string == true) {
|
||||
strcpy(newline, item[i]->name);
|
||||
strcat(newline, " = \"");
|
||||
strcat(newline, *item[i]->strsource);
|
||||
strcat(newline, "\"");
|
||||
} else {
|
||||
strcpy(newline, item[i]->name);
|
||||
strcat(newline, " = ");
|
||||
switch(item[i]->type) {
|
||||
case TRUEFALSE:
|
||||
strcat(newline, (*item[i]->source)?"true":"false");
|
||||
break;
|
||||
case YESNO:
|
||||
strcat(newline, (*item[i]->source)?"yes":"no");
|
||||
break;
|
||||
case ONOFF:
|
||||
strcat(newline, (*item[i]->source)?"on":"off");
|
||||
break;
|
||||
case ENABLED:
|
||||
strcat(newline, (*item[i]->source)?"enabled":"disabled");
|
||||
break;
|
||||
case HEX:
|
||||
sprintf(t, "0x%0.2x", *item[i]->source);
|
||||
strcat(newline, t);
|
||||
break;
|
||||
case DEC:
|
||||
default:
|
||||
sprintf(t, "%d", *item[i]->source);
|
||||
strcat(newline, t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Config::load(substring &fn) { return load(strptr(fn)); }
|
||||
|
||||
void config::save(char *fn) {
|
||||
bool Config::save(char *fn) {
|
||||
FILE *fp;
|
||||
int i, fsize;
|
||||
uint32 l;
|
||||
char *buffer;
|
||||
uint8 set[4096];
|
||||
bool blank = false;
|
||||
fp = fopen(fn, "rb");
|
||||
if(!fp) {
|
||||
blank = true;
|
||||
} else {
|
||||
fseek(fp, 0, SEEK_END);
|
||||
fsize = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
if(fsize == 0) {
|
||||
blank = true;
|
||||
} else {
|
||||
buffer = (char*)malloc(fsize + 1);
|
||||
fread(buffer, 1, fsize, fp);
|
||||
buffer[fsize] = 0;
|
||||
|
||||
strcpy(data, buffer);
|
||||
free(buffer);
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
fp = fopen(fn, "wb");
|
||||
//no write access?
|
||||
if(!fp)return;
|
||||
if(!fp)return false;
|
||||
|
||||
//list of config items. if the item is set in the
|
||||
//existing config file, then don't test it to see
|
||||
//if it needs to be written again later on
|
||||
memset(set, 0, item_count);
|
||||
|
||||
if(blank == false) {
|
||||
for(int i=0;i<list_count;i++) {
|
||||
strcpy(data, list[i]->desc);
|
||||
replace(data, "\r\n", "\n");
|
||||
qreplace(data, "\t", " ");
|
||||
|
||||
split(line, "\n", data);
|
||||
split(oldline, "\n", data);
|
||||
|
||||
for(i=0;i<count(line);i++) {
|
||||
qreplace(line[i], " ", "");
|
||||
|
||||
if(qstrpos(line[i], "#") != null) {
|
||||
strset(line[i], qstrpos(line[i], "#"), 0);
|
||||
}
|
||||
|
||||
//this line is empty, restore the old line and continue
|
||||
if(strlen(line[i]) == 0) {
|
||||
strcpy(line[i], oldline[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
qsplit(part, "=", line[i]);
|
||||
|
||||
l = find(strptr(part[0]));
|
||||
if(l == null) {
|
||||
//invalid item name, restore the old line and continue
|
||||
strcpy(line[i], oldline[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
set[l] = 1;
|
||||
set_newline(l);
|
||||
|
||||
//copy the user comment from the old config file, if it exists
|
||||
if(qstrpos(oldline[i], "#") != null) {
|
||||
strcat(newline, " ");
|
||||
strcat(newline, strptr(oldline[i]) + qstrpos(oldline[i], "#"));
|
||||
}
|
||||
|
||||
strcpy(line[i], newline);
|
||||
}
|
||||
|
||||
//write out the old config file + changes first
|
||||
for(i=0;i<count(line);) {
|
||||
fprintf(fp, "%s", strptr(line[i]));
|
||||
|
||||
//write a line feed on all lines but the last.
|
||||
//keeps the file from growing everytime it is saved
|
||||
if(++i < count(line))fprintf(fp, "\r\n");
|
||||
split(line, "\n", data);
|
||||
for(int l=0;l<count(line);l++) {
|
||||
fprintf(fp, "# %s\r\n", strptr(line[l]));
|
||||
}
|
||||
fprintf(fp, "# (default = %s)\r\n", uint_to_string(list[i]->type, list[i]->def));
|
||||
fprintf(fp, "%s = %s\r\n\r\n", list[i]->name, uint_to_string(list[i]->type, list[i]->data));
|
||||
}
|
||||
|
||||
int lines_written;
|
||||
for(i=lines_written=0;i<item_count;i++) {
|
||||
//if the item was written to the file above...
|
||||
if(set[i] == 1)continue;
|
||||
|
||||
set_newline(i);
|
||||
//prevent a newline from appearing at the top of the file
|
||||
//when the config file is created for the first time
|
||||
if(lines_written == 0 && blank == false)fprintf(fp, "\r\n");
|
||||
fprintf(fp, "%s\r\n", strptr(newline));
|
||||
lines_written++;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
void config::save(substring &fn) { save(strptr(fn)); }
|
||||
bool Config::save(substring &fn) { return save(strptr(fn)); }
|
||||
|
||||
config::config() {
|
||||
item_count = 0;
|
||||
}
|
||||
|
||||
config::~config() {
|
||||
for(int i=0;i<item_count;i++) {
|
||||
if(item[i])delete(item[i]);
|
||||
}
|
||||
Config::Config() {
|
||||
list_count = 0;
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
libconfig : version 0.03 ~byuu (08/20/05)
|
||||
libconfig : version 0.05 ~byuu (09/13/05)
|
||||
*/
|
||||
|
||||
#ifndef __LIBCONFIG
|
||||
@@ -7,41 +7,92 @@
|
||||
|
||||
#include "libstring.h"
|
||||
|
||||
class config_item {
|
||||
public:
|
||||
uint32 *source, def, type;
|
||||
string *strsource, strdef;
|
||||
bool is_string;
|
||||
string name;
|
||||
config_item();
|
||||
};
|
||||
class Config;
|
||||
|
||||
//operator= is the /only/ overloaded operator that isn't inherited by derived classes.
|
||||
//similarly, base constructor/destructors with arguments are not inherited.
|
||||
//the inclusion of the overloaded virtual function 'toggle' is to allow toggle to call
|
||||
//the overloaded set() function, if it exists. for some reason, Setting::toggle() calls
|
||||
//Setting::set() no matter what, even if the derived class defines set()...
|
||||
//the below macro is a quick way to take care of all of these issues.
|
||||
//usage example:
|
||||
// class T : public Setting { public: SettingOperators(T); } t;
|
||||
// t = 0; // -> t.set(0);
|
||||
#define SettingOperators(__name) \
|
||||
inline __name &operator=(const bool _data) { set((uint)_data); return *this; } \
|
||||
inline __name &operator=(const uint _data) { set(_data); return *this; } \
|
||||
inline __name &operator=(const uint8 _data) { set(_data); return *this; } \
|
||||
inline __name &operator=(const uint16 _data) { set(_data); return *this; } \
|
||||
inline __name &operator=(const uint32 _data) { set(_data); return *this; } \
|
||||
inline __name &operator=(const int _data) { set(_data); return *this; } \
|
||||
inline __name &operator=(const int8 _data) { set(_data); return *this; } \
|
||||
inline __name &operator=(const int16 _data) { set(_data); return *this; } \
|
||||
inline __name &operator=(const int32 _data) { set(_data); return *this; } \
|
||||
void toggle() { data ^= 1; set(data); } \
|
||||
__name(Config *_parent, char *_name, char *_desc = 0, uint _data = 0, uint _type = Setting::DEC) : \
|
||||
Setting(_parent, _name, _desc, _data, _type) {}
|
||||
|
||||
class Setting {
|
||||
friend class Config;
|
||||
|
||||
protected:
|
||||
uint data, type, def;
|
||||
|
||||
class config {
|
||||
private:
|
||||
uint32 item_count;
|
||||
config_item *item[4096];
|
||||
string data, line, oldline, newline, part;
|
||||
public:
|
||||
enum {
|
||||
TRUEFALSE = 0,
|
||||
YESNO = 1,
|
||||
ONOFF = 2,
|
||||
ENABLED = 3,
|
||||
DEC = 4,
|
||||
HEX = 5,
|
||||
STR = 6
|
||||
TRUE_FALSE,
|
||||
ENABLED_DISABLED,
|
||||
ON_OFF,
|
||||
YES_NO,
|
||||
BOOL,
|
||||
DEC,
|
||||
HEX
|
||||
};
|
||||
void add(uint32 *variable, char *name, uint32 def, uint32 type = DEC);
|
||||
void add(string *variable, char *name, char *def, uint32 type = STR);
|
||||
uint32 find(char *name);
|
||||
void load(char *fn);
|
||||
void load(substring &fn);
|
||||
void save(char *fn);
|
||||
void save(substring &fn);
|
||||
void set_newline(int i);
|
||||
char *name, *desc;
|
||||
virtual void toggle();
|
||||
virtual uint get();
|
||||
virtual void set(uint _data);
|
||||
|
||||
config();
|
||||
~config();
|
||||
Setting(Config *_parent, char *_name, char *_desc = 0, uint _data = 0, uint _type = DEC);
|
||||
|
||||
inline operator bool() { return (bool)get(); }
|
||||
inline operator uint() { return get(); }
|
||||
inline operator uint8() { return get(); }
|
||||
inline operator uint16() { return get(); }
|
||||
inline operator uint32() { return get(); }
|
||||
inline operator int() { return get(); }
|
||||
inline operator int8() { return get(); }
|
||||
inline operator int16() { return get(); }
|
||||
inline operator int32() { return get(); }
|
||||
|
||||
inline Setting &operator=(const bool _data) { set((uint)_data); return *this; }
|
||||
inline Setting &operator=(const uint _data) { set(_data); return *this; }
|
||||
inline Setting &operator=(const uint8 _data) { set(_data); return *this; }
|
||||
inline Setting &operator=(const uint16 _data) { set(_data); return *this; }
|
||||
inline Setting &operator=(const uint32 _data) { set(_data); return *this; }
|
||||
inline Setting &operator=(const int _data) { set(_data); return *this; }
|
||||
inline Setting &operator=(const int8 _data) { set(_data); return *this; }
|
||||
inline Setting &operator=(const int16 _data) { set(_data); return *this; }
|
||||
inline Setting &operator=(const int32 _data) { set(_data); return *this; }
|
||||
};
|
||||
|
||||
class Config {
|
||||
protected:
|
||||
vector<Setting*> list;
|
||||
uint list_count;
|
||||
|
||||
string data, line, part, subpart;
|
||||
|
||||
uint string_to_uint(uint type, char *input);
|
||||
char *uint_to_string(uint type, uint input);
|
||||
|
||||
public:
|
||||
void add(Setting *setting);
|
||||
bool load(char *fn);
|
||||
bool load(substring &fn);
|
||||
bool save(char *fn);
|
||||
bool save(substring &fn);
|
||||
Config();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -6,7 +6,7 @@ public:
|
||||
uint8 *rom, *sram;
|
||||
uint32 rom_size, sram_size;
|
||||
uint8 read (uint32 addr);
|
||||
void write(uint32 addr, byte value);
|
||||
void write(uint32 addr, uint8 value);
|
||||
void write_protect(bool r);
|
||||
void set_cartinfo(CartInfo *ci);
|
||||
|
||||
|
@@ -6,7 +6,7 @@ public:
|
||||
uint8 *rom, *sram;
|
||||
uint32 rom_size, sram_size;
|
||||
uint8 read (uint32 addr);
|
||||
void write(uint32 addr, byte value);
|
||||
void write(uint32 addr, uint8 value);
|
||||
void write_protect(bool r);
|
||||
void set_cartinfo(CartInfo *ci);
|
||||
|
||||
|
@@ -7,7 +7,7 @@ public:
|
||||
uint8 *rom, *sram;
|
||||
uint32 rom_size, sram_size;
|
||||
uint8 read (uint32 addr);
|
||||
void write(uint32 addr, byte value);
|
||||
void write(uint32 addr, uint8 value);
|
||||
void write_protect(bool r);
|
||||
void set_cartinfo(CartInfo *ci);
|
||||
|
||||
|
@@ -7,7 +7,7 @@ public:
|
||||
uint8 *rom, *sram;
|
||||
uint32 rom_size, sram_size;
|
||||
uint8 read (uint32 addr);
|
||||
void write(uint32 addr, byte value);
|
||||
void write(uint32 addr, uint8 value);
|
||||
void write_protect(bool r);
|
||||
void set_cartinfo(CartInfo *ci);
|
||||
|
||||
|
@@ -171,33 +171,39 @@ void bMemBus::get_cartinfo(CartInfo *ci) {
|
||||
***************************************/
|
||||
|
||||
uint8 bMemBus::read(uint32 addr) {
|
||||
uint32 b, w, r;
|
||||
addr &= 0xffffff;
|
||||
b = (addr >> 16);
|
||||
w = (addr & 0xffff);
|
||||
static uint32 r;
|
||||
switch(addr & 0xc00000) {
|
||||
case 0x400000:
|
||||
if((addr & 0xfe0000) == 0x7e0000) {
|
||||
r = wram[addr & 0x01ffff];
|
||||
break;
|
||||
}
|
||||
//fallthrough
|
||||
case 0xc00000:
|
||||
r = cart->read(addr);
|
||||
break;
|
||||
|
||||
if(b <= 0x3f) {
|
||||
if(w <= 0x1fff) {
|
||||
r = wram[w];
|
||||
} else if(w <= 0x5fff) {
|
||||
r = mmio[w - 0x2000]->read(w);
|
||||
} else {
|
||||
//case 0x000000:
|
||||
//case 0x800000:
|
||||
default:
|
||||
switch(addr & 0x00e000) {
|
||||
case 0x0000:
|
||||
r = wram[addr & 0x1fff];
|
||||
break;
|
||||
case 0x2000:
|
||||
case 0x4000:
|
||||
r = mmio[(addr - 0x2000) & 0x3fff]->read(addr & 0x7fff);
|
||||
break;
|
||||
// case 0x6000:
|
||||
// case 0x8000:
|
||||
// case 0xa000:
|
||||
// case 0xc000:
|
||||
// case 0xe000:
|
||||
default:
|
||||
r = cart->read(addr);
|
||||
break;
|
||||
}
|
||||
} else if(b <= 0x7d) {
|
||||
r = cart->read(addr);
|
||||
} else if(b <= 0x7f) {
|
||||
r = wram[addr & 0x01ffff];
|
||||
} else if(b <= 0xbf) {
|
||||
if(w <= 0x1fff) {
|
||||
r = wram[w];
|
||||
} else if(w <= 0x5fff) {
|
||||
r = mmio[w - 0x2000]->read(w);
|
||||
} else {
|
||||
r = cart->read(addr);
|
||||
}
|
||||
} else {
|
||||
r = cart->read(addr);
|
||||
break;
|
||||
}
|
||||
|
||||
snes->notify(SNES::MEM_READ, addr, r);
|
||||
@@ -205,33 +211,38 @@ uint32 b, w, r;
|
||||
}
|
||||
|
||||
void bMemBus::write(uint32 addr, uint8 value) {
|
||||
uint32 b, w;
|
||||
addr &= 0xffffff;
|
||||
b = (addr >> 16);
|
||||
w = (addr & 0xffff);
|
||||
switch(addr & 0xc00000) {
|
||||
case 0x400000:
|
||||
if((addr & 0xfe0000) == 0x7e0000) {
|
||||
wram[addr & 0x01ffff] = value;
|
||||
break;
|
||||
}
|
||||
//fallthrough
|
||||
case 0xc00000:
|
||||
cart->write(addr, value);
|
||||
break;
|
||||
|
||||
if(b <= 0x3f) {
|
||||
if(w <= 0x1fff) {
|
||||
wram[w] = value;
|
||||
} else if(w <= 0x5fff) {
|
||||
mmio[w - 0x2000]->write(w, value);
|
||||
} else {
|
||||
//case 0x000000:
|
||||
//case 0x800000:
|
||||
default:
|
||||
switch(addr & 0x00e000) {
|
||||
case 0x0000:
|
||||
wram[addr & 0x1fff] = value;
|
||||
break;
|
||||
case 0x2000:
|
||||
case 0x4000:
|
||||
mmio[(addr - 0x2000) & 0x3fff]->write(addr & 0x7fff, value);
|
||||
break;
|
||||
// case 0x6000:
|
||||
// case 0x8000:
|
||||
// case 0xa000:
|
||||
// case 0xc000:
|
||||
// case 0xe000:
|
||||
default:
|
||||
cart->write(addr, value);
|
||||
break;
|
||||
}
|
||||
} else if(b <= 0x7d) {
|
||||
cart->write(addr, value);
|
||||
} else if(b <= 0x7f) {
|
||||
wram[addr & 0x01ffff] = value;
|
||||
} else if(b <= 0xbf) {
|
||||
if(w <= 0x1fff) {
|
||||
wram[w] = value;
|
||||
} else if(w <= 0x5fff) {
|
||||
mmio[w - 0x2000]->write(w, value);
|
||||
} else {
|
||||
cart->write(addr, value);
|
||||
}
|
||||
} else {
|
||||
cart->write(addr, value);
|
||||
break;
|
||||
}
|
||||
|
||||
snes->notify(SNES::MEM_WRITE, addr, value);
|
||||
@@ -243,7 +254,7 @@ void bMemBus::power() {
|
||||
}
|
||||
|
||||
void bMemBus::reset() {
|
||||
fastROM = false;
|
||||
set_speed(false);
|
||||
}
|
||||
|
||||
bMemBus::bMemBus() {
|
||||
@@ -253,5 +264,5 @@ bMemBus::bMemBus() {
|
||||
}
|
||||
|
||||
bMemBus::~bMemBus() {
|
||||
if(wram)free(wram);
|
||||
zerofree(wram);
|
||||
}
|
||||
|
@@ -18,13 +18,13 @@ bool rom_loaded;
|
||||
enum { LOROM = 0x20, HIROM = 0x21, EXLOROM = 0x22, EXHIROM = 0x25 };
|
||||
|
||||
uint8 read (uint32 addr);
|
||||
void write(uint32 addr, byte value);
|
||||
void write(uint32 addr, uint8 value);
|
||||
|
||||
bool load_cart(Reader *rf);
|
||||
bool load_sram(Reader *rf);
|
||||
bool save_sram(Writer *wf);
|
||||
void unload_cart();
|
||||
void get_cartinfo(CartInfo *ci);
|
||||
bool load_cart(Reader *rf);
|
||||
bool load_sram(Reader *rf);
|
||||
bool save_sram(Writer *wf);
|
||||
void unload_cart();
|
||||
void get_cartinfo(CartInfo *ci);
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#include "../base.h"
|
||||
|
||||
uint16 Memory::read_word(uint32 addr, uint8 wrap) {
|
||||
uint16 Memory::read_word(uint32 addr, uint wrap) {
|
||||
uint16 r;
|
||||
switch(wrap) {
|
||||
case WRAP_NONE:
|
||||
@@ -19,24 +19,24 @@ uint16 r;
|
||||
return r;
|
||||
}
|
||||
|
||||
void Memory::write_word(uint32 addr, uint16 value, uint8 wrap) {
|
||||
void Memory::write_word(uint32 addr, uint16 data, uint wrap) {
|
||||
switch(wrap) {
|
||||
case WRAP_NONE:
|
||||
write(addr, value);
|
||||
write(addr + 1, value >> 8);
|
||||
write(addr, data);
|
||||
write(addr + 1, data >> 8);
|
||||
return;
|
||||
case WRAP_BANK:
|
||||
write(addr, value);
|
||||
write((addr & 0xff0000) | ((addr + 1) & 0xffff), value >> 8);
|
||||
write(addr, data);
|
||||
write((addr & 0xff0000) | ((addr + 1) & 0xffff), data >> 8);
|
||||
return;
|
||||
case WRAP_PAGE:
|
||||
write(addr, value);
|
||||
write((addr & 0xffff00) | ((addr + 1) & 0xff), value >> 8);
|
||||
write(addr, data);
|
||||
write((addr & 0xffff00) | ((addr + 1) & 0xff), data >> 8);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Memory::read_long(uint32 addr, uint8 wrap) {
|
||||
uint32 Memory::read_long(uint32 addr, uint wrap) {
|
||||
uint32 r;
|
||||
switch(wrap) {
|
||||
case WRAP_NONE:
|
||||
@@ -58,22 +58,22 @@ uint32 r;
|
||||
return r;
|
||||
}
|
||||
|
||||
void Memory::write_long(uint32 addr, uint32 value, uint8 wrap) {
|
||||
void Memory::write_long(uint32 addr, uint32 data, uint wrap) {
|
||||
switch(wrap) {
|
||||
case WRAP_NONE:
|
||||
write(addr, value);
|
||||
write(addr + 1, value >> 8);
|
||||
write(addr + 2, value >> 16);
|
||||
write(addr, data);
|
||||
write(addr + 1, data >> 8);
|
||||
write(addr + 2, data >> 16);
|
||||
return;
|
||||
case WRAP_BANK:
|
||||
write(addr, value);
|
||||
write((addr & 0xff0000) | ((addr + 1) & 0xffff), value >> 8);
|
||||
write((addr & 0xff0000) | ((addr + 2) & 0xffff), value >> 16);
|
||||
write(addr, data);
|
||||
write((addr & 0xff0000) | ((addr + 1) & 0xffff), data >> 8);
|
||||
write((addr & 0xff0000) | ((addr + 2) & 0xffff), data >> 16);
|
||||
return;
|
||||
case WRAP_PAGE:
|
||||
write(addr, value);
|
||||
write((addr & 0xffff00) | ((addr + 1) & 0xff), value >> 8);
|
||||
write((addr & 0xffff00) | ((addr + 2) & 0xff), value >> 16);
|
||||
write(addr, data);
|
||||
write((addr & 0xffff00) | ((addr + 1) & 0xff), data >> 8);
|
||||
write((addr & 0xffff00) | ((addr + 2) & 0xff), data >> 16);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -82,16 +82,30 @@ MMIO mmio_unmapped;
|
||||
uint8 MMIO::read (uint32 addr) { return cpu->regs.mdr; }
|
||||
void MMIO::write(uint32 addr, uint8 value) {}
|
||||
|
||||
uint8 MemBus::speed(uint32 addr) {
|
||||
uint8 MemBus::calc_speed(uint32 addr, bool fast) {
|
||||
if((addr & 0xc00000) == 0x400000)return 8;
|
||||
if((addr & 0x808000) == 0x808000)return fastROM?6:8;
|
||||
if((addr & 0xc00000) == 0xc00000)return fastROM?6:8;
|
||||
if((addr & 0x808000) == 0x808000)return fast?6:8;
|
||||
if((addr & 0xc00000) == 0xc00000)return fast?6:8;
|
||||
if((addr & 0xe000) == 0x2000)return 6;
|
||||
if((addr & 0xfe00) == 0x4000)return 12;
|
||||
if((addr & 0xe000) == 0x4000)return 6;
|
||||
return 8;
|
||||
}
|
||||
|
||||
uint8 MemBus::speed(uint32 addr) {
|
||||
return speed_table[addr >> 9];
|
||||
}
|
||||
|
||||
void MemBus::set_speed(bool fast) {
|
||||
fastROM = fast;
|
||||
|
||||
if(fastROM) {
|
||||
speed_table = (uint8*)speed_table_fastrom;
|
||||
} else {
|
||||
speed_table = (uint8*)speed_table_slowrom;
|
||||
}
|
||||
}
|
||||
|
||||
void MemBus::flush_mmio_mappers() {
|
||||
for(int i=0;i<0x4000;i++) {
|
||||
mmio[i] = &mmio_unmapped;
|
||||
@@ -99,7 +113,7 @@ void MemBus::flush_mmio_mappers() {
|
||||
}
|
||||
|
||||
bool MemBus::set_mmio_mapper(uint16 addr, MMIO *mapper) {
|
||||
/* out of range? */
|
||||
//out of range?
|
||||
if(addr < 0x2000 || addr >= 0x6000)return false;
|
||||
|
||||
mmio[(addr - 0x2000) & 0x3fff] = mapper;
|
||||
@@ -110,6 +124,12 @@ MemBus::MemBus() {
|
||||
int i;
|
||||
fastROM = false;
|
||||
flush_mmio_mappers();
|
||||
|
||||
for(i=0;i<32768;i++) {
|
||||
speed_table_slowrom[i] = calc_speed(i << 9, false);
|
||||
speed_table_fastrom[i] = calc_speed(i << 9, true);
|
||||
}
|
||||
speed_table = (uint8*)speed_table_slowrom;
|
||||
}
|
||||
|
||||
MemBus::~MemBus() {}
|
||||
|
@@ -1,18 +1,18 @@
|
||||
class Memory {
|
||||
public:
|
||||
enum { WRAP_NONE = 0, WRAP_BANK = 1, WRAP_PAGE = 2 };
|
||||
virtual uint8 read (uint32 addr) = 0;
|
||||
virtual void write(uint32 addr, uint8 value) = 0;
|
||||
virtual uint16 read_word (uint32 addr, uint8 wrap = WRAP_NONE);
|
||||
virtual void write_word(uint32 addr, uint16 value, uint8 wrap = WRAP_NONE);
|
||||
virtual uint32 read_long (uint32 addr, uint8 wrap = WRAP_NONE);
|
||||
virtual void write_long(uint32 addr, uint32 value, uint8 wrap = WRAP_NONE);
|
||||
virtual uint8 read (uint32 addr) = 0;
|
||||
virtual void write (uint32 addr, uint8 data) = 0;
|
||||
virtual uint16 read_word (uint32 addr, uint wrap = WRAP_NONE);
|
||||
virtual void write_word(uint32 addr, uint16 data, uint wrap = WRAP_NONE);
|
||||
virtual uint32 read_long (uint32 addr, uint wrap = WRAP_NONE);
|
||||
virtual void write_long(uint32 addr, uint32 data, uint wrap = WRAP_NONE);
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8 *rom, *sram;
|
||||
uint32 rom_size, sram_size;
|
||||
}CartInfo;
|
||||
uint8 *rom, *sram;
|
||||
uint32 rom_size, sram_size;
|
||||
} CartInfo;
|
||||
|
||||
class Cart : public Memory {
|
||||
public:
|
||||
@@ -31,15 +31,26 @@ public:
|
||||
Cart *cart;
|
||||
MMIO *mmio[0x4000];
|
||||
bool fastROM;
|
||||
virtual void flush_mmio_mappers();
|
||||
virtual bool set_mmio_mapper(uint16 addr, MMIO *mapper);
|
||||
virtual uint8 speed(uint32 addr);
|
||||
void flush_mmio_mappers();
|
||||
bool set_mmio_mapper(uint16 addr, MMIO *mapper);
|
||||
|
||||
virtual bool load_cart(Reader *rf) = 0;
|
||||
virtual bool load_sram(Reader *rf) = 0;
|
||||
virtual bool save_sram(Writer *wf) = 0;
|
||||
virtual void unload_cart() = 0;
|
||||
virtual void get_cartinfo(CartInfo *ci) = 0;
|
||||
private:
|
||||
//0x1000000 / 512 = 32768
|
||||
//512 = 0x200, smallest block of a different-speed memory range
|
||||
//ex. $4000-$41ff = 512
|
||||
uint8 *speed_table,
|
||||
speed_table_slowrom[32768],
|
||||
speed_table_fastrom[32768];
|
||||
inline uint8 calc_speed(uint32 addr, bool fast);
|
||||
public:
|
||||
uint8 speed(uint32 addr);
|
||||
void set_speed(bool fast);
|
||||
|
||||
virtual bool load_cart(Reader *rf) = 0;
|
||||
virtual bool load_sram(Reader *rf) = 0;
|
||||
virtual bool save_sram(Writer *wf) = 0;
|
||||
virtual void unload_cart() = 0;
|
||||
virtual void get_cartinfo(CartInfo *ci) = 0;
|
||||
|
||||
virtual void power() = 0;
|
||||
virtual void reset() = 0;
|
||||
|
@@ -6,7 +6,7 @@ void bPPU::run() {}
|
||||
|
||||
void bPPU::scanline() {
|
||||
_y = cpu->vcounter();
|
||||
_screen_width = (regs.bg_mode == 5 || regs.bg_mode == 6)?512:256;
|
||||
_screen_width = (regs.bg_mode == 5 || regs.bg_mode == 6) ? 512 : 256;
|
||||
_interlace = cpu->interlace();
|
||||
_interlace_field = cpu->interlace_field();
|
||||
|
||||
@@ -25,50 +25,23 @@ void bPPU::scanline() {
|
||||
}
|
||||
}
|
||||
|
||||
if(_y == (cpu->overscan()?239:224) && regs.display_disabled == false) {
|
||||
if(_y == (cpu->overscan() ? 239 : 224) && regs.display_disabled == false) {
|
||||
//OAM address reset
|
||||
regs.oam_addr = ((regs.oam_addrh << 8) | regs.oam_addrl) << 1;
|
||||
}
|
||||
}
|
||||
|
||||
//only allow frameskip setting to ignore actual rendering; not RTO, etc.
|
||||
if(settings.frameskip_pos != 0)return;
|
||||
void bPPU::render_scanline() {
|
||||
if(status.render_output == false)return;
|
||||
|
||||
if(_y > 0 && _y < (cpu->overscan()?239:224)) {
|
||||
if(regs.bg_mode == 5 || regs.bg_mode == 6) {
|
||||
output->hires = true;
|
||||
output->line[_y].hires = true;
|
||||
}
|
||||
if(_interlace == true) {
|
||||
output->interlace = true;
|
||||
output->line[_y].interlace = true;
|
||||
}
|
||||
if(_y > 0 && _y < (cpu->overscan() ? 239 : 224)) {
|
||||
render_line();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
output->hires = false;
|
||||
output->interlace = false;
|
||||
for(int i=0;i<239;i++) {
|
||||
output->line[i].hires = false;
|
||||
output->line[i].interlace = false;
|
||||
}
|
||||
}
|
||||
|
||||
void bPPU::set_frameskip(int fs) {
|
||||
settings.frameskip = fs;
|
||||
settings.frameskip_changed = true;
|
||||
}
|
||||
|
||||
void bPPU::power() {
|
||||
@@ -82,7 +55,6 @@ void bPPU::power() {
|
||||
}
|
||||
|
||||
void bPPU::reset() {
|
||||
memset(output->buffer, 0, 512 * 478 * 2);
|
||||
frame();
|
||||
|
||||
memset(sprite_list, 0, sizeof(sprite_list));
|
||||
@@ -173,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;
|
||||
@@ -205,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;
|
||||
@@ -225,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;
|
||||
@@ -242,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;
|
||||
@@ -277,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) {
|
||||
@@ -329,15 +306,11 @@ 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*)memalloc(65536, "bPPU::vram");
|
||||
oam = (uint8*)memalloc( 544, "bPPU::oam");
|
||||
cgram = (uint8*)memalloc( 512, "bPPU::cgram");
|
||||
vram = (uint8*)malloc(65536);
|
||||
oam = (uint8*)malloc( 544);
|
||||
cgram = (uint8*)malloc( 512);
|
||||
memset(vram, 0, 65536);
|
||||
memset(oam, 0, 544);
|
||||
memset(cgram, 0, 512);
|
||||
@@ -346,7 +319,7 @@ bPPU::bPPU() {
|
||||
|
||||
int i, l;
|
||||
uint8 r, g, b;
|
||||
float m;
|
||||
double m;
|
||||
uint16 *ptr;
|
||||
for(l=0;l<16;l++) {
|
||||
mosaic_table[l] = (uint16*)malloc(4096 * 2);
|
||||
@@ -358,7 +331,7 @@ uint16 *ptr;
|
||||
light_table = (uint16*)malloc(16 * 32768 * 2);
|
||||
ptr = (uint16*)light_table;
|
||||
for(l=0;l<16;l++) {
|
||||
m = (float)l / 15.0;
|
||||
m = (double)l / 15.0;
|
||||
for(i=0;i<32768;i++) {
|
||||
r = (i ) & 31;
|
||||
g = (i >> 5) & 31;
|
||||
@@ -366,9 +339,9 @@ uint16 *ptr;
|
||||
if(l == 0) { r = g = b = 0; }
|
||||
else if(l == 15);
|
||||
else {
|
||||
r = (uint8)((float)r * m);
|
||||
g = (uint8)((float)g * m);
|
||||
b = (uint8)((float)b * m);
|
||||
r = (uint8)((double)r * m);
|
||||
g = (uint8)((double)g * m);
|
||||
b = (uint8)((double)b * m);
|
||||
}
|
||||
*ptr++ = (r) | (g << 5) | (b << 10);
|
||||
}
|
||||
@@ -378,30 +351,15 @@ uint16 *ptr;
|
||||
bPPU::~bPPU() {
|
||||
delete(mmio);
|
||||
|
||||
if(vram) {
|
||||
free(vram);
|
||||
vram = 0;
|
||||
}
|
||||
if(oam) {
|
||||
free(oam);
|
||||
oam = 0;
|
||||
}
|
||||
if(cgram) {
|
||||
free(cgram);
|
||||
cgram = 0;
|
||||
}
|
||||
zerofree(vram);
|
||||
zerofree(oam);
|
||||
zerofree(cgram);
|
||||
|
||||
for(int i=0;i<16;i++) {
|
||||
if(mosaic_table[i]) {
|
||||
free(mosaic_table[i]);
|
||||
mosaic_table[i] = 0;
|
||||
}
|
||||
zerofree(mosaic_table[i]);
|
||||
}
|
||||
|
||||
if(light_table) {
|
||||
memfree(light_table);
|
||||
light_table = 0;
|
||||
}
|
||||
zerofree(light_table);
|
||||
}
|
||||
|
||||
bPPUMMIO::bPPUMMIO(bPPU *_ppu) {
|
||||
|
@@ -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 {
|
||||
@@ -25,12 +25,7 @@ struct sprite_item {
|
||||
bool vflip, hflip;
|
||||
uint8 palette;
|
||||
uint8 priority;
|
||||
}sprite_list[128];
|
||||
|
||||
struct {
|
||||
int32 frameskip, frameskip_pos;
|
||||
bool frameskip_changed;
|
||||
}settings;
|
||||
} sprite_list[128];
|
||||
|
||||
struct {
|
||||
//open bus support
|
||||
@@ -95,34 +90,32 @@ 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;
|
||||
bool addsub_mode;
|
||||
bool direct_color;
|
||||
|
||||
//$2131
|
||||
bool color_mode, color_halve;
|
||||
bool bg_color_enabled[6];
|
||||
bool color_enabled[6];
|
||||
|
||||
//$2132
|
||||
uint8 color_r, color_g, color_b;
|
||||
@@ -145,7 +138,7 @@ struct {
|
||||
//$213e
|
||||
bool time_over, range_over;
|
||||
uint16 oam_itemcount, oam_tilecount;
|
||||
}regs;
|
||||
} regs;
|
||||
uint8 vram_read (uint16 addr);
|
||||
void vram_write (uint16 addr, uint8 value);
|
||||
uint8 oam_read (uint16 addr);
|
||||
@@ -157,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
|
||||
@@ -225,7 +220,7 @@ struct {
|
||||
|
||||
void latch_counters();
|
||||
|
||||
/* PPU render functions */
|
||||
//PPU render functions
|
||||
|
||||
#include "bppu_render.h"
|
||||
|
||||
@@ -234,13 +229,15 @@ uint16 *mosaic_table[16];
|
||||
void render_line();
|
||||
|
||||
void update_oam_status();
|
||||
/* Required functions */
|
||||
//required functions
|
||||
void run();
|
||||
void scanline();
|
||||
void render_scanline();
|
||||
void frame();
|
||||
void power();
|
||||
void reset();
|
||||
void set_frameskip(int fs);
|
||||
|
||||
bool scanline_is_hires() { return (regs.bg_mode == 5 || regs.bg_mode == 6); }
|
||||
|
||||
bPPU();
|
||||
~bPPU();
|
||||
|
@@ -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
|
||||
@@ -393,18 +520,21 @@ void bPPU::mmio_w2130(uint8 value) {
|
||||
regs.color_mask = (value >> 6) & 3;
|
||||
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
|
||||
@@ -475,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;
|
||||
@@ -488,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;
|
||||
@@ -538,9 +676,9 @@ uint8 bPPU::mmio_r213d() {
|
||||
//STAT77
|
||||
uint8 bPPU::mmio_r213e() {
|
||||
uint8 r = 0x00;
|
||||
r |= (regs.time_over) ?0x80:0x00;
|
||||
r |= (regs.range_over)?0x40:0x00;
|
||||
r |= 0x01; //PPU1 version number
|
||||
r |= (regs.time_over) ? 0x80 : 0x00;
|
||||
r |= (regs.range_over) ? 0x40 : 0x00;
|
||||
r |= (ppu1_version & 0x0f);
|
||||
regs.ppu1_mdr = r;
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
@@ -560,7 +698,7 @@ uint8 r = 0x00;
|
||||
}
|
||||
r |= (regs.ppu2_mdr & 0x20);
|
||||
r |= (region << 4); //0 = NTSC, 1 = PAL
|
||||
r |= 0x03; //PPU2 version number
|
||||
r |= (ppu2_version & 0x0f);
|
||||
regs.ppu2_mdr = r;
|
||||
return regs.ppu2_mdr;
|
||||
}
|
||||
|
@@ -104,32 +104,30 @@ Mode7: ->
|
||||
1, 2, 3, 4, 5
|
||||
OAM0, BG1n, OAM1, OAM2, OAM3
|
||||
|
||||
***
|
||||
This appears to be incorrect, possibly should be...
|
||||
Mode 7 EXTBG: ->
|
||||
1, 2, 3, 4, 5, 6, 7
|
||||
BG2B, OAM0, BG1n, OAM1, BG2A, OAM2, OAM3
|
||||
***
|
||||
Mode 7 (extbg): ->
|
||||
1, 2, 3, 4, 5, 6
|
||||
BG2B, OAM0, OAM1, BG2A, OAM2, OAM3
|
||||
*/
|
||||
inline void bPPU::render_line_mode7() {
|
||||
if(regs.mode7_extbg == false) {
|
||||
render_line_mode7(2, 0, 0); //bg2 priorities are ignored
|
||||
render_line_mode7(BG1, 2, 2);
|
||||
render_line_oam(1, 3, 4, 5);
|
||||
} else {
|
||||
render_line_mode7(0, 1, 4); //bg1 priority is ignored
|
||||
render_line_oam(2, 3, 5, 6);
|
||||
render_line_mode7(BG1, 3, 3);
|
||||
render_line_mode7(BG2, 1, 5);
|
||||
render_line_oam(2, 4, 6, 7);
|
||||
}
|
||||
}
|
||||
|
||||
void bPPU::render_line() {
|
||||
if(regs.display_disabled == true) {
|
||||
memset(output->buffer + (_y << 10), 0, 2048);
|
||||
memset(snes->get_ppu_output_handle(), 0, 1024);
|
||||
return;
|
||||
}
|
||||
|
||||
clear_pixel_cache();
|
||||
build_color_window_tables();
|
||||
build_window_tables(COL);
|
||||
|
||||
switch(regs.bg_mode) {
|
||||
case 0:render_line_mode0();break;
|
||||
case 1:render_line_mode1();break;
|
||||
@@ -140,5 +138,6 @@ void bPPU::render_line() {
|
||||
case 6:render_line_mode6();break;
|
||||
case 7:render_line_mode7();break;
|
||||
}
|
||||
|
||||
render_line_output();
|
||||
}
|
||||
|
@@ -18,32 +18,35 @@ enum { TILE_2BIT = 0, TILE_4BIT = 1, TILE_8BIT = 2 };
|
||||
|
||||
enum { PC_BG1 = 0x80, PC_BG2 = 0x81, PC_BG3 = 0x82, PC_BG4 = 0x83, PC_OAM = 0x84, PC_BACK = 0x00 };
|
||||
struct _pixel {
|
||||
//palette # index for main/subscreen pixels
|
||||
//0 = transparent / use palette color # 0
|
||||
uint8 src_main, src_sub;
|
||||
//bgr555 color data for main/subscreen pixels: 0x0000 = transparent / use palette color # 0
|
||||
//needs to be bgr555 instead of palette index for direct color mode ($2130 bit 0) to work
|
||||
uint16 src_main, src_sub;
|
||||
//indicates source of palette # for main/subscreen (BG1-4, OAM, or back)
|
||||
uint8 bg_main, bg_sub;
|
||||
uint8 bg_main, bg_sub;
|
||||
//true when bg_main == OAM && palette index >= 192, disables color add/sub effects
|
||||
uint8 color_exempt;
|
||||
//priority level of src_n. to set src_n,
|
||||
//the priority of the pixel must be >pri_n
|
||||
uint8 pri_main, pri_sub;
|
||||
}pixel_cache[512];
|
||||
uint8 pri_main, pri_sub;
|
||||
} pixel_cache[512];
|
||||
|
||||
uint8 *bg_tiledata[3];
|
||||
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);
|
||||
@@ -55,7 +58,7 @@ uint8 oam_itemlist[32];
|
||||
struct oam_tileitem {
|
||||
uint16 x, y, pri, pal, tile;
|
||||
bool hflip;
|
||||
}oam_tilelist[34];
|
||||
} oam_tilelist[34];
|
||||
|
||||
enum { OAM_PRI_NONE = 4 };
|
||||
uint8 oam_line_pal[512], oam_line_pri[512];
|
||||
@@ -66,15 +69,16 @@ void render_oam_tile(int tile_num);
|
||||
void render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos);
|
||||
|
||||
//bppu_render_mode7.cpp
|
||||
void render_line_mode7(uint8 bg1_pri, uint8 bg2b_pri, uint8 bg2a_pri);
|
||||
void render_line_mode7(uint8 bg, uint8 pri0_pos, uint8 pri1_pos);
|
||||
|
||||
//bppu_render_addsub.cpp
|
||||
inline uint16 addsub_pixels(int cdest_index, int cdest_bg, int csrc_index, int csrc_bg);
|
||||
inline uint16 addsub_pixel(int cdest_index, int cdest_bg);
|
||||
inline uint16 addsub_pixels(uint32 cdest, uint32 csrc);
|
||||
inline uint16 addsub_pixel (uint32 cdest);
|
||||
|
||||
//bppu_render_line.cpp
|
||||
enum { BLENDTYPE_BACK = 0, BLENDTYPE_MAIN = 1, BLENDTYPE_SUB = 2, BLENDTYPE_COMBINE = 3 };
|
||||
|
||||
inline uint16 get_palette(int index);
|
||||
inline uint16 get_palette(uint8 index);
|
||||
inline uint16 get_direct_color(uint8 p, uint8 t);
|
||||
inline uint16 get_pixel(int x);
|
||||
inline void render_line_output();
|
||||
|
@@ -1,15 +1,6 @@
|
||||
inline uint16 bPPU::addsub_pixels(int cdest_index, int cdest_bg, int csrc_index, int csrc_bg) {
|
||||
inline uint16 bPPU::addsub_pixels(uint32 cdest, uint32 csrc) {
|
||||
int r, g, b;
|
||||
uint32 cdest = get_palette(cdest_index);
|
||||
uint32 csrc = get_palette(csrc_index);
|
||||
uint16 res;
|
||||
//oam palettes 0-3 are not affected by color add/sub
|
||||
if(cdest_bg == OAM) {
|
||||
if(cdest_index < 192) {
|
||||
return cdest;
|
||||
}
|
||||
}
|
||||
|
||||
switch(regs.color_mode) {
|
||||
case 0: //COLORMODE_ADD:
|
||||
if(regs.color_halve == true) {
|
||||
@@ -53,18 +44,10 @@ uint16 res;
|
||||
return 0x0000; //prevent annoying warning message
|
||||
}
|
||||
|
||||
inline uint16 bPPU::addsub_pixel(int cdest_index, int cdest_bg) {
|
||||
inline uint16 bPPU::addsub_pixel(uint32 cdest) {
|
||||
int r, g, b;
|
||||
uint32 cdest = get_palette(cdest_index);
|
||||
uint32 csrc = (regs.color_r) | (regs.color_g << 5) | (regs.color_b << 10);
|
||||
uint16 res;
|
||||
//only oam palettes 4-7 are affected by color add/sub
|
||||
if(cdest_bg == OAM) {
|
||||
if(cdest_index < 192) {
|
||||
return cdest;
|
||||
}
|
||||
}
|
||||
|
||||
switch(regs.color_mode) {
|
||||
case 0: //COLORMODE_ADD:
|
||||
if(regs.color_halve == true && regs.addsub_mode == 0) {
|
||||
|
@@ -3,7 +3,7 @@ void bPPU::render_line_bg(uint8 bg, uint8 color_depth, uint8 pri0_pos, uint8 pri
|
||||
return;
|
||||
}
|
||||
|
||||
int x;
|
||||
int x;
|
||||
int _scaddr = regs.bg_scaddr[bg];
|
||||
int _tdaddr = regs.bg_tdaddr[bg];
|
||||
bool _bg_enabled = regs.bg_enabled[bg];
|
||||
@@ -25,17 +25,7 @@ uint16 opt_valid_bit; //offset-per-tile valid flag bit
|
||||
//entry point. This allows all 256 palette colors
|
||||
//to be used, instead of just the first 32.
|
||||
//entry = bg * 32, where 32 is from 8 * 4
|
||||
uint8 bgpal_index;
|
||||
if(regs.bg_mode == 0) {
|
||||
switch(bg) {
|
||||
case BG1:bgpal_index = 0;break;
|
||||
case BG2:bgpal_index = 32;break;
|
||||
case BG3:bgpal_index = 64;break;
|
||||
case BG4:bgpal_index = 96;break;
|
||||
}
|
||||
} else {
|
||||
bgpal_index = 0;
|
||||
}
|
||||
uint8 bgpal_index = (regs.bg_mode == 0) ? (bg << 5) : 0;
|
||||
|
||||
uint8 pal_size, tiledata_size;
|
||||
switch(color_depth) {
|
||||
@@ -114,37 +104,44 @@ int mosaic_x, mosaic_y;
|
||||
} else {
|
||||
mtable = (uint16*)mosaic_table[0];
|
||||
}
|
||||
|
||||
mosaic_x = mtable[bg_x];
|
||||
mosaic_y = mtable[bg_y];
|
||||
|
||||
uint8 tile_x;
|
||||
uint16 t, base_xpos, base_pos, pos;
|
||||
uint16 tile_num;
|
||||
int mirror_x, mirror_y;
|
||||
uint8 pal_index;
|
||||
int mirror_x, mirror_y;
|
||||
uint8 pal_index, pal_num;
|
||||
uint8 *tile_ptr;
|
||||
int xpos, ypos;
|
||||
uint16 map_index, hoffset, voffset, col;
|
||||
|
||||
uint8 *wt_main = main_windowtable[bg];
|
||||
uint8 *wt_sub = sub_windowtable[bg];
|
||||
build_window_tables(bg);
|
||||
for(screen_x=0;screen_x<_screen_width;screen_x++) {
|
||||
//offset-per-tile mode. horizontal OPT is buggy, so it is disabled
|
||||
//vertical OPT seems to be working OK...
|
||||
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++) {
|
||||
if(regs.bg_mode == 2 || regs.bg_mode == 4 || regs.bg_mode == 6) {
|
||||
if(regs.bg_mode == 6) {
|
||||
//hires adjust
|
||||
tile_x = (mtable[screen_x + (hscroll & 15)] >> 4);
|
||||
} else {
|
||||
tile_x = (mtable[screen_x + (hscroll & 7)] >> 3);
|
||||
}
|
||||
|
||||
hoffset = hscroll;
|
||||
voffset = vscroll;
|
||||
|
||||
//tile 0 is unaffected by OPT mode...
|
||||
if(tile_x != 0) {
|
||||
tile_x = (tile_x - 1) & 31;
|
||||
//multiply by two to index into 16-bit table entries
|
||||
tile_x = ((tile_x - 1) & 31) << 1;
|
||||
|
||||
if(regs.bg_mode == 4) {
|
||||
pos = regs.bg_scaddr[BG3] + (tile_x << 1);
|
||||
t = *((uint16*)vram + (pos >> 1));
|
||||
pos = regs.bg_scaddr[BG3] + tile_x;
|
||||
t = read16(vram, pos);
|
||||
if(t & opt_valid_bit) {
|
||||
if(!(t & 0x8000)) {
|
||||
hoffset = ((t & 0x1ff8) | (hscroll & 7)) & screen_width_mask;
|
||||
@@ -153,18 +150,19 @@ uint8 *wt_sub = sub_windowtable[bg];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pos = regs.bg_scaddr[BG3] + (tile_x << 1);
|
||||
t = *((uint16*)vram + (pos >> 1));
|
||||
pos = regs.bg_scaddr[BG3] + tile_x;
|
||||
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 << 1);
|
||||
t = *((uint16*)vram + (pos >> 1));
|
||||
pos = regs.bg_scaddr[BG3] + 64 + tile_x;
|
||||
t = read16(vram, pos);
|
||||
if(t & opt_valid_bit) {
|
||||
voffset = (t & 0x1fff) & screen_height_mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mosaic_x = mtable[(screen_x + hoffset) & screen_width_mask ];
|
||||
mosaic_y = mtable[(screen_y + voffset) & screen_height_mask];
|
||||
}
|
||||
@@ -188,31 +186,37 @@ 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));
|
||||
mirror_y = (t & 0x8000)?1:0;
|
||||
mirror_x = (t & 0x4000)?1:0;
|
||||
t = read16(vram, pos);
|
||||
mirror_y = !!(t & 0x8000);
|
||||
mirror_x = !!(t & 0x4000);
|
||||
|
||||
int _pri;
|
||||
_pri = (t & 0x2000) ? pri1_pos : pri0_pos;
|
||||
|
||||
tile_num = t & 0x03ff;
|
||||
|
||||
//16x16 horizontal tile mirroring
|
||||
if(tile_width == 4) {
|
||||
if(((mosaic_x & 15) >= 8 && !mirror_x) ||
|
||||
((mosaic_x & 15) < 8 && mirror_x))tile_num++;
|
||||
tile_num &= 0x03ff;
|
||||
}
|
||||
|
||||
//16x16 vertical tile mirroring
|
||||
if(tile_height == 4) {
|
||||
if(((mosaic_y & 15) >= 8 && !mirror_y) ||
|
||||
((mosaic_y & 15) < 8 && mirror_y))tile_num += 16;
|
||||
tile_num &= 0x03ff;
|
||||
}
|
||||
|
||||
tile_num += (_tdaddr >> tiledata_size);
|
||||
|
||||
if(bg_td_state[tile_num] == 1) {
|
||||
render_bg_tile(color_depth, tile_num);
|
||||
}
|
||||
|
||||
pal_index = ((t >> 10) & 7) * pal_size + bgpal_index;
|
||||
pal_num = ((t >> 10) & 7);
|
||||
pal_index = pal_num * pal_size + bgpal_index;
|
||||
|
||||
if(mirror_y) { ypos = (7 - (mosaic_y & 7)); }
|
||||
else { ypos = ( (mosaic_y & 7)); }
|
||||
@@ -220,23 +224,30 @@ int _pri;
|
||||
//loop while we are rendering from the same tile, as there's no need to do all of the above work
|
||||
//unless we have rendered all of the visible tile, taking mosaic into account.
|
||||
tile_ptr = (uint8*)bg_td + (tile_num << 6) + (ypos << 3);
|
||||
while(1) {
|
||||
do {
|
||||
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 {
|
||||
col = get_palette(col + pal_index);
|
||||
}
|
||||
|
||||
if(_bg_enabled == true && !wt_main[screen_x]) {
|
||||
if(pixel_cache[screen_x].pri_main < _pri) {
|
||||
pixel_cache[screen_x].pri_main = _pri;
|
||||
pixel_cache[screen_x].bg_main = 0x80 | bg;
|
||||
pixel_cache[screen_x].src_main = col + pal_index;
|
||||
pixel_cache[screen_x].src_main = col;
|
||||
pixel_cache[screen_x].color_exempt = false;
|
||||
}
|
||||
}
|
||||
if(_bgsub_enabled == true && !wt_sub[screen_x]) {
|
||||
if(pixel_cache[screen_x].pri_sub < _pri) {
|
||||
pixel_cache[screen_x].pri_sub = _pri;
|
||||
pixel_cache[screen_x].bg_sub = 0x80 | bg;
|
||||
pixel_cache[screen_x].src_sub = col + pal_index;
|
||||
pixel_cache[screen_x].src_sub = col;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -246,8 +257,7 @@ int _pri;
|
||||
mosaic_x = mtable[bg_x];
|
||||
|
||||
if(base_xpos != ((mosaic_x >> 3) & 31))break;
|
||||
screen_x++;
|
||||
if(screen_x >= _screen_width)break;
|
||||
}
|
||||
}
|
||||
if(++screen_x >= _screen_width)break;
|
||||
} while(1);
|
||||
} while(++screen_x < _screen_width);
|
||||
}
|
||||
|
@@ -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,46 +1,55 @@
|
||||
inline uint16 bPPU::get_palette(int index) {
|
||||
return *((uint16*)cgram + index);
|
||||
inline uint16 bPPU::get_palette(uint8 index) {
|
||||
return read16(cgram, index << 1);
|
||||
}
|
||||
|
||||
inline uint16 bPPU::get_direct_color(uint8 p, uint8 t) {
|
||||
//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);
|
||||
}
|
||||
|
||||
inline uint16 bPPU::get_pixel(int x) {
|
||||
_pixel *p = &pixel_cache[x];
|
||||
uint16 _r;
|
||||
uint16 _r, src_back = get_palette(0);
|
||||
if(p->bg_main && p->bg_sub) {
|
||||
if(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->bg_main & 0x7f, p->src_sub, p->bg_sub & 0x7f);
|
||||
_r = addsub_pixels(p->src_main, p->src_sub);
|
||||
} else {
|
||||
_r = addsub_pixel(p->src_main, p->bg_main & 0x7f);
|
||||
_r = addsub_pixel(p->src_main);
|
||||
}
|
||||
} else {
|
||||
_r = get_palette(p->src_main);
|
||||
_r = p->src_main;
|
||||
}
|
||||
} else if(p->bg_main) {
|
||||
if(regs.bg_color_enabled[p->bg_main & 0x7f] && sub_colorwindowtable[x]) {
|
||||
_r = addsub_pixel(p->src_main, p->bg_main & 0x7f);
|
||||
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 = get_palette(p->src_main);
|
||||
_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(0, BACK, p->src_sub, p->bg_sub & 0x7f);
|
||||
_r = addsub_pixels(src_back, p->src_sub);
|
||||
} else {
|
||||
_r = addsub_pixel(0, BACK);
|
||||
_r = addsub_pixel(src_back);
|
||||
}
|
||||
} else {
|
||||
_r = 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]) {
|
||||
_r = addsub_pixel(0, BACK);
|
||||
if(window_cache[COL].main[x]) {
|
||||
if(regs.color_enabled[BACK] && window_cache[COL].sub[x]) {
|
||||
_r = addsub_pixel(src_back);
|
||||
} else {
|
||||
_r = get_palette(0);
|
||||
_r = src_back;
|
||||
}
|
||||
} else {
|
||||
_r = 0x0000;
|
||||
@@ -53,10 +62,7 @@ inline void bPPU::render_line_output() {
|
||||
int x;
|
||||
uint16 _r;
|
||||
uint16 *ptr;
|
||||
ptr = (uint16*)output->buffer + (_y << 10);
|
||||
if(_interlace == true) {
|
||||
ptr += _interlace_field << 9;
|
||||
}
|
||||
ptr = (uint16*)snes->get_ppu_output_handle();
|
||||
|
||||
uint16 *ltable;
|
||||
ltable = (uint16*)light_table + (regs.display_brightness << 15);
|
||||
@@ -64,8 +70,7 @@ uint16 *ltable;
|
||||
if(_screen_width == 256) {
|
||||
for(x=0;x<256;x++) {
|
||||
_r = get_pixel(x);
|
||||
*ptr = *(ltable + _r);
|
||||
ptr += 2;
|
||||
*ptr++ = *(ltable + _r);
|
||||
}
|
||||
} else {
|
||||
for(x=0;x<512;x++) {
|
||||
|
@@ -1,62 +1,73 @@
|
||||
#define CLIP_10BIT_SIGNED(x) \
|
||||
((x) & ((1 << 10) - 1)) + (((((x) & (1 << 13)) ^ (1 << 13)) - (1 << 13)) >> 3)
|
||||
/*
|
||||
bsnes mode7 renderer
|
||||
|
||||
#define CAST_WORDTOINT(x) \
|
||||
(int32)(((x & 0x8000) ? (x | 0xffff0000) : (x & 0x00007fff)))
|
||||
base algorithm written by anomie
|
||||
bsnes implementation written by byuu
|
||||
|
||||
supports mode 7 + extbg + rotate + zoom + direct color + scrolling + m7sel + windowing + mosaic
|
||||
does not support pseudo-hires
|
||||
interlace support is automatic via main rendering routine
|
||||
*/
|
||||
|
||||
//13-bit sign extend
|
||||
//--s---vvvvvvvvvv -> ssssssvvvvvvvvvv
|
||||
#define CLIP(x) ( ((x) & 0x2000) ? ( (x) | ~0x03ff) : ((x) & 0x03ff) )
|
||||
//#define CLIP(x) ( ((x) & 0x03ff) | (((x) & 0x2000) ? -0x0400 : 0) )
|
||||
|
||||
void bPPU::render_line_mode7(uint8 bg, uint8 pri0_pos, uint8 pri1_pos) {
|
||||
if(regs.bg_enabled[bg] == false && regs.bgsub_enabled[bg] == false)return;
|
||||
|
||||
int32 x, y;
|
||||
int32 a, b, c, d, cx, cy;
|
||||
int32 hofs, vofs;
|
||||
|
||||
void bPPU::render_line_mode7(uint8 bg1_pri, uint8 bg2b_pri, uint8 bg2a_pri) {
|
||||
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;
|
||||
hoffset = ((int32)regs.m7_hofs << 19) >> 19;
|
||||
voffset = ((int32)regs.m7_vofs << 19) >> 19;
|
||||
a = int32(int16(regs.m7a));
|
||||
b = int32(int16(regs.m7b));
|
||||
c = int32(int16(regs.m7c));
|
||||
d = int32(int16(regs.m7d));
|
||||
|
||||
centerx = ((int32)regs.m7x << 19) >> 19;
|
||||
centery = ((int32)regs.m7y << 19) >> 19;
|
||||
cx = (int32(regs.m7x) << 19) >> 19;
|
||||
cy = (int32(regs.m7y) << 19) >> 19;
|
||||
hofs = (int32(regs.m7_hofs) << 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 = window_cache[bg].main;
|
||||
uint8 *wt_sub = window_cache[bg].sub;
|
||||
|
||||
if(regs.mode7_vflip == true) {
|
||||
yy = 255 - _y;
|
||||
y = 255 - _y;
|
||||
} else {
|
||||
yy = _y;
|
||||
}
|
||||
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, _bg;
|
||||
bool _bg_enabled, _bgsub_enabled;
|
||||
if(regs.mode7_extbg == false) {
|
||||
_pri = bg1_pri;
|
||||
_bg = BG1;
|
||||
_bg_enabled = regs.bg_enabled[BG1];
|
||||
_bgsub_enabled = regs.bgsub_enabled[BG1];
|
||||
} else {
|
||||
_bg = BG2;
|
||||
_bg_enabled = regs.bg_enabled[BG2];
|
||||
_bgsub_enabled = regs.bgsub_enabled[BG2];
|
||||
y = _y;
|
||||
}
|
||||
|
||||
uint8 *wt_main = main_windowtable[_bg];
|
||||
uint8 *wt_sub = sub_windowtable[_bg];
|
||||
build_window_tables(_bg);
|
||||
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];
|
||||
}
|
||||
|
||||
int32 psx = ((a * CLIP(hofs - cx)) & ~63) + ((b * CLIP(vofs - cy)) & ~63) + ((b * mtable_y[y]) & ~63) + (cx << 8);
|
||||
int32 psy = ((c * CLIP(hofs - cx)) & ~63) + ((d * CLIP(vofs - cy)) & ~63) + ((d * mtable_y[y]) & ~63) + (cy << 8);
|
||||
for(x=0;x<256;x++) {
|
||||
px = ((m7a + m7b) >> 8);
|
||||
py = ((m7c + m7d) >> 8);
|
||||
px = psx + (a * mtable_x[x]);
|
||||
py = psy + (c * mtable_x[x]);
|
||||
|
||||
//mask floating-point bits (low 8 bits)
|
||||
px >>= 8;
|
||||
py >>= 8;
|
||||
|
||||
switch(regs.mode7_repeat) {
|
||||
case 0: //screen repitition outside of screen area
|
||||
@@ -68,20 +79,7 @@ uint8 *wt_sub = sub_windowtable[_bg];
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
break;
|
||||
case 2: //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;
|
||||
case 3: //palette color 0 outside of screen area
|
||||
case 2: //palette color 0 outside of screen area
|
||||
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
|
||||
palette = 0;
|
||||
} else {
|
||||
@@ -93,46 +91,61 @@ uint8 *wt_sub = sub_windowtable[_bg];
|
||||
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) {
|
||||
tile = 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(!palette)goto _end_setpixel;
|
||||
|
||||
if(regs.mode7_extbg == false) {
|
||||
//_pri set at top of function, as it is static
|
||||
if(regs.mode7_hflip == true) {
|
||||
_x = 255 - x;
|
||||
} else {
|
||||
_x = x;
|
||||
}
|
||||
if(bg == BG1) {
|
||||
_pri = pri0_pos;
|
||||
} else {
|
||||
_pri = (palette >> 7) ? bg2a_pri : bg2b_pri;
|
||||
_pri = (palette >> 7) ? pri1_pos : pri0_pos;
|
||||
palette &= 0x7f;
|
||||
if(regs.mode7_hflip == true) {
|
||||
_x = 255 - x;
|
||||
} else {
|
||||
_x = x;
|
||||
}
|
||||
}
|
||||
|
||||
if(main_colorwindowtable[_x]) {
|
||||
if(_bg_enabled == true && !wt_main[_x]) {
|
||||
if(!palette)continue;
|
||||
|
||||
if(regs.mode7_hflip == true) {
|
||||
_x = 255 - x;
|
||||
} else {
|
||||
_x = 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...
|
||||
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 = palette;
|
||||
pixel_cache[_x].bg_main = 0x80 | bg;
|
||||
pixel_cache[_x].src_main = col;
|
||||
pixel_cache[_x].color_exempt = false;
|
||||
}
|
||||
}
|
||||
if(_bgsub_enabled == true && !wt_sub[_x]) {
|
||||
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 = palette;
|
||||
pixel_cache[_x].bg_sub = 0x80 | bg;
|
||||
pixel_cache[_x].src_sub = col;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_end_setpixel:
|
||||
m7a += step_m7a;
|
||||
m7c += step_m7c;
|
||||
}
|
||||
}
|
||||
|
||||
#undef CLIP
|
||||
|
@@ -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,19 +252,20 @@ 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;
|
||||
pixel_cache[x].bg_main = PC_OAM;
|
||||
pixel_cache[x].src_main = oam_line_pal[x];
|
||||
pixel_cache[x].src_main = get_palette(oam_line_pal[x]);
|
||||
pixel_cache[x].color_exempt = (oam_line_pal[x] < 192);
|
||||
}
|
||||
}
|
||||
if(_bgsub_enabled == true && !wt_sub[x]) {
|
||||
if(pixel_cache[x].pri_sub < _pri) {
|
||||
pixel_cache[x].pri_sub = _pri;
|
||||
pixel_cache[x].bg_sub = PC_OAM;
|
||||
pixel_cache[x].src_sub = oam_line_pal[x];
|
||||
pixel_cache[x].src_sub = get_palette(oam_line_pal[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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,27 +1,38 @@
|
||||
#include "../base.h"
|
||||
|
||||
PPUOutput::PPUOutput() {
|
||||
buffer = (uint16*)memalloc(512 * 478 * 2, "PPUOutput::buffer");
|
||||
memset(buffer, 0, 512 * 478 * 2);
|
||||
hires = false;
|
||||
interlace = false;
|
||||
for(int i=0;i<239;i++) {
|
||||
line[i].hires = false;
|
||||
line[i].interlace = false;
|
||||
void PPU::get_scanline_info(scanline_info *info) {
|
||||
info->hires = scanline_is_hires();
|
||||
info->interlace = cpu->interlace();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
PPUOutput::~PPUOutput() {
|
||||
if(buffer)memfree(buffer, "PPUOutput::buffer");
|
||||
}
|
||||
|
||||
void PPU::set_frameskip(int fs) {}
|
||||
|
||||
PPU::PPU() {
|
||||
status.render_output = true;
|
||||
status.frames_updated = false;
|
||||
status.frames_rendered = 0;
|
||||
status.frames_executed = 0;
|
||||
|
||||
ppu1_version = 1;
|
||||
ppu2_version = 1;
|
||||
mmio = &mmio_unmapped;
|
||||
output = new PPUOutput();
|
||||
}
|
||||
|
||||
PPU::~PPU() {
|
||||
if(output)delete(output);
|
||||
}
|
||||
PPU::~PPU() {}
|
||||
|
@@ -1,19 +1,36 @@
|
||||
class PPUOutput {
|
||||
public:
|
||||
bool hires, interlace;
|
||||
struct {
|
||||
bool hires, interlace;
|
||||
}line[239];
|
||||
uint16 *buffer;
|
||||
PPUOutput();
|
||||
~PPUOutput();
|
||||
};
|
||||
|
||||
class PPU {
|
||||
public:
|
||||
int _y;
|
||||
PPUOutput *output;
|
||||
MMIO *mmio;
|
||||
|
||||
//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
|
||||
uint8 ppu1_version;
|
||||
|
||||
//PPU2 version number
|
||||
//* 1 and 3 are known
|
||||
//* reported by $213f
|
||||
uint8 ppu2_version;
|
||||
|
||||
int _y;
|
||||
MMIO *mmio;
|
||||
|
||||
struct scanline_info {
|
||||
bool hires;
|
||||
bool interlace;
|
||||
};
|
||||
virtual bool scanline_is_hires() = 0;
|
||||
virtual void get_scanline_info(scanline_info *info);
|
||||
|
||||
virtual uint8 vram_read (uint16 addr) = 0;
|
||||
virtual void vram_write (uint16 addr, uint8 value) = 0;
|
||||
virtual uint8 oam_read (uint16 addr) = 0;
|
||||
@@ -25,10 +42,12 @@ MMIO *mmio;
|
||||
|
||||
virtual void run() = 0;
|
||||
virtual void scanline() = 0;
|
||||
virtual void frame() = 0;
|
||||
virtual void render_scanline() = 0;
|
||||
virtual void frame();
|
||||
virtual void power() = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual void set_frameskip(int fs);
|
||||
virtual void enable_renderer(bool r);
|
||||
virtual bool renderer_enabled();
|
||||
|
||||
PPU();
|
||||
~PPU();
|
||||
|
@@ -1,11 +1,12 @@
|
||||
CC = c++
|
||||
CFLAGS = -O2
|
||||
CFLAGS = -O3 -fomit-frame-pointer -ffast-math
|
||||
OBJS = sdlmain.o \
|
||||
libstring.o libconfig.o \
|
||||
reader.o \
|
||||
memory.o bmemory.o \
|
||||
cpu.o bcpu.o \
|
||||
apu.o bapu.o bapuskip.o \
|
||||
bdsp.o \
|
||||
ppu.o bppu.o \
|
||||
snes.o \
|
||||
srtc.o sdd1.o
|
||||
@@ -60,6 +61,12 @@ bapu.o: ../apu/bapu/*
|
||||
bapuskip.o: ../apu/bapuskip/*
|
||||
$(CC) $(CFLAGS) -c ../apu/bapuskip/bapuskip.cpp
|
||||
|
||||
###########
|
||||
### dsp ###
|
||||
###########
|
||||
bdsp.o: ../dsp/bdsp/*
|
||||
$(CC) $(CFLAGS) -c ../dsp/bdsp/bdsp.cpp
|
||||
|
||||
###########
|
||||
### ppu ###
|
||||
###########
|
||||
|
@@ -1,11 +1,12 @@
|
||||
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 \
|
||||
memory.obj bmemory.obj \
|
||||
cpu.obj bcpu.obj \
|
||||
apu.obj bapu.obj bapuskip.obj \
|
||||
bdsp.obj \
|
||||
ppu.obj bppu.obj \
|
||||
snes.obj \
|
||||
srtc.obj sdd1.obj
|
||||
@@ -61,6 +62,12 @@ bapu.obj: ../apu/bapu/*
|
||||
bapuskip.obj: ../apu/bapuskip/*
|
||||
$(CC) $(CFLAGS) /c ../apu/bapuskip/bapuskip.cpp
|
||||
|
||||
###########
|
||||
### dsp ###
|
||||
###########
|
||||
bdsp.obj: ../dsp/bdsp/*
|
||||
$(CC) $(CFLAGS) /c ../dsp/bdsp/bdsp.cpp
|
||||
|
||||
###########
|
||||
### ppu ###
|
||||
###########
|
||||
|
@@ -1,13 +1,13 @@
|
||||
void bSNES::set_status(uint32 new_status) { run_status = new_status; }
|
||||
uint32 bSNES::get_status() { return run_status; }
|
||||
|
||||
void bSNES::snes_run() {
|
||||
void bSNES::run() {
|
||||
if(!rom_image->loaded())return;
|
||||
|
||||
switch(run_status) {
|
||||
case RUN:
|
||||
while(update_frame == false) {
|
||||
run();
|
||||
SNES::run();
|
||||
}
|
||||
update_frame = false;
|
||||
render();
|
||||
@@ -17,29 +17,46 @@ void bSNES::snes_run() {
|
||||
}
|
||||
}
|
||||
|
||||
void bSNES::render_frame() {}
|
||||
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[cfg.input.joypad1.up];
|
||||
joypad1.down = keystate[cfg.input.joypad1.down];
|
||||
joypad1.left = keystate[cfg.input.joypad1.left];
|
||||
joypad1.right = keystate[cfg.input.joypad1.right];
|
||||
joypad1.select = keystate[cfg.input.joypad1.select];
|
||||
joypad1.start = keystate[cfg.input.joypad1.start];
|
||||
joypad1.y = keystate[cfg.input.joypad1.y];
|
||||
joypad1.b = keystate[cfg.input.joypad1.b];
|
||||
joypad1.x = keystate[cfg.input.joypad1.x];
|
||||
joypad1.a = keystate[cfg.input.joypad1.a];
|
||||
joypad1.l = keystate[cfg.input.joypad1.l];
|
||||
joypad1.r = keystate[cfg.input.joypad1.r];
|
||||
joypad1.up = keystate[(int)config::input.joypad1.up];
|
||||
joypad1.down = keystate[(int)config::input.joypad1.down];
|
||||
joypad1.left = keystate[(int)config::input.joypad1.left];
|
||||
joypad1.right = keystate[(int)config::input.joypad1.right];
|
||||
joypad1.select = keystate[(int)config::input.joypad1.select];
|
||||
joypad1.start = keystate[(int)config::input.joypad1.start];
|
||||
joypad1.y = keystate[(int)config::input.joypad1.y];
|
||||
joypad1.b = keystate[(int)config::input.joypad1.b];
|
||||
joypad1.x = keystate[(int)config::input.joypad1.x];
|
||||
joypad1.a = keystate[(int)config::input.joypad1.a];
|
||||
joypad1.l = keystate[(int)config::input.joypad1.l];
|
||||
joypad1.r = keystate[(int)config::input.joypad1.r];
|
||||
|
||||
//It's impossible to hold both up+down, or left+right down
|
||||
//at the same time on a directional pad; and besides, allowing
|
||||
|
@@ -14,13 +14,15 @@ bJoypad joypad1, joypad2;
|
||||
|
||||
public:
|
||||
enum { STOP = 0, RUN };
|
||||
void run();
|
||||
void video_run();
|
||||
void sound_run();
|
||||
|
||||
void set_status(uint32 new_status);
|
||||
uint32 get_status();
|
||||
void snes_run();
|
||||
void render_frame();
|
||||
|
||||
//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);
|
||||
|
@@ -1,18 +1,86 @@
|
||||
apu.enabled = true
|
||||
# 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
|
||||
video.display_width = 256
|
||||
video.display_height = 223
|
||||
|
||||
# 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
|
||||
input.joypad1.start = 0x0d
|
||||
|
||||
# Joypad1 start
|
||||
# (default = 0xd)
|
||||
input.joypad1.start = 0xd
|
||||
|
||||
|
@@ -1,3 +1,2 @@
|
||||
@nmake /NOLOGO /f Makefile.win32
|
||||
@move bsnes_sdl.exe ../../bsnes_sdl.exe>nul
|
||||
@pause
|
@@ -1,47 +1,32 @@
|
||||
#define __config_add(name, def, type) add(&name, #name, def, type)
|
||||
namespace config {
|
||||
|
||||
class Config : public config {
|
||||
public:
|
||||
struct Video {
|
||||
static Setting fullscreen;
|
||||
static Setting display_width, display_height;
|
||||
static Setting output_width, output_height;
|
||||
} video;
|
||||
Setting Video::fullscreen(&config_file, "video.fullscreen", "Enable fullscreen mode at startup", false, Setting::TRUE_FALSE);
|
||||
Setting Video::display_width (&config_file, "video.display_width", "Window / Fullscreen width", 320, Setting::DEC);
|
||||
Setting Video::display_height(&config_file, "video.display_height", "Window / Fullscreen height", 240, Setting::DEC);
|
||||
Setting Video::output_width (&config_file, "video.output_width", "SNES video output width", 256, Setting::DEC);
|
||||
Setting Video::output_height (&config_file, "video.output_height", "SNES video output height", 223, Setting::DEC);
|
||||
|
||||
struct {
|
||||
uint32 enabled;
|
||||
}apu;
|
||||
struct Input {
|
||||
struct Joypad {
|
||||
static Setting up, down, left, right, a, b, x, y, l, r, select, start;
|
||||
} joypad1;
|
||||
} input;
|
||||
Setting Input::Joypad::up (&config_file, "input.joypad1.up", "Joypad1 up", SDLK_UP, Setting::HEX);
|
||||
Setting Input::Joypad::down (&config_file, "input.joypad1.down", "Joypad1 down", SDLK_DOWN, Setting::HEX);
|
||||
Setting Input::Joypad::left (&config_file, "input.joypad1.left", "Joypad1 left", SDLK_LEFT, Setting::HEX);
|
||||
Setting Input::Joypad::right (&config_file, "input.joypad1.right", "Joypad1 right", SDLK_RIGHT, Setting::HEX);
|
||||
Setting Input::Joypad::a (&config_file, "input.joypad1.a", "Joypad1 A", SDLK_x, Setting::HEX);
|
||||
Setting Input::Joypad::b (&config_file, "input.joypad1.b", "Joypad1 B", SDLK_z, Setting::HEX);
|
||||
Setting Input::Joypad::x (&config_file, "input.joypad1.x", "Joypad1 X", SDLK_s, Setting::HEX);
|
||||
Setting Input::Joypad::y (&config_file, "input.joypad1.y", "Joypad1 Y", SDLK_a, Setting::HEX);
|
||||
Setting Input::Joypad::l (&config_file, "input.joypad1.l", "Joypad1 L", SDLK_d, Setting::HEX);
|
||||
Setting Input::Joypad::r (&config_file, "input.joypad1.r", "Joypad1 R", SDLK_c, Setting::HEX);
|
||||
Setting Input::Joypad::select(&config_file, "input.joypad1.select", "Joypad1 select", SDLK_RSHIFT, Setting::HEX);
|
||||
Setting Input::Joypad::start (&config_file, "input.joypad1.start", "Joypad1 start", SDLK_RETURN, Setting::HEX);
|
||||
|
||||
struct {
|
||||
uint32 fullscreen;
|
||||
uint32 display_width, display_height;
|
||||
uint32 output_width, output_height;
|
||||
}video;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
uint32 up, down, left, right;
|
||||
uint32 a, b, x, y, l, r;
|
||||
uint32 select, start;
|
||||
}joypad1;
|
||||
}input;
|
||||
|
||||
Config() {
|
||||
__config_add(apu.enabled, true, TRUEFALSE);
|
||||
|
||||
__config_add(video.fullscreen, false, TRUEFALSE);
|
||||
__config_add(video.display_width, 256, DEC);
|
||||
__config_add(video.display_height, 223, DEC);
|
||||
__config_add(video.output_width, 256, DEC);
|
||||
__config_add(video.output_height, 223, DEC);
|
||||
|
||||
__config_add(input.joypad1.up, SDLK_UP, HEX);
|
||||
__config_add(input.joypad1.down, SDLK_DOWN, HEX);
|
||||
__config_add(input.joypad1.left, SDLK_LEFT, HEX);
|
||||
__config_add(input.joypad1.right, SDLK_RIGHT, HEX);
|
||||
__config_add(input.joypad1.a, SDLK_x, HEX);
|
||||
__config_add(input.joypad1.b, SDLK_z, HEX);
|
||||
__config_add(input.joypad1.x, SDLK_s, HEX);
|
||||
__config_add(input.joypad1.y, SDLK_a, HEX);
|
||||
__config_add(input.joypad1.l, SDLK_d, HEX);
|
||||
__config_add(input.joypad1.r, SDLK_c, HEX);
|
||||
__config_add(input.joypad1.select, SDLK_RSHIFT, HEX);
|
||||
__config_add(input.joypad1.start, SDLK_RETURN, HEX);
|
||||
}
|
||||
|
||||
}cfg;
|
||||
};
|
||||
|
@@ -1,87 +1,49 @@
|
||||
uint8 color_curve_table[32];
|
||||
uint32 color_lookup_table[65536];
|
||||
|
||||
void update_color_lookup_table() {
|
||||
int i, r, g, b, c;
|
||||
for(i=0,c=0;i<16;i++) {
|
||||
color_curve_table[i] = c;
|
||||
c = c + i + 1;
|
||||
}
|
||||
for(;i<31;i++) {
|
||||
color_curve_table[i] = c;
|
||||
c += 8;
|
||||
}
|
||||
color_curve_table[i] = 0xff;
|
||||
|
||||
int color_depth = 16;
|
||||
if(color_depth == 15) {
|
||||
for(i=0;i<65536;i++) {
|
||||
r = (i ) & 31;
|
||||
g = (i >> 5) & 31;
|
||||
b = (i >> 10) & 31;
|
||||
r = color_curve_table[r] >> 3;
|
||||
g = color_curve_table[g] >> 3;
|
||||
b = color_curve_table[b] >> 3;
|
||||
color_lookup_table[i] = (r << 10) | (g << 5) | (b);
|
||||
}
|
||||
} else if(color_depth == 16) {
|
||||
for(i=0;i<65536;i++) {
|
||||
r = (i ) & 31;
|
||||
g = (i >> 5) & 31;
|
||||
b = (i >> 10) & 31;
|
||||
r = color_curve_table[r] >> 3;
|
||||
g = color_curve_table[g] >> 2;
|
||||
b = color_curve_table[b] >> 3;
|
||||
color_lookup_table[i] = (r << 11) | (g << 5) | (b);
|
||||
}
|
||||
} else if(color_depth == 32) {
|
||||
for(i=0;i<65536;i++) {
|
||||
r = (i ) & 31;
|
||||
g = (i >> 5) & 31;
|
||||
b = (i >> 10) & 31;
|
||||
r = color_curve_table[r];
|
||||
g = color_curve_table[g];
|
||||
b = color_curve_table[b];
|
||||
color_lookup_table[i] = (r << 16) | (g << 8) | (b);
|
||||
}
|
||||
} else {
|
||||
alert("Error: Unsupported color depth [%d]", color_depth);
|
||||
}
|
||||
}
|
||||
|
||||
void render16() {
|
||||
uint16 *src, *dest;
|
||||
uint16 *dest, *src;
|
||||
uint32 pitch;
|
||||
int x, y;
|
||||
pitch = (backbuffer->pitch >> 1) - 256;
|
||||
src = (uint16*)ppu->output->buffer + (1 << 10);
|
||||
|
||||
SNES::video_info vi;
|
||||
snes->get_video_info(&vi);
|
||||
|
||||
pitch = (backbuffer->pitch >> 1);
|
||||
dest = (uint16*)backbuffer->pixels;
|
||||
for(y=0;y<223;y++) {
|
||||
for(x=0;x<256;x++) {
|
||||
*dest++ = color_lookup_table[*src];
|
||||
src += 2;
|
||||
src = (uint16*)vi.data;
|
||||
|
||||
if(vi.width == 256 && vi.height == 224) {
|
||||
for(y=0;y<224;y++) {
|
||||
memcpy(dest, src, 512);
|
||||
dest += pitch;
|
||||
src += 256;
|
||||
}
|
||||
} else if(vi.width == 512 && vi.height == 224) {
|
||||
for(y=0;y<224;y++) {
|
||||
memcpy(dest, src, 1024);
|
||||
dest += pitch;
|
||||
src += 512;
|
||||
}
|
||||
} else if(vi.width == 256 && vi.height == 448) {
|
||||
for(y=0;y<448;y++) {
|
||||
memcpy(dest, src, 512);
|
||||
dest += pitch;
|
||||
src += 256;
|
||||
}
|
||||
} else if(vi.width == 512 && vi.height == 448) {
|
||||
for(y=0;y<448;y++) {
|
||||
memcpy(dest, src, 1024);
|
||||
dest += pitch;
|
||||
src += 512;
|
||||
}
|
||||
dest += pitch;
|
||||
src += 512;
|
||||
}
|
||||
|
||||
|
||||
screen_info.rs.x = 0;
|
||||
screen_info.rs.y = (vi.height == 224) ? 1 : 2;
|
||||
screen_info.rs.w = vi.width;
|
||||
screen_info.rs.h = (vi.height == 224) ? 223 : 446;
|
||||
}
|
||||
|
||||
void render32() {
|
||||
uint16 *src;
|
||||
uint32 *dest, pitch;
|
||||
int x, y;
|
||||
pitch = (screen->pitch >> 2) - 256;
|
||||
src = (uint16*)ppu->output->buffer + (1 << 10);
|
||||
dest = (uint32*)screen->pixels;
|
||||
for(y=0;y<223;y++) {
|
||||
for(x=0;x<256;x++) {
|
||||
*dest++ = color_lookup_table[*src];
|
||||
src += 2;
|
||||
}
|
||||
dest += pitch;
|
||||
src += 512;
|
||||
}
|
||||
}
|
||||
void render32() {}
|
||||
|
||||
void render() {
|
||||
if(SDL_MUSTLOCK(screen)) {
|
||||
|
@@ -1,14 +1,13 @@
|
||||
#define INTERFACE_MAIN
|
||||
#define BSNES_VERSION "0.011"
|
||||
#define BSNES_TITLE "bsnes/SDL v" BSNES_VERSION
|
||||
#include "../base.h"
|
||||
#include "sdlmain.h"
|
||||
|
||||
#include "config.cpp"
|
||||
|
||||
#ifdef _WIN32_
|
||||
HWND hwnd;
|
||||
#endif
|
||||
|
||||
#include "config.cpp"
|
||||
#include "bsnes.h"
|
||||
#include "rom.cpp"
|
||||
#include "render.cpp"
|
||||
@@ -47,24 +46,31 @@ va_list args;
|
||||
void init_snes() {
|
||||
mem_bus = new bMemBus();
|
||||
cpu = new bCPU();
|
||||
if(cfg.apu.enabled) {
|
||||
apu = new bAPU();
|
||||
} else {
|
||||
apu = new bAPUSkip();
|
||||
}
|
||||
apu = new bAPU();
|
||||
dsp = new bDSP();
|
||||
ppu = new bPPU();
|
||||
snes = new bSNES();
|
||||
bsnes = static_cast<bSNES*>(snes);
|
||||
|
||||
snes->init();
|
||||
|
||||
//TODO: add sound support and remove this,
|
||||
//this is used with linux/bsd and mkfifo to
|
||||
//play audio in real-time while sound output
|
||||
//isn't available.
|
||||
snes->log_audio_enable("output.wav");
|
||||
|
||||
snes->set_playback_buffer_size(2000);
|
||||
}
|
||||
|
||||
void term_snes() {
|
||||
if(mem_bus) { delete(mem_bus); mem_bus = 0; }
|
||||
if(cpu) { delete(cpu); cpu = 0; }
|
||||
if(apu) { delete(apu); apu = 0; }
|
||||
if(ppu) { delete(ppu); ppu = 0; }
|
||||
if(snes) { delete(snes); snes = 0; }
|
||||
snes->term();
|
||||
|
||||
if(mem_bus) { delete(static_cast<bMemBus*>(mem_bus)); mem_bus = 0; }
|
||||
if(cpu) { delete(static_cast<bCPU*> (cpu)); cpu = 0; }
|
||||
if(apu) { delete(static_cast<bAPU*> (apu)); apu = 0; }
|
||||
if(ppu) { delete(static_cast<bPPU*> (ppu)); ppu = 0; }
|
||||
if(snes) { delete(static_cast<bSNES*> (snes)); snes = 0; }
|
||||
}
|
||||
|
||||
void center_window() {
|
||||
@@ -82,22 +88,17 @@ void set_window_info() {
|
||||
//SDL won't draw anything if you blit an image that's larger than
|
||||
//the display mode/window, even if you use the SoftStretch blit and
|
||||
//clip the source + dest rectangles properly...
|
||||
if(cfg.video.display_width < cfg.video.output_width) {
|
||||
cfg.video.display_width = cfg.video.output_width;
|
||||
if((int)config::video.display_width < (int)config::video.output_width) {
|
||||
config::video.display_width = config::video.output_width;
|
||||
}
|
||||
if(cfg.video.display_height < cfg.video.output_height) {
|
||||
cfg.video.display_height = cfg.video.output_height;
|
||||
if((int)config::video.display_height < (int)config::video.output_height) {
|
||||
config::video.display_height = config::video.output_height;
|
||||
}
|
||||
|
||||
screen_info.rd.x = (cfg.video.display_width - cfg.video.output_width ) >> 1;
|
||||
screen_info.rd.y = (cfg.video.display_height - cfg.video.output_height) >> 1;
|
||||
screen_info.rd.w = cfg.video.output_width;
|
||||
screen_info.rd.h = cfg.video.output_height;
|
||||
|
||||
screen_info.rs.x = 0;
|
||||
screen_info.rs.y = 0;
|
||||
screen_info.rs.w = 256;
|
||||
screen_info.rs.h = 223;
|
||||
screen_info.rd.x = ((int)config::video.display_width - (int)config::video.output_width ) >> 1;
|
||||
screen_info.rd.y = ((int)config::video.display_height - (int)config::video.output_height) >> 1;
|
||||
screen_info.rd.w = config::video.output_width;
|
||||
screen_info.rd.h = config::video.output_height;
|
||||
}
|
||||
|
||||
#ifdef _WIN32_
|
||||
@@ -115,14 +116,13 @@ SDL_Event event;
|
||||
return 0;
|
||||
}
|
||||
|
||||
cfg.load("bsnes_sdl.cfg");
|
||||
config_file.load("bsnes_sdl.cfg");
|
||||
|
||||
rom_image = new ROMImage();
|
||||
init_snes();
|
||||
|
||||
rom_image->select(argv[1]);
|
||||
rom_image->load();
|
||||
snes->power();
|
||||
|
||||
if(rom_image->loaded() == false) {
|
||||
alert("Failed to load image. Usage: bsnes_sdl <filename.smc>");
|
||||
@@ -132,13 +132,11 @@ SDL_Event event;
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
atexit(SDL_Quit);
|
||||
set_window_info();
|
||||
screen = SDL_SetVideoMode(cfg.video.display_width, cfg.video.display_height, 16,
|
||||
SDL_SWSURFACE | ((cfg.video.fullscreen)?SDL_FULLSCREEN:0));
|
||||
if(!screen) {
|
||||
alert("Failed to initialize SDL");
|
||||
goto _end;
|
||||
}
|
||||
backbuffer = SDL_CreateRGBSurface(SDL_SWSURFACE, 256, 223, 16, 0xf800, 0x07e0, 0x001f, 0x0000);
|
||||
screen = SDL_SetVideoMode(config::video.display_width, config::video.display_height, 16,
|
||||
SDL_SWSURFACE | ((config::video.fullscreen)?SDL_FULLSCREEN:0));
|
||||
if(!screen) { alert("Failed to initialize SDL"); goto _end; }
|
||||
backbuffer = SDL_CreateRGBSurface(SDL_SWSURFACE, 512, 448, 16, 0xf800, 0x07e0, 0x001f, 0x0000);
|
||||
if(!backbuffer) { alert("Failed to initialize SDL"); goto _end; }
|
||||
|
||||
SDL_WM_SetCaption(BSNES_TITLE, 0);
|
||||
#ifdef _WIN32_
|
||||
@@ -146,18 +144,21 @@ SDL_Event event;
|
||||
#endif
|
||||
center_window();
|
||||
|
||||
update_color_lookup_table();
|
||||
snes->power();
|
||||
bsnes->set_status(bSNES::RUN);
|
||||
|
||||
int cursor_status;
|
||||
while(1) {
|
||||
bsnes->snes_run();
|
||||
bsnes->run();
|
||||
while(SDL_PollEvent(&event)) {
|
||||
switch(event.type) {
|
||||
case SDL_KEYUP:
|
||||
switch(event.key.keysym.sym) {
|
||||
case SDLK_ESCAPE:
|
||||
goto _end;
|
||||
case SDLK_BACKSPACE:
|
||||
snes->capture_screenshot();
|
||||
break;
|
||||
case SDLK_F10: //toggle cursor display
|
||||
cursor_status = (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE)?SDL_DISABLE:SDL_ENABLE;
|
||||
SDL_ShowCursor(cursor_status);
|
||||
@@ -174,7 +175,7 @@ int cursor_status;
|
||||
}
|
||||
|
||||
_end:
|
||||
cfg.save("bsnes_sdl.cfg");
|
||||
config_file.save("bsnes_sdl.cfg");
|
||||
term_snes();
|
||||
|
||||
return 0;
|
||||
|
@@ -13,5 +13,5 @@
|
||||
SDL_Surface *screen, *backbuffer;
|
||||
|
||||
struct {
|
||||
SDL_Rect rs, rd;
|
||||
}screen_info;
|
||||
SDL_Rect rs, rd;
|
||||
} screen_info;
|
||||
|
@@ -1 +1 @@
|
||||
c:\root\bsnes_g2\bsnes_sdl.exe c:\root\bsnes_testrom\zelda_us.smc
|
||||
bsnes_sdl c:\root\bsnes_testrom\zelda_us.smc
|
@@ -1,24 +1,48 @@
|
||||
#include "../base.h"
|
||||
|
||||
#include "snes_video.cpp"
|
||||
#include "snes_audio.cpp"
|
||||
#include "snes_input.cpp"
|
||||
|
||||
void SNES::run() {
|
||||
uint32 cycles;
|
||||
uint32 cycles, r;
|
||||
if(apusync.cycles < 0) {
|
||||
cpu->run();
|
||||
apusync.cycles += apusync.apu_multbl[cpu->cycles_executed()];
|
||||
} else {
|
||||
apu->run();
|
||||
apusync.cycles -= apusync.cpu_multbl[apu->cycles_executed()];
|
||||
cycles = apu->cycles_executed();
|
||||
apusync.dsp += cycles;
|
||||
apusync.cycles -= apusync.cpu_multbl[cycles];
|
||||
|
||||
//1024000(SPC700) / 32000(DSP) = 32spc/dsp ticks
|
||||
//24576000(Sound clock crystal) / 32000(DSP) = 768crystal/dsp ticks
|
||||
while(apusync.dsp >= 768) {
|
||||
apusync.dsp -= 768;
|
||||
audio_update(dsp->run());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SNES::init() {
|
||||
srtc = new SRTC();
|
||||
sdd1 = new SDD1();
|
||||
|
||||
srtc->init();
|
||||
sdd1->init();
|
||||
|
||||
video_init();
|
||||
audio_init();
|
||||
}
|
||||
|
||||
void SNES::term() {
|
||||
audio_term();
|
||||
}
|
||||
|
||||
void SNES::power() {
|
||||
cpu->power();
|
||||
apu->power();
|
||||
dsp->power();
|
||||
ppu->power();
|
||||
mem_bus->power();
|
||||
|
||||
@@ -30,16 +54,18 @@ int i;
|
||||
for(i=0x2100;i<=0x213f;i++)mem_bus->set_mmio_mapper(i, ppu->mmio);
|
||||
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);
|
||||
//S-RTC
|
||||
mem_bus->set_mmio_mapper(0x2800, srtc->mmio);
|
||||
mem_bus->set_mmio_mapper(0x2801, srtc->mmio);
|
||||
//input
|
||||
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);
|
||||
for(i=0x4300;i<=0x437f;i++)mem_bus->set_mmio_mapper(i, cpu->mmio);
|
||||
//S-DD1
|
||||
for(i=0x4800;i<=0x4807;i++)mem_bus->set_mmio_mapper(i, sdd1->mmio);
|
||||
|
||||
srtc->enable();
|
||||
sdd1->enable();
|
||||
|
||||
memset(video.data, 0, 512 * 448 * sizeof(uint32));
|
||||
memset(video.ppu_data, 0, 512 * 480 * sizeof(uint16));
|
||||
video_update();
|
||||
}
|
||||
|
||||
void SNES::reset() {
|
||||
@@ -47,13 +73,30 @@ void SNES::reset() {
|
||||
|
||||
cpu->reset();
|
||||
apu->reset();
|
||||
dsp->reset();
|
||||
ppu->reset();
|
||||
mem_bus->reset();
|
||||
|
||||
srtc->reset();
|
||||
sdd1->reset();
|
||||
|
||||
memset(video.data, 0, 512 * 448 * sizeof(uint32));
|
||||
memset(video.ppu_data, 0, 512 * 480 * sizeof(uint16));
|
||||
video_update();
|
||||
}
|
||||
|
||||
void SNES::frame() {
|
||||
video_update();
|
||||
}
|
||||
|
||||
void SNES::scanline() {
|
||||
video_scanline();
|
||||
}
|
||||
|
||||
/****************
|
||||
*** PAL/NTSC ***
|
||||
****************/
|
||||
|
||||
void SNES::set_region(uint8 new_region) {
|
||||
if(new_region == NTSC) {
|
||||
snes_region = NTSC;
|
||||
@@ -68,6 +111,10 @@ void SNES::set_region(uint8 new_region) {
|
||||
|
||||
uint8 SNES::region() { return snes_region; }
|
||||
|
||||
/**************
|
||||
*** Timing ***
|
||||
**************/
|
||||
|
||||
void SNES::update_timing() {
|
||||
apusync.cycles = 0;
|
||||
if(snes_region == NTSC) {
|
||||
@@ -87,6 +134,7 @@ int i;
|
||||
/***************************
|
||||
*** Debugging functions ***
|
||||
***************************/
|
||||
|
||||
void SNES::notify(uint32 message, uint32 param1, uint32 param2) {}
|
||||
|
||||
void SNES::debugger_enable() {
|
||||
@@ -102,8 +150,10 @@ bool SNES::debugger_enabled() {
|
||||
}
|
||||
|
||||
SNES::SNES() {
|
||||
is_debugger_enabled = true;
|
||||
is_debugger_enabled = false;
|
||||
|
||||
snes_region = NTSC;
|
||||
update_timing();
|
||||
|
||||
dsp_buffer.data = 0;
|
||||
}
|
||||
|
@@ -6,10 +6,12 @@ uint8 snes_region;
|
||||
|
||||
//APU synchronization
|
||||
struct {
|
||||
int32 cpu_freq, apu_freq;
|
||||
int32 cpu_multbl[1024], apu_multbl[1024];
|
||||
int32 cycles;
|
||||
}apusync;
|
||||
int32 cpu_freq, apu_freq;
|
||||
int32 cpu_multbl[1024], apu_multbl[1024];
|
||||
int32 cycles;
|
||||
|
||||
int32 dsp;
|
||||
} apusync;
|
||||
|
||||
void update_timing();
|
||||
|
||||
@@ -17,29 +19,22 @@ public:
|
||||
enum { NTSC = 0, PAL = 1 };
|
||||
|
||||
//system functions
|
||||
void run();
|
||||
virtual void render_frame() = 0;
|
||||
virtual void init();
|
||||
virtual void power();
|
||||
virtual void reset();
|
||||
virtual uint8 region();
|
||||
virtual void set_region(uint8 new_region);
|
||||
virtual void run();
|
||||
virtual void init();
|
||||
virtual void term();
|
||||
virtual void power();
|
||||
virtual void reset();
|
||||
|
||||
//input functions
|
||||
enum {
|
||||
DEV_JOYPAD1 = 0,
|
||||
DEV_JOYPAD2 = 1
|
||||
};
|
||||
enum {
|
||||
JOYPAD_B = 0, JOYPAD_Y = 1,
|
||||
JOYPAD_SELECT = 2, JOYPAD_START = 3,
|
||||
JOYPAD_UP = 4, JOYPAD_DOWN = 5,
|
||||
JOYPAD_LEFT = 6, JOYPAD_RIGHT = 7,
|
||||
JOYPAD_A = 8, JOYPAD_X = 9,
|
||||
JOYPAD_L = 10, JOYPAD_R = 11
|
||||
};
|
||||
virtual void poll_input() = 0;
|
||||
virtual bool get_input_status(uint8 device, uint8 button) = 0;
|
||||
virtual void frame();
|
||||
virtual void scanline();
|
||||
|
||||
//PAL/NTSC
|
||||
uint8 region();
|
||||
void set_region(uint8 new_region);
|
||||
|
||||
#include "snes_video.h"
|
||||
#include "snes_audio.h"
|
||||
#include "snes_input.h"
|
||||
|
||||
//debugging functions
|
||||
enum {
|
||||
@@ -53,10 +48,12 @@ enum {
|
||||
OAM_READ, OAM_WRITE,
|
||||
CGRAM_READ, CGRAM_WRITE,
|
||||
};
|
||||
virtual void notify(uint32 message, uint32 param1 = 0, uint32 param2 = 0);
|
||||
virtual void debugger_enable();
|
||||
virtual void debugger_disable();
|
||||
virtual bool debugger_enabled();
|
||||
|
||||
//message functions
|
||||
virtual void notify(uint32 message, uint32 param1 = 0, uint32 param2 = 0);
|
||||
|
||||
SNES();
|
||||
};
|
||||
|
145
src/snes/snes_audio.cpp
Normal file
145
src/snes/snes_audio.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
void SNES::set_playback_buffer_size(uint32 buffer_size) {
|
||||
if(dsp_buffer.data) {
|
||||
free(dsp_buffer.data);
|
||||
dsp_buffer.data = 0;
|
||||
}
|
||||
|
||||
//* 2 is for left/right channel data
|
||||
dsp_buffer.data = (uint16*)malloc(buffer_size * sizeof(uint16) * 2);
|
||||
memset(dsp_buffer.data, 0, buffer_size * sizeof(uint16) * 2);
|
||||
|
||||
dsp_buffer.size = buffer_size;
|
||||
dsp_buffer.pos = 0;
|
||||
}
|
||||
|
||||
uint32 SNES::get_playback_buffer_pos() {
|
||||
return dsp_buffer.pos;
|
||||
}
|
||||
|
||||
uint16 *SNES::get_playback_buffer() {
|
||||
return dsp_buffer.data;
|
||||
}
|
||||
|
||||
void SNES::audio_update(uint32 data) {
|
||||
if(pcmfp) {
|
||||
fputc(data, pcmfp);
|
||||
fputc(data >> 8, pcmfp);
|
||||
fputc(data >> 16, pcmfp);
|
||||
fputc(data >> 24, pcmfp);
|
||||
}
|
||||
|
||||
if((bool)config::snes.mute == true)data = 0x0000;
|
||||
|
||||
dsp_buffer.data[dsp_buffer.pos++] = (data) & 0xffff;
|
||||
dsp_buffer.data[dsp_buffer.pos++] = (data >> 16) & 0xffff;
|
||||
dsp_buffer.pos %= dsp_buffer.size;
|
||||
|
||||
sound_run();
|
||||
}
|
||||
|
||||
void SNES::log_audio_enable(const char *fn) {
|
||||
char tfn[256];
|
||||
int i;
|
||||
if(pcmfp)log_audio_disable();
|
||||
|
||||
if(!fn) {
|
||||
for(i=0;i<=999;i++) {
|
||||
sprintf(tfn, "audio%0.3d.wav", i);
|
||||
pcmfp = fopen(tfn, "rb");
|
||||
if(!pcmfp)break;
|
||||
fclose(pcmfp);
|
||||
pcmfp = 0;
|
||||
}
|
||||
if(i >= 1000)return;
|
||||
} else {
|
||||
strcpy(tfn, fn);
|
||||
}
|
||||
|
||||
pcmfp = fopen(tfn, "wb");
|
||||
if(!pcmfp)return;
|
||||
|
||||
//header
|
||||
fwrite("RIFF", 1, 4, pcmfp);
|
||||
//file size
|
||||
fputc(0, pcmfp);
|
||||
fputc(0, pcmfp);
|
||||
fputc(0, pcmfp);
|
||||
fputc(0, pcmfp);
|
||||
//format
|
||||
fwrite("WAVE", 1, 4, pcmfp);
|
||||
fwrite("fmt ", 1, 4, pcmfp);
|
||||
//fmt size
|
||||
fputc(0x12, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
//fmt type (PCM)
|
||||
fputc(1, pcmfp);
|
||||
fputc(0, pcmfp);
|
||||
//channels
|
||||
fputc(2, pcmfp);
|
||||
fputc(0, pcmfp);
|
||||
//sample rate (32000hz)
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0x7d, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
//byte rate (32000 * 2 * (16 / 8)
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0xf4, pcmfp);
|
||||
fputc(0x01, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
//block align (bytes per sample) (4)
|
||||
fputc(4, pcmfp);
|
||||
fputc(0, pcmfp);
|
||||
//???
|
||||
fputc(0x10, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
fwrite("fact", 1, 4, pcmfp);
|
||||
fputc(0x04, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0x0b, pcmfp);
|
||||
fputc(0xf4, pcmfp);
|
||||
fputc(0x01, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
//data
|
||||
fwrite("data", 1, 4, pcmfp);
|
||||
//data size
|
||||
fputc(0, pcmfp);
|
||||
fputc(0, pcmfp);
|
||||
fputc(0, pcmfp);
|
||||
fputc(0, pcmfp);
|
||||
}
|
||||
|
||||
void SNES::log_audio_disable() {
|
||||
if(pcmfp) {
|
||||
int fsize, t;
|
||||
fseek(pcmfp, 0, SEEK_END);
|
||||
fsize = ftell(pcmfp);
|
||||
fseek(pcmfp, 4, SEEK_SET);
|
||||
t = fsize - 2;
|
||||
fputc(t, pcmfp);
|
||||
fputc(t >> 8, pcmfp);
|
||||
fputc(t >> 16, pcmfp);
|
||||
fputc(t >> 24, pcmfp);
|
||||
fseek(pcmfp, 0x36, SEEK_SET);
|
||||
t = fsize - 0x3a;
|
||||
fputc(t, pcmfp);
|
||||
fputc(t >> 8, pcmfp);
|
||||
fputc(t >> 16, pcmfp);
|
||||
fputc(t >> 24, pcmfp);
|
||||
fclose(pcmfp);
|
||||
pcmfp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SNES::audio_init() {
|
||||
}
|
||||
|
||||
void SNES::audio_term() {
|
||||
log_audio_disable();
|
||||
}
|
22
src/snes/snes_audio.h
Normal file
22
src/snes/snes_audio.h
Normal file
@@ -0,0 +1,22 @@
|
||||
struct {
|
||||
uint16 *data;
|
||||
uint32 size, pos;
|
||||
} dsp_buffer;
|
||||
|
||||
FILE *pcmfp;
|
||||
|
||||
//buffer_size is in samples
|
||||
void set_playback_buffer_size(uint32 buffer_size);
|
||||
uint32 get_playback_buffer_pos();
|
||||
uint16 *get_playback_buffer();
|
||||
|
||||
//if a filename is not specified, one will be generated
|
||||
//automatically ("audio%0.3d.wav")
|
||||
void log_audio_enable(const char *fn = 0);
|
||||
void log_audio_disable();
|
||||
|
||||
void audio_update(uint32 data);
|
||||
void audio_init();
|
||||
void audio_term();
|
||||
|
||||
virtual void sound_run() = 0;
|
0
src/snes/snes_input.cpp
Normal file
0
src/snes/snes_input.cpp
Normal file
21
src/snes/snes_input.h
Normal file
21
src/snes/snes_input.h
Normal file
@@ -0,0 +1,21 @@
|
||||
enum {
|
||||
DEV_JOYPAD1 = 0,
|
||||
DEV_JOYPAD2 = 1
|
||||
};
|
||||
|
||||
enum {
|
||||
JOYPAD_B = 0, JOYPAD_Y = 1,
|
||||
JOYPAD_SELECT = 2, JOYPAD_START = 3,
|
||||
JOYPAD_UP = 4, JOYPAD_DOWN = 5,
|
||||
JOYPAD_LEFT = 6, JOYPAD_RIGHT = 7,
|
||||
JOYPAD_A = 8, JOYPAD_X = 9,
|
||||
JOYPAD_L = 10, JOYPAD_R = 11
|
||||
};
|
||||
|
||||
//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(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.
|
||||
virtual bool get_input_status(uint8 device, uint8 button) = 0;
|
343
src/snes/snes_video.cpp
Normal file
343
src/snes/snes_video.cpp
Normal file
@@ -0,0 +1,343 @@
|
||||
#include "snes_video_ex.cpp"
|
||||
|
||||
const uint8 SNES::color_curve_table[32] = {
|
||||
0x00, 0x01, 0x03, 0x06, 0x0a, 0x0f, 0x15, 0x1c,
|
||||
0x24, 0x2d, 0x37, 0x42, 0x4e, 0x5b, 0x69, 0x78,
|
||||
0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0,
|
||||
0xc8, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, 0xff
|
||||
};
|
||||
|
||||
void SNES::update_color_lookup_table() {
|
||||
int i, l, r, g, b;
|
||||
double lr = 0.2126, lg = 0.7152, lb = 0.0722; //luminance
|
||||
uint32 col;
|
||||
|
||||
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);
|
||||
|
||||
r = (col >> 16) & 0xff;
|
||||
g = (col >> 8) & 0xff;
|
||||
b = (col ) & 0xff;
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
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:
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SNES::set_video_format(uint8 mode, uint8 depth) {
|
||||
//only make changes at the start of a new frame
|
||||
video.format_changed = true;
|
||||
|
||||
video_changed.mode = mode;
|
||||
video_changed.depth = depth;
|
||||
}
|
||||
|
||||
//internal function called at the start of the frame
|
||||
//after SNES::set_video_format() is called
|
||||
void SNES::update_video_format() {
|
||||
video.mode = video_changed.mode;
|
||||
video.depth = video_changed.depth;
|
||||
|
||||
update_color_lookup_table();
|
||||
video.format_changed = false;
|
||||
}
|
||||
|
||||
void SNES::get_video_info(video_info *info) {
|
||||
info->data = video.data;
|
||||
info->mode = video.mode;
|
||||
|
||||
switch(video.mode) {
|
||||
case VM_256x224:
|
||||
info->width = 256;
|
||||
info->height = 224;
|
||||
break;
|
||||
case VM_512x224:
|
||||
info->width = 512;
|
||||
info->height = 224;
|
||||
break;
|
||||
case VM_256x448:
|
||||
info->width = 256;
|
||||
info->height = 448;
|
||||
break;
|
||||
case VM_512x448:
|
||||
info->width = 512;
|
||||
info->height = 448;
|
||||
break;
|
||||
case VM_VARIABLE:
|
||||
if(video.frame_hires == false) {
|
||||
info->width = 256;
|
||||
} else {
|
||||
info->width = 512;
|
||||
}
|
||||
|
||||
if(video.frame_interlace == false) {
|
||||
info->height = 224;
|
||||
} else {
|
||||
info->height = 448;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SNES::video_update_256x224(uint16 *src) {
|
||||
int x, y;
|
||||
uint16 *dest;
|
||||
dest = video.data;
|
||||
|
||||
for(y=0;y<224;y++) {
|
||||
if(video_frame[y].hires == false) {
|
||||
for(x=0;x<256;x++) {
|
||||
*dest++ = color_lookup_table[*src++];
|
||||
}
|
||||
src += 768;
|
||||
} else {
|
||||
for(x=0;x<256;x++) {
|
||||
*dest++ = color_lookup_table[*src];
|
||||
src += 2;
|
||||
}
|
||||
src += 512;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SNES::video_update_512x224(uint16 *src) {
|
||||
int x, y;
|
||||
uint16 *dest;
|
||||
dest = video.data;
|
||||
|
||||
for(y=0;y<224;y++) {
|
||||
if(video_frame[y].hires == false) {
|
||||
for(x=0;x<256;x++) {
|
||||
*dest++ = color_lookup_table[*src];
|
||||
*dest++ = color_lookup_table[*src++];
|
||||
}
|
||||
src += 768;
|
||||
} else {
|
||||
for(x=0;x<512;x++) {
|
||||
*dest++ = color_lookup_table[*src++];
|
||||
}
|
||||
src += 512;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SNES::video_update_256x448(uint16 *src) {
|
||||
int x, y;
|
||||
uint16 *dest;
|
||||
bool field = !cpu->interlace_field();
|
||||
dest = video.data;
|
||||
|
||||
for(y=0;y<224;y++) {
|
||||
if(video_frame[y].interlace == false) {
|
||||
if(video_frame[y].hires == false) {
|
||||
for(x=0;x<512;x++) {
|
||||
*dest++ = color_lookup_table[*(src + (uint8)x)];
|
||||
}
|
||||
src += 1024;
|
||||
} else {
|
||||
for(x=0;x<512;x++) {
|
||||
*dest++ = color_lookup_table[*(src + ((x & 255) << 1))];
|
||||
}
|
||||
src += 1024;
|
||||
}
|
||||
} else {
|
||||
if(field) {
|
||||
dest += 256;
|
||||
src += 512;
|
||||
}
|
||||
|
||||
if(video_frame[y].hires == false) {
|
||||
for(x=0;x<256;x++) {
|
||||
*dest++ = color_lookup_table[*src++];
|
||||
}
|
||||
src += 256;
|
||||
} else {
|
||||
for(x=0;x<256;x++) {
|
||||
*dest++ = color_lookup_table[*src];
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if(!field) {
|
||||
dest += 256;
|
||||
src += 512;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SNES::video_update_512x448(uint16 *src) {
|
||||
int x, y;
|
||||
uint16 *dest;
|
||||
bool field = !cpu->interlace_field();
|
||||
dest = video.data;
|
||||
|
||||
for(y=0;y<224;y++) {
|
||||
if(video_frame[y].interlace == false) {
|
||||
if(video_frame[y].hires == false) {
|
||||
for(x=0;x<512;x++) {
|
||||
*dest++ = color_lookup_table[*(src + (uint8)x)];
|
||||
*dest++ = color_lookup_table[*(src + (uint8)x)];
|
||||
}
|
||||
src += 1024;
|
||||
} else {
|
||||
for(x=0;x<1024;x++) {
|
||||
*dest++ = color_lookup_table[*(src + (x & 511))];
|
||||
}
|
||||
src += 1024;
|
||||
}
|
||||
} else {
|
||||
if(field) {
|
||||
dest += 512;
|
||||
src += 512;
|
||||
}
|
||||
|
||||
if(video_frame[y].hires == false) {
|
||||
for(x=0;x<256;x++) {
|
||||
*dest++ = color_lookup_table[*(src + x)];
|
||||
*dest++ = color_lookup_table[*(src + x)];
|
||||
}
|
||||
src += 512;
|
||||
} else {
|
||||
for(x=0;x<512;x++) {
|
||||
*dest++ = color_lookup_table[*src++];
|
||||
}
|
||||
}
|
||||
|
||||
if(!field) {
|
||||
dest += 512;
|
||||
src += 512;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SNES::video_update() {
|
||||
if(ppu->renderer_enabled()) {
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//SNES::capture_screenshot() was called by emulation interface
|
||||
if(flag_output_screenshot == true) {
|
||||
output_screenshot();
|
||||
flag_output_screenshot = false;
|
||||
}
|
||||
}
|
||||
|
||||
video_run();
|
||||
|
||||
video.frame_hires = false;
|
||||
video.frame_interlace = false;
|
||||
}
|
||||
|
||||
void SNES::video_scanline() {
|
||||
int y = cpu->vcounter();
|
||||
int o = int(cpu->overscan()) << 3;
|
||||
if(y <= (0 + o) || y >= (224 + o))return;
|
||||
y -= o;
|
||||
|
||||
PPU::scanline_info si;
|
||||
ppu->get_scanline_info(&si);
|
||||
|
||||
video_frame[y].hires = si.hires;
|
||||
video_frame[y].interlace = si.interlace;
|
||||
|
||||
video.frame_hires |= si.hires;
|
||||
video.frame_interlace |= si.interlace;
|
||||
}
|
||||
|
||||
uint16 *SNES::get_ppu_output_handle() {
|
||||
return (uint16*)(video.ppu_data +
|
||||
(cpu->vcounter() * 1024) +
|
||||
((cpu->interlace() && cpu->interlace_field())?512:0));
|
||||
}
|
||||
|
||||
void SNES::video_init() {
|
||||
int i, c;
|
||||
video.format_changed = false;
|
||||
|
||||
video.data = (uint16*)malloc(512 * 448 * sizeof(uint32));
|
||||
video.ppu_data = (uint16*)malloc(512 * 480 * sizeof(uint16));
|
||||
memset(video.data, 0, 512 * 448 * sizeof(uint32));
|
||||
memset(video.ppu_data, 0, 512 * 480 * sizeof(uint16));
|
||||
|
||||
for(i=0;i<224;i++) {
|
||||
video_frame[i].hires = false;
|
||||
video_frame[i].interlace = false;
|
||||
}
|
||||
|
||||
video.frame_hires = false;
|
||||
video.frame_interlace = false;
|
||||
|
||||
set_video_format(VM_VARIABLE, 16);
|
||||
update_video_format();
|
||||
|
||||
flag_output_screenshot = false;
|
||||
}
|
72
src/snes/snes_video.h
Normal file
72
src/snes/snes_video.h
Normal file
@@ -0,0 +1,72 @@
|
||||
enum {
|
||||
VM_256x224, //video data will be scaled to 256x224
|
||||
VM_512x224, //..
|
||||
VM_256x448, //..
|
||||
VM_512x448, //..
|
||||
VM_VARIABLE //video data can be 256x224 - 512x448
|
||||
};
|
||||
|
||||
enum {
|
||||
VMF_NORMAL = 0,
|
||||
VMF_HIRES = 1,
|
||||
VMF_INTERLACE = 2,
|
||||
VMF_HINTERLACE = 3
|
||||
};
|
||||
|
||||
//video color adjustment
|
||||
//via config::snes.video_color_adjust_mode
|
||||
enum {
|
||||
VCA_NORMAL = 0,
|
||||
VCA_GRAYSCALE = 1,
|
||||
VCA_VGA = 2,
|
||||
VCA_GENESIS = 3
|
||||
};
|
||||
|
||||
static const uint8 color_curve_table[32];
|
||||
uint32 color_lookup_table[32768];
|
||||
|
||||
struct {
|
||||
uint16 *data, *ppu_data;
|
||||
uint8 mode;
|
||||
uint8 depth;
|
||||
|
||||
bool frame_hires, frame_interlace;
|
||||
|
||||
bool format_changed;
|
||||
} video, video_changed;
|
||||
|
||||
struct {
|
||||
bool hires, interlace;
|
||||
} video_frame[224];
|
||||
|
||||
struct video_info {
|
||||
uint16 *data;
|
||||
uint8 mode;
|
||||
uint32 width, height;
|
||||
};
|
||||
|
||||
//public functions
|
||||
void capture_screenshot();
|
||||
void update_color_lookup_table();
|
||||
|
||||
virtual void set_video_format(uint8 mode, uint8 depth);
|
||||
virtual void get_video_info(video_info *info);
|
||||
virtual void video_run() = 0;
|
||||
|
||||
//private functions
|
||||
uint16 *get_ppu_output_handle(); //used by PPU only
|
||||
private:
|
||||
//when a screenshot is requested, wait until the frame
|
||||
//has finished rendering, so we can tell the image size
|
||||
bool flag_output_screenshot;
|
||||
uint16 to_rgb555(uint32 color);
|
||||
void output_screenshot();
|
||||
void update_video_format();
|
||||
void video_update_256x224(uint16 *src);
|
||||
void video_update_512x224(uint16 *src);
|
||||
void video_update_256x448(uint16 *src);
|
||||
void video_update_512x448(uint16 *src);
|
||||
void video_update();
|
||||
void video_scanline();
|
||||
void video_init();
|
||||
public:
|
106
src/snes/snes_video_ex.cpp
Normal file
106
src/snes/snes_video_ex.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
void SNES::capture_screenshot() {
|
||||
flag_output_screenshot = true;
|
||||
}
|
||||
|
||||
//used to convert pixel data to write to rgb555 format
|
||||
//bitmap image via SNES::output_screenshot() function
|
||||
uint16 SNES::to_rgb555(uint32 color) {
|
||||
if(video.depth == 15) {
|
||||
//rgb555
|
||||
return color & 0x7fff;
|
||||
}
|
||||
|
||||
if(video.depth == 16) {
|
||||
//rgb565->rgb555
|
||||
return ((color >> 1) & 0x7fe0) | (color & 0x001f);
|
||||
}
|
||||
|
||||
if(video.depth == 24 || video.depth == 32) {
|
||||
//rgb888->rgb555
|
||||
return ((color >> 9) & 0x7c00) | ((color >> 6) & 0x03e0) | ((color >> 3) & 0x001f);
|
||||
}
|
||||
|
||||
//unsupported color depth
|
||||
return color;
|
||||
}
|
||||
|
||||
void SNES::output_screenshot() {
|
||||
FILE *fp;
|
||||
char fn[256];
|
||||
int i;
|
||||
//get a file name that doesn't exit...
|
||||
for(i=0;i<=999;i++) {
|
||||
sprintf(fn, "image%0.3d.bmp", i);
|
||||
fp = fopen(fn, "rb");
|
||||
if(!fp)break;
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
}
|
||||
if(i >= 1000)return;
|
||||
|
||||
fp = fopen(fn, "wb");
|
||||
if(!fp)return;
|
||||
|
||||
video_info vi;
|
||||
get_video_info(&vi);
|
||||
int width, height;
|
||||
width = vi.width;
|
||||
height = (vi.height == 224) ? 223 : 446;
|
||||
int32 fsize;
|
||||
fsize = 0x36 + (width * height * sizeof(uint16));
|
||||
|
||||
//header
|
||||
fputc('B', fp);
|
||||
fputc('M', fp);
|
||||
//file size
|
||||
fputc(fsize, fp);
|
||||
fputc(fsize >> 8, fp);
|
||||
fputc(fsize >> 16, fp);
|
||||
fputc(fsize >> 24, fp);
|
||||
//???
|
||||
fputc(0, fp);
|
||||
fputc(0, fp);
|
||||
fputc(0, fp);
|
||||
fputc(0, fp);
|
||||
//start of data
|
||||
fputc(0x36, fp);
|
||||
fputc(0x00, fp);
|
||||
fputc(0x00, fp);
|
||||
fputc(0x00, fp);
|
||||
//remaining header size
|
||||
fputc(0x28, fp);
|
||||
fputc(0x00, fp);
|
||||
fputc(0x00, fp);
|
||||
fputc(0x00, fp);
|
||||
//width
|
||||
fputc(width, fp);
|
||||
fputc(width >> 8, fp);
|
||||
fputc(width >> 16, fp);
|
||||
fputc(width >> 24, fp);
|
||||
//height
|
||||
fputc(height, fp);
|
||||
fputc(height >> 8, fp);
|
||||
fputc(height >> 16, fp);
|
||||
fputc(height >> 24, fp);
|
||||
//format
|
||||
fputc(0x01, fp);
|
||||
fputc(0x00, fp);
|
||||
//bpp
|
||||
fputc(16, fp);
|
||||
fputc( 0, fp);
|
||||
//???
|
||||
for(i=0;i<24;i++) { fputc(0, fp); }
|
||||
|
||||
int x, y;
|
||||
uint16 c;
|
||||
for(y=height;y>=1;y--) {
|
||||
for(x=0;x<width;x++) {
|
||||
c = to_rgb555(video.data[y * width + x]);
|
||||
fputc(c, fp);
|
||||
fputc(c >> 8, fp);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
}
|
@@ -1,15 +1,16 @@
|
||||
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 \
|
||||
memory.obj bmemory.obj \
|
||||
cpu.obj bcpu.obj \
|
||||
apu.obj bapu.obj bapuskip.obj \
|
||||
bdsp.obj \
|
||||
ppu.obj bppu.obj \
|
||||
snes.obj \
|
||||
srtc.obj sdd1.obj
|
||||
LIBS = kernel32.lib user32.lib gdi32.lib comdlg32.lib ddraw.lib dxguid.lib
|
||||
LIBS = kernel32.lib user32.lib gdi32.lib comdlg32.lib ddraw.lib dsound.lib dxguid.lib
|
||||
|
||||
all: $(OBJS)
|
||||
rc /r /fobsnes.res bsnes.rc
|
||||
@@ -21,7 +22,7 @@ clean:
|
||||
######################
|
||||
### win32-specific ###
|
||||
######################
|
||||
winmain.obj: *.cpp *.h
|
||||
winmain.obj: *.cpp *.h ../config/*
|
||||
$(CC) $(CFLAGS) /c winmain.cpp
|
||||
|
||||
#################
|
||||
@@ -62,6 +63,12 @@ bapu.obj: ../apu/bapu/*
|
||||
bapuskip.obj: ../apu/bapuskip/*
|
||||
$(CC) $(CFLAGS) /c ../apu/bapuskip/bapuskip.cpp
|
||||
|
||||
###########
|
||||
### dsp ###
|
||||
###########
|
||||
bdsp.obj: ../dsp/bdsp/*
|
||||
$(CC) $(CFLAGS) /c ../dsp/bdsp/bdsp.cpp
|
||||
|
||||
###########
|
||||
### ppu ###
|
||||
###########
|
||||
|
@@ -43,31 +43,31 @@ uint32 bSNES::get_status() {
|
||||
return run_status;
|
||||
}
|
||||
|
||||
void bSNES::snes_run() {
|
||||
void bSNES::run() {
|
||||
if(!rom_image->loaded())return;
|
||||
|
||||
switch(run_status) {
|
||||
case RUN:
|
||||
while(update_frame == false) {
|
||||
run();
|
||||
SNES::run();
|
||||
}
|
||||
update_frame = false;
|
||||
return;
|
||||
case STOP:
|
||||
break;
|
||||
case RUNONCE:
|
||||
run();
|
||||
SNES::run();
|
||||
set_status(STOP);
|
||||
break;
|
||||
case RUNTOSIGNAL:
|
||||
run();
|
||||
SNES::run();
|
||||
if(w_bp->hit() == true) {
|
||||
set_status(STOP);
|
||||
disassemble_bp_op();
|
||||
}
|
||||
break;
|
||||
case RUNTOFRAME:
|
||||
run();
|
||||
SNES::run();
|
||||
if(update_frame == true) {
|
||||
update_frame = false;
|
||||
set_status(STOP);
|
||||
@@ -79,7 +79,7 @@ void bSNES::snes_run() {
|
||||
}
|
||||
return;
|
||||
case RUNTOCPUSTEP:
|
||||
run();
|
||||
SNES::run();
|
||||
if(status.cpu_ran == true) {
|
||||
set_status(STOP);
|
||||
} else if(w_bp->hit() == true) {
|
||||
@@ -88,7 +88,7 @@ void bSNES::snes_run() {
|
||||
}
|
||||
break;
|
||||
case RUNTOCPUPROCEED:
|
||||
run();
|
||||
SNES::run();
|
||||
if(cpu->in_opcode() == false && status.cpu_stop_pos == cpu->regs.pc.d) {
|
||||
set_status(STOP);
|
||||
disassemble_cpu_op();
|
||||
@@ -98,14 +98,14 @@ void bSNES::snes_run() {
|
||||
}
|
||||
break;
|
||||
case RUNTOCPUTRACE:
|
||||
run();
|
||||
SNES::run();
|
||||
if(status.cpu_trace_pos >= status.cpu_trace_stop) {
|
||||
set_status(STOP);
|
||||
disassemble_cpu_op();
|
||||
}
|
||||
break;
|
||||
case RUNTOAPUSTEP:
|
||||
run();
|
||||
SNES::run();
|
||||
if(status.apu_ran == true || w_bp->hit() == true) {
|
||||
set_status(STOP);
|
||||
}
|
||||
@@ -113,37 +113,85 @@ void bSNES::snes_run() {
|
||||
}
|
||||
}
|
||||
|
||||
void bSNES::render_frame() {
|
||||
dd_renderer->update();
|
||||
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);
|
||||
}
|
||||
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() {
|
||||
ds_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(cfg.input.joypad1.up);
|
||||
joypad1.down = KeyDown(cfg.input.joypad1.down);
|
||||
joypad1.left = KeyDown(cfg.input.joypad1.left);
|
||||
joypad1.right = KeyDown(cfg.input.joypad1.right);
|
||||
joypad1.select = KeyDown(cfg.input.joypad1.select);
|
||||
joypad1.start = KeyDown(cfg.input.joypad1.start);
|
||||
joypad1.y = KeyDown(cfg.input.joypad1.y);
|
||||
joypad1.b = KeyDown(cfg.input.joypad1.b);
|
||||
joypad1.x = KeyDown(cfg.input.joypad1.x);
|
||||
joypad1.a = KeyDown(cfg.input.joypad1.a);
|
||||
joypad1.l = KeyDown(cfg.input.joypad1.l);
|
||||
joypad1.r = KeyDown(cfg.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;
|
||||
@@ -163,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) {
|
||||
@@ -183,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;
|
||||
}
|
||||
|
||||
@@ -272,7 +340,6 @@ void bSNES::notify(uint32 message, uint32 param1, uint32 param2) {
|
||||
switch(message) {
|
||||
case RENDER_FRAME:
|
||||
update_frame = true;
|
||||
render_frame();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@@ -35,13 +35,15 @@ enum {
|
||||
RUNTOAPUSTEP
|
||||
};
|
||||
enum { DRAM = 0, SPCRAM = 1, VRAM = 2, OAM = 3, CGRAM = 4 };
|
||||
void run();
|
||||
void video_run();
|
||||
void sound_run();
|
||||
|
||||
void set_status(uint32 new_status);
|
||||
uint32 get_status();
|
||||
void snes_run();
|
||||
void render_frame();
|
||||
|
||||
//input functions
|
||||
void poll_input();
|
||||
void poll_input(uint8 type);
|
||||
bool get_input_status(uint8 device, uint8 button);
|
||||
|
||||
//debugging functions
|
||||
|
Binary file not shown.
@@ -1,52 +1,55 @@
|
||||
#define __config_add(name, def, type) add(&name, #name, def, type)
|
||||
namespace config {
|
||||
|
||||
class Config : public config {
|
||||
public:
|
||||
struct Video {
|
||||
static Setting mode, use_vram, vblank;
|
||||
} video;
|
||||
Setting Video::mode(&config_file, "video.mode",
|
||||
"Video mode\n"
|
||||
" 0 = 256x224w\n"
|
||||
" 1 = 512x448w\n"
|
||||
" 2 = 960x720w\n"
|
||||
" 3 = 640x480f\n"
|
||||
" 4 = 1024x768f",
|
||||
1, Setting::DEC);
|
||||
Setting Video::use_vram(&config_file, "video.use_vram", "Use Video RAM instead of System RAM", true, Setting::TRUE_FALSE);
|
||||
Setting Video::vblank(&config_file, "video.vblank", "Wait for vertical retrace when updating screen", false, Setting::TRUE_FALSE);
|
||||
|
||||
struct {
|
||||
uint32 enabled;
|
||||
}apu;
|
||||
struct GUI {
|
||||
static Setting show_fps;
|
||||
} gui;
|
||||
Setting GUI::show_fps(&config_file, "gui.show_fps", "Show framerate in window title", true, Setting::TRUE_FALSE);
|
||||
|
||||
struct {
|
||||
uint32 mode;
|
||||
uint32 use_vram;
|
||||
uint32 color_curve;
|
||||
uint32 vblank;
|
||||
}video;
|
||||
struct Input {
|
||||
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::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);
|
||||
|
||||
struct {
|
||||
struct {
|
||||
uint32 up, down, left, right;
|
||||
uint32 a, b, x, y, l, r;
|
||||
uint32 select, start;
|
||||
}joypad1;
|
||||
}input;
|
||||
|
||||
struct {
|
||||
uint32 show_fps;
|
||||
}gui;
|
||||
|
||||
Config() {
|
||||
__config_add(apu.enabled, true, TRUEFALSE);
|
||||
|
||||
__config_add(video.mode, 1, DEC);
|
||||
__config_add(video.use_vram, true, TRUEFALSE);
|
||||
__config_add(video.color_curve, true, ENABLED);
|
||||
__config_add(video.vblank, false, TRUEFALSE);
|
||||
|
||||
__config_add(input.joypad1.up, VK_UP, HEX);
|
||||
__config_add(input.joypad1.down, VK_DOWN, HEX);
|
||||
__config_add(input.joypad1.left, VK_LEFT, HEX);
|
||||
__config_add(input.joypad1.right, VK_RIGHT, HEX);
|
||||
__config_add(input.joypad1.a, 'X', HEX);
|
||||
__config_add(input.joypad1.b, 'Z', HEX);
|
||||
__config_add(input.joypad1.x, 'S', HEX);
|
||||
__config_add(input.joypad1.y, 'A', HEX);
|
||||
__config_add(input.joypad1.l, 'D', HEX);
|
||||
__config_add(input.joypad1.r, 'C', HEX);
|
||||
__config_add(input.joypad1.select, VK_SHIFT, HEX);
|
||||
__config_add(input.joypad1.start, VK_RETURN, HEX);
|
||||
|
||||
__config_add(gui.show_fps, true, TRUEFALSE);
|
||||
}
|
||||
}cfg;
|
||||
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);
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user