Compare commits

...
6 Commits
Author SHA1 Message Date
byuu 49c39e0e4d Update to bsnes v015 release.
- Added GZ / ZIP / JMA archive support [Nach, NSRT team]
    - Fixed bug in APU ADDW/SUBW opcode flags, thanks to DMV27, anomymous for info
    - Mosaic support is now (mostly) hardware accurate, thanks to TRAC for info
    - Fixed a bug in SC tilemap clipping, fixes Seiken Densetsu 3
    - Emulated pseudo-hires mode, uses a fairly poor color filter to simulate TV effect, the same one that SNES9x and Super Sleuth use
    - Rewrote the ROM loading code to be more port-friendly, and improved header detection
    - Added C4 emulation -- mostly correct. Only minor bugs remain, possibly not C4 related [Nach, byuu], also uses code from zsKnight, Overload, and anomie
    - Fixed noise channel generation for DSP, fixes Dual Orb 2 opening. Thanks to DMV27 for info
    - Fixed bug with DSP VxSRCN registers, fixes horrible sound corruption in Mortal Kombat 2/3
    - Modified DSP KON register reading to act according to anomie's research, while still allowing Der Langrisser, etc. to play sounds correctly
    - Fixed a bug in CPU BCD math, fixes numbers in SimEarth, thanks to DMV27 for info
    - Rewrote the windows port from scratch
    - -- Added triple buffering support (buggy)
    - -- Added DirectInput (joypad) support, allows both keyboard and joypad to be mapped to the same SNES controller button. Only one controller supported for this release, will be improved shortly
    - -- Added pause key (mapped to Pause/Break)
    - -- bsnes no longer consumes CPU time when paused or when no ROM is loaded
    - -- Updated DirectDraw to 7, and added video mode configuration options to configuration file
    - -- Video modes can specify screen width+height, refresh rate, and render width+height
    - -- Added CTRL+[1-0] hotkeys for swapping video modes
    - -- Added +/- hotkeys for adjusting frameskipping rate
    - -- Added adjustable speed regulation. There are five modes, all can be adjusted inside the configuration file. CTRL+[+/-] will adjust the speed mode.
    - -- Added PPU options to toggle any BG / OAM layers with any priority, HDMA effects, and offset per tile effects
    - -- Added option to accept invalid button combinations (up+down, left+right) to joypad config menu
    - -- bsnes now properly clears the main window when unloading games
    - [code] Made destructors for base classes virtual, so the correct destructors will be called now
2005-12-03 21:05:52 +00:00
byuu 7dec0b2a3c Update to bsnes v014 release.
This version adds speed regulation, greatly improves PPU rendering, and increases speed by ~30% over the previous version.
Changelog:
    - Rewrote offset-per-tile mode emulation, should be correct now. Fixes Chrono Trigger, Contra III, Tetris Attack, etc.
    - Fixed a bug with HDMA occuring during interrupts. Fixes Tales of Phantasia souond test screen
    - Updated compiler to Visual Studio 2005, and enabled profile guided optimizations
    - Added conditional compilation of debugging functions (faster without them)
    - Added conditional compilation of core classes as pointers (allowing polymorphism) or objects (allowing inlining). The latter results in a speed increase
    - Small fixes to BG and OAM rendering routines
    - Corrected sprite tile bounds wrapping
    - Corrected sprite rendering in hires video modes
    - Rewrote color add/sub routines, should be correct now. Fixes Illusion of Gaia menu, etc.
    - Optimized video blitting routines, will temporarilly break mixed video mode screenshots
    - Prevented selecting menu options via return key from being recognized as keypresses by the emulator
    - Added system speed regulation (60hz/NTSC or 50hz/PAL)! Many thanks to kode54, GIGO, and Richard Bannister for their assistance
I disabled the debugger and polymorphism, and enabled profile guided optimizations for this build, to maximize speed. The debugger and polymorphism can be re-enabled via uncommenting the respective #defines in src/base.h and recompiling, or bsnes v0.013 can be used. I may start releasing two separate builds in the future... not sure yet.
2005-11-12 16:49:26 +00:00
byuu f288280ceb Update to bsnes v013r02 release.
[No changelog available]
2005-10-25 23:25:28 +00:00
byuu c6c5f4669c Update to bsnes v013 release.
- Greatly improved HDMA timing and accuracy with help from anomie and DMV27 -- fixes bugs in Energy Breaker and Street Fighter Alpha 2
    - Fixed a problem with color add/sub code -- fixes opening battle in Tales of Phantasia and clouds in Energy Breaker
    - Temporarily added DMV27's bugfix for the DSP KON register -- fixes sound in Der Langrisser, but this is not a hardware-accurate fix
    - Disabled VRAM writes outside of vblank -- fixes Hook, but breaks many PD ROMs and fan translations (Roto's BS Zelda hack, Gideon Zhi's Ys 4 translation, etc). I might add an option in the future to toggle this behavior, but for now these games will no longer work. Please keep in mind these games will not run properly on real SNES hardware, either.
    - Improved frameskipping code thanks to a suggestion from Richard Bannister
    - Misc. other code cleanups and improvements (notably in the color table generation code)
    - bsnes is now endian-safe and runs on Mac OS X
    - Added caching support for window clipping tables resulting in a slight speedup. Please let me know if you spot any errors as a result of this change.
2005-10-23 23:32:30 +00:00
byuu 397b9c4505 Update to bsnes v012 release.
Changelog:
    - Added S-DSP emulation
    - Added sound output support via DirectSound -- no sound buffering though, so sound is muted by default
    - Added option to record raw sound output to WAV files
    - Added multiple color adjustment filters to the video output
    - Added mode3/4 direct color support
    - Added mode7 direct color and mosaic support
    - Greatly improved mode7 rendering algorithm thanks to anomie
    - Fixed mode7 screen repitition and EXTBG effects
    - Greatly increased accuracy of NMI and IRQ timing, and emulated many newly discovered hardware quirks involving the two
    - A few speed improvements courtesy of Nach for profiling the code for me
I'm now looking for assistance with sound buffering. Specifically, I need help modifying the DirectSound code to allow the emulator to be ran between 50%-400% normal speed, while keeping the sound output relatively good. If you have experience with this and can help, please get in touch with me (setsunakun0 at hotmail dot com).
2005-10-02 00:38:34 +00:00
byuu 7e2cfb6d40 Update to bsnes v011 release.
- Fixed Mode 0 color palette index problem. Fixes ToP, DQ5, etc.
    - Improved LoROM memory mapper to support 32mbit images. Fixes Tokimeki Memorial, etc.
    - Added full S-DD1 support, SFA2 and Star Ocean are now playable. Special thanks to Andreas Naive
    - Updated BGnxOFS / Mode7 registers with anomie's latest findings
    - Added basic ROM mirroring support. Fixes copy protection issues in MMX, etc.
    - Rewrote string library to work better on gcc/linux
    - Cleaned up S-RTC/S-DD1 emulation to make way for future add-on chip emulation
    - Rewrote DMA code, now runs cycle-by-cycle
    - Rewrote HDMA code, now allows HDMA to be enabled mid-frame, fixes many games
    - Fixed a bug in Mode7 vertical screen flip mode. Fixes FF5 title screen, etc.
    - Greatly improved IRQ triggering. Fixes Der Langrisser, etc.
    - Added full support for open bus. This includes PPU1 and PPU2 open bus support
    - Modified CPU core back to cycle-based system. Slower, but improves debugger
    - Implemented temporary fix for debugger to handle new cycle-based cores
    - Modified CGRAM to ignore highest bit, since it is not used at all by the SNES, and is impossible to read on real hardware. Lowers memory usage by ~1.2mb
    - Added mostly accurate PAL timing support. This should increase compatibility by ~30% or so
    - More stuff I'm forgetting at the moment...
2005-08-26 20:38:00 +00:00
244 changed files with 35819 additions and 8864 deletions

No files matched your search

+193 -48
View File
@@ -1,57 +1,202 @@
#[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
video.mode = 1
# Mutes SNES audio output when enabled
# (default = false)
snes.mute = false
#[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.
# Regulate speed to 60hz (NTSC) / 50hz (PAL)
# (default = true)
system.regulate_speed = true
# Slowest speed setting (in hz)
# (default = 16000)
system.speed_slowest = 16000
# Slow speed setting
# (default = 24000)
system.speed_slow = 24000
# Normal speed setting
# (default = 32000)
system.speed_normal = 32000
# Fast speed setting
# (default = 48000)
system.speed_fast = 48000
# Fastest speed setting
# (default = 64000)
system.speed_fastest = 64000
# Video mode at startup
# (default = 2)
video.mode = 2
# Video mode 0 (windowed)
# (default = "256x223")
video.mode_0 = "256x223"
# Video mode 1 (windowed)
# (default = "512x446")
video.mode_1 = "512x446"
# Video mode 2 (windowed)
# (default = "640x480")
video.mode_2 = "640x480"
# Video mode 3 (windowed)
# (default = "960x720")
video.mode_3 = "960x720"
# Video mode 4 (windowed)
# (default = "1152x864")
video.mode_4 = "1152x864"
# Video mode 5 (fullscreen)
# (default = "640x480@60:640x480")
video.mode_5 = "640x480@60:640x480"
# Video mode 6 (fullscreen)
# (default = "800x600@60:800x600")
video.mode_6 = "800x600@60:800x600"
# Video mode 7 (fullscreen)
# (default = "1024x768@60:1024x768")
video.mode_7 = "1024x768@60:1024x768"
# Video mode 8 (fullscreen)
# (default = "1280x960@60:1280x960")
video.mode_8 = "1280x960@60:1280x960"
# Video mode 9 (fullscreen)
# (default = "1600x1200@60:1600x1200")
video.mode_9 = "1600x1200@60:1600x1200"
# 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
# Use triple buffering
# (default = false)
video.triple_buffering = false
#[show fps]
# true: show fps in titlebar
# false: do not show fps in titlebar
# Show framerate in window title
# (default = true)
gui.show_fps = true
#[wait for vertical retrace]
video.vblank = false
# Allow "impossible" key combinations for joypad 1 (not recommended)
# (default = false)
input.joypad1.allow_invalid_input = false
# Joypad1 up
# (default = 0x80c8)
input.joypad1.up = 0x80c8
# Joypad1 down
# (default = 0x81d0)
input.joypad1.down = 0x81d0
# Joypad1 left
# (default = 0x82cb)
input.joypad1.left = 0x82cb
# Joypad1 right
# (default = 0x83cd)
input.joypad1.right = 0x83cd
# Joypad1 A
# (default = 0x42d)
input.joypad1.a = 0x42d
# Joypad1 B
# (default = 0x32c)
input.joypad1.b = 0x32c
# Joypad1 X
# (default = 0x11f)
input.joypad1.x = 0x11f
# Joypad1 Y
# (default = 0x1e)
input.joypad1.y = 0x1e
# Joypad1 L
# (default = 0x620)
input.joypad1.l = 0x620
# Joypad1 R
# (default = 0x72e)
input.joypad1.r = 0x72e
# Joypad1 select
# (default = 0x836)
input.joypad1.select = 0x836
# Joypad1 start
# (default = 0x91c)
input.joypad1.start = 0x91c
# Allow "impossible" key combinations for joypad 2 (not recommended)
# (default = false)
input.joypad2.allow_invalid_input = false
# Joypad2 up
# (default = 0xff14)
input.joypad2.up = 0xff14
# Joypad2 down
# (default = 0xff22)
input.joypad2.down = 0xff22
# Joypad2 left
# (default = 0xff21)
input.joypad2.left = 0xff21
# Joypad2 right
# (default = 0xff23)
input.joypad2.right = 0xff23
# Joypad2 A
# (default = 0xff25)
input.joypad2.a = 0xff25
# Joypad2 B
# (default = 0xff24)
input.joypad2.b = 0xff24
# Joypad2 X
# (default = 0xff17)
input.joypad2.x = 0xff17
# Joypad2 Y
# (default = 0xff16)
input.joypad2.y = 0xff16
# Joypad2 L
# (default = 0xff18)
input.joypad2.l = 0xff18
# Joypad2 R
# (default = 0xff26)
input.joypad2.r = 0xff26
# Joypad2 select
# (default = 0xff1a)
input.joypad2.select = 0xff1a
# Joypad2 start
# (default = 0xff1b)
input.joypad2.start = 0xff1b
#[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.
input.joypad1.up = 0x26
input.joypad1.down = 0x28
input.joypad1.left = 0x25
input.joypad1.right = 0x27
input.joypad1.a = 0x58
input.joypad1.b = 0x5a
input.joypad1.x = 0x53
input.joypad1.y = 0x41
input.joypad1.l = 0x44
input.joypad1.r = 0x43
input.joypad1.select = 0x10
input.joypad1.start = 0x0d
BIN
View File
Binary file not shown.
+6 -1
View File
@@ -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
View File
@@ -1,2 +1,3 @@
#include "../base.h"
#include "iplrom.h"
#include "dapu.cpp"
+7 -2
View File
@@ -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,11 +17,17 @@ 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;
virtual void reset() = 0;
//debugging functions
virtual bool in_opcode();
void disassemble_opcode(char *output);
inline uint16 __relb(int8 offset, int op_len);
APU() {}
virtual ~APU() {}
};
+7 -6
View File
@@ -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;
+23 -11
View File
@@ -24,13 +24,13 @@ uint8 r;
break;
case 0xf3: //DSPDATA
//0x80-0xff is a read-only mirror of 0x00-0x7f
r = dsp_regs[status.dsp_addr & 0x7f];
r = r_dsp->read(status.dsp_addr & 0x7f);
break;
case 0xf4: //CPUIO0
case 0xf5: //CPUIO1
case 0xf6: //CPUIO2
case 0xf7: //CPUIO3
r = cpu->port_read(addr & 3);
r = r_cpu->port_read(addr & 3);
break;
case 0xf8: //???
case 0xf9: //??? -- Mapped to SPCRAM
@@ -63,7 +63,10 @@ uint8 r;
r = spcram[addr];
}
}
#ifdef DEBUGGER
snes->notify(SNES::SPCRAM_READ, addr, r);
#endif
return r;
}
@@ -78,12 +81,12 @@ void bAPU::spcram_write(uint16 addr, uint8 value) {
//one-time clearing of APU port read registers,
//emulated by simulating CPU writes of 0x00
if(value & 0x20) {
cpu->port_write(2, 0x00);
cpu->port_write(3, 0x00);
r_cpu->port_write(2, 0x00);
r_cpu->port_write(3, 0x00);
}
if(value & 0x10) {
cpu->port_write(0, 0x00);
cpu->port_write(1, 0x00);
r_cpu->port_write(0, 0x00);
r_cpu->port_write(1, 0x00);
}
//0->1 transistion resets timers
@@ -111,7 +114,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;
r_dsp->write(status.dsp_addr & 0x7f, value);
}
break;
case 0xf4: //CPUIO0
@@ -143,7 +146,10 @@ void bAPU::spcram_write(uint16 addr, uint8 value) {
//even if the iplrom is enabled.
spcram[addr] = value;
}
#ifdef DEBUGGER
snes->notify(SNES::SPCRAM_WRITE, addr, value);
#endif
}
uint8 bAPU::port_read(uint8 port) {
@@ -209,6 +215,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();
}
@@ -226,7 +240,8 @@ void bAPU::reset() {
regs.sp = 0xef;
regs.p = 0x02;
status.cycle_pos = 0;
status.cycle_pos = 0;
status.cycles_executed = 0;
//$f1
status.iplrom_enabled = true;
@@ -246,15 +261,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
+3 -1
View File
@@ -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();
@@ -53,6 +54,7 @@ enum {
inline void stack_write(uint8 value);
inline void exec_cycle();
inline bool in_opcode();
inline void init_op_table();
inline uint8 op_adc (uint8 x, uint8 y);
+17 -8
View File
@@ -1,18 +1,27 @@
void bAPU::exec_cycle() {
uint8 op;
if(status.cycle_pos == 0) {
op = spcram_read(regs.pc);
snes->notify(SNES::APU_EXEC_OPCODE_BEGIN);
status.opcode = op_read();
status.cycle_pos = 1;
add_cycles(1);
} else {
if(status.cycle_pos) {
(this->*optbl[status.opcode])();
add_cycles(1);
if(status.cycle_pos == 0) {
#ifdef DEBUGGER
snes->notify(SNES::APU_EXEC_OPCODE_END);
#endif
}
return;
}
//on first cycle?
#ifdef DEBUGGER
snes->notify(SNES::APU_EXEC_OPCODE_BEGIN);
#endif
status.opcode = op_read();
status.cycle_pos = 1;
add_cycles(1);
}
//only return true when we are on an opcode edge
bool bAPU::in_opcode() {
return (status.cycle_pos != 0);
}
void bAPU::init_op_table() {
+8 -10
View File
@@ -9,12 +9,11 @@ int16 r = x + y + regs.p.c;
}
uint16 bAPU::op_addw(uint16 x, uint16 y) {
int32 r = x + y;
regs.p.n = !!(r & 0x8000);
regs.p.v = !!(~(x ^ y) & (y ^ (uint16)r) & 0x8000);
regs.p.h = !!((x ^ y ^ (uint16)r) & 0x10);
int16 r;
regs.p.c = 0;
r = op_adc(x, y);
r |= op_adc(x >> 8, y >> 8) << 8;
regs.p.z = ((uint16)r == 0);
regs.p.c = (r > 0xffff);
return r;
}
@@ -66,12 +65,11 @@ int16 r = x - y - !regs.p.c;
}
uint16 bAPU::op_subw(uint16 x, uint16 y) {
int32 r = x - y;
regs.p.n = !!(r & 0x8000);
regs.p.v = !!((x ^ y) & (x ^ (uint16)r) & 0x8000);
regs.p.h = !((x ^ y ^ (uint16)r) & 0x10);
int16 r;
regs.p.c = 1;
r = op_sbc(x, y);
r |= op_sbc(x >> 8, y >> 8) << 8;
regs.p.z = ((uint16)r == 0);
regs.p.c = (r >= 0);
return r;
}
+5 -3
View File
@@ -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;
+3 -3
View File
@@ -107,16 +107,16 @@ int i, l;
replace(t, "$5", op_list[i].arg[5]);
replace(t, "$6", op_list[i].arg[6]);
replace(t, "$7", op_list[i].arg[7]);
fprintf(fp, "%s\r\n\r\n", *t);
fprintf(fp, "%s\r\n\r\n", strptr(t));
strcpy(t, output_header);
replace(t, "$$", op_list[i].name);
fprintf(fph, "%s", *t);
fprintf(fph, "%s", strptr(t));
strcpy(t, output_table);
replace(t, "$$", op_list[i].name);
replace(t, "$0", op_list[i].arg[0]);
fprintf(fpt, "%s", *t);
fprintf(fpt, "%s", strptr(t));
}
}
Binary file not shown.
+12 -3
View File
@@ -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();
-171
View File
@@ -1,171 +0,0 @@
#include "../../base.h"
uint8 bAPUSkip::spcram_read (uint16 addr) { return 0xff; }
void bAPUSkip::spcram_write(uint16 addr, uint8 value) {}
/*
This routine is very serious. It will eat holes through
the ROM to skip APU test conditions. Or in other words,
it will disable and/or force branches when neccesary.
It can very easily break or corrupt a game and prevent it
from being playable until the ROM is reloaded (ROM writes
are only performed in memory, of course).
However, this kind of brute force approach is required to
get many games playable without proper SPC700 emulation.
*/
uint8 bAPUSkip::port_read(uint8 port) {
port &= 3;
_apu_port *p = &apu_port[port];
int i, x, y, z, t;
uint32 addr;
addr = cpu->regs.pc.d;
p->read_addr[p->read_pos & 31] = addr;
//- lda $214x
// cmp $214x
// bne -
// cmp ???
// beq/bne -
__test1:
//look for an lda/cmp read pattern
if(addr == p->read_addr[(p->read_pos - 1) & 31])goto __test2;
if(addr != p->read_addr[(p->read_pos - 2) & 31])goto __test2;
if(addr == p->read_addr[(p->read_pos - 3) & 31])goto __test2;
if(addr != p->read_addr[(p->read_pos - 4) & 31])goto __test2;
if(p->read_addr[(p->read_pos - 1) & 31] != p->read_addr[(p->read_pos - 3) & 31])goto __test2;
//try and find compare opcode
for(i=0;i<24;i++) {
x = mem_bus->read(addr + i);
if(x == OP_CMP_CONST || x == OP_CPX_CONST || x == OP_CPY_CONST)break;
if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) break;
if(x == OP_CMP_LONG)break;
}
if(i == 24)goto __test2;
//seek to next opcode
if(x == OP_CMP_CONST) {
i += (cpu->regs.p.m)?2:3;
} else if(x == OP_CPX_CONST || x == OP_CPY_CONST) {
i += (cpu->regs.p.x)?2:3;
} else if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) {
i += 3;
} else { //(x == OP_CMP_LONG) {
i += 4;
}
x = mem_bus->read(addr + i);
if(x == OP_BNE) {
mem_bus->cart->write_protect(false);
mem_bus->write(addr + i, OP_NOP);
mem_bus->write(addr + i + 1, OP_NOP);
mem_bus->cart->write_protect(true);
} else if(x == OP_BEQ) {
mem_bus->cart->write_protect(false);
mem_bus->write(addr + i, OP_BRA);
mem_bus->cart->write_protect(true);
} else goto __test2;
goto __pass;
//- lda $214x
// cmp ???
// beq/bne -
__test2:
//look for a repeated read pattern
if(addr != p->read_addr[(p->read_pos - 1) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 2) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 3) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 4) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 5) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 6) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 7) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 8) & 31])goto __test3;
//try and find compare opcode
for(i=0;i<24;i++) {
x = mem_bus->read(addr + i);
if(x == OP_CMP_CONST || x == OP_CPX_CONST || x == OP_CPY_CONST)break;
if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) break;
if(x == OP_CMP_LONG)break;
}
if(i == 24)goto __test3;
//seek to next opcode
if(x == OP_CMP_CONST) {
i += (cpu->regs.p.m)?2:3;
} else if(x == OP_CPX_CONST || x == OP_CPY_CONST) {
i += (cpu->regs.p.x)?2:3;
} else if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) {
i += 3;
} else if(x == OP_CMP_LONG) {
i += 4;
}
x = mem_bus->read(addr + i);
if(x == OP_BNE) {
mem_bus->cart->write_protect(false);
mem_bus->write(addr + i, OP_NOP);
mem_bus->write(addr + i + 1, OP_NOP);
mem_bus->cart->write_protect(true);
} else if(x == OP_BEQ) {
mem_bus->cart->write_protect(false);
mem_bus->write(addr + i, OP_BRA);
mem_bus->cart->write_protect(true);
} else goto __test3;
goto __pass;
//fallback
__test3:
if(p->pos < 4) {
if(!(port & 1)) {
p->value = cpu->regs.a.l;
} else {
p->value = cpu->regs.a.h;
}
} else if(p->pos < 8) {
if(!(port & 1)) {
p->value = cpu->regs.x.l;
} else {
p->value = cpu->regs.x.h;
}
} else if(p->pos < 12) {
if(!(port & 1)) {
p->value = cpu->regs.y.l;
} else {
p->value = cpu->regs.y.h;
}
} else if(p->pos < 16) {
p->value = rand();
}
if(++p->pos == 16)p->pos = 0;
__pass:
p->read_pos++;
p->read_pos &= 31;
return p->value;
}
void bAPUSkip::port_write(uint8 port, uint8 value) {
port &= 3;
apu_port[port].value = value;
}
void bAPUSkip::run() {
snes->notify(SNES::APU_EXEC_OPCODE_BEGIN);
snes->notify(SNES::APU_EXEC_OPCODE_END);
}
void bAPUSkip::power() {
reset();
}
void bAPUSkip::reset() {
regs.a = 0x00;
regs.x = 0x00;
regs.y = 0x00;
regs.sp = 0x00;
regs.p = 0x02;
regs.pc = 0xffc0;
memset(&apu_port[0], 0, sizeof(_apu_port));
memset(&apu_port[1], 0, sizeof(_apu_port));
memset(&apu_port[2], 0, sizeof(_apu_port));
memset(&apu_port[3], 0, sizeof(_apu_port));
}
-33
View File
@@ -1,33 +0,0 @@
class bAPUSkip : public APU {
public:
struct _apu_port {
uint8 value;
uint8 step, pos;
uint32 read_addr[32], read_pos;
}apu_port[4];
enum {
OP_CMP_CONST = 0xc9,
OP_CPX_CONST = 0xe0,
OP_CPY_CONST = 0xc0,
OP_CMP_ADDR = 0xcd,
OP_CPX_ADDR = 0xec,
OP_CPY_ADDR = 0xcc,
OP_CMP_LONG = 0xcf,
OP_BNE = 0xd0,
OP_BEQ = 0xf0,
OP_BRA = 0x80,
OP_NOP = 0xea
};
uint8 spcram_read (uint16 addr);
void spcram_write(uint16 addr, uint8 value);
uint8 port_read (uint8 port);
void port_write (uint8 port, uint8 value);
void run();
uint32 cycles_executed() { return 12 * 24; }
void power();
void reset();
};
+12 -1
View File
@@ -1,12 +1,23 @@
//virtual function, see src/cpu/dcpu.cpp
//for explanation of this function
bool APU::in_opcode() { return false; }
uint16 APU::__relb(int8 offset, int op_len) {
uint16 pc = regs.pc + op_len;
return pc + offset;
}
void APU::disassemble_opcode(char *output) {
char *s = output, t[512];
char *s, t[512];
uint8 op, op0, op1;
uint16 opw, opdp0, opdp1;
s = output;
if(in_opcode() == true) {
strcpy(s, "..???? <APU within opcode>");
return;
}
sprintf(s, "..%0.4x ", regs.pc);
op = spcram_read(regs.pc);
+1 -8
View File
@@ -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
+43 -5
View File
@@ -1,11 +1,49 @@
//debugging extensions (~10% speed hit)
//#define DEBUGGER
//snes core polymorphism (allow mem/cpu/apu/ppu overriding,
//~10% speed hit)
//#define POLYMORPHISM
//enable GZ, ZIP format support
#define GZIP_SUPPORT
//enable JMA support
#define JMA_SUPPORT
//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"
//structs
typedef struct {
uint8 *data;
uint32 size;
}lfile;
inline uint16 read16(uint8 *addr, uint pos) {
#ifdef ARCH_LSB
return *((uint16*)(addr + pos));
#else
return (addr[pos]) | (addr[pos + 1] << 8);
#endif
}
#if defined(_WIN32)
#define _WIN32_
#undef _UNIX_
#elif defined(__GNUC__)
#define _UNIX_
#undef _WIN32_
#else
#error "unknown architecture"
#endif
//platform-specific global functions
void *memalloc(uint32 size, char *name = 0, ...);
+243
View File
@@ -0,0 +1,243 @@
#include "../base.h"
void Cartridge::read_header() {
cart.srtc = false;
cart.sdd1 = false;
cart.c4 = false;
if(cart.header_index == 0x7fc0 && cart.rom_size >= 0x401000) {
cart.mapper = EXLOROM;
} else if(cart.header_index == 0x7fc0 && rom[cart.header_index + MAPPER] == 0x32) {
cart.mapper = EXLOROM;
} else if(cart.header_index == 0x7fc0) {
cart.mapper = LOROM;
} else if(cart.header_index == 0xffc0) {
cart.mapper = HIROM;
} else { //cart.header_index == 0x40ffc0
cart.mapper = EXHIROM;
}
uint8 mapper = rom[cart.header_index + MAPPER];
uint8 rom_type = rom[cart.header_index + ROM_TYPE];
if(mapper == 0x35 && rom_type == 0x55) {
cart.srtc = true;
}
if(mapper == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
cart.sdd1 = true;
}
if(mapper == 0x20 && rom_type == 0xf3) {
cart.c4 = true;
}
if(rom[cart.header_index + SRAM_SIZE] & 7) {
cart.sram_size = 1024 << (rom[cart.header_index + SRAM_SIZE] & 7);
} else {
cart.sram_size = 0;
}
cart.region = (rom[cart.header_index + REGION] < 2) ? NTSC : PAL;
memcpy(&cart.name, &rom[cart.header_index + CART_NAME], 21);
cart.name[21] = 0;
for(int i=0;i<22;i++) {
if(cart.name[i] & 0x80) {
cart.name[i] = '?';
}
}
}
void Cartridge::find_header() {
int32 score_lo = 0,
score_hi = 0,
score_ex = 0;
if(rom_size < 0x010000) {
//cart too small to be anything else
cart.header_index = 0x007fc0;
return;
}
if((rom[0x7fc0 + MAPPER] & ~0x10) == 0x20)score_lo++;
if((rom[0xffc0 + MAPPER] & ~0x10) == 0x21)score_hi++;
if(rom[0x7fc0 + ROM_TYPE] < 0x08)score_lo++;
if(rom[0xffc0 + ROM_TYPE] < 0x08)score_hi++;
if(rom[0x7fc0 + ROM_SIZE] < 0x10)score_lo++;
if(rom[0xffc0 + ROM_SIZE] < 0x10)score_hi++;
if(rom[0x7fc0 + SRAM_SIZE] < 0x08)score_lo++;
if(rom[0xffc0 + SRAM_SIZE] < 0x08)score_hi++;
if(rom[0x7fc0 + REGION] < 14)score_lo++;
if(rom[0xffc0 + REGION] < 14)score_hi++;
if(rom[0x7fc0 + LICENSE] < 3)score_lo++;
if(rom[0xffc0 + LICENSE] < 3)score_hi++;
uint16 cksum, icksum;
cksum = rom[0x7fc0 + CKSUM] | (rom[0x7fc0 + CKSUM + 1] << 8);
icksum = rom[0x7fc0 + ICKSUM] | (rom[0x7fc0 + ICKSUM + 1] << 8);
if((cksum + icksum) == 0xffff)score_lo += 8;
cksum = rom[0xffc0 + CKSUM] | (rom[0xffc0 + CKSUM + 1] << 8);
icksum = rom[0xffc0 + ICKSUM] | (rom[0xffc0 + ICKSUM + 1] << 8);
if((cksum + icksum) == 0xffff)score_hi += 8;
if(rom_size < 0x401000) {
score_ex = 0;
} else {
if(rom[0x7fc0 + MAPPER] == 0x32)score_lo++;
else score_ex += 16;
}
if(score_lo >= score_hi && score_lo >= score_ex) {
cart.header_index = 0x007fc0;
} else if(score_hi >= score_ex) {
cart.header_index = 0x00ffc0;
} else {
cart.header_index = 0x40ffc0;
}
}
void Cartridge::load_sram() {
if(cart.sram_size == 0) {
sram = 0;
return;
}
FileReader ff;
if(!ff.open(sram_fn)) {
sram = (uint8*)malloc(cart.sram_size);
memset(sram, 0, cart.sram_size);
return;
}
sram = ff.read(cart.sram_size);
ff.close();
}
void Cartridge::save_sram() {
if(cart.sram_size == 0)return;
FileWriter ff;
if(!ff.open(sram_fn))return;
ff.write(sram, cart.sram_size);
ff.close();
}
void Cartridge::load_rom(Reader *rf) {
base_rom = rf->read();
rom_size = rf->size();
if((rom_size & 0x7fff) == 0x0200) {
rom = base_rom + 512;
rom_size -= 512;
} else {
rom = base_rom;
}
cart.rom_size = rom_size;
}
bool Cartridge::load(const char *fn) {
if(cart_loaded == true)return false;
if(strlen(fn) < 3)return false;
dprintf("* Loading \"%s\"...", fn);
strcpy(rom_fn, fn);
switch(Reader::detect(rom_fn)) {
case Reader::RF_NORMAL: {
FileReader ff;
if(!ff.open(rom_fn)) {
alert("Error loading image file (%s)!", rom_fn);
return false;
}
load_rom(static_cast<Reader*>(&ff));
ff.close();
break;
}
#ifdef GZIP_SUPPORT
case Reader::RF_GZ: {
GZReader gf;
if(!gf.open(rom_fn)) {
alert("Error loading image file (%s)!", rom_fn);
return false;
}
load_rom(static_cast<Reader*>(&gf));
gf.close();
break;
}
case Reader::RF_ZIP: {
ZipReader zf(rom_fn);
load_rom(static_cast<Reader*>(&zf));
break;
}
#endif
#ifdef JMA_SUPPORT
case Reader::RF_JMA: {
try {
JMAReader jf(rom_fn);
load_rom(static_cast<Reader*>(&jf));
} catch(JMA::jma_errors jma_error) {
alert("Error loading image file (%s)!", rom_fn);
return false;
}
break;
}
#endif
}
int i;
strcpy(sram_fn, fn);
for(i=strlen(fn)-1;i>=0;i--) {
if(fn[i] == '.')break;
}
if(i != 0)sram_fn[i] = 0;
strcat(sram_fn, ".srm");
find_header();
read_header();
load_sram();
cart_loaded = true;
r_mem->load_cart();
return true;
}
bool Cartridge::unload() {
if(cart_loaded == false)return false;
r_mem->unload_cart();
if(base_rom) {
zerofree(base_rom);
}
if(sram) {
save_sram();
zerofree(sram);
}
cart_loaded = false;
return true;
}
Cartridge::Cartridge() {
cart_loaded = false;
base_rom = 0;
rom = 0;
sram = 0;
rom_size = 0;
}
Cartridge::~Cartridge() {
if(cart_loaded == true) {
unload();
}
}
+59
View File
@@ -0,0 +1,59 @@
class Cartridge {
public:
bool cart_loaded;
char rom_fn[4096], sram_fn[4096];
uint8 *base_rom, *rom, *sram;
uint32 rom_size;
enum {
//header fields
CART_NAME = 0x00,
MAPPER = 0x15,
ROM_TYPE = 0x16,
ROM_SIZE = 0x17,
SRAM_SIZE = 0x18,
REGION = 0x19,
LICENSE = 0x1a,
VERSION = 0x1b,
ICKSUM = 0x1c,
CKSUM = 0x1e,
//regions
NTSC = 0,
PAL = 1,
//memory mappers
LOROM = 0x20,
HIROM = 0x21,
EXLOROM = 0x22,
EXHIROM = 0x25,
};
struct {
uint32 header_index;
char name[32];
uint32 rom_size;
uint32 sram_size;
bool region;
uint32 mapper;
bool srtc;
bool sdd1;
bool c4;
} cart;
void load_rom(Reader *rf);
void load_sram();
void save_sram();
void find_header();
void read_header();
bool load(const char *fn);
bool unload();
Cartridge();
~Cartridge();
};
extern Cartridge cartridge;
+197
View File
@@ -0,0 +1,197 @@
/*
C4 emulation
Used in Rockman X2/X3 (Megaman X2/X3)
Portions (c) anomie, Overload, zsKnight, Nach, byuu
*/
#include "../../base.h"
#include "c4data.cpp"
#include "c4fn.cpp"
#include "c4oam.cpp"
#include "c4ops.cpp"
void C4::init() {}
void C4::enable() {}
uint32 C4::ldr(uint8 r) {
uint16 addr = 0x0080 + (r * 3);
return (reg[addr]) | (reg[addr + 1] << 8) | (reg[addr + 2] << 16);
}
void C4::str(uint8 r, uint32 data) {
uint16 addr = 0x0080 + (r * 3);
reg[addr ] = (data);
reg[addr + 1] = (data >> 8);
reg[addr + 2] = (data >> 16);
}
void C4::mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh) {
int64 rx = x & 0xffffff;
int64 ry = y & 0xffffff;
if(rx & 0x800000)rx |= ~0x7fffff;
if(ry & 0x800000)ry |= ~0x7fffff;
rx *= ry;
rl = (rx) & 0xffffff;
rh = (rx >> 24) & 0xffffff;
}
uint32 C4::sin(uint32 rx) {
r0 = rx & 0x1ff;
if(r0 & 0x100)r0 ^= 0x1ff;
if(r0 & 0x080)r0 ^= 0x0ff;
if(rx & 0x100) {
return sin_table[r0 + 0x80];
} else {
return sin_table[r0];
}
}
uint32 C4::cos(uint32 rx) {
return sin(rx + 0x080);
}
void C4::immediate_reg(uint32 start) {
r0 = ldr(0);
for(uint32 i=start;i<48;i++) {
if((r0 & 0x0fff) < 0x0c00) {
ram[r0 & 0x0fff] = immediate_data[i];
}
r0++;
}
str(0, r0);
}
void C4::transfer_data() {
uint32 src;
uint16 dest, count;
src = (reg[0x40]) | (reg[0x41] << 8) | (reg[0x42] << 16);
count = (reg[0x43]) | (reg[0x44] << 8);
dest = (reg[0x45]) | (reg[0x46] << 8);
for(uint32 i=0;i<count;i++) {
write(dest++, r_mem->read(src++));
}
}
void C4::write(uint16 addr, uint8 data) {
addr &= 0x1fff;
if(addr < 0x0c00) {
//ram
ram[addr] = data;
return;
}
if(addr < 0x1f00) {
//unmapped
return;
}
//command register
reg[addr & 0xff] = data;
if(addr == 0x1f47) {
//memory transfer
transfer_data();
return;
}
if(addr == 0x1f4f) {
//c4 command
if(reg[0x4d] == 0x0e && !(data & 0xc3)) {
//c4 test command
reg[0x80] = data >> 2;
return;
}
switch(data) {
case 0x00:op00();break;
case 0x01:op01();break;
case 0x05:op05();break;
case 0x0d:op0d();break;
case 0x10:op10();break;
case 0x13:op13();break;
case 0x15:op15();break;
case 0x1f:op1f();break;
case 0x22:op22();break;
case 0x25:op25();break;
case 0x2d:op2d();break;
case 0x40:op40();break;
case 0x54:op54();break;
case 0x5c:op5c();break;
case 0x5e:op5e();break;
case 0x60:op60();break;
case 0x62:op62();break;
case 0x64:op64();break;
case 0x66:op66();break;
case 0x68:op68();break;
case 0x6a:op6a();break;
case 0x6c:op6c();break;
case 0x6e:op6e();break;
case 0x70:op70();break;
case 0x72:op72();break;
case 0x74:op74();break;
case 0x76:op76();break;
case 0x78:op78();break;
case 0x7a:op7a();break;
case 0x7c:op7c();break;
case 0x89:op89();break;
}
}
}
void C4::writeb(uint16 addr, uint8 data) {
write(addr, data);
}
void C4::writew(uint16 addr, uint16 data) {
write(addr, data);
write(addr + 1, data >> 8);
}
void C4::writel(uint16 addr, uint32 data) {
write(addr, data);
write(addr + 1, data >> 8);
write(addr + 2, data >> 16);
}
uint8 C4::read(uint16 addr) {
addr &= 0x1fff;
if(addr < 0x0c00) {
return ram[addr];
}
if(addr >= 0x1f00) {
return reg[addr & 0xff];
}
return r_cpu->regs.mdr;
}
uint8 C4::readb(uint16 addr) {
return read(addr);
}
uint16 C4::readw(uint16 addr) {
return read(addr) | (read(addr + 1) << 8);
}
uint32 C4::readl(uint16 addr) {
return read(addr) | (read(addr + 1) << 8) + (read(addr + 2) << 16);
}
void C4::power() {
reset();
}
void C4::reset() {
memset(ram, 0, 0x0c00);
memset(reg, 0, 0x0100);
}
C4::C4() {}
+94
View File
@@ -0,0 +1,94 @@
class C4 {
private:
uint8 ram[0x0c00];
uint8 reg[0x0100];
uint32 r0, r1, r2, r3, r4, r5, r6, r7,
r8, r9, r10, r11, r12, r13, r14, r15;
static const uint8 immediate_data[48];
static const uint16 wave_data[40];
static const uint32 sin_table[256];
static const int16 SinTable[512];
static const int16 CosTable[512];
int16 C4WFXVal, C4WFYVal, C4WFZVal, C4WFX2Val, C4WFY2Val, C4WFDist, C4WFScale;
int16 C41FXVal, C41FYVal, C41FAngleRes, C41FDist, C41FDistVal;
double tanval;
double c4x,c4y,c4z, c4x2,c4y2,c4z2;
void C4TransfWireFrame();
void C4TransfWireFrame2();
void C4CalcWireFrame();
void C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color);
void C4DrawWireFrame();
void C4DoScaleRotate(int row_padding);
public:
uint32 ldr(uint8 r);
void str(uint8 r, uint32 data);
void mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh);
uint32 sin(uint32 rx);
uint32 cos(uint32 rx);
void transfer_data();
void immediate_reg(uint32 num);
void op00_00();
void op00_03();
void op00_05();
void op00_07();
void op00_08();
void op00_0b();
void op00_0c();
void op00();
void op01();
void op05();
void op0d();
void op10();
void op13();
void op15();
void op1f();
void op22();
void op25();
void op2d();
void op40();
void op54();
void op5c();
void op5e();
void op60();
void op62();
void op64();
void op66();
void op68();
void op6a();
void op6c();
void op6e();
void op70();
void op72();
void op74();
void op76();
void op78();
void op7a();
void op7c();
void op89();
void init();
void enable();
void power();
void reset();
void write (uint16 addr, uint8 data);
void writeb(uint16 addr, uint8 data);
void writew(uint16 addr, uint16 data);
void writel(uint16 addr, uint32 data);
uint8 read (uint16 addr);
uint8 readb(uint16 addr);
uint16 readw(uint16 addr);
uint32 readl(uint16 addr);
C4();
};
+183
View File
@@ -0,0 +1,183 @@
const uint8 C4::immediate_data[48] = {
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f,
0x00, 0x80, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff,
0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00
};
const uint16 C4::wave_data[40] = {
0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020a, 0x020c, 0x020e,
0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e,
0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060a, 0x060c, 0x060e,
0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080a, 0x080c, 0x080e
};
const uint32 C4::sin_table[256] = {
0x000000, 0x000324, 0x000648, 0x00096c, 0x000c8f, 0x000fb2, 0x0012d5, 0x0015f6,
0x001917, 0x001c37, 0x001f56, 0x002273, 0x002590, 0x0028aa, 0x002bc4, 0x002edb,
0x0031f1, 0x003505, 0x003817, 0x003b26, 0x003e33, 0x00413e, 0x004447, 0x00474d,
0x004a50, 0x004d50, 0x00504d, 0x005347, 0x00563e, 0x005931, 0x005c22, 0x005f0e,
0x0061f7, 0x0064dc, 0x0067bd, 0x006a9b, 0x006d74, 0x007049, 0x007319, 0x0075e5,
0x0078ad, 0x007b70, 0x007e2e, 0x0080e7, 0x00839c, 0x00864b, 0x0088f5, 0x008b9a,
0x008e39, 0x0090d3, 0x009368, 0x0095f6, 0x00987f, 0x009b02, 0x009d7f, 0x009ff6,
0x00a267, 0x00a4d2, 0x00a736, 0x00a994, 0x00abeb, 0x00ae3b, 0x00b085, 0x00b2c8,
0x00b504, 0x00b73a, 0x00b968, 0x00bb8f, 0x00bdae, 0x00bfc7, 0x00c1d8, 0x00c3e2,
0x00c5e4, 0x00c7de, 0x00c9d1, 0x00cbbb, 0x00cd9f, 0x00cf7a, 0x00d14d, 0x00d318,
0x00d4db, 0x00d695, 0x00d848, 0x00d9f2, 0x00db94, 0x00dd2d, 0x00debe, 0x00e046,
0x00e1c5, 0x00e33c, 0x00e4aa, 0x00e60f, 0x00e76b, 0x00e8bf, 0x00ea09, 0x00eb4b,
0x00ec83, 0x00edb2, 0x00eed8, 0x00eff5, 0x00f109, 0x00f213, 0x00f314, 0x00f40b,
0x00f4fa, 0x00f5de, 0x00f6ba, 0x00f78b, 0x00f853, 0x00f912, 0x00f9c7, 0x00fa73,
0x00fb14, 0x00fbac, 0x00fc3b, 0x00fcbf, 0x00fd3a, 0x00fdab, 0x00fe13, 0x00fe70,
0x00fec4, 0x00ff0e, 0x00ff4e, 0x00ff84, 0x00ffb1, 0x00ffd3, 0x00ffec, 0x00fffb,
0x000000, 0xfffcdb, 0xfff9b7, 0xfff693, 0xfff370, 0xfff04d, 0xffed2a, 0xffea09,
0xffe6e8, 0xffe3c8, 0xffe0a9, 0xffdd8c, 0xffda6f, 0xffd755, 0xffd43b, 0xffd124,
0xffce0e, 0xffcafa, 0xffc7e8, 0xffc4d9, 0xffc1cc, 0xffbec1, 0xffbbb8, 0xffb8b2,
0xffb5af, 0xffb2af, 0xffafb2, 0xffacb8, 0xffa9c1, 0xffa6ce, 0xffa3dd, 0xffa0f1,
0xff9e08, 0xff9b23, 0xff9842, 0xff9564, 0xff928b, 0xff8fb6, 0xff8ce6, 0xff8a1a,
0xff8752, 0xff848f, 0xff81d1, 0xff7f18, 0xff7c63, 0xff79b4, 0xff770a, 0xff7465,
0xff71c6, 0xff6f2c, 0xff6c97, 0xff6a09, 0xff6780, 0xff64fd, 0xff6280, 0xff6009,
0xff5d98, 0xff5b2d, 0xff58c9, 0xff566b, 0xff5414, 0xff51c4, 0xff4f7a, 0xff4d37,
0xff4afb, 0xff48c5, 0xff4697, 0xff4470, 0xff4251, 0xff4038, 0xff3e27, 0xff3c1e,
0xff3a1b, 0xff3821, 0xff362e, 0xff3444, 0xff3260, 0xff3085, 0xff2eb2, 0xff2ce7,
0xff2b24, 0xff296a, 0xff27b7, 0xff260d, 0xff246b, 0xff22d2, 0xff2141, 0xff1fb9,
0xff1e3a, 0xff1cc3, 0xff1b55, 0xff19f0, 0xff1894, 0xff1740, 0xff15f6, 0xff14b4,
0xff137c, 0xff124d, 0xff1127, 0xff100a, 0xff0ef6, 0xff0dec, 0xff0ceb, 0xff0bf4,
0xff0b05, 0xff0a21, 0xff0945, 0xff0874, 0xff07ac, 0xff06ed, 0xff0638, 0xff058d,
0xff04eb, 0xff0453, 0xff03c4, 0xff0340, 0xff02c5, 0xff0254, 0xff01ec, 0xff018f,
0xff013b, 0xff00f1, 0xff00b1, 0xff007b, 0xff004e, 0xff002c, 0xff0013, 0xff0004
};
const int16 C4::SinTable[512] = {
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765,
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402
};
const int16 C4::CosTable[512] = {
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402,
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765
};
+242
View File
@@ -0,0 +1,242 @@
#include <math.h>
#define Tan(a) (CosTable[a] ? ((((int32)SinTable[a]) << 16) / CosTable[a]) : 0x80000000)
#define sar(b, n) ((b) >> (n))
#ifdef PI
#undef PI
#endif
#define PI 3.1415926535897932384626433832795
//Wireframe Helpers
void C4::C4TransfWireFrame() {
c4x = (double)C4WFXVal;
c4y = (double)C4WFYVal;
c4z = (double)C4WFZVal - 0x95;
//Rotate X
tanval = -(double)C4WFX2Val * PI * 2 / 128;
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
//Rotate Y
tanval = -(double)C4WFY2Val * PI * 2 / 128;
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
//Rotate Z
tanval = -(double)C4WFDist * PI * 2 / 128;
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
//Scale
C4WFXVal = (int16)(c4x * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
C4WFYVal = (int16)(c4y * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
}
void C4::C4CalcWireFrame() {
C4WFXVal = C4WFX2Val - C4WFXVal;
C4WFYVal = C4WFY2Val - C4WFYVal;
if(abs(C4WFXVal) > abs(C4WFYVal)) {
C4WFDist = abs(C4WFXVal) + 1;
C4WFYVal = (256 * (long)C4WFYVal) / abs(C4WFXVal);
C4WFXVal = (C4WFXVal < 0) ? -256 : 256;
} else if(C4WFYVal != 0) {
C4WFDist = abs(C4WFYVal) + 1;
C4WFXVal = (256 * (long)C4WFXVal) / abs(C4WFYVal);
C4WFYVal = (C4WFYVal < 0) ? -256 : 256;
} else {
C4WFDist = 0;
}
}
void C4::C4TransfWireFrame2() {
c4x = (double)C4WFXVal;
c4y = (double)C4WFYVal;
c4z = (double)C4WFZVal;
//Rotate X
tanval = -(double)C4WFX2Val * PI * 2 / 128;
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
//Rotate Y
tanval = -(double)C4WFY2Val * PI * 2 / 128;
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
//Rotate Z
tanval = -(double)C4WFDist * PI * 2 / 128;
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
//Scale
C4WFXVal = (int16)(c4x * C4WFScale / 0x100);
C4WFYVal = (int16)(c4y * C4WFScale / 0x100);
}
void C4::C4DrawWireFrame() {
uint32 line = readl(0x1f80);
uint32 point1, point2;
int16 X1, Y1, Z1;
int16 X2, Y2, Z2;
uint8 Color;
for(int32 i = ram[0x0295]; i > 0; i--, line += 5) {
if(r_mem->read(line) == 0xff && r_mem->read(line + 1) == 0xff) {
int32 tmp = line - 5;
while(r_mem->read(tmp + 2) == 0xff && r_mem->read(tmp + 3) == 0xff && (tmp + 2) >= 0) { tmp -= 5; }
point1 = (read(0x1f82) << 16) | (r_mem->read(tmp + 2) << 8) | r_mem->read(tmp + 3);
} else {
point1 = (read(0x1f82) << 16) | (r_mem->read(line) << 8) | r_mem->read(line + 1);
}
point2 = (read(0x1f82) << 16) | (r_mem->read(line + 2) << 8) | r_mem->read(line + 3);
X1=(r_mem->read(point1 + 0) << 8) | r_mem->read(point1 + 1);
Y1=(r_mem->read(point1 + 2) << 8) | r_mem->read(point1 + 3);
Z1=(r_mem->read(point1 + 4) << 8) | r_mem->read(point1 + 5);
X2=(r_mem->read(point2 + 0) << 8) | r_mem->read(point2 + 1);
Y2=(r_mem->read(point2 + 2) << 8) | r_mem->read(point2 + 3);
Z2=(r_mem->read(point2 + 4) << 8) | r_mem->read(point2 + 5);
Color = r_mem->read(line + 4);
C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color);
}
}
void C4::C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color) {
//Transform coordinates
C4WFXVal = (int16)X1;
C4WFYVal = (int16)Y1;
C4WFZVal = Z1;
C4WFScale = read(0x1f90);
C4WFX2Val = read(0x1f86);
C4WFY2Val = read(0x1f87);
C4WFDist = read(0x1f88);
C4TransfWireFrame2();
X1 = (C4WFXVal + 48) << 8;
Y1 = (C4WFYVal + 48) << 8;
C4WFXVal = (int16)X2;
C4WFYVal = (int16)Y2;
C4WFZVal = Z2;
C4TransfWireFrame2();
X2 = (C4WFXVal + 48) << 8;
Y2 = (C4WFYVal + 48) << 8;
//Get line info
C4WFXVal = (int16)(X1 >> 8);
C4WFYVal = (int16)(Y1 >> 8);
C4WFX2Val = (int16)(X2 >> 8);
C4WFY2Val = (int16)(Y2 >> 8);
C4CalcWireFrame();
X2 = (int16)C4WFXVal;
Y2 = (int16)C4WFYVal;
//Render line
for(int32 i = C4WFDist ? C4WFDist : 1; i > 0; i--) {
if(X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000) {
uint16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2;
uint8 bit = 0x80 >> ((X1 >> 8) & 7);
ram[addr + 0x300] &= ~bit;
ram[addr + 0x301] &= ~bit;
if(Color & 1) { ram[addr + 0x300] |= bit; }
if(Color & 2) { ram[addr + 0x301] |= bit; }
}
X1 += X2;
Y1 += Y2;
}
}
void C4::C4DoScaleRotate(int row_padding) {
int16 A, B, C, D;
//Calculate matrix
int32 XScale = readw(0x1f8f);
int32 YScale = readw(0x1f92);
if(XScale & 0x8000)XScale = 0x7fff;
if(YScale & 0x8000)YScale = 0x7fff;
if(readw(0x1f80) == 0) { //no rotation
A = (int16)XScale;
B = 0;
C = 0;
D = (int16)YScale;
} else if(readw(0x1f80) == 128) { //90 degree rotation
A = 0;
B = (int16)(-YScale);
C = (int16)XScale;
D = 0;
} else if(readw(0x1f80) == 256) { //180 degree rotation
A = (int16)(-XScale);
B = 0;
C = 0;
D = (int16)(-YScale);
} else if(readw(0x1f80) == 384) { //270 degree rotation
A = 0;
B = (int16)YScale;
C = (int16)(-XScale);
D = 0;
} else {
A = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * XScale, 15);
B = (int16)(-sar(SinTable[readw(0x1f80) & 0x1ff] * YScale, 15));
C = (int16) sar(SinTable[readw(0x1f80) & 0x1ff] * XScale, 15);
D = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * YScale, 15);
}
//Calculate Pixel Resolution
uint8 w = read(0x1f89) & ~7;
uint8 h = read(0x1f8c) & ~7;
//Clear the output RAM
memset(ram, 0, (w + row_padding / 4) * h / 2);
int32 Cx = (int16)readw(0x1f83);
int32 Cy = (int16)readw(0x1f86);
//Calculate start position (i.e. (Ox, Oy) = (0, 0))
//The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in
//the function. We do Cx*A etc normally because the matrix parameters
//already have the fractional parts.
int32 LineX = (Cx << 12) - Cx * A - Cx * B;
int32 LineY = (Cy << 12) - Cy * C - Cy * D;
//Start loop
uint32 X, Y;
uint8 byte;
int32 outidx = 0;
uint8 bit = 0x80;
for(int32 y = 0; y < h; y++) {
X = LineX;
Y = LineY;
for(int32 x = 0; x < w; x++) {
if((X >> 12) >= w || (Y >> 12) >= h) {
byte = 0;
} else {
uint32 addr = (Y >> 12) * w + (X >> 12);
byte = read(0x600 + (addr >> 1));
if(addr & 1) { byte >>= 4; }
}
//De-bitplanify
if(byte & 1) { ram[outidx ] |= bit; }
if(byte & 2) { ram[outidx + 1] |= bit; }
if(byte & 4) { ram[outidx + 16] |= bit; }
if(byte & 8) { ram[outidx + 17] |= bit; }
bit >>= 1;
if(!bit) {
bit = 0x80;
outidx += 32;
}
X += A; //Add 1 to output x => add an A and a C
Y += C;
}
outidx += 2 + row_padding;
if(outidx & 0x10) {
outidx &= ~0x10;
} else {
outidx -= w * 4 + row_padding;
}
LineX += B; //Add 1 to output y => add a B and a D
LineY += D;
}
}
+224
View File
@@ -0,0 +1,224 @@
//Build OAM
void C4::op00_00() {
uint32 oamptr = ram[0x626] << 2;
for(int32 i=0x1fd;i>oamptr && i>=0;i-=4) {
//clear oam-to-be
if(i >= 0)ram[i] = 0xe0;
}
uint16 globalx, globaly;
uint32 oamptr2;
int16 sprx, spry;
uint8 sprname, sprattr;
uint8 sprcount;
globalx = readw(0x621);
globaly = readw(0x623);
oamptr2 = 0x200 + (ram[0x626] >> 2);
if(!ram[0x620])return;
sprcount = 128 - ram[0x626];
uint8 offset = (ram[0x626] & 3) * 2;
for(int pri=0x30;pri>=0;pri-=0x10) {
uint32 srcptr = 0x220;
for(int i=ram[0x620];i>0 && sprcount>0;i--, srcptr+=16) {
if((ram[srcptr + 4] & 0x30) != pri)continue;
sprx = readw(srcptr) - globalx;
spry = readw(srcptr + 2) - globaly;
sprname = ram[srcptr + 5];
sprattr = ram[srcptr + 4] | ram[srcptr + 6];
uint32 spraddr = readl(srcptr + 7);
if(r_mem->read(spraddr)) {
int16 x, y;
for(int sprcnt=r_mem->read(spraddr++);sprcnt>0 && sprcount>0;sprcnt--, spraddr+=4) {
x = (int8)r_mem->read(spraddr + 1);
if(sprattr & 0x40) {
x = -x - ((r_mem->read(spraddr) & 0x20) ? 16 : 8);
}
x += sprx;
if(x >= -16 && x <= 272) {
y = (int8)r_mem->read(spraddr + 2);
if(sprattr & 0x80) {
y = -y - ((r_mem->read(spraddr) & 0x20) ? 16 : 8);
}
y += spry;
if(y >= -16 && y <= 224) {
ram[oamptr ] = (uint8)x;
ram[oamptr + 1] = (uint8)y;
ram[oamptr + 2] = sprname + r_mem->read(spraddr + 3);
ram[oamptr + 3] = sprattr ^ (r_mem->read(spraddr) & 0xc0);
ram[oamptr2] &= ~(3 << offset);
if(x & 0x100)ram[oamptr2] |= 1 << offset;
if(r_mem->read(spraddr) & 0x20)ram[oamptr2] |= 2 << offset;
oamptr += 4;
sprcount--;
offset = (offset + 2) & 6;
if(!offset)oamptr2++;
}
}
}
} else if(sprcount > 0) {
ram[oamptr ] = (uint8)sprx;
ram[oamptr + 1] = (uint8)spry;
ram[oamptr + 2] = sprname;
ram[oamptr + 3] = sprattr;
ram[oamptr2] &= ~(3 << offset);
if(sprx & 0x100)ram[oamptr2] |= 3 << offset;
else ram[oamptr2] |= 2 << offset;
oamptr += 4;
sprcount--;
offset = (offset + 2) & 6;
if(!offset)oamptr2++;
}
}
}
}
//Scale and Rotate
void C4::op00_03() {
C4DoScaleRotate(0);
}
//Transform Lines
void C4::op00_05() {
C4WFX2Val = read(0x1f83);
C4WFY2Val = read(0x1f86);
C4WFDist = read(0x1f89);
C4WFScale = read(0x1f8c);
//Transform Vertices
uint32 ptr = 0;
for(int32 i = readw(0x1f80); i > 0; i--, ptr += 0x10) {
C4WFXVal = readw(ptr + 1);
C4WFYVal = readw(ptr + 5);
C4WFZVal = readw(ptr + 9);
C4TransfWireFrame();
//Displace
writew(ptr + 1, C4WFXVal + 0x80);
writew(ptr + 5, C4WFYVal + 0x50);
}
writew(0x600, 23);
writew(0x602, 0x60);
writew(0x605, 0x40);
writew(0x600 + 8, 23);
writew(0x602 + 8, 0x60);
writew(0x605 + 8, 0x40);
ptr = 0xb02;
uint32 ptr2 = 0;
for(int32 i = readw(0xb00); i > 0; i--, ptr += 2, ptr2 += 8) {
C4WFXVal = readw((read(ptr + 0) << 4) + 1);
C4WFYVal = readw((read(ptr + 0) << 4) + 5);
C4WFX2Val = readw((read(ptr + 1) << 4) + 1);
C4WFY2Val = readw((read(ptr + 1) << 4) + 5);
C4CalcWireFrame();
writew(ptr2 + 0x600, C4WFDist ? C4WFDist : 1);
writew(ptr2 + 0x602, C4WFXVal);
writew(ptr2 + 0x605, C4WFYVal);
}
}
//Scale and Rotate
void C4::op00_07() {
C4DoScaleRotate(64);
}
//Draw Wireframe
void C4::op00_08() {
C4DrawWireFrame();
}
//Disintegrate
void C4::op00_0b() {
uint8 width, height;
uint32 startx, starty;
uint32 srcptr;
uint32 x, y;
int32 scalex, scaley;
int32 cx, cy;
int32 i, j;
width = read(0x1f89);
height = read(0x1f8c);
cx = readw(0x1f80);
cy = readw(0x1f83);
scalex = (int16)readw(0x1f86);
scaley = (int16)readw(0x1f8f);
startx = -cx * scalex + (cx << 8);
starty = -cy * scaley + (cy << 8);
srcptr = 0x600;
for(i = 0; i < (width * height) >> 1; i++) {
write(i, 0);
}
for(y = starty, i = 0;i < height; i++, y += scaley) {
for(x = startx, j = 0;j < width; j++, x += scalex) {
if((x >> 8) < width && (y >> 8) < height && (y >> 8) * width + (x >> 8) < 0x2000) {
uint8 pixel = (j & 1) ? (ram[srcptr] >> 4) : (ram[srcptr]);
int32 index = (y >> 11) * width * 4 + (x >> 11) * 32 + ((y >> 8) & 7) * 2;
uint8 mask = 0x80 >> ((x >> 8) & 7);
if(pixel & 1)ram[index ] |= mask;
if(pixel & 2)ram[index + 1] |= mask;
if(pixel & 4)ram[index + 16] |= mask;
if(pixel & 8)ram[index + 17] |= mask;
}
if(j & 1)srcptr++;
}
}
}
//Bitplane Wave
void C4::op00_0c() {
uint32 destptr = 0;
uint32 waveptr = read(0x1f83);
uint16 mask1 = 0xc0c0;
uint16 mask2 = 0x3f3f;
int32 i, j;
int16 height, temp;
for(j = 0; j < 0x10; j++) {
do {
height = -((int8)ram[waveptr + 0xb00]) - 16;
for(i = 0; i < 40; i++) {
temp = readw(destptr + wave_data[i]) & mask2;
if(height >= 0) {
if(height < 8) {
temp |= mask1 & readw(0xa00 + height * 2);
} else {
temp |= mask1 & 0xff00;
}
}
writew(destptr + wave_data[i], temp);
height++;
}
waveptr = (waveptr + 1) & 0x7f;
mask1 = (mask1 >> 2) | (mask1 << 6);
mask2 = (mask2 >> 2) | (mask2 << 6);
} while(mask1 != 0xc0c0);
destptr += 16;
do {
height = -((int8)ram[waveptr + 0xb00]) - 16;
for(i = 0; i < 40; i++) {
temp = readw(destptr + wave_data[i]) & mask2;
if(height >= 0) {
if(height < 8) {
temp |= mask1 & readw(0xa10 + height * 2);
} else {
temp |= mask1 & 0xff00;
}
writew(destptr + wave_data[i], temp);
height++;
}
waveptr = (waveptr + 1) & 0x7f;
mask1 = (mask1 >> 2) | (mask1 << 6);
mask2 = (mask2 >> 2) | (mask2 << 6);
}
} while(mask1 != 0xc0c0);
destptr += 16;
}
}
+222
View File
@@ -0,0 +1,222 @@
//Sprite Functions
void C4::op00() {
switch(reg[0x4d]) {
case 0x00:op00_00();break;
case 0x03:op00_03();break;
case 0x05:op00_05();break;
case 0x07:op00_07();break;
case 0x08:op00_08();break;
case 0x0b:op00_0b();break;
case 0x0c:op00_0c();break;
}
}
//Draw Wireframe
void C4::op01() {
memset(ram + 0x300, 0, 2304);
C4DrawWireFrame();
}
//Propulsion
void C4::op05() {
int32 temp = 0x10000;
if(readw(0x1f83)) {
temp = sar((temp / readw(0x1f83)) * readw(0x1f81), 8);
}
writew(0x1f80, temp);
}
//Set Vector length
void C4::op0d() {
C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83);
C41FDistVal = readw(0x1f86);
tanval = sqrt(((double)C41FYVal) * ((double)C41FYVal) + ((double)C41FXVal) * ((double)C41FXVal));
tanval = (double)C41FDistVal / tanval;
C41FYVal = (int16)(((double)C41FYVal * tanval) * 0.99);
C41FXVal = (int16)(((double)C41FXVal * tanval) * 0.98);
writew(0x1f89, C41FXVal);
writew(0x1f8c, C41FYVal);
}
//Triangle
void C4::op10() {
r0 = ldr(0);
r1 = ldr(1);
r4 = r0 & 0x1ff;
if(r1 & 0x8000)r1 |= ~0x7fff;
mul(cos(r4), r1, r5, r2);
r5 = (r5 >> 16) & 0xff;
r2 = (r2 << 8) + r5;
mul(sin(r4), r1, r5, r3);
r5 = (r5 >> 16) & 0xff;
r3 = (r3 << 8) + r5;
str(0, r0);
str(1, r1);
str(2, r2);
str(3, r3);
str(4, r4);
str(5, r5);
}
//Triangle
void C4::op13() {
r0 = ldr(0);
r1 = ldr(1);
r4 = r0 & 0x1ff;
mul(cos(r4), r1, r5, r2);
r5 = (r5 >> 8) & 0xffff;
r2 = (r2 << 16) + r5;
mul(sin(r4), r1, r5, r3);
r5 = (r5 >> 8) & 0xffff;
r3 = (r3 << 16) + r5;
str(0, r0);
str(1, r1);
str(2, r2);
str(3, r3);
str(4, r4);
str(5, r5);
}
//Pythagorean
void C4::op15() {
C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83);
C41FDist = (int16)sqrt((double)C41FXVal * (double)C41FXVal + (double)C41FYVal * (double)C41FYVal);
writew(0x1f80, C41FDist);
}
//Calculate distance
void C4::op1f() {
C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83);
if(!C41FXVal) {
C41FAngleRes = (C41FYVal > 0) ? 0x080 : 0x180;
} else {
tanval = ((double)C41FYVal) / ((double)C41FXVal);
C41FAngleRes = (short)(atan(tanval) / (PI * 2) * 512);
C41FAngleRes = C41FAngleRes;
if(C41FXVal < 0) {
C41FAngleRes += 0x100;
}
C41FAngleRes &= 0x1ff;
}
writew(0x1f86, C41FAngleRes);
}
//Trapezoid
void C4::op22() {
int16 angle1 = readw(0x1f8c) & 0x1ff;
int16 angle2 = readw(0x1f8f) & 0x1ff;
int32 tan1 = Tan(angle1);
int32 tan2 = Tan(angle2);
int16 y = readw(0x1f83) - readw(0x1f89);
int16 left, right;
for(int32 j = 0; j < 225; j++, y++) {
if(y >= 0) {
left = sar((int32)tan1 * y, 16) - readw(0x1f80) + readw(0x1f86);
right = sar((int32)tan2 * y, 16) - readw(0x1f80) + readw(0x1f86) + readw(0x1f93);
if(left < 0 && right < 0) {
left = 1;
right = 0;
} else if(left < 0) {
left = 0;
} else if(right < 0) {
right = 0;
}
if(left > 255 && right > 255) {
left = 255;
right = 254;
} else if(left > 255) {
left = 255;
} else if(right > 255) {
right = 255;
}
} else {
left = 1;
right = 0;
}
ram[j + 0x800] = (uint8)left;
ram[j + 0x900] = (uint8)right;
}
}
//Multiply
void C4::op25() {
r0 = ldr(0);
r1 = ldr(1);
mul(r0, r1, r0, r1);
str(0, r0);
str(1, r1);
}
//Transform Coords
void C4::op2d() {
C4WFXVal = readw(0x1f81);
C4WFYVal = readw(0x1f84);
C4WFZVal = readw(0x1f87);
C4WFX2Val = read (0x1f89);
C4WFY2Val = read (0x1f8a);
C4WFDist = read (0x1f8b);
C4WFScale = readw(0x1f90);
C4TransfWireFrame2();
writew(0x1f80, C4WFXVal);
writew(0x1f83, C4WFYVal);
}
//Sum
void C4::op40() {
r0 = 0;
for(uint32 i=0;i<0x800;i++) {
r0 += ram[i];
}
str(0, r0);
}
//Square
void C4::op54() {
r0 = ldr(0);
mul(r0, r0, r1, r2);
str(1, r1);
str(2, r2);
}
//Immediate Register
void C4::op5c() {
str(0, 0x000000);
immediate_reg(0);
}
//Immediate Register (Multiple)
void C4::op5e() { immediate_reg( 0); }
void C4::op60() { immediate_reg( 3); }
void C4::op62() { immediate_reg( 6); }
void C4::op64() { immediate_reg( 9); }
void C4::op66() { immediate_reg(12); }
void C4::op68() { immediate_reg(15); }
void C4::op6a() { immediate_reg(18); }
void C4::op6c() { immediate_reg(21); }
void C4::op6e() { immediate_reg(24); }
void C4::op70() { immediate_reg(27); }
void C4::op72() { immediate_reg(30); }
void C4::op74() { immediate_reg(33); }
void C4::op76() { immediate_reg(36); }
void C4::op78() { immediate_reg(39); }
void C4::op7a() { immediate_reg(42); }
void C4::op7c() { immediate_reg(45); }
//Immediate ROM
void C4::op89() {
str(0, 0x054336);
str(1, 0xffffff);
}
+102
View File
@@ -0,0 +1,102 @@
#include "../../base.h"
#include "sdd1emu.cpp"
void SDD1::init() {}
void SDD1::enable() {
for(int i=0x4800;i<=0x4807;i++) {
r_mem->set_mmio_mapper(i, mmio);
}
}
void SDD1::power() {
reset();
}
void SDD1::reset() {
sdd1.index[0] = 0x000000;
sdd1.index[1] = 0x100000;
sdd1.index[2] = 0x200000;
sdd1.index[3] = 0x300000;
for(int i=0;i<8;i++) {
sdd1.active[i] = false;
}
sdd1.dma_active = false;
}
uint32 SDD1::offset(uint32 addr) {
uint8 b = (addr >> 16) & 0xff;
if(b <= 0xbf)return 0;
b -= 0xc0; //b = 0x00-0x3f
b >>= 4; //b = 0-3
b &= 3; //bitmask
return sdd1.index[b] + (addr & 0x0fffff);
}
uint8 SDD1::mmio_read(uint16 addr) {
switch(addr) {
//>>20 == 0x100000 == 1mb
case 0x4804:return (sdd1.index[0] >> 20) & 7;
case 0x4805:return (sdd1.index[1] >> 20) & 7;
case 0x4806:return (sdd1.index[2] >> 20) & 7;
case 0x4807:return (sdd1.index[3] >> 20) & 7;
}
return r_cpu->regs.mdr;
}
void SDD1::mmio_write(uint16 addr, uint8 data) {
int i;
switch(addr) {
case 0x4801:
for(i=0;i<8;i++) {
sdd1.active[i] = !!(data & (1 << i));
}
break;
//<<20 == 0x100000 == 1mb
case 0x4804:sdd1.index[0] = (data & 7) << 20;break;
case 0x4805:sdd1.index[1] = (data & 7) << 20;break;
case 0x4806:sdd1.index[2] = (data & 7) << 20;break;
case 0x4807:sdd1.index[3] = (data & 7) << 20;break;
}
}
void SDD1::dma_begin(uint8 channel, uint32 addr, uint16 length) {
if(sdd1.active[channel] == true) {
sdd1.active[channel] = false;
sdd1.dma_active = true;
sdd1.buffer_index = 0;
sdd1.buffer_size = length;
sdd1emu.decompress(addr, (length) ? length : 65536, sdd1.buffer);
}
}
bool SDD1::dma_active() {
return sdd1.dma_active;
}
uint8 SDD1::dma_read() {
if(--sdd1.buffer_size == 0) {
sdd1.dma_active = false;
}
//sdd1.buffer[] is 65536 bytes, and sdd1.buffer_index
//is of type uint16, so no buffer overflow is possible
return sdd1.buffer[sdd1.buffer_index++];
}
SDD1::SDD1() {
mmio = new SDD1MMIO();
}
uint8 SDD1MMIO::read(uint32 addr) {
return sdd1->mmio_read(addr);
}
void SDD1MMIO::write(uint32 addr, uint8 value) {
sdd1->mmio_write(addr, value);
}
+37
View File
@@ -0,0 +1,37 @@
#include "sdd1emu.h"
class SDD1MMIO : public MMIO {
public:
inline uint8 read (uint32 addr);
inline void write(uint32 addr, uint8 value);
};
class SDD1 {
public:
SDD1emu sdd1emu;
SDD1MMIO *mmio;
struct {
uint32 index[4]; //memory mapping registers
uint8 buffer[65536]; //pointer to decompressed S-DD1 data,
//max. DMA length is 65536
uint16 buffer_index; //DMA read index into S-DD1 decompression buffer
uint16 buffer_size;
bool active[8]; //true when DMA channel should pass through S-DD1
bool dma_active;
}sdd1;
void init();
void enable();
void power();
void reset();
uint32 offset(uint32 addr);
void dma_begin(uint8 channel, uint32 addr, uint16 length);
bool dma_active();
uint8 dma_read();
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
SDD1();
};
+447
View File
@@ -0,0 +1,447 @@
/************************************************************************
S-DD1'algorithm emulation code
------------------------------
Author: Andreas Naive
Date: August 2003
Last update: October 2004
This code is Public Domain. There is no copyright holded by the author.
Said this, the author wish to explicitly emphasize his inalienable moral rights
over this piece of intelectual work and the previous research that made it
possible, as recognized by most of the copyright laws around the world.
This code is provided 'as-is', with no warranty, expressed or implied.
No responsability is assumed by the author in connection with it.
The author is greatly indebted with The Dumper, without whose help and
patience providing him with real S-DD1 data the research would have never been
possible. He also wish to note that in the very beggining of his research,
Neviksti had done some steps in the right direction. By last, the author is
indirectly indebted to all the people that worked and contributed in the
S-DD1 issue in the past.
An algorithm's documentation is available as a separate document.
The implementation is obvious when the algorithm is
understood.
************************************************************************/
#define SDD1_read(__addr) (r_mem->read(__addr))
////////////////////////////////////////////////////
void SDD1_IM::prepareDecomp(uint32 in_buf) {
byte_ptr=in_buf;
bit_count=4;
}
////////////////////////////////////////////////////
uint8 SDD1_IM::getCodeword(uint8 code_len) {
uint8 codeword;
uint8 comp_count;
codeword = (SDD1_read(byte_ptr))<<bit_count;
++bit_count;
if (codeword & 0x80) {
codeword |= SDD1_read(byte_ptr+1)>>(9-bit_count);
bit_count+=code_len;
}
if (bit_count & 0x08) {
byte_ptr++;
bit_count&=0x07;
}
return codeword;
}
//////////////////////////////////////////////////////
SDD1_GCD::SDD1_GCD(SDD1_IM *associatedIM) :
IM(associatedIM)
{
}
//////////////////////////////////////////////////////
void SDD1_GCD::getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind) {
const uint8 run_count[] = {
0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00,
0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00,
0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01,
0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00,
0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03,
0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01,
0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02,
0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00,
0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07,
0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03,
0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05,
0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01,
0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06,
0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02,
0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04,
0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00,
0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f,
0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07,
0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b,
0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03,
0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d,
0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05,
0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09,
0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01,
0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e,
0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06,
0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a,
0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02,
0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c,
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04,
0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00,
};
uint8 codeword=IM->getCodeword(code_num);
if (codeword & 0x80) {
*LPSind=1;
*MPScount=run_count[codeword>>(code_num^0x07)];
}
else {
*MPScount=(1<<code_num);
}
}
///////////////////////////////////////////////////////
SDD1_BG::SDD1_BG(SDD1_GCD *associatedGCD, uint8 code) :
GCD(associatedGCD), code_num(code)
{
}
///////////////////////////////////////////////
void SDD1_BG::prepareDecomp(void) {
MPScount=0;
LPSind=0;
}
//////////////////////////////////////////////
uint8 SDD1_BG::getBit(bool8 *endOfRun) {
uint8 bit;
if (!(MPScount || LPSind)) GCD->getRunCount(code_num, &MPScount, &LPSind);
if (MPScount) {
bit=0;
MPScount--;
}
else {
bit=1;
LPSind=0;
}
if (MPScount || LPSind) (*endOfRun)=0;
else (*endOfRun)=1;
return bit;
}
/////////////////////////////////////////////////
SDD1_PEM::SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7) {
BG[0]=associatedBG0;
BG[1]=associatedBG1;
BG[2]=associatedBG2;
BG[3]=associatedBG3;
BG[4]=associatedBG4;
BG[5]=associatedBG5;
BG[6]=associatedBG6;
BG[7]=associatedBG7;
}
/////////////////////////////////////////////////////////
const SDD1_PEM::state SDD1_PEM::evolution_table[]={
{ 0,25,25},
{ 0, 2, 1},
{ 0, 3, 1},
{ 0, 4, 2},
{ 0, 5, 3},
{ 1, 6, 4},
{ 1, 7, 5},
{ 1, 8, 6},
{ 1, 9, 7},
{ 2,10, 8},
{ 2,11, 9},
{ 2,12,10},
{ 2,13,11},
{ 3,14,12},
{ 3,15,13},
{ 3,16,14},
{ 3,17,15},
{ 4,18,16},
{ 4,19,17},
{ 5,20,18},
{ 5,21,19},
{ 6,22,20},
{ 6,23,21},
{ 7,24,22},
{ 7,24,23},
{ 0,26, 1},
{ 1,27, 2},
{ 2,28, 4},
{ 3,29, 8},
{ 4,30,12},
{ 5,31,16},
{ 6,32,18},
{ 7,24,22}
};
//////////////////////////////////////////////////////
void SDD1_PEM::prepareDecomp(void) {
for (uint8 i=0; i<32; i++) {
contextInfo[i].status=0;
contextInfo[i].MPS=0;
}
}
/////////////////////////////////////////////////////////
uint8 SDD1_PEM::getBit(uint8 context) {
bool8 endOfRun;
uint8 bit;
SDD1_ContextInfo *pContInfo=&contextInfo[context];
uint8 currStatus = pContInfo->status;
const state *pState=&SDD1_PEM::evolution_table[currStatus];
uint8 currentMPS=pContInfo->MPS;
bit=(BG[pState->code_num])->getBit(&endOfRun);
if (endOfRun)
if (bit) {
if (!(currStatus & 0xfe)) (pContInfo->MPS)^=0x01;
(pContInfo->status)=pState->nextIfLPS;
}
else
(pContInfo->status)=pState->nextIfMPS;
return bit^currentMPS;
}
//////////////////////////////////////////////////////////////
SDD1_CM::SDD1_CM(SDD1_PEM *associatedPEM) :
PEM(associatedPEM)
{
}
//////////////////////////////////////////////////////////////
void SDD1_CM::prepareDecomp(uint32 first_byte) {
bitplanesInfo = SDD1_read(first_byte) & 0xc0;
contextBitsInfo = SDD1_read(first_byte) & 0x30;
bit_number=0;
for (int i=0; i<8; i++) prevBitplaneBits[i]=0;
switch (bitplanesInfo) {
case 0x00:
currBitplane = 1;
break;
case 0x40:
currBitplane = 7;
break;
case 0x80:
currBitplane = 3;
}
}
/////////////////////////////////////////////////////////////
uint8 SDD1_CM::getBit(void) {
uint8 currContext;
uint16 *context_bits;
switch (bitplanesInfo) {
case 0x00:
currBitplane ^= 0x01;
break;
case 0x40:
currBitplane ^= 0x01;
if (!(bit_number & 0x7f)) currBitplane = ((currBitplane+2) & 0x07);
break;
case 0x80:
currBitplane ^= 0x01;
if (!(bit_number & 0x7f)) currBitplane ^= 0x02;
break;
case 0xc0:
currBitplane = bit_number & 0x07;
}
context_bits = &prevBitplaneBits[currBitplane];
currContext=(currBitplane & 0x01)<<4;
switch (contextBitsInfo) {
case 0x00:
currContext|=((*context_bits & 0x01c0)>>5)|(*context_bits & 0x0001);
break;
case 0x10:
currContext|=((*context_bits & 0x0180)>>5)|(*context_bits & 0x0001);
break;
case 0x20:
currContext|=((*context_bits & 0x00c0)>>5)|(*context_bits & 0x0001);
break;
case 0x30:
currContext|=((*context_bits & 0x0180)>>5)|(*context_bits & 0x0003);
}
uint8 bit=PEM->getBit(currContext);
*context_bits <<= 1;
*context_bits |= bit;
bit_number++;
return bit;
}
//////////////////////////////////////////////////
SDD1_OL::SDD1_OL(SDD1_CM *associatedCM) :
CM(associatedCM)
{
}
///////////////////////////////////////////////////
void SDD1_OL::prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf) {
bitplanesInfo = SDD1_read(first_byte) & 0xc0;
length=out_len;
buffer=out_buf;
}
///////////////////////////////////////////////////
void SDD1_OL::launch(void) {
uint8 i;
uint8 register1, register2;
switch (bitplanesInfo) {
case 0x00:
case 0x40:
case 0x80:
i=1;
do { //if length==0, we output 2^16 bytes
if (!i) {
*(buffer++)=register2;
i=~i;
}
else {
for (register1=register2=0, i=0x80; i; i>>=1) {
if (CM->getBit()) register1 |= i;
if (CM->getBit()) register2 |= i;
}
*(buffer++)=register1;
}
} while (--length);
break;
case 0xc0:
do {
for (register1=0, i=0x01; i; i<<=1) {
if (CM->getBit()) register1 |= i;
}
*(buffer++)=register1;
} while (--length);
}
}
///////////////////////////////////////////////////////
void SDD1emu::decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf) {
IM.prepareDecomp(in_buf);
BG0.prepareDecomp();
BG1.prepareDecomp();
BG2.prepareDecomp();
BG3.prepareDecomp();
BG4.prepareDecomp();
BG5.prepareDecomp();
BG6.prepareDecomp();
BG7.prepareDecomp();
PEM.prepareDecomp();
CM.prepareDecomp(in_buf);
OL.prepareDecomp(in_buf, out_len, out_buf);
OL.launch();
}
////////////////////////////////////////////////////////////
SDD1emu::SDD1emu() :
GCD(&IM),
BG0(&GCD, 0), BG1(&GCD, 1), BG2(&GCD, 2), BG3(&GCD, 3),
BG4(&GCD, 4), BG5(&GCD, 5), BG6(&GCD, 6), BG7(&GCD, 7),
PEM(&BG0, &BG1, &BG2, &BG3, &BG4, &BG5, &BG6, &BG7),
CM(&PEM),
OL(&CM)
{
}
///////////////////////////////////////////////////////////
+161
View File
@@ -0,0 +1,161 @@
/************************************************************************
S-DD1'algorithm emulation code
------------------------------
Author: Andreas Naive
Date: August 2003
Last update: October 2004
This code is Public Domain. There is no copyright holded by the author.
Said this, the author wish to explicitly emphasize his inalienable moral rights
over this piece of intelectual work and the previous research that made it
possible, as recognized by most of the copyright laws around the world.
This code is provided 'as-is', with no warranty, expressed or implied.
No responsability is assumed by the author in connection with it.
The author is greatly indebted with The Dumper, without whose help and
patience providing him with real S-DD1 data the research would have never been
possible. He also wish to note that in the very beggining of his research,
Neviksti had done some steps in the right direction. By last, the author is
indirectly indebted to all the people that worked and contributed in the
S-DD1 issue in the past.
An algorithm's documentation is available as a separate document.
The implementation is obvious when the algorithm is
understood.
************************************************************************/
class SDD1_IM { //Input Manager
public:
SDD1_IM(void) {}
void prepareDecomp(uint32 in_buf);
uint8 getCodeword(const uint8 code_len);
private:
uint32 byte_ptr;
uint8 bit_count;
};
////////////////////////////////////////////////////
class SDD1_GCD { //Golomb-Code Decoder
public:
SDD1_GCD(SDD1_IM *associatedIM);
void getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind);
private:
SDD1_IM *const IM;
};
//////////////////////////////////////////////////////
class SDD1_BG { // Bits Generator
public:
SDD1_BG(SDD1_GCD *associatedGCD, uint8 code);
void prepareDecomp(void);
uint8 getBit(bool8 *endOfRun);
private:
const uint8 code_num;
uint8 MPScount;
bool8 LPSind;
SDD1_GCD *const GCD;
};
////////////////////////////////////////////////
class SDD1_PEM { //Probability Estimation Module
public:
SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7);
void prepareDecomp(void);
uint8 getBit(uint8 context);
private:
struct state {
uint8 code_num;
uint8 nextIfMPS;
uint8 nextIfLPS;
};
static const state evolution_table[];
struct SDD1_ContextInfo {
uint8 status;
uint8 MPS;
} contextInfo[32];
SDD1_BG * BG[8];
};
///////////////////////////////////////////////////
class SDD1_CM { //Context Model
public:
SDD1_CM(SDD1_PEM *associatedPEM);
void prepareDecomp(uint32 first_byte);
uint8 getBit(void);
private:
uint8 bitplanesInfo;
uint8 contextBitsInfo;
uint8 bit_number;
uint8 currBitplane;
uint16 prevBitplaneBits[8];
SDD1_PEM *const PEM;
};
///////////////////////////////////////////////////
class SDD1_OL { //Output Logic
public:
SDD1_OL(SDD1_CM *associatedCM);
void prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf);
void launch(void);
private:
uint8 bitplanesInfo;
uint16 length;
uint8 *buffer;
SDD1_CM *const CM;
};
/////////////////////////////////////////////////////////
class SDD1emu {
public:
SDD1emu(void);
void decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf);
private:
SDD1_IM IM;
SDD1_GCD GCD;
SDD1_BG BG0; SDD1_BG BG1; SDD1_BG BG2; SDD1_BG BG3;
SDD1_BG BG4; SDD1_BG BG5; SDD1_BG BG6; SDD1_BG BG7;
SDD1_PEM PEM;
SDD1_CM CM;
SDD1_OL OL;
};
@@ -50,7 +50,9 @@
whenever the RTC is set.
*/
void bCPU::srtc_set_time() {
#include "../../base.h"
void SRTC::set_time() {
time_t rawtime;
tm *t;
::time(&rawtime);
@@ -72,12 +74,19 @@ tm *t;
srtc.data[12] = t->tm_wday;
}
void bCPU::srtc_power() {
void SRTC::init() {}
void SRTC::enable() {
r_mem->set_mmio_mapper(0x2800, mmio);
r_mem->set_mmio_mapper(0x2801, mmio);
}
void SRTC::power() {
memset(&srtc, 0, sizeof(srtc));
reset();
}
void bCPU::srtc_reset() {
void SRTC::reset() {
srtc.index = -1;
srtc.mode = SRTC_READ;
}
@@ -87,7 +96,7 @@ void bCPU::srtc_reset() {
//as reads will refresh the data array with the current system
//time. The write method is only here for the sake of faux
//emulation of the real hardware.
void bCPU::srtc_write(uint8 data) {
void SRTC::write(uint8 data) {
data &= 0x0f; //only the low four bits are used
if(data >= 0x0d) {
@@ -140,10 +149,10 @@ void bCPU::srtc_write(uint8 data) {
}
}
uint8 bCPU::srtc_read() {
uint8 SRTC::read() {
if(srtc.mode == SRTC_READ) {
if(srtc.index < 0) {
srtc_set_time();
set_time();
srtc.index++;
return 0x0f; //send start message
} else if(srtc.index > MAX_SRTC_INDEX) {
@@ -156,3 +165,21 @@ uint8 bCPU::srtc_read() {
return 0x00;
}
}
SRTC::SRTC() {
mmio = new SRTCMMIO();
}
uint8 SRTCMMIO::read(uint32 addr) {
switch(addr) {
case 0x2800:return srtc->read();
}
return r_cpu->regs.mdr;
}
void SRTCMMIO::write(uint32 addr, uint8 value) {
switch(addr) {
case 0x2801:srtc->write(value);break;
}
}
+24 -15
View File
@@ -1,10 +1,12 @@
void srtc_set_time();
void srtc_power();
void srtc_reset();
void srtc_write(uint8 data);
uint8 srtc_read();
class SRTCMMIO : public MMIO {
public:
inline uint8 read (uint32 addr);
inline void write(uint32 addr, uint8 value);
};
#define MAX_SRTC_INDEX 0x0c
class SRTC {
public:
enum { MAX_SRTC_INDEX = 0x0c };
enum {
SRTC_READ = 0,
@@ -18,9 +20,7 @@ enum {
SRTC_COMMAND_CLEAR = 4
};
#define DAYTICKS (60*60*24)
#define HOURTICKS (60*60)
#define MINUTETICKS (60)
SRTCMMIO *mmio;
/******************************
[srtc.data structure]
@@ -38,11 +38,20 @@ Index Description Range
9 Year ones 0-9
10 Year tens 0-9
11 Year hundreds 9-11 (9=19xx, 10=20xx, 11=21xx)
12 Day of week 0-6 (0=Sunday, ...)
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);
uint8 read();
SRTC();
};
+44
View File
@@ -0,0 +1,44 @@
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",
false, Setting::TRUE_FALSE);
//do not save these settings to config_file
Setting CPU::hdma_enable(0, "cpu.hdma_enable", "Enable HDMA effects", true, Setting::TRUE_FALSE);
Setting PPU::opt_enable(0, "ppu.opt_enable", "Enable offset-per-tile effects", true, Setting::TRUE_FALSE);
Setting PPU::bg1_pri0_enable(0, "ppu.bg1_pri0_enable", "Enable BG1 Priority 0", true, Setting::TRUE_FALSE);
Setting PPU::bg1_pri1_enable(0, "ppu.bg1_pri1_enable", "Enable BG1 Priority 1", true, Setting::TRUE_FALSE);
Setting PPU::bg2_pri0_enable(0, "ppu.bg2_pri0_enable", "Enable BG2 Priority 0", true, Setting::TRUE_FALSE);
Setting PPU::bg2_pri1_enable(0, "ppu.bg2_pri1_enable", "Enable BG2 Priority 1", true, Setting::TRUE_FALSE);
Setting PPU::bg3_pri0_enable(0, "ppu.bg3_pri0_enable", "Enable BG3 Priority 0", true, Setting::TRUE_FALSE);
Setting PPU::bg3_pri1_enable(0, "ppu.bg3_pri1_enable", "Enable BG3 Priority 1", true, Setting::TRUE_FALSE);
Setting PPU::bg4_pri0_enable(0, "ppu.bg4_pri0_enable", "Enable BG4 Priority 0", true, Setting::TRUE_FALSE);
Setting PPU::bg4_pri1_enable(0, "ppu.bg4_pri1_enable", "Enable BG4 Priority 1", true, Setting::TRUE_FALSE);
Setting PPU::oam_pri0_enable(0, "ppu.oam_pri0_enable", "Enable OAM Priority 0", true, Setting::TRUE_FALSE);
Setting PPU::oam_pri1_enable(0, "ppu.oam_pri1_enable", "Enable OAM Priority 1", true, Setting::TRUE_FALSE);
Setting PPU::oam_pri2_enable(0, "ppu.oam_pri2_enable", "Enable OAM Priority 2", true, Setting::TRUE_FALSE);
Setting PPU::oam_pri3_enable(0, "ppu.oam_pri3_enable", "Enable OAM Priority 3", true, Setting::TRUE_FALSE);
};
+30
View File
@@ -0,0 +1,30 @@
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;
extern struct CPU {
static Setting hdma_enable;
} cpu;
extern struct PPU {
static Setting opt_enable;
static Setting bg1_pri0_enable, bg1_pri1_enable;
static Setting bg2_pri0_enable, bg2_pri1_enable;
static Setting bg3_pri0_enable, bg3_pri1_enable;
static Setting bg4_pri0_enable, bg4_pri1_enable;
static Setting oam_pri0_enable, oam_pri1_enable;
static Setting oam_pri2_enable, oam_pri3_enable;
} ppu;
};
+82 -184
View File
@@ -1,7 +1,5 @@
#include "../../base.h"
#include "srtc.cpp"
#include "bcpu_opfn.cpp"
#include "bcpu_op_read.cpp"
#include "bcpu_op_rmw.cpp"
@@ -15,172 +13,70 @@
#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);
}
bool bCPU::hdma_test() {
if(status.hdma_triggered == false) {
if(vcounter() < (overscan()?239:224) && hcounter() >= 278) {
status.hdma_triggered = true;
return true;
}
}
return false;
}
bool bCPU::nmi_test() {
if(vcounter() >= ((overscan()?239:224) + 1) && status.nmi_triggered == false) {
if((vcounter() == ((overscan()?239:224) + 1) && hcycles() >= 12) || (vcounter() > ((overscan()?239:224) + 1))) {
status.nmi_triggered = true;
status.nmi_pin = 0;
if(status.nmi_enabled == true) {
return true;
}
}
}
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_pin == 0)return false; //same as above
if(status.virq_enabled == false && status.hirq_enabled == false)return false;
//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
if(vpos == 261 && hpos == 339 && interlace() == false)return false;
if(vpos == 262 && interlace() == false)return false;
if(vpos == 262 && hpos == 339)return false;
if(vpos > 262)return false;
if(hpos > 339)return false;
if(hpos == 0) {
hpos = 24;
} else {
hpos <<= 2;
hpos += 24; //30 - status.cycle_count;
//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_pin == 1) {
//dprintf("* vpos=%3d,hpos=%4d; v=%3d,h=%4d; lc=%d,virq=%3d,hirq=%3d",
// vpos, hpos, vcounter(), hcycles(), status.cycle_count, status.virq_pos, status.hirq_pos);
status.irq_triggered = true;
status.irq_pin = 0;
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(nmi_test() == true) {
irq(0xffea);
break;
}
if(irq_test() == true) {
irq(0xffee);
break;
}
exec_opcode();
break;
case CPUSTATE_STP:
exec_opcode();
break;
if(run_state.hdma) {
exec_hdma();
return;
}
if(run_state.dma) {
exec_dma();
return;
}
if(status.cycle_pos == 0) {
//interrupts only trigger on opcode edges
if(!run_state.irq && !run_state.stp) {
if(time.nmi_pending == true) {
time.nmi_pending = false;
aa.w = 0xffea;
run_state.irq = true;
} else if(time.irq_pending == true) {
time.irq_pending = false;
aa.w = 0xffee;
run_state.irq = true;
}
}
}
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_pin = 1;
status.joypad2_read_pos = 16;
}
}
void bCPU::frame() {
hdma_initialize();
time.nmi_read = 1;
time.nmi_line = 1;
time.nmi_transition = 0;
status.nmi_triggered = false;
status.nmi_pin = 1;
status.r4210_read = false;
status.irq_triggered = false;
status.irq_pin = 1;
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() {
srtc_power();
region = snes->region();
regs.a = regs.x = regs.y = 0x0000;
regs.s = 0x01ff;
@@ -188,12 +84,8 @@ void bCPU::power() {
}
void bCPU::reset() {
srtc_reset();
frame();
//reset vector location
regs.pc = mem_bus->read(0xfffc) | (mem_bus->read(0xfffd) << 8);
regs.pc = r_mem->read(0xfffc) | (r_mem->read(0xfffd) << 8);
//registers are not fully reset by SNES
regs.x.h = 0x00;
@@ -203,26 +95,33 @@ void bCPU::reset() {
regs.db = 0x00;
regs.p = 0x34;
regs.e = 1;
regs.mdr = 0x00;
time_reset();
mmio_reset();
dma_reset();
status.cpu_state = CPUSTATE_RUN;
run_state.hdma = false;
run_state.dma = false;
run_state.irq = false;
run_state.wai = false;
run_state.stp = false;
status.hdma_triggered = false;
status.nmi_triggered = false;
status.nmi_pin = 1;
status.r4210_read = false;
status.irq_triggered = false;
status.irq_pin = 1;
status.cycle_pos = 0;
status.cycle_count = 0;
status.cycles_executed = 0;
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) {
@@ -235,50 +134,52 @@ void bCPU::port_write(uint8 port, uint8 value) {
void bCPU::cpu_c2() {
if(regs.d.l != 0x00) {
status.cycle_count = 6;
cycle_edge();
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;
cycle_edge();
add_cycles(6);
cpu_io();
}
}
void bCPU::cpu_c6(uint16 addr) {
if(regs.e && (regs.pc.w & 0xff00) != (addr & 0xff00)) {
status.cycle_count = 6;
cycle_edge();
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;
cycle_edge();
pre_exec_cycle();
add_cycles(6);
cycle_edge();
}
uint8 bCPU::mem_read(uint32 addr) {
uint8 r;
status.cycle_count = mem_bus->speed(addr);
status.cycle_count = r_mem->speed(addr);
pre_exec_cycle();
add_cycles(status.cycle_count - 4);
regs.mdr = r_mem->read(addr);
add_cycles(4);
cycle_edge();
add_cycles(2);
r = mem_bus->read(addr);
add_cycles(status.cycle_count - 2);
return r;
return regs.mdr;
}
void bCPU::mem_write(uint32 addr, uint8 value) {
status.cycle_count = mem_bus->speed(addr);
status.cycle_count = r_mem->speed(addr);
pre_exec_cycle();
add_cycles(status.cycle_count);
r_mem->write(addr, value);
cycle_edge();
add_cycles(6);
mem_bus->write(addr, value);
add_cycles(status.cycle_count - 6);
}
uint32 bCPU::op_addr(uint8 mode, uint32 addr) {
@@ -290,12 +191,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;
@@ -345,9 +245,7 @@ void bCPU::stack_write(uint8 value) {
}
bCPU::bCPU() {
time_init();
mmio = new bCPUMMIO(this);
init_op_tables();
}
+95 -61
View File
@@ -10,11 +10,12 @@ 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;
public:
#include "srtc.h"
#include "bcpu_timing.h"
uint8 apu_port[4];
@@ -31,41 +32,49 @@ CPUReg24 aa, rd;
uint8 dp, sp;
enum {
CPUSTATE_RUN = 0,
CPUSTATE_WAI,
CPUSTATE_STP,
CPUSTATE_DMA
};
enum {
DMASTATE_STOP = 0,
DMASTATE_INIT,
DMASTATE_DMASYNC,
DMASTATE_DMASYNC2,
DMASTATE_DMASYNC3,
DMASTATE_RUN,
DMASTATE_CPUSYNC
DMASTATE_CPUSYNC,
HDMASTATE_IDMASYNC,
HDMASTATE_IDMASYNC2,
HDMASTATE_IDMASYNC3,
HDMASTATE_ICPUSYNC,
HDMASTATE_DMASYNC,
HDMASTATE_DMASYNC2,
HDMASTATE_DMASYNC3,
HDMASTATE_RUN,
HDMASTATE_CPUSYNC
};
struct {
uint8 cpu_state, cycle_count;
bool hdma;
bool dma;
bool irq;
bool stp;
bool wai;
} run_state;
uint8 dma_state;
uint32 dma_cycle_count;
bool hdma_triggered;
struct {
uint8 cycle_pos, cycle_count;
uint8 opcode;
uint32 cycles_executed;
bool nmi_triggered;
bool nmi_pin;
bool r4210_read;
uint8 dma_state, hdma_state;
uint32 dma_cycle_count, hdma_cycle_count;
bool irq_triggered;
bool irq_pin;
//$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;
@@ -88,13 +97,21 @@ 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
//$420b
bool active;
//$420c
bool hdma_active;
bool hdma_enabled;
//$43x0
uint8 dmap;
bool direction;
@@ -104,59 +121,69 @@ struct {
uint8 xfermode;
//$43x1
uint8 destaddr;
//$43x2-$43x4
uint32 srcaddr;
//$43x2-$43x3
uint16 srcaddr;
//$43x4
uint8 srcbank;
//$43x5-$43x6
uint16 xfersize;
union {
uint16 xfersize;
uint16 hdma_iaddr;
};
//$43x7
uint8 hdma_indirect_bank;
uint8 hdma_ibank;
//$43x8-$43x9
uint32 hdma_taddr;
uint16 hdma_addr;
//$43xa
uint8 hdma_line_counter;
//$43xb/$43xf
uint8 hdma_unknown;
//hdma-specific
bool hdma_first_line;
bool hdma_repeat;
uint32 hdma_itaddr;
bool hdma_completed;
}channel[8];
bool hdma_active;
bool hdma_do_transfer;
} channel[8];
inline bool hdma_test();
inline bool nmi_test();
inline bool irq_test();
inline void irq(uint16 addr);
inline bool hdma_test();
inline bool nmi_test();
inline bool irq_test();
inline uint8 pio_status();
inline void run();
inline void scanline();
inline void frame();
inline void power();
inline void reset();
inline uint8 pio_status();
inline void run();
inline uint32 cycles_executed();
inline void scanline();
inline void frame();
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 uint16 dma_cputommio(uint8 i, uint8 index);
inline uint16 dma_mmiotocpu(uint8 i, uint8 index);
inline void dma_xfer_type0(uint8 i);
inline void dma_xfer_type1(uint8 i);
inline void dma_xfer_type2(uint8 i);
inline void dma_xfer_type3(uint8 i);
inline void dma_xfer_type4(uint8 i);
inline void dma_xfer_type5(uint8 i);
inline void hdma_write(uint8 i, uint8 l, uint8 x);
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 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
void mmio_reset();
uint8 mmio_r2180();
uint8 mmio_r21c2();
uint8 mmio_r21c3();
uint8 mmio_r4016();
uint8 mmio_r4017();
uint8 mmio_r4210();
uint8 mmio_r4211();
uint8 mmio_r4212();
@@ -167,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);
@@ -184,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);
@@ -212,8 +242,12 @@ struct {
void mmio_w43xb(uint8 value, uint8 i);
enum { CYCLE_OPREAD = 0, CYCLE_READ, CYCLE_WRITE, CYCLE_IO };
inline void exec_opcode();
inline void cycle_edge();
inline void pre_exec_cycle();
inline void exec_hdma();
inline void exec_dma();
inline void exec_cycle();
inline void last_cycle();
inline bool in_opcode();
//cpu extra-cycle conditions
inline void cpu_c2();
+196 -182
View File
@@ -1,92 +1,53 @@
uint16 bCPU::dma_cputommio(uint8 i, uint8 index) {
uint8 x;
x = mem_bus->read(channel[i].srcaddr);
mem_bus->write(0x2100 | ((channel[i].destaddr + index) & 0xff), x);
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].srcbank << 16) | (channel[i].srcaddr);
if(channel[i].fixedxfer == false) {
channel[i].srcaddr = (channel[i].srcaddr & 0xff0000) + ((channel[i].srcaddr + channel[i].incmode) & 0xffff);
channel[i].srcaddr += channel[i].incmode;
}
add_cycles(8);
return --channel[i].xfersize;
return r;
}
uint16 bCPU::dma_mmiotocpu(uint8 i, uint8 index) {
void bCPU::dma_cputommio(uint8 i, uint8 index) {
uint8 x;
x = mem_bus->read(0x2100 | ((channel[i].destaddr + index) & 0xff));
mem_bus->write(channel[i].srcaddr, x);
if(channel[i].fixedxfer == false) {
channel[i].srcaddr = (channel[i].srcaddr & 0xff0000) + ((channel[i].srcaddr + channel[i].incmode) & 0xffff);
if(sdd1->dma_active() == true) {
x = sdd1->dma_read();
} else {
x = r_mem->read(dma_addr(i));
}
r_mem->write(0x2100 | ((channel[i].destaddr + index) & 0xff), x);
add_cycles(8);
return --channel[i].xfersize;
channel[i].xfersize--;
}
void bCPU::dma_xfer_type0(uint8 i) {
if(channel[i].direction == 0) {
if(dma_cputommio(i, 0) == 0)return;
} else {
if(dma_mmiotocpu(i, 0) == 0)return;
}
void bCPU::dma_mmiotocpu(uint8 i, uint8 index) {
uint8 x;
x = r_mem->read(0x2100 | ((channel[i].destaddr + index) & 0xff));
r_mem->write(dma_addr(i), x);
add_cycles(8);
channel[i].xfersize--;
}
void bCPU::dma_xfer_type1(uint8 i) {
void bCPU::dma_write(uint8 i, uint8 index) {
if(channel[i].direction == 0) {
if(dma_cputommio(i, 0) == 0)return;
if(dma_cputommio(i, 1) == 0)return;
dma_cputommio(i, index);
} else {
if(dma_mmiotocpu(i, 0) == 0)return;
if(dma_mmiotocpu(i, 1) == 0)return;
}
}
void bCPU::dma_xfer_type2(uint8 i) {
if(channel[i].direction == 0) {
if(dma_cputommio(i, 0) == 0)return;
if(dma_cputommio(i, 0) == 0)return;
} else {
if(dma_mmiotocpu(i, 0) == 0)return;
if(dma_mmiotocpu(i, 0) == 0)return;
}
}
void bCPU::dma_xfer_type3(uint8 i) {
if(channel[i].direction == 0) {
if(dma_cputommio(i, 0) == 0)return;
if(dma_cputommio(i, 0) == 0)return;
if(dma_cputommio(i, 1) == 0)return;
if(dma_cputommio(i, 1) == 0)return;
} else {
if(dma_mmiotocpu(i, 0) == 0)return;
if(dma_mmiotocpu(i, 0) == 0)return;
if(dma_mmiotocpu(i, 1) == 0)return;
if(dma_mmiotocpu(i, 1) == 0)return;
}
}
void bCPU::dma_xfer_type4(uint8 i) {
if(channel[i].direction == 0) {
if(dma_cputommio(i, 0) == 0)return;
if(dma_cputommio(i, 1) == 0)return;
if(dma_cputommio(i, 2) == 0)return;
if(dma_cputommio(i, 3) == 0)return;
} else {
if(dma_mmiotocpu(i, 0) == 0)return;
if(dma_mmiotocpu(i, 1) == 0)return;
if(dma_mmiotocpu(i, 2) == 0)return;
if(dma_mmiotocpu(i, 3) == 0)return;
}
}
void bCPU::dma_xfer_type5(uint8 i) {
if(channel[i].direction == 0) {
if(dma_cputommio(i, 0) == 0)return;
if(dma_cputommio(i, 1) == 0)return;
if(dma_cputommio(i, 0) == 0)return;
if(dma_cputommio(i, 1) == 0)return;
} else {
if(dma_mmiotocpu(i, 0) == 0)return;
if(dma_mmiotocpu(i, 1) == 0)return;
if(dma_mmiotocpu(i, 0) == 0)return;
if(dma_mmiotocpu(i, 1) == 0)return;
dma_mmiotocpu(i, index);
}
}
@@ -95,17 +56,26 @@ int i;
for(i=0;i<8;i++) {
if(channel[i].active == false)continue;
switch(channel[i].xfermode) {
case 0:dma_xfer_type0(i);break;
case 1:dma_xfer_type1(i);break;
case 2:dma_xfer_type2(i);break;
case 3:dma_xfer_type3(i);break;
case 4:dma_xfer_type4(i);break;
case 5:dma_xfer_type5(i);break;
case 6:dma_xfer_type2(i);break;
case 7:dma_xfer_type3(i);break;
//first byte transferred?
if(channel[i].read_index == 0) {
sdd1->dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr),
channel[i].xfersize);
}
switch(channel[i].xfermode) {
case 0:dma_write(i, 0); break; //0
case 1:dma_write(i, channel[i].read_index & 1); break; //0,1
case 2:dma_write(i, 0); break; //0,0
case 3:dma_write(i, (channel[i].read_index >> 1) & 1);break; //0,0,1,1
case 4:dma_write(i, channel[i].read_index & 3); break; //0,1,2,3
case 5:dma_write(i, channel[i].read_index & 1); break; //0,1,0,1
case 6:dma_write(i, 0); break; //0,0 [2]
case 7:dma_write(i, (channel[i].read_index >> 1) & 1);break; //0,0,1,1 [3]
}
channel[i].read_index++;
dma_add_cycles(8);
if(channel[i].xfersize == 0) {
channel[i].active = false;
}
@@ -116,126 +86,170 @@ int i;
status.dma_state = DMASTATE_CPUSYNC;
}
void bCPU::hdma_write(uint8 i, uint8 l, uint8 x) {
uint32 bCPU::hdma_addr(uint8 i) {
return (channel[i].srcbank << 16) | (channel[i].hdma_addr++);
}
uint32 bCPU::hdma_iaddr(uint8 i) {
return (channel[i].hdma_ibank << 16) | (channel[i].hdma_iaddr++);
}
uint16 bCPU::hdma_mmio(uint8 i) {
uint8 l = channel[i].read_index;
uint16 index;
switch(channel[i].xfermode) {
case 0:mem_bus->write(0x2100 | ((channel[i].destaddr) & 0xff), x);break;
case 1:mem_bus->write(0x2100 | ((channel[i].destaddr + l) & 0xff), x);break;
case 2:mem_bus->write(0x2100 | ((channel[i].destaddr) & 0xff), x);break;
case 3:mem_bus->write(0x2100 | ((channel[i].destaddr + (l >> 1)) & 0xff), x);break;
case 4:mem_bus->write(0x2100 | ((channel[i].destaddr + l) & 0xff), x);break;
case 5:mem_bus->write(0x2100 | ((channel[i].destaddr + (l & 1)) & 0xff), x);break;
case 6:mem_bus->write(0x2100 | ((channel[i].destaddr) & 0xff), x);break;
case 7:mem_bus->write(0x2100 | ((channel[i].destaddr + (l >> 1)) & 0xff), x);break;
case 0:index = 0; break; //0
case 1:index = l & 1; break; //0,1
case 2:index = 0; break; //0,0
case 3:index = (l >> 1) & 1;break; //0,0,1,1
case 4:index = l & 3; break; //0,1,2,3
case 5:index = l & 1; break; //0,1,0,1
case 6:index = 0; break; //0,0 [2]
case 7:index = (l >> 1) & 1;break; //0,0,1,1 [3]
}
return (0x2100 | ((channel[i].destaddr + index) & 0xff));
}
uint8 bCPU::hdma_read(uint8 i) {
if(channel[i].direction == DMA_MMIOTOCPU) {
return r_mem->read(hdma_mmio(i));
} else if(!channel[i].hdma_indirect) {
return r_mem->read(hdma_addr(i));
} else {
return r_mem->read(hdma_iaddr(i));
}
}
void bCPU::hdma_write(uint8 i, uint8 x) {
uint32 addr;
if(channel[i].direction == DMA_CPUTOMMIO) {
addr = hdma_mmio(i);
} else if(!channel[i].hdma_indirect) {
addr = hdma_addr(i);
} else {
addr = hdma_iaddr(i);
}
if((bool)config::cpu.hdma_enable == true) {
r_mem->write(addr, x);
}
add_cycles(8);
hdma_add_cycles(8);
}
void bCPU::hdma_update(uint8 i) {
channel[i].hdma_line_counter = r_mem->read(hdma_addr(i));
add_cycles(8);
hdma_add_cycles(8);
if(channel[i].hdma_indirect) {
channel[i].hdma_iaddr = r_mem->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 |= r_mem->read(hdma_addr(i)) << 8;
add_cycles(8);
hdma_add_cycles(8);
}
}
void bCPU::hdma_run() {
int l, xferlen;
uint8 x, active_channels = 0;
static uint8 hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
for(int i=0;i<8;i++) {
if(channel[i].hdma_completed == true)continue;
// add_cycles(8);
active_channels++;
if(channel[i].hdma_line_counter == 0) {
channel[i].hdma_line_counter = mem_bus->read(channel[i].hdma_taddr++);
if(channel[i].hdma_line_counter == 0) {
channel[i].hdma_completed = true;
continue;
}
if(!channel[i].hdma_enabled || !channel[i].hdma_active)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 == false) {
channel[i].hdma_itaddr = channel[i].hdma_taddr;
} else {
channel[i].hdma_itaddr = mem_bus->read(channel[i].hdma_taddr++);
channel[i].hdma_itaddr |= mem_bus->read(channel[i].hdma_taddr++) << 8;
channel[i].hdma_itaddr |= channel[i].hdma_indirect_bank << 16;
// 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;
if(channel[i].hdma_indirect == false) {
channel[i].hdma_itaddr = channel[i].hdma_taddr;
channel[i].hdma_do_transfer = !!(channel[i].hdma_line_counter & 0x80);
if((channel[i].hdma_line_counter & 0x7f) == 0) {
hdma_update(i);
}
switch(channel[i].xfermode) {
case 0: xferlen = 1;break;
case 1:case 2:case 6: xferlen = 2;break;
case 3:case 4:case 5:case 7:xferlen = 4;break;
}
for(l=0;l<xferlen;l++) {
x = mem_bus->read(channel[i].hdma_itaddr++);
if(channel[i].hdma_indirect == false) {
channel[i].hdma_taddr++;
}
hdma_write(i, l, x);
// add_cycles(8);
}
}
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++) {
if(channel[i].hdma_active == false) {
channel[i].hdma_completed = true;
continue;
}
active_channels++;
channel[i].hdma_first_line = true;
channel[i].hdma_repeat = false;
channel[i].hdma_taddr = channel[i].srcaddr;
channel[i].hdma_line_counter = 0x00;
channel[i].hdma_completed = false;
if(channel[i].hdma_indirect == false) {
add_cycles(8);
} else {
add_cycles(24);
}
if(channel[i].hdma_enabled)r++;
}
return r;
}
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;
}
/* hdmainit_activate()
* hdma_activate()
*
* Functions are called by CPU timing routine
* when an HDMA event (init or run) occurs.
*/
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;
}
}
void bCPU::dma_reset() {
for(int i=0;i<8;i++) {
channel[i].active = false;
channel[i].hdma_active = false;
channel[i].dmap = 0x00;
channel[i].direction = 0;
channel[i].hdma_indirect = false;
channel[i].incmode = 1;
channel[i].fixedxfer = false;
channel[i].xfermode = 0;
channel[i].destaddr = 0;
channel[i].srcaddr = 0;
channel[i].xfersize = 0;
channel[i].hdma_indirect_bank = 0;
channel[i].hdma_taddr = 0x000000;
channel[i].hdma_line_counter = 0x00;
channel[i].hdma_unknown = 0x00;
channel[i].read_index = 0;
channel[i].active = false;
channel[i].hdma_enabled = false;
channel[i].dmap = 0x00;
channel[i].direction = 0;
channel[i].hdma_indirect = false;
channel[i].incmode = 1;
channel[i].fixedxfer = false;
channel[i].xfermode = 0;
channel[i].destaddr = 0;
channel[i].srcaddr = 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_first_line = false;
channel[i].hdma_repeat = false;
channel[i].hdma_itaddr = 0x000000;
channel[i].hdma_completed = true;
channel[i].hdma_active = false;
channel[i].hdma_do_transfer = false;
}
}
+160 -26
View File
@@ -1,40 +1,174 @@
inline void bCPU::cycle_edge() {
int c, n, z;
if(status.dma_state != DMASTATE_STOP) {
switch(status.dma_state) {
case DMASTATE_INIT:
status.dma_state = DMASTATE_DMASYNC;
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;
case DMASTATE_DMASYNC:
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.dma_cycle_count += channel[z].xfersize << 3;
}
status.cpu_state = CPUSTATE_DMA;
status.dma_state = DMASTATE_RUN;
while(status.dma_state == DMASTATE_RUN) {
dma_run();
}
status.cpu_state = CPUSTATE_RUN;
}
}
if(run_state.dma) {
switch(status.dma_state) {
case DMASTATE_CPUSYNC:
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_opcode() {
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
cycle_edge();
break;
case DMASTATE_CPUSYNC:
exec_cycle();
break;
}
}
void bCPU::exec_cycle() {
//irq active? run one bus cycle of the irq event and return
if(run_state.irq) {
irq_run();
return;
}
if(status.cycle_pos) {
(this->*optbl[status.opcode])();
#ifdef DEBUGGER
if(status.cycle_pos == 0) {
snes->notify(SNES::CPU_EXEC_OPCODE_END);
}
#endif
return;
}
//on first cycle?
#ifdef DEBUGGER
snes->notify(SNES::CPU_EXEC_OPCODE_BEGIN);
(this->*optbl[op_read()])();
snes->notify(SNES::CPU_EXEC_OPCODE_END);
#endif
status.opcode = op_read();
status.cycle_pos = 1;
}
//only return true when we are on an opcode edge
bool bCPU::in_opcode() {
return (status.cycle_pos != 0);
}
void bCPU::init_op_tables() {
+69
View File
@@ -0,0 +1,69 @@
/*
[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(r_mem->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;
#ifdef DEBUGGER
//let debugger know the new IRQ opcode address
snes->notify(SNES::CPU_EXEC_OPCODE_END);
#endif
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;
}
+178 -96
View File
@@ -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;
@@ -35,35 +37,28 @@ void bCPU::mmio_reset() {
//WMDATA
uint8 bCPU::mmio_r2180() {
uint8 r;
r = mem_bus->read(0x7e0000 | status.wram_addr);
r = r_mem->read(0x7e0000 | status.wram_addr);
status.wram_addr++;
status.wram_addr &= 0x01ffff;
return r;
}
//???
uint8 bCPU::mmio_r21c2() {
return 0x20;
}
//???
uint8 bCPU::mmio_r21c3() {
return 0x00;
}
/*
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.
*/
//JOYSER0
//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 = 0x00;
uint8 r;
r = regs.mdr & 0xfc;
if(status.joypad1_strobe_value == 1) {
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_B);
} else {
@@ -85,59 +80,98 @@ uint8 r = 0x00;
}
if(++status.joypad1_read_pos > 17)status.joypad1_read_pos = 17;
}
return r;
}
//JOYSER1
//7-5 = MDR
//4-2 = Always 1
//1-0 = Joypad serial data
uint8 bCPU::mmio_r4017() {
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
//7 = NMI acknowledge
//6-4 = MDR
//3-0 = CPU (5a22) version
uint8 bCPU::mmio_r4210() {
uint8 r = 0x00;
uint16 v, h, hc, vs;
v = vcounter();
h = hcounter();
hc = hcycles();
vs = (overscan()?239:224);
uint8 r;
r = regs.mdr & 0x70;
r |= uint8(!time.nmi_read) << 7;
if(status.r4210_read == false) {
if((v == (vs + 1) && hc >= 2) || v > (vs + 1)) {
r |= 0x80;
status.r4210_read = true;
status.nmi_pin = 1;
}
if(!nmi_trigger_pos_match(0) && !nmi_trigger_pos_match(2)) {
time.nmi_read = 1;
}
r |= 0x40;
r |= 0x02; //cpu version number
r |= (cpu_version & 0x0f);
return r;
}
//TIMEUP
//7 = IRQ acknowledge
//6-0 = MDR
uint8 bCPU::mmio_r4211() {
uint8 r = 0x00;
r |= 0x40;
if(status.irq_triggered == true)r |= 0x80;
status.irq_triggered = false;
uint8 r;
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;
}
//HVBJOY
//7 = in vblank
//6 = in hblank
//5-1 = MDR
//0 = joypad ready
uint8 bCPU::mmio_r4212() {
uint8 r;
uint16 v, h, hc, vs;
r = 0x00;
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;
}
@@ -168,7 +202,7 @@ uint8 bCPU::mmio_r4217() {
//JOY1L
uint8 bCPU::mmio_r4218() {
uint8 r = 0x00;
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
@@ -181,7 +215,7 @@ uint16 v = vcounter();
//JOY1H
uint8 bCPU::mmio_r4219() {
uint8 r = 0x00;
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
@@ -196,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;
@@ -218,7 +282,7 @@ uint8 bCPU::mmio_r43x3(uint8 i) {
//A1Bx
uint8 bCPU::mmio_r43x4(uint8 i) {
return channel[i].srcaddr >> 16;
return channel[i].srcbank;
}
//DASxL
@@ -233,17 +297,17 @@ uint8 bCPU::mmio_r43x6(uint8 i) {
//DASBx
uint8 bCPU::mmio_r43x7(uint8 i) {
return channel[i].hdma_indirect_bank;
return channel[i].hdma_ibank;
}
//A2AxL
uint8 bCPU::mmio_r43x8(uint8 i) {
return channel[i].hdma_taddr;
return channel[i].hdma_addr;
}
//A2AxH
uint8 bCPU::mmio_r43x9(uint8 i) {
return channel[i].hdma_taddr >> 8;
return channel[i].hdma_addr >> 8;
}
//NTRLx
@@ -257,12 +321,10 @@ 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);
return r_apu->port_read(addr & 3);
}
//HDMA
@@ -281,19 +343,17 @@ uint8 i;
case 0x9:return cpu->mmio_r43x9(i);
case 0xa:return cpu->mmio_r43xa(i);
case 0xb:return cpu->mmio_r43xb(i);
case 0xc:return 0x43; //unmapped
case 0xd:return 0x43; //unmapped
case 0xe:return 0x43; //unmapped
case 0xc:return cpu->regs.mdr; //unmapped
case 0xd:return cpu->regs.mdr; //unmapped
case 0xe:return cpu->regs.mdr; //unmapped
case 0xf:return cpu->mmio_r43xb(i); //mirror of 43xb
}
}
switch(addr) {
case 0x2180:return cpu->mmio_r2180(); //WMDATA
case 0x21c2:return cpu->mmio_r21c2(); //???
case 0x21c3:return cpu->mmio_r21c3(); //???
case 0x2800:return cpu->srtc_read();
case 0x4016:return cpu->mmio_r4016(); //JOYSER0
case 0x4017:return cpu->mmio_r4017(); //JOYSER1
case 0x4210:return cpu->mmio_r4210(); //RDNMI
case 0x4211:return cpu->mmio_r4211(); //TIMEUP
case 0x4212:return cpu->mmio_r4212(); //HVBJOY
@@ -304,14 +364,17 @@ 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 0x00;
return cpu->regs.mdr;
}
//WMDATA
void bCPU::mmio_w2180(uint8 value) {
mem_bus->write(0x7e0000 | status.wram_addr, value);
r_mem->write(0x7e0000 | status.wram_addr, value);
status.wram_addr++;
status.wram_addr &= 0x01ffff;
}
@@ -336,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);
@@ -350,19 +422,26 @@ void bCPU::mmio_w4200(uint8 value) {
status.hirq_enabled = !!(value & 0x10);
status.auto_joypad_poll = !!(value & 0x01);
if(status.nmi_enabled == false) {
status.nmi_pin = 0;
if(time.nmi_read == 0) {
if(time.nmi_line == 1 && !status.nmi_enabled == 0) {
time.nmi_transition = 1;
}
time.nmi_line = !status.nmi_enabled;
}
if(status.virq_enabled == false && status.hirq_enabled == false) {
status.irq_pin = 0;
time.irq_line = 1;
time.irq_read = 1;
time.irq_transition = 0;
}
update_interrupts();
}
//WRIO
void bCPU::mmio_w4201(uint8 value) {
if((status.pio & 0x80) && !(value & 0x80)) {
ppu->latch_counters();
r_ppu->latch_counters();
}
status.pio = value;
}
@@ -390,44 +469,48 @@ 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;
if(status.irq_triggered == false)status.irq_pin = 1;
update_interrupts();
}
//HTIMEH
void bCPU::mmio_w4208(uint8 value) {
status.hirq_pos = (status.hirq_pos & 0x00ff) | (value << 8);
if(status.irq_triggered == false)status.irq_pin = 1;
update_interrupts();
}
//VTIMEL
void bCPU::mmio_w4209(uint8 value) {
status.virq_pos = (status.virq_pos & 0xff00) | value;
if(status.irq_triggered == false)status.irq_pin = 1;
update_interrupts();
}
//VTIMEH
void bCPU::mmio_w420a(uint8 value) {
status.virq_pos = (status.virq_pos & 0x00ff) | (value << 8);
if(status.irq_triggered == false)status.irq_pin = 1;
update_interrupts();
}
//DMAEN
void bCPU::mmio_w420b(uint8 value) {
int len;
if(value != 0x00) {
status.dma_state = DMASTATE_INIT;
run_state.dma = true;
status.dma_state = DMASTATE_DMASYNC;
}
for(int i=0;i<8;i++) {
if(value & (1 << i)) {
channel[i].active = true;
channel[i].hdma_active = false;
channel[i].active = true;
channel[i].hdma_enabled = false;
channel[i].hdma_active = false;
channel[i].read_index = 0;
}
}
}
@@ -435,13 +518,14 @@ void bCPU::mmio_w420b(uint8 value) {
//HDMAEN
void bCPU::mmio_w420c(uint8 value) {
for(int i=0;i<8;i++) {
channel[i].hdma_active = !!(value & (1 << i));
channel[i].hdma_enabled = !!(value & (1 << i));
channel[i].hdma_active = !!(value & (1 << i));
}
}
//MEMSEL
void bCPU::mmio_w420d(uint8 value) {
mem_bus->fastROM = value & 1;
r_mem->set_speed(value & 1);
}
//DMAPx
@@ -461,17 +545,17 @@ void bCPU::mmio_w43x1(uint8 value, uint8 i) {
//A1TxL
void bCPU::mmio_w43x2(uint8 value, uint8 i) {
channel[i].srcaddr = (channel[i].srcaddr & 0xffff00) | value;
channel[i].srcaddr = (channel[i].srcaddr & 0xff00) | value;
}
//A1TxH
void bCPU::mmio_w43x3(uint8 value, uint8 i) {
channel[i].srcaddr = (channel[i].srcaddr & 0xff00ff) | (value << 8);
channel[i].srcaddr = (channel[i].srcaddr & 0x00ff) | (value << 8);
}
//A1Bx
void bCPU::mmio_w43x4(uint8 value, uint8 i) {
channel[i].srcaddr = (channel[i].srcaddr & 0x00ffff) | (value << 16);
channel[i].srcbank = value;
}
//DASxL
@@ -486,17 +570,17 @@ void bCPU::mmio_w43x6(uint8 value, uint8 i) {
//DASBx
void bCPU::mmio_w43x7(uint8 value, uint8 i) {
channel[i].hdma_indirect_bank = value;
channel[i].hdma_ibank = value;
}
//A2AxL
void bCPU::mmio_w43x8(uint8 value, uint8 i) {
channel[i].hdma_taddr = (channel[i].hdma_taddr & 0xffff00) | value;
channel[i].hdma_addr = (channel[i].hdma_addr & 0xff00) | value;
}
//A2AxH
void bCPU::mmio_w43x9(uint8 value, uint8 i) {
channel[i].hdma_taddr = (channel[i].hdma_taddr & 0xff00ff) | (value << 8);
channel[i].hdma_addr = (channel[i].hdma_addr & 0x00ff) | (value << 8);
}
//NTRLx
@@ -511,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);
@@ -547,8 +629,8 @@ uint8 i;
case 0x2181:cpu->mmio_w2181(value);return; //WMADDL
case 0x2182:cpu->mmio_w2182(value);return; //WMADDM
case 0x2183:cpu->mmio_w2183(value);return; //WMADDH
case 0x2801:cpu->srtc_write(value);return;
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
+1 -1
View File
@@ -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();
File diff suppressed because it is too large. Load diff
+411 -239
View File
@@ -1,310 +1,482 @@
void bCPU::op_bra() {
l1:
rd.l = op_read();
if(1) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bcc() {
l1:
rd.l = op_read();
if(!regs.p.c) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
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;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
break;
case 2:
cpu_c6(aa.w);
break;
case 3:
last_cycle();
cpu_io();
status.cycle_pos = 0;
break;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bcs() {
l1:
rd.l = op_read();
if(regs.p.c) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
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;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
break;
case 2:
cpu_c6(aa.w);
break;
case 3:
last_cycle();
cpu_io();
status.cycle_pos = 0;
break;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bne() {
l1:
rd.l = op_read();
if(!regs.p.z) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
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;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
break;
case 2:
cpu_c6(aa.w);
break;
case 3:
last_cycle();
cpu_io();
status.cycle_pos = 0;
break;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_beq() {
l1:
rd.l = op_read();
if(regs.p.z) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
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;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
break;
case 2:
cpu_c6(aa.w);
break;
case 3:
last_cycle();
cpu_io();
status.cycle_pos = 0;
break;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bpl() {
l1:
rd.l = op_read();
if(!regs.p.n) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
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;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
break;
case 2:
cpu_c6(aa.w);
break;
case 3:
last_cycle();
cpu_io();
status.cycle_pos = 0;
break;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bmi() {
l1:
rd.l = op_read();
if(regs.p.n) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
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;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
break;
case 2:
cpu_c6(aa.w);
break;
case 3:
last_cycle();
cpu_io();
status.cycle_pos = 0;
break;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bvc() {
l1:
rd.l = op_read();
if(!regs.p.v) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
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;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
break;
case 2:
cpu_c6(aa.w);
break;
case 3:
last_cycle();
cpu_io();
status.cycle_pos = 0;
break;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bvs() {
l1:
rd.l = op_read();
if(regs.p.v) {
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;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
break;
case 2:
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;
} else {
return;
break;
case 2:
cpu_c6(aa.w);
break;
case 3:
last_cycle();
cpu_io();
status.cycle_pos = 0;
break;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_brl() {
l1:
rd.l = op_read();
l2:
rd.h = op_read();
l3:
cpu_io();
regs.pc.w = regs.pc.d + (int16)rd.w;
switch(status.cycle_pos++) {
case 1:
rd.l = op_read();
break;
case 2:
rd.h = op_read();
break;
case 3:
last_cycle();
cpu_io();
regs.pc.w = regs.pc.d + (int16)rd.w;
status.cycle_pos = 0;
break;
}
}
void bCPU::op_jmp_addr() {
l1:
rd.l = op_read();
l2:
rd.h = op_read();
regs.pc.w = rd.w;
switch(status.cycle_pos++) {
case 1:
rd.l = op_read();
break;
case 2:
last_cycle();
rd.h = op_read();
regs.pc.w = rd.w;
status.cycle_pos = 0;
break;
}
}
void bCPU::op_jmp_long() {
l1:
rd.l = op_read();
l2:
rd.h = op_read();
l3:
rd.b = op_read();
regs.pc.d = rd.d & 0xffffff;
switch(status.cycle_pos++) {
case 1:
rd.l = op_read();
break;
case 2:
rd.h = op_read();
break;
case 3:
last_cycle();
rd.b = op_read();
regs.pc.d = rd.d & 0xffffff;
status.cycle_pos = 0;
break;
}
}
void bCPU::op_jmp_iaddr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
rd.l = op_read(OPMODE_ADDR, aa.w);
l4:
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
regs.pc.w = rd.w;
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
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;
break;
}
}
void bCPU::op_jmp_iaddrx() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_io();
l4:
rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
l5:
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
regs.pc.w = rd.w;
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
cpu_io();
break;
case 4:
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;
break;
}
}
void bCPU::op_jmp_iladdr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
rd.l = op_read(OPMODE_ADDR, aa.w);
l4:
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
l5:
rd.b = op_read(OPMODE_ADDR, aa.w + 2);
regs.pc.d = rd.d & 0xffffff;
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
rd.l = op_read(OPMODE_ADDR, aa.w);
break;
case 4:
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;
break;
}
}
void bCPU::op_jsr_addr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_io();
l4:
regs.pc.w--;
stack_write(regs.pc.h);
l5:
stack_write(regs.pc.l);
regs.pc.w = aa.w;
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
cpu_io();
break;
case 4:
regs.pc.w--;
stack_write(regs.pc.h);
break;
case 5:
last_cycle();
stack_write(regs.pc.l);
regs.pc.w = aa.w;
status.cycle_pos = 0;
break;
}
}
void bCPU::op_jsr_long() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
stack_write(regs.pc.b);
l4:
cpu_io();
l5:
aa.b = op_read();
l6:
regs.pc.w--;
stack_write(regs.pc.h);
l7:
stack_write(regs.pc.l);
regs.pc.d = aa.d & 0xffffff;
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
stack_write(regs.pc.b);
break;
case 4:
cpu_io();
break;
case 5:
aa.b = op_read();
break;
case 6:
regs.pc.w--;
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;
break;
}
}
void bCPU::op_jsr_iaddrx() {
l1:
aa.l = op_read();
l2:
stack_write(regs.pc.h);
l3:
stack_write(regs.pc.l);
l4:
aa.h = op_read();
l5:
cpu_io();
l6:
rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
l7:
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
regs.pc.w = rd.w;
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
stack_write(regs.pc.h);
break;
case 3:
stack_write(regs.pc.l);
break;
case 4:
aa.h = op_read();
break;
case 5:
cpu_io();
break;
case 6:
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;
break;
}
}
void bCPU::op_rti() {
l1:
cpu_io();
l2:
cpu_io();
l3:
regs.p = stack_read();
if(regs.e)regs.p |= 0x30;
if(regs.p.x) {
regs.x.h = 0x00;
regs.y.h = 0x00;
switch(status.cycle_pos++) {
case 1:
cpu_io();
break;
case 2:
cpu_io();
break;
case 3:
regs.p = stack_read();
if(regs.e)regs.p |= 0x30;
if(regs.p.x) {
regs.x.h = 0x00;
regs.y.h = 0x00;
}
break;
case 4:
rd.l = stack_read();
break;
case 5:
rd.h = stack_read();
if(regs.e) {
regs.pc.w = rd.w;
status.cycle_pos = 0;
}
break;
case 6:
last_cycle();
rd.b = stack_read();
regs.pc.d = rd.d & 0xffffff;
status.cycle_pos = 0;
break;
}
l4:
rd.l = stack_read();
l5:
rd.h = stack_read();
if(regs.e) {
regs.pc.w = rd.w;
return;
}
l6:
rd.b = stack_read();
regs.pc.d = rd.d & 0xffffff;
}
void bCPU::op_rts() {
l1:
cpu_io();
l2:
cpu_io();
l3:
rd.l = stack_read();
l4:
rd.h = stack_read();
l5:
cpu_io();
regs.pc.w = rd.w;
regs.pc.w++;
switch(status.cycle_pos++) {
case 1:
cpu_io();
break;
case 2:
cpu_io();
break;
case 3:
rd.l = stack_read();
break;
case 4:
rd.h = stack_read();
break;
case 5:
last_cycle();
cpu_io();
regs.pc.w = rd.w;
regs.pc.w++;
status.cycle_pos = 0;
break;
}
}
void bCPU::op_rtl() {
l1:
cpu_io();
l2:
cpu_io();
l3:
rd.l = stack_read();
l4:
rd.h = stack_read();
l5:
rd.b = stack_read();
regs.pc.d = rd.d & 0xffffff;
regs.pc.w++;
switch(status.cycle_pos++) {
case 1:
cpu_io();
break;
case 2:
cpu_io();
break;
case 3:
rd.l = stack_read();
break;
case 4:
rd.h = stack_read();
break;
case 5:
last_cycle();
rd.b = stack_read();
regs.pc.d = rd.d & 0xffffff;
regs.pc.w++;
status.cycle_pos = 0;
break;
}
}
+2804 -1534
View File
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+510 -268
View File
@@ -1,340 +1,582 @@
void bCPU::op_sta_addr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
op_write(OPMODE_DBR, aa.w, regs.a.w);
if(regs.p.m)return;
l4:
op_write(OPMODE_DBR, aa.w + 1, regs.a.w >> 8);
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
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;
}
}
void bCPU::op_stx_addr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
op_write(OPMODE_DBR, aa.w, regs.x.w);
if(regs.p.x)return;
l4:
op_write(OPMODE_DBR, aa.w + 1, regs.x.w >> 8);
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
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;
}
}
void bCPU::op_sty_addr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
op_write(OPMODE_DBR, aa.w, regs.y.w);
if(regs.p.x)return;
l4:
op_write(OPMODE_DBR, aa.w + 1, regs.y.w >> 8);
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
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;
}
}
void bCPU::op_stz_addr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
op_write(OPMODE_DBR, aa.w, 0x0000);
if(regs.p.m)return;
l4:
op_write(OPMODE_DBR, aa.w + 1, 0x0000 >> 8);
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
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;
}
}
void bCPU::op_sta_addrx() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_c4(aa.w, aa.w + regs.x.w);
l4:
op_write(OPMODE_DBR, aa.w + regs.x.w, regs.a.w);
if(regs.p.m)return;
l5:
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, regs.a.w >> 8);
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
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;
}
}
void bCPU::op_stz_addrx() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_c4(aa.w, aa.w + regs.x.w);
l4:
op_write(OPMODE_DBR, aa.w + regs.x.w, 0x0000);
if(regs.p.m)return;
l5:
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, 0x0000 >> 8);
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
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;
}
}
void bCPU::op_sta_addry() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_c4(aa.w, aa.w + regs.y.w);
l4:
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
if(regs.p.m)return;
l5:
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
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;
}
}
void bCPU::op_sta_long() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
aa.b = op_read();
l4:
op_write(OPMODE_LONG, aa.d, regs.a.l);
if(regs.p.m)return;
l5:
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
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;
}
}
void bCPU::op_sta_longx() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
aa.b = op_read();
l4:
op_write(OPMODE_LONG, aa.d + regs.x.w, regs.a.l);
if(regs.p.m)return;
l5:
op_write(OPMODE_LONG, aa.d + regs.x.w + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
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;
}
}
void bCPU::op_sta_dp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
op_write(OPMODE_DP, dp, regs.a.w);
if(regs.p.m)return;
l4:
op_write(OPMODE_DP, dp + 1, regs.a.w >> 8);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
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;
}
}
void bCPU::op_stx_dp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
op_write(OPMODE_DP, dp, regs.x.w);
if(regs.p.x)return;
l4:
op_write(OPMODE_DP, dp + 1, regs.x.w >> 8);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
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;
}
}
void bCPU::op_sty_dp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
op_write(OPMODE_DP, dp, regs.y.w);
if(regs.p.x)return;
l4:
op_write(OPMODE_DP, dp + 1, regs.y.w >> 8);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
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;
}
}
void bCPU::op_stz_dp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
op_write(OPMODE_DP, dp, 0x0000);
if(regs.p.m)return;
l4:
op_write(OPMODE_DP, dp + 1, 0x0000 >> 8);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
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;
}
}
void bCPU::op_sta_dpx() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
op_write(OPMODE_DP, dp + regs.x.w, regs.a.w);
if(regs.p.m)return;
l5:
op_write(OPMODE_DP, dp + regs.x.w + 1, regs.a.w >> 8);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
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;
}
}
void bCPU::op_sty_dpx() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
op_write(OPMODE_DP, dp + regs.x.w, regs.y.w);
if(regs.p.x)return;
l5:
op_write(OPMODE_DP, dp + regs.x.w + 1, regs.y.w >> 8);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
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;
}
}
void bCPU::op_stz_dpx() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
op_write(OPMODE_DP, dp + regs.x.w, 0x0000);
if(regs.p.m)return;
l5:
op_write(OPMODE_DP, dp + regs.x.w + 1, 0x0000 >> 8);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
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;
}
}
void bCPU::op_stx_dpy() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
op_write(OPMODE_DP, dp + regs.y.w, regs.x.l);
if(regs.p.x)return;
l5:
op_write(OPMODE_DP, dp + regs.y.w + 1, regs.x.h);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
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;
}
}
void bCPU::op_sta_idp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
aa.l = op_read(OPMODE_DP, dp);
l4:
aa.h = op_read(OPMODE_DP, dp + 1);
l5:
op_write(OPMODE_DBR, aa.w, regs.a.l);
if(regs.p.m)return;
l6:
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
aa.l = op_read(OPMODE_DP, dp);
break;
case 4:
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;
}
}
void bCPU::op_sta_ildp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
aa.l = op_read(OPMODE_DP, dp);
l4:
aa.h = op_read(OPMODE_DP, dp + 1);
l5:
aa.b = op_read(OPMODE_DP, dp + 2);
l6:
op_write(OPMODE_LONG, aa.d, regs.a.l);
if(regs.p.m)return;
l7:
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
aa.l = op_read(OPMODE_DP, dp);
break;
case 4:
aa.h = op_read(OPMODE_DP, dp + 1);
break;
case 5:
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;
}
}
void bCPU::op_sta_idpx() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
aa.l = op_read(OPMODE_DP, dp + regs.x.w);
l5:
aa.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
l6:
op_write(OPMODE_DBR, aa.w, regs.a.l);
if(regs.p.m)return;
l7:
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
cpu_io();
break;
case 4:
aa.l = op_read(OPMODE_DP, dp + regs.x.w);
break;
case 5:
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;
}
}
void bCPU::op_sta_idpy() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
aa.l = op_read(OPMODE_DP, dp);
l4:
aa.h = op_read(OPMODE_DP, dp + 1);
l5:
cpu_c4(aa.w, aa.w + regs.y.w);
l6:
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
if(regs.p.m)return;
l7:
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
aa.l = op_read(OPMODE_DP, dp);
break;
case 4:
aa.h = op_read(OPMODE_DP, dp + 1);
break;
case 5:
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;
}
}
void bCPU::op_sta_ildpy() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
aa.l = op_read(OPMODE_DP, dp);
l4:
aa.h = op_read(OPMODE_DP, dp + 1);
l5:
aa.b = op_read(OPMODE_DP, dp + 2);
l6:
op_write(OPMODE_LONG, aa.d + regs.y.w, regs.a.l);
if(regs.p.m)return;
l7:
op_write(OPMODE_LONG, aa.d + regs.y.w + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
aa.l = op_read(OPMODE_DP, dp);
break;
case 4:
aa.h = op_read(OPMODE_DP, dp + 1);
break;
case 5:
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;
}
}
void bCPU::op_sta_sr() {
l1:
sp = op_read();
l2:
cpu_io();
l3:
op_write(OPMODE_SP, sp, regs.a.l);
if(regs.p.m)return;
l4:
op_write(OPMODE_SP, sp + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
sp = op_read();
break;
case 2:
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;
}
}
void bCPU::op_sta_isry() {
l1:
sp = op_read();
l2:
cpu_io();
l3:
aa.l = op_read(OPMODE_SP, sp);
l4:
aa.h = op_read(OPMODE_SP, sp + 1);
l5:
cpu_io();
l6:
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
if(regs.p.m)return;
l7:
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
sp = op_read();
break;
case 2:
cpu_io();
break;
case 3:
aa.l = op_read(OPMODE_SP, sp);
break;
case 4:
aa.h = op_read(OPMODE_SP, sp + 1);
break;
case 5:
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;
}
}
+107 -25
View File
@@ -1,31 +1,75 @@
//op_read
inline void bCPU::op_adc_b() {
int32 r = regs.a.l + rd.l + regs.p.c;
//bcd
if(regs.p.d) {
if(((r ) & 15) > 9)r += 6;
if(((r >> 4) & 15) > 9)r += 6 << 4;
uint8 n0 = (regs.a.l ) & 15;
uint8 n1 = (regs.a.l >> 4) & 15;
n0 += ((rd.l) & 15) + regs.p.c;
if(n0 > 9) {
n0 -= 10;
n0 &= 15;
n1++;
}
n1 += ((rd.l >> 4) & 15);
if(n1 > 9) {
n1 -= 10;
n1 &= 15;
regs.p.c = 1;
} else {
regs.p.c = 0;
}
r = (n1 << 4) | (n0);
} else {
r = regs.a.l + rd.l + regs.p.c;
regs.p.c = (r > 0xff);
}
regs.p.n = !!(r & 0x80);
regs.p.v = !!(~(regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80);
regs.p.z = ((uint8)r == 0);
regs.p.c = (r > 0xff);
regs.a.l = r;
}
inline void bCPU::op_adc_w() {
int32 r = regs.a.w + rd.w + regs.p.c;
//bcd
int32 r;
if(regs.p.d) {
if(((r ) & 15) > 9)r += 6;
if(((r >> 4) & 15) > 9)r += 6 << 4;
if(((r >> 8) & 15) > 9)r += 6 << 8;
if(((r >> 12) & 15) > 9)r += 6 << 12;
uint8 n0 = (regs.a.w ) & 15;
uint8 n1 = (regs.a.w >> 4) & 15;
uint8 n2 = (regs.a.w >> 8) & 15;
uint8 n3 = (regs.a.w >> 12) & 15;
n0 += ((rd.w) & 15) + regs.p.c;
if(n0 > 9) {
n0 -= 10;
n0 &= 15;
n1++;
}
n1 += ((rd.w >> 4) & 15);
if(n1 > 9) {
n1 -= 10;
n1 &= 15;
n2++;
}
n2 += ((rd.w >> 8) & 15);
if(n2 > 9) {
n2 -= 10;
n2 &= 15;
n3++;
}
n3 += ((rd.w >> 12) & 15);
if(n3 > 9) {
n3 -= 10;
n3 &= 15;
regs.p.c = 1;
} else {
regs.p.c = 0;
}
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | (n0);
} else {
r = regs.a.w + rd.w + regs.p.c;
regs.p.c = (r > 0xffff);
}
regs.p.n = !!(r & 0x8000);
regs.p.v = !!(~(regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000);
regs.p.z = ((uint16)r == 0);
regs.p.c = (r > 0xffff);
regs.a.w = r;
}
@@ -156,32 +200,70 @@ inline void bCPU::op_ora_w() {
}
inline void bCPU::op_sbc_b() {
int32 r = regs.a.l - rd.l - !regs.p.c;
//bcd
int32 r;
if(regs.p.d) {
if(((r ) & 15) > 9)r -= 6;
if(((r >> 4) & 15) > 9)r -= 6 << 4;
uint8 n0 = (regs.a.l ) & 15;
uint8 n1 = (regs.a.l >> 4) & 15;
n0 -= ((rd.l ) & 15) + !regs.p.c;
n1 -= ((rd.l >> 4) & 15);
if(n0 > 9) {
n0 += 10;
n1--;
}
if(n1 > 9) {
n1 += 10;
regs.p.c = 0;
} else {
regs.p.c = 1;
}
r = (n1 << 4) | (n0);
} else {
r = regs.a.l - rd.l - !regs.p.c;
regs.p.c = (r >= 0);
}
regs.p.n = !!(r & 0x80);
regs.p.v = !!((regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80);
regs.p.z = ((byte)r == 0);
regs.p.c = (r >= 0);
regs.p.z = ((uint8)r == 0);
regs.a.l = r;
}
inline void bCPU::op_sbc_w() {
int32 r = regs.a.w - rd.w - !regs.p.c;
//bcd
int32 r;
if(regs.p.d) {
if(((r ) & 15) > 9)r -= 6;
if(((r >> 4) & 15) > 9)r -= 6 << 4;
if(((r >> 8) & 15) > 9)r -= 6 << 8;
if(((r >> 12) & 15) > 9)r -= 6 << 12;
uint8 n0 = (regs.a.w ) & 15;
uint8 n1 = (regs.a.w >> 4) & 15;
uint8 n2 = (regs.a.w >> 8) & 15;
uint8 n3 = (regs.a.w >> 12) & 15;
n0 -= ((rd.w ) & 15) + !regs.p.c;
n1 -= ((rd.w >> 4) & 15);
n2 -= ((rd.w >> 8) & 15);
n3 -= ((rd.w >> 12) & 15);
if(n0 > 9) {
n0 += 10;
n1--;
}
if(n1 > 9) {
n1 += 10;
n2--;
}
if(n2 > 9) {
n2 += 10;
n3--;
}
if(n3 > 9) {
n3 += 10;
regs.p.c = 0;
} else {
regs.p.c = 1;
}
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | (n0);
} else {
r = regs.a.w - rd.w - !regs.p.c;
regs.p.c = (r >= 0);
}
regs.p.n = !!(r & 0x8000);
regs.p.v = !!((regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000);
regs.p.z = ((word)r == 0);
regs.p.c = (r >= 0);
regs.p.z = ((uint16)r == 0);
regs.a.w = r;
}
+1 -1
View File
@@ -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;
+283 -66
View File
@@ -1,21 +1,194 @@
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; }
/* Notes about PAL timing:
* As I do not have PAL hardware to run timing tests on, I've
* had to guess on a lot of things. Below is how I've arrived
* at various calculations:
*
* NTSC timing crystal: ~21477272hz
* PAL timing crystal: ~21281370hz
* NTSC ~60fps, PAL ~50fps
* NTSC ~262 lines/frame, PAL ~312 lines/frame
* NTSC 21477272 / (262 * 60) = ~1366 cycles/line
* PAL 21281370 / (312 * 50) = ~1364 cycles/line
*
* As the cycles/line are very close between the two systems,
* I have left the known NTSC anomalies intact for PAL timing.
* In reality, some of these may not exist, and some may be
* slightly different.
*
* [known]
* - DRAM refresh occurs at about the same time every
* scanline on PAL units (per Overload).
* [unknown]
* - Are dots 323/327 still 2 cycles longer than the
* other dots?
* - Is scanline 240 on non-interlace odd frames still
* 4 cycles short?
*/
void bCPU::set_interlace(bool r) { time.interlace = r; }
void bCPU::set_overscan(bool r) { time.overscan = r; }
uint16 bCPU::vcounter() { return time.v; }
uint16 bCPU::hcounter() { return get_hcounter(); }
uint16 bCPU::hcycles() { return time.hc; }
uint8 bCPU::dma_counter() { return (time.dma_counter + time.hc) & 6; }
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; 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]
//interlace mode has 525 scanlines: 263 on the even frame,
//and 262 on the odd.
//non-interlace mode has 524 scanlines: 262 scanlines on
//both even and odd frames.
//[PAL] <PAL info is unverified on hardware>
//interlace mode has 625 scanlines: 313 on the even frame,
//and 312 on the odd.
//non-interlace mode has 624 scanlines: 312 scanlines on
//both even and odd frames.
//
//cycles per frame:
// 263 * 1364 = 358732
@@ -28,114 +201,158 @@ void bCPU::inc_vcounter() {
time.interlace_field ^= 1;
if(time.interlace == true && time.interlace_field == 0) {
time.frame_lines = 263;
time.frame_lines = time.region_scanlines + 1;
} else {
time.frame_lines = 262;
time.frame_lines = time.region_scanlines;
}
}
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 322 and 326. dots 322 and 326
//all dots are 4 cycles long, except dots 323 and 327. dots 323 and 327
//are 6 cycles long. this holds true for all scanlines except scanline
//240 on non-interlace odd frames. the reason for this is because this
//scanline is only 1360 cycles long, instead of 1364 like all other
//scanlines.
//this makes the effective range of hscan_pos 0-339 at all times.
//dot 322 range = { 1288, 1290, 1292 }
//dot 326 range = { 1306, 1308, 1310 }
//dot 323 range = { 1292, 1294, 1296 }
//dot 327 range = { 1310, 1312, 1314 }
uint16 bCPU::get_hcounter() {
if(time.v == 240 && time.interlace == false && time.interlace_field == 1) {
return time.hc >> 2;
}
return (time.hc - ((time.hc > 1288) << 1) - ((time.hc > 1306) << 1)) >> 2;
return (time.hc - ((time.hc > 1292) << 1) - ((time.hc > 1310) << 1)) >> 2;
}
void bCPU::apu_sync() {
int cycles;
while(apusync.cycles >= 0) {
apu->run();
uint32 bCPU::cycles_executed() {
uint32 r = status.cycles_executed;
status.cycles_executed = 0;
return r;
}
cycles = apu->cycles_executed();
if(cycles) {
apusync.cycles -= apusync.cpu_multbl[cycles];
void bCPU::cycle_edge() {
if(time.hdmainit_triggered == false) {
if(time.hc >= time.hdmainit_trigger_pos || time.v) {
time.hdmainit_triggered = true;
hdmainit_activate();
}
}
}
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
time.dram_refresh_pos ^= 12;
if(time.hdma_triggered == false) {
if(time.v <= (overscan() ? 239 : 224)) {
if(time.hc >= 1106) {
time.hdma_triggered = true;
hdma_activate();
}
}
}
}
void bCPU::add_cycles(int cycles) {
cycles >>= 1;
while(cycles--) {
apusync.cycles += apusync.apu_freq << 1;
apu_sync();
time.hc += 2;
status.cycles_executed += cycles;
if(time.hc >= time.line_cycles) {
inc_vcounter();
if(time.v == 0) {
frame();
ppu->frame();
poll_interrupts(cycles);
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();
r_ppu->frame();
snes->frame();
}
scanline();
r_ppu->scanline();
snes->scanline();
time.line_rendered = false;
}
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;
}
}
}
scanline();
ppu->scanline();
}
if(time.dram_refreshed == false && time.hc >= time.dram_refresh_pos) {
dram_refresh();
}
if(hdma_test() == true) {
hdma_run();
}
}
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;
r_ppu->render_scanline();
}
}
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;
time.interlace_field = false;
time.overscan = false;
time.line_cycles = 1364;
time.frame_lines = 262;
time.dram_refreshed = false;
time.dram_refresh_pos = 538;
time.dram_refresh_pos = (cpu_version == 2) ? 538 : 530;
time.dma_counter = 0;
apusync.cycles = apusync.cpu_multbl[255];
}
//set at V=0,H=0
time.hdmainit_trigger_pos = 0;
time.hdmainit_triggered = true;
void bCPU::time_init() {
apusync.cpu_freq = 21477272 >> 3;
apusync.apu_freq = 24576000 >> 3;
time.hdma_triggered = false;
int i;
for(i=0;i<1024;i++) {
apusync.cpu_multbl[i] = i * apusync.cpu_freq;
apusync.apu_multbl[i] = i * apusync.apu_freq;
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;
break;
case PAL:
time.region_scanlines = 312;
break;
}
time.frame_lines = time.region_scanlines;
}
+47 -11
View File
@@ -4,11 +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;
}time;
uint16 hdmainit_trigger_pos;
bool hdmainit_triggered;
bool hdma_triggered;
uint16 region_scanlines;
//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();
@@ -16,6 +52,15 @@ inline uint16 hcycles();
inline bool interlace();
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);
@@ -24,15 +69,6 @@ inline uint8 dma_counter();
inline void inc_vcounter();
inline uint16 get_hcounter();
inline void apu_sync();
inline void dram_refresh();
inline void cycle_edge();
inline void add_cycles(int cycles);
inline void time_reset();
inline void time_init();
//APU synchronization
struct {
int32 cpu_freq, apu_freq;
int32 cpu_multbl[1024], apu_multbl[1024];
int32 cycles;
}apusync;
+16 -10
View File
@@ -44,7 +44,7 @@ char t[4096];
i++;
}
sprintf(output_op, "void bCPU::op_$$() {\r\n");
sprintf(output_op, "void bCPU::op_$$() {\r\n switch(status.cycle_pos++) {\r\n");
sprintf(output_header, "void op_$$();\r\n");
sprintf(output_table, "optbl[$0] = &bCPU::op_$$;\r\n");
@@ -53,9 +53,8 @@ char t[4096];
void update_line(int i, int n) {
char t[4096];
sprintf(t, "goto l%d;", n + 2);
replace(line[i], "end;", "return;");
replace(line[i], "skip;", t);
replace(line[i], "end;", "status.cycle_pos = 0;");
replace(line[i], "skip;", "status.cycle_pos++;");
}
void gen_op() {
@@ -67,12 +66,12 @@ char t[4096];
n = strdec(line[i]);
sprintf(t, "%d:", n);
strltrim(line[i], t);
sprintf(t, "l%d:\r\n", n);
sprintf(t, " case %d:\r\n", n);
strcat(output_op, t);
update_line(i, n);
if(strcmp(line[i], "")) {
strcat(output_op, " ");
strcat(output_op, " ");
strcat(output_op, line[i]);
strcat(output_op, "\r\n");
}
@@ -82,13 +81,20 @@ char t[4096];
if((strptr(line[i])[1]) == ':' || !strcmp(line[i], "}"))break;
update_line(i, n);
strcat(output_op, " ");
strcat(output_op, line[i]);
strcat(output_op, "\r\n");
i++;
}
if(!strcmp(line[i], "}")) {
strcat(output_op, " status.cycle_pos = 0;\r\n");
}
strcat(output_op, " break;\r\n");
}
strcat(output_op, "}");
strcat(output_op, " }\r\n}");
line_num = i + 1;
}
@@ -107,16 +113,16 @@ int i, l;
replace(t, "$5", op_list[i].arg[5]);
replace(t, "$6", op_list[i].arg[6]);
replace(t, "$7", op_list[i].arg[7]);
fprintf(fp, "%s\r\n\r\n", *t);
fprintf(fp, "%s\r\n\r\n", strptr(t));
strcpy(t, output_header);
replace(t, "$$", op_list[i].name);
fprintf(fph, "%s", *t);
fprintf(fph, "%s", strptr(t));
strcpy(t, output_table);
replace(t, "$$", op_list[i].name);
replace(t, "$0", op_list[i].arg[0]);
fprintf(fpt, "%s", *t);
fprintf(fpt, "%s", strptr(t));
}
}
Binary file not shown.
+58 -30
View File
@@ -1,15 +1,17 @@
nop(0xea) {
1:cpu_io();
1:last_cycle();
cpu_io();
}
wdm(0x42) {
1:cpu_io();
regs.pc.w++;
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;
@@ -27,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;
}
@@ -40,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;
@@ -49,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;
@@ -81,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) {
@@ -103,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);
@@ -116,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);
@@ -148,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);
@@ -161,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);
@@ -180,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),
@@ -196,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);
}
@@ -210,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);
}
@@ -218,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;
@@ -230,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) {
@@ -239,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) {
@@ -248,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);
}
+37 -15
View File
@@ -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++;
}
+68 -34
View File
@@ -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);
}
+20 -10
View File
@@ -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);
}
+60 -30
View File
@@ -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);
}
+1
View File
@@ -2,5 +2,6 @@
#include "dcpu.cpp"
CPU::CPU() {
cpu_version = 1;
mmio = &mmio_unmapped;
}
+33 -22
View File
@@ -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;
@@ -26,33 +32,37 @@ CPURegs regs;
};
virtual uint8 pio_status() = 0;
virtual void run() = 0;
virtual uint32 cycles_executed() = 0;
virtual void scanline() = 0;
virtual void frame() = 0;
virtual void power() = 0;
virtual void reset() = 0;
//opcode disassembler
enum {
OPTYPE_DP = 0, //dp
OPTYPE_DPX, //dp,x
OPTYPE_DPY, //dp,y
OPTYPE_IDP, //(dp)
OPTYPE_IDPX, //(dp,x)
OPTYPE_IDPY, //(dp),y
OPTYPE_ILDP, //[dp]
OPTYPE_ILDPY, //[dp],y
OPTYPE_ADDR, //addr
OPTYPE_ADDRX, //addr,x
OPTYPE_ADDRY, //addr,y
OPTYPE_IADDRX, //(addr,x)
OPTYPE_ILADDR, //[addr]
OPTYPE_LONG, //long
OPTYPE_LONGX, //long, x
OPTYPE_SR, //sr,s
OPTYPE_ISRY, //(sr,s),y
OPTYPE_ADDR_PC, //pbr:addr
OPTYPE_IADDR_PC //pbr:(addr)
};
enum {
OPTYPE_DP = 0, //dp
OPTYPE_DPX, //dp,x
OPTYPE_DPY, //dp,y
OPTYPE_IDP, //(dp)
OPTYPE_IDPX, //(dp,x)
OPTYPE_IDPY, //(dp),y
OPTYPE_ILDP, //[dp]
OPTYPE_ILDPY, //[dp],y
OPTYPE_ADDR, //addr
OPTYPE_ADDRX, //addr,x
OPTYPE_ADDRY, //addr,y
OPTYPE_IADDRX, //(addr,x)
OPTYPE_ILADDR, //[addr]
OPTYPE_LONG, //long
OPTYPE_LONGX, //long, x
OPTYPE_SR, //sr,s
OPTYPE_ISRY, //(sr,s),y
OPTYPE_ADDR_PC, //pbr:addr
OPTYPE_IADDR_PC //pbr:(addr)
};
//see dcpu.cpp for notes on this function
virtual bool in_opcode();
void disassemble_opcode(char *output);
uint32 resolve_offset(uint8 offset_type, uint32 addr);
uint8 opcode_length();
@@ -60,4 +70,5 @@ CPURegs regs;
uint16 __relw(int16 offset);
CPU();
virtual ~CPU() {}
};
+19 -9
View File
@@ -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); }
@@ -82,6 +91,7 @@ CPUReg24 pc;
CPUReg16 a, x, y, s, d;
CPURegFlags p;
uint8 db;
uint8 mdr; //memory data register (openbus)
bool e;
CPURegs() { db = 0; e = false; }
CPURegs() { db = 0; mdr = 0x00; e = false; }
};
+40 -14
View File
@@ -1,3 +1,17 @@
//this is a virtual function.
//in opcode-based CPU emulators, the main emulation routine
//will only be able to call the disassemble_opcode() function
//on clean opcode edges. but with cycle-based CPU emulators,
//the CPU may be in the middle of executing an opcode when the
//emulator (e.g. debugger) wants to disassemble an opcode. this
//would mean that important registers may not reflect what they
//did at the start of the opcode (especially regs.pc), so in
//cycle-based emulators, this function should be overridden to
//reflect whether or not an opcode has only been partially
//executed. if not, the debugger should abort attempts to skip,
//disable, or disassemble the current opcode.
bool CPU::in_opcode() { return false; }
uint16 CPU::__relb(int8 offset) {
uint32 addr;
addr = (regs.pc.d & 0xff0000) | ((regs.pc.d + 2) & 0xffff);
@@ -24,23 +38,23 @@ uint32 r = 0;
break;
case OPTYPE_IDP:
addr = (regs.d + (addr & 0xffff)) & 0xffff;
r = (regs.db << 16) + mem_bus->read_word(addr);
r = (regs.db << 16) + r_mem->read_word(addr);
break;
case OPTYPE_IDPX:
addr = (regs.d + regs.x + (addr & 0xffff)) & 0xffff;
r = (regs.db << 16) + mem_bus->read_word(addr);
r = (regs.db << 16) + r_mem->read_word(addr);
break;
case OPTYPE_IDPY:
addr = (regs.d + (addr & 0xffff)) & 0xffff;
r = (regs.db << 16) + mem_bus->read_word(addr) + regs.y;
r = (regs.db << 16) + r_mem->read_word(addr) + regs.y;
break;
case OPTYPE_ILDP:
addr = (regs.d + (addr & 0xffff)) & 0xffff;
r = mem_bus->read_long(addr);
r = r_mem->read_long(addr);
break;
case OPTYPE_ILDPY:
addr = (regs.d + (addr & 0xffff)) & 0xffff;
r = mem_bus->read_long(addr) + regs.y;
r = r_mem->read_long(addr) + regs.y;
break;
case OPTYPE_ADDR:
r = (regs.db << 16) + (addr & 0xffff);
@@ -74,23 +88,31 @@ uint32 r = 0;
break;
case OPTYPE_ISRY:
addr = (regs.s + (addr & 0xff)) & 0xffff;
r = (regs.db << 16) + mem_bus->read_word(addr) + regs.y;
r = (regs.db << 16) + r_mem->read_word(addr) + regs.y;
break;
}
return r;
}
void CPU::disassemble_opcode(char *output) {
char *s = output;
char *s;
char t[256];
uint8 op, op0, op1, op2;
sprintf(s, "%0.6x ", regs.pc.d);
static CPUReg24 pc;
s = output;
//TODO: This should wrap around the bank byte
op = mem_bus->read(regs.pc.d);
op0 = mem_bus->read(regs.pc.d + 1);
op1 = mem_bus->read(regs.pc.d + 2);
op2 = mem_bus->read(regs.pc.d + 3);
if(in_opcode() == true) {
strcpy(s, "?????? <CPU within opcode>");
return;
}
pc.d = regs.pc.d;
sprintf(s, "%0.6x ", pc.d);
op = r_mem->read(pc.d); pc.w++;
op0 = r_mem->read(pc.d); pc.w++;
op1 = r_mem->read(pc.d); pc.w++;
op2 = r_mem->read(pc.d);
switch(op) {
case 0x00:sprintf(t, "brk #$%0.2x ", op0);break;
@@ -431,7 +453,11 @@ static uint8 op_len_tbl[256] = {
6,2,2,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0xen
2,2,2,2, 3,2,2,2, 1,3,1,1, 3,3,3,4 //0xfn
};
op = mem_bus->read(regs.pc.d);
if(in_opcode() == true) {
return 0;
}
op = r_mem->read(regs.pc.d);
len = op_len_tbl[op];
if(len == 5)return (regs.p.m)?2:3;
if(len == 6)return (regs.p.x)?2:3;
+605
View File
@@ -0,0 +1,605 @@
#include "../../base.h"
#include "bdsp_tables.cpp"
uint8 bDSP::readb(uint16 addr) {
return spcram[addr];
}
void bDSP::writeb(uint16 addr, uint8 data) {
spcram[addr] = data;
}
uint16 bDSP::readw(uint16 addr) {
return (readb(addr)) | (readb(addr + 1) << 8);
}
void bDSP::writew(uint16 addr, uint16 data) {
writeb(addr, data);
writeb(addr + 1, 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;
break;
//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
//anomie's code breaks MK2 sound completely...
if(voice[v].SRCN != data) {
voice[v].SRCN = data;
voice[v].brr_ptr = readw((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 = r_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 = readw((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) {
//TRAC believes KON/KOFF is polled every sample. further testing is needed
if(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) {
//new KON code
status.ENDX &= ~mask;
status.kon &= ~mask;
voice[v].brr_ptr = readw((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();
}
}
//old KON code, breaks sound effects in DL / SFA2
// 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 = readb(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 = readb(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 = readw((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 = clip(15, 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) = readw((status.ESA << 8) + status.echo_index);
F(1,0) = readw((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);
writew((status.ESA << 8) + status.echo_index, esamplel);
writew((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
View 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 readb (uint16 addr);
uint16 readw (uint16 addr);
void writeb(uint16 addr, uint8 data);
void writew(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
View 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
};
+12
View File
@@ -0,0 +1,12 @@
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;
DSP() {}
virtual ~DSP() {}
};
+67 -11
View File
@@ -1,30 +1,86 @@
#define BSNES_VERSION "0.015"
#define BSNES_TITLE "bsnes v" BSNES_VERSION
#ifdef POLYMORPHISM
#define ref(x) x
#else
#define ref(x) (&x)
#endif
#define deref(x) __##x
#define r_mem ref(deref(mem))
#define r_cpu ref(deref(cpu))
#define r_apu ref(deref(apu))
#define r_dsp ref(deref(dsp))
#define r_ppu ref(deref(ppu))
#include "reader/reader.h"
#include "cart/cart.h"
#include "memory/memory.h"
#include "memory/bmemory/bmemory.h"
extern MMIO mmio_unmapped;
extern MemBus *mem_bus;
#include "cpu/cpu.h"
#include "cpu/bcpu/bcpu.h"
extern CPU *cpu;
#include "apu/apu.h"
#include "apu/bapu/bapu.h"
#include "apu/bapuskip/bapuskip.h"
extern APU *apu;
#include "dsp/dsp.h"
#include "dsp/bdsp/bdsp.h"
#include "ppu/ppu.h"
#include "ppu/bppu/bppu.h"
extern PPU *ppu;
#include "snes/snes.h"
#include "chip/srtc/srtc.h"
#include "chip/sdd1/sdd1.h"
#include "chip/c4/c4.h"
extern MMIO mmio_unmapped;
#ifdef POLYMORPHISM
extern MemBus *deref(mem);
extern CPU *deref(cpu);
extern APU *deref(apu);
extern DSP *deref(dsp);
extern PPU *deref(ppu);
#else
extern bMemBus deref(mem);
extern bCPU deref(cpu);
extern bAPU deref(apu);
extern bDSP deref(dsp);
extern bPPU deref(ppu);
#endif
extern SNES *snes;
extern SRTC *srtc;
extern SDD1 *sdd1;
extern C4 *c4;
#include "config/config.h"
#ifdef INTERFACE_MAIN
MemBus *mem_bus;
CPU *cpu;
APU *apu;
PPU *ppu;
SNES *snes;
Cartridge cartridge;
#include "config/config.cpp"
#ifdef POLYMORPHISM
MemBus *deref(mem);
CPU *deref(cpu);
APU *deref(apu);
DSP *deref(dsp);
PPU *deref(ppu);
#else
bMemBus deref(mem);
bCPU deref(cpu);
bAPU deref(apu);
bDSP deref(dsp);
bPPU deref(ppu);
#endif
SNES *snes;
SRTC *srtc;
SDD1 *sdd1;
C4 *c4;
#endif
+26 -10
View File
@@ -1,5 +1,5 @@
/*
libbase : version 0.01 ~byuu
libbase : version 0.03 ~byuu (08/20/05)
*/
#ifndef __LIBBASE
@@ -10,17 +10,33 @@
#include <stdarg.h>
#include <string.h>
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long ulong;
#ifndef TRUE
#define TRUE 1
#endif
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned long uint32;
#ifndef FALSE
#define FALSE 0
#endif
typedef signed char int8;
typedef signed short int16;
typedef signed long int32;
#define zerofree(__n) if(__n) { free(__n); __n = 0; }
typedef unsigned int uint;
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long ulong;
typedef unsigned long long uquad;
typedef unsigned char bool8;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned long uint32;
typedef unsigned long long uint64;
typedef signed char int8;
typedef signed short int16;
typedef signed long int32;
typedef signed long long int64;
#ifdef null
#undef null
+149 -263
View File
@@ -1,317 +1,203 @@
#include "libbase.h"
#include "libconfig.h"
//if this function returns true, the option is written
//to the configuration file. by always returning true,
//every option is always written. disable the first line
//to only output options after they have been changed by
//the program from their default values first.
bool config_item::changed() {
return true;
void Setting::toggle() {
data ^= 1;
set(data);
}
if(is_string == true) {
if(!strcmp(*strsource, strdef))return false;
return true;
uint Setting::get() {
return data;
}
void Setting::set(uint _data) {
data = _data;
if(type != DEC && type != HEX) {
//data is a boolean type
data &= 1;
}
return (*source != def);
}
config_item::config_item() {
strcpy(name, "");
strcpy(strdef, "");
is_string = false;
source = 0;
strsource = 0;
def = 0;
type = 0;
char *Setting::sget() {
return strptr(char_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++;
void Setting::sset(const char *_data) {
strcpy(char_data, _data);
strunquote(char_data);
}
void config::add(string *variable, char *name, char *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 = 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;
}
Setting::Setting(Config *_parent, char *_name, char *_desc, uint _data, uint _type) {
int s;
if(_parent) {
_parent->add(this);
}
return null;
}
uint32 config::get(char *name) {
int i = find(name);
if(i == null)return 0;
return *item[i]->source;
}
s = strlen(_name);
name = (char*)malloc(s + 1);
strcpy(name, _name);
string &config::strget(char *name) {
int i = find(name);
if(i == null) {
static string not_found;
strcmp(not_found, "");
return not_found;
if(_desc) {
s = strlen(_desc);
desc = (char*)malloc(s + 1);
strcpy(desc, _desc);
} else {
desc = (char*)malloc(1);
*desc = 0;
}
return *item[i]->strsource;
data = _data;
def = _data;
type = _type;
}
void config::set(char *name, uint32 value) {
int i = find(name);
if(i == null)return;
*item[i]->source = value;
Setting::Setting(Config *_parent, char *_name, char *_desc, char *_data) {
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;
}
strcpy(char_data, _data);
strcpy(char_def, _data);
type = STR;
}
void config::set(char *name, char *value) {
int i = find(name);
if(i == null)return;
strcpy(*item[i]->strsource, value);
void Config::add(Setting *setting) {
list[list_count++] = setting;
}
void config::load(char *fn) {
uint Config::string_to_uint(uint type, char *input) {
if(strmatch(input, "true") ||
strmatch(input, "enabled") ||
strmatch(input, "on") ||
strmatch(input, "yes")
) {
return (uint)true;
}
if(strmatch(input, "false") ||
strmatch(input, "disabled") ||
strmatch(input, "off") ||
strmatch(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(strqpos(line[i], "#") != null) {
strset(line[i], strqpos(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(*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(*part[1] + 2); //skip 0x prefix
} else { /* fall back on DEC */
*item[l]->source = strdec(part[1]);
for(int l = 0; l < list_count; l++) {
if(strmatch(list[l]->name, part[0])) {
if(list[l]->type != Setting::STR) {
list[l]->set(string_to_uint(list[l]->type, strptr(part[1])));
} else {
list[l]->sset(strptr(part[1]));
}
}
}
}
}
//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(strqpos(line[i], "#") != null) {
strset(line[i], strqpos(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(*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(strqpos(oldline[i], "#") != null) {
strcat(newline, " ");
strcat(newline, *oldline[i] + strqpos(oldline[i], "#"));
}
strcpy(line[i], newline);
split(line, "\n", data);
for(int l = 0; l < count(line); l++) {
fprintf(fp, "# %s\r\n", strptr(line[l]));
}
//write out the old config file + changes first
for(i=0;i<count(line);) {
fprintf(fp, "%s", *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");
if(list[i]->type != Setting::STR) {
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));
} else {
fprintf(fp, "# (default = \"%s\")\r\n", strptr(list[i]->char_def));
fprintf(fp, "%s = \"%s\"\r\n\r\n", list[i]->name, strptr(list[i]->char_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;
//...or if it is still set to the default value,
//then don't output it to the file here
if(item[i]->changed() == false)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", *newline);
lines_written++;
}
fclose(fp);
return true;
}
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;
}
+93 -34
View File
@@ -1,5 +1,5 @@
/*
libconfig : version 0.02 ~byuu
libconfig : version 0.05 ~byuu (10/30/05)
*/
#ifndef __LIBCONFIG
@@ -7,45 +7,104 @@
#include "libstring.h"
class config_item {
public:
uint32 *source, def, type;
string *strsource, strdef;
bool is_string;
string name;
bool changed();
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; } \
inline __name &operator=(const float _data) { set((uint)_data); return *this; } \
inline __name &operator=(const double _data) { set((uint)_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,
STR
};
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);
uint32 get(char *name);
string &strget(char *name);
void set(char *name, uint32 value);
void set(char *name, char *value);
char *name, *desc;
substring char_data, char_def;
virtual void toggle();
virtual uint get();
virtual void set(uint _data);
void load(char *fn);
void save(char *fn);
void set_newline(int i);
virtual char *sget();
virtual void sset(const char *_data);
config();
~config();
Setting(Config *_parent, char *_name, char *_desc, uint _data, uint _type);
Setting(Config *_parent, char *_name, char *_desc, char *_data);
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 operator float() { return (float) get(); }
inline operator double() { return (double)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; }
inline Setting &operator=(const float _data) { set((uint)_data); return *this; }
inline Setting &operator=(const double _data) { set((uint)_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
+166 -106
View File
@@ -1,23 +1,26 @@
#include "libbase.h"
#include "libstring.h"
_string::_string() {
substring::substring() {
size = 16;
s = (char*)malloc(size + 1);
*s = 0;
}
_string::~_string() {
free(s);
}
void string::addto(uint32 num) {
while(listcount < (num + 1)) {
list[listcount++] = new _string();
substring::~substring() {
if(s) {
free(s);
s = 0;
}
}
_string &string::str(uint32 num) {
void string::addto(uint num) {
while(listcount < (num + 1)) {
list[listcount++] = new substring();
}
}
substring &string::str(uint num) {
if(listcount < (num + 1)) { addto(num); }
return *list[num];
}
@@ -31,60 +34,90 @@ string::string() {
string::~string() {
int i;
for(i=listcount-1;i>=0;i--) {
delete((_string*)list[i]);
delete((substring*)list[i]);
}
}
uint32 count(string &str) {
return str.count;
char chrlower(char c) {
if(c >= 'A' && c <= 'Z')return c + ('a' - 'A');
return c;
}
void strresize(_string &str, uint32 size) {
char *t;
int sl;
if(str.size == size)return;
sl = strlen(str.s);
t = (char*)malloc(size + 1);
strcpy(t, str.s);
free(str.s);
str.s = t;
char chrupper(char c) {
if(c >= 'a' && c <= 'z')return c - ('a' - 'A');
return c;
}
uint count(string &str) { return str.count; }
void strresize(substring &str, uint size) {
str.s = (char*)realloc(str.s, size + 1);
str.s[size] = 0;
str.size = size;
}
char *strptr(_string &str) {
return str.s;
}
char *strptr(substring &str) { return str.s; }
void strcpy(_string &dest, char *src) {
uint strlen(substring &str) { return strlen(strptr(str)); }
int strcmp(substring &dest, const char *src) { return strcmp(strptr(dest), src); }
int strcmp(const char *dest, substring &src) { return strcmp(dest, strptr(src)); }
int strcmp(substring &dest, substring &src) { return strcmp(strptr(dest), strptr(src)); }
int __stricmp(const char *dest, const char *src) {
while(*dest && *src) {
if(chrlower(*dest) != chrlower(*src))break;
dest++;
src++;
}
return (int)chrlower(*dest) - (int)chrlower(*src);
}
int stricmp(substring &dest, const char *src) { return __stricmp(strptr(dest), src); }
int stricmp(const char *dest, substring &src) { return __stricmp(dest, strptr(src)); }
int stricmp(substring &dest, substring &src) { return __stricmp(strptr(dest), strptr(src)); }
bool strmatch(const char *dest, const char *src) { return !strcmp(dest, src); }
bool strmatch(substring &dest, const char *src) { return strmatch(strptr(dest), src); }
bool strmatch(const char *dest, substring &src) { return strmatch(dest, strptr(src)); }
bool strmatch(substring &dest, substring &src) { return strmatch(strptr(dest), strptr(src)); }
bool strimatch(const char *dest, const char *src) { return !stricmp(dest, src); }
bool strimatch(substring &dest, const char *src) { return strimatch(strptr(dest), src); }
bool strimatch(const char *dest, substring &src) { return strimatch(dest, strptr(src)); }
bool strimatch(substring &dest, substring &src) { return strimatch(strptr(dest), strptr(src)); }
void strcpy(substring &dest, const char *src) {
int srclen = strlen(src);
if(srclen > dest.size) { strresize(dest, srclen); }
strcpy(dest.s, src);
}
void strcpy(substring &dest, substring &src) { strcpy(dest, strptr(src)); }
void strset(_string &dest, uint32 pos, uint8 c) {
void strset(substring &dest, uint pos, uint8 c) {
char *s;
if(pos > dest.size) { strresize(dest, pos); }
dest.s[pos] = c;
}
void strcat(_string &dest, char *src) {
void strcat(substring &dest, const char *src) {
int srclen, destlen;
srclen = strlen(src);
destlen = strlen(dest.s);
if(srclen + destlen > dest.size) { strresize(dest, srclen + destlen); }
strcat(dest.s, src);
}
void strcat(substring &dest, substring &src) { strcat(dest, strptr(src)); }
void strinsert(_string &dest, char *src, uint32 pos) {
_string *s = new _string();
strcpy(*s, strptr(dest) + pos);
void strinsert(substring &dest, const char *src, uint pos) {
static substring s;
strcpy(s, strptr(dest) + pos);
strset(dest, pos, 0);
strcat(dest, src);
strcat(dest, *s);
delete(s);
strcat(dest, s);
}
void strinsert(substring &dest, substring &src, uint pos) { strinsert(dest, strptr(src), pos); }
void strremove(_string &dest, uint32 start, uint32 length) {
void strremove(substring &dest, uint start, uint length) {
int destlen;
char *s;
int i, sl = strlen(dest.s);
@@ -98,65 +131,62 @@ int i, sl = strlen(dest.s);
s[i] = 0;
}
bool stricmp(char *dest, char *src) {
int i, sl = strlen(dest);
if(sl != strlen(src))return false;
for(i=0;i<sl;i++) {
if(dest[i] >= 'A' && dest[i] <= 'Z') {
if(dest[i] != src[i] && dest[i] + 0x20 != src[i])return false;
} else if(dest[i] >='a' && dest[i] <= 'z') {
if(dest[i] != src[i] && dest[i] - 0x20 != src[i])return false;
} else {
if(dest[i] != src[i])return false;
}
}
return true;
}
void strlower(char *str) {
int i, sl = strlen(str);
for(i=0;i<sl;i++) {
if(str[i] >= 'A' && str[i] <= 'Z')str[i] += 0x20;
while(*str) {
*str = chrlower(*str);
str++;
}
}
void strlower(substring &str) { strlower(strptr(str)); }
void strupper(char *str) {
int i, sl = strlen(str);
for(i=0;i<sl;i++) {
if(str[i] >= 'a' && str[i] <= 'z')str[i] -= 0x20;
while(*str) {
*str = chrupper(*str);
str++;
}
}
void strupper(substring &str) { strupper(strptr(str)); }
uint32 strpos(char *str, char *key) {
bool strpos(const char *str, const char *key, uint &pos) {
int i, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return null;
for(i=0;i<=ssl-ksl;i++) {
if(!memcmp(str+i, key, ksl))return i;
if(ksl > ssl)return false;
for(i = 0; i <= ssl - ksl; i++) {
if(!memcmp(str + i, key, ksl)) {
pos = i;
return true;
}
}
return null;
return false;
}
bool strpos(substring &str, const char *key, uint &pos) { return strpos(strptr(str), key, pos); }
bool strpos(const char *str, substring &key, uint &pos) { return strpos(str, strptr(key), pos); }
bool strpos(substring &str, substring &key, uint &pos) { return strpos(strptr(str), strptr(key), pos); }
uint32 strqpos(char *str, char *key) {
bool qstrpos(const char *str, const char *key, uint &pos) {
int i, z, ssl = strlen(str), ksl = strlen(key);
uint8 x;
if(ksl > ssl)return null;
for(i=0;i<=ssl-ksl;) {
if(ksl > ssl)return false;
for(i = 0; i <= ssl - ksl;) {
x = str[i];
if(x == '\"' || x == '\'') {
z = i++;
while(str[i] != x && i < ssl)i++;
if(i >= ssl)i = z;
}
if(!memcmp(str+i, key, ksl)) {
return i;
if(!memcmp(str + i, key, ksl)) {
pos = i;
return true;
} else {
i++;
}
}
return null;
return false;
}
bool qstrpos(substring &str, const char *key, uint &pos) { return qstrpos(strptr(str), key, pos); }
bool qstrpos(const char *str, substring &key, uint &pos) { return qstrpos(str, strptr(key), pos); }
bool qstrpos(substring &str, substring &key, uint &pos) { return qstrpos(strptr(str), strptr(key), pos); }
void strtr(char *dest, char *before, char *after) {
void strtr(char *dest, const char *before, const char *after) {
int i, l, sl = strlen(dest), bsl = strlen(before), asl = strlen(after);
if((bsl != asl) || bsl == 0)return;
for(i=0;i<sl;i++) {
@@ -165,52 +195,55 @@ int i, l, sl = strlen(dest), bsl = strlen(before), asl = strlen(after);
}
}
}
void strtr(substring &dest, const char *before, const char *after) { strtr(strptr(dest), before, after); }
uint32 strbegin(char *str, char *key) {
bool strbegin(const char *str, const char *key) {
int i, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return 1;
if(!memcmp(str, key, ksl))return 0;
return 1;
if(ksl > ssl)return false;
return (!memcmp(str, key, ksl));
}
bool strbegin(substring &str, const char *key) { return strbegin(strptr(str), key); }
uint32 stribegin(char *str, char *key) {
bool stribegin(const char *str, const char *key) {
int i, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return 1;
if(ksl > ssl)return false;
for(i=0;i<ksl;i++) {
if(str[i] >= 'A' && str[i] <= 'Z') {
if(str[i] != key[i] && str[i]+0x20 != key[i])return 1;
if(str[i] != key[i] && str[i]+0x20 != key[i])return false;
} else if(str[i] >= 'a' && str[i] <= 'z') {
if(str[i] != key[i] && str[i]-0x20 != key[i])return 1;
if(str[i] != key[i] && str[i]-0x20 != key[i])return false;
} else {
if(str[i] != key[i])return 1;
if(str[i] != key[i])return false;
}
}
return 0;
return true;
}
bool stribegin(substring &str, const char *key) { return stribegin(strptr(str), key); }
uint32 strend(char *str, char *key) {
bool strend(const char *str, const char *key) {
int i, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return 1;
if(!memcmp(str + ssl - ksl, key, ksl))return 0;
return 1;
if(ksl > ssl)return false;
return (!memcmp(str + ssl - ksl, key, ksl));
}
bool strend(substring &str, const char *key) { return strend(strptr(str), key); }
uint32 striend(char *str, char *key) {
bool striend(const char *str, const char *key) {
int i, z, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return 1;
if(ksl > ssl)return false;
for(i=ssl-ksl, z=0;i<ssl;i++, z++) {
if(str[i] >= 'A' && str[i] <= 'Z') {
if(str[i] != key[z] && str[i]+0x20 != key[z])return 1;
if(str[i] != key[z] && str[i]+0x20 != key[z])return false;
} else if(str[i] >= 'a' && str[i] <= 'z') {
if(str[i] != key[z] && str[i]-0x20 != key[z])return 1;
if(str[i] != key[z] && str[i]-0x20 != key[z])return false;
} else {
if(str[i] != key[z])return 1;
if(str[i] != key[z])return false;
}
}
return 0;
return true;
}
bool striend(substring &str, const char *key) { return striend(strptr(str), key); }
void strltrim(char *str, char *key) {
void strltrim(char *str, const char *key) {
int i, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return;
if(!strbegin(str, key)) {
@@ -218,8 +251,9 @@ int i, ssl = strlen(str), ksl = strlen(key);
str[i] = 0;
}
}
void strltrim(substring &str, const char *key) { strltrim(strptr(str), key); }
void striltrim(char *str, char *key) {
void striltrim(char *str, const char *key) {
int i, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return;
if(!stribegin(str, key)) {
@@ -227,25 +261,28 @@ int i, ssl = strlen(str), ksl = strlen(key);
str[i] = 0;
}
}
void striltrim(substring &str, const char *key) { striltrim(strptr(str), key); }
void strrtrim(char *str, char *key) {
void strrtrim(char *str, const char *key) {
int ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return;
if(!strend(str, key)) {
str[ssl - ksl] = 0;
}
}
void strrtrim(substring &str, const char *key) { strrtrim(strptr(str), key); }
void strirtrim(char *str, char *key) {
void strirtrim(char *str, const char *key) {
int ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return;
if(!striend(str, key)) {
str[ssl - ksl] = 0;
}
}
void strirtrim(substring &str, const char *key) { strirtrim(strptr(str), key); }
/* does not work on type char* because function increases string length */
void strquote(_string &str) {
//does not work on type char* because function increases string length
void strquote(substring &str) {
static string t;
strcpy(t, "\"");
strcat(t, str);
@@ -255,15 +292,15 @@ static string t;
bool strunquote(char *str) {
int i, ssl = strlen(str);
/* make sure string is long enough to have quotes */
//make sure string is long enough to have quotes
if(ssl < 2)return false;
/* make sure string actually has quotes */
//make sure string actually has quotes
if(str[0] == '\"' && str[ssl - 1] == '\"');
else if(str[0] == '\'' && str[ssl - 1] == '\'');
else return false;
/* now remove them */
//now remove them
for(i=0;i<ssl;i++) {
str[i] = str[i + 1];
}
@@ -271,9 +308,10 @@ int i, ssl = strlen(str);
return true;
}
bool strunquote(substring &str) { return strunquote(strptr(str)); }
uint32 strhex(char *str) {
uint32 r = 0, m = 0;
uint strhex(const char *str) {
uint r = 0, m = 0;
int i, ssl = strlen(str);
uint8 x;
for(i=0;i<ssl;i++) {
@@ -292,31 +330,44 @@ uint8 x;
}
return r;
}
uint strhex(substring &str) { return strhex(strptr(str)); }
int strdec(char *str) {
uint32 m = 1;
int sstrhex(const char *str) {
if(str[0] == '-') {
return -strhex(str + 1);
}
return strhex(str);
}
int sstrhex(substring &str) { return sstrhex(strptr(str)); }
uint strdec(const char *str) {
uint m = 1;
int i, r = 0, ssl = strlen(str);
uint8 x;
for(i=0;i<ssl;i++) {
if(str[i] >= '0' && str[i] <= '9');
else if(str[i] == '-' && i == 0);
else break;
}
for(--i;i>=0;i--, m*=10) {
x = str[i];
if(x >= '0' && x <= '9')x -= '0';
else if(i == 0 && str[i] == '-') {
r *= -1;
return r;
}
else return r;
r += x * m;
}
return r;
}
uint strdec(substring &str) { return strdec(strptr(str)); }
uint32 strbin(char *str) {
uint32 r = 0, m = 0;
int sstrdec(const char *str) {
if(str[0] == '-') {
return -strdec(str + 1);
}
return strdec(str);
}
int sstrdec(substring &str) { return sstrdec(strptr(str)); }
uint strbin(const char *str) {
uint r = 0, m = 0;
int i, ssl = strlen(str);
uint8 x;
for(i=0;i<ssl;i++) {
@@ -331,6 +382,15 @@ uint8 x;
}
return r;
}
uint strbin(substring &str) { return strbin(strptr(str)); }
int sstrbin(const char *str) {
if(str[0] == '-') {
return -strbin(str + 1);
}
return strbin(str);
}
int sstrbin(substring &str) { return sstrbin(strptr(str)); }
#include "libstring_math.cpp"
#include "libstring_split.cpp"
+164 -229
View File
@@ -1,5 +1,5 @@
/*
libstring : version 0.05 ~byuu
libstring : version 0.07 ~byuu (11/30/05)
*/
#ifndef __LIBSTRING
@@ -8,247 +8,182 @@
#include "libvector.h"
class string;
class _string;
class substring;
uint32 count(string &str);
void strresize(_string &str, uint32 size);
char* strptr(_string &str);
void strcpy(_string &dest, char *src);
void strset(_string &dest, uint32 pos, uint8 c);
void strcat(_string &dest, char *src);
void strinsert(_string &dest, char *src, uint32 pos);
void strremove(_string &dest, uint32 start, uint32 length = 0);
bool stricmp(char *dest, char *src);
void strlower(char *str);
void strupper(char *str);
uint32 strpos(char *str, char *key);
uint32 strqpos(char *str, char *key);
void strtr(char *dest, char *before, char *after);
uint32 strbegin(char *str, char *key);
uint32 stribegin(char *str, char *key);
uint32 strend(char *str, char *key);
uint32 striend(char *str, char *key);
void strltrim(char *str, char *key);
void striltrim(char *str, char *key);
void strrtrim(char *str, char *key);
void strirtrim(char *str, char *key);
void strquote(_string &str);
bool strunquote(char *str);
uint32 strhex(char *str);
int strdec(char *str);
uint32 strbin(char *str);
uint32 strmath(char *in_str);
uint32 strmathentity(char *str);
void replace (_string &str, char *key, char *token);
void qreplace(_string &str, char *key, char *token);
void split (string &dest, char *key, char *src);
void qsplit(string &dest, char *key, char *src);
void sprintf(_string &str, char *s, ...);
char chrlower(char c);
char chrupper(char c);
class _string {
uint count(string &str);
void strresize(substring &str, uint size);
char* strptr(substring &str);
uint strlen(substring &str);
int strcmp(substring &dest, const char *src);
int strcmp(const char *dest, substring &src);
int strcmp(substring &dest, substring &src);
//vc6/win32 and gcc/dos only support stricmp, whereas
//gcc/unix only supports strcasecmp. this is an attempt
//to avoid platform-specific defines...
#define stricmp __stricmp
int __stricmp(const char *dest, const char *src);
int stricmp(substring &dest, const char *src);
int stricmp(const char *dest, substring &src);
int stricmp(substring &dest, substring &src);
bool strmatch(const char *dest, const char *src);
bool strmatch(substring &dest, const char *src);
bool strmatch(const char *dest, substring &src);
bool strmatch(substring &dest, substring &src);
bool strimatch(const char *dest, const char *src);
bool strimatch(substring &dest, const char *src);
bool strimatch(const char *dest, substring &src);
bool strimatch(substring &dest, substring &src);
void strcpy(substring &dest, const char *src);
void strcpy(substring &dest, substring &src);
void strset(substring &dest, uint pos, uint8 c);
void strcat(substring &dest, const char *src);
void strcat(substring &dest, substring &src);
void strinsert(substring &dest, const char *src, uint pos);
void strinsert(substring &dest, substring &src, uint pos);
void strremove(substring &dest, uint start, uint length = 0);
void strlower(char *str);
void strlower(substring &str);
void strupper(char *str);
void strupper(substring &str);
bool strpos(const char *str, const char *key, uint &pos);
bool strpos(substring &str, const char *key, uint &pos);
bool strpos(const char *str, substring &key, uint &pos);
bool strpos(substring &str, substring &key, uint &pos);
bool qstrpos(const char *str, const char *key, uint &pos);
bool qstrpos(substring &str, const char *key, uint &pos);
bool qstrpos(const char *str, substring &key, uint &pos);
bool qstrpos(substring &str, substring &key, uint &pos);
void strtr(char *dest, const char *before, const char *after);
void strtr(substring &dest, const char *before, const char *after);
bool strbegin(const char *str, const char *key);
bool strbegin(substring &str, const char *key);
bool stribegin(const char *str, const char *key);
bool stribegin(substring &str, const char *key);
bool strend(const char *str, const char *key);
bool strend(substring &str, const char *key);
bool striend(const char *str, const char *key);
bool striend(substring &str, const char *key);
void strltrim(char *str, const char *key);
void strltrim(substring &str, const char *key);
void striltrim(char *str, const char *key);
void striltrim(substring &str, const char *key);
void strrtrim(char *str, const char *key);
void strrtrim(substring &str, const char *key);
void strirtrim(char *str, const char *key);
void strirtrim(substring &str, const char *key);
void strquote(substring &str);
bool strunquote(char *str);
bool strunquote(substring &str);
uint strhex(const char *str);
uint strhex(substring &str);
int sstrhex(const char *str);
int sstrhex(substring &str);
uint strdec(const char *str);
uint strdec(substring &str);
int sstrdec(const char *str);
int sstrdec(substring &str);
uint strbin(const char *str);
uint strbin(substring &str);
int sstrbin(const char *str);
int sstrbin(substring &str);
uint strmath(const char *in_str);
uint strmath(substring &in_str);
bool strmathentity(const char *str);
bool strmathentity(substring &str);
void replace(substring &str, const char *key, const char *token);
void replace(substring &str, const char *key, substring &token);
void qreplace(substring &str, const char *key, const char *token);
void qreplace(substring &str, const char *key, substring &token);
void split(string &dest, const char *key, char *src);
void split(string &dest, const char *key, substring &src);
void qsplit(string &dest, const char *key, char *src);
void qsplit(string &dest, const char *key, substring &src);
void sprintf(substring &str, const char *s, ...);
class substring {
public:
char *s;
uint32 size;
inline char* operator*() { return s; }
uint size;
//inline char* operator*() { return s; }
//inline operator char*() { return s; }
#ifdef __LIBSTRING_OVERLOADS
inline _string& operator=(char *cpy);
inline _string& operator=(_string &cpy);
inline _string& operator=(string &cpy);
inline _string& operator+=(char *cat);
inline _string& operator+=(_string &cat);
inline _string& operator+=(string &cat);
inline _string& operator-=(char *cut);
inline _string& operator-=(_string &cut);
inline _string& operator-=(string &cut);
inline bool operator==(char *cmp);
inline bool operator==(_string &cmp);
inline bool operator==(string &cmp);
inline bool operator!=(char *cmp);
inline bool operator!=(_string &cmp);
inline bool operator!=(string &cmp);
#endif
inline operator char*() { return s; }
_string();
~_string();
substring();
~substring();
};
/* listcount is the actual size of list[], used for allocation
* of substrings.
* count is used by split() and count() to return the number of
* active/valid substrings. example: if string T contains 16
* substrings, and split is called, which sets three substrings,
* then count() needs to reflect that only three substrings are
* now used, but listcount still needs to reflect the true size
* of list[].
*/
class string {
public:
vector<_string*> list;
uint32 count, listcount;
void addto(uint32 num); //creates all needed strings to make list[num] valid
_string &str(uint32 num); //gets a _string reference, creating it + new strings if needed
vector<substring*> list;
uint listcount, count;
void addto(uint num); //creates all needed strings to make list[num] valid
substring &str(uint num); //gets a substring reference, creating it + new strings if needed
inline char* operator*() { return strptr(str(0)); }
#ifdef __LIBSTRING_OVERLOADS
inline string& operator=(char *cpy);
inline string& operator=(_string &cpy);
inline string& operator=(string &cpy);
inline string& operator+=(char *cat);
inline string& operator+=(_string &cat);
inline string& operator+=(string &cat);
inline string& operator-=(char *cut);
inline string& operator-=(_string &cut);
inline string& operator-=(string &cut);
inline bool operator==(char *cmp);
inline bool operator==(_string &cmp);
inline bool operator==(string &cmp);
inline bool operator!=(char *cmp);
inline bool operator!=(_string &cmp);
inline bool operator!=(string &cmp);
#endif
inline operator char*() { return str(0).s; }
inline operator _string&() { return str(0); }
inline _string& operator[](uint32 i) { return str(i); }
inline _string& operator[](int i) { return str(i); }
//inline char* operator*() { return strptr(str(0)); }
//inline operator char*() { return str(0).s; }
inline operator substring&() { return str(0); }
inline substring& operator[](uint i) { return str(i); }
inline substring& operator[](uint8 i) { return str(i); }
inline substring& operator[](uint16 i) { return str(i); }
inline substring& operator[](uint32 i) { return str(i); }
inline substring& operator[](int i) { return str(i); }
inline substring& operator[](int8 i) { return str(i); }
inline substring& operator[](int16 i) { return str(i); }
inline substring& operator[](int32 i) { return str(i); }
string();
~string();
};
#ifdef __LIBSTRING_OVERLOADS
inline _string& _string::operator=(char *cpy) {
strcpy(*this, cpy);
return *this;
}
inline _string& _string::operator=(_string &cpy) {
strcpy(*this, cpy);
return *this;
}
inline _string& _string::operator=(string &cpy) {
strcpy(*this, cpy.str(0));
return *this;
}
inline string& string::operator=(char *cpy) {
strcpy(str(0), cpy);
return *this;
}
inline string& string::operator=(_string &cpy) {
strcpy(str(0), cpy);
return *this;
}
inline string& string::operator=(string &cpy) {
strcpy(str(0), cpy.str(0));
return *this;
}
inline _string& _string::operator+=(char *cat) {
strcat(*this, cat);
return *this;
}
inline _string& _string::operator+=(_string &cat) {
strcat(*this, cat);
return *this;
}
inline _string& _string::operator+=(string &cat) {
strcat(*this, cat.str(0));
return *this;
}
inline string& string::operator+=(char *cat) {
strcat(str(0), cat);
return *this;
}
inline string& string::operator+=(_string &cat) {
strcat(str(0), cat);
return *this;
}
inline string& string::operator+=(string &cat) {
strcat(str(0), cat.str(0));
return *this;
}
inline _string& _string::operator-=(char *cut) {
strrtrim(*this, cut);
return *this;
}
inline _string& _string::operator-=(_string &cut) {
strrtrim(*this, cut);
return *this;
}
inline _string& _string::operator-=(string &cut) {
strrtrim(*this, cut.str(0));
return *this;
}
inline string& string::operator-=(char *cut) {
strrtrim(str(0), cut);
return *this;
}
inline string& string::operator-=(_string &cut) {
strrtrim(str(0), cut);
return *this;
}
inline string& string::operator-=(string &cut) {
strrtrim(str(0), cut.str(0));
return *this;
}
inline bool _string::operator==(char *cmp) {
if(!strcmp(*this, cmp))return true;
return false;
}
inline bool _string::operator==(_string &cmp) {
if(!strcmp(*this, cmp))return true;
return false;
}
inline bool _string::operator==(string &cmp) {
if(!strcmp(*this, cmp.str(0)))return true;
return false;
}
inline bool string::operator==(char *cmp) {
if(!strcmp(str(0), cmp))return true;
return false;
}
inline bool string::operator==(_string &cmp) {
if(!strcmp(str(0), cmp))return true;
return false;
}
inline bool string::operator==(string &cmp) {
if(!strcmp(str(0), cmp.str(0)))return true;
return false;
}
inline bool _string::operator!=(char *cmp) {
if(!strcmp(*this, cmp))return false;
return true;
}
inline bool _string::operator!=(_string &cmp) {
if(!strcmp(*this, cmp))return false;
return true;
}
inline bool _string::operator!=(string &cmp) {
if(!strcmp(*this, cmp.str(0)))return false;
return true;
}
inline bool string::operator!=(char *cmp) {
if(!strcmp(str(0), cmp))return false;
return true;
}
inline bool string::operator!=(_string &cmp) {
if(!strcmp(str(0), cmp))return false;
return true;
}
inline bool string::operator!=(string &cmp) {
if(!strcmp(str(0), cmp.str(0)))return false;
return true;
}
#endif //__LIBSTRING_OVERLOADS
#endif //__LIBSTRING
+13 -11
View File
@@ -43,10 +43,10 @@ strmath(str)
str, and returns numerical result
example: strmath("5+5")=10
***************************************/
uint32 p_strmath(char *str) {
int i = 0, ssl = strlen(str);
uint p_strmath(const char *str) {
int i = 0, ssl = strlen(str);
uint r, array[128], array_size = 0, z = 0;
uint8 x, mode = 0;
uint32 r, array[128], array_size = 0, z = 0;
uint8 array_gate[128];
char *s1;
if(!ssl)return 0;
@@ -95,11 +95,11 @@ char *s1;
return r;
}
uint32 strmath(char *in_str) {
uint32 r = 0;
uint32 pdepth = 0, cpdepth, maxpdepth = 0;
uint32 pstart, pend, spos;
int i, sc, sl = strlen(in_str);
uint strmath(const char *in_str) {
uint r = 0;
uint pdepth = 0, cpdepth, maxpdepth = 0;
uint pstart, pend, spos;
int i, sc, sl = strlen(in_str);
char *str = (char*)malloc(sl + 1), *str0;
char *pstr;
char num[64];
@@ -165,13 +165,15 @@ char num[64];
free(str);
return r;
}
uint strmath(substring &in_str) { return strmath(strptr(in_str)); }
uint32 strmathentity(char *str) {
bool strmathentity(const char *str) {
int i, ssl = strlen(str);
for(i=0;i<ssl;i++) {
if(str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/' ||
str[i] == '%' || str[i] == '&' || str[i] == '|' || str[i] == '^' ||
(str[i] == '<' && str[i+1] == '<') || (str[i] == '>' && str[i+1] == '>'))return 1;
(str[i] == '<' && str[i+1] == '<') || (str[i] == '>' && str[i+1] == '>'))return true;
}
return 0;
return false;
}
bool strmathentity(substring &str) { return strmathentity(strptr(str)); }
+8 -6
View File
@@ -1,6 +1,6 @@
void replace(_string &str, char *key, char *token) {
int i, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str);
uint32 replace_count = 0, size = ssl;
void replace(substring &str, const char *key, const char *token) {
int i, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str);
uint replace_count = 0, size = ssl;
char *data;
if(ksl > ssl)return;
if(tsl > ksl) { //the new string may be longer than the old string...
@@ -27,11 +27,12 @@ char *data;
strcpy(str, data);
free(data);
}
void replace(substring &str, const char *key, substring &token) { replace(str, key, strptr(token)); }
void qreplace(_string &str, char *key, char *token) {
int i, l, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str);
void qreplace(substring &str, const char *key, const char *token) {
int i, l, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str);
uint replace_count = 0, size = ssl;
uint8 x;
uint32 replace_count = 0, size = ssl;
char *data;
if(ksl > ssl)return;
if(tsl > ksl) {
@@ -80,3 +81,4 @@ char *data;
strcpy(str, data);
free(data);
}
void qreplace(substring &str, const char *key, substring &token) { qreplace(str, key, strptr(token)); }
+8 -6
View File
@@ -1,7 +1,7 @@
void split(string &dest, char *key, char *src) {
int i, ssl = strlen(src), ksl = strlen(key);
void split(string &dest, const char *key, char *src) {
int i, ssl = strlen(src), ksl = strlen(key);
uint lp = 0, split_count = 0;
uint8 x;
uint32 lp = 0, split_count = 0;
for(i=0;i<=ssl-ksl;) {
if(!memcmp(src + i, key, ksl)) {
x = src[i];
@@ -15,11 +15,12 @@ uint32 lp = 0, split_count = 0;
strcpy(dest[split_count++], src + lp);
dest.count = split_count;
}
void split(string &dest, const char *key, substring &src) { split(dest, key, strptr(src)); }
void qsplit(string &dest, char *key, char *src) {
int i, z, ssl = strlen(src), ksl = strlen(key);
void qsplit(string &dest, const char *key, char *src) {
int i, z, ssl = strlen(src), ksl = strlen(key);
uint lp = 0, split_count = 0;
uint8 x;
uint32 lp = 0, split_count = 0;
for(i=0;i<=ssl-ksl;) {
x = src[i];
if(x=='\"' || x=='\'') {
@@ -39,3 +40,4 @@ uint32 lp = 0, split_count = 0;
strcpy(dest[split_count++], src + lp);
dest.count = split_count;
}
void qsplit(string &dest, const char *key, substring &src) { qsplit(dest, key, strptr(src)); }
+4 -4
View File
@@ -1,5 +1,5 @@
void numtobin(char *s, uint32 num) {
uint32 mask = 0x80000000, len = 0, z = 0;
void numtobin(char *s, uint num) {
uint mask = 0x80000000, len = 0, z = 0;
for(;mask;mask>>=1,len++) { if(num&mask)break; }
len = 32 - len;
do {
@@ -9,7 +9,7 @@ uint32 mask = 0x80000000, len = 0, z = 0;
s[z] = 0;
}
void sprintf(_string &str, char *s, ...) {
void sprintf(substring &str, const char *s, ...) {
va_list args;
char t[2], n[256];
int i, l, sl, z;
@@ -17,7 +17,7 @@ uint8 pad_type, pad_len;
uint32 num;
char *r;
va_start(args, s);
strcpy(*str, "");
strcpy(str, "");
for(i=0;i<strlen(s);i++) {
if(s[i] == '%') {
i++;
+23 -18
View File
@@ -1,65 +1,70 @@
/*
libvector : version 0.01 ~byuu
libvector : version 0.03 ~byuu (08/16/05)
*/
#ifndef __LIBVECTOR
#define __LIBVECTOR
template<typename T> class vector {
public:
private:
T *array;
int size, sizelimit;
//find next array size that is a power of two
int findsize(int newsize) {
int r = 1;
while(r >= 1) {
r <<= 1;
if(r > sizelimit)return sizelimit;
if(r >= newsize)return r;
if(r > sizelimit)return sizelimit;
if(r >= newsize) return r;
}
return size;
}
public:
void resize(int newsize) {
T *newarray;
newsize = findsize(newsize);
if(newsize > sizelimit)newsize = sizelimit;
if(newsize == size)return;
newarray = (T*)malloc(sizeof(T) * newsize);
if(newsize >= size) {
memcpy(newarray, array, sizeof(T) * size);
} else {
memcpy(newarray, array, sizeof(T) * newsize);
}
free(array);
array = (T*)realloc(array, sizeof(T) * newsize);
array = newarray;
size = newsize;
if(newsize > size) {
for(int i=size;i<newsize;i+=sizeof(T)) {
array[i] = (T)0;
}
}
size = newsize;
}
vector(int newsize, int newsizelimit) {
size = newsize;
sizelimit = newsizelimit;
array = (T*)malloc(sizeof(T) * size);
array = (T*)calloc(size, sizeof(T));
}
vector(int newsize) {
size = newsize;
sizelimit = 1 << 24;
array = (T*)malloc(sizeof(T) * size);
array = (T*)calloc(size, sizeof(T));
}
vector() {
size = 16;
sizelimit = 1 << 24;
array = (T*)malloc(sizeof(T) * size);
array = (T*)calloc(size, sizeof(T));
}
~vector() {
if(array)free(array);
if(array) {
free(array);
array = 0;
}
}
//operator T() { return array[0]; }
inline T &operator[](int index) {
if(index >= size)resize(index + 1);
if(index > sizelimit)return array[size - 1];
+1 -1
View File
@@ -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);
+106
View File
@@ -0,0 +1,106 @@
void bCartExLoROM::write_protect(bool r) { write_protected = r; }
uint8 bCartExLoROM::read(uint32 addr) {
uint32 b, w;
addr &= 0xffffff;
b = (addr >> 16);
w = (addr & 0xffff);
//SRAM Region A
if((b & 0x7f) >= 0x30 && (b & 0x7f) <= 0x3f && (w & 0xe000) == 0x6000) {
b &= 0x7f;
if(b >= 0x30 && b <= 0x3f) {
if(sram_size) {
addr = (b - 0x30) * 0x2000 + (w - 0x6000);
addr &= (sram_size - 1);
return sram[addr];
} else {
return 0x00; //no SRAM available
}
} else {
return 0x00; //unmapped
}
}
//SRAM Region B
if(b >= 0x70 && b <= 0x7d) {
if(sram_size) {
addr = (addr & 0xffffff) - 0x700000;
addr &= (sram_size - 1);
return sram[addr];
} else {
return 0x00; //no SRAM available
}
}
if(b <= 0x3f) {
addr = (b << 15) | (addr & 0x7fff);
} else if(b <= 0x7f) {
addr &= 0x3fffff;
} else if(b <= 0xbf) {
b &= 0x7f;
addr = (b << 15) | (addr & 0x7fff);
} else {
addr = sdd1->offset(addr);
}
if(addr < rom_size)return rom[addr];
return 0x00;
}
void bCartExLoROM::write(uint32 addr, uint8 value) {
uint32 b, w;
addr &= 0xffffff;
b = (addr >> 16);
w = (addr & 0xffff);
//SRAM Region A
if((b & 0x7f) >= 0x30 && (b & 0x7f) <= 0x3f && (w & 0xe000) == 0x6000) {
b &= 0x7f;
if(b >= 0x30 && b <= 0x3f) {
if(sram_size) {
addr = (b - 0x30) * 0x2000 + (w - 0x6000);
addr &= (sram_size - 1);
sram[addr] = value;
return;
} else {
return; //no SRAM available
}
} else {
return; //unmapped
}
}
//SRAM Region B
if(b >= 0x70 && b <= 0x7d) {
if(sram_size) {
addr = (addr & 0xffffff) - 0x700000;
addr &= (sram_size - 1);
sram[addr] = value;
} else {
return; //no SRAM available
}
}
if(write_protected == true)return;
if(b <= 0x3f) {
addr = (b << 15) | (addr & 0x7fff);
} else if(b <= 0x7f) {
addr &= 0x3fffff;
} else if(b <= 0xbf) {
b &= 0x7f;
addr = (b << 15) | (addr & 0x7fff);
} else {
addr = sdd1->offset(addr);
}
if(addr < rom_size)rom[addr] = value;
}
void bCartExLoROM::set_cartinfo(CartInfo *ci) {
rom = ci->rom;
sram = ci->sram;
rom_size = ci->rom_size;
sram_size = ci->sram_size;
}
+14
View File
@@ -0,0 +1,14 @@
class bCartExLoROM : public Cart {
private:
bool write_protected;
public:
uint8 *rom, *sram;
uint32 rom_size, sram_size;
uint8 read (uint32 addr);
void write(uint32 addr, uint8 value);
void write_protect(bool r);
void set_cartinfo(CartInfo *ci);
bCartExLoROM() : write_protected(true) {}
};
+25 -5
View File
@@ -33,10 +33,13 @@ uint32 b, w;
}
}
addr &= 0x3fffff;
if(addr < rom_size)return rom[addr];
addr &= ROM_mask;
return 0x00;
if(addr >= P0_size) {
addr = P0_size + (addr & (P1_size - 1));
}
return rom[addr];
}
void bCartHiROM::write(uint32 addr, uint8 value) {
@@ -74,8 +77,14 @@ uint32 b, w;
}
if(write_protected == true)return;
addr &= 0x3fffff;
if(addr < rom_size)rom[addr] = value;
addr &= ROM_mask;
if(addr >= P0_size) {
addr = P0_size + (addr & (P1_size - 1));
}
rom[addr] = value;
}
void bCartHiROM::set_cartinfo(CartInfo *ci) {
@@ -83,4 +92,15 @@ void bCartHiROM::set_cartinfo(CartInfo *ci) {
sram = ci->sram;
rom_size = ci->rom_size;
sram_size = ci->sram_size;
//calculate highest power of 2, which is the size of the first ROM chip
P0_size = 0x800000;
while(!(rom_size & P0_size))P0_size >>= 1;
P1_size = rom_size - P0_size;
if(rom_size == P0_size) { //cart only contains one ROM chip
ROM_mask = (P0_size - 1);
} else { //cart contains two ROM chips
ROM_mask = (P0_size + P0_size - 1);
}
}
+3 -2
View File
@@ -1,12 +1,13 @@
class bCartHiROM : public Cart {
private:
bool write_protected;
bool write_protected;
uint32 P0_size, P1_size, ROM_mask;
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);
+42 -9
View File
@@ -6,6 +6,12 @@ uint32 b, w;
b = (addr >> 16);
w = (addr & 0xffff);
if(cartridge.cart.c4) {
if(!(b & 0x40) && w >= 0x6000 && w <= 0x7fff) {
return c4->read(w);
}
}
//SRAM Region A
if((b & 0x7f) >= 0x30 && (b & 0x7f) <= 0x3f && (w & 0xe000) == 0x6000) {
b &= 0x7f;
@@ -35,17 +41,20 @@ uint32 b, w;
if(w & 0x8000) {
b &= 0x7f;
b %= 0x60;
addr = (b << 15) | (addr & 0x7fff);
} else {
b &= 0x7f;
b %= 0x60;
if(b == 0x00)b = 0x60;
if(b == 0x00)b = 0x7f;
addr = (((b << 15) | (addr & 0x7fff)) - 0x8000);
}
if(addr < rom_size)return rom[addr];
return 0x00;
addr &= ROM_mask;
if(addr >= P0_size) {
addr = P0_size + (addr & (P1_size - 1));
}
return rom[addr];
}
void bCartLoROM::write(uint32 addr, uint8 value) {
@@ -54,6 +63,13 @@ uint32 b, w;
b = (addr >> 16);
w = (addr & 0xffff);
if(cartridge.cart.c4) {
if(!(b & 0x40) && w >= 0x6000 && w <= 0x7fff) {
c4->write(w, value);
return;
}
}
//SRAM Region A
if((b & 0x7f) >= 0x30 && (b & 0x7f) <= 0x3f && (w & 0xe000) == 0x6000) {
b &= 0x7f;
@@ -83,17 +99,23 @@ uint32 b, w;
}
if(write_protected == true)return;
if(w & 0x8000) {
b &= 0x7f;
b %= 0x60;
addr = (b << 15) | (addr & 0x7fff);
} else {
b &= 0x7f;
b %= 0x60;
if(b == 0x00)b = 0x60;
if(b == 0x00)b = 0x7f;
addr = (((b << 15) | (addr & 0x7fff)) - 0x8000);
}
if(addr < rom_size)rom[addr] = value;
addr &= ROM_mask;
if(addr >= P0_size) {
addr = P0_size + (addr & (P1_size - 1));
}
rom[addr] = value;
}
void bCartLoROM::set_cartinfo(CartInfo *ci) {
@@ -101,4 +123,15 @@ void bCartLoROM::set_cartinfo(CartInfo *ci) {
sram = ci->sram;
rom_size = ci->rom_size;
sram_size = ci->sram_size;
//calculate highest power of 2, which is the size of the first ROM chip
P0_size = 0x800000;
while(!(rom_size & P0_size))P0_size >>= 1;
P1_size = rom_size - P0_size;
if(rom_size == P0_size) { //cart only contains one ROM chip
ROM_mask = (P0_size - 1);
} else { //cart contains two ROM chips
ROM_mask = (P0_size + P0_size - 1);
}
}
+3 -2
View File
@@ -1,12 +1,13 @@
class bCartLoROM : public Cart {
private:
bool write_protected;
bool write_protected;
uint32 P0_size, P1_size, ROM_mask;
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);
+95 -139
View File
@@ -1,61 +1,18 @@
#include "../../base.h"
#include "bcart_lorom.cpp"
#include "bcart_hirom.cpp"
#include "bcart_exlorom.cpp"
#include "bcart_exhirom.cpp"
bool bMemBus::load_cart(Reader *rf) {
uint32 cksum, icksum, index;
char cart_title[24];
uint8 mapper;
if(rom_loaded == true)return false;
void bMemBus::load_cart() {
if(rom_loaded == true)return;
rf->read(&rom);
rom_size = rf->size();
if(rom_size < 32768)return false;
if(rom_size >= 0x410000) {
mapper = EXHIROM;
goto end;
}
if(rom_size < 65536) {
mapper = LOROM;
goto end;
}
cksum = rom[0xffdc] | (rom[0xffdd] << 8);
icksum = rom[0xffde] | (rom[0xffdf] << 8);
if(cksum + icksum == 0xffff) {
mapper = HIROM;
} else {
mapper = LOROM;
}
end:
switch(mapper) {
case LOROM: index = 0x007fc0;break;
case HIROM: index = 0x00ffc0;break;
case EXHIROM:index = 0x40ffc0;break;
}
memcpy(cart_title, (char*)rom + index, 21);
cart_title[21] = 0;
switch(rom[index + 0x18] & 7) {
case 0:sram_size = 0; break;
case 1:sram_size = 2 * 1024;break;
case 2:sram_size = 4 * 1024;break;
case 3:sram_size = 8 * 1024;break;
case 4:sram_size = 16 * 1024;break;
case 5:sram_size = 32 * 1024;break;
case 6:sram_size = 64 * 1024;break;
case 7:sram_size = 128 * 1024;break;
}
dprintf("* Image Name : \"%s\"", cart_title);
dprintf("* MAD : %0.2x", mapper);
dprintf("* SRAM Size : %dkb", sram_size / 1024);
uint8 *rom = cartridge.rom;
uint16 index = cartridge.cart.header_index;
dprintf("* Image Name : \"%s\"", cartridge.cart.name);
dprintf("* Region : %s", (cartridge.cart.region == Cartridge::NTSC) ? "NTSC" : "PAL");
dprintf("* MAD : %0.2x", cartridge.cart.mapper);
dprintf("* SRAM Size : %dkb", cartridge.cart.sram_size / 1024);
dprintf("* Reset:%0.4x NMI:%0.4x IRQ:%0.4x BRK[n]:%0.4x COP[n]:%0.4x BRK[e]:%0.4x COP[e]:%0.4x",
rom[index + 0x3c] | (rom[index + 0x3d] << 8), //Reset
rom[index + 0x2a] | (rom[index + 0x2b] << 8), //NMI
@@ -68,58 +25,42 @@ end:
dprintf("");
CartInfo ci;
ci.rom = rom;
ci.sram = sram;
ci.rom_size = rom_size;
ci.sram_size = sram_size;
ci.rom = cartridge.rom;
ci.sram = cartridge.sram;
ci.rom_size = cartridge.cart.rom_size;
ci.sram_size = cartridge.cart.sram_size;
switch(mapper) {
case LOROM: cart = new bCartLoROM(); break;
case HIROM: cart = new bCartHiROM(); break;
case EXHIROM:cart = new bCartExHiROM();break;
default:return false;
switch(cartridge.cart.mapper) {
case Cartridge::LOROM: cart = new bCartLoROM(); break;
case Cartridge::HIROM: cart = new bCartHiROM(); break;
case Cartridge::EXLOROM:cart = new bCartExLoROM();break;
case Cartridge::EXHIROM:cart = new bCartExHiROM();break;
default:return;
}
cart->set_cartinfo(&ci);
if(cartridge.cart.region == Cartridge::NTSC) {
snes->set_region(SNES::NTSC);
} else {
snes->set_region(SNES::PAL);
}
rom_loaded = true;
return true;
}
bool bMemBus::load_sram(Reader *rf) {
if(rom_loaded == false || sram_size == 0)return false;
rf->read(&sram, sram_size);
CartInfo ci;
ci.rom = rom;
ci.sram = sram;
ci.rom_size = rom_size;
ci.sram_size = sram_size;
cart->set_cartinfo(&ci);
return true;
}
bool bMemBus::save_sram(Writer *wf) {
if(rom_loaded == false || sram_size == 0)return false;
wf->write(sram, sram_size);
return true;
}
void bMemBus::unload_cart() {
if(rom_loaded == false)return;
if(rom) free(rom);
if(sram)free(sram);
delete(cart);
rom_loaded = false;
}
void bMemBus::get_cartinfo(CartInfo *ci) {
ci->rom = rom;
ci->sram = sram;
ci->rom_size = rom_size;
ci->sram_size = sram_size;
ci->rom = cartridge.rom;
ci->sram = cartridge.sram;
ci->rom_size = cartridge.cart.rom_size;
ci->sram_size = cartridge.cart.sram_size;
}
/***********************
@@ -139,70 +80,85 @@ void bMemBus::get_cartinfo(CartInfo *ci) {
***************************************/
uint8 bMemBus::read(uint32 addr) {
uint32 b, w, r;
addr &= 0xffffff;
b = (addr >> 16);
w = (addr & 0xffff);
uint8 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;
}
#ifdef DEBUGGER
snes->notify(SNES::MEM_READ, addr, r);
#endif
return 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;
}
#ifdef DEBUGGER
snes->notify(SNES::MEM_WRITE, addr, value);
#endif
}
void bMemBus::power() {
@@ -211,7 +167,7 @@ void bMemBus::power() {
}
void bMemBus::reset() {
fastROM = false;
set_speed(false);
}
bMemBus::bMemBus() {
@@ -221,5 +177,5 @@ bMemBus::bMemBus() {
}
bMemBus::~bMemBus() {
if(wram)free(wram);
zerofree(wram);
}
+14 -9
View File
@@ -1,23 +1,28 @@
#include "bcart_lorom.h"
#include "bcart_hirom.h"
#include "bcart_exlorom.h"
#include "bcart_exhirom.h"
class bMemBus : public MemBus {
public:
uint8 *rom, *sram, *wram;
uint32 rom_size, sram_size;
//rom_image is the actual image, including header.
//rom is the image sans header, which is actually
//just a pointer to rom_image (with no header), or
//rom_image + 512 (if a header is present).
//rom should never be allocated or released directly.
uint8 *wram;
bool rom_loaded;
enum { LOROM = 0x20, HIROM = 0x21, EXHIROM = 0x25 };
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);
void load_cart();
void unload_cart();
bool cart_loaded() { return rom_loaded; }
void get_cartinfo(CartInfo *ci);
void power();
void reset();
+40 -26
View File
@@ -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,40 +58,50 @@ 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;
}
}
MMIO mmio_unmapped;
uint8 MMIO::read (uint32 addr) { return 0x00; }
uint8 MMIO::read (uint32 addr) { return r_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;
}
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 +109,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 +120,10 @@ MemBus::MemBus() {
int i;
fastROM = false;
flush_mmio_mappers();
}
MemBus::~MemBus() {}
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;
}
+30 -18
View File
@@ -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,19 +31,31 @@ 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:
inline uint8 speed(uint32 addr) {
return speed_table[addr >> 9];
}
void set_speed(bool fast);
virtual void load_cart() = 0;
virtual void unload_cart() = 0;
virtual bool cart_loaded() = 0;
virtual void get_cartinfo(CartInfo *ci) = 0;
virtual void power() = 0;
virtual void reset() = 0;
MemBus();
~MemBus();
virtual ~MemBus() {}
};
+161 -123
View File
@@ -5,18 +5,40 @@
void bPPU::run() {}
void bPPU::scanline() {
_y = cpu->vcounter();
_screen_width = (regs.bg_mode == 5 || regs.bg_mode == 6)?512:256;
_interlace = cpu->interlace();
_interlace_field = cpu->interlace_field();
line.y = r_cpu->vcounter();
line.width = (regs.hires) ? 512 : 256;
line.interlace = r_cpu->interlace();
line.interlace_field = r_cpu->interlace_field();
if(_y == 0) {
if(line.y == 0) {
//RTO flag reset
regs.time_over = false;
regs.range_over = false;
}
if(_y == 1) {
int32 bg;
if(line.y == 1) {
//mosaic reset
for(bg=BG1;bg<=BG4;bg++) {
regs.bg_y[bg] = 1;
}
regs.mosaic_countdown = regs.mosaic_size + 1;
regs.mosaic_countdown--;
} else {
for(bg=BG1;bg<=BG4;bg++) {
if(!regs.mosaic_enabled[bg] || !regs.mosaic_countdown) {
regs.bg_y[bg] = line.y;
}
}
if(!regs.mosaic_countdown) {
regs.mosaic_countdown = regs.mosaic_size + 1;
}
regs.mosaic_countdown--;
}
if(line.y == 1) {
//OAM FirstSprite priority set
if(regs.oam_priority == true) {
regs.oam_firstsprite = (regs.oam_addr & 0xfe) >> 1;
@@ -25,65 +47,52 @@ void bPPU::scanline() {
}
}
if(_y == (cpu->overscan()?239:224) && regs.display_disabled == false) {
if(line.y == (r_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(line.y > 0 && line.y < (r_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;
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;
PPU::frame();
}
void bPPU::power() {
PPU::power();
memset(vram, 0, 65536);
memset(oam, 0, 544);
memset(cgram, 0, 512);
region = snes->region();
reset();
}
void bPPU::reset() {
memset(output->buffer, 0, 512 * 478 * 2);
PPU::reset();
frame();
memset(sprite_list, 0, sizeof(sprite_list));
//open bus support
regs.ppu1_mdr = 0xff;
regs.ppu2_mdr = 0xff;
//bg line counters
regs.bg_y[0] = 0;
regs.bg_y[1] = 0;
regs.bg_y[2] = 0;
regs.bg_y[3] = 0;
//$2100
regs.display_disabled = 0;
regs.display_brightness = 0;
@@ -108,13 +117,15 @@ void bPPU::reset() {
regs.bg_tilesize[BG4] = 0;
regs.bg3_priority = 0;
regs.bg_mode = 0;
regs.hires = false;
//$2106
regs.mosaic_size = 0;
regs.mosaic_enabled[BG1] = false;
regs.mosaic_enabled[BG2] = false;
regs.mosaic_enabled[BG3] = false;
regs.mosaic_enabled[BG4] = false;
regs.mosaic_size = 0;
regs.mosaic_enabled[BG1] = false;
regs.mosaic_enabled[BG2] = false;
regs.mosaic_enabled[BG3] = false;
regs.mosaic_enabled[BG4] = false;
regs.mosaic_countdown = 0;
//$2107-$210a
regs.bg_scaddr[BG1] = 0x0000;
@@ -133,6 +144,8 @@ void bPPU::reset() {
regs.bg_tdaddr[BG4] = 0x0000;
//$210d-$2114
regs.bg_ofslatch = 0x00;
regs.m7_hofs = regs.m7_vofs = 0x0000;
regs.bg_hofs[BG1] = regs.bg_vofs[BG1] = 0x0000;
regs.bg_hofs[BG2] = regs.bg_vofs[BG2] = 0x0000;
regs.bg_hofs[BG3] = regs.bg_vofs[BG3] = 0x0000;
@@ -152,6 +165,7 @@ void bPPU::reset() {
regs.mode7_hflip = false;
//$211b-$2120
regs.m7_latch = 0x00;
regs.m7a = 0x0000;
regs.m7b = 0x0000;
regs.m7c = 0x0000;
@@ -163,30 +177,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;
@@ -195,12 +212,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;
@@ -215,16 +232,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;
@@ -232,26 +249,28 @@ 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;
regs.color_g = 0x00;
regs.color_b = 0x00;
regs.color_r = 0x00;
regs.color_g = 0x00;
regs.color_b = 0x00;
regs.color_rgb = 0x0000;
//$2133
regs.mode7_extbg = false;
regs.overscan = false;
regs.scanlines = 224;
regs.oam_halve = false;
regs.interlace = false;
regs.mode7_extbg = false;
regs.pseudo_hires = false;
regs.overscan = false;
regs.scanlines = 224;
regs.oam_halve = false;
regs.interlace = false;
//$2137
regs.hcounter = 0;
@@ -267,27 +286,35 @@ void bPPU::reset() {
regs.time_over = false;
regs.range_over = false;
line.width = 256; //needed for clear_window_cache()
update_sprite_list_sizes();
clear_tiledata_cache();
clear_window_cache();
}
uint8 bPPU::vram_read(uint16 addr) {
uint8 r;
r = vram[addr];
#ifdef DEBUGGER
snes->notify(SNES::VRAM_READ, addr, r);
#endif
return r;
}
void bPPU::vram_write(uint16 addr, uint8 value) {
vram[addr] = value;
#ifdef DEBUGGER
snes->notify(SNES::VRAM_WRITE, addr, value);
#endif
}
uint8 bPPU::oam_read(uint16 addr) {
uint8 r;
if(addr >= 0x0200)addr = 0x0200 | (addr & 31);
r = oam[addr];
#ifdef DEBUGGER
snes->notify(SNES::OAM_READ, addr, r);
#endif
return r;
}
@@ -295,53 +322,63 @@ void bPPU::oam_write(uint16 addr, uint8 value) {
if(addr >= 0x0200)addr = 0x0200 | (addr & 31);
oam[addr] = value;
update_sprite_list(addr);
#ifdef DEBUGGER
snes->notify(SNES::OAM_WRITE, addr, value);
#endif
}
uint8 bPPU::cgram_read(uint16 addr) {
uint8 r;
r = cgram[addr & 511];
addr &= 511;
r = cgram[addr];
if(addr & 1) {
r &= 0x7f;
}
#ifdef DEBUGGER
snes->notify(SNES::CGRAM_READ, addr, r);
#endif
return r;
}
void bPPU::cgram_write(uint16 addr, uint8 value) {
cgram[addr & 511] = value;
addr &= 511;
if(addr & 1) {
value &= 0x7f;
}
cgram[addr] = value;
#ifdef DEBUGGER
snes->notify(SNES::CGRAM_WRITE, addr, value);
#endif
}
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);
init_tiledata_cache();
int i, l;
byte r, g, b;
double m;
int i, l;
uint8 r, g, b;
double m;
uint16 *ptr;
for(l=0;l<16;l++) {
mosaic_table[l] = (uint16*)memalloc(4096 * 2, "bPPU::mosaic_table[%2d]", l);
mosaic_table[l] = (uint16*)malloc(4096 * 2);
for(i=0;i<4096;i++) {
mosaic_table[l][i] = (i / (l + 1)) * (l + 1);
}
}
light_table = (uint16*)memalloc(16 * 65536 * 2, "bPPU::light_table");
ptr = (word*)light_table;
light_table = (uint16*)malloc(16 * 32768 * 2);
ptr = (uint16*)light_table;
for(l=0;l<16;l++) {
m = (double)l / 15.0;
for(i=0;i<65536;i++) {
for(i=0;i<32768;i++) {
r = (i ) & 31;
g = (i >> 5) & 31;
b = (i >> 10) & 31;
@@ -360,14 +397,15 @@ uint16 *ptr;
bPPU::~bPPU() {
delete(mmio);
if(vram) memfree(vram, "bPPU::vram");
if(oam) memfree(oam, "bPPU::oam");
if(cgram)memfree(cgram, "bPPU::cgram");
zerofree(vram);
zerofree(oam);
zerofree(cgram);
for(int i=0;i<16;i++) {
if(mosaic_table[i])memfree(mosaic_table[i], "bPPU::mosaic_table[%2d]", i);
zerofree(mosaic_table[i]);
}
if(light_table)memfree(light_table, "bPPU::light_table");
zerofree(light_table);
}
bPPUMMIO::bPPUMMIO(bPPU *_ppu) {
+40 -21
View File
@@ -11,9 +11,18 @@ bPPU *ppu;
class bPPU : public PPU {
public:
uint8 *vram, *oam, *cgram;
uint8 region;
enum { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5 };
enum { SC_32x32 = 0, SC_32x64 = 1, SC_64x32 = 2, SC_64x64 = 3 };
enum { NTSC = 0, PAL = 1 };
enum { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5, COL = 5 };
enum { SC_32x32 = 0, SC_64x32 = 1, SC_32x64 = 2, SC_64x64 = 3 };
struct {
uint32 y;
uint32 width;
bool interlace;
bool interlace_field;
} line;
struct sprite_item {
uint8 width, height;
@@ -23,14 +32,15 @@ struct sprite_item {
bool vflip, hflip;
uint8 palette;
uint8 priority;
}sprite_list[128];
} sprite_list[128];
struct {
int32 frameskip, frameskip_pos;
bool frameskip_changed;
}settings;
//open bus support
uint8 ppu1_mdr, ppu2_mdr;
//bg line counters
uint16 bg_y[4];
struct {
//$2100
bool display_disabled;
uint8 display_brightness;
@@ -51,10 +61,12 @@ struct {
bool bg_tilesize[4];
bool bg3_priority;
uint8 bg_mode;
bool hires;
//$2106
uint8 mosaic_size;
bool mosaic_enabled[4];
uint16 mosaic_countdown;
//$2107-$210a
uint16 bg_scaddr[4];
@@ -64,6 +76,8 @@ struct {
uint16 bg_tdaddr[4];
//$210d-$2114
uint8 bg_ofslatch;
uint16 m7_hofs, m7_vofs;
uint16 bg_hofs[4];
uint16 bg_vofs[4];
@@ -81,46 +95,47 @@ struct {
bool mode7_hflip;
//$211b-$2120
uint8 m7_latch;
uint16 m7a, m7b, m7c, m7d, m7x, m7y;
//$2121
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;
uint16 color_rgb;
//$2133
bool mode7_extbg;
bool pseudo_hires;
bool overscan;
uint16 scanlines;
bool oam_halve;
@@ -137,7 +152,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);
@@ -149,6 +164,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
@@ -217,7 +234,7 @@ struct {
void latch_counters();
/* PPU render functions */
//PPU render functions
#include "bppu_render.h"
@@ -226,13 +243,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.hires); }
bPPU();
~bPPU();
+331 -125
View File
@@ -1,6 +1,6 @@
void bPPU::latch_counters() {
regs.hcounter = cpu->hcounter();
regs.vcounter = cpu->vcounter();
regs.hcounter = r_cpu->hcounter();
regs.vcounter = r_cpu->vcounter();
regs.counters_latched = true;
}
@@ -16,6 +16,55 @@ uint16 addr;
return (addr << 1);
}
bool bPPU::vram_can_read() {
if(regs.display_disabled == true) {
return true;
}
uint16 v = r_cpu->vcounter();
uint16 hc = r_cpu->hcycles();
uint16 ls;
if(r_cpu->interlace() && !r_cpu->interlace_field()) {
ls = r_cpu->region_scanlines();
} else {
ls = r_cpu->region_scanlines() - 1;
}
if(v == ls && hc == 1362)return false;
if(v < (r_cpu->overscan() ? 239 : 224))return false;
if(v == (r_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 = r_cpu->vcounter();
uint16 hc = r_cpu->hcycles();
if(v == 0) {
if(hc <= 4)return true;
if(hc == 6) { value = r_cpu->regs.mdr; return true; }
return false;
}
if(v < (r_cpu->overscan() ? 240 : 225))return false;
if(v == (r_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,14 @@ void bPPU::mmio_w2105(uint8 value) {
regs.bg_tilesize[BG1] = !!(value & 0x10);
regs.bg3_priority = !!(value & 0x08);
regs.bg_mode = (value & 7);
regs.hires = (regs.bg_mode == 5 || regs.bg_mode == 6);
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
@@ -117,42 +174,56 @@ void bPPU::mmio_w210c(uint8 value) {
//BG1HOFS
void bPPU::mmio_w210d(uint8 value) {
regs.bg_hofs[BG1] = (value << 8) | (regs.bg_hofs[BG1] >> 8);
regs.m7_hofs = (value << 8) | regs.m7_latch;
regs.m7_latch = value;
regs.bg_hofs[BG1] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_hofs[BG1] >> 8) & 7);
regs.bg_ofslatch = value;
}
//BG1VOFS
void bPPU::mmio_w210e(uint8 value) {
regs.bg_vofs[BG1] = (value << 8) | (regs.bg_vofs[BG1] >> 8);
regs.m7_vofs = (value << 8) | regs.m7_latch;
regs.m7_latch = value;
regs.bg_vofs[BG1] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_vofs[BG1] >> 8) & 7);
regs.bg_ofslatch = value;
}
//BG2HOFS
void bPPU::mmio_w210f(uint8 value) {
regs.bg_hofs[BG2] = (value << 8) | (regs.bg_hofs[BG2] >> 8);
regs.bg_hofs[BG2] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_hofs[BG2] >> 8) & 7);
regs.bg_ofslatch = value;
}
//BG2VOFS
void bPPU::mmio_w2110(uint8 value) {
regs.bg_vofs[BG2] = (value << 8) | (regs.bg_vofs[BG2] >> 8);
regs.bg_vofs[BG2] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_vofs[BG2] >> 8) & 7);
regs.bg_ofslatch = value;
}
//BG3HOFS
void bPPU::mmio_w2111(uint8 value) {
regs.bg_hofs[BG3] = (value << 8) | (regs.bg_hofs[BG3] >> 8);
regs.bg_hofs[BG3] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_hofs[BG3] >> 8) & 7);
regs.bg_ofslatch = value;
}
//BG3VOFS
void bPPU::mmio_w2112(uint8 value) {
regs.bg_vofs[BG3] = (value << 8) | (regs.bg_vofs[BG3] >> 8);
regs.bg_vofs[BG3] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_vofs[BG3] >> 8) & 7);
regs.bg_ofslatch = value;
}
//BG4HOFS
void bPPU::mmio_w2113(uint8 value) {
regs.bg_hofs[BG4] = (value << 8) | (regs.bg_hofs[BG4] >> 8);
regs.bg_hofs[BG4] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_hofs[BG4] >> 8) & 7);
regs.bg_ofslatch = value;
}
//BG4VOFS
void bPPU::mmio_w2114(uint8 value) {
regs.bg_vofs[BG4] = (value << 8) | (regs.bg_vofs[BG4] >> 8);
regs.bg_vofs[BG4] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_vofs[BG4] >> 8) & 7);
regs.bg_ofslatch = value;
}
//VMAIN
@@ -171,77 +242,97 @@ 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
void bPPU::mmio_w211a(uint8 value) {
regs.mode7_repeat = (value >> 6) & 3;
regs.mode7_vflip = !!(value & 0x02);
regs.mode7_hflip = !!(value & 0x01);
regs.mode7_vflip = !!(value & 0x02);
regs.mode7_hflip = !!(value & 0x01);
}
//M7A
void bPPU::mmio_w211b(uint8 value) {
regs.m7a = (value << 8) | (regs.m7a >> 8);
regs.m7a = (value << 8) | regs.m7_latch;
regs.m7_latch = value;
}
//M7B
void bPPU::mmio_w211c(uint8 value) {
regs.m7b = (value << 8) | (regs.m7b >> 8);
regs.m7b = (value << 8) | regs.m7_latch;
regs.m7_latch = value;
}
//M7C
void bPPU::mmio_w211d(uint8 value) {
regs.m7c = (value << 8) | (regs.m7c >> 8);
regs.m7c = (value << 8) | regs.m7_latch;
regs.m7_latch = value;
}
//M7D
void bPPU::mmio_w211e(uint8 value) {
regs.m7d = (value << 8) | (regs.m7d >> 8);
regs.m7d = (value << 8) | regs.m7_latch;
regs.m7_latch = value;
}
//M7X
void bPPU::mmio_w211f(uint8 value) {
regs.m7x = (value << 8) | (regs.m7x >> 8);
regs.m7x = (value << 8) | regs.m7_latch;
regs.m7_latch = value;
}
//M7Y
void bPPU::mmio_w2120(uint8 value) {
regs.m7y = (value << 8) | (regs.m7y >> 8);
regs.m7y = (value << 8) | regs.m7_latch;
regs.m7_latch = value;
}
//CGADD
@@ -250,7 +341,13 @@ void bPPU::mmio_w2121(uint8 value) {
}
//CGDATA
//note: CGRAM palette data format is 15-bits
//(0,bbbbb,ggggg,rrrrr). Highest bit is ignored,
//as evidenced by $213b CGRAM data reads.
void bPPU::mmio_w2122(uint8 value) {
if(regs.cgram_addr & 1) {
value &= 0x7f;
}
cgram_write(regs.cgram_addr, value);
regs.cgram_addr++;
regs.cgram_addr &= 0x01ff;
@@ -258,72 +355,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
@@ -346,20 +488,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
@@ -367,18 +521,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
@@ -386,119 +543,148 @@ void bPPU::mmio_w2132(uint8 value) {
if(value & 0x80)regs.color_b = value & 0x1f;
if(value & 0x40)regs.color_g = value & 0x1f;
if(value & 0x20)regs.color_r = value & 0x1f;
regs.color_rgb = (regs.color_r) | (regs.color_g << 5) | (regs.color_b << 10);
}
//SETINI
void bPPU::mmio_w2133(uint8 value) {
regs.mode7_extbg = !!(value & 0x40);
regs.overscan = !!(value & 0x04);
regs.scanlines = (value & 0x04)?239:224;
regs.oam_halve = !!(value & 0x02);
regs.interlace = !!(value & 0x01);
regs.mode7_extbg = !!(value & 0x40);
regs.pseudo_hires = !!(value & 0x08);
regs.overscan = !!(value & 0x04);
regs.scanlines = (value & 0x04)?239:224;
regs.oam_halve = !!(value & 0x02);
regs.interlace = !!(value & 0x01);
cpu->set_overscan(regs.overscan);
cpu->set_interlace(regs.interlace);
r_cpu->set_overscan(regs.overscan);
r_cpu->set_interlace(regs.interlace);
}
//MPYL
uint8 bPPU::mmio_r2134() {
uint32 r;
r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
return (r);
regs.ppu1_mdr = r;
return regs.ppu1_mdr;
}
//MPYM
uint8 bPPU::mmio_r2135() {
uint32 r;
r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
return (r >> 8);
regs.ppu1_mdr = r >> 8;
return regs.ppu1_mdr;
}
//MPYH
uint8 bPPU::mmio_r2136() {
uint32 r;
r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
return (r >> 16);
regs.ppu1_mdr = r >> 16;
return regs.ppu1_mdr;
}
//SLHV
uint8 bPPU::mmio_r2137() {
if(cpu->pio_status() & 0x80) {
if(r_cpu->pio_status() & 0x80) {
latch_counters();
}
return 0x00;
return r_cpu->regs.mdr;
}
//OAMDATAREAD
uint8 bPPU::mmio_r2138() {
uint8 r;
r = oam_read(regs.oam_addr);
regs.ppu1_mdr = oam_read(regs.oam_addr);
if(!(regs.oam_addr & 1)) {
regs.oam_latchdata = r;
regs.oam_latchdata = regs.ppu1_mdr;
}
regs.oam_addr++;
regs.oam_addr &= 0x03ff;
return r;
return regs.ppu1_mdr;
}
//VMDATALREAD
uint8 bPPU::mmio_r2139() {
uint16 addr = get_vram_address();
uint8 r = regs.vram_readbuffer;
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 r;
return regs.ppu1_mdr;
}
//VMDATAHREAD
uint8 bPPU::mmio_r213a() {
uint16 addr = get_vram_address() + 1;
uint8 r = regs.vram_readbuffer >> 8;
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 r;
return regs.ppu1_mdr;
}
//CGDATAREAD
//note: CGRAM palette data is 15-bits (0,bbbbb,ggggg,rrrrr)
//therefore, the high byte read from each color does not
//update bit 7 of the PPU2 MDR.
uint8 bPPU::mmio_r213b() {
uint8 r;
r = cgram_read(regs.cgram_addr);
if(!(regs.cgram_addr & 1)) {
regs.ppu2_mdr = cgram_read(regs.cgram_addr) & 0xff;
} else {
regs.ppu2_mdr &= 0x80;
regs.ppu2_mdr |= cgram_read(regs.cgram_addr) & 0x7f;
}
regs.cgram_addr++;
regs.cgram_addr &= 0x01ff;
return r;
return regs.ppu2_mdr;
}
//OPHCT
uint8 bPPU::mmio_r213c() {
uint16 r = regs.hcounter;
if(regs.latch_hcounter)r >>= 8;
if(!regs.latch_hcounter) {
regs.ppu2_mdr = regs.hcounter & 0xff;
} else {
regs.ppu2_mdr &= 0xfe;
regs.ppu2_mdr |= (regs.hcounter >> 8) & 1;
}
regs.latch_hcounter ^= 1;
return r;
return regs.ppu2_mdr;
}
//OPVCT
uint8 bPPU::mmio_r213d() {
uint16 r = regs.vcounter;
if(regs.latch_vcounter)r >>= 8;
if(!regs.latch_vcounter) {
regs.ppu2_mdr = regs.vcounter & 0xff;
} else {
regs.ppu2_mdr &= 0xfe;
regs.ppu2_mdr |= (regs.vcounter >> 8) & 1;
}
regs.latch_vcounter ^= 1;
return r;
return regs.ppu2_mdr;
}
//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
return r;
r |= (regs.time_over) ? 0x80 : 0x00;
r |= (regs.range_over) ? 0x40 : 0x00;
r |= (ppu1_version & 0x0f);
regs.ppu1_mdr = r;
return regs.ppu1_mdr;
}
//STAT78
@@ -507,21 +693,41 @@ uint8 r = 0x00;
regs.latch_hcounter = 0;
regs.latch_vcounter = 0;
r |= cpu->interlace_field() << 7;
if(!(cpu->pio_status() & 0x80)) {
r |= 1 << 6;
r |= r_cpu->interlace_field() << 7;
if(!(r_cpu->pio_status() & 0x80)) {
r |= 0x40;
} else if(regs.counters_latched == true) {
r |= 1 << 6;
r |= 0x40;
regs.counters_latched = false;
}
r |= (1 << 5);
r |= 0x03; //PPU2 version number
return r;
r |= (regs.ppu2_mdr & 0x20);
r |= (region << 4); //0 = NTSC, 1 = PAL
r |= (ppu2_version & 0x0f);
regs.ppu2_mdr = r;
return regs.ppu2_mdr;
}
uint8 bPPUMMIO::read(uint32 addr) {
//cpu->sync();
switch(addr) {
case 0x2104:
case 0x2105:
case 0x2106:
case 0x2108:
case 0x2109:
case 0x210a:
case 0x2114:
case 0x2115:
case 0x2116:
case 0x2118:
case 0x2119:
case 0x211a:
case 0x2124:
case 0x2125:
case 0x2126:
case 0x2128:
case 0x2129:
case 0x212a:
return ppu->regs.ppu1_mdr;
case 0x2134:return ppu->mmio_r2134(); //MPYL
case 0x2135:return ppu->mmio_r2135(); //MPYM
case 0x2136:return ppu->mmio_r2136(); //MPYH
@@ -535,11 +741,11 @@ uint8 bPPUMMIO::read(uint32 addr) {
case 0x213e:return ppu->mmio_r213e(); //STAT77
case 0x213f:return ppu->mmio_r213f(); //STAT78
}
return 0x00;
return r_cpu->regs.mdr;
}
void bPPUMMIO::write(uint32 addr, uint8 value) {
//cpu->sync();
switch(addr) {
case 0x2100:ppu->mmio_w2100(value);return; //INIDISP
case 0x2101:ppu->mmio_w2101(value);return; //OBSEL
+55 -24
View File
@@ -6,6 +6,40 @@
#include "bppu_render_addsub.cpp"
#include "bppu_render_line.cpp"
bool bPPU::render_enabled(uint8 bg, uint8 pri) {
switch(bg) {
case BG1:
switch(pri) {
case 0: return config::ppu.bg1_pri0_enable;
case 1: return config::ppu.bg1_pri1_enable;
} break;
case BG2:
switch(pri) {
case 0: return config::ppu.bg2_pri0_enable;
case 1: return config::ppu.bg2_pri1_enable;
} break;
case BG3:
switch(pri) {
case 0: return config::ppu.bg3_pri0_enable;
case 1: return config::ppu.bg3_pri1_enable;
} break;
case BG4:
switch(pri) {
case 0: return config::ppu.bg4_pri0_enable;
case 1: return config::ppu.bg4_pri1_enable;
} break;
case OAM:
switch(pri) {
case 0: return config::ppu.oam_pri0_enable;
case 1: return config::ppu.oam_pri1_enable;
case 2: return config::ppu.oam_pri2_enable;
case 3: return config::ppu.oam_pri3_enable;
} break;
}
return true;
}
/*
Mode 0: ->
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
@@ -20,28 +54,25 @@ inline void bPPU::render_line_mode0() {
}
/*
Mode 1 (pri=0): ->
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
BG3B, OAM0, BG3A, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3
Mode 1 (pri=1): ->
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
BG3B, OAM0, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3, BG3A
Mode 1 (pri=0): ->
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
BG3B, OAM0, BG3A, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3
*/
inline void bPPU::render_line_mode1() {
switch(regs.bg3_priority) {
case 0:
render_line_bg(BG1, COLORDEPTH_16, 6, 9);
render_line_bg(BG2, COLORDEPTH_16, 5, 8);
render_line_bg(BG3, COLORDEPTH_4, 1, 3);
render_line_oam(2, 4, 7, 10);
break;
case 1:
if(regs.bg3_priority) {
render_line_bg(BG1, COLORDEPTH_16, 5, 8);
render_line_bg(BG2, COLORDEPTH_16, 4, 7);
render_line_bg(BG3, COLORDEPTH_4, 1, 10);
render_line_oam(2, 3, 6, 9);
break;
} else {
render_line_bg(BG1, COLORDEPTH_16, 6, 9);
render_line_bg(BG2, COLORDEPTH_16, 5, 8);
render_line_bg(BG3, COLORDEPTH_4, 1, 3);
render_line_oam(2, 4, 7, 10);
}
}
@@ -104,32 +135,31 @@ 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(output + (line.y * 1024), 0, 1024);
return;
}
clear_pixel_cache();
build_color_window_tables();
build_window_tables(COL);
update_bg_info();
switch(regs.bg_mode) {
case 0:render_line_mode0();break;
case 1:render_line_mode1();break;
@@ -140,5 +170,6 @@ void bPPU::render_line() {
case 6:render_line_mode6();break;
case 7:render_line_mode7();break;
}
render_line_output();
}
+35 -25
View File
@@ -1,8 +1,5 @@
//bppu_render.cpp
int _screen_width;
bool _interlace;
int _interlace_field;
inline bool render_enabled(uint8 bg, uint8 pri);
inline void render_line_mode0();
inline void render_line_mode1();
inline void render_line_mode2();
@@ -16,36 +13,45 @@ inline void render_line_mode7();
enum { COLORDEPTH_4 = 0, COLORDEPTH_16 = 1, COLORDEPTH_256 = 2 };
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;
//color_exemption -- true when bg == OAM && palette index >= 192, disables color add/sub effects
uint8 ce_main, ce_sub;
//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[256];
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[256], sub[256];
} 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
struct {
uint16 tw, th; //tile width, height
uint16 mx, my; //screen mask x, y
} bg_info[4];
inline void update_bg_info();
inline uint16 bg_get_tile(uint8 bg, uint16 x, uint16 y);
void render_line_bg(uint8 bg, uint8 color_depth, uint8 pri0_pos, uint8 pri1_pos);
//bppu_render_oam.cpp
@@ -55,26 +61,30 @@ 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];
uint8 oam_line_pal[256], oam_line_pri[256];
bool is_sprite_on_scanline();
void load_oam_tiles();
void render_oam_tile(int tile_num);
void render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos);
void render_line_oam_lores(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 x, uint32 cdest, uint32 csrc, bool halve);
//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_pixel(int x);
inline uint16 get_palette(uint8 index);
inline uint16 get_direct_color(uint8 p, uint8 t);
inline uint16 get_pixel_normal(uint32 x);
inline uint16 get_pixel_swap(uint32 x);
inline uint16 get_pixel_lores(uint32 x);
inline uint16 get_pixel_hires(uint32 x);
inline void render_line_output();
+20 -100
View File
@@ -1,109 +1,29 @@
inline uint16 bPPU::addsub_pixels(int cdest_index, int cdest_bg, int csrc_index, int csrc_bg) {
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;
}
}
inline uint16 bPPU::addsub_pixels(uint32 x, uint32 cdest, uint32 csrc, bool halve) {
if(!regs.color_mode) {
//add
cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
cdest += csrc;
switch(regs.color_mode) {
case 0: //COLORMODE_ADD:
if(regs.color_halve == true) {
cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
cdest += csrc;
cdest >>= 1;
cdest &= 0x03e07c1f;
return (cdest >> 16) | cdest;
} else {
cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
cdest += csrc;
if(!halve) {
if(cdest & 0x04000000)cdest |= 0x03e00000;
if(cdest & 0x00008000)cdest |= 0x00007c00;
if(cdest & 0x00000020)cdest |= 0x0000001f;
cdest &= 0x03e07c1f;
return (cdest >> 16) | cdest;
}
break;
case 1: //COLORMODE_SUB:
if(regs.color_halve == true) {
if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00;
else cdest -= (csrc & 0x7c00);
if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0;
else cdest -= (csrc & 0x03e0);
if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f;
else cdest -= (csrc & 0x001f);
return (cdest & 0x7bde) >> 1;
} else {
if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00;
else cdest -= (csrc & 0x7c00);
if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0;
else cdest -= (csrc & 0x03e0);
if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f;
else cdest -= (csrc & 0x001f);
return cdest;
}
break;
}
return 0x0000; //prevent annoying warning message
}
inline uint16 bPPU::addsub_pixel(int cdest_index, int cdest_bg) {
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) {
cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
cdest += csrc;
cdest >>= 1;
cdest &= 0x03e07c1f;
return (cdest >> 16) | cdest;
} else {
cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
cdest += csrc;
if(cdest & 0x04000000)cdest |= 0x03e00000;
if(cdest & 0x00008000)cdest |= 0x00007c00;
if(cdest & 0x00000020)cdest |= 0x0000001f;
cdest &= 0x03e07c1f;
return (cdest >> 16) | cdest;
}
break;
case 1: //COLORMODE_SUB:
if(regs.color_halve == true && regs.addsub_mode == 0) {
if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00;
else cdest -= (csrc & 0x7c00);
if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0;
else cdest -= (csrc & 0x03e0);
if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f;
else cdest -= (csrc & 0x001f);
return (cdest & 0x7bde) >> 1;
} else {
if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00;
else cdest -= (csrc & 0x7c00);
if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0;
else cdest -= (csrc & 0x03e0);
if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f;
else cdest -= (csrc & 0x001f);
return cdest;
}
break;
cdest &= 0x03e07c1f;
return (cdest >> 16) | cdest;
} else {
//subtract
if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00;
else cdest -= (csrc & 0x7c00);
if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0;
else cdest -= (csrc & 0x03e0);
if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f;
else cdest -= (csrc & 0x001f);
return (!halve) ? cdest : ((cdest & 0x7bde) >> 1);
}
return 0x0000; //prevent annoying warning message
}
+167 -195
View File
@@ -1,234 +1,206 @@
//called once at the start of every rendered scanline
void bPPU::update_bg_info() {
for(int bg = 0; bg < 4; bg++) {
bg_info[bg].th = (regs.bg_tilesize[bg]) ? 4 : 3;
bg_info[bg].tw = (regs.hires) ? 4 : bg_info[bg].th;
bg_info[bg].mx = (bg_info[bg].th == 4) ? (line.width << 1) : line.width;
bg_info[bg].my = bg_info[bg].mx;
if(regs.bg_scsize[bg] & 0x01)bg_info[bg].mx <<= 1;
if(regs.bg_scsize[bg] & 0x02)bg_info[bg].my <<= 1;
bg_info[bg].mx--;
bg_info[bg].my--;
}
}
uint16 bPPU::bg_get_tile(uint8 bg, uint16 x, uint16 y) {
uint16 pos;
x &= bg_info[bg].mx;
y &= bg_info[bg].my;
x >>= bg_info[bg].tw;
y >>= bg_info[bg].th;
pos = (regs.bg_scsize[bg] & 2) ? ((y & 0x20) << ((regs.bg_scsize[bg] & 1) ? 6 : 5)) : 0;
pos += (regs.bg_scsize[bg] & 1) ? ((x & 0x20) << 5) : 0;
pos += ((y & 31) << 5) + (x & 31);
return read16(vram, regs.bg_scaddr[bg] + (pos << 1));
}
void bPPU::render_line_bg(uint8 bg, uint8 color_depth, uint8 pri0_pos, uint8 pri1_pos) {
if(regs.bg_enabled[bg] == false && regs.bgsub_enabled[bg] == false) {
return;
}
int x;
int _scaddr = regs.bg_scaddr[bg];
int _tdaddr = regs.bg_tdaddr[bg];
bool _bg_enabled = regs.bg_enabled[bg];
bool _bgsub_enabled = regs.bgsub_enabled[bg];
//are layers disabled by user?
if(render_enabled(bg, 0) == false)pri0_pos = 0;
if(render_enabled(bg, 1) == false)pri1_pos = 0;
//nothing to render?
if(!pri0_pos && !pri1_pos)return;
uint16 opt_valid_bit; //offset-per-tile valid flag bit
if(bg == BG1) {
opt_valid_bit = 0x2000;
} else if(bg == BG2) {
opt_valid_bit = 0x4000;
} else {
opt_valid_bit = 0x0000;
bool bg_enabled = regs.bg_enabled[bg];
bool bgsub_enabled = regs.bgsub_enabled[bg];
uint16 opt_valid_bit = (bg == BG1) ? 0x2000 : ((bg == BG2) ? 0x4000 : 0x0000);
uint8 bgpal_index = (regs.bg_mode == 0) ? (bg << 5) : 0;
uint8 pal_size = (color_depth == 2) ? 256 : ((color_depth == 1) ? 16 : 4);
uint16 tile_mask = (color_depth == 2) ? 0x03ff : ((color_depth == 1) ? 0x07ff : 0x0fff);
//4 + color_depth = >>(4-6) -- / {16, 32, 64 } bytes/tile
//index is a tile number count to add to base tile number
uint tiledata_index = regs.bg_tdaddr[bg] >> (4 + color_depth);
uint8 *bg_td = (uint8*)bg_tiledata[color_depth];
uint8 *bg_td_state = (uint8*)bg_tiledata_state[color_depth];
uint8 tile_width = bg_info[bg].tw;
uint8 tile_height = bg_info[bg].th;
uint16 mask_x = bg_info[bg].mx; //screen width mask
uint16 mask_y = bg_info[bg].my; //screen height mask
uint x = 0;
uint y = regs.bg_y[bg];
if(line.interlace && regs.hires) {
y = (y << 1) + line.interlace_field;
}
uint8 pal_size, tiledata_size;
switch(color_depth) {
case COLORDEPTH_4:
pal_size = 4;
tiledata_size = 4; //<<4=*16
break;
case COLORDEPTH_16:
pal_size = 16;
tiledata_size = 5; //<<5=*32
break;
case COLORDEPTH_256:
pal_size = 256;
tiledata_size = 6; //<<6=*64
break;
}
uint16 hscroll = (regs.hires) ? (regs.bg_hofs[bg] << 1) : regs.bg_hofs[bg];
uint16 vscroll = (line.interlace && regs.hires) ? (regs.bg_vofs[bg] << 1) : regs.bg_vofs[bg];
hscroll &= mask_x;
vscroll &= mask_y;
uint8 *bg_td, *bg_td_state;
bg_td = (uint8*)bg_tiledata[color_depth];
bg_td_state = (uint8*)bg_tiledata_state[color_depth];
uint16 *mtable = (uint16*)mosaic_table[(regs.mosaic_enabled[bg]) ? regs.mosaic_size : 0];
uint16 mosaic_x;
uint16 mosaic_y;
uint16 screen_width, screen_height;
screen_width = _screen_width;
screen_height = _screen_width; //this is correct -- ppu tilemap is a perfect square
uint8 tile_size, tile_width, tile_height;
tile_size = (regs.bg_tilesize[bg])?4:3; //<<4=*16, <<3=*8
tile_width = tile_size;
tile_height = tile_size;
int screen_x, screen_y;
if(_interlace == true && _screen_width == 512) {
screen_y = (_y << 1) + _interlace_field;
} else {
screen_y = _y;
}
//Modes 5 and 6 seem to force 16-width tiles due to having twice the resolution.
//The tile size attribute in $2105 has no effect on tile width.
if(_screen_width == 512) {
tile_width = 4; //<<4=*16
}
if(tile_size == 4) { //16x16 tile size
screen_width <<= 1;
screen_height <<= 1;
}
if(regs.bg_scsize[bg] & 0x01)screen_width <<= 1;
if(regs.bg_scsize[bg] & 0x02)screen_height <<= 1;
uint16 screen_width_mask, screen_height_mask;
screen_width_mask = screen_width - 1;
screen_height_mask = screen_height - 1;
int bg_x, bg_y;
uint16 vscroll, hscroll;
if(_screen_width == 512) {
hscroll = (regs.bg_hofs[bg] << 1) & screen_width_mask;
} else {
hscroll = regs.bg_hofs[bg] & screen_width_mask;
}
bg_x = hscroll;
if(_screen_width == 512 && _interlace == true) {
vscroll = (regs.bg_vofs[bg] << 1) & screen_height_mask;
} else {
vscroll = regs.bg_vofs[bg] & screen_height_mask;
}
bg_y = (screen_y + vscroll) & screen_height_mask;
uint16 *mtable;
int mosaic_x, mosaic_y;
if(regs.mosaic_enabled[bg] == true) {
mtable = (uint16*)mosaic_table[regs.mosaic_size];
} 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;
uint16 hval, vval;
uint16 t, tile_pri, tile_num;
uint8 pal_index, pal_num;
uint8 *tile_ptr;
int xpos, ypos;
uint16 map_index, hoffset, voffset, col;
uint xpos, ypos;
uint16 hoffset, voffset, opt_x, col;
bool mirror_x, mirror_y;
bool is_opt_mode = (config::ppu.opt_enable) && (regs.bg_mode == 2 || regs.bg_mode == 4 || regs.bg_mode == 6);
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...
if(regs.bg_mode == 2 || regs.bg_mode == 4 || regs.bg_mode == 6) {
if(regs.bg_mode == 6) {
tile_x = (mtable[screen_x + (hscroll & 15)] >> 4);
} else {
tile_x = (mtable[screen_x + (hscroll & 7)] >> 3);
}
hoffset = hscroll;
voffset = vscroll;
if(tile_x != 0) {
tile_x = (tile_x - 1) & 31;
uint8 *wt_main = window_cache[bg].main;
uint8 *wt_sub = window_cache[bg].sub;
int32 prev_x = -1, prev_y = -1;
for(x = 0; x < line.width; x++) {
hoffset = x + hscroll;
voffset = y + vscroll;
if(is_opt_mode) {
opt_x = (x + (hscroll & 7));
//tile 0 is unaffected by OPT mode...
if(opt_x >= 8) {
hval = bg_get_tile(BG3,
(opt_x - 8) + (regs.bg_hofs[BG3] & ~7),
regs.bg_vofs[BG3]);
vval = bg_get_tile(BG3,
(opt_x - 8) + (regs.bg_hofs[BG3] & ~7),
regs.bg_vofs[BG3] + 8);
if(regs.bg_mode == 4) {
pos = regs.bg_scaddr[BG3] + (tile_x << 1);
t = *((uint16*)vram + (pos >> 1));
if(t & opt_valid_bit) {
if(!(t & 0x8000)) {
hoffset = ((t & 0x1ff8) | (hscroll & 7)) & screen_width_mask;
if(hval & opt_valid_bit) {
if(!(hval & 0x8000)) {
hoffset = opt_x + (hval & ~7);
} else {
voffset = (t & 0x1fff) & screen_height_mask;
voffset = y + hval;
}
}
} else {
pos = regs.bg_scaddr[BG3] + (tile_x << 1);
t = *((uint16*)vram + (pos >> 1));
if(t & opt_valid_bit) {
hoffset = ((t & 0x1ff8) | (hscroll & 7)) & screen_width_mask;
if(hval & opt_valid_bit) {
hoffset = opt_x + (hval & ~7);
}
pos = regs.bg_scaddr[BG3] + 64 + (tile_x << 1);
t = *((uint16*)vram + (pos >> 1));
if(t & opt_valid_bit) {
voffset = (t & 0x1fff) & screen_height_mask;
if(vval & opt_valid_bit) {
voffset = y + vval;
}
}
}
mosaic_x = mtable[(screen_x + hoffset) & screen_width_mask ];
mosaic_y = mtable[(screen_y + voffset) & screen_height_mask];
}
switch(regs.bg_scsize[bg]) {
case 0:
map_index = 0;
break;
case 1:
map_index = ((mosaic_x >> tile_size) >> 5) << 11;
break;
case 2:
map_index = ((mosaic_y >> tile_size) >> 5) << 11;
break;
case 3:
map_index = ((mosaic_x >> tile_size) >> 5) << 11 |
((mosaic_y >> tile_size) >> 5) << 12;
break;
}
mosaic_x = mtable[hoffset & mask_x];
mosaic_y = voffset & mask_y;
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;
if((mosaic_x >> 3) != prev_x || (mosaic_y >> 3) != prev_y) {
prev_x = (mosaic_x >> 3);
prev_y = (mosaic_y >> 3);
int _pri;
_pri = (t & 0x2000) ? pri1_pos : pri0_pos;
t = bg_get_tile(bg, mosaic_x, mosaic_y);
mirror_y = !!(t & 0x8000);
mirror_x = !!(t & 0x4000);
tile_pri = (t & 0x2000) ? pri1_pos : pri0_pos;
tile_num = t;
if(tile_width == 4) { //16x16 horizontal tile mirroring
if(!!(mosaic_x & 8) != mirror_x)tile_num++;
}
if(tile_height == 4) { //16x16 vertical tile mirroring
if(!!(mosaic_y & 8) != mirror_y)tile_num += 16;
}
tile_num = t & 0x03ff;
if(tile_width == 4) {
if(((mosaic_x & 15) >= 8 && !mirror_x) ||
((mosaic_x & 15) < 8 && mirror_x))tile_num++;
tile_num &= 0x03ff;
}
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);
tile_num += tiledata_index;
tile_num &= tile_mask;
if(bg_td_state[tile_num] == 1) {
render_bg_tile(color_depth, tile_num);
if(bg_td_state[tile_num] == 1) {
render_bg_tile(color_depth, tile_num);
}
pal_num = ((t >> 10) & 7);
pal_index = (pal_num * pal_size) + bgpal_index;
ypos = mosaic_y & 7;
if(mirror_y)ypos ^= 7; //invert y tile pos
tile_ptr = (uint8*)bg_td + (tile_num * 64) + (ypos * 8);
}
pal_index = ((t >> 10) & 7) * pal_size;
xpos = mosaic_x & 7;
if(mirror_x)xpos ^= 7; //invert x tile pos
col = *(tile_ptr + xpos);
if(col) {
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(mirror_y) { ypos = (7 - (mosaic_y & 7)); }
else { ypos = ( (mosaic_y & 7)); }
#define setpixel_main(x) \
if(pixel_cache[x].pri_main < tile_pri) { \
pixel_cache[x].pri_main = tile_pri; \
pixel_cache[x].bg_main = bg; \
pixel_cache[x].src_main = col; \
pixel_cache[x].ce_main = false; \
}
#define setpixel_sub(x) \
if(pixel_cache[x].pri_sub < tile_pri) { \
pixel_cache[x].pri_sub = tile_pri; \
pixel_cache[x].bg_sub = bg; \
pixel_cache[x].src_sub = col; \
pixel_cache[x].ce_sub = false; \
}
//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) {
if(mirror_x) { xpos = (7 - (mosaic_x & 7)); }
else { xpos = ( (mosaic_x & 7)); }
col = *(tile_ptr + xpos);
if(col && main_colorwindowtable[screen_x]) {
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;
}
}
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;
}
if(!regs.hires) {
if(bg_enabled == true && !wt_main[x]) { setpixel_main(x); }
if(bgsub_enabled == true && !wt_sub[x]) { setpixel_sub(x); }
} else {
int hx = x >> 1;
if(x & 1) {
if(bg_enabled == true && !wt_main[hx]) { setpixel_main(hx); }
} else {
if(bgsub_enabled == true && !wt_sub[hx]) { setpixel_sub(hx); }
}
}
bg_x++;
bg_x &= screen_width_mask;
mosaic_x = mtable[bg_x];
if(base_xpos != ((mosaic_x >> 3) & 31))break;
screen_x++;
if(screen_x >= _screen_width)break;
#undef setpixel_main
#undef setpixel_sub
}
}
}
+34 -2
View File
@@ -3,6 +3,7 @@
if(d0 & __m)col += 1; \
if(d1 & __m)col += 2; \
*dest++ = col
#define render_bg_tile_line_16(__m) \
col = 0; \
if(d0 & __m)col += 1; \
@@ -10,6 +11,7 @@
if(d2 & __m)col += 4; \
if(d3 & __m)col += 8; \
*dest++ = col
#define render_bg_tile_line_256(__m) \
col = 0; \
if(d0 & __m)col += 1; \
@@ -96,8 +98,24 @@ uint8 *dest;
}
}
#undef render_bg_tile_line_4
#undef render_bg_tile_line_16
#undef render_bg_tile_line_256
inline void bPPU::clear_pixel_cache() {
memset(pixel_cache, 0, sizeof(pixel_cache));
uint16 main = get_palette(0);
uint16 sub = (regs.pseudo_hires || regs.hires) ? main : regs.color_rgb;
uint32 i = 255;
do {
pixel_cache[i].src_main = main;
pixel_cache[i].src_sub = sub;
pixel_cache[i].bg_main = BACK;
pixel_cache[i].bg_sub = BACK;
pixel_cache[i].ce_main = false;
pixel_cache[i].ce_sub = false;
pixel_cache[i].pri_main = 0;
pixel_cache[i].pri_sub = 0;
} while(i--);
}
void bPPU::init_tiledata_cache() {
@@ -112,8 +130,22 @@ void bPPU::init_tiledata_cache() {
void bPPU::clear_tiledata_cache() {
memset(bg_tiledata[TILE_2BIT], 0, 262144);
memset(bg_tiledata[TILE_4BIT], 0, 131072);
memset(bg_tiledata[TILE_4BIT], 0, 65536);
memset(bg_tiledata[TILE_8BIT], 0, 65536);
memset(bg_tiledata_state[TILE_2BIT], 0, 4096);
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);
}
+101 -58
View File
@@ -1,76 +1,119 @@
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_pixel(int x) {
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_normal(uint32 x) {
_pixel *p = &pixel_cache[x];
uint16 _r;
if(p->bg_main && p->bg_sub) {
if(regs.bg_color_enabled[p->bg_main & 0x7f] && sub_colorwindowtable[x]) {
if(regs.addsub_mode) {
_r = addsub_pixels(p->src_main, p->bg_main & 0x7f, p->src_sub, p->bg_sub & 0x7f);
} else {
_r = addsub_pixel(p->src_main, p->bg_main & 0x7f);
}
} else {
_r = get_palette(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);
} else {
_r = get_palette(p->src_main);
}
} else if(p->bg_sub) {
if(regs.bg_color_enabled[BACK]) {
if(sub_colorwindowtable[x]) {
if(regs.addsub_mode) {
_r = addsub_pixels(0, BACK, p->src_sub, p->bg_sub & 0x7f);
} else {
_r = addsub_pixel(0, BACK);
}
} else {
_r = get_palette(0);
}
} else {
_r = 0x0000;
}
uint16 src_main, src_sub;
uint8 bg_sub;
src_main = p->src_main;
if(!regs.addsub_mode) {
bg_sub = BACK;
src_sub = regs.color_rgb;
} else {
if(main_colorwindowtable[x]) {
if(regs.bg_color_enabled[BACK] && sub_colorwindowtable[x]) {
_r = addsub_pixel(0, BACK);
} else {
_r = get_palette(0);
bg_sub = p->bg_sub;
src_sub = p->src_sub;
}
if(!window_cache[COL].main[x]) {
if(!window_cache[COL].sub[x]) {
return 0x0000;
}
src_main = 0x0000;
}
if(!p->ce_main && regs.color_enabled[p->bg_main] && window_cache[COL].sub[x]) {
bool halve = false;
if(regs.color_halve && window_cache[COL].main[x]) {
if(regs.addsub_mode && bg_sub == BACK);
else {
halve = true;
}
}
return addsub_pixels(x, src_main, src_sub, halve);
}
return src_main;
}
inline uint16 bPPU::get_pixel_swap(uint32 x) {
_pixel *p = &pixel_cache[x];
uint16 src_main, src_sub;
uint8 bg_sub;
src_main = p->src_sub;
if(!regs.addsub_mode) {
bg_sub = BACK;
src_sub = regs.color_rgb;
} else {
bg_sub = p->bg_main;
src_sub = p->src_main;
}
if(!window_cache[COL].main[x]) {
if(!window_cache[COL].sub[x]) {
return 0x0000;
}
src_main = 0x0000;
}
if(!p->ce_sub && regs.color_enabled[p->bg_sub] && window_cache[COL].sub[x]) {
bool halve = false;
if(regs.color_halve && window_cache[COL].main[x]) {
if(regs.addsub_mode && bg_sub == BACK);
else {
halve = true;
}
} else {
_r = 0x0000;
}
return addsub_pixels(x, src_main, src_sub, halve);
}
return src_main;
}
inline uint16 bPPU::get_pixel_lores(uint32 x) {
return get_pixel_normal(x);
}
inline uint16 bPPU::get_pixel_hires(uint32 x) {
if(x & 1) {
return get_pixel_normal(x >> 1);
} else {
return get_pixel_swap(x >> 1);
}
return _r;
}
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;
}
uint32 r, x;
uint16 *ptr = (uint16*)output + (line.y * 1024) +
((line.interlace && line.interlace_field) ? 512 : 0);
uint16 *ltable = (uint16*)light_table + (regs.display_brightness << 15);
uint16 *ltable;
ltable = (uint16*)light_table + (regs.display_brightness << 16);
if(_screen_width == 256) {
if(!regs.pseudo_hires && !regs.hires) {
for(x=0;x<256;x++) {
_r = get_pixel(x);
*ptr = *(ltable + _r);
ptr += 2;
r = get_pixel_lores(x);
*ptr++ = *(ltable + r);
}
} else {
for(x=0;x<512;x++) {
_r = get_pixel(x);
*ptr++ = *(ltable + _r);
r = get_pixel_hires(x);
*ptr++ = *(ltable + r);
}
if(regs.pseudo_hires && !regs.hires) {
ptr -= 512;
for(x=0;x<256;x++) {
*(ptr + x) = ((ptr[x << 1] & 0x7bde) >> 1) + ((ptr[(x << 1) + 1] & 0x7bde) >> 1);
}
}
}
}
+114 -96
View File
@@ -1,62 +1,79 @@
#define CLIP_10BIT_SIGNED(x) \
((x) & ((1 << 10) - 1)) + (((((x) & (1 << 13)) ^ (1 << 13)) - (1 << 13)) >> 3)
/*
bsnes mode7 renderer
#define CAST_WORDTOINT(x) \
(int)(((x & 0x8000)?(x | 0xffff0000):(x & 0x00007fff)))
base algorithm written by anomie
bsnes implementation written by byuu
void bPPU::render_line_mode7(uint8 bg1_pri, uint8 bg2b_pri, uint8 bg2a_pri) {
int x;
int step_m7a, step_m7c, m7a, m7b, m7c, m7d;
int hoffset, voffset;
int centerx, centery;
int xx, yy;
int px, py;
int tx, ty, tile, palette;
uint8 layer_pos;
hoffset = (CAST_WORDTOINT(regs.bg_hofs[BG1]) << 7) >> 7;
voffset = (CAST_WORDTOINT(regs.bg_vofs[BG1]) << 7) >> 7;
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
*/
centerx = (CAST_WORDTOINT(regs.m7x) << 7) >> 7;
centery = (CAST_WORDTOINT(regs.m7y) << 7) >> 7;
//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;
//are layers disabled by user?
if(render_enabled(bg, 0) == false)pri0_pos = 0;
if(render_enabled(bg, 1) == false)pri1_pos = 0;
//nothing to render?
if(!pri0_pos && !pri1_pos);
int32 x, y;
int32 a, b, c, d, cx, cy;
int32 hofs, vofs;
int32 px, py;
int32 tx, ty, tile, palette;
a = int32(int16(regs.m7a));
b = int32(int16(regs.m7b));
c = int32(int16(regs.m7c));
d = int32(int16(regs.m7d));
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 = 223 - _y;
y = 255 - line.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 = line.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 +85,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 +97,60 @@ 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(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;
}
}
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 = 0x80 | _bg;
pixel_cache[_x].src_sub = palette;
}
}
if(!palette)continue;
if(regs.mode7_hflip == true) {
_x = 255 - x;
} else {
_x = x;
}
_end_setpixel:
m7a += step_m7a;
m7c += step_m7c;
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 = bg;
pixel_cache[_x].src_main = col;
pixel_cache[_x].ce_main = false;
}
}
if(regs.bgsub_enabled[bg] == true && !wt_sub[_x]) {
if(pixel_cache[_x].pri_sub < _pri) {
pixel_cache[_x].pri_sub = _pri;
pixel_cache[_x].bg_sub = bg;
pixel_cache[_x].src_sub = col;
pixel_cache[_x].ce_sub = false;
}
}
}
}
#undef CLIP
+84 -81
View File
@@ -63,10 +63,10 @@ uint16 width, height;
addr &= 0x001f;
z = oam[0x0200 + addr];
i = addr << 2;
sprite_list[i ].x = ((z & 0x01)?0x0100:0x0000) + (sprite_list[i ].x & 0xff);
sprite_list[i + 1].x = ((z & 0x04)?0x0100:0x0000) + (sprite_list[i + 1].x & 0xff);
sprite_list[i + 2].x = ((z & 0x10)?0x0100:0x0000) + (sprite_list[i + 2].x & 0xff);
sprite_list[i + 3].x = ((z & 0x40)?0x0100:0x0000) + (sprite_list[i + 3].x & 0xff);
sprite_list[i ].x = ((z & 0x01) ? 256 : 0) + (sprite_list[i ].x & 255);
sprite_list[i + 1].x = ((z & 0x04) ? 256 : 0) + (sprite_list[i + 1].x & 255);
sprite_list[i + 2].x = ((z & 0x10) ? 256 : 0) + (sprite_list[i + 2].x & 255);
sprite_list[i + 3].x = ((z & 0x40) ? 256 : 0) + (sprite_list[i + 3].x & 255);
get_sprite_size(i, !!(z & 0x02));
get_sprite_size(i + 1, !!(z & 0x08));
get_sprite_size(i + 2, !!(z & 0x20));
@@ -90,18 +90,18 @@ uint16 addr = 0x0200;
bool bPPU::is_sprite_on_scanline() {
//if sprite is entirely offscreen and doesn't wrap around to the left side of the screen,
//then it is not counted. 256 is correct, and not 255 -- as one might first expect
if(spr->x > 256 && (spr->x + spr->width) < 512 && _screen_width != 512)return false;
if(spr->x > 256 && (spr->x + spr->width) < 512)return false;
if(regs.oam_halve == false) {
if(_y >= spr->y && _y < (spr->y + spr->height)) {
if(line.y >= spr->y && line.y < (spr->y + spr->height)) {
return true;
} else if((spr->y + spr->height) >= 256 && _y < ((spr->y + spr->height) & 255)) {
} else if((spr->y + spr->height) >= 256 && line.y < ((spr->y + spr->height) & 255)) {
return true;
}
} else {
if(_y >= spr->y && _y < (spr->y + (spr->height >> 1))) {
if(line.y >= spr->y && line.y < (spr->y + (spr->height >> 1))) {
return true;
} else if((spr->y + (spr->height >> 1)) >= 256 && _y < ((spr->y + (spr->height >> 1)) & 255)) {
} else if((spr->y + (spr->height >> 1)) >= 256 && line.y < ((spr->y + (spr->height >> 1)) & 255)) {
return true;
}
}
@@ -110,62 +110,53 @@ bool bPPU::is_sprite_on_scanline() {
}
void bPPU::load_oam_tiles() {
uint16 tile_width;
tile_width = spr->width >> 3;
uint16 tile_width = spr->width >> 3;
int x = spr->x;
int y = (spr->vflip) ? ((spr->height - 1) - (line.y - spr->y)) : (line.y - spr->y);
int x, y, chr, nameselect_index;
x = spr->x;
if(_screen_width == 512)x <<= 1;
x &= 511;
if(spr->vflip) {
y = ((spr->height - 1) - (_y - spr->y));
} else {
y = (_y - spr->y);
}
//todo: double-check code below. seems that interlace_field
//should be added to hires 512x448 sprites as well, and not
//just when oam_halve is enabled...
if(regs.oam_halve == true) {
y <<= 1;
if(_interlace == true && _screen_width == 512) {
y += _interlace_field;
if(line.interlace && line.width == 512) {
y += line.interlace_field;
}
}
x &= 511;
y &= 255;
chr = spr->character;
uint16 tdaddr = regs.oam_tdaddr;
uint16 chrx = (spr->character ) & 15;
uint16 chry = (spr->character >> 4) & 15;
if(spr->use_nameselect == true) {
chr += 256;
nameselect_index = regs.oam_nameselect << 13;
} else {
nameselect_index = 0x0000;
tdaddr += (256 * 32) + (regs.oam_nameselect << 13);
}
chr += (y >> 3) << 4;
chry += (y >> 3);
chry &= 15;
chry <<= 4;
int i, n, mx, pos, z;
int i, n, sx, mx, pos;
for(i=0;i<tile_width;i++) {
z = x;
z += (i << ((_screen_width == 512)?4:3));
z &= 511;
sx = x;
sx += i << 3;
sx &= 511;
//ignore sprites that are offscreen
//sprites at 256 are still counted, even though they aren't visible onscreen
if(z >= 257 && (z + 7) < 512 && _screen_width != 512)continue;
if(sx >= 257 && (sx + 7) < 512)continue;
if(regs.oam_tilecount++ > 34)break;
n = regs.oam_tilecount - 1;
oam_tilelist[n].x = z;
oam_tilelist[n].x = sx;
oam_tilelist[n].y = y;
oam_tilelist[n].pri = spr->priority;
oam_tilelist[n].pal = (spr->palette << 4) + 128;
oam_tilelist[n].hflip = spr->hflip;
if(oam_tilelist[n].hflip) {
mx = (tile_width - 1) - i;
} else {
mx = i;
}
pos = regs.oam_tdaddr + ((chr + mx) << 5) + ((y & 7) << 1) + nameselect_index;
mx = (oam_tilelist[n].hflip) ? ((tile_width - 1) - i) : i;
pos = tdaddr + ((chry + ((chrx + mx) & 15)) << 5);
oam_tilelist[n].tile = (pos >> 5) & 0x07ff;
}
}
@@ -182,38 +173,26 @@ oam_tileitem *t = &oam_tilelist[tile_num];
int x, sx, col;
sx = t->x;
//tile_ptr = tiledata + (tile * (8_width * 8_height)) + ((y & 7_height_mask) * 8_width);
tile_ptr = (uint8*)oam_td + (t->tile << 6) + ((t->y & 7) << 3);
for(x=0;x<8;x++) {
sx &= 511;
if(sx < _screen_width) {
col = *(tile_ptr + ((t->hflip)?7-x:x));
if(sx < 256) {
col = *(tile_ptr + ((t->hflip) ? (7 - x) : x));
if(col) {
col += t->pal;
oam_line_pal[sx] = col;
oam_line_pri[sx] = t->pri;
if(_screen_width == 512) {
oam_line_pal[sx + 1] = col;
oam_line_pri[sx + 1] = t->pri;
}
}
}
sx += (_screen_width == 512)?2:1;
sx++;
}
}
void bPPU::render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) {
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);
int s;
regs.oam_itemcount = 0;
regs.oam_tilecount = 0;
memset(oam_line_pri, OAM_PRI_NONE, 512);
memset(oam_line_pri, OAM_PRI_NONE, 256);
memset(oam_itemlist, 0xff, 32);
for(s=0;s<128;s++) {
@@ -239,33 +218,57 @@ uint8 *wt_sub = sub_windowtable[OAM];
regs.time_over |= (regs.oam_tilecount > 34);
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(regs.bg_enabled[OAM] == false && regs.bgsub_enabled[OAM] == false)return;
//are layers disabled by user?
if(render_enabled(OAM, 0) == false)pri0_pos = 0;
if(render_enabled(OAM, 1) == false)pri1_pos = 0;
if(render_enabled(OAM, 2) == false)pri2_pos = 0;
if(render_enabled(OAM, 3) == false)pri3_pos = 0;
//nothing to render?
if(!pri0_pos && !pri1_pos && !pri2_pos && !pri3_pos)return;
render_line_oam_lores(pri0_pos, pri1_pos, pri2_pos, pri3_pos);
}
#define setpixel_main(x) \
if(pixel_cache[x].pri_main < pri) { \
pixel_cache[x].pri_main = pri; \
pixel_cache[x].bg_main = OAM; \
pixel_cache[x].src_main = get_palette(oam_line_pal[x]); \
pixel_cache[x].ce_main = (oam_line_pal[x] < 192); \
}
#define setpixel_sub(x) \
if(pixel_cache[x].pri_sub < pri) { \
pixel_cache[x].pri_sub = pri; \
pixel_cache[x].bg_sub = OAM; \
pixel_cache[x].src_sub = get_palette(oam_line_pal[x]); \
pixel_cache[x].ce_sub = (oam_line_pal[x] < 192); \
}
void bPPU::render_line_oam_lores(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) {
bool bg_enabled = regs.bg_enabled[OAM];
bool bgsub_enabled = regs.bgsub_enabled[OAM];
build_window_tables(OAM);
uint8 *wt_main = window_cache[OAM].main;
uint8 *wt_sub = window_cache[OAM].sub;
int pri;
for(int x=0;x<256;x++) {
if(oam_line_pri[x] == OAM_PRI_NONE)continue;
switch(oam_line_pri[x]) {
case 0:_pri = pri0_pos;break;
case 1:_pri = pri1_pos;break;
case 2:_pri = pri2_pos;break;
case 3:_pri = pri3_pos;break;
case 0:pri = pri0_pos;break;
case 1:pri = pri1_pos;break;
case 2:pri = pri2_pos;break;
case 3:pri = pri3_pos;break;
}
if(main_colorwindowtable[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];
}
}
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];
}
}
}
if(bg_enabled == true && !wt_main[x]) { setpixel_main(x); }
if(bgsub_enabled == true && !wt_sub[x]) { setpixel_sub(x); }
}
}
#undef setpixel_main
#undef setpixel_sub
+75 -135
View File
@@ -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, 256);
return;
}
if(mainscreen == false && regs.sub_window_enabled[bg] == false) {
memset(wtbl, 0, 256);
return;
}
} else {
uint8 mask;
if(mainscreen == true) {
mask = regs.color_mask;
} else {
mask = regs.colorsub_mask;
}
if(mask == 0) {
//always
memset(wtbl, 1, 256);
return;
}
if(mask == 3) {
//never
memset(wtbl, 0, 256);
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;
@@ -17,61 +56,54 @@ bool r;
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.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) {
for(x=0;x<_screen_width;x++) {
wtbl[x] = (x >= window1_left && x <= window1_right)?true:false;
if(regs.window1_enabled[bg] == false && regs.window2_enabled[bg] == false) {
memset(wtbl, clr, 256);
} else if(regs.window1_enabled[bg] == true && regs.window2_enabled[bg] == false) {
if(regs.window1_invert[bg] == false) {
for(x = 0; x < 256; x++) {
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;
for(x = 0; x < 256; x++) {
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) {
for(x=0;x<_screen_width;x++) {
wtbl[x] = (x >= window2_left && x <= window2_right)?true:false;
} else if(regs.window1_enabled[bg] == false && regs.window2_enabled[bg] == true) {
if(regs.window2_invert[bg] == false) {
for(x = 0; x < 256; x++) {
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;
for(x = 0; x < 256; x++) {
wtbl[x] = (x < window2_left || x > window2_right) ? set : clr;
}
}
} else { //if(regs.bg_window1_enabled[bg] == true && regs.bg_window2_enabled[bg] == true) {
for(x=0;x<_screen_width;x++) {
if(regs.bg_window1_invert[bg] == false) {
} else { //if(regs.window1_enabled[bg] == true && regs.window2_enabled[bg] == true) {
for(x = 0; x < 256; x++) {
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 +111,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);
}
Loaded 100 of 244 files, more files were not shown because too many files have changed in this diff. Show more