mirror of https://github.com/bsnes-emu/bsnes.git
Update to bsnes v018 release.
I began working on bsnes on October 14th, 2004. I am releasing bsnes v0.018 today to celebrate bsnes' two year anniversary. Please note that this release incurs a ~15% speed reduction since v0.017, due to IRQ and S-SMP timing improvements. Changelog: - Fixed many critical errors in IRQ timing, should be *very* close to real hardware now - Corrected major CPU timing bug involving CPU I/O condition 4 - Corrected bug with generic HiROM / LoROM memory maps - Corrected bug involving HDMA indirect channel termination [anomie] - OAM address reset now occurs when screen display is enabled, per recent research - Readded full DMA, HDMA and HDMA init bus sync timing - Added preliminary emulation of S-SMP $00f0 TEST register (6 of 8 bits are supported) - Readded emulation of known timing differences between CPU revisions 1 and 2 - Config file can now control scanline-based PPU render position. This will only be needed until a proper dot-based PPU renderer is added - Removed core debugging hooks so that debugging console can remain in public releases, it now functions as a tracer and memory editor - Config file paths once again work correctly even if missing trailing backslash - Video configuration simplified, sorry in advance to those who enjoyed the profile mode used before - Added new configuration screen to control some emulation settings - Replaced bsnes program icon with a much nicer one [FitzRoy] - Optimized memory speed detection algorithm - Preliminary UPS soft-patching support (do not use this yet!) - Decreased memory usage and optimized generic libraries used by bsnes (/src/lib) - Now caching OAM by one line, somewhat similar to a real SNES. Fixes Winter Gold, but causes line rendering error in Mega lo Mania - Lots more, as usual The following games have been fixed since v0.017 by the above bugfixes: - Battle Blaze (J, U) - Circuit USA (J) - F1 Grand Prix (J) - Funaki Masakatsu no Hybrid Wrestler - Tougi Denshou (J) - Jumbo Ozaki no Hole in One (J) - Mahjongg Taikai II (J) - RPG Tsukuru - Super Dante (J) - Robocop Versus The Terminator (U, E) - Sink or Swim (U, E) - Street Racer (J) - Touge Densetsu Saisoku Battle (J) - Winter Olympics (U, E)
This commit is contained in:
parent
ccf1c00b58
commit
35fd80bde7
35
license.txt
35
license.txt
|
@ -1,35 +0,0 @@
|
|||
bsnes License:
|
||||
--------------
|
||||
You are free to redistribute this software, and its source code; provided
|
||||
there is no charge for the software, nor any charge for the medium used to
|
||||
distribute the software. You are also free to use and modify the source code
|
||||
as you desire for personal use only. No publically-released derivative works
|
||||
of this program nor its source code are permitted without my permission,
|
||||
though I will likely grant you permission if you ask me. You must also abide
|
||||
by the terms of any additional source code licenses contained within this
|
||||
program.
|
||||
|
||||
Simple DirectMedia Layer License:
|
||||
---------------------------------
|
||||
The Simple DirectMedia Layer (SDL for short) is a cross-platform library
|
||||
designed to make it easy to write multi-media software, such as games and
|
||||
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:
|
||||
http://www.gnu.org/copyleft/lesser.html
|
||||
|
||||
JMA License:
|
||||
------------
|
||||
JMA is licensed under the GNU GPL. I have received special exemption from
|
||||
Nach to use this library in bsnes.
|
||||
|
||||
Licensing Exemptions:
|
||||
---------------------
|
||||
libco is public domain. You may obtain the latest version at:
|
||||
http://byuu.org/
|
||||
|
||||
Richard Bannister has asked for and received my permission to distribute
|
||||
a binary-only port of bsnes on the Mac OS X platform.
|
108
readme.txt
108
readme.txt
|
@ -1,108 +0,0 @@
|
|||
bsnes
|
||||
Version 0.017
|
||||
Author: byuu
|
||||
|
||||
|
||||
General
|
||||
-------
|
||||
bsnes is a Super Nintendo / Super Famicom emulator that began on
|
||||
October 14th, 2004.
|
||||
|
||||
The latest version can be downloaded from:
|
||||
http://byuu.org/
|
||||
|
||||
Please see license.txt for important licensing information.
|
||||
|
||||
|
||||
Known Bug(s)
|
||||
------------
|
||||
Uniracers / Unirally
|
||||
- 2-player mode sprite issues (mid-frame OAM writes not supported)
|
||||
|
||||
|
||||
Known Limitations
|
||||
-----------------
|
||||
S-CPU
|
||||
- Invalid DMA / HDMA transfers (eg WRAM<>WRAM) not fully emulated
|
||||
- DMA / HDMA bus synchronization timing not supported
|
||||
- Multiply / Divide register delays not implemented
|
||||
|
||||
S-SMP
|
||||
- Cycle breakdown of opcodes is theoretical, but mostly correct
|
||||
|
||||
S-PPU
|
||||
- Uses scanline-based renderer. This is very inaccurate, but very
|
||||
few games rely on mid-scanline writes to function correctly
|
||||
- Does not support FirstSprite+Y priority
|
||||
- OAM / CGRAM accesses during active display not supported correctly
|
||||
- RTO flags are not calculated on frames that are skipped when frameskipping
|
||||
is enabled. This provides a major speedup, however it will cause in issues
|
||||
in games that test these flags, eg the SNES Test Program Electronics Test.
|
||||
Turning frameskipping off will allow RTO flag calculation on every frame
|
||||
|
||||
S-DSP
|
||||
- Runs at 32khz. Hardware S-DSP likely runs at 1.024mhz to perform
|
||||
multiple reads / writes per sample. Sound is still output at 32khz,
|
||||
of course
|
||||
|
||||
Hardware Bugs
|
||||
- CPUr1 HDMA crashing bug not emulated
|
||||
- CPU<>APU communication bus conflicts not emulated
|
||||
|
||||
|
||||
Unsupported Hardware
|
||||
--------------------
|
||||
SA-1
|
||||
Coprocessor used in many popular games, including:
|
||||
- Dragon Ball Z Hyper Dimension
|
||||
- Kirby Super Star
|
||||
- Kirby's Dreamland 3
|
||||
- Marvelous
|
||||
- SD Gundam G-NEXT
|
||||
- Super Mario RPG
|
||||
|
||||
Super FX
|
||||
Coprocessor used in many popular games, including:
|
||||
- Doom
|
||||
- Star Fox
|
||||
- Star Fox 2 (unreleased beta)
|
||||
- Super Mario World 2: Yoshi's Island
|
||||
|
||||
SPC7110
|
||||
Coprocessor used only by the following games:
|
||||
- Far East of Eden Zero
|
||||
- Far East of Eden Zero: Shounen Jump no Shou
|
||||
- Momotarou Densetsu Happy
|
||||
- Super Power League 4
|
||||
|
||||
DSP-3
|
||||
Coprocessor used only by SD Gundam GX
|
||||
|
||||
DSP-4
|
||||
Coprocessor used only by Top Gear 3000
|
||||
|
||||
ST010 / ST011 / ST018
|
||||
SETA coprocessors used by very few games
|
||||
|
||||
BS-X (Broadcast Satellite)
|
||||
Add-on unit sold only in Japan that played specially-made games that
|
||||
were downloaded via satellite
|
||||
|
||||
BS-X Flashcart
|
||||
Flash cartridge used by BS-X, as well as some standalone games by
|
||||
Asciisoft
|
||||
|
||||
Bandai Sufami Turbo
|
||||
Special cartloader to play some Bandai games
|
||||
|
||||
Super Gameboy
|
||||
Cartridge passthrough used for playing Gameboy games
|
||||
|
||||
|
||||
Unsupported controllers
|
||||
-----------------------
|
||||
Mouse
|
||||
Super Scope
|
||||
Justifier
|
||||
Multitap (4-port)
|
||||
Multitap (5-port)
|
|
@ -1,44 +0,0 @@
|
|||
class APURegFlags {
|
||||
private:
|
||||
template<uint mask> class bit {
|
||||
public:
|
||||
uint data;
|
||||
inline operator bool() { return bool(data & mask); }
|
||||
inline bool operator = (const bool i) { (i) ? data |= mask : data &= ~mask; return bool(data & mask); }
|
||||
inline bool operator |= (const bool i) { if(i)data |= mask; return bool(data & mask); }
|
||||
inline bool operator ^= (const bool i) { if(i)data ^= mask; return bool(data & mask); }
|
||||
inline bool operator &= (const bool i) { if(i)data &= mask; return bool(data & mask); }
|
||||
};
|
||||
|
||||
public:
|
||||
union {
|
||||
uint8 data;
|
||||
bit<0x80> n;
|
||||
bit<0x40> v;
|
||||
bit<0x20> p;
|
||||
bit<0x10> b;
|
||||
bit<0x08> h;
|
||||
bit<0x04> i;
|
||||
bit<0x02> z;
|
||||
bit<0x01> c;
|
||||
};
|
||||
|
||||
inline operator unsigned() const { return data; }
|
||||
inline unsigned operator = (const uint8 i) { data = i; return data; }
|
||||
inline unsigned operator |= (const uint8 i) { data |= i; return data; }
|
||||
inline unsigned operator ^= (const uint8 i) { data ^= i; return data; }
|
||||
inline unsigned operator &= (const uint8 i) { data &= i; return data; }
|
||||
|
||||
APURegFlags() : data(0) {}
|
||||
};
|
||||
|
||||
class APURegs {
|
||||
public:
|
||||
uint16 pc;
|
||||
union {
|
||||
uint16 ya;
|
||||
struct { uint8 order_lsb2(a, y); };
|
||||
};
|
||||
uint8 x, sp;
|
||||
APURegFlags p;
|
||||
};
|
|
@ -1,3 +0,0 @@
|
|||
cl /O2 /wd4996 bapugen.cpp
|
||||
@pause
|
||||
@del *.obj
|
|
@ -1,256 +0,0 @@
|
|||
optbl[0x7d] = &bAPU::op_mov_a_x;
|
||||
optbl[0xdd] = &bAPU::op_mov_a_y;
|
||||
optbl[0x5d] = &bAPU::op_mov_x_a;
|
||||
optbl[0xfd] = &bAPU::op_mov_y_a;
|
||||
optbl[0x9d] = &bAPU::op_mov_x_sp;
|
||||
optbl[0xbd] = &bAPU::op_mov_sp_x;
|
||||
optbl[0xe8] = &bAPU::op_mov_a_const;
|
||||
optbl[0xcd] = &bAPU::op_mov_x_const;
|
||||
optbl[0x8d] = &bAPU::op_mov_y_const;
|
||||
optbl[0xe6] = &bAPU::op_mov_a_ix;
|
||||
optbl[0xbf] = &bAPU::op_mov_a_ixinc;
|
||||
optbl[0xe4] = &bAPU::op_mov_a_dp;
|
||||
optbl[0xf8] = &bAPU::op_mov_x_dp;
|
||||
optbl[0xeb] = &bAPU::op_mov_y_dp;
|
||||
optbl[0xf4] = &bAPU::op_mov_a_dpx;
|
||||
optbl[0xf9] = &bAPU::op_mov_x_dpy;
|
||||
optbl[0xfb] = &bAPU::op_mov_y_dpx;
|
||||
optbl[0xe5] = &bAPU::op_mov_a_addr;
|
||||
optbl[0xe9] = &bAPU::op_mov_x_addr;
|
||||
optbl[0xec] = &bAPU::op_mov_y_addr;
|
||||
optbl[0xf5] = &bAPU::op_mov_a_addrx;
|
||||
optbl[0xf6] = &bAPU::op_mov_a_addry;
|
||||
optbl[0xe7] = &bAPU::op_mov_a_idpx;
|
||||
optbl[0xf7] = &bAPU::op_mov_a_idpy;
|
||||
optbl[0xfa] = &bAPU::op_mov_dp_dp;
|
||||
optbl[0x8f] = &bAPU::op_mov_dp_const;
|
||||
optbl[0xc6] = &bAPU::op_mov_ix_a;
|
||||
optbl[0xaf] = &bAPU::op_mov_ixinc_a;
|
||||
optbl[0xc4] = &bAPU::op_mov_dp_a;
|
||||
optbl[0xd8] = &bAPU::op_mov_dp_x;
|
||||
optbl[0xcb] = &bAPU::op_mov_dp_y;
|
||||
optbl[0xd4] = &bAPU::op_mov_dpx_a;
|
||||
optbl[0xd9] = &bAPU::op_mov_dpy_x;
|
||||
optbl[0xdb] = &bAPU::op_mov_dpx_y;
|
||||
optbl[0xc5] = &bAPU::op_mov_addr_a;
|
||||
optbl[0xc9] = &bAPU::op_mov_addr_x;
|
||||
optbl[0xcc] = &bAPU::op_mov_addr_y;
|
||||
optbl[0xd5] = &bAPU::op_mov_addrx_a;
|
||||
optbl[0xd6] = &bAPU::op_mov_addry_a;
|
||||
optbl[0xc7] = &bAPU::op_mov_idpx_a;
|
||||
optbl[0xd7] = &bAPU::op_mov_idpy_a;
|
||||
optbl[0xba] = &bAPU::op_movw_ya_dp;
|
||||
optbl[0xda] = &bAPU::op_movw_dp_ya;
|
||||
optbl[0xaa] = &bAPU::op_mov1_c_bit;
|
||||
optbl[0xca] = &bAPU::op_mov1_bit_c;
|
||||
optbl[0x2f] = &bAPU::op_bra;
|
||||
optbl[0xf0] = &bAPU::op_beq;
|
||||
optbl[0xd0] = &bAPU::op_bne;
|
||||
optbl[0xb0] = &bAPU::op_bcs;
|
||||
optbl[0x90] = &bAPU::op_bcc;
|
||||
optbl[0x70] = &bAPU::op_bvs;
|
||||
optbl[0x50] = &bAPU::op_bvc;
|
||||
optbl[0x30] = &bAPU::op_bmi;
|
||||
optbl[0x10] = &bAPU::op_bpl;
|
||||
optbl[0x03] = &bAPU::op_bbs0;
|
||||
optbl[0x13] = &bAPU::op_bbc0;
|
||||
optbl[0x23] = &bAPU::op_bbs1;
|
||||
optbl[0x33] = &bAPU::op_bbc1;
|
||||
optbl[0x43] = &bAPU::op_bbs2;
|
||||
optbl[0x53] = &bAPU::op_bbc2;
|
||||
optbl[0x63] = &bAPU::op_bbs3;
|
||||
optbl[0x73] = &bAPU::op_bbc3;
|
||||
optbl[0x83] = &bAPU::op_bbs4;
|
||||
optbl[0x93] = &bAPU::op_bbc4;
|
||||
optbl[0xa3] = &bAPU::op_bbs5;
|
||||
optbl[0xb3] = &bAPU::op_bbc5;
|
||||
optbl[0xc3] = &bAPU::op_bbs6;
|
||||
optbl[0xd3] = &bAPU::op_bbc6;
|
||||
optbl[0xe3] = &bAPU::op_bbs7;
|
||||
optbl[0xf3] = &bAPU::op_bbc7;
|
||||
optbl[0x2e] = &bAPU::op_cbne_dp;
|
||||
optbl[0xde] = &bAPU::op_cbne_dpx;
|
||||
optbl[0x6e] = &bAPU::op_dbnz_dp;
|
||||
optbl[0xfe] = &bAPU::op_dbnz_y;
|
||||
optbl[0x5f] = &bAPU::op_jmp_addr;
|
||||
optbl[0x1f] = &bAPU::op_jmp_iaddrx;
|
||||
optbl[0x3f] = &bAPU::op_call;
|
||||
optbl[0x4f] = &bAPU::op_pcall;
|
||||
optbl[0x01] = &bAPU::op_tcall_0;
|
||||
optbl[0x11] = &bAPU::op_tcall_1;
|
||||
optbl[0x21] = &bAPU::op_tcall_2;
|
||||
optbl[0x31] = &bAPU::op_tcall_3;
|
||||
optbl[0x41] = &bAPU::op_tcall_4;
|
||||
optbl[0x51] = &bAPU::op_tcall_5;
|
||||
optbl[0x61] = &bAPU::op_tcall_6;
|
||||
optbl[0x71] = &bAPU::op_tcall_7;
|
||||
optbl[0x81] = &bAPU::op_tcall_8;
|
||||
optbl[0x91] = &bAPU::op_tcall_9;
|
||||
optbl[0xa1] = &bAPU::op_tcall_10;
|
||||
optbl[0xb1] = &bAPU::op_tcall_11;
|
||||
optbl[0xc1] = &bAPU::op_tcall_12;
|
||||
optbl[0xd1] = &bAPU::op_tcall_13;
|
||||
optbl[0xe1] = &bAPU::op_tcall_14;
|
||||
optbl[0xf1] = &bAPU::op_tcall_15;
|
||||
optbl[0x0f] = &bAPU::op_brk;
|
||||
optbl[0x6f] = &bAPU::op_ret;
|
||||
optbl[0x7f] = &bAPU::op_reti;
|
||||
optbl[0x88] = &bAPU::op_adc_a_const;
|
||||
optbl[0x28] = &bAPU::op_and_a_const;
|
||||
optbl[0x68] = &bAPU::op_cmp_a_const;
|
||||
optbl[0xc8] = &bAPU::op_cmp_x_const;
|
||||
optbl[0xad] = &bAPU::op_cmp_y_const;
|
||||
optbl[0x48] = &bAPU::op_eor_a_const;
|
||||
optbl[0x08] = &bAPU::op_or_a_const;
|
||||
optbl[0xa8] = &bAPU::op_sbc_a_const;
|
||||
optbl[0x86] = &bAPU::op_adc_a_ix;
|
||||
optbl[0x26] = &bAPU::op_and_a_ix;
|
||||
optbl[0x66] = &bAPU::op_cmp_a_ix;
|
||||
optbl[0x46] = &bAPU::op_eor_a_ix;
|
||||
optbl[0x06] = &bAPU::op_or_a_ix;
|
||||
optbl[0xa6] = &bAPU::op_sbc_a_ix;
|
||||
optbl[0x84] = &bAPU::op_adc_a_dp;
|
||||
optbl[0x24] = &bAPU::op_and_a_dp;
|
||||
optbl[0x64] = &bAPU::op_cmp_a_dp;
|
||||
optbl[0x3e] = &bAPU::op_cmp_x_dp;
|
||||
optbl[0x7e] = &bAPU::op_cmp_y_dp;
|
||||
optbl[0x44] = &bAPU::op_eor_a_dp;
|
||||
optbl[0x04] = &bAPU::op_or_a_dp;
|
||||
optbl[0xa4] = &bAPU::op_sbc_a_dp;
|
||||
optbl[0x94] = &bAPU::op_adc_a_dpx;
|
||||
optbl[0x34] = &bAPU::op_and_a_dpx;
|
||||
optbl[0x74] = &bAPU::op_cmp_a_dpx;
|
||||
optbl[0x54] = &bAPU::op_eor_a_dpx;
|
||||
optbl[0x14] = &bAPU::op_or_a_dpx;
|
||||
optbl[0xb4] = &bAPU::op_sbc_a_dpx;
|
||||
optbl[0x85] = &bAPU::op_adc_a_addr;
|
||||
optbl[0x25] = &bAPU::op_and_a_addr;
|
||||
optbl[0x65] = &bAPU::op_cmp_a_addr;
|
||||
optbl[0x1e] = &bAPU::op_cmp_x_addr;
|
||||
optbl[0x5e] = &bAPU::op_cmp_y_addr;
|
||||
optbl[0x45] = &bAPU::op_eor_a_addr;
|
||||
optbl[0x05] = &bAPU::op_or_a_addr;
|
||||
optbl[0xa5] = &bAPU::op_sbc_a_addr;
|
||||
optbl[0x95] = &bAPU::op_adc_a_addrx;
|
||||
optbl[0x96] = &bAPU::op_adc_a_addry;
|
||||
optbl[0x35] = &bAPU::op_and_a_addrx;
|
||||
optbl[0x36] = &bAPU::op_and_a_addry;
|
||||
optbl[0x75] = &bAPU::op_cmp_a_addrx;
|
||||
optbl[0x76] = &bAPU::op_cmp_a_addry;
|
||||
optbl[0x55] = &bAPU::op_eor_a_addrx;
|
||||
optbl[0x56] = &bAPU::op_eor_a_addry;
|
||||
optbl[0x15] = &bAPU::op_or_a_addrx;
|
||||
optbl[0x16] = &bAPU::op_or_a_addry;
|
||||
optbl[0xb5] = &bAPU::op_sbc_a_addrx;
|
||||
optbl[0xb6] = &bAPU::op_sbc_a_addry;
|
||||
optbl[0x87] = &bAPU::op_adc_a_idpx;
|
||||
optbl[0x27] = &bAPU::op_and_a_idpx;
|
||||
optbl[0x67] = &bAPU::op_cmp_a_idpx;
|
||||
optbl[0x47] = &bAPU::op_eor_a_idpx;
|
||||
optbl[0x07] = &bAPU::op_or_a_idpx;
|
||||
optbl[0xa7] = &bAPU::op_sbc_a_idpx;
|
||||
optbl[0x97] = &bAPU::op_adc_a_idpy;
|
||||
optbl[0x37] = &bAPU::op_and_a_idpy;
|
||||
optbl[0x77] = &bAPU::op_cmp_a_idpy;
|
||||
optbl[0x57] = &bAPU::op_eor_a_idpy;
|
||||
optbl[0x17] = &bAPU::op_or_a_idpy;
|
||||
optbl[0xb7] = &bAPU::op_sbc_a_idpy;
|
||||
optbl[0x99] = &bAPU::op_adc_ix_iy;
|
||||
optbl[0x39] = &bAPU::op_and_ix_iy;
|
||||
optbl[0x79] = &bAPU::op_cmp_ix_iy;
|
||||
optbl[0x59] = &bAPU::op_eor_ix_iy;
|
||||
optbl[0x19] = &bAPU::op_or_ix_iy;
|
||||
optbl[0xb9] = &bAPU::op_sbc_ix_iy;
|
||||
optbl[0x89] = &bAPU::op_adc_dp_dp;
|
||||
optbl[0x29] = &bAPU::op_and_dp_dp;
|
||||
optbl[0x69] = &bAPU::op_cmp_dp_dp;
|
||||
optbl[0x49] = &bAPU::op_eor_dp_dp;
|
||||
optbl[0x09] = &bAPU::op_or_dp_dp;
|
||||
optbl[0xa9] = &bAPU::op_sbc_dp_dp;
|
||||
optbl[0x98] = &bAPU::op_adc_dp_const;
|
||||
optbl[0x38] = &bAPU::op_and_dp_const;
|
||||
optbl[0x78] = &bAPU::op_cmp_dp_const;
|
||||
optbl[0x58] = &bAPU::op_eor_dp_const;
|
||||
optbl[0x18] = &bAPU::op_or_dp_const;
|
||||
optbl[0xb8] = &bAPU::op_sbc_dp_const;
|
||||
optbl[0x7a] = &bAPU::op_addw_ya_dp;
|
||||
optbl[0x5a] = &bAPU::op_cmpw_ya_dp;
|
||||
optbl[0x9a] = &bAPU::op_subw_ya_dp;
|
||||
optbl[0x4a] = &bAPU::op_and1_bit;
|
||||
optbl[0x6a] = &bAPU::op_and1_notbit;
|
||||
optbl[0x8a] = &bAPU::op_eor1_bit;
|
||||
optbl[0xea] = &bAPU::op_not1_bit;
|
||||
optbl[0x0a] = &bAPU::op_or1_bit;
|
||||
optbl[0x2a] = &bAPU::op_or1_notbit;
|
||||
optbl[0xbc] = &bAPU::op_inc_a;
|
||||
optbl[0x3d] = &bAPU::op_inc_x;
|
||||
optbl[0xfc] = &bAPU::op_inc_y;
|
||||
optbl[0x9c] = &bAPU::op_dec_a;
|
||||
optbl[0x1d] = &bAPU::op_dec_x;
|
||||
optbl[0xdc] = &bAPU::op_dec_y;
|
||||
optbl[0x1c] = &bAPU::op_asl_a;
|
||||
optbl[0x5c] = &bAPU::op_lsr_a;
|
||||
optbl[0x3c] = &bAPU::op_rol_a;
|
||||
optbl[0x7c] = &bAPU::op_ror_a;
|
||||
optbl[0xab] = &bAPU::op_inc_dp;
|
||||
optbl[0x8b] = &bAPU::op_dec_dp;
|
||||
optbl[0x0b] = &bAPU::op_asl_dp;
|
||||
optbl[0x4b] = &bAPU::op_lsr_dp;
|
||||
optbl[0x2b] = &bAPU::op_rol_dp;
|
||||
optbl[0x6b] = &bAPU::op_ror_dp;
|
||||
optbl[0xbb] = &bAPU::op_inc_dpx;
|
||||
optbl[0x9b] = &bAPU::op_dec_dpx;
|
||||
optbl[0x1b] = &bAPU::op_asl_dpx;
|
||||
optbl[0x5b] = &bAPU::op_lsr_dpx;
|
||||
optbl[0x3b] = &bAPU::op_rol_dpx;
|
||||
optbl[0x7b] = &bAPU::op_ror_dpx;
|
||||
optbl[0xac] = &bAPU::op_inc_addr;
|
||||
optbl[0x8c] = &bAPU::op_dec_addr;
|
||||
optbl[0x0c] = &bAPU::op_asl_addr;
|
||||
optbl[0x4c] = &bAPU::op_lsr_addr;
|
||||
optbl[0x2c] = &bAPU::op_rol_addr;
|
||||
optbl[0x6c] = &bAPU::op_ror_addr;
|
||||
optbl[0x3a] = &bAPU::op_incw_dp;
|
||||
optbl[0x1a] = &bAPU::op_decw_dp;
|
||||
optbl[0x00] = &bAPU::op_nop;
|
||||
optbl[0xef] = &bAPU::op_sleep;
|
||||
optbl[0xff] = &bAPU::op_stop;
|
||||
optbl[0x9f] = &bAPU::op_xcn;
|
||||
optbl[0xdf] = &bAPU::op_daa;
|
||||
optbl[0xbe] = &bAPU::op_das;
|
||||
optbl[0x60] = &bAPU::op_clrc;
|
||||
optbl[0x20] = &bAPU::op_clrp;
|
||||
optbl[0x80] = &bAPU::op_setc;
|
||||
optbl[0x40] = &bAPU::op_setp;
|
||||
optbl[0xe0] = &bAPU::op_clrv;
|
||||
optbl[0xed] = &bAPU::op_notc;
|
||||
optbl[0xa0] = &bAPU::op_ei;
|
||||
optbl[0xc0] = &bAPU::op_di;
|
||||
optbl[0x02] = &bAPU::op_set0_dp;
|
||||
optbl[0x12] = &bAPU::op_clr0_dp;
|
||||
optbl[0x22] = &bAPU::op_set1_dp;
|
||||
optbl[0x32] = &bAPU::op_clr1_dp;
|
||||
optbl[0x42] = &bAPU::op_set2_dp;
|
||||
optbl[0x52] = &bAPU::op_clr2_dp;
|
||||
optbl[0x62] = &bAPU::op_set3_dp;
|
||||
optbl[0x72] = &bAPU::op_clr3_dp;
|
||||
optbl[0x82] = &bAPU::op_set4_dp;
|
||||
optbl[0x92] = &bAPU::op_clr4_dp;
|
||||
optbl[0xa2] = &bAPU::op_set5_dp;
|
||||
optbl[0xb2] = &bAPU::op_clr5_dp;
|
||||
optbl[0xc2] = &bAPU::op_set6_dp;
|
||||
optbl[0xd2] = &bAPU::op_clr6_dp;
|
||||
optbl[0xe2] = &bAPU::op_set7_dp;
|
||||
optbl[0xf2] = &bAPU::op_clr7_dp;
|
||||
optbl[0x0e] = &bAPU::op_tset_addr_a;
|
||||
optbl[0x4e] = &bAPU::op_tclr_addr_a;
|
||||
optbl[0x2d] = &bAPU::op_push_a;
|
||||
optbl[0x4d] = &bAPU::op_push_x;
|
||||
optbl[0x6d] = &bAPU::op_push_y;
|
||||
optbl[0x0d] = &bAPU::op_push_p;
|
||||
optbl[0xae] = &bAPU::op_pop_a;
|
||||
optbl[0xce] = &bAPU::op_pop_x;
|
||||
optbl[0xee] = &bAPU::op_pop_y;
|
||||
optbl[0x8e] = &bAPU::op_pop_p;
|
||||
optbl[0xcf] = &bAPU::op_mul_ya;
|
||||
optbl[0x9e] = &bAPU::op_div_ya_x;
|
306
src/apu/dapu.cpp
306
src/apu/dapu.cpp
|
@ -1,306 +0,0 @@
|
|||
//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, 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);
|
||||
op0 = spcram_read(regs.pc + 1);
|
||||
op1 = spcram_read(regs.pc + 2);
|
||||
opw = (op0) | (op1 << 8);
|
||||
opdp0 = ((regs.p.p)?0x100:0x000) + op0;
|
||||
opdp1 = ((regs.p.p)?0x100:0x000) + op1;
|
||||
|
||||
strcpy(t, " ");
|
||||
switch(op) {
|
||||
case 0x00:sprintf(t, "nop"); break;
|
||||
case 0x01:sprintf(t, "tcall 0"); break;
|
||||
case 0x02:sprintf(t, "set0 $%0.3x", opdp0); break;
|
||||
case 0x03:sprintf(t, "bbs0 $%0.3x,$%0.4x", opdp0, __relb(op1, 3)); break;
|
||||
case 0x04:sprintf(t, "or a,$%0.3x", opdp0); break;
|
||||
case 0x05:sprintf(t, "or a,$%0.4x", opw); break;
|
||||
case 0x06:sprintf(t, "or a,(x)"); break;
|
||||
case 0x07:sprintf(t, "or a,($%0.3x+x)", opdp0); break;
|
||||
case 0x08:sprintf(t, "or a,#$%0.2x", op0); break;
|
||||
case 0x09:sprintf(t, "or $%0.3x,$%0.3x", opdp1, opdp0); break;
|
||||
case 0x0a:sprintf(t, "or1 c,$%0.4x:%d", opw & 0x1fff, opw >> 13); break;
|
||||
case 0x0b:sprintf(t, "asl $%0.3x", opdp0); break;
|
||||
case 0x0c:sprintf(t, "asl $%0.4x", opw); break;
|
||||
case 0x0d:sprintf(t, "push p"); break;
|
||||
case 0x0e:sprintf(t, "tset $%0.4x,a", opw); break;
|
||||
case 0x0f:sprintf(t, "brk"); break;
|
||||
case 0x10:sprintf(t, "bpl $%0.4x", __relb(op0, 2)); break;
|
||||
case 0x11:sprintf(t, "tcall 1"); break;
|
||||
case 0x12:sprintf(t, "clr0 $%0.3x", opdp0); break;
|
||||
case 0x13:sprintf(t, "bbc0 $%0.3x,$%0.4x", opdp0, __relb(op1, 3)); break;
|
||||
case 0x14:sprintf(t, "or a,$%0.3x+x", opdp0); break;
|
||||
case 0x15:sprintf(t, "or a,$%0.4x+x", opw); break;
|
||||
case 0x16:sprintf(t, "or a,$%0.4x+y", opw); break;
|
||||
case 0x17:sprintf(t, "or a,($%0.3x)+y", opdp0); break;
|
||||
case 0x18:sprintf(t, "or $%0.3x,#$%0.2x", opdp1, op0); break;
|
||||
case 0x19:sprintf(t, "or (x),(y)"); break;
|
||||
case 0x1a:sprintf(t, "decw $%0.3x", opdp0); break;
|
||||
case 0x1b:sprintf(t, "asl $%0.3x+x", opdp0); break;
|
||||
case 0x1c:sprintf(t, "asl a"); break;
|
||||
case 0x1d:sprintf(t, "dec x"); break;
|
||||
case 0x1e:sprintf(t, "cmp x,$%0.4x", opw); break;
|
||||
case 0x1f:sprintf(t, "jmp ($%0.4x+x)", opw); break;
|
||||
case 0x20:sprintf(t, "clrp"); break;
|
||||
case 0x21:sprintf(t, "tcall 2"); break;
|
||||
case 0x22:sprintf(t, "set1 $%0.3x", opdp0); break;
|
||||
case 0x23:sprintf(t, "bbs1 $%0.3x,$%0.4x", opdp0, __relb(op1, 3)); break;
|
||||
case 0x24:sprintf(t, "and a,$%0.3x", opdp0); break;
|
||||
case 0x25:sprintf(t, "and a,$%0.4x", opw); break;
|
||||
case 0x26:sprintf(t, "and a,(x)"); break;
|
||||
case 0x27:sprintf(t, "and a,($%0.3x+x)", opdp0); break;
|
||||
case 0x28:sprintf(t, "and a,#$%0.2x", op0); break;
|
||||
case 0x29:sprintf(t, "and $%0.3x,$%0.3x", opdp1, opdp0); break;
|
||||
case 0x2a:sprintf(t, "or1 c,!$%0.4x:%d", opw & 0x1fff, opw >> 13); break;
|
||||
case 0x2b:sprintf(t, "rol $%0.3x", opdp0); break;
|
||||
case 0x2c:sprintf(t, "rol $%0.4x", opw); break;
|
||||
case 0x2d:sprintf(t, "push a"); break;
|
||||
case 0x2e:sprintf(t, "cbne $%0.3x,$%0.4x", opdp0, __relb(op1, 3)); break;
|
||||
case 0x2f:sprintf(t, "bra $%0.4x", __relb(op0, 2)); break;
|
||||
case 0x30:sprintf(t, "bmi $%0.4x", __relb(op0, 2)); break;
|
||||
case 0x31:sprintf(t, "tcall 3"); break;
|
||||
case 0x32:sprintf(t, "clr1 $%0.3x", opdp0); break;
|
||||
case 0x33:sprintf(t, "bbc1 $%0.3x,$%0.4x", opdp0, __relb(op1, 3)); break;
|
||||
case 0x34:sprintf(t, "and a,$%0.3x+x", opdp0); break;
|
||||
case 0x35:sprintf(t, "and a,$%0.4x+x", opw); break;
|
||||
case 0x36:sprintf(t, "and a,$%0.4x+y", opw); break;
|
||||
case 0x37:sprintf(t, "and a,($%0.3x)+y", opdp0); break;
|
||||
case 0x38:sprintf(t, "and $%0.3x,#$%0.2x", opdp1, op0); break;
|
||||
case 0x39:sprintf(t, "and (x),(y)"); break;
|
||||
case 0x3a:sprintf(t, "incw $%0.3x", opdp0); break;
|
||||
case 0x3b:sprintf(t, "rol $%0.3x+x", opdp0); break;
|
||||
case 0x3c:sprintf(t, "rol a"); break;
|
||||
case 0x3d:sprintf(t, "inc x"); break;
|
||||
case 0x3e:sprintf(t, "cmp x,$%0.3x", opdp0); break;
|
||||
case 0x3f:sprintf(t, "call $%0.4x", opw); break;
|
||||
case 0x40:sprintf(t, "setp"); break;
|
||||
case 0x41:sprintf(t, "tcall 4"); break;
|
||||
case 0x42:sprintf(t, "set2 $%0.3x", opdp0); break;
|
||||
case 0x43:sprintf(t, "bbs2 $%0.3x,$%0.4x", opdp0, __relb(op1, 3)); break;
|
||||
case 0x44:sprintf(t, "eor a,$%0.3x", opdp0); break;
|
||||
case 0x45:sprintf(t, "eor a,$%0.4x", opw); break;
|
||||
case 0x46:sprintf(t, "eor a,(x)"); break;
|
||||
case 0x47:sprintf(t, "eor a,($%0.3x+x)", opdp0); break;
|
||||
case 0x48:sprintf(t, "eor a,#$%0.2x", op0); break;
|
||||
case 0x49:sprintf(t, "eor $%0.3x,$%0.3x", opdp1, opdp0); break;
|
||||
case 0x4a:sprintf(t, "and1 c,$%0.4x:%d", opw & 0x1fff, opw >> 13); break;
|
||||
case 0x4b:sprintf(t, "lsr $%0.3x", opdp0); break;
|
||||
case 0x4c:sprintf(t, "lsr $%0.4x", opw); break;
|
||||
case 0x4d:sprintf(t, "push x"); break;
|
||||
case 0x4e:sprintf(t, "tclr $%0.4x,a", opw); break;
|
||||
case 0x4f:sprintf(t, "pcall $ff%0.2x", op0); break;
|
||||
case 0x50:sprintf(t, "bvc $%0.4x", __relb(op0, 2)); break;
|
||||
case 0x51:sprintf(t, "tcall 5"); break;
|
||||
case 0x52:sprintf(t, "clr2 $%0.3x", opdp0); break;
|
||||
case 0x53:sprintf(t, "bbc2 $%0.3x,$%0.4x", opdp0, __relb(op1, 3)); break;
|
||||
case 0x54:sprintf(t, "eor a,$%0.3x+x", opdp0); break;
|
||||
case 0x55:sprintf(t, "eor a,$%0.4x+x", opw); break;
|
||||
case 0x56:sprintf(t, "eor a,$%0.4x+y", opw); break;
|
||||
case 0x57:sprintf(t, "eor a,($%0.3x)+y", opdp0); break;
|
||||
case 0x58:sprintf(t, "eor $%0.3x,#$%0.2x", opdp1, op0); break;
|
||||
case 0x59:sprintf(t, "eor (x),(y)"); break;
|
||||
case 0x5a:sprintf(t, "cmpw ya,$%0.3x", opdp0); break;
|
||||
case 0x5b:sprintf(t, "lsr $%0.3x+x", opdp0); break;
|
||||
case 0x5c:sprintf(t, "lsr a"); break;
|
||||
case 0x5d:sprintf(t, "mov x,a"); break;
|
||||
case 0x5e:sprintf(t, "cmp y,$%0.4x", opw); break;
|
||||
case 0x5f:sprintf(t, "jmp $%0.4x", opw); break;
|
||||
case 0x60:sprintf(t, "clrc"); break;
|
||||
case 0x61:sprintf(t, "tcall 6"); break;
|
||||
case 0x62:sprintf(t, "set3 $%0.3x", opdp0); break;
|
||||
case 0x63:sprintf(t, "bbs3 $%0.3x,$%0.4x", opdp0, __relb(op1, 3)); break;
|
||||
case 0x64:sprintf(t, "cmp a,$%0.3x", opdp0); break;
|
||||
case 0x65:sprintf(t, "cmp a,$%0.4x", opw); break;
|
||||
case 0x66:sprintf(t, "cmp a,(x)"); break;
|
||||
case 0x67:sprintf(t, "cmp a,($%0.3x+x)", opdp0); break;
|
||||
case 0x68:sprintf(t, "cmp a,#$%0.2x", op0); break;
|
||||
case 0x69:sprintf(t, "cmp $%0.3x,$%0.3x", opdp1, opdp0); break;
|
||||
case 0x6a:sprintf(t, "and1 c,!$%0.4x:%d", opw & 0x1fff, opw >> 13); break;
|
||||
case 0x6b:sprintf(t, "ror $%0.3x", opdp0); break;
|
||||
case 0x6c:sprintf(t, "ror $%0.4x", opw); break;
|
||||
case 0x6d:sprintf(t, "push y"); break;
|
||||
case 0x6e:sprintf(t, "dbnz $%0.3x,$%0.4x", opdp0, __relb(op1, 3)); break;
|
||||
case 0x6f:sprintf(t, "ret"); break;
|
||||
case 0x70:sprintf(t, "bvs $%0.4x", __relb(op0, 2)); break;
|
||||
case 0x71:sprintf(t, "tcall 7"); break;
|
||||
case 0x72:sprintf(t, "clr3 $%0.3x", opdp0); break;
|
||||
case 0x73:sprintf(t, "bbc3 $%0.3x,$%0.4x", opdp0, __relb(op1, 3)); break;
|
||||
case 0x74:sprintf(t, "cmp a,$%0.3x+x", opdp0); break;
|
||||
case 0x75:sprintf(t, "cmp a,$%0.4x+x", opw); break;
|
||||
case 0x76:sprintf(t, "cmp a,$%0.4x+y", opw); break;
|
||||
case 0x77:sprintf(t, "cmp a,($%0.3x)+y", opdp0); break;
|
||||
case 0x78:sprintf(t, "cmp $%0.3x,#$%0.2x", opdp1, op0); break;
|
||||
case 0x79:sprintf(t, "cmp (x),(y)"); break;
|
||||
case 0x7a:sprintf(t, "addw ya,$%0.3x", opdp0); break;
|
||||
case 0x7b:sprintf(t, "ror $%0.3x+x", opdp0); break;
|
||||
case 0x7c:sprintf(t, "ror a"); break;
|
||||
case 0x7d:sprintf(t, "mov a,x"); break;
|
||||
case 0x7e:sprintf(t, "cmp y,$%0.3x", opdp0); break;
|
||||
case 0x7f:sprintf(t, "reti"); break;
|
||||
case 0x80:sprintf(t, "setc"); break;
|
||||
case 0x81:sprintf(t, "tcall 8"); break;
|
||||
case 0x82:sprintf(t, "set4 $%0.3x", opdp0); break;
|
||||
case 0x83:sprintf(t, "bbs4 $%0.3x,$%0.4x", opdp0, __relb(op1, 3)); break;
|
||||
case 0x84:sprintf(t, "adc a,$%0.3x", opdp0); break;
|
||||
case 0x85:sprintf(t, "adc a,$%0.4x", opw); break;
|
||||
case 0x86:sprintf(t, "adc a,(x)"); break;
|
||||
case 0x87:sprintf(t, "adc a,($%0.3x+x)", opdp0); break;
|
||||
case 0x88:sprintf(t, "adc a,#$%0.2x", op0); break;
|
||||
case 0x89:sprintf(t, "adc $%0.3x,$%0.3x", opdp1, opdp0); break;
|
||||
case 0x8a:sprintf(t, "eor1 c,$%0.4x:%d", opw & 0x1fff, opw >> 13); break;
|
||||
case 0x8b:sprintf(t, "dec $%0.3x", opdp0); break;
|
||||
case 0x8c:sprintf(t, "dec $%0.4x", opw); break;
|
||||
case 0x8d:sprintf(t, "mov y,#$%0.2x", op0); break;
|
||||
case 0x8e:sprintf(t, "pop p"); break;
|
||||
case 0x8f:sprintf(t, "mov $%0.3x,#$%0.2x", opdp1, op0); break;
|
||||
case 0x90:sprintf(t, "bcc $%0.4x", __relb(op0, 2)); break;
|
||||
case 0x91:sprintf(t, "tcall 9"); break;
|
||||
case 0x92:sprintf(t, "clr4 $%0.3x", opdp0); break;
|
||||
case 0x93:sprintf(t, "bbc4 $%0.3x,$%0.4x", opdp0, __relb(op1, 3)); break;
|
||||
case 0x94:sprintf(t, "adc a,$%0.3x+x", opdp0); break;
|
||||
case 0x95:sprintf(t, "adc a,$%0.4x+x", opw); break;
|
||||
case 0x96:sprintf(t, "adc a,$%0.4x+y", opw); break;
|
||||
case 0x97:sprintf(t, "adc a,($%0.3x)+y", opdp0); break;
|
||||
case 0x98:sprintf(t, "adc $%0.3x,#$%0.2x", opdp1, op0); break;
|
||||
case 0x99:sprintf(t, "adc (x),(y)"); break;
|
||||
case 0x9a:sprintf(t, "subw ya,$%0.3x", opdp0); break;
|
||||
case 0x9b:sprintf(t, "dec $%0.3x+x", opdp0); break;
|
||||
case 0x9c:sprintf(t, "dec a"); break;
|
||||
case 0x9d:sprintf(t, "mov x,sp"); break;
|
||||
case 0x9e:sprintf(t, "div ya,x"); break;
|
||||
case 0x9f:sprintf(t, "xcn a"); break;
|
||||
case 0xa0:sprintf(t, "ei"); break;
|
||||
case 0xa1:sprintf(t, "tcall 10"); break;
|
||||
case 0xa2:sprintf(t, "set5 $%0.3x", opdp0); break;
|
||||
case 0xa3:sprintf(t, "bbs5 $%0.3x,$%0.4x", opdp0, __relb(op1, 3)); break;
|
||||
case 0xa4:sprintf(t, "sbc a,$%0.3x", opdp0); break;
|
||||
case 0xa5:sprintf(t, "sbc a,$%0.4x", opw); break;
|
||||
case 0xa6:sprintf(t, "sbc a,(x)"); break;
|
||||
case 0xa7:sprintf(t, "sbc a,($%0.3x+x)", opdp0); break;
|
||||
case 0xa8:sprintf(t, "sbc a,#$%0.2x", op0); break;
|
||||
case 0xa9:sprintf(t, "sbc $%0.3x,$%0.3x", opdp1, opdp0); break;
|
||||
case 0xaa:sprintf(t, "mov1 c,$%0.4x:%d", opw & 0x1fff, opw >> 13); break;
|
||||
case 0xab:sprintf(t, "inc $%0.3x", opdp0); break;
|
||||
case 0xac:sprintf(t, "inc $%0.4x", opw); break;
|
||||
case 0xad:sprintf(t, "cmp y,#$%0.2x", op0); break;
|
||||
case 0xae:sprintf(t, "pop a"); break;
|
||||
case 0xaf:sprintf(t, "mov (x)+,a"); break;
|
||||
case 0xb0:sprintf(t, "bcs $%0.4x", __relb(op0, 2)); break;
|
||||
case 0xb1:sprintf(t, "tcall 11"); break;
|
||||
case 0xb2:sprintf(t, "clr5 $%0.3x", opdp0); break;
|
||||
case 0xb3:sprintf(t, "bbc5 $%0.3x,$%0.4x", opdp0, __relb(op1, 3)); break;
|
||||
case 0xb4:sprintf(t, "sbc a,$%0.3x+x", opdp0); break;
|
||||
case 0xb5:sprintf(t, "sbc a,$%0.4x+x", opw); break;
|
||||
case 0xb6:sprintf(t, "sbc a,$%0.4x+y", opw); break;
|
||||
case 0xb7:sprintf(t, "sbc a,($%0.3x)+y", opdp0); break;
|
||||
case 0xb8:sprintf(t, "sbc $%0.3x,#$%0.2x", opdp1, op0); break;
|
||||
case 0xb9:sprintf(t, "sbc (x),(y)"); break;
|
||||
case 0xba:sprintf(t, "movw ya,$%0.3x", opdp0); break;
|
||||
case 0xbb:sprintf(t, "inc $%0.3x+x", opdp0); break;
|
||||
case 0xbc:sprintf(t, "inc a"); break;
|
||||
case 0xbd:sprintf(t, "mov sp,x"); break;
|
||||
case 0xbe:sprintf(t, "das a"); break;
|
||||
case 0xbf:sprintf(t, "mov a,(x)+"); break;
|
||||
case 0xc0:sprintf(t, "di"); break;
|
||||
case 0xc1:sprintf(t, "tcall 12"); break;
|
||||
case 0xc2:sprintf(t, "set6 $%0.3x", opdp0); break;
|
||||
case 0xc3:sprintf(t, "bbs6 $%0.3x,$%0.4x", opdp0, __relb(op1, 3)); break;
|
||||
case 0xc4:sprintf(t, "mov $%0.3x,a", opdp0); break;
|
||||
case 0xc5:sprintf(t, "mov $%0.4x,a", opw); break;
|
||||
case 0xc6:sprintf(t, "mov (x),a"); break;
|
||||
case 0xc7:sprintf(t, "mov ($%0.3x+x),a", opdp0); break;
|
||||
case 0xc8:sprintf(t, "cmp x,#$%0.2x", op0); break;
|
||||
case 0xc9:sprintf(t, "mov $%0.4x,x", opw); break;
|
||||
case 0xca:sprintf(t, "mov1 $%0.4x:%d,c", opw & 0x1fff, opw >> 13); break;
|
||||
case 0xcb:sprintf(t, "mov $%0.3x,y", opdp0); break;
|
||||
case 0xcc:sprintf(t, "mov $%0.4x,y", opw); break;
|
||||
case 0xcd:sprintf(t, "mov x,#$%0.2x", op0); break;
|
||||
case 0xce:sprintf(t, "pop x"); break;
|
||||
case 0xcf:sprintf(t, "mul ya"); break;
|
||||
case 0xd0:sprintf(t, "bne $%0.4x", __relb(op0, 2)); break;
|
||||
case 0xd1:sprintf(t, "tcall 13"); break;
|
||||
case 0xd2:sprintf(t, "clr6 $%0.3x", opdp0); break;
|
||||
case 0xd3:sprintf(t, "bbc6 $%0.3x,$%0.4x", opdp0, __relb(op1, 3)); break;
|
||||
case 0xd4:sprintf(t, "mov $%0.3x+x,a", opdp0); break;
|
||||
case 0xd5:sprintf(t, "mov $%0.4x+x,a", opw); break;
|
||||
case 0xd6:sprintf(t, "mov $%0.4x+y,a", opw); break;
|
||||
case 0xd7:sprintf(t, "mov ($%0.3x)+y,a", opdp0); break;
|
||||
case 0xd8:sprintf(t, "mov $%0.3x,x", opdp0); break;
|
||||
case 0xd9:sprintf(t, "mov $%0.3x+y,x", opdp0); break;
|
||||
case 0xda:sprintf(t, "movw $%0.3x,ya", opdp0); break;
|
||||
case 0xdb:sprintf(t, "mov $%0.3x+x,y", opdp0); break;
|
||||
case 0xdc:sprintf(t, "dec y"); break;
|
||||
case 0xdd:sprintf(t, "mov a,y"); break;
|
||||
case 0xde:sprintf(t, "cbne $%0.3x+x,$%0.4x", opdp0, __relb(op1, 3));break;
|
||||
case 0xdf:sprintf(t, "daa a"); break;
|
||||
case 0xe0:sprintf(t, "clrv"); break;
|
||||
case 0xe1:sprintf(t, "tcall 14"); break;
|
||||
case 0xe2:sprintf(t, "set7 $%0.3x", opdp0); break;
|
||||
case 0xe3:sprintf(t, "bbs7 $%0.3x,$%0.4x", opdp0, __relb(op1, 3)); break;
|
||||
case 0xe4:sprintf(t, "mov a,$%0.3x", opdp0); break;
|
||||
case 0xe5:sprintf(t, "mov a,$%0.4x", opw); break;
|
||||
case 0xe6:sprintf(t, "mov a,(x)"); break;
|
||||
case 0xe7:sprintf(t, "mov a,($%0.3x+x)", opdp0); break;
|
||||
case 0xe8:sprintf(t, "mov a,#$%0.2x", op0); break;
|
||||
case 0xe9:sprintf(t, "mov x,$%0.4x", opw); break;
|
||||
case 0xea:sprintf(t, "not1 c,$%0.4x:%d", opw & 0x1fff, opw >> 13); break;
|
||||
case 0xeb:sprintf(t, "mov y,$%0.3x", opdp0); break;
|
||||
case 0xec:sprintf(t, "mov y,$%0.4x", opw); break;
|
||||
case 0xed:sprintf(t, "notc"); break;
|
||||
case 0xee:sprintf(t, "pop y"); break;
|
||||
case 0xef:sprintf(t, "sleep"); break;
|
||||
case 0xf0:sprintf(t, "beq $%0.4x", __relb(op0, 2)); break;
|
||||
case 0xf1:sprintf(t, "tcall 15"); break;
|
||||
case 0xf2:sprintf(t, "clr7 $%0.3x", opdp0); break;
|
||||
case 0xf3:sprintf(t, "bbc7 $%0.3x,$%0.4x", opdp0, __relb(op1, 3)); break;
|
||||
case 0xf4:sprintf(t, "mov a,$%0.3x+x", opdp0); break;
|
||||
case 0xf5:sprintf(t, "mov a,$%0.4x+x", opw); break;
|
||||
case 0xf6:sprintf(t, "mov a,$%0.4x+y", opw); break;
|
||||
case 0xf7:sprintf(t, "mov a,($%0.3x)+y", opdp0); break;
|
||||
case 0xf8:sprintf(t, "mov x,$%0.3x", opdp0); break;
|
||||
case 0xf9:sprintf(t, "mov x,$%0.3x+y", opdp0); break;
|
||||
case 0xfa:sprintf(t, "mov $%0.3x,$%0.3x", opdp1, opdp0); break;
|
||||
case 0xfb:sprintf(t, "mov y,$%0.3x+x", opdp0); break;
|
||||
case 0xfc:sprintf(t, "inc y"); break;
|
||||
case 0xfd:sprintf(t, "mov y,a"); break;
|
||||
case 0xfe:sprintf(t, "dbnz y,$%0.4x", __relb(op0, 2)); break;
|
||||
case 0xff:sprintf(t, "stop"); break;
|
||||
}
|
||||
t[strlen(t)] = ' ';
|
||||
strcat(s, t);
|
||||
|
||||
sprintf(t, "A:%0.2x X:%0.2x Y:%0.2x SP:01%0.2x YA:%0.4x ",
|
||||
regs.a, regs.x, regs.y, regs.sp, regs.ya);
|
||||
strcat(s, t);
|
||||
|
||||
sprintf(t, "%c%c%c%c%c%c%c%c",
|
||||
(regs.p.n)?'N':'n',
|
||||
(regs.p.v)?'V':'v',
|
||||
(regs.p.p)?'P':'p',
|
||||
(regs.p.b)?'B':'b',
|
||||
(regs.p.h)?'H':'h',
|
||||
(regs.p.i)?'I':'i',
|
||||
(regs.p.z)?'Z':'z',
|
||||
(regs.p.c)?'C':'c');
|
||||
strcat(s, t);
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
cl /O2 /wd4996 sapugen.cpp
|
||||
@pause
|
||||
@del *.obj
|
|
@ -1,201 +0,0 @@
|
|||
uint8 sAPU::spcram_read(uint16 addr) {
|
||||
uint8 r;
|
||||
if((addr & 0xfff0) == 0x00f0) {
|
||||
//addr >= 0x00f0 && addr <= 0x00ff
|
||||
|
||||
#ifdef FAVOR_SPEED
|
||||
co_return();
|
||||
#endif
|
||||
|
||||
switch(addr) {
|
||||
case 0xf0: //TEST -- operation unknown, supposedly returns 0x00
|
||||
r = 0x00;
|
||||
break;
|
||||
case 0xf1: //CONTROL -- write-only register, always returns 0x00
|
||||
r = 0x00;
|
||||
break;
|
||||
case 0xf2: //DSPADDR
|
||||
r = status.dsp_addr;
|
||||
break;
|
||||
case 0xf3: //DSPDATA
|
||||
//0x80-0xff is a read-only mirror of 0x00-0x7f
|
||||
r = r_dsp->read(status.dsp_addr & 0x7f);
|
||||
break;
|
||||
case 0xf4: //CPUIO0
|
||||
case 0xf5: //CPUIO1
|
||||
case 0xf6: //CPUIO2
|
||||
case 0xf7: //CPUIO3
|
||||
r = r_cpu->port_read(addr & 3);
|
||||
break;
|
||||
case 0xf8: //???
|
||||
case 0xf9: //??? -- Mapped to SPCRAM
|
||||
r = spcram[addr];
|
||||
break;
|
||||
case 0xfa: //T0TARGET
|
||||
case 0xfb: //T1TARGET
|
||||
case 0xfc: //T2TARGET -- write-only registers, always return 0x00
|
||||
r = 0x00;
|
||||
break;
|
||||
case 0xfd: //T0OUT -- 4-bit counter value
|
||||
r = t0.stage3_ticks & 15;
|
||||
t0.stage3_ticks = 0;
|
||||
break;
|
||||
case 0xfe: //T1OUT -- 4-bit counter value
|
||||
r = t1.stage3_ticks & 15;
|
||||
t1.stage3_ticks = 0;
|
||||
break;
|
||||
case 0xff: //T2OUT -- 4-bit counter value
|
||||
r = t2.stage3_ticks & 15;
|
||||
t2.stage3_ticks = 0;
|
||||
break;
|
||||
}
|
||||
} else if(addr < 0xffc0) {
|
||||
r = spcram[addr];
|
||||
} else {
|
||||
if(status.iplrom_enabled == true) {
|
||||
r = iplrom[addr & 0x3f];
|
||||
} else {
|
||||
r = spcram[addr];
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::SPCRAM_READ, addr, r);
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
void sAPU::spcram_write(uint16 addr, uint8 data) {
|
||||
if((addr & 0xfff0) == 0x00f0) {
|
||||
//addr >= 0x00f0 && addr >= 0x00ff
|
||||
|
||||
#ifdef FAVOR_SPEED
|
||||
co_return();
|
||||
#endif
|
||||
|
||||
switch(addr) {
|
||||
case 0xf0: //TEST -- operation unknown
|
||||
break;
|
||||
case 0xf1: //CONTROL
|
||||
status.iplrom_enabled = !!(data & 0x80);
|
||||
|
||||
//one-time clearing of APU port read registers,
|
||||
//emulated by simulating CPU writes of 0x00
|
||||
if(data & 0x20) {
|
||||
r_cpu->port_write(2, 0x00);
|
||||
r_cpu->port_write(3, 0x00);
|
||||
}
|
||||
if(data & 0x10) {
|
||||
r_cpu->port_write(0, 0x00);
|
||||
r_cpu->port_write(1, 0x00);
|
||||
}
|
||||
|
||||
//0->1 transistion resets timers
|
||||
if(t2.enabled == false && (data & 0x04)) {
|
||||
t2.stage2_ticks = 0;
|
||||
t2.stage3_ticks = 0;
|
||||
}
|
||||
t2.enabled = !!(data & 0x04);
|
||||
|
||||
if(t1.enabled == false && (data & 0x02)) {
|
||||
t1.stage2_ticks = 0;
|
||||
t1.stage3_ticks = 0;
|
||||
}
|
||||
t1.enabled = !!(data & 0x02);
|
||||
|
||||
if(t0.enabled == false && (data & 0x01)) {
|
||||
t0.stage2_ticks = 0;
|
||||
t0.stage3_ticks = 0;
|
||||
}
|
||||
t0.enabled = !!(data & 0x01);
|
||||
break;
|
||||
case 0xf2: //DSPADDR
|
||||
status.dsp_addr = data;
|
||||
break;
|
||||
case 0xf3: //DSPDATA
|
||||
//0x80-0xff is a read-only mirror of 0x00-0x7f
|
||||
if(status.dsp_addr < 0x80) {
|
||||
r_dsp->write(status.dsp_addr & 0x7f, data);
|
||||
}
|
||||
break;
|
||||
case 0xf4: //CPUIO0
|
||||
case 0xf5: //CPUIO1
|
||||
case 0xf6: //CPUIO2
|
||||
case 0xf7: //CPUIO3
|
||||
port_write(addr & 3, data);
|
||||
break;
|
||||
case 0xf8: //???
|
||||
case 0xf9: //??? - Mapped to SPCRAM
|
||||
spcram[addr] = data;
|
||||
break;
|
||||
case 0xfa: //T0TARGET
|
||||
t0.target = data;
|
||||
break;
|
||||
case 0xfb: //T1TARGET
|
||||
t1.target = data;
|
||||
break;
|
||||
case 0xfc: //T2TARGET
|
||||
t2.target = data;
|
||||
break;
|
||||
case 0xfd: //T0OUT
|
||||
case 0xfe: //T1OUT
|
||||
case 0xff: //T2OUT -- read-only registers
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
//writes to $ffc0-$ffff always go to spcram,
|
||||
//even if the iplrom is enabled.
|
||||
spcram[addr] = data;
|
||||
}
|
||||
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::SPCRAM_WRITE, addr, data);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8 sAPU::port_read(uint8 port) {
|
||||
return spcram[0xf4 + (port & 3)];
|
||||
}
|
||||
|
||||
void sAPU::port_write(uint8 port, uint8 data) {
|
||||
spcram[0xf4 + (port & 3)] = data;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void sAPU::op_io() {
|
||||
add_clocks(24);
|
||||
tick_timers();
|
||||
//co_return();
|
||||
}
|
||||
|
||||
uint8 sAPU::op_read(uint16 addr) {
|
||||
add_clocks(8);
|
||||
#ifdef FAVOR_ACCURACY
|
||||
co_return();
|
||||
#endif
|
||||
uint8 r = spcram_read(addr);
|
||||
add_clocks(16);
|
||||
tick_timers();
|
||||
return r;
|
||||
}
|
||||
|
||||
void sAPU::op_write(uint16 addr, uint8 data) {
|
||||
add_clocks(24);
|
||||
tick_timers();
|
||||
#ifdef FAVOR_ACCURACY
|
||||
co_return();
|
||||
#endif
|
||||
spcram_write(addr, data);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
uint8 sAPU::op_readpc () { return op_read(regs.pc++); }
|
||||
uint8 sAPU::op_readstack () { return op_read(0x0100 | ++regs.sp); }
|
||||
void sAPU::op_writestack(uint8 data) { op_write(0x0100 | regs.sp--, data); }
|
||||
uint8 sAPU::op_readaddr (uint16 addr) { return op_read(addr); }
|
||||
|
||||
void sAPU::op_writeaddr (uint16 addr, uint8 data) { op_write(addr, data); }
|
||||
uint8 sAPU::op_readdp (uint8 addr) { return op_read((uint(regs.p.p) << 8) + addr); }
|
||||
void sAPU::op_writedp (uint8 addr, uint8 data) { op_write((uint(regs.p.p) << 8) + addr, data); }
|
|
@ -1,24 +0,0 @@
|
|||
uint8 spcram_read (uint16 addr);
|
||||
void spcram_write(uint16 addr, uint8 data);
|
||||
|
||||
uint8 port_read (uint8 port);
|
||||
void port_write(uint8 port, uint8 data);
|
||||
|
||||
/*****
|
||||
* core APU bus functions
|
||||
*****/
|
||||
inline void op_io ();
|
||||
inline uint8 op_read (uint16 addr);
|
||||
inline void op_write(uint16 addr, uint8 data);
|
||||
|
||||
/*****
|
||||
* helper memory addressing functions used by APU core
|
||||
*****/
|
||||
inline uint8 op_readpc ();
|
||||
inline uint8 op_readstack ();
|
||||
inline void op_writestack(uint8 data);
|
||||
inline uint8 op_readaddr (uint16 addr);
|
||||
|
||||
inline void op_writeaddr (uint16 addr, uint8 data);
|
||||
inline uint8 op_readdp (uint8 addr);
|
||||
inline void op_writedp (uint8 addr, uint8 data);
|
|
@ -1,35 +0,0 @@
|
|||
void sAPU::add_clocks(int clocks) {
|
||||
status.clocks_executed += clocks;
|
||||
}
|
||||
|
||||
uint32 sAPU::clocks_executed() {
|
||||
uint32 r = status.clocks_executed;
|
||||
status.clocks_executed = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
//occurs once every 24 clocks (once every APU opcode cycle)
|
||||
void sAPU::tick_timers() {
|
||||
t0.tick();
|
||||
t1.tick();
|
||||
t2.tick();
|
||||
}
|
||||
|
||||
void sAPU::sAPUTimer::tick() {
|
||||
//stage 1 increment
|
||||
stage1_ticks++;
|
||||
if(stage1_ticks < cycle_frequency)return;
|
||||
|
||||
stage1_ticks -= cycle_frequency;
|
||||
if(enabled == false)return;
|
||||
|
||||
//stage 2 increment
|
||||
stage2_ticks++;
|
||||
|
||||
if(stage2_ticks != target)return;
|
||||
|
||||
//stage 3 increment
|
||||
stage2_ticks = 0;
|
||||
stage3_ticks++;
|
||||
stage3_ticks &= 15;
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
class sAPUTimer {
|
||||
public:
|
||||
uint8 cycle_frequency, target;
|
||||
uint8 stage1_ticks, stage2_ticks, stage3_ticks;
|
||||
bool enabled;
|
||||
inline void tick();
|
||||
} t0, t1, t2;
|
||||
|
||||
inline void add_clocks(int clocks);
|
||||
inline void tick_timers();
|
||||
uint32 clocks_executed();
|
17
src/base.h
17
src/base.h
|
@ -1,9 +1,9 @@
|
|||
#define BSNES_VERSION "0.017"
|
||||
#define BSNES_VERSION "0.018"
|
||||
#define BSNES_TITLE "bsnes v" BSNES_VERSION
|
||||
|
||||
#define MEMCORE bMemBus
|
||||
#define CPUCORE sCPU
|
||||
#define APUCORE sAPU
|
||||
#define SMPCORE sSMP
|
||||
#define DSPCORE bDSP
|
||||
#define PPUCORE bPPU
|
||||
|
||||
|
@ -19,11 +19,8 @@
|
|||
//enable JMA support
|
||||
#define JMA_SUPPORT
|
||||
|
||||
//debugging extensions (~10% speed hit)
|
||||
//#define DEBUGGER
|
||||
|
||||
//snes core polymorphism
|
||||
//(allow mem/cpu/apu/ppu overriding, ~10% speed hit)
|
||||
//(allow runtime cpu/smp/dsp/ppu/bus selection, ~10% speed hit)
|
||||
//#define POLYMORPHISM
|
||||
|
||||
#if defined(PROCESSOR_X86)
|
||||
|
@ -38,7 +35,10 @@
|
|||
|
||||
#include "lib/libbase.h"
|
||||
#include "lib/libco_x86.h"
|
||||
#include "lib/libarray.h"
|
||||
#include "lib/libvector.h"
|
||||
#include "lib/libfile.h"
|
||||
#include "lib/libups.h"
|
||||
#include "lib/libstring.h"
|
||||
#include "lib/libconfig.h"
|
||||
|
||||
|
@ -60,7 +60,10 @@ namespace source {
|
|||
none = 0,
|
||||
debug,
|
||||
cpu,
|
||||
apu,
|
||||
ppu,
|
||||
smp,
|
||||
dsp,
|
||||
bus,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include "../base.h"
|
||||
#include "database.cpp"
|
||||
|
||||
Cartridge cartridge;
|
||||
|
||||
void Cartridge::read_dbi() {
|
||||
info.srtc = false;
|
||||
info.sdd1 = false;
|
||||
|
@ -204,8 +206,17 @@ bool header = ((size & 0x7fff) == 512);
|
|||
if(info.rom_size & 0x7fff) {
|
||||
info.rom_size += 0x8000 - (info.rom_size & 0x7fff);
|
||||
}
|
||||
base_rom = rf.read(info.rom_size + (header ? 512 : 0));
|
||||
rom = base_rom + (header ? 512 : 0);
|
||||
|
||||
uint8 *base_rom = rf.read(info.rom_size + (header ? 512 : 0));
|
||||
if(header) {
|
||||
memcpy(rom_header, base_rom, 512);
|
||||
} else {
|
||||
memset(rom_header, 0x00, 512);
|
||||
}
|
||||
|
||||
rom = (uint8*)malloc(info.rom_size);
|
||||
memcpy(rom, base_rom + (header ? 512 : 0), info.rom_size);
|
||||
SafeFree(base_rom);
|
||||
|
||||
info.crc32 = 0xffffffff;
|
||||
for(int32 i = 0; i < info.rom_size; i++) {
|
||||
|
@ -214,6 +225,27 @@ bool header = ((size & 0x7fff) == 512);
|
|||
info.crc32 = ~info.crc32;
|
||||
}
|
||||
|
||||
void Cartridge::patch_rom(Reader &rf) {
|
||||
UPS<ramfile, ramfile, ramfile> ups;
|
||||
uint patchsize = rf.size();
|
||||
uint8 *patchdata = rf.read();
|
||||
|
||||
fopen(ups.original, 0, file::mode_writeread);
|
||||
fopen(ups.modified, 0, file::mode_writeread);
|
||||
fopen(ups.patch.fp, 0, file::mode_writeread);
|
||||
|
||||
fwrite(ups.original, rom, info.rom_size);
|
||||
fwrite(ups.patch.fp, patchdata, patchsize);
|
||||
|
||||
if(ups.apply() == true) {
|
||||
info.crc32 = ups.modified_crc32;
|
||||
info.rom_size = ups.modified_filesize;
|
||||
rom = (uint8*)realloc(rom, info.rom_size);
|
||||
fseek(ups.modified, 0, file::seek_start);
|
||||
fread(ups.modified, rom, info.rom_size);
|
||||
}
|
||||
}
|
||||
|
||||
bool Cartridge::load(const char *fn) {
|
||||
if(cart_loaded == true)return false;
|
||||
if(strlen(fn) < 3)return false;
|
||||
|
@ -223,6 +255,7 @@ bool Cartridge::load(const char *fn) {
|
|||
strcpy(rom_fn, fn);
|
||||
|
||||
switch(Reader::detect(rom_fn)) {
|
||||
|
||||
case Reader::RF_NORMAL: {
|
||||
FileReader ff(rom_fn);
|
||||
if(!ff.ready()) {
|
||||
|
@ -230,8 +263,8 @@ bool Cartridge::load(const char *fn) {
|
|||
return false;
|
||||
}
|
||||
load_rom(ff);
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
#ifdef GZIP_SUPPORT
|
||||
case Reader::RF_GZ: {
|
||||
GZReader gf(rom_fn);
|
||||
|
@ -240,14 +273,14 @@ bool Cartridge::load(const char *fn) {
|
|||
return false;
|
||||
}
|
||||
load_rom(gf);
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Reader::RF_ZIP: {
|
||||
ZipReader zf(rom_fn);
|
||||
load_rom(zf);
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef JMA_SUPPORT
|
||||
case Reader::RF_JMA: {
|
||||
try {
|
||||
|
@ -257,9 +290,9 @@ bool Cartridge::load(const char *fn) {
|
|||
alert("Error loading image file (%s)!", rom_fn);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//remove ROM extension
|
||||
|
@ -275,16 +308,20 @@ bool Cartridge::load(const char *fn) {
|
|||
strcat(sram_fn, ".");
|
||||
strcat(sram_fn, config::fs.save_ext.sget());
|
||||
|
||||
//override default path (current directory)?
|
||||
if(strmatch(config::fs.save_path.sget(), "") == false) {
|
||||
//remove path if fs.sram_path was specified
|
||||
string new_fn, parts;
|
||||
stringarray save_path;
|
||||
strcpy(save_path, config::fs.save_path.sget());
|
||||
replace(save_path, "\\", "/");
|
||||
if(strlen(save_path) && !strend(save_path, "/")) { strcat(save_path, "/"); }
|
||||
|
||||
if(strlen(save_path) != 0) {
|
||||
//override default path (current directory)
|
||||
stringarray new_fn, parts;
|
||||
strcpy(new_fn, sram_fn);
|
||||
replace(new_fn, "\\", "/");
|
||||
split(parts, "/", new_fn);
|
||||
|
||||
//add new SRAM path
|
||||
strcpy(new_fn, config::fs.save_path.sget());
|
||||
strcpy(new_fn, save_path);
|
||||
|
||||
//append fs.base_path if fs.sram_path is not fully-qualified path
|
||||
if(strbegin(new_fn, "./") == true) {
|
||||
|
@ -304,11 +341,34 @@ bool Cartridge::load(const char *fn) {
|
|||
strrtrim(cheat_fn, config::fs.save_ext.sget());
|
||||
strrtrim(cheat_fn, ".");
|
||||
strcat(cheat_fn, ".cht");
|
||||
|
||||
if(fexists(cheat_fn) == true) {
|
||||
FileReader ff(cheat_fn);
|
||||
cheat.load(ff);
|
||||
}
|
||||
|
||||
//load patch file if it exists
|
||||
strcpy(patch_fn, sram_fn);
|
||||
strrtrim(patch_fn, config::fs.save_ext.sget());
|
||||
strrtrim(patch_fn, ".");
|
||||
strcat(patch_fn, ".ups");
|
||||
|
||||
if(fexists(patch_fn) == true) {
|
||||
FileReader ff(patch_fn);
|
||||
patch_rom(ff);
|
||||
}
|
||||
|
||||
#ifdef GZIP_SUPPORT
|
||||
else {
|
||||
strrtrim(patch_fn, ".ups");
|
||||
strcat(patch_fn, ".upz");
|
||||
if(fexists(patch_fn) == true) {
|
||||
ZipReader zf(patch_fn);
|
||||
patch_rom(zf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if(read_database() == true) {
|
||||
read_dbi();
|
||||
} else {
|
||||
|
@ -328,14 +388,9 @@ bool Cartridge::unload() {
|
|||
|
||||
r_mem->unload_cart();
|
||||
|
||||
if(base_rom) {
|
||||
SafeFree(base_rom);
|
||||
}
|
||||
|
||||
if(sram) {
|
||||
save_sram();
|
||||
SafeFree(sram);
|
||||
}
|
||||
if(sram) { save_sram(); }
|
||||
SafeFree(rom);
|
||||
SafeFree(sram);
|
||||
|
||||
if(cheat.count() > 0 || fexists(cheat_fn)) {
|
||||
FileWriter ff(cheat_fn);
|
||||
|
@ -352,9 +407,8 @@ Cartridge::Cartridge() {
|
|||
|
||||
cart_loaded = false;
|
||||
|
||||
base_rom = 0;
|
||||
rom = 0;
|
||||
sram = 0;
|
||||
rom = 0;
|
||||
sram = 0;
|
||||
}
|
||||
|
||||
Cartridge::~Cartridge() {
|
||||
|
|
|
@ -18,7 +18,7 @@ db_item dbi;
|
|||
bool cart_loaded;
|
||||
char rom_fn[4096], sram_fn[4096], cheat_fn[4096], patch_fn[4096];
|
||||
|
||||
uint8 *base_rom, *rom, *sram;
|
||||
uint8 rom_header[512], *rom, *sram;
|
||||
|
||||
enum {
|
||||
//header fields
|
||||
|
@ -79,6 +79,7 @@ struct {
|
|||
} info;
|
||||
|
||||
void load_rom(Reader &rf);
|
||||
void patch_rom(Reader &rf);
|
||||
void load_sram();
|
||||
void save_sram();
|
||||
void read_dbi();
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "../base.h"
|
||||
|
||||
Cheat cheat;
|
||||
|
||||
/*****
|
||||
* string <> binary code translation routines
|
||||
* decode() "7e1234:56" -> 0x7e123456
|
||||
|
@ -7,7 +9,7 @@
|
|||
*****/
|
||||
|
||||
bool Cheat::decode(char *str, uint32 &addr, uint8 &data, uint8 &type) {
|
||||
string t, part;
|
||||
stringarray t, part;
|
||||
strcpy(t, str);
|
||||
strlower(t);
|
||||
if(strlen(t) == 8 || (strlen(t) == 9 && strptr(t)[6] == ':')) {
|
||||
|
@ -270,15 +272,15 @@ bool Cheat::load(Reader &rf) {
|
|||
if(!rf.ready())return false;
|
||||
|
||||
uint8 *raw_data = rf.read();
|
||||
string data;
|
||||
stringarray data, line;
|
||||
raw_data[rf.size()] = 0;
|
||||
strcpy(data, (char*)raw_data);
|
||||
SafeFree(raw_data);
|
||||
replace(data, "\r\n", "\n");
|
||||
string line;
|
||||
|
||||
split(line, "\n", data);
|
||||
for(int i = 0; i < ::count(line); i++) {
|
||||
string part;
|
||||
stringarray part;
|
||||
uint8 en = *(strptr(line[i]));
|
||||
if(en == '+') {
|
||||
strltrim(line[i], "+");
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "../../base.h"
|
||||
|
||||
C4 *c4;
|
||||
|
||||
#include "c4data.cpp"
|
||||
#include "c4fn.cpp"
|
||||
#include "c4oam.cpp"
|
||||
|
|
|
@ -92,3 +92,5 @@ public:
|
|||
|
||||
C4();
|
||||
};
|
||||
|
||||
extern C4 *c4;
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#include "../../base.h"
|
||||
|
||||
DSP1 *dsp1;
|
||||
|
||||
#include "dsp1emu.cpp"
|
||||
|
||||
void DSP1::init() {}
|
||||
|
|
|
@ -14,3 +14,5 @@ public:
|
|||
uint8 read (uint16 addr);
|
||||
void write(uint16 addr, uint8 data);
|
||||
};
|
||||
|
||||
extern DSP1 *dsp1;
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#include "../../base.h"
|
||||
|
||||
DSP2 *dsp2;
|
||||
|
||||
#include "dsp2_op.cpp"
|
||||
|
||||
void DSP2::init() {}
|
||||
|
|
|
@ -39,3 +39,5 @@ struct {
|
|||
DSP2();
|
||||
~DSP2();
|
||||
};
|
||||
|
||||
extern DSP2 *dsp2;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "../../base.h"
|
||||
|
||||
OBC1 *obc1;
|
||||
|
||||
void OBC1::init() {}
|
||||
void OBC1::enable() {}
|
||||
|
||||
|
|
|
@ -16,3 +16,5 @@ struct {
|
|||
OBC1();
|
||||
~OBC1();
|
||||
};
|
||||
|
||||
extern OBC1 *obc1;
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#include "../../base.h"
|
||||
|
||||
SDD1 *sdd1;
|
||||
|
||||
#include "sdd1emu.cpp"
|
||||
|
||||
void SDD1::init() {}
|
||||
|
|
|
@ -28,3 +28,5 @@ struct {
|
|||
|
||||
SDD1();
|
||||
};
|
||||
|
||||
extern SDD1 *sdd1;
|
||||
|
|
|
@ -52,6 +52,8 @@
|
|||
|
||||
#include "../../base.h"
|
||||
|
||||
SRTC *srtc;
|
||||
|
||||
void SRTC::set_time() {
|
||||
time_t rawtime;
|
||||
tm *t;
|
||||
|
|
|
@ -48,3 +48,5 @@ struct {
|
|||
|
||||
SRTC();
|
||||
};
|
||||
|
||||
extern SRTC *srtc;
|
||||
|
|
|
@ -2,26 +2,6 @@ Config config_file;
|
|||
|
||||
namespace config {
|
||||
|
||||
void fs_set_path(Setting &s, const char *data) {
|
||||
string path;
|
||||
strcpy(path, data);
|
||||
strunquote(path);
|
||||
replace(path, "\\", "/");
|
||||
|
||||
//blank path?
|
||||
if(strlen(path) == 0) {
|
||||
s.sset(strptr(path));
|
||||
return;
|
||||
}
|
||||
|
||||
//missing final directory marker?
|
||||
if(strptr(path)[strlen(path) - 1] != '/') {
|
||||
strcat(path, "/");
|
||||
}
|
||||
|
||||
s.sset(strptr(path));
|
||||
}
|
||||
|
||||
Setting FS::base_path(0, "fs.base_path",
|
||||
"Directory that bsnes resides in", "");
|
||||
Setting FS::rom_path(&config_file, "fs.rom_path",
|
||||
|
@ -48,15 +28,33 @@ Setting SNES::gamma(&config_file, "snes.colorfilter.gamma",
|
|||
"Gamma", 80, Setting::DEC);
|
||||
|
||||
Setting SNES::ntsc_merge_fields(&config_file, "snes.ntsc_merge_fields",
|
||||
"Merge fields in NTSC video filter\n"
|
||||
"Set to true if using filter at any refresh rate other than 60hz\n"
|
||||
"", true, Setting::TRUE_FALSE);
|
||||
"Merge fields in NTSC video filter\n"
|
||||
"Set to true if using filter at any refresh rate other than 60hz\n"
|
||||
"", true, Setting::TRUE_FALSE);
|
||||
|
||||
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 SNES::controller_port0(&config_file, "snes.controller_port_1",
|
||||
"Controller attached to SNES port 1", ::SNES::DEVICEID_JOYPAD1, Setting::DEC);
|
||||
Setting SNES::controller_port1(&config_file, "snes.controller_port_2",
|
||||
"Controller attached to SNES port 2", ::SNES::DEVICEID_JOYPAD2, Setting::DEC);
|
||||
|
||||
Setting CPU::ntsc_clock_rate(&config_file, "cpu.ntsc_clock_rate",
|
||||
"NTSC S-CPU clock rate (in hz)", 21477272, Setting::DEC);
|
||||
Setting CPU::pal_clock_rate(&config_file, "cpu.pal_clock_rate",
|
||||
"PAL S-CPU clock rate (in hz)", 21241370, Setting::DEC);
|
||||
Setting CPU::hdma_enable(0, "cpu.hdma_enable",
|
||||
"Enable HDMA effects", true, Setting::TRUE_FALSE);
|
||||
|
||||
Setting SMP::ntsc_clock_rate(&config_file, "smp.ntsc_clock_rate",
|
||||
"NTSC S-SMP clock rate (in hz)", 24576000, Setting::DEC);
|
||||
Setting SMP::pal_clock_rate(&config_file, "smp.pal_clock_rate",
|
||||
"PAL S-SMP clock rate (in hz)", 24576000, Setting::DEC);
|
||||
|
||||
Setting PPU::render_scanline_position(&config_file, "ppu.render_scanline_position",
|
||||
"Approximate HCLOCK position to render at for scanline-based renderers",
|
||||
256, Setting::DEC);
|
||||
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);
|
||||
|
|
|
@ -2,8 +2,6 @@ extern Config config_file;
|
|||
|
||||
namespace config {
|
||||
|
||||
void fs_set_path(Setting &s, const char *data);
|
||||
|
||||
extern struct FS {
|
||||
static Setting base_path, rom_path, save_path;
|
||||
static Setting save_ext;
|
||||
|
@ -13,13 +11,21 @@ extern struct SNES {
|
|||
static Setting gamma_ramp, sepia, grayscale, invert, contrast, brightness, gamma;
|
||||
static Setting ntsc_merge_fields;
|
||||
static Setting mute;
|
||||
static Setting controller_port0;
|
||||
static Setting controller_port1;
|
||||
} snes;
|
||||
|
||||
extern struct CPU {
|
||||
static Setting ntsc_clock_rate, pal_clock_rate;
|
||||
static Setting hdma_enable;
|
||||
} cpu;
|
||||
|
||||
extern struct SMP {
|
||||
static Setting ntsc_clock_rate, pal_clock_rate;
|
||||
} smp;
|
||||
|
||||
extern struct PPU {
|
||||
static Setting render_scanline_position;
|
||||
static Setting opt_enable;
|
||||
|
||||
static Setting bg1_pri0_enable, bg1_pri1_enable;
|
||||
|
|
|
@ -59,21 +59,21 @@ uint8 r;
|
|||
r = regs.mdr & 0xfc;
|
||||
|
||||
if(status.joypad_strobe_latch == 1) {
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_B);
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_B);
|
||||
} else {
|
||||
switch(status.joypad1_read_pos) {
|
||||
case 0: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_B); break;
|
||||
case 1: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_Y); break;
|
||||
case 2: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_SELECT); break;
|
||||
case 3: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_START); break;
|
||||
case 4: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_UP); break;
|
||||
case 5: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_DOWN); break;
|
||||
case 6: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_LEFT); break;
|
||||
case 7: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_RIGHT); break;
|
||||
case 8: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_A); break;
|
||||
case 9: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_X); break;
|
||||
case 10: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_L); break;
|
||||
case 11: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_R); break;
|
||||
case 0: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_B); break;
|
||||
case 1: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_Y); break;
|
||||
case 2: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_SELECT); break;
|
||||
case 3: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_START); break;
|
||||
case 4: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_UP); break;
|
||||
case 5: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_DOWN); break;
|
||||
case 6: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_LEFT); break;
|
||||
case 7: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_RIGHT); break;
|
||||
case 8: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_A); break;
|
||||
case 9: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_X); break;
|
||||
case 10: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_L); break;
|
||||
case 11: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_R); break;
|
||||
case 12: break;
|
||||
case 13: break;
|
||||
case 14: break;
|
||||
|
@ -97,21 +97,21 @@ uint8 r;
|
|||
r |= 0x1c;
|
||||
|
||||
if(status.joypad_strobe_latch == 1) {
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_B);
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_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 0: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_B); break;
|
||||
case 1: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_Y); break;
|
||||
case 2: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_SELECT); break;
|
||||
case 3: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_START); break;
|
||||
case 4: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_UP); break;
|
||||
case 5: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_DOWN); break;
|
||||
case 6: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_LEFT); break;
|
||||
case 7: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_RIGHT); break;
|
||||
case 8: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_A); break;
|
||||
case 9: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_X); break;
|
||||
case 10: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_L); break;
|
||||
case 11: r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_R); break;
|
||||
case 12: break;
|
||||
case 13: break;
|
||||
case 14: break;
|
||||
|
@ -213,10 +213,10 @@ 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_JOYPAD1, SNES::JOYPAD_A) << 7;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_X) << 6;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_L) << 5;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_R) << 4;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_A) << 7;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_X) << 6;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_L) << 5;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_R) << 4;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -226,14 +226,14 @@ 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_JOYPAD1, SNES::JOYPAD_B) << 7;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_Y) << 6;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_SELECT) << 5;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_START) << 4;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_UP) << 3;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_DOWN) << 2;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_LEFT) << 1;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_RIGHT);
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_B) << 7;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_Y) << 6;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_SELECT) << 5;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_START) << 4;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_UP) << 3;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_DOWN) << 2;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_LEFT) << 1;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD1, SNES::JOYPAD_RIGHT);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -243,10 +243,10 @@ 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;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_A) << 7;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_X) << 6;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_L) << 5;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_R) << 4;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -256,14 +256,14 @@ 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);
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_B) << 7;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_Y) << 6;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_SELECT) << 5;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_START) << 4;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_UP) << 3;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_DOWN) << 2;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_LEFT) << 1;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEVICEID_JOYPAD2, SNES::JOYPAD_RIGHT);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -330,7 +330,7 @@ uint8 bCPU::mmio_r43xb(uint8 i) {
|
|||
uint8 bCPU::mmio_read(uint16 addr) {
|
||||
//APU
|
||||
if((addr & 0xffc0) == 0x2140) { //$2140-$217f
|
||||
return r_apu->port_read(addr & 3);
|
||||
return r_smp->port_read(addr & 3);
|
||||
}
|
||||
|
||||
//HDMA
|
||||
|
@ -414,8 +414,7 @@ void bCPU::mmio_w4016(uint8 value) {
|
|||
status.joypad_strobe_latch = bool(value & 1);
|
||||
|
||||
if(status.joypad_strobe_latch == 1) {
|
||||
snes->poll_input(SNES::DEV_JOYPAD1);
|
||||
snes->poll_input(SNES::DEV_JOYPAD2);
|
||||
snes->poll_input();
|
||||
status.joypad1_read_pos = 0;
|
||||
status.joypad2_read_pos = 0;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ void bCPU::cpu_c2() {
|
|||
}
|
||||
|
||||
void bCPU::cpu_c4(uint16 x, uint16 y) {
|
||||
if(!regs.p.x && (x & 0xff00) != (y & 0xff00)) {
|
||||
if(!regs.p.x || (x & 0xff00) != (y & 0xff00)) {
|
||||
cpu_io();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ sta_addrx(0x9d, regs.p.m, regs.a.w),
|
|||
stz_addrx(0x9e, regs.p.m, 0x0000) {
|
||||
1:aa.l = op_readpc();
|
||||
2:aa.h = op_readpc();
|
||||
3:cpu_c4(aa.w, aa.w + regs.x.w);
|
||||
3:cpu_io();
|
||||
4:if($1)last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, $2);
|
||||
if($1)end;
|
||||
|
@ -26,7 +26,7 @@ stz_addrx(0x9e, regs.p.m, 0x0000) {
|
|||
sta_addry(0x99) {
|
||||
1:aa.l = op_readpc();
|
||||
2:aa.h = op_readpc();
|
||||
3:cpu_c4(aa.w, aa.w + regs.y.w);
|
||||
3:cpu_io();
|
||||
4:if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
|
@ -136,7 +136,7 @@ sta_idpy(0x91) {
|
|||
2:cpu_c2();
|
||||
3:aa.l = op_readdp(dp);
|
||||
4:aa.h = op_readdp(dp + 1);
|
||||
5:cpu_c4(aa.w, aa.w + regs.y.w);
|
||||
5:cpu_io();
|
||||
6:if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
*/
|
||||
|
||||
uint16 bCPU::vcounter() { return time.v; }
|
||||
uint16 bCPU::hcycles() { return time.hc; }
|
||||
uint16 bCPU::hclock() { return time.hc; }
|
||||
|
||||
bool bCPU::interlace() { return time.interlace; }
|
||||
bool bCPU::interlace_field() { return time.interlace_field; }
|
||||
|
@ -193,7 +193,7 @@ uint32 r = status.cycles_executed;
|
|||
|
||||
void bCPU::cycle_edge() {
|
||||
if(time.line_rendered == false) {
|
||||
if(time.hc >= 128) {
|
||||
if(time.hc >= 192) {
|
||||
time.line_rendered = true;
|
||||
r_ppu->render_scanline();
|
||||
}
|
||||
|
@ -259,8 +259,7 @@ void bCPU::scanline() {
|
|||
update_interrupts();
|
||||
|
||||
if(vcounter() == (!overscan() ? 227 : 242) && status.auto_joypad_poll == true) {
|
||||
snes->poll_input(SNES::DEV_JOYPAD1);
|
||||
snes->poll_input(SNES::DEV_JOYPAD2);
|
||||
snes->poll_input();
|
||||
//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
|
||||
|
|
|
@ -48,7 +48,7 @@ struct {
|
|||
|
||||
inline uint16 vcounter();
|
||||
inline uint16 hcounter();
|
||||
inline uint16 hcycles();
|
||||
inline uint16 hclock();
|
||||
inline bool interlace();
|
||||
inline bool interlace_field();
|
||||
inline bool overscan();
|
||||
|
|
|
@ -5,4 +5,5 @@ CPU::CPU() {
|
|||
cpu_version = 1;
|
||||
}
|
||||
|
||||
CPU::~CPU() {}
|
||||
CPU::~CPU() {
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ uint8 cpu_version;
|
|||
//timing
|
||||
virtual uint16 vcounter() = 0;
|
||||
virtual uint16 hcounter() = 0;
|
||||
virtual uint16 hcycles() = 0;
|
||||
virtual uint16 hclock() = 0;
|
||||
virtual bool interlace() = 0;
|
||||
virtual bool interlace_field() = 0;
|
||||
virtual bool overscan() = 0;
|
||||
|
|
|
@ -1,33 +1,17 @@
|
|||
class CPURegFlags {
|
||||
private:
|
||||
template<uint mask> class bit {
|
||||
public:
|
||||
uint data;
|
||||
inline operator bool() { return bool(data & mask); }
|
||||
inline bool operator = (const bool i) { (i) ? data |= mask : data &= ~mask; return bool(data & mask); }
|
||||
inline bool operator |= (const bool i) { if(i)data |= mask; return bool(data & mask); }
|
||||
inline bool operator ^= (const bool i) { if(i)data ^= mask; return bool(data & mask); }
|
||||
inline bool operator &= (const bool i) { if(i)data &= mask; return bool(data & mask); }
|
||||
};
|
||||
|
||||
public:
|
||||
union {
|
||||
uint8 data;
|
||||
bit<0x80> n;
|
||||
bit<0x40> v;
|
||||
bit<0x20> m, p;
|
||||
bit<0x10> x, b;
|
||||
bit<0x08> d;
|
||||
bit<0x04> i;
|
||||
bit<0x02> z;
|
||||
bit<0x01> c;
|
||||
struct {
|
||||
uint8 order_msb8(n:1, v:1, m:1, x:1, d:1, i:1, z:1, c:1);
|
||||
};
|
||||
};
|
||||
|
||||
inline operator unsigned() const { return data; }
|
||||
inline unsigned operator = (const uint8 i) { data = i; return data; }
|
||||
inline unsigned operator |= (const uint8 i) { data |= i; return data; }
|
||||
inline unsigned operator ^= (const uint8 i) { data ^= i; return data; }
|
||||
inline unsigned operator &= (const uint8 i) { data &= i; return data; }
|
||||
template<typename T> inline unsigned operator = (const T i) { data = i; return data; }
|
||||
template<typename T> inline unsigned operator |= (const T i) { data |= i; return data; }
|
||||
template<typename T> inline unsigned operator ^= (const T i) { data ^= i; return data; }
|
||||
template<typename T> inline unsigned operator &= (const T i) { data &= i; return data; }
|
||||
|
||||
CPURegFlags() : data(0) {}
|
||||
};
|
||||
|
|
|
@ -421,6 +421,10 @@ uint8 op2 = dreadb(pc.d);
|
|||
}
|
||||
|
||||
strcat(s, t);
|
||||
strcat(s, " ");
|
||||
|
||||
sprintf(t, "V:%3d H:%4d", vcounter(), hclock());
|
||||
strcat(s, t);
|
||||
}
|
||||
|
||||
/*****
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
cl /O2 scpugen.cpp
|
||||
cl /nologo /O2 scpugen.cpp
|
||||
@pause
|
||||
@del *.obj
|
|
@ -2,12 +2,6 @@
|
|||
|
||||
void sCPU::main() {
|
||||
for(;;) {
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_BEGIN);
|
||||
#endif
|
||||
|
||||
status.in_opcode = true;
|
||||
|
||||
if(event.irq) {
|
||||
event.irq = false;
|
||||
if(status.nmi_pending == true) {
|
||||
|
@ -20,6 +14,10 @@ void sCPU::main() {
|
|||
op_irq();
|
||||
}
|
||||
|
||||
tracer.trace_cpuop(); //traces CPU opcode (only if tracer is enabled)
|
||||
|
||||
status.in_opcode = true;
|
||||
|
||||
switch(op_readpc()) {
|
||||
#include "op_read.cpp"
|
||||
#include "op_write.cpp"
|
||||
|
@ -30,10 +28,6 @@ void sCPU::main() {
|
|||
|
||||
status.in_opcode = false;
|
||||
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_END);
|
||||
#endif
|
||||
|
||||
#ifdef FAVOR_SPEED
|
||||
co_return();
|
||||
#endif
|
||||
|
@ -53,24 +47,24 @@ void sCPU::op_irq() {
|
|||
regs.p.d = 0;
|
||||
rd.h = op_read(event.irq_vector + 1);
|
||||
regs.pc.w = rd.w;
|
||||
|
||||
#ifdef DEBUGGER
|
||||
status.in_opcode = false;
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_END);
|
||||
status.in_opcode = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void sCPU::op_io_cond2() {
|
||||
if(regs.d.l != 0x00)op_io();
|
||||
alwaysinline void sCPU::op_io_cond2() {
|
||||
if(regs.d.l != 0x00) {
|
||||
op_io();
|
||||
}
|
||||
}
|
||||
|
||||
void sCPU::op_io_cond4(uint16 x, uint16 y) {
|
||||
if(!regs.p.x && (x & 0xff00) != (y & 0xff00))op_io();
|
||||
alwaysinline void sCPU::op_io_cond4(uint16 x, uint16 y) {
|
||||
if(!regs.p.x || (x & 0xff00) != (y & 0xff00)) {
|
||||
op_io();
|
||||
}
|
||||
}
|
||||
|
||||
void sCPU::op_io_cond6(uint16 addr) {
|
||||
if(regs.e && (regs.pc.w & 0xff00) != (addr & 0xff00))op_io();
|
||||
alwaysinline void sCPU::op_io_cond6(uint16 addr) {
|
||||
if(regs.e && (regs.pc.w & 0xff00) != (addr & 0xff00)) {
|
||||
op_io();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ sta_addrx(0x9d, regs.acc_8b, regs.a.w),
|
|||
stz_addrx(0x9e, regs.acc_8b, 0x0000) {
|
||||
1:aa.l = op_readpc();
|
||||
2:aa.h = op_readpc();
|
||||
3:op_io_cond4(aa.w, aa.w + regs.x.w);
|
||||
3:op_io();
|
||||
4:if($1)last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, $2);
|
||||
if($1)end;
|
||||
|
@ -26,7 +26,7 @@ stz_addrx(0x9e, regs.acc_8b, 0x0000) {
|
|||
sta_addry(0x99) {
|
||||
1:aa.l = op_readpc();
|
||||
2:aa.h = op_readpc();
|
||||
3:op_io_cond4(aa.w, aa.w + regs.y.w);
|
||||
3:op_io();
|
||||
4:if(regs.acc_8b)last_cycle();
|
||||
op_writedbr(aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.acc_8b)end;
|
||||
|
@ -136,7 +136,7 @@ sta_idpy(0x91) {
|
|||
2:op_io_cond2();
|
||||
3:aa.l = op_readdp(dp);
|
||||
4:aa.h = op_readdp(dp + 1);
|
||||
5:op_io_cond4(aa.w, aa.w + regs.y.w);
|
||||
5:op_io();
|
||||
6:if(regs.acc_8b)last_cycle();
|
||||
op_writedbr(aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.acc_8b)end;
|
||||
|
|
|
@ -46,7 +46,7 @@ case 0x9c: {
|
|||
case 0x9d: {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io_cond4(aa.w, aa.w + regs.x.w);
|
||||
op_io();
|
||||
if(regs.acc_8b)last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, regs.a.w);
|
||||
if(regs.acc_8b)break;
|
||||
|
@ -58,7 +58,7 @@ case 0x9d: {
|
|||
case 0x9e: {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io_cond4(aa.w, aa.w + regs.x.w);
|
||||
op_io();
|
||||
if(regs.acc_8b)last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, 0x0000);
|
||||
if(regs.acc_8b)break;
|
||||
|
@ -70,7 +70,7 @@ case 0x9e: {
|
|||
case 0x99: {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io_cond4(aa.w, aa.w + regs.y.w);
|
||||
op_io();
|
||||
if(regs.acc_8b)last_cycle();
|
||||
op_writedbr(aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.acc_8b)break;
|
||||
|
@ -241,7 +241,7 @@ case 0x91: {
|
|||
op_io_cond2();
|
||||
aa.l = op_readdp(dp);
|
||||
aa.h = op_readdp(dp + 1);
|
||||
op_io_cond4(aa.w, aa.w + regs.y.w);
|
||||
op_io();
|
||||
if(regs.acc_8b)last_cycle();
|
||||
op_writedbr(aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.acc_8b)break;
|
||||
|
|
|
@ -29,6 +29,7 @@ uint8 r;
|
|||
r_mem->write(abus, r);
|
||||
}
|
||||
|
||||
status.dma_clocks += 8;
|
||||
add_clocks(8);
|
||||
co_return();
|
||||
cycle_edge();
|
||||
|
@ -52,7 +53,7 @@ uint8 sCPU::dma_bbus(uint8 i, uint8 index) {
|
|||
}
|
||||
}
|
||||
|
||||
uint32 sCPU::dma_addr(uint8 i) {
|
||||
inline uint32 sCPU::dma_addr(uint8 i) {
|
||||
uint32 r = (channel[i].srcbank << 16) | (channel[i].srcaddr);
|
||||
|
||||
if(channel[i].fixedxfer == false) {
|
||||
|
@ -66,11 +67,11 @@ uint32 r = (channel[i].srcbank << 16) | (channel[i].srcaddr);
|
|||
return r;
|
||||
}
|
||||
|
||||
uint32 sCPU::hdma_addr(uint8 i) {
|
||||
inline uint32 sCPU::hdma_addr(uint8 i) {
|
||||
return (channel[i].srcbank << 16) | (channel[i].hdma_addr++);
|
||||
}
|
||||
|
||||
uint32 sCPU::hdma_iaddr(uint8 i) {
|
||||
inline uint32 sCPU::hdma_iaddr(uint8 i) {
|
||||
return (channel[i].hdma_ibank << 16) | (channel[i].hdma_iaddr++);
|
||||
}
|
||||
|
||||
|
@ -92,9 +93,8 @@ void sCPU::dma_transfertobusa(uint8 i, uint8 bbus) {
|
|||
channel[i].xfersize--;
|
||||
}
|
||||
|
||||
void sCPU::dma_write(uint8 i, uint8 index) {
|
||||
//cannot use dma_transfer() directly,
|
||||
//due to current S-DD1 implementation
|
||||
inline void sCPU::dma_write(uint8 i, uint8 index) {
|
||||
//cannot use dma_transfer() directly, due to current S-DD1 implementation
|
||||
if(channel[i].direction == 0) {
|
||||
dma_transfertobusb(i, index);
|
||||
} else {
|
||||
|
@ -103,10 +103,9 @@ void sCPU::dma_write(uint8 i, uint8 index) {
|
|||
}
|
||||
|
||||
void sCPU::dma_run() {
|
||||
add_clocks(18);
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
if(channel[i].dma_enabled == false)continue;
|
||||
status.dma_clocks += 8;
|
||||
add_clocks(8);
|
||||
|
||||
if(cartridge.info.sdd1 == true) {
|
||||
|
@ -114,6 +113,15 @@ void sCPU::dma_run() {
|
|||
channel[i].xfersize);
|
||||
}
|
||||
|
||||
if(tracer.enabled() == true && tracer.cpudma_enabled() == true) {
|
||||
tprintf("[DMA] channel:%d direction:%s reverse:%c fixed:%c mode:%d b_addr:$21%0.2x "
|
||||
"a_addr:$%0.2x%0.4x length:$%0.4x (%5d)",
|
||||
i, channel[i].direction ? "b->a" : "a->b", channel[i].reversexfer ? '1' : '0',
|
||||
channel[i].fixedxfer ? '1' : '0', channel[i].xfermode, channel[i].destaddr,
|
||||
channel[i].srcbank, channel[i].srcaddr,
|
||||
channel[i].xfersize, channel[i].xfersize ? channel[i].xfersize : 65536);
|
||||
}
|
||||
|
||||
uint index = 0;
|
||||
do {
|
||||
dma_write(i, dma_bbus(i, index++));
|
||||
|
@ -122,18 +130,26 @@ void sCPU::dma_run() {
|
|||
channel[i].dma_enabled = false;
|
||||
}
|
||||
|
||||
set_irq_delay(24);
|
||||
counter_set(counter.irq_delay, 24);
|
||||
}
|
||||
|
||||
/*****
|
||||
* HDMA functions
|
||||
*****/
|
||||
|
||||
bool sCPU::hdma_active(uint8 i) {
|
||||
inline bool sCPU::hdma_active(uint8 i) {
|
||||
return (channel[i].hdma_enabled && !channel[i].hdma_completed);
|
||||
}
|
||||
|
||||
uint8 sCPU::hdma_enabled_channels() {
|
||||
inline bool sCPU::hdma_active_after(uint8 i) {
|
||||
for(int n = i + 1; n < 8; n++) {
|
||||
if(hdma_active(n) == true) { return true; }
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline uint8 sCPU::hdma_enabled_channels() {
|
||||
uint8 r = 0;
|
||||
for(int i = 0; i < 8; i++) {
|
||||
if(channel[i].hdma_enabled)r++;
|
||||
|
@ -141,7 +157,7 @@ uint8 r = 0;
|
|||
return r;
|
||||
}
|
||||
|
||||
uint8 sCPU::hdma_active_channels() {
|
||||
inline uint8 sCPU::hdma_active_channels() {
|
||||
uint8 r = 0;
|
||||
for(int i = 0; i < 8; i++) {
|
||||
if(hdma_active(i) == true)r++;
|
||||
|
@ -153,31 +169,22 @@ void sCPU::hdma_update(uint8 i) {
|
|||
channel[i].hdma_line_counter = r_mem->read(hdma_addr(i));
|
||||
add_clocks(8);
|
||||
|
||||
channel[i].hdma_completed = (channel[i].hdma_line_counter == 0);
|
||||
channel[i].hdma_do_transfer = !channel[i].hdma_completed;
|
||||
|
||||
if(channel[i].hdma_indirect) {
|
||||
channel[i].hdma_iaddr = r_mem->read(hdma_addr(i)) << 8;
|
||||
add_clocks(8);
|
||||
}
|
||||
|
||||
if(channel[i].hdma_line_counter == 0) {
|
||||
channel[i].hdma_completed = true;
|
||||
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_clocks(8);
|
||||
if(!channel[i].hdma_completed || hdma_active_after(i)) {
|
||||
channel[i].hdma_iaddr >>= 8;
|
||||
channel[i].hdma_iaddr |= r_mem->read(hdma_addr(i)) << 8;
|
||||
add_clocks(8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sCPU::hdma_run() {
|
||||
if(hdma_active_channels() == 0)return;
|
||||
|
||||
add_clocks(18);
|
||||
|
||||
static uint8 hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
|
||||
for(int i = 0; i < 8; i++) {
|
||||
if(hdma_active(i) == false)continue;
|
||||
|
@ -205,19 +212,17 @@ static uint8 hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
|
|||
}
|
||||
}
|
||||
|
||||
set_irq_delay(24);
|
||||
counter_set(counter.irq_delay, 24);
|
||||
}
|
||||
|
||||
void sCPU::hdma_init() {
|
||||
void sCPU::hdma_init_reset() {
|
||||
for(int i = 0; i < 8; i++) {
|
||||
channel[i].hdma_completed = false;
|
||||
channel[i].hdma_do_transfer = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(hdma_enabled_channels() == 0)return;
|
||||
|
||||
add_clocks(18);
|
||||
|
||||
void sCPU::hdma_init() {
|
||||
for(int i = 0; i < 8; i++) {
|
||||
if(!channel[i].hdma_enabled)continue;
|
||||
channel[i].dma_enabled = false; //HDMA init during DMA will stop DMA mid-transfer
|
||||
|
@ -226,7 +231,7 @@ void sCPU::hdma_init() {
|
|||
hdma_update(i);
|
||||
}
|
||||
|
||||
set_irq_delay(24);
|
||||
counter_set(counter.irq_delay, 24);
|
||||
}
|
||||
|
||||
/*****
|
||||
|
|
|
@ -58,10 +58,12 @@ struct {
|
|||
void dma_run();
|
||||
|
||||
bool hdma_active(uint8 i);
|
||||
bool hdma_active_after(uint8 i);
|
||||
uint8 hdma_enabled_channels();
|
||||
uint8 hdma_active_channels();
|
||||
void hdma_update(uint8 i);
|
||||
void hdma_run();
|
||||
void hdma_init_reset();
|
||||
void hdma_init();
|
||||
|
||||
void dma_power();
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
void sCPU::op_io() {
|
||||
status.clock_count = 6;
|
||||
precycle_edge();
|
||||
add_clocks(6);
|
||||
//co_return();
|
||||
cycle_edge();
|
||||
|
@ -15,6 +16,7 @@ void sCPU::op_io() {
|
|||
|
||||
uint8 sCPU::op_read(uint32 addr) {
|
||||
status.clock_count = r_mem->speed(addr);
|
||||
precycle_edge();
|
||||
add_clocks(status.clock_count - 4);
|
||||
#ifdef FAVOR_ACCURACY
|
||||
co_return();
|
||||
|
@ -27,6 +29,7 @@ uint8 sCPU::op_read(uint32 addr) {
|
|||
|
||||
void sCPU::op_write(uint32 addr, uint8 data) {
|
||||
status.clock_count = r_mem->speed(addr);
|
||||
precycle_edge();
|
||||
add_clocks(status.clock_count);
|
||||
#ifdef FAVOR_ACCURACY
|
||||
co_return();
|
||||
|
|
|
@ -17,17 +17,17 @@ uint8 apu_port[4];
|
|||
*****/
|
||||
uint8 op_readpc () { return op_read((regs.pc.b << 16) + regs.pc.w++); }
|
||||
uint8 op_readstack() { (regs.e) ? regs.s.l++ : regs.s.w++; return op_read(regs.s.w); }
|
||||
uint8 op_readaddr (uint32 addr) { return op_read(uclip<16>(addr)); }
|
||||
uint8 op_readlong (uint32 addr) { return op_read(uclip<24>(addr)); }
|
||||
uint8 op_readdbr (uint32 addr) { return op_read(uclip<24>((regs.db << 16) + addr)); }
|
||||
uint8 op_readpbr (uint32 addr) { return op_read((regs.pc.b << 16) + uclip<16>(addr)); }
|
||||
uint8 op_readdp (uint32 addr) { return op_read(uclip<16>(regs.d + uclip<16>(addr))); }
|
||||
uint8 op_readsp (uint32 addr) { return op_read(uclip<16>(regs.s + uclip<16>(addr))); }
|
||||
uint8 op_readaddr (uint32 addr) { return op_read(addr & 0xffff); }
|
||||
uint8 op_readlong (uint32 addr) { return op_read(addr & 0xffffff); }
|
||||
uint8 op_readdbr (uint32 addr) { return op_read(((regs.db << 16) + addr) & 0xffffff); }
|
||||
uint8 op_readpbr (uint32 addr) { return op_read((regs.pc.b << 16) + (addr & 0xffff)); }
|
||||
uint8 op_readdp (uint32 addr) { return op_read((regs.d + (addr & 0xffff)) & 0xffff); }
|
||||
uint8 op_readsp (uint32 addr) { return op_read((regs.s + (addr & 0xffff)) & 0xffff); }
|
||||
|
||||
void op_writestack(uint8 data) { op_write(regs.s.w, data); (regs.e) ? regs.s.l-- : regs.s.w--; }
|
||||
void op_writeaddr (uint32 addr, uint8 data) { op_write(uclip<16>(addr), data); }
|
||||
void op_writelong (uint32 addr, uint8 data) { op_write(uclip<24>(addr), data); }
|
||||
void op_writedbr (uint32 addr, uint8 data) { op_write(uclip<24>((regs.db << 16) + addr), data); }
|
||||
void op_writepbr (uint32 addr, uint8 data) { op_write((regs.pc.b << 16) + uclip<16>(addr), data); }
|
||||
void op_writedp (uint32 addr, uint8 data) { op_write(uclip<16>(regs.d + uclip<16>(addr)), data); }
|
||||
void op_writesp (uint32 addr, uint8 data) { op_write(uclip<16>(regs.s + uclip<16>(addr)), data); }
|
||||
void op_writeaddr (uint32 addr, uint8 data) { op_write(addr & 0xffff, data); }
|
||||
void op_writelong (uint32 addr, uint8 data) { op_write(addr & 0xffffff, data); }
|
||||
void op_writedbr (uint32 addr, uint8 data) { op_write(((regs.db << 16) + addr) & 0xffffff, data); }
|
||||
void op_writepbr (uint32 addr, uint8 data) { op_write((regs.pc.b << 16) + (addr & 0xffff), data); }
|
||||
void op_writedp (uint32 addr, uint8 data) { op_write((regs.d + (addr & 0xffff)) & 0xffff, data); }
|
||||
void op_writesp (uint32 addr, uint8 data) { op_write((regs.s + (addr & 0xffff)) & 0xffff, data); }
|
||||
|
|
|
@ -2,21 +2,17 @@ uint8 sCPU::pio_status() {
|
|||
return status.pio;
|
||||
}
|
||||
|
||||
/*****
|
||||
* WRAM data registers
|
||||
*****/
|
||||
|
||||
//WMDATA
|
||||
uint8 sCPU::mmio_r2180() {
|
||||
uint8 r = r_mem->read(0x7e0000 | status.wram_addr++);
|
||||
status.wram_addr &= 0x01ffff;
|
||||
uint8 r = r_mem->read(0x7e0000 | status.wram_addr);
|
||||
status.wram_addr = (status.wram_addr + 1) & 0x01ffff;
|
||||
return r;
|
||||
}
|
||||
|
||||
//WMDATA
|
||||
void sCPU::mmio_w2180(uint8 data) {
|
||||
r_mem->write(0x7e0000 | status.wram_addr++, data);
|
||||
status.wram_addr &= 0x01ffff;
|
||||
r_mem->write(0x7e0000 | status.wram_addr, data);
|
||||
status.wram_addr = (status.wram_addr + 1) & 0x01ffff;
|
||||
}
|
||||
|
||||
//WMADDL
|
||||
|
@ -37,24 +33,27 @@ void sCPU::mmio_w2183(uint8 data) {
|
|||
status.wram_addr &= 0x01ffff;
|
||||
}
|
||||
|
||||
/*****
|
||||
* Joypad registers
|
||||
*****/
|
||||
//JOYSER0
|
||||
//bit 0 is shared between JOYSER0 and JOYSER1, therefore
|
||||
//strobing $4016.d0 affects both controller port latches.
|
||||
//$4017 bit 0 writes are ignored.
|
||||
void sCPU::mmio_w4016(uint8 data) {
|
||||
status.joypad_strobe_latch = !!(data & 1);
|
||||
|
||||
//TODO: test whether strobe latch of zero returns
|
||||
//realtime or buffered status of joypadN.b
|
||||
if(status.joypad_strobe_latch == 1) {
|
||||
snes->poll_input();
|
||||
}
|
||||
}
|
||||
|
||||
//JOYSER0
|
||||
//7-2 = MDR
|
||||
//1-0 = Joypad serial data
|
||||
//
|
||||
//TODO: test whether strobe latch of zero returns
|
||||
//realtime or buffered status of joypadN.b
|
||||
uint8 sCPU::mmio_r4016() {
|
||||
uint8 r = regs.mdr & 0xfc;
|
||||
r |= status.joypad1_bits & 1;
|
||||
if(status.joypad_strobe_latch == 0) {
|
||||
status.joypad1_bits >>= 1;
|
||||
status.joypad1_bits |= 0x8000;
|
||||
}
|
||||
|
||||
r |= (uint8)snes->port_read(0);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -64,41 +63,149 @@ uint8 r = regs.mdr & 0xfc;
|
|||
//1-0 = Joypad serial data
|
||||
uint8 sCPU::mmio_r4017() {
|
||||
uint8 r = (regs.mdr & 0xe0) | 0x1c;
|
||||
r |= status.joypad2_bits & 1;
|
||||
if(status.joypad_strobe_latch == 0) {
|
||||
status.joypad2_bits >>= 1;
|
||||
status.joypad2_bits |= 0x8000;
|
||||
}
|
||||
|
||||
r |= (uint8)snes->port_read(1);
|
||||
return r;
|
||||
}
|
||||
|
||||
//TODO: handle reads during joypad polling (v=225-227)
|
||||
//NMITIMEN
|
||||
void sCPU::mmio_w4200(uint8 data) {
|
||||
status.nmi_enabled = !!(data & 0x80);
|
||||
status.virq_enabled = !!(data & 0x20);
|
||||
status.hirq_enabled = !!(data & 0x10);
|
||||
status.auto_joypad_poll = !!(data & 0x01);
|
||||
|
||||
uint8 sCPU::mmio_r4218() { return status.joy1l; } //JOY1L
|
||||
uint8 sCPU::mmio_r4219() { return status.joy1h; } //JOY1H
|
||||
uint8 sCPU::mmio_r421a() { return status.joy2l; } //JOY2L
|
||||
uint8 sCPU::mmio_r421b() { return status.joy2h; } //JOY2H
|
||||
uint8 sCPU::mmio_r421c() { return status.joy3l; } //JOY3L
|
||||
uint8 sCPU::mmio_r421d() { return status.joy3h; } //JOY3H
|
||||
uint8 sCPU::mmio_r421e() { return status.joy4l; } //JOY4L
|
||||
uint8 sCPU::mmio_r421f() { return status.joy4h; } //JOY4H
|
||||
if(status.nmi_read == 0) {
|
||||
if(status.nmi_line == 1 && status.nmi_enabled == 1) {
|
||||
status.nmi_transition = 1;
|
||||
}
|
||||
status.nmi_line = !status.nmi_enabled;
|
||||
}
|
||||
|
||||
//JOYSER0
|
||||
//bit 0 is shared between JOYSER0 and JOYSER1, therefore
|
||||
//strobing $4016.d0 affects both controller port latches.
|
||||
//$4017 bit 0 writes are ignored.
|
||||
void sCPU::mmio_w4016(uint8 data) {
|
||||
status.joypad_strobe_latch = bool(data & 1);
|
||||
if(status.irq_read == 0) {
|
||||
if(status.irq_line == 1 && (status.virq_enabled || status.hirq_enabled)) {
|
||||
status.irq_transition = 1;
|
||||
}
|
||||
status.irq_line = !(status.virq_enabled || status.hirq_enabled);
|
||||
}
|
||||
|
||||
if(status.joypad_strobe_latch == 1) {
|
||||
run_manual_joypad_poll();
|
||||
if(status.virq_enabled == true && status.hirq_enabled == false) {
|
||||
status.irq_lock = false;
|
||||
}
|
||||
|
||||
if(status.virq_enabled == false && status.hirq_enabled == false) {
|
||||
status.irq_line = 1;
|
||||
status.irq_read = 1;
|
||||
status.irq_transition = 0;
|
||||
}
|
||||
|
||||
update_interrupts();
|
||||
counter_set(counter.irq_delay, 2);
|
||||
}
|
||||
|
||||
//WRIO
|
||||
void sCPU::mmio_w4201(uint8 data) {
|
||||
if((status.pio & 0x80) && !(data & 0x80)) {
|
||||
r_ppu->latch_counters();
|
||||
}
|
||||
status.pio = data;
|
||||
}
|
||||
|
||||
//WRMPYA
|
||||
void sCPU::mmio_w4202(uint8 data) {
|
||||
status.mul_a = data;
|
||||
}
|
||||
|
||||
//WRMPYB
|
||||
void sCPU::mmio_w4203(uint8 data) {
|
||||
status.mul_b = data;
|
||||
status.r4216 = status.mul_a * status.mul_b;
|
||||
//counter_set(counter.hw_math, 48);
|
||||
}
|
||||
|
||||
//WRDIVL
|
||||
void sCPU::mmio_w4204(uint8 data) {
|
||||
status.div_a = (status.div_a & 0xff00) | (data);
|
||||
}
|
||||
|
||||
//WRDIVH
|
||||
void sCPU::mmio_w4205(uint8 data) {
|
||||
status.div_a = (status.div_a & 0x00ff) | (data << 8);
|
||||
}
|
||||
|
||||
//WRDIVB
|
||||
void sCPU::mmio_w4206(uint8 data) {
|
||||
status.div_b = data;
|
||||
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;
|
||||
//counter_set(counter.hw_math, 96);
|
||||
}
|
||||
|
||||
//HTIMEL
|
||||
void sCPU::mmio_w4207(uint8 data) {
|
||||
status.hirq_pos = (status.hirq_pos & ~0xff) | (data);
|
||||
status.hirq_pos &= 0x01ff;
|
||||
update_interrupts();
|
||||
|
||||
uint vpos = status.vcounter, hpos = status.hclock;
|
||||
timeshift_backward(10, vpos, hpos);
|
||||
if(hpos < status.hirq_trigger_pos) { status.irq_lock = false; }
|
||||
}
|
||||
|
||||
//HTIMEH
|
||||
void sCPU::mmio_w4208(uint8 data) {
|
||||
status.hirq_pos = (status.hirq_pos & 0xff) | (data << 8);
|
||||
status.hirq_pos &= 0x01ff;
|
||||
update_interrupts();
|
||||
|
||||
uint vpos = status.vcounter, hpos = status.hclock;
|
||||
timeshift_backward(10, vpos, hpos);
|
||||
if(hpos < status.hirq_trigger_pos) { status.irq_lock = false; }
|
||||
}
|
||||
|
||||
//VTIMEL
|
||||
void sCPU::mmio_w4209(uint8 data) {
|
||||
status.virq_pos = (status.virq_pos & ~0xff) | (data);
|
||||
status.virq_pos &= 0x01ff;
|
||||
update_interrupts();
|
||||
|
||||
uint vpos = status.vcounter, hpos = status.hclock;
|
||||
timeshift_backward(10, vpos, hpos);
|
||||
if(hpos < status.hirq_trigger_pos) { status.irq_lock = false; }
|
||||
}
|
||||
|
||||
//VTIMEH
|
||||
void sCPU::mmio_w420a(uint8 data) {
|
||||
status.virq_pos = (status.virq_pos & 0xff) | (data << 8);
|
||||
status.virq_pos &= 0x01ff;
|
||||
update_interrupts();
|
||||
|
||||
uint vpos = status.vcounter, hpos = status.hclock;
|
||||
timeshift_backward(10, vpos, hpos);
|
||||
if(hpos < status.hirq_trigger_pos) { status.irq_lock = false; }
|
||||
}
|
||||
|
||||
//DMAEN
|
||||
void sCPU::mmio_w420b(uint8 data) {
|
||||
for(int i = 0; i < 8; i++) {
|
||||
channel[i].dma_enabled = !!(data & (1 << i));
|
||||
}
|
||||
if(data) {
|
||||
status.dma_state = DMASTATE_DMASYNC;
|
||||
status.dma_pending = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*****
|
||||
* NMI / IRQ registers
|
||||
*****/
|
||||
//HDMAEN
|
||||
void sCPU::mmio_w420c(uint8 data) {
|
||||
for(int i = 0; i < 8; i++) {
|
||||
channel[i].hdma_enabled = !!(data & (1 << i));
|
||||
}
|
||||
}
|
||||
|
||||
//MEMSEL
|
||||
void sCPU::mmio_w420d(uint8 data) {
|
||||
r_mem->set_speed(data & 1);
|
||||
}
|
||||
|
||||
//RDNMI
|
||||
//7 = NMI acknowledge
|
||||
|
@ -106,9 +213,9 @@ void sCPU::mmio_w4016(uint8 data) {
|
|||
//3-0 = CPU (5a22) version
|
||||
uint8 sCPU::mmio_r4210() {
|
||||
uint8 r = (regs.mdr & 0x70);
|
||||
r |= uint8(!status.nmi_read) << 7;
|
||||
r |= (uint8)(!status.nmi_read) << 7;
|
||||
|
||||
if(!nmi_read_pos_match(0) && !nmi_read_pos_match(2)) {
|
||||
if(!counter.nmi_fire) {
|
||||
status.nmi_read = 1;
|
||||
}
|
||||
|
||||
|
@ -121,9 +228,9 @@ uint8 r = (regs.mdr & 0x70);
|
|||
//6-0 = MDR
|
||||
uint8 sCPU::mmio_r4211() {
|
||||
uint8 r = (regs.mdr & 0x7f);
|
||||
r |= uint8(!status.irq_read) << 7;
|
||||
r |= (uint8)(!status.irq_read) << 7;
|
||||
|
||||
if(!irq_read_pos_match(0) && !irq_read_pos_match(2)) {
|
||||
if(!counter.irq_fire) {
|
||||
status.irq_read = 1;
|
||||
status.irq_line = 1;
|
||||
status.irq_transition = 0;
|
||||
|
@ -153,132 +260,44 @@ uint16 vs = !overscan() ? 225 : 240;
|
|||
return r;
|
||||
}
|
||||
|
||||
//NMITIMEN
|
||||
void sCPU::mmio_w4200(uint8 data) {
|
||||
status.nmi_enabled = bool(data & 0x80);
|
||||
status.virq_enabled = bool(data & 0x20);
|
||||
status.hirq_enabled = bool(data & 0x10);
|
||||
status.auto_joypad_poll = bool(data & 0x01);
|
||||
|
||||
//if(!status.nmi_enabled)status.nmi_read=1;
|
||||
|
||||
if(status.nmi_read == 0) {
|
||||
if(status.nmi_line == 1 && !status.nmi_enabled == 0) {
|
||||
status.nmi_transition = 1;
|
||||
}
|
||||
status.nmi_line = !status.nmi_enabled;
|
||||
}
|
||||
|
||||
if(status.virq_enabled == false && status.hirq_enabled == false) {
|
||||
status.irq_line = 1;
|
||||
status.irq_read = 1;
|
||||
status.irq_transition = 0;
|
||||
}
|
||||
|
||||
update_interrupts();
|
||||
set_irq_delay(2);
|
||||
}
|
||||
|
||||
//HTIMEL
|
||||
void sCPU::mmio_w4207(uint8 data) {
|
||||
status.hirq_pos = (status.hirq_pos & ~0xff) | (data);
|
||||
status.hirq_pos &= 0x01ff;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//HTIMEH
|
||||
void sCPU::mmio_w4208(uint8 data) {
|
||||
status.hirq_pos = (status.hirq_pos & 0xff) | (data << 8);
|
||||
status.hirq_pos &= 0x01ff;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//VTIMEL
|
||||
void sCPU::mmio_w4209(uint8 data) {
|
||||
status.virq_pos = (status.virq_pos & ~0xff) | (data);
|
||||
status.virq_pos &= 0x01ff;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//VTIMEH
|
||||
void sCPU::mmio_w420a(uint8 data) {
|
||||
status.virq_pos = (status.virq_pos & 0xff) | (data << 8);
|
||||
status.virq_pos &= 0x01ff;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
/*****
|
||||
* I/O registers
|
||||
****/
|
||||
|
||||
//RDIO
|
||||
uint8 sCPU::mmio_r4213() {
|
||||
return status.pio;
|
||||
}
|
||||
|
||||
//WRIO
|
||||
void sCPU::mmio_w4201(uint8 data) {
|
||||
if((status.pio & 0x80) && !(data & 0x80)) {
|
||||
r_ppu->latch_counters();
|
||||
}
|
||||
status.pio = data;
|
||||
}
|
||||
|
||||
/*****
|
||||
* Math registers (multiplication and division)
|
||||
*****/
|
||||
|
||||
//RDDIVL
|
||||
uint8 sCPU::mmio_r4214() {
|
||||
if(counter.hw_math) { return 0x00; }
|
||||
return status.r4214;
|
||||
}
|
||||
|
||||
//RDDIVH
|
||||
uint8 sCPU::mmio_r4215() {
|
||||
if(counter.hw_math) { return 0x00; }
|
||||
return status.r4214 >> 8;
|
||||
}
|
||||
|
||||
//RDMPYL
|
||||
uint8 sCPU::mmio_r4216() {
|
||||
if(counter.hw_math) { return 0x00; }
|
||||
return status.r4216;
|
||||
}
|
||||
|
||||
//RDMPYH
|
||||
uint8 sCPU::mmio_r4217() {
|
||||
if(counter.hw_math) { return 0x00; }
|
||||
return status.r4216 >> 8;
|
||||
}
|
||||
|
||||
//WRMPYA
|
||||
void sCPU::mmio_w4202(uint8 data) {
|
||||
status.mul_a = data;
|
||||
}
|
||||
|
||||
//WRMPYB
|
||||
void sCPU::mmio_w4203(uint8 data) {
|
||||
status.mul_b = data;
|
||||
status.r4216 = status.mul_a * status.mul_b;
|
||||
}
|
||||
|
||||
//WRDIVL
|
||||
void sCPU::mmio_w4204(uint8 data) {
|
||||
status.div_a = (status.div_a & 0xff00) | (data);
|
||||
}
|
||||
|
||||
//WRDIVH
|
||||
void sCPU::mmio_w4205(uint8 data) {
|
||||
status.div_a = (status.div_a & 0x00ff) | (data << 8);
|
||||
}
|
||||
|
||||
//WRDIVB
|
||||
void sCPU::mmio_w4206(uint8 data) {
|
||||
status.div_b = data;
|
||||
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;
|
||||
}
|
||||
|
||||
/*****
|
||||
* DMA / HDMA registers
|
||||
*****/
|
||||
//TODO: handle reads during joypad polling (v=225-227)
|
||||
uint8 sCPU::mmio_r4218() { return status.joy1l; } //JOY1L
|
||||
uint8 sCPU::mmio_r4219() { return status.joy1h; } //JOY1H
|
||||
uint8 sCPU::mmio_r421a() { return status.joy2l; } //JOY2L
|
||||
uint8 sCPU::mmio_r421b() { return status.joy2h; } //JOY2H
|
||||
uint8 sCPU::mmio_r421c() { return status.joy3l; } //JOY3L
|
||||
uint8 sCPU::mmio_r421d() { return status.joy3h; } //JOY3H
|
||||
uint8 sCPU::mmio_r421e() { return status.joy4l; } //JOY4L
|
||||
uint8 sCPU::mmio_r421f() { return status.joy4h; } //JOY4H
|
||||
|
||||
//DMAPx
|
||||
uint8 sCPU::mmio_r43x0(uint8 i) {
|
||||
|
@ -342,34 +361,13 @@ uint8 sCPU::mmio_r43xb(uint8 i) {
|
|||
return channel[i].unknown;
|
||||
}
|
||||
|
||||
//DMAEN
|
||||
//Note: DMA enable does not disable active HDMA channels
|
||||
void sCPU::mmio_w420b(uint8 data) {
|
||||
for(int i = 0; i < 8; i++) {
|
||||
channel[i].dma_enabled = bool(data & (1 << i));
|
||||
}
|
||||
if(data)dma_run(); //temporary
|
||||
}
|
||||
|
||||
//HDMAEN
|
||||
void sCPU::mmio_w420c(uint8 data) {
|
||||
for(int i = 0; i < 8; i++) {
|
||||
channel[i].hdma_enabled = bool(data & (1 << i));
|
||||
}
|
||||
}
|
||||
|
||||
//MEMSEL
|
||||
void sCPU::mmio_w420d(uint8 data) {
|
||||
r_mem->set_speed(data & 1);
|
||||
}
|
||||
|
||||
//DMAPx
|
||||
void sCPU::mmio_w43x0(uint8 i, uint8 data) {
|
||||
channel[i].dmap = data;
|
||||
channel[i].direction = bool(data & 0x80);
|
||||
channel[i].hdma_indirect = bool(data & 0x40);
|
||||
channel[i].reversexfer = bool(data & 0x10);
|
||||
channel[i].fixedxfer = bool(data & 0x08);
|
||||
channel[i].direction = !!(data & 0x80);
|
||||
channel[i].hdma_indirect = !!(data & 0x40);
|
||||
channel[i].reversexfer = !!(data & 0x10);
|
||||
channel[i].fixedxfer = !!(data & 0x08);
|
||||
channel[i].xfermode = data & 7;
|
||||
}
|
||||
|
||||
|
@ -430,10 +428,6 @@ void sCPU::mmio_w43xb(uint8 i, uint8 data) {
|
|||
channel[i].unknown = data;
|
||||
}
|
||||
|
||||
/*****
|
||||
* reset / read / write
|
||||
*****/
|
||||
|
||||
void sCPU::mmio_power() {
|
||||
}
|
||||
|
||||
|
@ -488,7 +482,7 @@ uint8 sCPU::mmio_read(uint16 addr) {
|
|||
#ifdef FAVOR_SPEED
|
||||
co_return();
|
||||
#endif
|
||||
return r_apu->port_read(addr & 3);
|
||||
return r_smp->port_read(addr & 3);
|
||||
}
|
||||
|
||||
//DMA
|
||||
|
|
|
@ -14,6 +14,21 @@ struct {
|
|||
uint16 irq_vector;
|
||||
} event;
|
||||
|
||||
struct {
|
||||
bool enabled;
|
||||
uint irq_delay;
|
||||
uint irq_fire;
|
||||
uint nmi_fire;
|
||||
uint hw_math;
|
||||
} counter;
|
||||
|
||||
enum {
|
||||
DMASTATE_INACTIVE,
|
||||
DMASTATE_DMASYNC,
|
||||
DMASTATE_RUN,
|
||||
DMASTATE_CPUSYNC,
|
||||
};
|
||||
|
||||
struct {
|
||||
//core
|
||||
uint8 opcode;
|
||||
|
@ -29,21 +44,36 @@ struct {
|
|||
bool interlace, interlace_field;
|
||||
bool overscan;
|
||||
uint16 field_lines, line_clocks;
|
||||
uint16 vblstart;
|
||||
|
||||
bool line_rendered;
|
||||
uint16 line_render_position;
|
||||
|
||||
bool dram_refreshed;
|
||||
uint16 dram_refresh_position;
|
||||
|
||||
bool hdmainit_triggered;
|
||||
uint16 hdmainit_trigger_position;
|
||||
|
||||
bool hdma_triggered;
|
||||
|
||||
uint16 irq_delay;
|
||||
|
||||
int16 nmi_read_pos, nmi_line_pos;
|
||||
uint16 nmi_trigger_pos;
|
||||
bool nmi_read, nmi_line, nmi_transition;
|
||||
bool nmi_pending;
|
||||
|
||||
int16 irq_read_pos, irq_line_pos;
|
||||
uint16 virq_trigger_pos, hirq_trigger_pos;
|
||||
bool irq_read, irq_line, irq_transition;
|
||||
bool irq_pending;
|
||||
bool irq_lock, irq_pending;
|
||||
|
||||
//dma
|
||||
uint dma_counter;
|
||||
uint dma_clocks;
|
||||
uint dma_state;
|
||||
bool dma_pending;
|
||||
bool hdma_pending;
|
||||
bool hdmainit_pending;
|
||||
|
||||
//mmio
|
||||
|
||||
|
|
|
@ -1,122 +1,60 @@
|
|||
void sCPU::set_irq_delay(uint clocks) {
|
||||
if(status.irq_delay < clocks) {
|
||||
status.irq_delay = clocks;
|
||||
}
|
||||
}
|
||||
|
||||
void sCPU::update_interrupts() {
|
||||
if(status.vcounter == (!overscan() ? 225 : 240)) {
|
||||
status.nmi_read_pos = 2;
|
||||
status.nmi_line_pos = 6;
|
||||
status.nmi_trigger_pos = (status.vcounter == status.vblstart) ? 2 : IRQ_TRIGGER_NEVER;
|
||||
|
||||
if(irq_pos_valid() == true) {
|
||||
status.virq_trigger_pos = status.virq_pos;
|
||||
status.hirq_trigger_pos = (status.hirq_enabled) ? ((status.hirq_pos + 1) * 4) : 0;
|
||||
} else {
|
||||
status.nmi_read_pos = -64;
|
||||
status.nmi_line_pos = -64;
|
||||
}
|
||||
|
||||
if(irq_pos_valid() == false) {
|
||||
status.irq_read_pos = -64;
|
||||
status.irq_line_pos = -64;
|
||||
return;
|
||||
}
|
||||
|
||||
uint vpos = status.virq_pos;
|
||||
uint hpos = (status.hirq_enabled) ? status.hirq_pos : 0;
|
||||
hpos = (hpos != 0) ? ((hpos << 2) + 14) : 10;
|
||||
if(hpos >= status.line_clocks) {
|
||||
hpos -= status.line_clocks;
|
||||
if(++vpos >= status.field_lines) {
|
||||
vpos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if((status.virq_enabled == true && status.vcounter == vpos) || status.virq_enabled == false) {
|
||||
status.irq_read_pos = hpos;
|
||||
} else {
|
||||
status.irq_read_pos = -64;
|
||||
}
|
||||
|
||||
hpos += 4;
|
||||
if(hpos >= status.line_clocks) {
|
||||
hpos -= status.line_clocks;
|
||||
if(++vpos >= status.field_lines) {
|
||||
vpos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if((status.virq_enabled == true && status.vcounter == vpos) || status.virq_enabled == false) {
|
||||
status.irq_line_pos = hpos;
|
||||
} else {
|
||||
status.irq_line_pos = -64;
|
||||
status.virq_trigger_pos = IRQ_TRIGGER_NEVER;
|
||||
status.hirq_trigger_pos = IRQ_TRIGGER_NEVER;
|
||||
}
|
||||
}
|
||||
|
||||
void sCPU::poll_interrupts(int clocks) {
|
||||
int16 start, end;
|
||||
if(status.hclock == 0) {
|
||||
start = -1;
|
||||
end = clocks;
|
||||
} else {
|
||||
start = status.hclock;
|
||||
end = status.hclock + clocks;
|
||||
}
|
||||
alwaysinline void sCPU::nmi_tick() {
|
||||
counter.nmi_fire -= 2;
|
||||
if(counter.nmi_fire != 0) { return; }
|
||||
|
||||
//NMI read test
|
||||
if(start < status.nmi_read_pos && status.nmi_read_pos <= end) {
|
||||
//nmi_read lowers even when NMI interrupts are disabled via $4200.d7
|
||||
status.nmi_read = 0;
|
||||
}
|
||||
|
||||
//NMI line test
|
||||
if(start < status.nmi_line_pos && status.nmi_line_pos <= end) {
|
||||
if(status.nmi_enabled == true) {
|
||||
if(status.nmi_line == 1) {
|
||||
status.nmi_transition = 1;
|
||||
}
|
||||
status.nmi_line = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//IRQ read test
|
||||
if(start < status.irq_read_pos && status.irq_read_pos <= end) {
|
||||
if(status.virq_enabled == true || status.hirq_enabled == true) {
|
||||
status.irq_read = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//IRQ line test
|
||||
if(start < status.irq_line_pos && status.irq_line_pos <= end) {
|
||||
if(status.virq_enabled == true || status.hirq_enabled == true) {
|
||||
status.irq_line = 0;
|
||||
status.irq_transition = 1;
|
||||
}
|
||||
if(status.nmi_enabled == true && status.nmi_line == 1) {
|
||||
status.nmi_line = 0;
|
||||
status.nmi_transition = 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool sCPU::nmi_read_pos_match(uint offset) {
|
||||
uint16 v = !overscan() ? 225 : 240;
|
||||
uint16 h = 2 + offset;
|
||||
return (status.vcounter == v && status.hclock == h);
|
||||
alwaysinline void sCPU::irq_tick() {
|
||||
counter.irq_fire -= 2;
|
||||
if(counter.irq_fire != 0) { return; }
|
||||
|
||||
if(status.virq_enabled == true || status.hirq_enabled == true) {
|
||||
status.irq_line = 0;
|
||||
status.irq_transition = 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool sCPU::irq_read_pos_match(uint offset) {
|
||||
if(irq_pos_valid() == false)return false;
|
||||
|
||||
uint vpos = status.virq_pos;
|
||||
uint hpos = (status.hirq_enabled) ? status.hirq_pos : 0;
|
||||
hpos = (hpos != 0) ? ((hpos << 2) + 14) : 10;
|
||||
hpos += offset;
|
||||
if(hpos >= status.line_clocks) {
|
||||
hpos -= status.line_clocks;
|
||||
if(++vpos >= status.field_lines) {
|
||||
vpos = 0;
|
||||
}
|
||||
alwaysinline void sCPU::poll_interrupts() {
|
||||
if(status.hclock == status.nmi_trigger_pos) {
|
||||
status.nmi_read = 0;
|
||||
counter.nmi_fire = 4;
|
||||
}
|
||||
|
||||
if((status.virq_enabled == true && status.vcounter == vpos) || status.virq_enabled == false) {
|
||||
return (status.hclock == hpos);
|
||||
}
|
||||
if(status.hclock == 10) { status.irq_lock = false; }
|
||||
|
||||
return false;
|
||||
if(status.hirq_trigger_pos == IRQ_TRIGGER_NEVER)return;
|
||||
if(status.virq_enabled == false && status.hirq_enabled == false)return;
|
||||
if(status.irq_lock == true)return;
|
||||
|
||||
uint vpos = status.vcounter;
|
||||
uint hpos = status.hclock;
|
||||
timeshift_backward(10, vpos, hpos);
|
||||
|
||||
bool trigger_irq = true;
|
||||
if(status.virq_enabled == true && vpos != status.virq_trigger_pos)trigger_irq = false;
|
||||
if(status.hirq_enabled == true && hpos != status.hirq_trigger_pos)trigger_irq = false;
|
||||
|
||||
if(trigger_irq == true) {
|
||||
status.irq_lock = true;
|
||||
status.irq_read = 0;
|
||||
counter.irq_fire = 4;
|
||||
}
|
||||
}
|
||||
|
||||
bool sCPU::irq_pos_valid() {
|
||||
|
@ -136,7 +74,7 @@ uint vlimit = region_scanlines() >> 1;
|
|||
return true;
|
||||
}
|
||||
|
||||
bool sCPU::nmi_test() {
|
||||
alwaysinline bool sCPU::nmi_test() {
|
||||
if(status.nmi_transition == 0)return false;
|
||||
|
||||
status.nmi_transition = 0;
|
||||
|
@ -144,11 +82,11 @@ bool sCPU::nmi_test() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool sCPU::irq_test() {
|
||||
alwaysinline bool sCPU::irq_test() {
|
||||
if(status.irq_transition == 1)goto irq_trigger;
|
||||
|
||||
if(status.irq_read == 0) {
|
||||
if(status.irq_line == 1 && (irq_read_pos_match(0) || irq_read_pos_match(2))) {
|
||||
if(status.irq_line == 1 && counter.irq_fire) {
|
||||
return false;
|
||||
}
|
||||
goto irq_trigger;
|
||||
|
|
|
@ -1,52 +1,8 @@
|
|||
void sCPU::run_manual_joypad_poll() {
|
||||
snes->poll_input(SNES::DEV_JOYPAD1);
|
||||
snes->poll_input(SNES::DEV_JOYPAD2);
|
||||
|
||||
status.joypad1_bits = uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_B)) << 0;
|
||||
status.joypad1_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_Y)) << 1;
|
||||
status.joypad1_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_SELECT)) << 2;
|
||||
status.joypad1_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_START)) << 3;
|
||||
status.joypad1_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_UP)) << 4;
|
||||
status.joypad1_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_DOWN)) << 5;
|
||||
status.joypad1_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_LEFT)) << 6;
|
||||
status.joypad1_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_RIGHT)) << 7;
|
||||
status.joypad1_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_A)) << 8;
|
||||
status.joypad1_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_X)) << 9;
|
||||
status.joypad1_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_L)) << 10;
|
||||
status.joypad1_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_R)) << 11;
|
||||
|
||||
status.joypad2_bits = uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_B)) << 0;
|
||||
status.joypad2_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_Y)) << 1;
|
||||
status.joypad2_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_SELECT)) << 2;
|
||||
status.joypad2_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_START)) << 3;
|
||||
status.joypad2_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_UP)) << 4;
|
||||
status.joypad2_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_DOWN)) << 5;
|
||||
status.joypad2_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_LEFT)) << 6;
|
||||
status.joypad2_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_RIGHT)) << 7;
|
||||
status.joypad2_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_A)) << 8;
|
||||
status.joypad2_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_X)) << 9;
|
||||
status.joypad2_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_L)) << 10;
|
||||
status.joypad2_bits |= uint8(snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_R)) << 11;
|
||||
}
|
||||
|
||||
/*****
|
||||
* 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.
|
||||
*****/
|
||||
|
||||
void sCPU::run_auto_joypad_poll() {
|
||||
run_manual_joypad_poll();
|
||||
|
||||
uint16 joy1 = 0x0000, joy2 = 0x0000;
|
||||
uint16 joy1 = 0, joy2 = 0;
|
||||
for(int i = 0; i < 16; i++) {
|
||||
joy1 |= (!!(status.joypad1_bits & (0x8000 >> i))) << i;
|
||||
joy2 |= (!!(status.joypad2_bits & (0x8000 >> i))) << i;
|
||||
joy1 |= (uint16)snes->port_read(0) ? (0x8000 >> i) : 0;
|
||||
joy2 |= (uint16)snes->port_read(1) ? (0x8000 >> i) : 0;
|
||||
}
|
||||
|
||||
status.joy1l = joy1;
|
||||
|
@ -60,10 +16,4 @@ uint16 joy1 = 0x0000, joy2 = 0x0000;
|
|||
|
||||
status.joy4l = 0x00;
|
||||
status.joy4h = 0x00;
|
||||
|
||||
status.joypad1_bits >>= 16;
|
||||
status.joypad2_bits >>= 16;
|
||||
|
||||
status.joypad1_bits |= 0xffff;
|
||||
status.joypad2_bits |= 0xffff;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
alwaysinline void sCPU::timeshift_forward(uint clocks, uint &vtime, uint &htime) {
|
||||
htime += clocks;
|
||||
|
||||
if(htime >= status.line_clocks) {
|
||||
htime -= status.line_clocks;
|
||||
if(++vtime >= status.field_lines) {
|
||||
vtime = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
alwaysinline void sCPU::timeshift_backward(uint clocks, uint &vtime, uint &htime) {
|
||||
if(htime >= clocks) {
|
||||
htime -= clocks;
|
||||
} else {
|
||||
htime += 1364 - clocks;
|
||||
if(status.region == SNES::NTSC && status.vcounter == 241 &&
|
||||
status.interlace == false && status.interlace_field == 1)htime -= 4;
|
||||
if(vtime > 0) {
|
||||
vtime--;
|
||||
} else {
|
||||
vtime = status.region_scanlines;
|
||||
if(status.interlace == true && status.interlace_field == 1)vtime++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,19 +2,30 @@
|
|||
(status.region == SNES::NTSC && status.vcounter == 240 && \
|
||||
status.interlace == false && status.interlace_field == 1)
|
||||
|
||||
#include "timeshift.cpp"
|
||||
#include "irq.cpp"
|
||||
#include "joypad.cpp"
|
||||
|
||||
uint16 sCPU::vcounter() { return status.vcounter; }
|
||||
uint16 sCPU::hcycles() { return status.hclock; }
|
||||
uint16 sCPU::hclock() { return status.hclock; }
|
||||
|
||||
bool sCPU::interlace() { return status.interlace; }
|
||||
bool sCPU::interlace_field() { return status.interlace_field; }
|
||||
bool sCPU::overscan() { return status.overscan; }
|
||||
uint16 sCPU::region_scanlines() { return status.region_scanlines; }
|
||||
|
||||
void sCPU::set_interlace(bool r) { status.interlace = r; update_interrupts(); }
|
||||
void sCPU::set_overscan (bool r) { status.overscan = r; update_interrupts(); }
|
||||
uint sCPU::dma_counter() { return (status.dma_counter + status.hclock) & 7; }
|
||||
|
||||
void sCPU::set_interlace(bool r) {
|
||||
status.interlace = r;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
void sCPU::set_overscan (bool r) {
|
||||
status.overscan = r;
|
||||
status.vblstart = (status.overscan == false) ? 225 : 240;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
/*****
|
||||
* One PPU dot = 4 CPU clocks
|
||||
|
@ -34,36 +45,41 @@ uint16 sCPU::hcounter() {
|
|||
}
|
||||
|
||||
void sCPU::add_clocks(uint clocks) {
|
||||
if(status.irq_delay) {
|
||||
if(status.irq_delay >= clocks) {
|
||||
status.irq_delay -= clocks;
|
||||
} else {
|
||||
status.irq_delay = 0;
|
||||
}
|
||||
}
|
||||
|
||||
status.clocks_executed += clocks;
|
||||
poll_interrupts(clocks);
|
||||
|
||||
if(counter.irq_delay) {
|
||||
counter.irq_delay = (counter.irq_delay > clocks) ? (counter.irq_delay - clocks) : 0;
|
||||
}
|
||||
|
||||
if(status.hclock + clocks >= status.line_clocks) {
|
||||
clocks = (status.hclock + clocks) - status.line_clocks;
|
||||
status.hclock = 0;
|
||||
while(status.hclock < status.line_clocks - 2) { tick(); }
|
||||
scanline();
|
||||
poll_interrupts(clocks);
|
||||
}
|
||||
|
||||
status.hclock += clocks;
|
||||
clocks >>= 1;
|
||||
while(clocks--) { tick(); }
|
||||
}
|
||||
|
||||
if(status.dram_refreshed == false) {
|
||||
if(status.hclock >= 530) {
|
||||
status.dram_refreshed = true;
|
||||
add_clocks(40);
|
||||
return;
|
||||
}
|
||||
alwaysinline void sCPU::tick() {
|
||||
status.hclock += 2;
|
||||
|
||||
if(counter.nmi_fire) { nmi_tick(); }
|
||||
if(counter.irq_fire) { irq_tick(); }
|
||||
|
||||
if(status.dram_refreshed == false && status.hclock >= status.dram_refresh_position) {
|
||||
status.dram_refreshed = true;
|
||||
add_clocks(40);
|
||||
return;
|
||||
}
|
||||
|
||||
poll_interrupts();
|
||||
}
|
||||
|
||||
void sCPU::scanline() {
|
||||
status.hclock = 0;
|
||||
status.dma_counter = (status.dma_counter + status.line_clocks) & 7;
|
||||
|
||||
if(++status.vcounter >= status.field_lines) {
|
||||
frame();
|
||||
}
|
||||
|
@ -72,9 +88,18 @@ void sCPU::scanline() {
|
|||
|
||||
//dram refresh occurs once every scanline
|
||||
status.dram_refreshed = false;
|
||||
if(cpu_version == 2) {
|
||||
if(ntsc_color_burst_phase_shift_scanline() == false) {
|
||||
if(status.dram_refresh_position == 534) {
|
||||
status.dram_refresh_position = 538;
|
||||
} else {
|
||||
status.dram_refresh_position = 534;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//hdma triggers once every visible scanline
|
||||
status.line_rendered =
|
||||
status.line_rendered = false;
|
||||
status.hdma_triggered = (status.vcounter <= (!overscan() ? 224 : 239)) ? false : true;
|
||||
|
||||
r_ppu->scanline();
|
||||
|
@ -83,6 +108,7 @@ void sCPU::scanline() {
|
|||
update_interrupts();
|
||||
|
||||
if(status.auto_joypad_poll == true && status.vcounter == (!overscan() ? 227 : 242)) {
|
||||
snes->poll_input();
|
||||
run_auto_joypad_poll();
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +124,13 @@ void sCPU::frame() {
|
|||
//interlaced even fields have one extra scanline
|
||||
//(263+262=525 NTSC, 313+312=625 PAL)
|
||||
if(status.interlace == true && status.interlace_field == 0)status.field_lines++;
|
||||
|
||||
status.hdmainit_triggered = false;
|
||||
if(cpu_version == 1) {
|
||||
status.hdmainit_trigger_position = 12 + 8 - dma_counter();
|
||||
} else {
|
||||
status.hdmainit_trigger_position = 12 + dma_counter();
|
||||
}
|
||||
|
||||
r_ppu->frame();
|
||||
snes->frame();
|
||||
|
@ -109,7 +141,12 @@ void sCPU::frame() {
|
|||
*
|
||||
* Used for DMA/HDMA bus synchronization
|
||||
*****/
|
||||
void sCPU::precycle_edge() {
|
||||
alwaysinline void sCPU::precycle_edge() {
|
||||
if(status.dma_state == DMASTATE_CPUSYNC) {
|
||||
status.dma_state = DMASTATE_INACTIVE;
|
||||
uint n = status.clock_count - (status.dma_clocks % status.clock_count);
|
||||
add_clocks(n ? n : status.clock_count);
|
||||
}
|
||||
}
|
||||
|
||||
/*****
|
||||
|
@ -119,23 +156,59 @@ void sCPU::precycle_edge() {
|
|||
*****/
|
||||
void sCPU::cycle_edge() {
|
||||
if(status.line_rendered == false) {
|
||||
if(status.hclock >= 128) {
|
||||
if(status.hclock >= status.line_render_position) {
|
||||
status.line_rendered = true;
|
||||
r_ppu->render_scanline();
|
||||
}
|
||||
}
|
||||
|
||||
switch(status.dma_state) {
|
||||
case DMASTATE_INACTIVE:
|
||||
break;
|
||||
|
||||
case DMASTATE_DMASYNC:
|
||||
status.dma_state = DMASTATE_RUN;
|
||||
break;
|
||||
|
||||
case DMASTATE_RUN:
|
||||
status.dma_state = DMASTATE_CPUSYNC;
|
||||
status.dma_clocks = 8 - dma_counter() + 8;
|
||||
add_clocks(status.dma_clocks);
|
||||
|
||||
if(status.hdmainit_pending) { hdma_init(); status.hdmainit_pending = false; }
|
||||
if(status.hdma_pending) { hdma_run(); status.hdma_pending = false; }
|
||||
if(status.dma_pending) { dma_run(); status.dma_pending = false; }
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(status.hdmainit_triggered == false) {
|
||||
if(status.hclock >= 12 || status.vcounter) {
|
||||
if(status.hclock >= status.hdmainit_trigger_position || status.vcounter) {
|
||||
status.hdmainit_triggered = true;
|
||||
hdma_init();
|
||||
|
||||
hdma_init_reset();
|
||||
if(hdma_enabled_channels()) {
|
||||
if(status.dma_state == DMASTATE_INACTIVE) {
|
||||
status.dma_state = DMASTATE_DMASYNC;
|
||||
status.hdmainit_pending = true;
|
||||
} else {
|
||||
hdma_init();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(status.hdma_triggered == false) {
|
||||
if(status.hclock >= 1106) {
|
||||
status.hdma_triggered = true;
|
||||
hdma_run();
|
||||
if(hdma_active_channels()) {
|
||||
if(status.dma_state == DMASTATE_INACTIVE) {
|
||||
status.dma_state = DMASTATE_DMASYNC;
|
||||
status.hdma_pending = true;
|
||||
} else {
|
||||
hdma_run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,7 +223,7 @@ void sCPU::cycle_edge() {
|
|||
* trigger during certain events (immediately after DMA, writes to $4200, etc)
|
||||
*****/
|
||||
void sCPU::last_cycle() {
|
||||
if(status.irq_delay)return;
|
||||
if(counter.irq_delay) { return; }
|
||||
|
||||
status.nmi_pending |= nmi_test();
|
||||
status.irq_pending |= irq_test();
|
||||
|
@ -174,6 +247,12 @@ void sCPU::timing_power() {
|
|||
}
|
||||
|
||||
void sCPU::timing_reset() {
|
||||
counter.enabled = false;
|
||||
counter.irq_delay = 0;
|
||||
counter.hw_math = 0;
|
||||
counter.irq_fire = 0;
|
||||
counter.nmi_fire = 0;
|
||||
|
||||
status.clock_count = 0;
|
||||
status.clocks_executed = 0;
|
||||
|
||||
|
@ -185,14 +264,21 @@ void sCPU::timing_reset() {
|
|||
status.interlace_field = 0;
|
||||
status.overscan = false;
|
||||
status.region_scanlines = (status.region == SNES::NTSC) ? 525 : 625;
|
||||
status.vblstart = 225;
|
||||
|
||||
status.field_lines = status.region_scanlines >> 1;
|
||||
status.line_clocks = 1364;
|
||||
|
||||
status.line_rendered = false;
|
||||
status.dram_refreshed = false;
|
||||
status.hdmainit_triggered = false;
|
||||
status.hdma_triggered = false;
|
||||
status.line_rendered = false;
|
||||
status.line_render_position = minmax<0, 1112>((uint16)config::ppu.render_scanline_position);
|
||||
|
||||
status.dram_refreshed = false;
|
||||
status.dram_refresh_position = (cpu_version == 1) ? 530 : 538;
|
||||
|
||||
status.hdmainit_triggered = false;
|
||||
status.hdmainit_trigger_position = 0;
|
||||
|
||||
status.hdma_triggered = false;
|
||||
|
||||
status.irq_delay = 0;
|
||||
|
||||
|
@ -204,10 +290,17 @@ void sCPU::timing_reset() {
|
|||
status.irq_read = 1;
|
||||
status.irq_line = 1;
|
||||
status.irq_transition = 0;
|
||||
status.irq_lock = false;
|
||||
status.irq_pending = false;
|
||||
|
||||
update_interrupts();
|
||||
|
||||
status.dma_counter = 0;
|
||||
status.dma_state = DMASTATE_INACTIVE;
|
||||
status.dma_pending = false;
|
||||
status.hdma_pending = false;
|
||||
status.hdmainit_pending = false;
|
||||
|
||||
//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]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
uint16 vcounter();
|
||||
uint16 hcounter();
|
||||
uint16 hcycles();
|
||||
uint16 hclock();
|
||||
|
||||
bool interlace();
|
||||
bool interlace_field();
|
||||
|
@ -10,7 +10,10 @@
|
|||
void set_interlace(bool r);
|
||||
void set_overscan(bool r);
|
||||
|
||||
uint dma_counter();
|
||||
|
||||
void add_clocks(uint clocks);
|
||||
void tick();
|
||||
void scanline();
|
||||
void frame();
|
||||
|
||||
|
@ -22,16 +25,23 @@
|
|||
void timing_power();
|
||||
void timing_reset();
|
||||
|
||||
void counter_set(uint &ctr, uint clocks) {
|
||||
if(clocks >= ctr) { ctr = clocks; }
|
||||
}
|
||||
|
||||
//timeshift.cpp
|
||||
void timeshift_forward (uint clocks, uint &v, uint &h);
|
||||
void timeshift_backward(uint clocks, uint &v, uint &h);
|
||||
|
||||
//irq.cpp
|
||||
void set_irq_delay(uint clocks);
|
||||
enum { IRQ_TRIGGER_NEVER = 0x3fff };
|
||||
void update_interrupts();
|
||||
void poll_interrupts(int clocks);
|
||||
bool nmi_read_pos_match(uint offset);
|
||||
bool irq_read_pos_match(uint offset);
|
||||
void nmi_tick();
|
||||
void irq_tick();
|
||||
void poll_interrupts();
|
||||
bool irq_pos_valid();
|
||||
bool nmi_test();
|
||||
bool irq_test();
|
||||
|
||||
//joypad.cpp
|
||||
void run_manual_joypad_poll();
|
||||
void run_auto_joypad_poll();
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
|
@ -185,7 +185,7 @@ int n = addr & 15;
|
|||
}
|
||||
|
||||
void bDSP::power() {
|
||||
spcram = r_apu->get_spcram_handle();
|
||||
spcram = r_smp->get_spcram_handle();
|
||||
memset(dspram, 0x00, 128);
|
||||
|
||||
for(int v = 0; v < 8; v++) {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#define r_mem ref(deref(mem))
|
||||
#define r_cpu ref(deref(cpu))
|
||||
#define r_apu ref(deref(apu))
|
||||
#define r_smp ref(deref(smp))
|
||||
#define r_dsp ref(deref(dsp))
|
||||
#define r_ppu ref(deref(ppu))
|
||||
|
||||
|
@ -22,9 +22,9 @@
|
|||
#include "cpu/scpu/scpu.h"
|
||||
//#include "cpu/bcpu/bcpu.h"
|
||||
|
||||
#include "apu/apu.h"
|
||||
#include "apu/sapu/sapu.h"
|
||||
//#include "apu/bapu/bapu.h"
|
||||
#include "smp/smp.h"
|
||||
#include "smp/ssmp/ssmp.h"
|
||||
//#include "smp/bsmp/bsmp.h"
|
||||
|
||||
#include "dsp/dsp.h"
|
||||
#include "dsp/bdsp/bdsp.h"
|
||||
|
@ -45,52 +45,32 @@ extern MMIO mmio_unmapped;
|
|||
#ifdef POLYMORPHISM
|
||||
extern MemBus *deref(mem);
|
||||
extern CPU *deref(cpu);
|
||||
extern APU *deref(apu);
|
||||
extern SMP *deref(smp);
|
||||
extern DSP *deref(dsp);
|
||||
extern PPU *deref(ppu);
|
||||
#else
|
||||
extern MEMCORE deref(mem);
|
||||
extern CPUCORE deref(cpu);
|
||||
extern APUCORE deref(apu);
|
||||
extern SMPCORE deref(smp);
|
||||
extern DSPCORE deref(dsp);
|
||||
extern PPUCORE deref(ppu);
|
||||
#endif
|
||||
extern SNES *snes;
|
||||
|
||||
extern SRTC *srtc;
|
||||
extern SDD1 *sdd1;
|
||||
extern C4 *c4;
|
||||
extern DSP1 *dsp1;
|
||||
extern DSP2 *dsp2;
|
||||
extern OBC1 *obc1;
|
||||
|
||||
#include "config/config.h"
|
||||
|
||||
#ifdef INTERFACE_MAIN
|
||||
Cartridge cartridge;
|
||||
Cheat cheat;
|
||||
|
||||
#include "config/config.cpp"
|
||||
#ifdef POLYMORPHISM
|
||||
MemBus *deref(mem);
|
||||
CPU *deref(cpu);
|
||||
APU *deref(apu);
|
||||
DSP *deref(dsp);
|
||||
PPU *deref(ppu);
|
||||
#else
|
||||
MEMCORE deref(mem);
|
||||
CPUCORE deref(cpu);
|
||||
APUCORE deref(apu);
|
||||
DSPCORE deref(dsp);
|
||||
PPUCORE deref(ppu);
|
||||
#endif
|
||||
SNES *snes;
|
||||
|
||||
SRTC *srtc;
|
||||
SDD1 *sdd1;
|
||||
C4 *c4;
|
||||
DSP1 *dsp1;
|
||||
DSP2 *dsp2;
|
||||
OBC1 *obc1;
|
||||
|
||||
#include "config/config.cpp"
|
||||
#ifdef POLYMORPHISM
|
||||
MemBus *deref(mem);
|
||||
CPU *deref(cpu);
|
||||
APU *deref(smp);
|
||||
DSP *deref(dsp);
|
||||
PPU *deref(ppu);
|
||||
#else
|
||||
MEMCORE deref(mem);
|
||||
CPUCORE deref(cpu);
|
||||
SMPCORE deref(smp);
|
||||
DSPCORE deref(dsp);
|
||||
PPUCORE deref(ppu);
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
libarray : version 0.07 ~byuu (10/14/06)
|
||||
*/
|
||||
|
||||
#ifndef __LIBARRAY
|
||||
#define __LIBARRAY
|
||||
|
||||
template<typename T> class array {
|
||||
protected:
|
||||
T *pool;
|
||||
uint poolsize, buffersize;
|
||||
|
||||
protected:
|
||||
uint findsize(uint size) {
|
||||
if(size <= 0x100) { return 0x100; }
|
||||
if(size <= 0x400) { return 0x400; }
|
||||
if(size <= 0x1000) { return 0x1000; }
|
||||
if(size <= 0x4000) { return 0x4000; }
|
||||
if(size <= 0x10000) { return 0x10000; }
|
||||
if(size <= 0x40000) { return 0x40000; }
|
||||
if(size <= 0x100000) { return 0x100000; }
|
||||
|
||||
return (size + 0x100000) & ~0xfffff;
|
||||
}
|
||||
|
||||
public:
|
||||
uint size() { return buffersize; }
|
||||
uint capacity() { return buffersize; }
|
||||
|
||||
void reset() {
|
||||
if(pool) {
|
||||
free(pool);
|
||||
pool = 0;
|
||||
}
|
||||
|
||||
poolsize = 0;
|
||||
buffersize = 0;
|
||||
}
|
||||
|
||||
void reserve(uint size) {
|
||||
if(size == poolsize)return;
|
||||
|
||||
if(size < poolsize) {
|
||||
buffersize = size;
|
||||
}
|
||||
|
||||
pool = static_cast<T*>(realloc(pool, sizeof(T) * size));
|
||||
poolsize = size;
|
||||
}
|
||||
|
||||
T *get(uint size = 0) {
|
||||
if(size > buffersize)resize(size);
|
||||
if(size > buffersize)throw "array[] out of bounds";
|
||||
return pool;
|
||||
}
|
||||
|
||||
void clear() { memset(pool, 0, sizeof(T) * buffersize); }
|
||||
|
||||
void resize(uint size) {
|
||||
reserve(findsize(size));
|
||||
buffersize = size;
|
||||
}
|
||||
|
||||
array() {
|
||||
pool = 0;
|
||||
poolsize = 0;
|
||||
buffersize = 0;
|
||||
}
|
||||
|
||||
~array() { reset(); }
|
||||
|
||||
inline T &operator[](int index) {
|
||||
if(index >= buffersize)resize(index + 1);
|
||||
if(index >= buffersize)throw "array[] out of bounds";
|
||||
return pool[index];
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
libbase : version 0.08b ~byuu (07/30/06)
|
||||
libbase : version 0.08c ~byuu (09/28/06)
|
||||
*/
|
||||
|
||||
#ifndef __LIBBASE
|
||||
|
@ -8,6 +8,9 @@
|
|||
#if defined(_MSC_VER)
|
||||
//disable libc deprecation warnings in MSVC 2k5+
|
||||
#pragma warning(disable:4996)
|
||||
|
||||
#define ftruncate _chsize
|
||||
#define vsnprintf _vsnprintf
|
||||
#endif
|
||||
|
||||
/*****
|
||||
|
@ -15,15 +18,15 @@
|
|||
*****/
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define noinline __declspec(noinline)
|
||||
#define inline inline
|
||||
#define forceinline __forceinline
|
||||
#define fastcall __fastcall
|
||||
#define noinline __declspec(noinline)
|
||||
#define inline inline
|
||||
#define alwaysinline __forceinline
|
||||
#define fastcall __fastcall
|
||||
#elif defined(__GNUC__)
|
||||
#define noinline
|
||||
#define inline inline
|
||||
#define forceinline inline
|
||||
#define fastcall __attribute__((fastcall))
|
||||
#define inline inline
|
||||
#define alwaysinline inline
|
||||
#define fastcall __attribute__((fastcall))
|
||||
#else
|
||||
#error "unsupported compiler"
|
||||
#endif
|
||||
|
@ -34,6 +37,7 @@
|
|||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#include <io.h>
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
|
@ -217,8 +221,6 @@ typedef int_t<48, int64> int48;
|
|||
#define order_msb6(a,b,c,d,e,f) f,e,d,c,b,a
|
||||
#define order_msb7(a,b,c,d,e,f,g) g,f,e,d,c,b,a
|
||||
#define order_msb8(a,b,c,d,e,f,g,h) h,g,f,e,d,c,b,a
|
||||
#define order_lsbit8(b0,b1,b2,b3,b4,b5,b6,b7) b7:1,b6:1,b5:1,b4:1,b3:1,b2:1,b1:1,b0:1
|
||||
#define order_msbit8(b7,b6,b5,b4,b3,b2,b1,b0) b0:1,b1:1,b2:1,b3:1,b4:1,b5:1,b6:1,b7:1
|
||||
#else
|
||||
//big-endian: uint8[] { 0x01, 0x02, 0x03, 0x04 } = 0x01020304
|
||||
#define order_lsb2(a,b) b,a
|
||||
|
@ -235,15 +237,13 @@ typedef int_t<48, int64> int48;
|
|||
#define order_msb6(a,b,c,d,e,f) a,b,c,d,e,f
|
||||
#define order_msb7(a,b,c,d,e,f,g) a,b,c,d,e,f,g
|
||||
#define order_msb8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h
|
||||
#define order_lsbit8(b7,b6,b5,b4,b3,b2,b1,b0) b0:1,b1:1,b2:1,b3:1,b4:1,b5:1,b6:1,b7:1
|
||||
#define order_msbit8(b0,b1,b2,b3,b4,b5,b6,b7) b7:1,b6:1,b5:1,b4:1,b3:1,b2:1,b1:1,b0:1
|
||||
#endif
|
||||
|
||||
/*****
|
||||
* libc extensions
|
||||
*****/
|
||||
|
||||
inline bool fexists(const char *fn) {
|
||||
static bool fexists(const char *fn) {
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
if(!fp)return false;
|
||||
fclose(fp);
|
||||
|
@ -251,7 +251,7 @@ FILE *fp = fopen(fn, "rb");
|
|||
return true;
|
||||
}
|
||||
|
||||
inline uint32 fsize(FILE *fp) {
|
||||
static uint32 fsize(FILE *fp) {
|
||||
if(!fp)return 0;
|
||||
uint32 pos = ftell(fp);
|
||||
fseek(fp, 0, SEEK_END);
|
||||
|
@ -260,7 +260,7 @@ uint32 size = ftell(fp);
|
|||
return size;
|
||||
}
|
||||
|
||||
inline uint32 fsize(const char *fn) {
|
||||
static uint32 fsize(const char *fn) {
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
if(!fp)return 0;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
|
@ -270,6 +270,8 @@ uint32 size = ftell(fp);
|
|||
return size;
|
||||
}
|
||||
|
||||
inline int ftruncate(FILE *fp, long size) { return ftruncate(fileno(fp), size); }
|
||||
|
||||
/*****
|
||||
* crc32 calculation
|
||||
* TODO: create libhash and move this code there
|
||||
|
|
|
@ -184,7 +184,7 @@ char *buffer = (char*)malloc(fsize + 1);
|
|||
|
||||
return true;
|
||||
}
|
||||
bool Config::load(substring &fn) { return load(strptr(fn)); }
|
||||
bool Config::load(string &fn) { return load(strptr(fn)); }
|
||||
|
||||
bool Config::save(char *fn) {
|
||||
FILE *fp;
|
||||
|
@ -209,7 +209,7 @@ FILE *fp;
|
|||
|
||||
return true;
|
||||
}
|
||||
bool Config::save(substring &fn) { return save(strptr(fn)); }
|
||||
bool Config::save(string &fn) { return save(strptr(fn)); }
|
||||
|
||||
Config::Config() {
|
||||
list_count = 0;
|
||||
|
|
|
@ -1,31 +1,15 @@
|
|||
/*
|
||||
libconfig : version 0.08a ~byuu (07/16/06)
|
||||
libconfig : version 0.10 ~byuu (10/10/06)
|
||||
*/
|
||||
|
||||
#ifndef __LIBCONFIG
|
||||
#define __LIBCONFIG
|
||||
|
||||
#include "libarray.h"
|
||||
#include "libstring.h"
|
||||
|
||||
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) \
|
||||
template<typename T> inline __name &operator=(const T &x) { set(x); return *this; } \
|
||||
void toggle() { data ^= 1; set(data); } \
|
||||
__name(Config *_parent, char *_name, char *_desc, uint _data, uint _type) : \
|
||||
Setting(_parent, _name, _desc, _data, _type) {} \
|
||||
__name(Config *_parent, char *_name, char *_desc, char *_data) : \
|
||||
Setting(_parent, _name, _desc, _data) {}
|
||||
|
||||
class Setting {
|
||||
friend class Config;
|
||||
|
||||
|
@ -49,7 +33,7 @@ enum {
|
|||
STR = 10,
|
||||
};
|
||||
char *name, *desc;
|
||||
substring char_data, char_def;
|
||||
string char_data, char_def;
|
||||
virtual void toggle();
|
||||
virtual uint get();
|
||||
virtual void set(uint _data);
|
||||
|
@ -72,10 +56,11 @@ substring char_data, char_def;
|
|||
|
||||
class Config {
|
||||
protected:
|
||||
vector<Setting*> list;
|
||||
array<Setting*> list;
|
||||
uint list_count;
|
||||
|
||||
string data, line, part, subpart;
|
||||
string data;
|
||||
stringarray line, part, subpart;
|
||||
|
||||
uint string_to_uint(uint type, char *input);
|
||||
char *uint_to_string(uint type, uint input);
|
||||
|
@ -83,9 +68,9 @@ char *uint_to_string(uint type, uint input);
|
|||
public:
|
||||
void add(Setting *setting);
|
||||
bool load(char *fn);
|
||||
bool load(substring &fn);
|
||||
bool load(string &fn);
|
||||
bool save(char *fn);
|
||||
bool save(substring &fn);
|
||||
bool save(string &fn);
|
||||
Config();
|
||||
};
|
||||
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
#include "libbase.h"
|
||||
#include "libvector.h"
|
||||
#include "libfile.h"
|
||||
|
||||
/*****
|
||||
* c wrappers
|
||||
*****/
|
||||
|
||||
void fread(file *s, uint8 *data, uint length) { s->read(data, length); }
|
||||
uint8 fread(file *s) { return s->read(); }
|
||||
uint8 fgetc(file *s) { return s->read(); }
|
||||
|
||||
void fwrite(file *s, uint8 *data, uint length) { s->write(data, length); }
|
||||
void fwrite(file *s, uint8 data) { s->write(data); }
|
||||
void fputc(file *s, uint8 data) { s->write(data); }
|
||||
|
||||
void fseek(file *s, uint offset, uint mode) { s->seek(offset, mode); }
|
||||
uint foffset(file *s) { return s->offset(); }
|
||||
uint ftell(file *s) { return s->offset(); }
|
||||
uint fsize(file *s) { return s->size(); }
|
||||
bool feof(file *s) { return s->eof(); }
|
||||
|
||||
bool fopen(file *s, const char *filename, uint mode) { return s->open(filename, mode); }
|
||||
bool fopen(file *s) { return s->open(); }
|
||||
bool fflush(file *s) { return s->flush(); }
|
||||
bool fclose(file *s) { return s->close(); }
|
||||
|
||||
/*****
|
||||
* c++ wrappers
|
||||
*****/
|
||||
|
||||
void fread(file &s, uint8 *data, uint length) { s.read(data, length); }
|
||||
uint8 fread(file &s) { return s.read(); }
|
||||
uint8 fgetc(file &s) { return s.read(); }
|
||||
|
||||
void fwrite(file &s, uint8 *data, uint length) { s.write(data, length); }
|
||||
void fwrite(file &s, uint8 data) { s.write(data); }
|
||||
void fputc(file &s, uint8 data) { s.write(data); }
|
||||
|
||||
void fseek(file &s, uint offset, uint mode) { s.seek(offset, mode); }
|
||||
uint foffset(file &s) { return s.offset(); }
|
||||
uint ftell(file &s) { return s.offset(); }
|
||||
uint fsize(file &s) { return s.size(); }
|
||||
bool feof(file &s) { return s.eof(); }
|
||||
|
||||
bool fopen(file &s, const char *filename, uint mode) { return s.open(filename, mode); }
|
||||
bool fopen(file &s) { return s.open(); }
|
||||
bool fflush(file &s) { return s.flush(); }
|
||||
bool fclose(file &s) { return s.close(); }
|
|
@ -1,12 +1,12 @@
|
|||
/*
|
||||
libfile : version 0.02 ~byuu (06/17/06)
|
||||
libfile : version 0.05 ~byuu (10/12/06)
|
||||
*/
|
||||
|
||||
#ifndef __LIBFILE
|
||||
#define __LIBFILE
|
||||
|
||||
/*****
|
||||
* file base class
|
||||
* file object
|
||||
*****/
|
||||
|
||||
class file {
|
||||
|
@ -19,7 +19,10 @@ enum { seek_start, seek_end, seek_back, seek_forward };
|
|||
virtual void write(uint8 *data, uint length) = 0;
|
||||
virtual void write(uint8 data) = 0;
|
||||
|
||||
virtual uint32 crc32();
|
||||
|
||||
virtual void seek(uint offset, uint mode = seek_start) = 0;
|
||||
virtual void truncate(uint size) = 0;
|
||||
virtual uint offset() = 0;
|
||||
virtual uint size() = 0;
|
||||
virtual bool eof() = 0;
|
||||
|
@ -30,51 +33,128 @@ enum { seek_start, seek_end, seek_back, seek_forward };
|
|||
virtual bool close() = 0;
|
||||
};
|
||||
|
||||
/*****
|
||||
* c wrappers
|
||||
*****/
|
||||
|
||||
void fread(file *s, uint8 *data, uint length);
|
||||
uint8 fread(file *s);
|
||||
uint8 fgetc(file *s);
|
||||
|
||||
void fwrite(file *s, uint8 *data, uint length);
|
||||
void fwrite(file *s, uint8 data);
|
||||
void fputc(file *s, uint8 data);
|
||||
|
||||
void fseek(file *s, uint offset, uint mode = file::seek_start);
|
||||
uint foffset(file *s);
|
||||
uint ftell(file *s);
|
||||
uint fsize(file *s);
|
||||
bool feof(file *s);
|
||||
|
||||
bool fopen(file *s, const char *filename, uint mode);
|
||||
bool fopen(file *s);
|
||||
bool fflush(file *s);
|
||||
bool fclose(file *s);
|
||||
inline uint32 file::crc32() {
|
||||
uint pos = offset(), i = size();
|
||||
seek(0);
|
||||
uint32 crc32 = 0xffffffff;
|
||||
while(i--) {
|
||||
crc32 = crc32_adjust(crc32, read());
|
||||
}
|
||||
seek(pos);
|
||||
return ~crc32;
|
||||
}
|
||||
|
||||
/*****
|
||||
* c++ wrappers
|
||||
*****/
|
||||
|
||||
void fread(file &s, uint8 *data, uint length);
|
||||
uint8 fread(file &s);
|
||||
uint8 fgetc(file &s);
|
||||
inline void fread(file &s, uint8 *data, uint length) { s.read(data, length); }
|
||||
inline uint8 fread(file &s) { return s.read(); }
|
||||
inline uint8 fgetc(file &s) { return s.read(); }
|
||||
|
||||
void fwrite(file &s, uint8 *data, uint length);
|
||||
void fwrite(file &s, uint8 data);
|
||||
void fputc(file &s, uint8 data);
|
||||
inline void fwrite(file &s, uint8 *data, uint length) { s.write(data, length); }
|
||||
inline void fwrite(file &s, uint8 data) { s.write(data); }
|
||||
inline void fputc(file &s, uint8 data) { s.write(data); }
|
||||
|
||||
void fseek(file &s, uint offset, uint mode = file::seek_start);
|
||||
uint foffset(file &s);
|
||||
uint ftell(file &s);
|
||||
uint fsize(file &s);
|
||||
bool feof(file &s);
|
||||
inline uint32 fcrc32(file &s) { return s.crc32(); }
|
||||
|
||||
bool fopen(file &s, const char *filename, uint mode);
|
||||
bool fopen(file &s);
|
||||
bool fflush(file &s);
|
||||
bool fclose(file &s);
|
||||
inline void fseek(file &s, uint offset, uint mode = file::seek_start) { s.seek(offset, mode); }
|
||||
inline void ftruncate(file &s, uint size) { s.truncate(size); }
|
||||
inline uint ftell(file &s) { return s.offset(); }
|
||||
inline uint fsize(file &s) { return s.size(); }
|
||||
inline bool feof(file &s) { return s.eof(); }
|
||||
|
||||
inline bool fopen(file &s, const char *filename, uint mode) { return s.open(filename, mode); }
|
||||
inline bool fopen(file &s) { return s.open(); }
|
||||
inline bool fflush(file &s) { return s.flush(); }
|
||||
inline bool fclose(file &s) { return s.close(); }
|
||||
|
||||
|
||||
/*****
|
||||
* endian wrappers
|
||||
*****/
|
||||
|
||||
inline uint8 fgetlb(file &s) { return fgetc(s); }
|
||||
inline uint8 fgetmb(file &s) { return fgetc(s); }
|
||||
|
||||
inline uint16 fgetlw(file &s) {
|
||||
return (fgetc(s)) | (fgetc(s) << 8);
|
||||
}
|
||||
|
||||
inline uint16 fgetmw(file &s) {
|
||||
return (fgetc(s) << 8) | (fgetc(s) << 8);
|
||||
}
|
||||
|
||||
inline uint32 fgetld(file &s) {
|
||||
return (fgetc(s)) | (fgetc(s) << 8) | (fgetc(s) << 16) | (fgetc(s) << 24);
|
||||
}
|
||||
|
||||
inline uint32 fgetmd(file &s) {
|
||||
return (fgetc(s) << 24) | (fgetc(s) << 16) | (fgetc(s) << 8) | (fgetc(s));
|
||||
}
|
||||
|
||||
inline uint64 fgetlq(file &s) {
|
||||
return ((uint64)fgetc(s) << 0) | ((uint64)fgetc(s) << 8) |
|
||||
((uint64)fgetc(s) << 16) | ((uint64)fgetc(s) << 24) |
|
||||
((uint64)fgetc(s) << 32) | ((uint64)fgetc(s) << 40) |
|
||||
((uint64)fgetc(s) << 48) | ((uint64)fgetc(s) << 56);
|
||||
}
|
||||
|
||||
inline uint64 fgetmq(file &s) {
|
||||
return ((uint64)fgetc(s) << 56) | ((uint64)fgetc(s) << 48) |
|
||||
((uint64)fgetc(s) << 40) | ((uint64)fgetc(s) << 32) |
|
||||
((uint64)fgetc(s) << 24) | ((uint64)fgetc(s) << 16) |
|
||||
((uint64)fgetc(s) << 8) | ((uint64)fgetc(s) << 0);
|
||||
}
|
||||
|
||||
inline void fputlb(file &s, uint8 data) { fputc(s, data); }
|
||||
inline void fputmb(file &s, uint8 data) { fputc(s, data); }
|
||||
|
||||
inline void fputlw(file &s, uint16 data) {
|
||||
fputc(s, data >> 0);
|
||||
fputc(s, data >> 8);
|
||||
}
|
||||
|
||||
inline void fputmw(file &s, uint16 data) {
|
||||
fputc(s, data >> 8);
|
||||
fputc(s, data >> 0);
|
||||
}
|
||||
|
||||
inline void fputld(file &s, uint32 data) {
|
||||
fputc(s, data >> 0);
|
||||
fputc(s, data >> 8);
|
||||
fputc(s, data >> 16);
|
||||
fputc(s, data >> 24);
|
||||
}
|
||||
|
||||
inline void fputmd(file &s, uint32 data) {
|
||||
fputc(s, data >> 24);
|
||||
fputc(s, data >> 16);
|
||||
fputc(s, data >> 8);
|
||||
fputc(s, data >> 0);
|
||||
}
|
||||
|
||||
inline void fputlq(file &s, uint64 data) {
|
||||
fputc(s, data >> 0);
|
||||
fputc(s, data >> 8);
|
||||
fputc(s, data >> 16);
|
||||
fputc(s, data >> 24);
|
||||
fputc(s, data >> 32);
|
||||
fputc(s, data >> 40);
|
||||
fputc(s, data >> 48);
|
||||
fputc(s, data >> 56);
|
||||
}
|
||||
|
||||
inline void fputmq(file &s, uint64 data) {
|
||||
fputc(s, data >> 56);
|
||||
fputc(s, data >> 48);
|
||||
fputc(s, data >> 40);
|
||||
fputc(s, data >> 32);
|
||||
fputc(s, data >> 24);
|
||||
fputc(s, data >> 16);
|
||||
fputc(s, data >> 8);
|
||||
fputc(s, data >> 0);
|
||||
}
|
||||
|
||||
/*****
|
||||
* ramfile
|
||||
|
@ -83,18 +163,19 @@ bool fclose(file &s);
|
|||
class ramfile : public file {
|
||||
private:
|
||||
FILE *fp;
|
||||
vector<uint8> filedata;
|
||||
array<uint8> filedata;
|
||||
char filename[1024];
|
||||
uint filepos;
|
||||
uint filesize;
|
||||
uint filemode;
|
||||
bool fileopen;
|
||||
bool filevirtual;
|
||||
|
||||
public:
|
||||
void read(uint8 *data, uint length) {
|
||||
if(!fileopen || filemode == mode_write) { return; }
|
||||
|
||||
filedata.read(filepos, data, length);
|
||||
memcpy(data, filedata.get(filepos + length) + filepos, length);
|
||||
filepos += length;
|
||||
if(filepos > filesize)filepos = filesize;
|
||||
}
|
||||
|
@ -102,15 +183,14 @@ public:
|
|||
uint8 read() {
|
||||
if(!fileopen || filemode == mode_write) { return 0; }
|
||||
|
||||
uint8 r = filedata[filepos++];
|
||||
if(filepos > filesize)filepos = filesize;
|
||||
return r;
|
||||
if(eof() == true) { return 0xff; }
|
||||
return filedata[filepos++];
|
||||
}
|
||||
|
||||
void write(uint8 *data, uint length) {
|
||||
if(!fileopen || filemode == mode_read) { return; }
|
||||
|
||||
filedata.write(filepos, data, length);
|
||||
memcpy(filedata.get(filepos + length) + filepos, data, length);
|
||||
filepos += length;
|
||||
if(filepos > filesize)filesize = filepos;
|
||||
}
|
||||
|
@ -127,7 +207,7 @@ public:
|
|||
|
||||
switch(mode) {
|
||||
case seek_start: filepos = offset; break;
|
||||
case seek_end: filepos = filesize - offset; break;
|
||||
case seek_end: filepos = filesize + offset; break;
|
||||
case seek_back: filepos -= offset; break;
|
||||
case seek_forward: filepos += offset; break;
|
||||
}
|
||||
|
@ -139,6 +219,11 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void truncate(uint size) {
|
||||
filesize = size;
|
||||
if(filepos > filesize)filepos = filesize;
|
||||
}
|
||||
|
||||
uint offset() {
|
||||
if(!fileopen) { return 0; }
|
||||
|
||||
|
@ -160,16 +245,21 @@ public:
|
|||
bool open(const char *fn, uint mode) {
|
||||
if(fileopen) { return false; }
|
||||
|
||||
strcpy(filename, fn);
|
||||
strcpy(filename, fn ? fn : "");
|
||||
filevirtual = (*filename == 0);
|
||||
filemode = mode;
|
||||
switch(filemode) {
|
||||
case mode_read:
|
||||
case mode_readwrite:
|
||||
fp = fopen(filename, "rb");
|
||||
if(!fp) { return false; }
|
||||
filesize = fsize(fp);
|
||||
fread(filedata.handle(filesize), 1, filesize, fp);
|
||||
fclose(fp);
|
||||
if(filevirtual == true) {
|
||||
filesize = 0;
|
||||
} else {
|
||||
fp = fopen(filename, "rb");
|
||||
if(!fp) { return false; }
|
||||
filesize = fsize(fp);
|
||||
fread(filedata.get(filesize), 1, filesize, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
filesize = 0;
|
||||
|
@ -191,10 +281,12 @@ public:
|
|||
case mode_readwrite:
|
||||
case mode_write:
|
||||
case mode_writeread:
|
||||
fp = fopen(filename, "wb");
|
||||
if(!fp) { return false; }
|
||||
fwrite(filedata.handle(filesize), 1, filesize, fp);
|
||||
fclose(fp);
|
||||
if(filevirtual == false) {
|
||||
fp = fopen(filename, "wb");
|
||||
if(!fp) { return false; }
|
||||
fwrite(filedata.get(filesize), 1, filesize, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
|
@ -205,7 +297,7 @@ public:
|
|||
|
||||
bool result = flush();
|
||||
fileopen = false;
|
||||
filedata.release();
|
||||
filedata.reset();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -237,6 +329,7 @@ public:
|
|||
uint8 read() {
|
||||
if(!fp || filemode == mode_write) { return 0; }
|
||||
|
||||
if(eof() == true) { return 0xff; }
|
||||
return fgetc(fp);
|
||||
}
|
||||
|
||||
|
@ -257,13 +350,19 @@ public:
|
|||
|
||||
switch(mode) {
|
||||
default:
|
||||
case seek_start: fseek(fp, offset, SEEK_SET); break;
|
||||
case seek_end: fseek(fp, offset, SEEK_END); break;
|
||||
case seek_back: fseek(fp, -offset, SEEK_CUR); break;
|
||||
case seek_forward: fseek(fp, offset, SEEK_CUR); break;
|
||||
case seek_start: fseek(fp, offset, SEEK_SET); break;
|
||||
case seek_end: fseek(fp, offset, SEEK_END); break;
|
||||
case seek_back: fseek(fp, offset, SEEK_CUR); break;
|
||||
case seek_forward: fseek(fp, offset, SEEK_CUR); break;
|
||||
}
|
||||
}
|
||||
|
||||
void truncate(uint size) {
|
||||
if(!fp) { return; }
|
||||
|
||||
ftruncate(fp, size);
|
||||
}
|
||||
|
||||
uint offset() {
|
||||
if(!fp) { return 0; }
|
||||
|
||||
|
@ -283,7 +382,12 @@ public:
|
|||
bool eof() {
|
||||
if(!fp) { return true; }
|
||||
|
||||
return feof(fp);
|
||||
if(feof(fp)) {
|
||||
seek(size(), seek_start);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool open(const char *filename, uint mode) {
|
||||
|
@ -331,4 +435,15 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/*****
|
||||
* directory object
|
||||
*****/
|
||||
|
||||
class directory {
|
||||
public:
|
||||
void open(const char *path) {}
|
||||
void close() {}
|
||||
uint read(char *filename, uint maxlength) { return 0; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,38 +1,7 @@
|
|||
#include "libbase.h"
|
||||
#include "libstring.h"
|
||||
|
||||
substring::substring() {
|
||||
size = 16;
|
||||
s = (char*)malloc(size + 1);
|
||||
*s = 0;
|
||||
}
|
||||
|
||||
substring::~substring() {
|
||||
SafeFree(s);
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
string::string() {
|
||||
count = 0;
|
||||
listcount = 0;
|
||||
addto(0);
|
||||
}
|
||||
|
||||
string::~string() {
|
||||
for(int i = listcount - 1; i >= 0; i--) {
|
||||
delete((substring*)list[i]);
|
||||
}
|
||||
}
|
||||
uint count(stringarray &str) { return str.size(); }
|
||||
|
||||
char chrlower(char c) {
|
||||
if(c >= 'A' && c <= 'Z')return c + ('a' - 'A');
|
||||
|
@ -44,21 +13,19 @@ char chrupper(char c) {
|
|||
return c;
|
||||
}
|
||||
|
||||
uint count(string &str) { return str.count; }
|
||||
|
||||
void strresize(substring &str, uint size) {
|
||||
void strresize(string &str, uint size) {
|
||||
str.s = (char*)realloc(str.s, size + 1);
|
||||
str.s[size] = 0;
|
||||
str.size = size;
|
||||
}
|
||||
|
||||
char *strptr(substring &str) { return str.s; }
|
||||
char *strptr(string &str) { return str.s; }
|
||||
|
||||
uint strlen(substring &str) { return strlen(strptr(str)); }
|
||||
uint strlen(string &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 strcmp(string &dest, const char *src) { return strcmp(strptr(dest), src); }
|
||||
int strcmp(const char *dest, string &src) { return strcmp(dest, strptr(src)); }
|
||||
int strcmp(string &dest, string &src) { return strcmp(strptr(dest), strptr(src)); }
|
||||
|
||||
int __stricmp(const char *dest, const char *src) {
|
||||
while(*dest) {
|
||||
|
@ -68,36 +35,36 @@ int __stricmp(const char *dest, const char *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)); }
|
||||
int stricmp(string &dest, const char *src) { return __stricmp(strptr(dest), src); }
|
||||
int stricmp(const char *dest, string &src) { return __stricmp(dest, strptr(src)); }
|
||||
int stricmp(string &dest, string &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 strmatch(string &dest, const char *src) { return strmatch(strptr(dest), src); }
|
||||
bool strmatch(const char *dest, string &src) { return strmatch(dest, strptr(src)); }
|
||||
bool strmatch(string &dest, string &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)); }
|
||||
bool strimatch(string &dest, const char *src) { return strimatch(strptr(dest), src); }
|
||||
bool strimatch(const char *dest, string &src) { return strimatch(dest, strptr(src)); }
|
||||
bool strimatch(string &dest, string &src) { return strimatch(strptr(dest), strptr(src)); }
|
||||
|
||||
void strcpy(substring &dest, const char src) {
|
||||
void strcpy(string &dest, const char src) {
|
||||
if(1 > dest.size) { strresize(dest, 1); }
|
||||
dest.s[0] = src;
|
||||
dest.s[1] = 0;
|
||||
}
|
||||
|
||||
void strcpy(substring &dest, const char *src) {
|
||||
void strcpy(string &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 strcpy(string &dest, string &src) { strcpy(dest, strptr(src)); }
|
||||
|
||||
//this differs from libc's strncpy in that it always
|
||||
//appends a null terminator to the end of a copied string
|
||||
void strncpy(substring &dest, const char *src, uint32 length) {
|
||||
void strncpy(string &dest, const char *src, uint32 length) {
|
||||
int srclen = strlen(src);
|
||||
//never copy more text than is in the string
|
||||
if(srclen > length)srclen = length;
|
||||
|
@ -105,38 +72,38 @@ int srclen = strlen(src);
|
|||
strncpy(dest.s, src, srclen);
|
||||
dest.s[srclen] = 0;
|
||||
}
|
||||
void strncpy(substring &dest, substring &src, uint32 length) { strncpy(dest, strptr(src), length); }
|
||||
void strncpy(string &dest, string &src, uint32 length) { strncpy(dest, strptr(src), length); }
|
||||
|
||||
void strset(substring &dest, uint pos, uint8 c) {
|
||||
void strset(string &dest, uint pos, uint8 c) {
|
||||
if(pos > dest.size) { strresize(dest, pos); }
|
||||
dest.s[pos] = c;
|
||||
}
|
||||
|
||||
void strcat(substring &dest, const char src) {
|
||||
void strcat(string &dest, const char src) {
|
||||
int length = strlen(dest);
|
||||
if(length + 1 > dest.size) { strresize(dest, length + 1); }
|
||||
dest.s[length] = src;
|
||||
dest.s[length + 1] = 0;
|
||||
}
|
||||
|
||||
void strcat(substring &dest, const char *src) {
|
||||
void strcat(string &dest, const char *src) {
|
||||
int srclen = strlen(src);
|
||||
int destlen = strlen(dest);
|
||||
if(srclen + destlen > dest.size) { strresize(dest, srclen + destlen); }
|
||||
strcat(dest.s, src);
|
||||
}
|
||||
void strcat(substring &dest, substring &src) { strcat(dest, strptr(src)); }
|
||||
void strcat(string &dest, string &src) { strcat(dest, strptr(src)); }
|
||||
|
||||
void strinsert(substring &dest, const char *src, uint pos) {
|
||||
static substring s;
|
||||
void strinsert(string &dest, const char *src, uint pos) {
|
||||
static string s;
|
||||
strcpy(s, strptr(dest) + pos);
|
||||
strset(dest, pos, 0);
|
||||
strcat(dest, src);
|
||||
strcat(dest, s);
|
||||
}
|
||||
void strinsert(substring &dest, substring &src, uint pos) { strinsert(dest, strptr(src), pos); }
|
||||
void strinsert(string &dest, string &src, uint pos) { strinsert(dest, strptr(src), pos); }
|
||||
|
||||
void strremove(substring &dest, uint start, uint length) {
|
||||
void strremove(string &dest, uint start, uint length) {
|
||||
int destlen;
|
||||
char *s;
|
||||
int i, sl = strlen(dest.s);
|
||||
|
@ -158,7 +125,7 @@ uint i = 0;
|
|||
}
|
||||
return str;
|
||||
}
|
||||
substring &strlower(substring &str) { strlower(strptr(str)); return str; }
|
||||
string &strlower(string &str) { strlower(strptr(str)); return str; }
|
||||
|
||||
char *strupper(char *str) {
|
||||
uint i = 0;
|
||||
|
@ -168,7 +135,7 @@ uint i = 0;
|
|||
}
|
||||
return str;
|
||||
}
|
||||
substring &strupper(substring &str) { strupper(strptr(str)); return str; }
|
||||
string &strupper(string &str) { strupper(strptr(str)); return str; }
|
||||
|
||||
bool strpos(const char *str, const char *key, uint &pos) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
|
@ -181,9 +148,9 @@ int ssl = strlen(str), ksl = strlen(key);
|
|||
}
|
||||
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); }
|
||||
bool strpos(string &str, const char *key, uint &pos) { return strpos(strptr(str), key, pos); }
|
||||
bool strpos(const char *str, string &key, uint &pos) { return strpos(str, strptr(key), pos); }
|
||||
bool strpos(string &str, string &key, uint &pos) { return strpos(strptr(str), strptr(key), pos); }
|
||||
|
||||
bool qstrpos(const char *str, const char *key, uint &pos) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
|
@ -204,9 +171,9 @@ int ssl = strlen(str), ksl = strlen(key);
|
|||
}
|
||||
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); }
|
||||
bool qstrpos(string &str, const char *key, uint &pos) { return qstrpos(strptr(str), key, pos); }
|
||||
bool qstrpos(const char *str, string &key, uint &pos) { return qstrpos(str, strptr(key), pos); }
|
||||
bool qstrpos(string &str, string &key, uint &pos) { return qstrpos(strptr(str), strptr(key), pos); }
|
||||
|
||||
void strtr(char *dest, const char *before, const char *after) {
|
||||
int sl = strlen(dest), bsl = strlen(before), asl = strlen(after);
|
||||
|
@ -220,14 +187,14 @@ int sl = strlen(dest), bsl = strlen(before), asl = strlen(after);
|
|||
}
|
||||
}
|
||||
}
|
||||
void strtr(substring &dest, const char *before, const char *after) { strtr(strptr(dest), before, after); }
|
||||
void strtr(string &dest, const char *before, const char *after) { strtr(strptr(dest), before, after); }
|
||||
|
||||
bool strbegin(const char *str, const char *key) {
|
||||
int i, ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return false;
|
||||
return (!memcmp(str, key, ksl));
|
||||
}
|
||||
bool strbegin(substring &str, const char *key) { return strbegin(strptr(str), key); }
|
||||
bool strbegin(string &str, const char *key) { return strbegin(strptr(str), key); }
|
||||
|
||||
bool stribegin(const char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
|
@ -243,14 +210,14 @@ int ssl = strlen(str), ksl = strlen(key);
|
|||
}
|
||||
return true;
|
||||
}
|
||||
bool stribegin(substring &str, const char *key) { return stribegin(strptr(str), key); }
|
||||
bool stribegin(string &str, const char *key) { return stribegin(strptr(str), key); }
|
||||
|
||||
bool strend(const char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return false;
|
||||
return (!memcmp(str + ssl - ksl, key, ksl));
|
||||
}
|
||||
bool strend(substring &str, const char *key) { return strend(strptr(str), key); }
|
||||
bool strend(string &str, const char *key) { return strend(strptr(str), key); }
|
||||
|
||||
bool striend(const char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
|
@ -266,7 +233,7 @@ int ssl = strlen(str), ksl = strlen(key);
|
|||
}
|
||||
return true;
|
||||
}
|
||||
bool striend(substring &str, const char *key) { return striend(strptr(str), key); }
|
||||
bool striend(string &str, const char *key) { return striend(strptr(str), key); }
|
||||
|
||||
void strltrim(char *str, const char *key) {
|
||||
int i, ssl = strlen(str), ksl = strlen(key);
|
||||
|
@ -276,7 +243,7 @@ int i, ssl = strlen(str), ksl = strlen(key);
|
|||
str[i] = 0;
|
||||
}
|
||||
}
|
||||
void strltrim(substring &str, const char *key) { strltrim(strptr(str), key); }
|
||||
void strltrim(string &str, const char *key) { strltrim(strptr(str), key); }
|
||||
|
||||
void striltrim(char *str, const char *key) {
|
||||
int i, ssl = strlen(str), ksl = strlen(key);
|
||||
|
@ -286,7 +253,7 @@ int i, ssl = strlen(str), ksl = strlen(key);
|
|||
str[i] = 0;
|
||||
}
|
||||
}
|
||||
void striltrim(substring &str, const char *key) { striltrim(strptr(str), key); }
|
||||
void striltrim(string &str, const char *key) { striltrim(strptr(str), key); }
|
||||
|
||||
void strrtrim(char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
|
@ -295,7 +262,7 @@ int ssl = strlen(str), ksl = strlen(key);
|
|||
str[ssl - ksl] = 0;
|
||||
}
|
||||
}
|
||||
void strrtrim(substring &str, const char *key) { strrtrim(strptr(str), key); }
|
||||
void strrtrim(string &str, const char *key) { strrtrim(strptr(str), key); }
|
||||
|
||||
void strirtrim(char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
|
@ -304,11 +271,11 @@ int ssl = strlen(str), ksl = strlen(key);
|
|||
str[ssl - ksl] = 0;
|
||||
}
|
||||
}
|
||||
void strirtrim(substring &str, const char *key) { strirtrim(strptr(str), key); }
|
||||
void strirtrim(string &str, const char *key) { strirtrim(strptr(str), key); }
|
||||
|
||||
//does not work on type char* because function increases string length
|
||||
void strquote(substring &str) {
|
||||
static substring t;
|
||||
void strquote(string &str) {
|
||||
static string t;
|
||||
strcpy(t, "\"");
|
||||
strcat(t, str);
|
||||
strcat(t, "\"");
|
||||
|
@ -333,7 +300,7 @@ int i, ssl = strlen(str);
|
|||
|
||||
return true;
|
||||
}
|
||||
bool strunquote(substring &str) { return strunquote(strptr(str)); }
|
||||
bool strunquote(string &str) { return strunquote(strptr(str)); }
|
||||
|
||||
uint strhex(const char *str) {
|
||||
uint r = 0, m = 0;
|
||||
|
@ -355,7 +322,7 @@ uint8 x;
|
|||
}
|
||||
return r;
|
||||
}
|
||||
uint strhex(substring &str) { return strhex(strptr(str)); }
|
||||
uint strhex(string &str) { return strhex(strptr(str)); }
|
||||
|
||||
int sstrhex(const char *str) {
|
||||
if(str[0] == '-') {
|
||||
|
@ -363,7 +330,7 @@ int sstrhex(const char *str) {
|
|||
}
|
||||
return strhex(str);
|
||||
}
|
||||
int sstrhex(substring &str) { return sstrhex(strptr(str)); }
|
||||
int sstrhex(string &str) { return sstrhex(strptr(str)); }
|
||||
|
||||
uint strdec(const char *str) {
|
||||
uint m = 1;
|
||||
|
@ -381,7 +348,7 @@ uint8 x;
|
|||
}
|
||||
return r;
|
||||
}
|
||||
uint strdec(substring &str) { return strdec(strptr(str)); }
|
||||
uint strdec(string &str) { return strdec(strptr(str)); }
|
||||
|
||||
int sstrdec(const char *str) {
|
||||
if(str[0] == '-') {
|
||||
|
@ -389,7 +356,7 @@ int sstrdec(const char *str) {
|
|||
}
|
||||
return strdec(str);
|
||||
}
|
||||
int sstrdec(substring &str) { return sstrdec(strptr(str)); }
|
||||
int sstrdec(string &str) { return sstrdec(strptr(str)); }
|
||||
|
||||
uint strbin(const char *str) {
|
||||
uint r = 0, m = 0;
|
||||
|
@ -407,7 +374,7 @@ uint8 x;
|
|||
}
|
||||
return r;
|
||||
}
|
||||
uint strbin(substring &str) { return strbin(strptr(str)); }
|
||||
uint strbin(string &str) { return strbin(strptr(str)); }
|
||||
|
||||
int sstrbin(const char *str) {
|
||||
if(str[0] == '-') {
|
||||
|
@ -415,7 +382,7 @@ int sstrbin(const char *str) {
|
|||
}
|
||||
return strbin(str);
|
||||
}
|
||||
int sstrbin(substring &str) { return sstrbin(strptr(str)); }
|
||||
int sstrbin(string &str) { return sstrbin(strptr(str)); }
|
||||
|
||||
char *utoa(char *str, uint num) {
|
||||
char *pstr = str;
|
||||
|
@ -433,7 +400,7 @@ uint mask = 1000000000;
|
|||
return pstr;
|
||||
}
|
||||
|
||||
substring &utoa(substring &str, uint num) {
|
||||
string &utoa(string &str, uint num) {
|
||||
if(str.size < 16) { strresize(str, 16); }
|
||||
utoa(strptr(str), num);
|
||||
return str;
|
||||
|
@ -450,7 +417,7 @@ char *pstr = str;
|
|||
return pstr;
|
||||
}
|
||||
|
||||
substring &itoa(substring &str, uint num) {
|
||||
string &itoa(string &str, uint num) {
|
||||
if(str.size < 16) { strresize(str, 16); }
|
||||
itoa(strptr(str), num);
|
||||
return str;
|
||||
|
@ -473,7 +440,7 @@ uint mask = 28, r;
|
|||
return pstr;
|
||||
}
|
||||
|
||||
substring &htoa(substring &str, uint num) {
|
||||
string &htoa(string &str, uint num) {
|
||||
if(str.size < 16) { strresize(str, 16); }
|
||||
htoa(strptr(str), num);
|
||||
return str;
|
||||
|
@ -496,7 +463,7 @@ uint mask = 28, r;
|
|||
return pstr;
|
||||
}
|
||||
|
||||
substring &uhtoa(substring &str, uint num) {
|
||||
string &uhtoa(string &str, uint num) {
|
||||
if(str.size < 16) { strresize(str, 16); }
|
||||
uhtoa(strptr(str), num);
|
||||
return str;
|
||||
|
@ -517,13 +484,13 @@ uint mask = 0x80000000;
|
|||
return pstr;
|
||||
}
|
||||
|
||||
substring &btoa(substring &str, uint num) {
|
||||
string &btoa(string &str, uint num) {
|
||||
if(str.size < 48) { strresize(str, 48); }
|
||||
btoa(strptr(str), num);
|
||||
return str;
|
||||
}
|
||||
|
||||
bool strfread(substring &str, const char *filename) {
|
||||
bool strfread(string &str, const char *filename) {
|
||||
strcpy(str, "");
|
||||
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
libstring : version 0.11b ~byuu (07/16/06)
|
||||
libstring : version 0.12 ~byuu (10/05/06)
|
||||
*/
|
||||
|
||||
#ifndef __LIBSTRING
|
||||
|
@ -8,188 +8,177 @@
|
|||
#include "libvector.h"
|
||||
|
||||
class string;
|
||||
class substring;
|
||||
typedef linear_vector<string> stringarray;
|
||||
|
||||
char chrlower(char c);
|
||||
char chrupper(char c);
|
||||
|
||||
uint count(string &str);
|
||||
uint count(stringarray &str);
|
||||
|
||||
void strresize(substring &str, uint size);
|
||||
void strresize(string &str, uint size);
|
||||
|
||||
char* strptr(substring &str);
|
||||
char* strptr(string &str);
|
||||
|
||||
uint strlen(substring &str);
|
||||
uint strlen(string &str);
|
||||
|
||||
int strcmp(substring &dest, const char *src);
|
||||
int strcmp(const char *dest, substring &src);
|
||||
int strcmp(substring &dest, substring &src);
|
||||
int strcmp(string &dest, const char *src);
|
||||
int strcmp(const char *dest, string &src);
|
||||
int strcmp(string &dest, string &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);
|
||||
int stricmp(string &dest, const char *src);
|
||||
int stricmp(const char *dest, string &src);
|
||||
int stricmp(string &dest, string &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 strmatch(string &dest, const char *src);
|
||||
bool strmatch(const char *dest, string &src);
|
||||
bool strmatch(string &dest, string &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);
|
||||
bool strimatch(string &dest, const char *src);
|
||||
bool strimatch(const char *dest, string &src);
|
||||
bool strimatch(string &dest, string &src);
|
||||
|
||||
void strcpy(substring &dest, const char *src);
|
||||
void strcpy(substring &dest, substring &src);
|
||||
void strncpy(substring &dest, const char *src, uint32 length);
|
||||
void strncpy(substring &dest, substring &src, uint32 length);
|
||||
void strcpy(string &dest, const char *src);
|
||||
void strcpy(string &dest, string &src);
|
||||
void strncpy(string &dest, const char *src, uint32 length);
|
||||
void strncpy(string &dest, string &src, uint32 length);
|
||||
|
||||
void strset(substring &dest, uint pos, uint8 c);
|
||||
void strset(string &dest, uint pos, uint8 c);
|
||||
|
||||
void strcat(substring &dest, const char src);
|
||||
void strcat(substring &dest, const char *src);
|
||||
void strcat(substring &dest, substring &src);
|
||||
void strcat(string &dest, const char src);
|
||||
void strcat(string &dest, const char *src);
|
||||
void strcat(string &dest, string &src);
|
||||
|
||||
void strinsert(substring &dest, const char *src, uint pos);
|
||||
void strinsert(substring &dest, substring &src, uint pos);
|
||||
void strinsert(string &dest, const char *src, uint pos);
|
||||
void strinsert(string &dest, string &src, uint pos);
|
||||
|
||||
void strremove(substring &dest, uint start, uint length = 0);
|
||||
void strremove(string &dest, uint start, uint length = 0);
|
||||
|
||||
char *strlower(char *str);
|
||||
substring &strlower(substring &str);
|
||||
string &strlower(string &str);
|
||||
|
||||
char *strupper(char *str);
|
||||
substring &strupper(substring &str);
|
||||
string &strupper(string &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 strpos(string &str, const char *key, uint &pos);
|
||||
bool strpos(const char *str, string &key, uint &pos);
|
||||
bool strpos(string &str, string &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);
|
||||
bool qstrpos(string &str, const char *key, uint &pos);
|
||||
bool qstrpos(const char *str, string &key, uint &pos);
|
||||
bool qstrpos(string &str, string &key, uint &pos);
|
||||
|
||||
void strtr(char *dest, const char *before, const char *after);
|
||||
void strtr(substring &dest, const char *before, const char *after);
|
||||
void strtr(string &dest, const char *before, const char *after);
|
||||
|
||||
bool strbegin(const char *str, const char *key);
|
||||
bool strbegin(substring &str, const char *key);
|
||||
bool strbegin(string &str, const char *key);
|
||||
|
||||
bool stribegin(const char *str, const char *key);
|
||||
bool stribegin(substring &str, const char *key);
|
||||
bool stribegin(string &str, const char *key);
|
||||
|
||||
bool strend(const char *str, const char *key);
|
||||
bool strend(substring &str, const char *key);
|
||||
bool strend(string &str, const char *key);
|
||||
|
||||
bool striend(const char *str, const char *key);
|
||||
bool striend(substring &str, const char *key);
|
||||
bool striend(string &str, const char *key);
|
||||
|
||||
void strltrim(char *str, const char *key);
|
||||
void strltrim(substring &str, const char *key);
|
||||
void strltrim(string &str, const char *key);
|
||||
|
||||
void striltrim(char *str, const char *key);
|
||||
void striltrim(substring &str, const char *key);
|
||||
void striltrim(string &str, const char *key);
|
||||
|
||||
void strrtrim(char *str, const char *key);
|
||||
void strrtrim(substring &str, const char *key);
|
||||
void strrtrim(string &str, const char *key);
|
||||
|
||||
void strirtrim(char *str, const char *key);
|
||||
void strirtrim(substring &str, const char *key);
|
||||
void strirtrim(string &str, const char *key);
|
||||
|
||||
void strquote(substring &str);
|
||||
void strquote(string &str);
|
||||
|
||||
bool strunquote(char *str);
|
||||
bool strunquote(substring &str);
|
||||
bool strunquote(string &str);
|
||||
|
||||
uint strhex(const char *str);
|
||||
uint strhex(substring &str);
|
||||
uint strhex(string &str);
|
||||
|
||||
int sstrhex(const char *str);
|
||||
int sstrhex(substring &str);
|
||||
int sstrhex(string &str);
|
||||
|
||||
uint strdec(const char *str);
|
||||
uint strdec(substring &str);
|
||||
uint strdec(string &str);
|
||||
|
||||
int sstrdec(const char *str);
|
||||
int sstrdec(substring &str);
|
||||
int sstrdec(string &str);
|
||||
|
||||
uint strbin(const char *str);
|
||||
uint strbin(substring &str);
|
||||
uint strbin(string &str);
|
||||
|
||||
int sstrbin(const char *str);
|
||||
int sstrbin(substring &str);
|
||||
int sstrbin(string &str);
|
||||
|
||||
char *utoa(char *str, uint num);
|
||||
substring &utoa(substring &str, uint num);
|
||||
string &utoa(string &str, uint num);
|
||||
|
||||
char *itoa(char *str, uint num);
|
||||
substring &itoa(substring &str, uint num);
|
||||
string &itoa(string &str, uint num);
|
||||
|
||||
char *htoa(char *str, uint num);
|
||||
substring &htoa(substring &str, uint num);
|
||||
string &htoa(string &str, uint num);
|
||||
|
||||
char *uhtoa(char *str, uint num);
|
||||
substring &uhtoa(substring &str, uint num);
|
||||
string &uhtoa(string &str, uint num);
|
||||
|
||||
char *btoa(char *str, uint num);
|
||||
substring &btoa(substring &str, uint num);
|
||||
string &btoa(string &str, uint num);
|
||||
|
||||
bool strfread(substring &str, const char *filename);
|
||||
bool strfread(string &str, const char *filename);
|
||||
|
||||
int strmath(const char *in_str);
|
||||
int strmath(substring &in_str);
|
||||
int strmath(string &in_str);
|
||||
|
||||
substring &replace(substring &str, const char *key, const char *token);
|
||||
substring &replace(substring &str, const char *key, substring &token);
|
||||
string &replace(string &str, const char *key, const char *token);
|
||||
string &replace(string &str, const char *key, string &token);
|
||||
|
||||
substring &qreplace(substring &str, const char *key, const char *token);
|
||||
substring &qreplace(substring &str, const char *key, substring &token);
|
||||
string &qreplace(string &str, const char *key, const char *token);
|
||||
string &qreplace(string &str, const char *key, string &token);
|
||||
|
||||
void split(string &dest, const char *key, const char *src);
|
||||
void split(string &dest, const char *key, substring &src);
|
||||
void split(stringarray &dest, const char *key, const char *src);
|
||||
void split(stringarray &dest, const char *key, string &src);
|
||||
|
||||
void qsplit(string &dest, const char *key, const char *src);
|
||||
void qsplit(string &dest, const char *key, substring &src);
|
||||
void qsplit(stringarray &dest, const char *key, const char *src);
|
||||
void qsplit(stringarray &dest, const char *key, string &src);
|
||||
|
||||
uint vsprintf(substring &str, const char *s, va_list args);
|
||||
uint sprintf(substring &str, const char *s, ...);
|
||||
uint vsprintf(string &str, const char *s, va_list args);
|
||||
uint sprintf(string &str, const char *s, ...);
|
||||
|
||||
class substring {
|
||||
class string {
|
||||
public:
|
||||
char *s;
|
||||
uint size;
|
||||
substring();
|
||||
~substring();
|
||||
};
|
||||
string() {
|
||||
size = 16;
|
||||
s = (char*)malloc(size + 1);
|
||||
*s = 0;
|
||||
}
|
||||
|
||||
/* 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<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
|
||||
~string() { SafeFree(s); }
|
||||
|
||||
inline operator substring&() { return str(0); }
|
||||
template<typename T> inline substring& operator[](const T i) { return str(i); }
|
||||
|
||||
string();
|
||||
~string();
|
||||
void operator=(const string &p) {
|
||||
SafeFree(s);
|
||||
size = p.size;
|
||||
s = (char*)malloc(size + 1);
|
||||
strcpy(s, p.s);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //__LIBSTRING
|
||||
|
|
|
@ -115,7 +115,7 @@ int strmath(const char *s) {
|
|||
}
|
||||
|
||||
#ifdef __LIBSTRING
|
||||
int strmath(substring &s) {
|
||||
int strmath(string &s) {
|
||||
return strmath(strptr(s));
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
substring &replace(substring &str, const char *key, const char *token) {
|
||||
string &replace(string &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;
|
||||
|
@ -28,9 +28,9 @@ char *data;
|
|||
free(data);
|
||||
return str;
|
||||
}
|
||||
substring &replace(substring &str, const char *key, substring &token) { return replace(str, key, strptr(token)); }
|
||||
string &replace(string &str, const char *key, string &token) { return replace(str, key, strptr(token)); }
|
||||
|
||||
substring &qreplace(substring &str, const char *key, const char *token) {
|
||||
string &qreplace(string &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;
|
||||
|
@ -83,4 +83,4 @@ char *data;
|
|||
free(data);
|
||||
return str;
|
||||
}
|
||||
substring &qreplace(substring &str, const char *key, substring &token) { return qreplace(str, key, strptr(token)); }
|
||||
string &qreplace(string &str, const char *key, string &token) { return qreplace(str, key, strptr(token)); }
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
void split(string &dest, const char *key, const char *src) {
|
||||
int ssl = strlen(src), ksl = strlen(key);
|
||||
uint lp = 0, split_count = 0;
|
||||
for(int32 i = 0; i <= ssl - ksl;) {
|
||||
void split(stringarray &dest, const char *key, const char *src) {
|
||||
dest.reset();
|
||||
|
||||
int ssl = strlen(src), ksl = strlen(key);
|
||||
int lp = 0, split_count = 0;
|
||||
for(int i = 0; i <= ssl - ksl;) {
|
||||
if(!memcmp(src + i, key, ksl)) {
|
||||
strncpy(dest[split_count++], src + lp, i - lp);
|
||||
i += ksl;
|
||||
|
@ -9,14 +11,15 @@ uint lp = 0, split_count = 0;
|
|||
} else i++;
|
||||
}
|
||||
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 split(stringarray &dest, const char *key, string &src) { split(dest, key, strptr(src)); }
|
||||
|
||||
void qsplit(string &dest, const char *key, const char *src) {
|
||||
int z, ssl = strlen(src), ksl = strlen(key);
|
||||
uint lp = 0, split_count = 0;
|
||||
for(int32 i = 0; i <= ssl - ksl;) {
|
||||
void qsplit(stringarray &dest, const char *key, const char *src) {
|
||||
dest.reset();
|
||||
|
||||
int z, ssl = strlen(src), ksl = strlen(key);
|
||||
int lp = 0, split_count = 0;
|
||||
for(int i = 0; i <= ssl - ksl;) {
|
||||
uint8 x = src[i];
|
||||
if(x == '\"' || x == '\'') {
|
||||
z = i++;
|
||||
|
@ -30,6 +33,5 @@ uint lp = 0, split_count = 0;
|
|||
} else i++;
|
||||
}
|
||||
strcpy(dest[split_count++], src + lp);
|
||||
dest.count = split_count;
|
||||
}
|
||||
void qsplit(string &dest, const char *key, substring &src) { qsplit(dest, key, strptr(src)); }
|
||||
void qsplit(stringarray &dest, const char *key, string &src) { qsplit(dest, key, strptr(src)); }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
uint sprintf(substring &str, const char *s, ...) {
|
||||
uint sprintf(string &str, const char *s, ...) {
|
||||
va_list args;
|
||||
va_start(args, s);
|
||||
uint length = vsprintf(str, s, args);
|
||||
|
@ -6,7 +6,14 @@ uint length = vsprintf(str, s, args);
|
|||
return length;
|
||||
}
|
||||
|
||||
uint vsprintf(substring &str, const char *s, va_list args) {
|
||||
uint vsprintf(string &str, const char *s, va_list args) {
|
||||
uint length = vsnprintf(0, 0, s, args);
|
||||
strresize(str, length + 1);
|
||||
return vsprintf(strptr(str), s, args);
|
||||
}
|
||||
|
||||
/*
|
||||
uint vsprintf(string &str, const char *s, va_list args) {
|
||||
bool leftalign;
|
||||
bool showbase;
|
||||
char positivesign;
|
||||
|
@ -200,3 +207,4 @@ uint i = 0;
|
|||
}
|
||||
return strlen(str);
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,430 @@
|
|||
/*
|
||||
libups : version 0.01 ~byuu, Nach (09/30/06)
|
||||
*/
|
||||
|
||||
#ifndef __LIBUPS
|
||||
#define __LIBUPS
|
||||
|
||||
template<typename FT>
|
||||
class UPSPatch {
|
||||
public:
|
||||
|
||||
enum {
|
||||
FLAG_INFO = 0x00000001,
|
||||
};
|
||||
|
||||
uint32 sig;
|
||||
uint16 version;
|
||||
uint32 format;
|
||||
uint32 flags;
|
||||
uint64 original_filesize;
|
||||
uint64 modified_filesize;
|
||||
|
||||
uint8 info_author[64 + 8];
|
||||
uint8 info_version[16 + 8];
|
||||
uint8 info_title[128 + 8];
|
||||
uint8 info_genre[32 + 8];
|
||||
uint8 info_language[32 + 8];
|
||||
uint8 info_date[8 + 8];
|
||||
uint8 info_website[256 + 8];
|
||||
uint8 info_description[1024 + 8];
|
||||
|
||||
FT fp;
|
||||
|
||||
uint32 xmlsize;
|
||||
uint32 original_crc32;
|
||||
uint32 modified_crc32;
|
||||
uint32 patch_crc32;
|
||||
|
||||
bool load();
|
||||
void save_header();
|
||||
void save_footer();
|
||||
void close();
|
||||
|
||||
UPSPatch();
|
||||
};
|
||||
|
||||
template<typename FTO, typename FTM, typename FTP>
|
||||
class UPS {
|
||||
public:
|
||||
|
||||
FTO original;
|
||||
FTM modified;
|
||||
UPSPatch<FTP> patch;
|
||||
|
||||
uint64 original_filesize;
|
||||
uint64 modified_filesize;
|
||||
uint64 largest_filesize;
|
||||
|
||||
uint32 original_crc32;
|
||||
uint32 modified_crc32;
|
||||
uint32 patch_crc32;
|
||||
|
||||
bool patch_eof;
|
||||
|
||||
uint ptr_read();
|
||||
void ptr_write(uint ptr);
|
||||
|
||||
void create(const char *original_filename,
|
||||
const char *modified_filename,
|
||||
const char *patch_filename);
|
||||
void create_linear();
|
||||
|
||||
bool apply(const char *original_filename,
|
||||
const char *modified_filename,
|
||||
const char *patch_filename);
|
||||
bool apply();
|
||||
void apply_linear();
|
||||
};
|
||||
|
||||
/*****
|
||||
* UPSPatch
|
||||
*****/
|
||||
|
||||
template<typename FT>
|
||||
bool UPSPatch<FT>::load() {
|
||||
fseek(fp, 0, file::seek_start);
|
||||
|
||||
patch_crc32 = 0xffffffff;
|
||||
while(ftell(fp) < fsize(fp) - 4) {
|
||||
patch_crc32 = crc32_adjust(patch_crc32, fgetc(fp));
|
||||
}
|
||||
patch_crc32 = ~patch_crc32;
|
||||
|
||||
fseek(fp, -16, file::seek_end);
|
||||
|
||||
xmlsize = fgetld(fp);
|
||||
original_crc32 = fgetld(fp);
|
||||
modified_crc32 = fgetld(fp);
|
||||
|
||||
if(patch_crc32 != fgetld(fp)) {
|
||||
fprintf(stdout, "error: patch checksum failure\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
fseek(fp, 0, file::seek_start);
|
||||
|
||||
sig = fgetld(fp);
|
||||
version = fgetlw(fp);
|
||||
format = fgetld(fp);
|
||||
flags = fgetld(fp);
|
||||
original_filesize = fgetlq(fp);
|
||||
modified_filesize = fgetlq(fp);
|
||||
|
||||
memset(info_author, 0, 64 + 8);
|
||||
memset(info_version, 0, 16 + 8);
|
||||
memset(info_title, 0, 128 + 8);
|
||||
memset(info_genre, 0, 32 + 8);
|
||||
memset(info_language, 0, 32 + 8);
|
||||
memset(info_date, 0, 8 + 8);
|
||||
memset(info_website, 0, 256 + 8);
|
||||
memset(info_description, 0, 1024 + 8);
|
||||
|
||||
if(flags & FLAG_INFO) {
|
||||
fread(fp, info_author, 64);
|
||||
fread(fp, info_version, 16);
|
||||
fread(fp, info_title, 128);
|
||||
fread(fp, info_genre, 32);
|
||||
fread(fp, info_language, 32);
|
||||
fread(fp, info_date, 8);
|
||||
fread(fp, info_website, 256);
|
||||
fread(fp, info_description, 1024);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename FT>
|
||||
void UPSPatch<FT>::save_header() {
|
||||
fputld(fp, sig);
|
||||
fputlw(fp, version);
|
||||
fputld(fp, format);
|
||||
fputld(fp, flags);
|
||||
fputlq(fp, original_filesize);
|
||||
fputlq(fp, modified_filesize);
|
||||
|
||||
if(flags & FLAG_INFO) {
|
||||
fwrite(fp, info_author, 64);
|
||||
fwrite(fp, info_version, 16);
|
||||
fwrite(fp, info_title, 128);
|
||||
fwrite(fp, info_genre, 32);
|
||||
fwrite(fp, info_language, 32);
|
||||
fwrite(fp, info_date, 8);
|
||||
fwrite(fp, info_website, 256);
|
||||
fwrite(fp, info_description, 1024);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename FT>
|
||||
void UPSPatch<FT>::save_footer() {
|
||||
fputld(fp, xmlsize);
|
||||
fputld(fp, original_crc32);
|
||||
fputld(fp, modified_crc32);
|
||||
|
||||
patch_crc32 = fcrc32(fp);
|
||||
fputld(fp, patch_crc32);
|
||||
}
|
||||
|
||||
template<typename FT>
|
||||
void UPSPatch<FT>::close() {
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
template<typename FT>
|
||||
UPSPatch<FT>::UPSPatch() {
|
||||
sig = 0x00737075; //'ups\0'
|
||||
version = 0x0001; //1.0
|
||||
format = 0x00000000; //linear
|
||||
flags = 0;
|
||||
original_filesize = 0;
|
||||
modified_filesize = 0;
|
||||
|
||||
memset(info_author, 0, 64 + 8);
|
||||
memset(info_version, 0, 16 + 8);
|
||||
memset(info_title, 0, 128 + 8);
|
||||
memset(info_genre, 0, 32 + 8);
|
||||
memset(info_language, 0, 32 + 8);
|
||||
memset(info_date, 0, 8 + 8);
|
||||
memset(info_website, 0, 256 + 8);
|
||||
memset(info_description, 0, 1024 + 8);
|
||||
|
||||
xmlsize = 0;
|
||||
original_crc32 = 0;
|
||||
modified_crc32 = 0;
|
||||
patch_crc32 = 0;
|
||||
}
|
||||
|
||||
/*****
|
||||
* UPS
|
||||
*****/
|
||||
|
||||
template<typename FTO, typename FTM, typename FTP>
|
||||
uint UPS<FTO, FTM, FTP>::ptr_read() {
|
||||
uint len = fgetc(patch.fp);
|
||||
if(len == 0xff) {
|
||||
patch_eof = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(len <= 0xf7) {
|
||||
return len;
|
||||
}
|
||||
|
||||
len -= 0xf8;
|
||||
uint ptr = 0;
|
||||
for(int i = 0; i < (len + 2); i++) {
|
||||
ptr |= fgetc(patch.fp) << (i << 3);
|
||||
}
|
||||
|
||||
ptr += 0xf8;
|
||||
if(len >= 1) { ptr += 0x10000; }
|
||||
if(len >= 2) { ptr += 0x1000000; }
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template<typename FTO, typename FTM, typename FTP>
|
||||
void UPS<FTO, FTM, FTP>::ptr_write(uint ptr) {
|
||||
if(ptr <= 0xf7) {
|
||||
fputc(patch.fp, ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
ptr -= 0xf8;
|
||||
if(ptr <= 0xffff) {
|
||||
fputc(patch.fp, 0xf8);
|
||||
fputc(patch.fp, ptr);
|
||||
fputc(patch.fp, ptr >> 8);
|
||||
return;
|
||||
}
|
||||
|
||||
ptr -= 0x10000;
|
||||
if(ptr <= 0xffffff) {
|
||||
fputc(patch.fp, 0xf9);
|
||||
fputc(patch.fp, ptr);
|
||||
fputc(patch.fp, ptr >> 8);
|
||||
fputc(patch.fp, ptr >> 16);
|
||||
return;
|
||||
}
|
||||
|
||||
ptr -= 0x1000000;
|
||||
fputc(patch.fp, 0xfa);
|
||||
fputc(patch.fp, ptr);
|
||||
fputc(patch.fp, ptr >> 8);
|
||||
fputc(patch.fp, ptr >> 16);
|
||||
fputc(patch.fp, ptr >> 24);
|
||||
}
|
||||
|
||||
template<typename FTO, typename FTM, typename FTP>
|
||||
void UPS<FTO, FTM, FTP>::create(
|
||||
const char *original_filename,
|
||||
const char *modified_filename,
|
||||
const char *patch_filename
|
||||
) {
|
||||
fopen(original, original_filename, file::mode_read);
|
||||
fopen(modified, modified_filename, file::mode_read);
|
||||
fopen(patch.fp, patch_filename, file::mode_writeread);
|
||||
|
||||
patch.original_filesize = original_filesize = fsize(original);
|
||||
patch.modified_filesize = modified_filesize = fsize(modified);
|
||||
largest_filesize = (original_filesize >= modified_filesize) ?
|
||||
original_filesize : modified_filesize;
|
||||
|
||||
patch.save_header();
|
||||
|
||||
switch(patch.format) {
|
||||
case 0x00000000: create_linear(); break;
|
||||
}
|
||||
|
||||
patch.original_crc32 = original_crc32 = fcrc32(original);
|
||||
patch.modified_crc32 = modified_crc32 = fcrc32(modified);
|
||||
|
||||
patch.save_footer();
|
||||
patch.close();
|
||||
}
|
||||
|
||||
template<typename FTO, typename FTM, typename FTP>
|
||||
void UPS<FTO, FTM, FTP>::create_linear() {
|
||||
fseek(original, 0, file::seek_start);
|
||||
fseek(modified, 0, file::seek_start);
|
||||
|
||||
uint last_ptr = 0, rle_count, last_out, rep_count;
|
||||
for(int i = 0; i < largest_filesize;) {
|
||||
uint8 r = fgetc(original) ^ fgetc(modified);
|
||||
i++;
|
||||
if(r == 0x00)continue;
|
||||
|
||||
//ptr
|
||||
ptr_write((i - 1) - last_ptr);
|
||||
|
||||
//data
|
||||
fputc(patch.fp, r);
|
||||
last_out = r;
|
||||
rep_count = 0;
|
||||
|
||||
do {
|
||||
r = fgetc(original) ^ fgetc(modified);
|
||||
i++;
|
||||
fputc(patch.fp, r);
|
||||
|
||||
if(last_out != r) {
|
||||
rep_count = 0;
|
||||
} else {
|
||||
if(++rep_count == (3 - 1)) {
|
||||
rle_count = 0;
|
||||
do {
|
||||
r = fgetc(original) ^ fgetc(modified);
|
||||
if(r != last_out || r == 0x00) { break; }
|
||||
rle_count++;
|
||||
} while(i < largest_filesize);
|
||||
|
||||
ptr_write(rle_count);
|
||||
if(i < largest_filesize) { fputc(patch.fp, r); }
|
||||
rep_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
last_out = r;
|
||||
if(r == 0x00) { break; }
|
||||
} while(i < largest_filesize);
|
||||
|
||||
last_ptr = i;
|
||||
}
|
||||
|
||||
fputc(patch.fp, 0xff);
|
||||
}
|
||||
|
||||
template<typename FTO, typename FTM, typename FTP>
|
||||
bool UPS<FTO, FTM, FTP>::apply(
|
||||
const char *original_filename,
|
||||
const char *modified_filename,
|
||||
const char *patch_filename
|
||||
) {
|
||||
fopen(original, original_filename, file::mode_read);
|
||||
fopen(modified, modified_filename, file::mode_writeread);
|
||||
fopen(patch.fp, patch_filename, file::mode_read);
|
||||
|
||||
return apply();
|
||||
}
|
||||
|
||||
template<typename FTO, typename FTM, typename FTP>
|
||||
bool UPS<FTO, FTM, FTP>::apply() {
|
||||
patch.load();
|
||||
patch_eof = false;
|
||||
|
||||
original_filesize = fsize(original);
|
||||
original_crc32 = fcrc32(original);
|
||||
|
||||
if(original_filesize == patch.original_filesize &&
|
||||
original_crc32 == patch.original_crc32) {
|
||||
modified_filesize = patch.modified_filesize;
|
||||
modified_crc32 = patch.modified_crc32;
|
||||
} else if(original_filesize == patch.modified_filesize &&
|
||||
original_crc32 == patch.modified_crc32) {
|
||||
modified_filesize = patch.original_filesize;
|
||||
modified_crc32 = patch.original_crc32;
|
||||
} else {
|
||||
fprintf(stdout, "error: input checksum failure\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
patch_crc32 = patch.patch_crc32;
|
||||
|
||||
apply_linear();
|
||||
patch.close();
|
||||
|
||||
if(modified_crc32 != fcrc32(modified)) {
|
||||
fprintf(stdout, "error: output checksum failure\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename FTO, typename FTM, typename FTP>
|
||||
void UPS<FTO, FTM, FTP>::apply_linear() {
|
||||
fseek(original, 0, file::seek_start);
|
||||
fseek(modified, 0, file::seek_start);
|
||||
for(uint i = 0; i < modified_filesize; i++) {
|
||||
fputc(modified, fgetc(original));
|
||||
}
|
||||
|
||||
fseek(original, 0, file::seek_start);
|
||||
fseek(modified, 0, file::seek_start);
|
||||
|
||||
uint rle_count, last_in, rep_count;
|
||||
while(!feof(patch.fp) && patch_eof == false && ftell(modified) < modified_filesize) {
|
||||
//ptr
|
||||
uint ptr = ptr_read();
|
||||
if(patch_eof == true) { break; }
|
||||
|
||||
//data
|
||||
fseek(original, ftell(original) + ptr, file::seek_start);
|
||||
fseek(modified, ftell(modified) + ptr, file::seek_start);
|
||||
|
||||
last_in = 0;
|
||||
rep_count = 0;
|
||||
|
||||
do {
|
||||
if(ftell(modified) >= modified_filesize) { break; }
|
||||
|
||||
uint8 r = fgetc(patch.fp);
|
||||
fputc(modified, r ^ fgetc(original));
|
||||
if(r != last_in) {
|
||||
rep_count = 0;
|
||||
} else {
|
||||
if(++rep_count == (3 - 1)) {
|
||||
rle_count = ptr_read();
|
||||
while(rle_count-- && ftell(modified) < modified_filesize) {
|
||||
fputc(modified, r ^ fgetc(original));
|
||||
}
|
||||
rep_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
last_in = r;
|
||||
if(r == 0x00) { break; }
|
||||
} while(!feof(patch.fp) && patch_eof == false && ftell(modified) < modified_filesize);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,103 +1,208 @@
|
|||
/*
|
||||
libvector : version 0.04a ~byuu (06/15/05)
|
||||
libvector : version 0.04 ~byuu (10/14/06)
|
||||
*/
|
||||
|
||||
/*****
|
||||
* Dynamic vector allocation template class library
|
||||
*
|
||||
* Implements auto-allocating, auto-resizing vectors that allow for
|
||||
* theoretically infinitely-sized arrays of objects.
|
||||
* Array indexes are not bounds checked, and reallocate to requested size when
|
||||
* accessing out of bounds.
|
||||
* These class are intended only for use with objects that require
|
||||
* construction. Significant overhead will result if used for raw memory
|
||||
* management. See libarray for a far more suitable raw memory vector array
|
||||
* class.
|
||||
*
|
||||
* Vectors also reserve an internal pool of memory that can be larger to
|
||||
* minimize memory allocation requests, but by default the pools only grow to
|
||||
* the requested vector index, as some objects may have substantial memory
|
||||
* requirements per object. The reserve() function may be used to allocate
|
||||
* memory in advance when possible.
|
||||
*
|
||||
* Two types of vectors are implemented. Their public interfaces are identical,
|
||||
* however they operate very differently internally.
|
||||
*
|
||||
* [linear_vector]
|
||||
* Works by allocating one giant heap of memory to contain all objects.
|
||||
* Constructors and destructors are called during resize() as needed.
|
||||
*
|
||||
* Pros:
|
||||
* - memory is allocated and objects are prebuilt in advance, so accessing
|
||||
* array objects will be very fast.
|
||||
* - all objects are in contigious memory, which helps for processor caching.
|
||||
* Cons:
|
||||
* - accessing object 15 will require objects 0-14 to be constructed first.
|
||||
* - resizing array may invalidate pointers to member objects inside classes
|
||||
* (eg object "this" pointer may change).
|
||||
*
|
||||
* Use when:
|
||||
* You need an array of objects that do not rely on pointers to member
|
||||
* variables, you have an idea of how many objects you will need, and
|
||||
* speed is critical.
|
||||
*
|
||||
* [ptr_vector]
|
||||
* Works by allocating a smaller heap of memory used as an array of pointers to
|
||||
* individual objects.
|
||||
*
|
||||
* Pros:
|
||||
* - accessing object 15 does not require objects 0-14 to be constructed first.
|
||||
* - resizing array will not invalidate pointers to member objects inside
|
||||
* classes.
|
||||
* Cons:
|
||||
* - memory for individual objects cannot be allocated in advance. Each "first"
|
||||
* access to an array object will require memory allocation and object
|
||||
* construction.
|
||||
* - objects are not guaranteed to be aligned in contigious memory, and
|
||||
* individual array indexes require two indirect memory lookups. Will affect
|
||||
* speed adversely when indexing very large arrays of objects.
|
||||
*
|
||||
* Use when:
|
||||
* Objects rely on pointers to member variables, you do not know how many
|
||||
* objects you will need in advance, you need to access vector elements out of
|
||||
* order and prefer not to have all previous objects constructed in advance,
|
||||
* and speed is less critical.
|
||||
*****/
|
||||
|
||||
#ifndef __LIBVECTOR
|
||||
#define __LIBVECTOR
|
||||
|
||||
template<typename T> class vector {
|
||||
private:
|
||||
T *array;
|
||||
int size, sizelimit;
|
||||
#include <new>
|
||||
|
||||
//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;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
template<typename T> class linear_vector {
|
||||
protected:
|
||||
T *pool;
|
||||
uint poolsize, objectsize;
|
||||
|
||||
public:
|
||||
void resize(int newsize) {
|
||||
newsize = findsize(newsize);
|
||||
uint size() { return objectsize; }
|
||||
uint capacity() { return poolsize; }
|
||||
|
||||
if(newsize > sizelimit)newsize = sizelimit;
|
||||
if(newsize == size)return;
|
||||
void reset() {
|
||||
for(uint i = 0; i < objectsize; i++) { pool[i].~T(); }
|
||||
|
||||
array = (T*)realloc(array, sizeof(T) * newsize);
|
||||
|
||||
if(newsize > size) {
|
||||
for(int i = size; i < newsize; i += sizeof(T)) {
|
||||
array[i] = (T)0;
|
||||
}
|
||||
if(pool) {
|
||||
free(pool);
|
||||
pool = 0;
|
||||
}
|
||||
|
||||
size = newsize;
|
||||
poolsize = 0;
|
||||
objectsize = 0;
|
||||
}
|
||||
|
||||
//used to free up memory used by vector, but without
|
||||
//actually destroying the vector itself
|
||||
void release() { resize(16); }
|
||||
void reserve(uint size) {
|
||||
if(size == poolsize)return;
|
||||
|
||||
T *handle(uint req_size = 0) {
|
||||
if(req_size > size)resize(req_size);
|
||||
return (T*)array;
|
||||
}
|
||||
|
||||
void read(uint start, T *source, uint length) {
|
||||
if(start + length > size)resize(start + length);
|
||||
memcpy(array + start, source, length);
|
||||
}
|
||||
|
||||
void read(T *source, uint length) { read(0, source, length); }
|
||||
|
||||
void write(uint start, T *dest, uint length) {
|
||||
if(start + length > size)resize(start + length);
|
||||
memcpy(dest, array + start, length);
|
||||
}
|
||||
|
||||
void write(T *dest, uint length) { write(0, dest, length); }
|
||||
|
||||
void clear() { memset(array, 0, size * sizeof(T)); }
|
||||
|
||||
vector(int newsize, int newsizelimit) {
|
||||
size = newsize;
|
||||
sizelimit = newsizelimit;
|
||||
array = (T*)malloc(size * sizeof(T));
|
||||
clear();
|
||||
}
|
||||
|
||||
vector(int newsize) {
|
||||
size = newsize;
|
||||
sizelimit = 1 << 24;
|
||||
array = (T*)malloc(size * sizeof(T));
|
||||
clear();
|
||||
}
|
||||
|
||||
vector() {
|
||||
size = 16;
|
||||
sizelimit = 1 << 24;
|
||||
array = (T*)malloc(size * sizeof(T));
|
||||
clear();
|
||||
}
|
||||
|
||||
~vector() {
|
||||
if(array) {
|
||||
free(array);
|
||||
array = 0;
|
||||
if(size < poolsize) {
|
||||
for(uint i = size; i < objectsize; i++) { pool[i].~T(); }
|
||||
objectsize = size;
|
||||
}
|
||||
|
||||
pool = static_cast<T*>(realloc(pool, sizeof(T) * size));
|
||||
poolsize = size;
|
||||
}
|
||||
|
||||
//operator T() { return array[0]; }
|
||||
void resize(int size) {
|
||||
if(size == objectsize)return;
|
||||
if(size > poolsize)reserve(size);
|
||||
|
||||
if(size < objectsize) {
|
||||
for(uint i = size; i < objectsize; i++) { pool[i].~T(); }
|
||||
} else {
|
||||
for(uint i = objectsize; i < size; i++) { new(pool + i) T; }
|
||||
}
|
||||
|
||||
objectsize = size;
|
||||
}
|
||||
|
||||
linear_vector() {
|
||||
pool = 0;
|
||||
poolsize = 0;
|
||||
objectsize = 0;
|
||||
}
|
||||
|
||||
~linear_vector() { reset(); }
|
||||
|
||||
inline operator T&() {
|
||||
if(objectsize == 0)resize(1);
|
||||
if(objectsize == 0)throw "vector[] out of bounds";
|
||||
return pool[0];
|
||||
}
|
||||
|
||||
inline T &operator[](int index) {
|
||||
if(index >= size)resize(index + 1);
|
||||
if(index > sizelimit)return array[size - 1];
|
||||
return array[index];
|
||||
if(index >= objectsize)resize(index + 1);
|
||||
if(index >= objectsize)throw "vector[] out of bounds";
|
||||
return pool[index];
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> class ptr_vector {
|
||||
protected:
|
||||
T **pool;
|
||||
uint poolsize, objectsize;
|
||||
|
||||
public:
|
||||
uint size() { return objectsize; }
|
||||
uint capacity() { return poolsize; }
|
||||
|
||||
void reset() {
|
||||
for(uint i = 0; i < objectsize; i++) { if(pool[i])delete pool[i]; }
|
||||
|
||||
if(pool) {
|
||||
free(pool);
|
||||
pool = 0;
|
||||
}
|
||||
|
||||
poolsize = 0;
|
||||
objectsize = 0;
|
||||
}
|
||||
|
||||
void reserve(uint size) {
|
||||
if(size == poolsize)return;
|
||||
|
||||
if(size < poolsize) {
|
||||
for(uint i = size; i < objectsize; i++) { if(pool[i])delete pool[i]; }
|
||||
objectsize = size;
|
||||
}
|
||||
|
||||
pool = static_cast<T**>(realloc(pool, sizeof(T*) * size));
|
||||
if(size > poolsize) {
|
||||
memset(pool + poolsize, 0, sizeof(T*) * (size - poolsize));
|
||||
}
|
||||
poolsize = size;
|
||||
}
|
||||
|
||||
void resize(int size) {
|
||||
if(size == objectsize)return;
|
||||
if(size > poolsize)reserve(size);
|
||||
|
||||
if(size < objectsize) {
|
||||
for(uint i = size; i < objectsize; i++) { if(pool[i])delete pool[i]; }
|
||||
}
|
||||
|
||||
objectsize = size;
|
||||
}
|
||||
|
||||
ptr_vector() {
|
||||
pool = 0;
|
||||
poolsize = 0;
|
||||
objectsize = 0;
|
||||
}
|
||||
|
||||
~ptr_vector() { reset(); }
|
||||
|
||||
inline operator T&() {
|
||||
if(objectsize == 0)resize(1);
|
||||
if(objectsize == 0)throw "vector[] out of bounds";
|
||||
if(!pool[0])pool[0] = new T;
|
||||
return *pool[0];
|
||||
}
|
||||
|
||||
inline T &operator[](int index) {
|
||||
if(index >= objectsize)resize(index + 1);
|
||||
if(index >= objectsize)throw "vector[] out of bounds";
|
||||
if(!pool[index])pool[index] = new T;
|
||||
return *pool[index];
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ void HideCursor() {
|
|||
}
|
||||
}
|
||||
|
||||
void ParseStyleParam(const char *style, string &output) {
|
||||
void ParseStyleParam(const char *style, stringarray &output) {
|
||||
string temp;
|
||||
strcpy(temp, style);
|
||||
strlower(temp);
|
||||
|
@ -95,7 +95,7 @@ libwin32_init::libwin32_init() {
|
|||
WNDCLASS wc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
|
||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
|
|
|
@ -32,7 +32,7 @@ uint GetScreenWidth();
|
|||
uint GetScreenHeight();
|
||||
void ShowCursor();
|
||||
void HideCursor();
|
||||
void ParseStyleParam(const char *style, string &output);
|
||||
void ParseStyleParam(const char *style, stringarray &output);
|
||||
|
||||
class Window;
|
||||
class Control;
|
||||
|
|
|
@ -11,7 +11,7 @@ bool Button::Create(Window *parent_window, const char *style, int x, int y, int
|
|||
state.width = width;
|
||||
state.height = height;
|
||||
|
||||
string part;
|
||||
stringarray part;
|
||||
ParseStyleParam(style, part);
|
||||
for(int i = 0; i < count(part); i++) {
|
||||
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
|
||||
|
|
|
@ -17,7 +17,7 @@ bool Checkbox::Create(Window *parent_window, const char *style, int x, int y, in
|
|||
state.width = width;
|
||||
state.height = height;
|
||||
|
||||
string part;
|
||||
stringarray part;
|
||||
ParseStyleParam(style, part);
|
||||
for(int i = 0; i < count(part); i++) {
|
||||
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
|
||||
|
|
|
@ -35,7 +35,7 @@ bool Combobox::Create(Window *parent_window, const char *style, int x, int y, in
|
|||
state.width = width;
|
||||
state.height = height;
|
||||
|
||||
string part;
|
||||
stringarray part;
|
||||
ParseStyleParam(style, part);
|
||||
for(int i = 0; i < count(part); i++) {
|
||||
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
|
||||
|
@ -53,7 +53,7 @@ string part;
|
|||
if(!hwnd)return false;
|
||||
|
||||
if(strmatch(text, "") == false) {
|
||||
string t;
|
||||
stringarray t;
|
||||
split(t, "|", text);
|
||||
for(int i = 0; i < ::count(t); i++) {
|
||||
AddItem(strptr(t[i]));
|
||||
|
|
|
@ -16,7 +16,7 @@ bool Editbox::Create(Window *parent_window, const char *style, int x, int y, int
|
|||
state.width = width;
|
||||
state.height = height;
|
||||
|
||||
string part;
|
||||
stringarray part;
|
||||
ParseStyleParam(style, part);
|
||||
for(int i = 0; i < count(part); i++) {
|
||||
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
* false - File was not selected
|
||||
*/
|
||||
bool FileOpen(Window *owner, const char *filter, const char *default_dir, char *output) {
|
||||
string dir;
|
||||
string dir, f;
|
||||
strcpy(dir, default_dir ? default_dir : "");
|
||||
replace(dir, "/", "\\");
|
||||
|
||||
string f, type, part;
|
||||
stringarray type, part;
|
||||
strcpy(f, "");
|
||||
split(type, "|", filter);
|
||||
for(int i = 0; i < count(type); i++) {
|
||||
|
|
|
@ -11,7 +11,7 @@ bool Groupbox::Create(Window *parent_window, const char *style, int x, int y, in
|
|||
state.width = width;
|
||||
state.height = height;
|
||||
|
||||
string part;
|
||||
stringarray part;
|
||||
ParseStyleParam(style, part);
|
||||
for(int i = 0; i < count(part); i++) {
|
||||
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
|
||||
|
|
|
@ -11,7 +11,7 @@ bool Label::Create(Window *parent_window, const char *style, int x, int y, int w
|
|||
state.width = width;
|
||||
state.height = height;
|
||||
|
||||
string part;
|
||||
stringarray part;
|
||||
ParseStyleParam(style, part);
|
||||
for(int i = 0; i < count(part); i++) {
|
||||
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
|
||||
|
|
|
@ -35,7 +35,7 @@ bool Listbox::Create(Window *parent_window, const char *style, int x, int y, int
|
|||
state.width = width;
|
||||
state.height = height;
|
||||
|
||||
string part;
|
||||
stringarray part;
|
||||
ParseStyleParam(style, part);
|
||||
for(int i = 0; i < count(part); i++) {
|
||||
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
|
||||
|
@ -53,7 +53,7 @@ string part;
|
|||
if(!hwnd)return false;
|
||||
|
||||
if(strmatch(text, "") == false) {
|
||||
string t;
|
||||
stringarray t;
|
||||
split(t, "|", text);
|
||||
for(int i = 0; i < ::count(t); i++) {
|
||||
AddItem(strptr(t[i]));
|
||||
|
|
|
@ -9,7 +9,7 @@ LVCOLUMN column;
|
|||
}
|
||||
|
||||
void Listview::AddItem(const char *text) {
|
||||
string t;
|
||||
stringarray t;
|
||||
split(t, "|", text);
|
||||
|
||||
LVITEM item;
|
||||
|
@ -26,7 +26,7 @@ uint pos = ListView_GetItemCount(hwnd);
|
|||
}
|
||||
|
||||
void Listview::SetItemText(uint id, const char *text) {
|
||||
string t;
|
||||
stringarray t;
|
||||
split(t, "|", text);
|
||||
|
||||
for(int i = 0; i < count(t); i++) {
|
||||
|
@ -72,7 +72,7 @@ bool Listview::Create(Window *parent_window, const char *style, int x, int y, in
|
|||
state.width = width;
|
||||
state.height = height;
|
||||
|
||||
string part;
|
||||
stringarray part;
|
||||
ParseStyleParam(style, part);
|
||||
for(int i = 0; i < count(part); i++) {
|
||||
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
|
||||
|
|
|
@ -17,7 +17,7 @@ bool Radiobox::Create(Window *parent_window, const char *style, int x, int y, in
|
|||
state.width = width;
|
||||
state.height = height;
|
||||
|
||||
string part;
|
||||
stringarray part;
|
||||
ParseStyleParam(style, part);
|
||||
for(int i = 0; i < count(part); i++) {
|
||||
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
|
||||
|
|
|
@ -25,7 +25,7 @@ bool Slider::Create(Window *parent_window, const char *style, int x, int y, int
|
|||
state.width = width;
|
||||
state.height = height;
|
||||
|
||||
string part;
|
||||
stringarray part;
|
||||
ParseStyleParam(style, part);
|
||||
for(int i = 0; i < count(part); i++) {
|
||||
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
|
||||
|
|
|
@ -72,7 +72,8 @@ bool result = false;
|
|||
|
||||
for(int i = 0; i < control_count; i++) {
|
||||
if(LOWORD(wparam) == list[i]->id) {
|
||||
if((list[i]->type == Control::COMBOBOX && HIWORD(wparam) == CBN_SELCHANGE) ||
|
||||
if((list[i]->type == Control::EDITBOX && HIWORD(wparam) == EN_CHANGE) ||
|
||||
(list[i]->type == Control::COMBOBOX && HIWORD(wparam) == CBN_SELCHANGE) ||
|
||||
(list[i]->type == Control::LISTBOX && HIWORD(wparam) == LBN_SELCHANGE)) {
|
||||
info.event_id = EVENT_CHANGED;
|
||||
info.control = list[i];
|
||||
|
@ -253,7 +254,7 @@ void Window::SetStyle(const char *style) {
|
|||
|
||||
if(parent)state.ws |= WS_CHILD;
|
||||
|
||||
string part;
|
||||
stringarray part;
|
||||
ParseStyleParam(style, part);
|
||||
for(int i = 0; i < count(part); i++) {
|
||||
if(strmatch(part[i], "visible")) state.ws |= WS_VISIBLE;
|
||||
|
@ -437,7 +438,7 @@ bool Window::Event(EventInfo &info) {
|
|||
Window::Window() {
|
||||
hwnd = 0;
|
||||
hwnd_resize = 0;
|
||||
backbrush = (HBRUSH)COLOR_WINDOW;
|
||||
backbrush = (HBRUSH)(COLOR_3DFACE + 1);
|
||||
control_count = 0;
|
||||
event_callback = 0;
|
||||
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
|
||||
FILE *fp, *fph, *fpt;
|
||||
|
||||
string data, line, part, subpart;
|
||||
string output_table, output_header, output_op;
|
||||
stringarray data, line, part, subpart;
|
||||
stringarray output_table, output_header, output_op;
|
||||
|
||||
struct _op_list {
|
||||
string name, arg;
|
||||
stringarray name, arg;
|
||||
} op_list[64];
|
||||
|
||||
int32 op_count, line_num;
|
||||
|
@ -143,7 +143,7 @@ char *buf = (char*)malloc(fsize + 1);
|
|||
|
||||
line_num = 0;
|
||||
while(line_num < count(line)) {
|
||||
while(strmatch(line[line_num], "") && line_num < count(line))line_num++;
|
||||
while(line_num < count(line) && strmatch(line[line_num], ""))line_num++;
|
||||
if(line_num >= count(line))break;
|
||||
|
||||
gen_header();
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
#include "libbase.h"
|
||||
#include "libstring.h"
|
||||
#include "libstring.cpp"
|
||||
|
||||
FILE *fp;
|
||||
|
||||
string data, line, part, subpart;
|
||||
string output_op;
|
||||
string data;
|
||||
stringarray line, part, subpart, output_op;
|
||||
|
||||
struct _op_list {
|
||||
string name, arg;
|
||||
struct OpList {
|
||||
stringarray name, arg;
|
||||
} op_list[64];
|
||||
|
||||
int32 op_count, line_num;
|
||||
|
@ -38,7 +37,7 @@ char t[4096];
|
|||
for(int l = 0; l < count(part); l++) {
|
||||
strcpy(op_list[z].arg[l], part[l]);
|
||||
}
|
||||
if(strend(line[i], " {"))break;
|
||||
if(strend(line[i], " {") == true)break;
|
||||
i++;
|
||||
}
|
||||
|
||||
|
@ -54,7 +53,7 @@ void gen_op() {
|
|||
int i = line_num, n, c;
|
||||
char t[4096];
|
||||
while(1) {
|
||||
if(strmatch(line[i], "}"))break;
|
||||
if(!strcmp(line[i], "}"))break;
|
||||
|
||||
//remove cycle number
|
||||
n = strdec(line[i]);
|
||||
|
@ -64,7 +63,7 @@ char t[4096];
|
|||
//strcat(output_op, t);
|
||||
|
||||
update_line(i);
|
||||
if(!strmatch(line[i], "")) {
|
||||
if(strcmp(line[i], "")) {
|
||||
strcat(output_op, " ");
|
||||
strcat(output_op, line[i]);
|
||||
strcat(output_op, "\r\n");
|
||||
|
@ -123,7 +122,7 @@ char *buf = (char*)malloc(fsize + 1);
|
|||
|
||||
line_num = 0;
|
||||
while(line_num < count(line)) {
|
||||
while(strmatch(line[line_num], "") && line_num < count(line))line_num++;
|
||||
while(line_num < count(line) && !strcmp(line[line_num], ""))line_num++;
|
||||
if(line_num >= count(line))break;
|
||||
|
||||
gen_begin();
|
||||
|
|
|
@ -10,31 +10,11 @@ void bMemBus::load_cart() {
|
|||
|
||||
switch(cartridge.info.mapper) {
|
||||
case Cartridge::PCB:
|
||||
if(!strcmp(cartridge.info.pcb, "SHVC-1A3B-01")) { cart_map_shvc_1a3b_13(); break; }
|
||||
if(!strcmp(cartridge.info.pcb, "SHVC-1A3B-11")) { cart_map_shvc_1a3b_13(); break; }
|
||||
if(!strcmp(cartridge.info.pcb, "SHVC-1A3B-12")) { cart_map_shvc_1a3b_13(); break; }
|
||||
if(!strcmp(cartridge.info.pcb, "SHVC-1A3B-13")) { cart_map_shvc_1a3b_13(); break; }
|
||||
|
||||
if(!strcmp(cartridge.info.pcb, "SHVC-1A3B-20")) { cart_map_shvc_1a3b_20(); break; }
|
||||
|
||||
if(!strcmp(cartridge.info.pcb, "SHVC-1A3M-10")) { cart_map_shvc_1a3m_30(); break; }
|
||||
if(!strcmp(cartridge.info.pcb, "SHVC-1A3M-20")) { cart_map_shvc_1a3m_30(); break; }
|
||||
if(!strcmp(cartridge.info.pcb, "SHVC-1A3M-21")) { cart_map_shvc_1a3m_30(); break; }
|
||||
if(!strcmp(cartridge.info.pcb, "SHVC-1A3M-30")) { cart_map_shvc_1a3m_30(); break; }
|
||||
|
||||
if(!strcmp(cartridge.info.pcb, "SHVC-1J3M-01")) { cart_map_shvc_1j3m_20(); break; }
|
||||
if(!strcmp(cartridge.info.pcb, "SHVC-1J3M-10")) { cart_map_shvc_1j3m_20(); break; }
|
||||
if(!strcmp(cartridge.info.pcb, "SHVC-1J3M-11")) { cart_map_shvc_1j3m_20(); break; }
|
||||
if(!strcmp(cartridge.info.pcb, "SHVC-1J3M-20")) { cart_map_shvc_1j3m_20(); break; }
|
||||
|
||||
if(!strcmp(cartridge.info.pcb, "BSC-1A5M-01")) { cart_map_bsc_1a5m_01(); break; }
|
||||
|
||||
if(!strcmp(cartridge.info.pcb, "BSC-1A7M-01")) { cart_map_bsc_1a7m_01(); break; }
|
||||
|
||||
if(!strcmp(cartridge.info.pcb, "BSC-1A7M-10")) { cart_map_bsc_1a7m_10(); break; }
|
||||
|
||||
dprintf("* PCB mapper not found");
|
||||
return;
|
||||
if(cart_map_pcb(cartridge.info.pcb) == false) {
|
||||
dprintf("* PCB mapper not found, cartridge load failed");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case Cartridge::LOROM:
|
||||
case Cartridge::HIROM:
|
||||
|
@ -43,7 +23,7 @@ void bMemBus::load_cart() {
|
|||
cart_map_generic(cartridge.info.mapper);
|
||||
break;
|
||||
default:
|
||||
dprintf("* generic mapper not found");
|
||||
dprintf("* Generic mapper not found, cartridge load failed");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -156,17 +136,11 @@ uint8 r;
|
|||
#endif
|
||||
|
||||
r = (this->*page_read[addr >> 8])(addr);
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::MEM_READ, addr, r);
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
void bMemBus::write(uint32 addr, uint8 data) {
|
||||
(this->*page_write[addr >> 8])(addr, data);
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::MEM_WRITE, addr, data);
|
||||
#endif
|
||||
}
|
||||
|
||||
void bMemBus::cart_map_reset() {
|
||||
|
|
|
@ -57,6 +57,7 @@ enum { TYPE_WRAM, TYPE_MMIO, TYPE_CART };
|
|||
|
||||
//load_cart() helper
|
||||
void calc_size(char *t, uint size) {
|
||||
size *= 8; //bytes -> bits
|
||||
if(size < 1024) { sprintf(t, "%dbit", size); return; }
|
||||
size /= 1024;
|
||||
if(size < 1024) { sprintf(t, "%dkbit", size); return; }
|
||||
|
|
|
@ -50,11 +50,11 @@ uint ram_size = cartridge.info.ram_size;
|
|||
//LoROM SRAM region
|
||||
//$[70-7f|f0-ff]:[0000-7fff]
|
||||
//Note: WRAM is remapped over $[7e-7f]:[0000-ffff]
|
||||
if(bank >= 0x70 && bank <= 0x7f && (addr & 0x8000) == 0x0000) {
|
||||
if(ram_size == 0)continue;
|
||||
|
||||
if(type == Cartridge::LOROM || !(bank & 0x80)) {
|
||||
if((bank & 0x7f) >= 0x70 && (bank & 0x7f) <= 0x7f && (addr & 0x8000) == 0x0000) {
|
||||
if(!(bank & 0x80) || type == Cartridge::LOROM) {
|
||||
//HiROM maps $[f0-ff]:[0000-7fff] to ROM
|
||||
if(ram_size == 0)continue;
|
||||
|
||||
addr = ((bank & 0x7f) - 0x70) * 0x8000 + (addr & 0x7fff);
|
||||
addr %= ram_size;
|
||||
page_handle[page] = cartridge.sram + addr;
|
||||
|
|
|
@ -11,6 +11,33 @@ uint mask = 1 << 31;
|
|||
}
|
||||
}
|
||||
|
||||
bool bMemBus::cart_map_pcb(const char *pcb) {
|
||||
if(!strcmp(pcb, "SHVC-1A3B-01")) { cart_map_shvc_1a3b_13(); return true; }
|
||||
if(!strcmp(pcb, "SHVC-1A3B-11")) { cart_map_shvc_1a3b_13(); return true; }
|
||||
if(!strcmp(pcb, "SHVC-1A3B-12")) { cart_map_shvc_1a3b_13(); return true; }
|
||||
if(!strcmp(pcb, "SHVC-1A3B-13")) { cart_map_shvc_1a3b_13(); return true; }
|
||||
|
||||
if(!strcmp(pcb, "SHVC-1A3B-20")) { cart_map_shvc_1a3b_20(); return true; }
|
||||
|
||||
if(!strcmp(pcb, "SHVC-1A3M-10")) { cart_map_shvc_1a3m_30(); return true; }
|
||||
if(!strcmp(pcb, "SHVC-1A3M-20")) { cart_map_shvc_1a3m_30(); return true; }
|
||||
if(!strcmp(pcb, "SHVC-1A3M-21")) { cart_map_shvc_1a3m_30(); return true; }
|
||||
if(!strcmp(pcb, "SHVC-1A3M-30")) { cart_map_shvc_1a3m_30(); return true; }
|
||||
|
||||
if(!strcmp(pcb, "SHVC-1J3M-01")) { cart_map_shvc_1j3m_20(); return true; }
|
||||
if(!strcmp(pcb, "SHVC-1J3M-10")) { cart_map_shvc_1j3m_20(); return true; }
|
||||
if(!strcmp(pcb, "SHVC-1J3M-11")) { cart_map_shvc_1j3m_20(); return true; }
|
||||
if(!strcmp(pcb, "SHVC-1J3M-20")) { cart_map_shvc_1j3m_20(); return true; }
|
||||
|
||||
if(!strcmp(pcb, "BSC-1A5M-01")) { cart_map_bsc_1a5m_01(); return true; }
|
||||
|
||||
if(!strcmp(pcb, "BSC-1A7M-01")) { cart_map_bsc_1a7m_01(); return true; }
|
||||
|
||||
if(!strcmp(pcb, "BSC-1A7M-10")) { cart_map_bsc_1a7m_10(); return true; }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void bMemBus::cart_map_range(
|
||||
uint mode,
|
||||
uint8 bank_lo, uint8 bank_hi,
|
||||
|
|
|
@ -15,6 +15,7 @@ enum {
|
|||
};
|
||||
|
||||
uint mirror(uint size, uint pos);
|
||||
bool cart_map_pcb(const char *pcb);
|
||||
void cart_map_range(uint mode, uint8 bank_lo, uint8 bank_hi, uint16 addr_lo, uint16 addr_hi, uint type, uint offset = 0);
|
||||
|
||||
#define mapper(name) void cart_map_##name()
|
||||
|
|
|
@ -41,7 +41,6 @@ mapper(shvc_1j3m_20) {
|
|||
map(LINEAR, 0xc0, 0xff, 0x0000, 0xffff, MAP_ROM);
|
||||
}
|
||||
|
||||
//unverified
|
||||
//BSC-1A5M-01
|
||||
//
|
||||
//$[c0-ef]:[0000-ffff] BSX
|
||||
|
@ -51,9 +50,9 @@ mapper(bsc_1a5m_01) {
|
|||
map(LINEAR, 0x70, 0x7f, 0x0000, 0x7fff, MAP_RAM);
|
||||
map(LINEAR, 0x80, 0x9f, 0x8000, 0xffff, MAP_ROM, 0x200000);
|
||||
map(LINEAR, 0xa0, 0xbf, 0x8000, 0xffff, MAP_ROM, 0x100000);
|
||||
map(LINEAR, 0xf0, 0xff, 0x0000, 0x7fff, MAP_RAM);
|
||||
}
|
||||
|
||||
//unverified
|
||||
//BSC-1A7M-01
|
||||
//
|
||||
//$[c0-ef]:[0000-ffff] BSX
|
||||
|
@ -63,9 +62,9 @@ mapper(bsc_1a7m_01) {
|
|||
map(LINEAR, 0x70, 0x7f, 0x0000, 0x7fff, MAP_RAM);
|
||||
map(LINEAR, 0x80, 0x9f, 0x8000, 0xffff, MAP_ROM, 0x000000);
|
||||
map(LINEAR, 0xa0, 0xbf, 0x8000, 0xffff, MAP_ROM, 0x100000);
|
||||
map(LINEAR, 0xf0, 0xff, 0x0000, 0x7fff, MAP_RAM);
|
||||
}
|
||||
|
||||
//unverified
|
||||
//BSC-1A7M-10
|
||||
//
|
||||
//$[c0-ef]:[0000-ffff] BSX
|
||||
|
@ -75,4 +74,5 @@ mapper(bsc_1a7m_10) {
|
|||
map(LINEAR, 0x70, 0x7f, 0x0000, 0x7fff, MAP_RAM);
|
||||
map(LINEAR, 0x80, 0x9f, 0x8000, 0xffff, MAP_ROM, 0x200000);
|
||||
map(LINEAR, 0xa0, 0xbf, 0x8000, 0xffff, MAP_ROM, 0x100000);
|
||||
map(LINEAR, 0xf0, 0xff, 0x0000, 0x7fff, MAP_RAM);
|
||||
}
|
||||
|
|
|
@ -82,24 +82,9 @@ MMIO mmio_unmapped;
|
|||
uint8 MMIO::mmio_read (uint16 addr) { return r_cpu->regs.mdr; }
|
||||
void MMIO::mmio_write(uint16 addr, uint8 data) {}
|
||||
|
||||
uint8 MemBus::calc_speed(uint32 addr, bool fast) {
|
||||
if((addr & 0xc00000) == 0x400000)return 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;
|
||||
}
|
||||
fastROM = fast;
|
||||
fastSpeed = fast ? 6 : 8;
|
||||
}
|
||||
|
||||
void MemBus::flush_mmio_mappers() {
|
||||
|
@ -117,12 +102,6 @@ bool MemBus::set_mmio_mapper(uint16 addr, MMIO *mapper) {
|
|||
}
|
||||
|
||||
MemBus::MemBus() {
|
||||
fastROM = false;
|
||||
set_speed(false);
|
||||
flush_mmio_mappers();
|
||||
|
||||
for(int 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;
|
||||
}
|
||||
|
|
|
@ -19,19 +19,21 @@ class MemBus : public Memory {
|
|||
public:
|
||||
MMIO *mmio[0x4000]; //mapped to $[00-3f|80-bf]:[2000-5fff]
|
||||
bool fastROM;
|
||||
uint fastSpeed;
|
||||
void flush_mmio_mappers();
|
||||
bool set_mmio_mapper(uint16 addr, MMIO *mapper);
|
||||
|
||||
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];
|
||||
uint8 calc_speed(uint32 addr, bool fast);
|
||||
public:
|
||||
uint8 speed(uint32 addr) { return speed_table[addr >> 9]; }
|
||||
inline uint8 speed(uint32 addr) {
|
||||
if(addr & 0x408000) {
|
||||
if(addr & 0x800000) { return fastSpeed; }
|
||||
return 8;
|
||||
}
|
||||
if((addr + 0x6000) & 0x4000) { return 8; }
|
||||
if((addr - 0x4000) & 0x7e00) { return 6; }
|
||||
return 12;
|
||||
}
|
||||
|
||||
void set_speed(bool fast);
|
||||
|
||||
virtual void load_cart() = 0;
|
||||
|
|
|
@ -36,6 +36,8 @@ void bPPU::scanline() {
|
|||
regs.mosaic_countdown--;
|
||||
}
|
||||
|
||||
//note: this should actually occur at V=225,HC=10.
|
||||
//this is a limitation of the scanline-based renderer.
|
||||
if(line.y == (!r_cpu->overscan() ? 225 : 240)) {
|
||||
if(regs.display_disabled == false) {
|
||||
//OAM address reset
|
||||
|
@ -62,10 +64,9 @@ void bPPU::render_scanline() {
|
|||
if(status.render_output == false)return;
|
||||
#endif
|
||||
|
||||
if(line.y > 0 && line.y < (r_cpu->overscan() ? 240 : 225)) {
|
||||
if(line.y >= 0 && line.y < (r_cpu->overscan() ? 240 : 225)) {
|
||||
if(status.render_output == true && line.y != 0) { render_line(); }
|
||||
render_line_oam_rto();
|
||||
if(status.render_output == false)return;
|
||||
render_line();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,59 +305,37 @@ void bPPU::reset() {
|
|||
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);
|
||||
if(addr >= 0x0200) { addr = 0x0200 | (addr & 31); }
|
||||
r = oam[addr];
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::OAM_READ, addr, r);
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
void bPPU::oam_write(uint16 addr, uint8 value) {
|
||||
if(addr >= 0x0200)addr = 0x0200 | (addr & 31);
|
||||
if(addr >= 0x0200) { addr = 0x0200 | (addr & 31); }
|
||||
oam[addr] = value;
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::OAM_WRITE, addr, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8 bPPU::cgram_read(uint16 addr) {
|
||||
uint8 r;
|
||||
addr &= 511;
|
||||
r = cgram[addr];
|
||||
if(addr & 1) {
|
||||
r &= 0x7f;
|
||||
}
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::CGRAM_READ, addr, r);
|
||||
#endif
|
||||
if(addr & 1) { r &= 0x7f; }
|
||||
return r;
|
||||
}
|
||||
|
||||
void bPPU::cgram_write(uint16 addr, uint8 value) {
|
||||
addr &= 511;
|
||||
if(addr & 1) {
|
||||
value &= 0x7f;
|
||||
}
|
||||
if(addr & 1) { value &= 0x7f; }
|
||||
cgram[addr] = value;
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::CGRAM_WRITE, addr, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
bPPU::bPPU() {
|
||||
|
@ -376,18 +355,12 @@ bPPU::bPPU() {
|
|||
}
|
||||
|
||||
for(int l = 0; l < 16; l++) {
|
||||
int r, g, b;
|
||||
double m = (double)l / 15.0;
|
||||
for(int i = 0; i < 32768; i++) {
|
||||
r = (i ) & 31;
|
||||
g = (i >> 5) & 31;
|
||||
b = (i >> 10) & 31;
|
||||
|
||||
r = minmax<0, 31>( (int)((double)r * m + 0.5) );
|
||||
g = minmax<0, 31>( (int)((double)g * m + 0.5) );
|
||||
b = minmax<0, 31>( (int)((double)b * m + 0.5) );
|
||||
|
||||
light_table[l][i] = (b << 10) | (g << 5) | (r);
|
||||
for(int i = 0; i < 32 * 32; i++) {
|
||||
int r = minmax<0, 31>((int)((double)((i) & 31) * m + 0.5));
|
||||
int g = minmax<0, 31>((int)((double)((i >> 5) & 31) * m + 0.5));
|
||||
if(i < 32)light_table_b[l][i] = (r << 10);
|
||||
light_table_gr[l][i] = (g << 5) | (r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -225,7 +225,8 @@ struct {
|
|||
|
||||
#include "bppu_render.h"
|
||||
|
||||
uint16 light_table[16][32768];
|
||||
uint16 light_table_b[16][32];
|
||||
uint16 light_table_gr[16][32 * 32];
|
||||
uint16 mosaic_table[16][4096];
|
||||
void render_line();
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ uint8 bPPU::vram_mmio_read(uint16 addr) {
|
|||
}
|
||||
|
||||
uint16 v = r_cpu->vcounter();
|
||||
uint16 hc = r_cpu->hcycles();
|
||||
uint16 hc = r_cpu->hclock();
|
||||
uint16 ls = (r_cpu->region_scanlines() >> 1) - 1;
|
||||
if(r_cpu->interlace() && !r_cpu->interlace_field())ls++;
|
||||
|
||||
|
@ -51,7 +51,7 @@ void bPPU::vram_mmio_write(uint16 addr, uint8 data) {
|
|||
}
|
||||
|
||||
uint16 v = r_cpu->vcounter();
|
||||
uint16 hc = r_cpu->hcycles();
|
||||
uint16 hc = r_cpu->hclock();
|
||||
if(v == 0) {
|
||||
if(hc <= 4) {
|
||||
vram_write(addr, data);
|
||||
|
@ -81,6 +81,10 @@ uint16 hc = r_cpu->hcycles();
|
|||
|
||||
//INIDISP
|
||||
void bPPU::mmio_w2100(uint8 value) {
|
||||
if(regs.display_disabled == true && !!(value & 0x80) == false) {
|
||||
regs.oam_addr = regs.oam_baseaddr << 1;
|
||||
}
|
||||
|
||||
regs.display_disabled = !!(value & 0x80);
|
||||
regs.display_brightness = value & 15;
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue