mirror of
https://github.com/ares-emulator/ares.git
synced 2026-11-09 09:19:42 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e308cf4275 | ||
|
|
192e53bb87 | ||
|
|
0ed9edfcdb | ||
|
|
764fe1974a | ||
|
|
a55d640459 | ||
|
|
6010bffe5d | ||
|
|
e492268025 | ||
|
|
a36c26c997 | ||
|
|
a3945e5772 | ||
|
|
6b6233b3af | ||
|
|
9f63cb1b99 | ||
|
|
49c39e0e4d | ||
|
|
7dec0b2a3c | ||
|
|
f288280ceb | ||
|
|
c6c5f4669c | ||
|
|
397b9c4505 | ||
|
|
7e2cfb6d40 | ||
|
|
970dcea0ac | ||
|
|
402c146a53 | ||
|
|
a471c150c9 | ||
|
|
ea38ea2537 | ||
|
|
09b326ae86 |
No files matched your search
Binary file not shown.
+31
-6
@@ -1,10 +1,35 @@
|
||||
bsnes Licensing Agreement:
|
||||
|
||||
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 source code are permitted without my permission. You must also abide
|
||||
by the terms of any additional source code licenses contained within my code.
|
||||
At present, this only includes the mode7 renderer, which was derived from the
|
||||
snes9x mode7 renderer.
|
||||
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
@@ -0,0 +1,108 @@
|
||||
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)
|
||||
@@ -0,0 +1,3 @@
|
||||
#include "../base.h"
|
||||
#include "iplrom.h"
|
||||
#include "dapu.cpp"
|
||||
@@ -0,0 +1,33 @@
|
||||
#include "apuregs.h"
|
||||
|
||||
class APU {
|
||||
public:
|
||||
APURegs regs;
|
||||
uint8 spcram[65536];
|
||||
static const uint8 iplrom[64];
|
||||
enum {
|
||||
FLAG_N = 0x80, FLAG_V = 0x40, FLAG_P = 0x20, FLAG_B = 0x10,
|
||||
FLAG_H = 0x08, FLAG_I = 0x04, FLAG_Z = 0x02, FLAG_C = 0x01
|
||||
};
|
||||
|
||||
virtual uint8 spcram_read (uint16 addr) = 0;
|
||||
virtual void spcram_write(uint16 addr, uint8 value) = 0;
|
||||
//$f4-$f7
|
||||
virtual uint8 port_read (uint8 port) = 0;
|
||||
virtual void port_write(uint8 port, uint8 value) = 0;
|
||||
|
||||
virtual uint8 *get_spcram_handle() { return spcram; }
|
||||
virtual void main() {}
|
||||
virtual void run() = 0;
|
||||
virtual uint32 clocks_executed() = 0;
|
||||
virtual void power() = 0;
|
||||
virtual void reset() = 0;
|
||||
|
||||
//debugging functions
|
||||
virtual bool in_opcode();
|
||||
void disassemble_opcode(char *output);
|
||||
inline uint16 __relb(int8 offset, int op_len);
|
||||
|
||||
APU() { memset(spcram, 0, 65536); }
|
||||
virtual ~APU() {}
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
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;
|
||||
};
|
||||
@@ -0,0 +1,60 @@
|
||||
#include "../../base.h"
|
||||
|
||||
#include "core/core.cpp"
|
||||
#include "memory/memory.cpp"
|
||||
#include "timing/timing.cpp"
|
||||
|
||||
void bAPU::run() {
|
||||
exec();
|
||||
}
|
||||
|
||||
void bAPU::power() {
|
||||
memset(spcram, 0x00, 65536);
|
||||
reset();
|
||||
}
|
||||
|
||||
void bAPU::reset() {
|
||||
regs.pc = 0xffc0;
|
||||
regs.a = 0x00;
|
||||
regs.x = 0x00;
|
||||
regs.y = 0x00;
|
||||
regs.sp = 0xef;
|
||||
regs.p = 0x02;
|
||||
|
||||
status.cycle_pos = 0;
|
||||
status.clocks_executed = 0;
|
||||
|
||||
//$f1
|
||||
status.iplrom_enabled = true;
|
||||
|
||||
t0.enabled = false;
|
||||
t1.enabled = false;
|
||||
t2.enabled = false;
|
||||
|
||||
t0.stage1_ticks = 0;
|
||||
t1.stage1_ticks = 0;
|
||||
t2.stage1_ticks = 0;
|
||||
|
||||
t0.stage2_ticks = 0;
|
||||
t1.stage2_ticks = 0;
|
||||
t2.stage2_ticks = 0;
|
||||
|
||||
t0.stage3_ticks = 0;
|
||||
t1.stage3_ticks = 0;
|
||||
t2.stage3_ticks = 0;
|
||||
}
|
||||
|
||||
bAPU::bAPU() {
|
||||
init_op_table();
|
||||
|
||||
t0.cycle_frequency = 128; //1.024mhz / 8khz = 128
|
||||
t1.cycle_frequency = 128; //1.024mhz / 8khz = 128
|
||||
t2.cycle_frequency = 16; //1.024mhz / 64khz = 16
|
||||
|
||||
//targets not initialized/changed upon reset
|
||||
t0.target = 0;
|
||||
t1.target = 0;
|
||||
t2.target = 0;
|
||||
}
|
||||
|
||||
bAPU::~bAPU() {}
|
||||
@@ -0,0 +1,24 @@
|
||||
class bAPU : public APU {
|
||||
public:
|
||||
#include "core/core.h"
|
||||
#include "memory/memory.h"
|
||||
#include "timing/timing.h"
|
||||
|
||||
struct {
|
||||
uint8 cycle_pos, opcode;
|
||||
uint32 clocks_executed;
|
||||
|
||||
//$f1
|
||||
bool iplrom_enabled;
|
||||
|
||||
//$f2
|
||||
uint8 dsp_addr;
|
||||
} status;
|
||||
|
||||
inline void run();
|
||||
inline void power();
|
||||
inline void reset();
|
||||
|
||||
bAPU();
|
||||
~bAPU();
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
#define CLASS_NAME "bAPU"
|
||||
#include "../../../lib/opgen.cpp"
|
||||
|
||||
int main() {
|
||||
fph = fopen("op.h", "wb");
|
||||
fpt = fopen("optable.cpp", "wb");
|
||||
|
||||
generate("op_mov.cpp", "op_mov.b");
|
||||
generate("op_pc.cpp", "op_pc.b");
|
||||
generate("op_read.cpp", "op_read.b");
|
||||
generate("op_rmw.cpp", "op_rmw.b");
|
||||
generate("op_misc.cpp", "op_misc.b");
|
||||
|
||||
fclose(fph);
|
||||
fclose(fpt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
cl /O2 /wd4996 bapugen.cpp
|
||||
@pause
|
||||
@del *.obj
|
||||
@@ -0,0 +1 @@
|
||||
@del *.exe
|
||||
@@ -0,0 +1,36 @@
|
||||
#include "opfn.cpp"
|
||||
#include "op_mov.cpp"
|
||||
#include "op_pc.cpp"
|
||||
#include "op_read.cpp"
|
||||
#include "op_rmw.cpp"
|
||||
#include "op_misc.cpp"
|
||||
|
||||
void bAPU::exec() {
|
||||
if(status.cycle_pos) {
|
||||
(this->*optbl[status.opcode])();
|
||||
add_cycles(1);
|
||||
if(status.cycle_pos == 0) {
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::APU_EXEC_OPCODE_END);
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//on first cycle?
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::APU_EXEC_OPCODE_BEGIN);
|
||||
#endif
|
||||
status.opcode = op_read();
|
||||
status.cycle_pos = 1;
|
||||
add_cycles(1);
|
||||
}
|
||||
|
||||
//only return true when we are on an opcode edge
|
||||
bool bAPU::in_opcode() {
|
||||
return (status.cycle_pos != 0);
|
||||
}
|
||||
|
||||
void bAPU::init_op_table() {
|
||||
#include "optable.cpp"
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
void (bAPU::*optbl[256])();
|
||||
uint16 dp, sp, rd, wr, bit, ya;
|
||||
inline uint8 op_adc (uint8 x, uint8 y);
|
||||
inline uint16 op_addw(uint16 x, uint16 y);
|
||||
inline uint8 op_and (uint8 x, uint8 y);
|
||||
inline uint8 op_cmp (uint8 x, uint8 y);
|
||||
inline uint16 op_cmpw(uint16 x, uint16 y);
|
||||
inline uint8 op_eor (uint8 x, uint8 y);
|
||||
inline uint8 op_inc (uint8 x);
|
||||
inline uint16 op_incw(uint16 x);
|
||||
inline uint8 op_dec (uint8 x);
|
||||
inline uint16 op_decw(uint16 x);
|
||||
inline uint8 op_or (uint8 x, uint8 y);
|
||||
inline uint8 op_sbc (uint8 x, uint8 y);
|
||||
inline uint16 op_subw(uint16 x, uint16 y);
|
||||
inline uint8 op_asl (uint8 x);
|
||||
inline uint8 op_lsr (uint8 x);
|
||||
inline uint8 op_rol (uint8 x);
|
||||
inline uint8 op_ror (uint8 x);
|
||||
|
||||
inline void exec();
|
||||
inline bool in_opcode();
|
||||
inline void init_op_table();
|
||||
|
||||
#include "op.h"
|
||||
@@ -0,0 +1,256 @@
|
||||
void op_mov_a_x();
|
||||
void op_mov_a_y();
|
||||
void op_mov_x_a();
|
||||
void op_mov_y_a();
|
||||
void op_mov_x_sp();
|
||||
void op_mov_sp_x();
|
||||
void op_mov_a_const();
|
||||
void op_mov_x_const();
|
||||
void op_mov_y_const();
|
||||
void op_mov_a_ix();
|
||||
void op_mov_a_ixinc();
|
||||
void op_mov_a_dp();
|
||||
void op_mov_x_dp();
|
||||
void op_mov_y_dp();
|
||||
void op_mov_a_dpx();
|
||||
void op_mov_x_dpy();
|
||||
void op_mov_y_dpx();
|
||||
void op_mov_a_addr();
|
||||
void op_mov_x_addr();
|
||||
void op_mov_y_addr();
|
||||
void op_mov_a_addrx();
|
||||
void op_mov_a_addry();
|
||||
void op_mov_a_idpx();
|
||||
void op_mov_a_idpy();
|
||||
void op_mov_dp_dp();
|
||||
void op_mov_dp_const();
|
||||
void op_mov_ix_a();
|
||||
void op_mov_ixinc_a();
|
||||
void op_mov_dp_a();
|
||||
void op_mov_dp_x();
|
||||
void op_mov_dp_y();
|
||||
void op_mov_dpx_a();
|
||||
void op_mov_dpy_x();
|
||||
void op_mov_dpx_y();
|
||||
void op_mov_addr_a();
|
||||
void op_mov_addr_x();
|
||||
void op_mov_addr_y();
|
||||
void op_mov_addrx_a();
|
||||
void op_mov_addry_a();
|
||||
void op_mov_idpx_a();
|
||||
void op_mov_idpy_a();
|
||||
void op_movw_ya_dp();
|
||||
void op_movw_dp_ya();
|
||||
void op_mov1_c_bit();
|
||||
void op_mov1_bit_c();
|
||||
void op_bra();
|
||||
void op_beq();
|
||||
void op_bne();
|
||||
void op_bcs();
|
||||
void op_bcc();
|
||||
void op_bvs();
|
||||
void op_bvc();
|
||||
void op_bmi();
|
||||
void op_bpl();
|
||||
void op_bbs0();
|
||||
void op_bbc0();
|
||||
void op_bbs1();
|
||||
void op_bbc1();
|
||||
void op_bbs2();
|
||||
void op_bbc2();
|
||||
void op_bbs3();
|
||||
void op_bbc3();
|
||||
void op_bbs4();
|
||||
void op_bbc4();
|
||||
void op_bbs5();
|
||||
void op_bbc5();
|
||||
void op_bbs6();
|
||||
void op_bbc6();
|
||||
void op_bbs7();
|
||||
void op_bbc7();
|
||||
void op_cbne_dp();
|
||||
void op_cbne_dpx();
|
||||
void op_dbnz_dp();
|
||||
void op_dbnz_y();
|
||||
void op_jmp_addr();
|
||||
void op_jmp_iaddrx();
|
||||
void op_call();
|
||||
void op_pcall();
|
||||
void op_tcall_0();
|
||||
void op_tcall_1();
|
||||
void op_tcall_2();
|
||||
void op_tcall_3();
|
||||
void op_tcall_4();
|
||||
void op_tcall_5();
|
||||
void op_tcall_6();
|
||||
void op_tcall_7();
|
||||
void op_tcall_8();
|
||||
void op_tcall_9();
|
||||
void op_tcall_10();
|
||||
void op_tcall_11();
|
||||
void op_tcall_12();
|
||||
void op_tcall_13();
|
||||
void op_tcall_14();
|
||||
void op_tcall_15();
|
||||
void op_brk();
|
||||
void op_ret();
|
||||
void op_reti();
|
||||
void op_adc_a_const();
|
||||
void op_and_a_const();
|
||||
void op_cmp_a_const();
|
||||
void op_cmp_x_const();
|
||||
void op_cmp_y_const();
|
||||
void op_eor_a_const();
|
||||
void op_or_a_const();
|
||||
void op_sbc_a_const();
|
||||
void op_adc_a_ix();
|
||||
void op_and_a_ix();
|
||||
void op_cmp_a_ix();
|
||||
void op_eor_a_ix();
|
||||
void op_or_a_ix();
|
||||
void op_sbc_a_ix();
|
||||
void op_adc_a_dp();
|
||||
void op_and_a_dp();
|
||||
void op_cmp_a_dp();
|
||||
void op_cmp_x_dp();
|
||||
void op_cmp_y_dp();
|
||||
void op_eor_a_dp();
|
||||
void op_or_a_dp();
|
||||
void op_sbc_a_dp();
|
||||
void op_adc_a_dpx();
|
||||
void op_and_a_dpx();
|
||||
void op_cmp_a_dpx();
|
||||
void op_eor_a_dpx();
|
||||
void op_or_a_dpx();
|
||||
void op_sbc_a_dpx();
|
||||
void op_adc_a_addr();
|
||||
void op_and_a_addr();
|
||||
void op_cmp_a_addr();
|
||||
void op_cmp_x_addr();
|
||||
void op_cmp_y_addr();
|
||||
void op_eor_a_addr();
|
||||
void op_or_a_addr();
|
||||
void op_sbc_a_addr();
|
||||
void op_adc_a_addrx();
|
||||
void op_adc_a_addry();
|
||||
void op_and_a_addrx();
|
||||
void op_and_a_addry();
|
||||
void op_cmp_a_addrx();
|
||||
void op_cmp_a_addry();
|
||||
void op_eor_a_addrx();
|
||||
void op_eor_a_addry();
|
||||
void op_or_a_addrx();
|
||||
void op_or_a_addry();
|
||||
void op_sbc_a_addrx();
|
||||
void op_sbc_a_addry();
|
||||
void op_adc_a_idpx();
|
||||
void op_and_a_idpx();
|
||||
void op_cmp_a_idpx();
|
||||
void op_eor_a_idpx();
|
||||
void op_or_a_idpx();
|
||||
void op_sbc_a_idpx();
|
||||
void op_adc_a_idpy();
|
||||
void op_and_a_idpy();
|
||||
void op_cmp_a_idpy();
|
||||
void op_eor_a_idpy();
|
||||
void op_or_a_idpy();
|
||||
void op_sbc_a_idpy();
|
||||
void op_adc_ix_iy();
|
||||
void op_and_ix_iy();
|
||||
void op_cmp_ix_iy();
|
||||
void op_eor_ix_iy();
|
||||
void op_or_ix_iy();
|
||||
void op_sbc_ix_iy();
|
||||
void op_adc_dp_dp();
|
||||
void op_and_dp_dp();
|
||||
void op_cmp_dp_dp();
|
||||
void op_eor_dp_dp();
|
||||
void op_or_dp_dp();
|
||||
void op_sbc_dp_dp();
|
||||
void op_adc_dp_const();
|
||||
void op_and_dp_const();
|
||||
void op_cmp_dp_const();
|
||||
void op_eor_dp_const();
|
||||
void op_or_dp_const();
|
||||
void op_sbc_dp_const();
|
||||
void op_addw_ya_dp();
|
||||
void op_cmpw_ya_dp();
|
||||
void op_subw_ya_dp();
|
||||
void op_and1_bit();
|
||||
void op_and1_notbit();
|
||||
void op_eor1_bit();
|
||||
void op_not1_bit();
|
||||
void op_or1_bit();
|
||||
void op_or1_notbit();
|
||||
void op_inc_a();
|
||||
void op_inc_x();
|
||||
void op_inc_y();
|
||||
void op_dec_a();
|
||||
void op_dec_x();
|
||||
void op_dec_y();
|
||||
void op_asl_a();
|
||||
void op_lsr_a();
|
||||
void op_rol_a();
|
||||
void op_ror_a();
|
||||
void op_inc_dp();
|
||||
void op_dec_dp();
|
||||
void op_asl_dp();
|
||||
void op_lsr_dp();
|
||||
void op_rol_dp();
|
||||
void op_ror_dp();
|
||||
void op_inc_dpx();
|
||||
void op_dec_dpx();
|
||||
void op_asl_dpx();
|
||||
void op_lsr_dpx();
|
||||
void op_rol_dpx();
|
||||
void op_ror_dpx();
|
||||
void op_inc_addr();
|
||||
void op_dec_addr();
|
||||
void op_asl_addr();
|
||||
void op_lsr_addr();
|
||||
void op_rol_addr();
|
||||
void op_ror_addr();
|
||||
void op_incw_dp();
|
||||
void op_decw_dp();
|
||||
void op_nop();
|
||||
void op_sleep();
|
||||
void op_stop();
|
||||
void op_xcn();
|
||||
void op_daa();
|
||||
void op_das();
|
||||
void op_clrc();
|
||||
void op_clrp();
|
||||
void op_setc();
|
||||
void op_setp();
|
||||
void op_clrv();
|
||||
void op_notc();
|
||||
void op_ei();
|
||||
void op_di();
|
||||
void op_set0_dp();
|
||||
void op_clr0_dp();
|
||||
void op_set1_dp();
|
||||
void op_clr1_dp();
|
||||
void op_set2_dp();
|
||||
void op_clr2_dp();
|
||||
void op_set3_dp();
|
||||
void op_clr3_dp();
|
||||
void op_set4_dp();
|
||||
void op_clr4_dp();
|
||||
void op_set5_dp();
|
||||
void op_clr5_dp();
|
||||
void op_set6_dp();
|
||||
void op_clr6_dp();
|
||||
void op_set7_dp();
|
||||
void op_clr7_dp();
|
||||
void op_tset_addr_a();
|
||||
void op_tclr_addr_a();
|
||||
void op_push_a();
|
||||
void op_push_x();
|
||||
void op_push_y();
|
||||
void op_push_p();
|
||||
void op_pop_a();
|
||||
void op_pop_x();
|
||||
void op_pop_y();
|
||||
void op_pop_p();
|
||||
void op_mul_ya();
|
||||
void op_div_ya_x();
|
||||
@@ -0,0 +1,164 @@
|
||||
nop(0x00) {
|
||||
1:
|
||||
}
|
||||
|
||||
sleep(0xef),
|
||||
stop(0xff) {
|
||||
1:
|
||||
2:regs.pc--;
|
||||
}
|
||||
|
||||
xcn(0x9f) {
|
||||
1:
|
||||
2:
|
||||
3:
|
||||
4:regs.a = (regs.a >> 4) | (regs.a << 4);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
daa(0xdf) {
|
||||
1:
|
||||
2:if(regs.p.c || (regs.a) > 0x99) {
|
||||
regs.a += 0x60;
|
||||
regs.p.c = 1;
|
||||
}
|
||||
if(regs.p.h || (regs.a & 15) > 0x09) {
|
||||
regs.a += 0x06;
|
||||
}
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
das(0xbe) {
|
||||
1:
|
||||
2:if(!regs.p.c || (regs.a) > 0x99) {
|
||||
regs.a -= 0x60;
|
||||
regs.p.c = 0;
|
||||
}
|
||||
if(!regs.p.h || (regs.a & 15) > 0x09) {
|
||||
regs.a -= 0x06;
|
||||
}
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
clrc(0x60, regs.p.c = 0),
|
||||
clrp(0x20, regs.p.p = 0),
|
||||
setc(0x80, regs.p.c = 1),
|
||||
setp(0x40, regs.p.p = 1) {
|
||||
1:$1;
|
||||
}
|
||||
|
||||
clrv(0xe0) {
|
||||
1:regs.p.v = 0;
|
||||
regs.p.h = 0;
|
||||
}
|
||||
|
||||
notc(0xed) {
|
||||
1:
|
||||
2:regs.p.c ^= 1;
|
||||
}
|
||||
|
||||
ei(0xa0, 1),
|
||||
di(0xc0, 0) {
|
||||
1:
|
||||
2:regs.p.i = $1;
|
||||
}
|
||||
|
||||
set0_dp(0x02, rd |= 0x01),
|
||||
clr0_dp(0x12, rd &= ~0x01),
|
||||
set1_dp(0x22, rd |= 0x02),
|
||||
clr1_dp(0x32, rd &= ~0x02),
|
||||
set2_dp(0x42, rd |= 0x04),
|
||||
clr2_dp(0x52, rd &= ~0x04),
|
||||
set3_dp(0x62, rd |= 0x08),
|
||||
clr3_dp(0x72, rd &= ~0x08),
|
||||
set4_dp(0x82, rd |= 0x10),
|
||||
clr4_dp(0x92, rd &= ~0x10),
|
||||
set5_dp(0xa2, rd |= 0x20),
|
||||
clr5_dp(0xb2, rd &= ~0x20),
|
||||
set6_dp(0xc2, rd |= 0x40),
|
||||
clr6_dp(0xd2, rd &= ~0x40),
|
||||
set7_dp(0xe2, rd |= 0x80),
|
||||
clr7_dp(0xf2, rd &= ~0x80) {
|
||||
1:dp = op_read();
|
||||
2:rd = op_read(OPMODE_DP, dp);
|
||||
3:$1;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
}
|
||||
|
||||
tset_addr_a(0x0e, |=),
|
||||
tclr_addr_a(0x4e, &=~) {
|
||||
1:dp = op_read();
|
||||
2:dp |= op_read() << 8;
|
||||
3:rd = op_read(OPMODE_ADDR, dp);
|
||||
4:regs.p.n = !!((rd & regs.a) & 0x80);
|
||||
regs.p.z = ((rd & regs.a) == 0);
|
||||
rd $1 regs.a;
|
||||
5:op_write(OPMODE_ADDR, dp, rd);
|
||||
}
|
||||
|
||||
push_a(0x2d, a),
|
||||
push_x(0x4d, x),
|
||||
push_y(0x6d, y),
|
||||
push_p(0x0d, p) {
|
||||
1:
|
||||
2:
|
||||
3:stack_write(regs.$1);
|
||||
}
|
||||
|
||||
pop_a(0xae, a),
|
||||
pop_x(0xce, x),
|
||||
pop_y(0xee, y),
|
||||
pop_p(0x8e, p) {
|
||||
1:
|
||||
2:
|
||||
3:regs.$1 = stack_read();
|
||||
}
|
||||
|
||||
mul_ya(0xcf) {
|
||||
1:
|
||||
2:
|
||||
3:
|
||||
4:
|
||||
5:
|
||||
6:
|
||||
7:
|
||||
8:ya = regs.y * regs.a;
|
||||
regs.a = ya;
|
||||
regs.y = ya >> 8;
|
||||
//result is set based on y (high-byte) only
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
}
|
||||
|
||||
div_ya_x(0x9e) {
|
||||
1:
|
||||
2:
|
||||
3:
|
||||
4:
|
||||
5:
|
||||
6:
|
||||
7:
|
||||
8:
|
||||
9:
|
||||
10:
|
||||
11:ya = regs.ya;
|
||||
//overflow set if quotient >= 256
|
||||
regs.p.v = !!(regs.y >= regs.x);
|
||||
regs.p.h = !!((regs.y & 15) >= (regs.x & 15));
|
||||
if(regs.y < (regs.x << 1)) {
|
||||
//if quotient is <= 511 (will fit into 9-bit result)
|
||||
regs.a = ya / regs.x;
|
||||
regs.y = ya % regs.x;
|
||||
} else {
|
||||
//otherwise, the quotient won't fit into regs.p.v + regs.a
|
||||
//this emulates the odd behavior of the SPC700 in this case
|
||||
regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x);
|
||||
regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x);
|
||||
}
|
||||
//result is set based on a (quotient) only
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
@@ -0,0 +1,643 @@
|
||||
void bAPU::op_nop() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_sleep() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
regs.pc--;
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_stop() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
regs.pc--;
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_xcn() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
regs.a = (regs.a >> 4) | (regs.a << 4);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_daa() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
if(regs.p.c || (regs.a) > 0x99) {
|
||||
regs.a += 0x60;
|
||||
regs.p.c = 1;
|
||||
}
|
||||
if(regs.p.h || (regs.a & 15) > 0x09) {
|
||||
regs.a += 0x06;
|
||||
}
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_das() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
if(!regs.p.c || (regs.a) > 0x99) {
|
||||
regs.a -= 0x60;
|
||||
regs.p.c = 0;
|
||||
}
|
||||
if(!regs.p.h || (regs.a & 15) > 0x09) {
|
||||
regs.a -= 0x06;
|
||||
}
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clrc() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.p.c = 0;
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clrp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.p.p = 0;
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_setc() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.p.c = 1;
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_setp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.p.p = 1;
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clrv() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.p.v = 0;
|
||||
regs.p.h = 0;
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_notc() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
regs.p.c ^= 1;
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_ei() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
regs.p.i = 1;
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_di() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
regs.p.i = 0;
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_set0_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= 0x01;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clr0_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd &= ~0x01;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_set1_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= 0x02;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clr1_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd &= ~0x02;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_set2_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= 0x04;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clr2_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd &= ~0x04;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_set3_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= 0x08;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clr3_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd &= ~0x08;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_set4_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= 0x10;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clr4_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd &= ~0x10;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_set5_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= 0x20;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clr5_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd &= ~0x20;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_set6_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= 0x40;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clr6_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd &= ~0x40;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_set7_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= 0x80;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clr7_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd &= ~0x80;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_tset_addr_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
} break;
|
||||
case 4: {
|
||||
regs.p.n = !!((rd & regs.a) & 0x80);
|
||||
regs.p.z = ((rd & regs.a) == 0);
|
||||
rd |= regs.a;
|
||||
} break;
|
||||
case 5: {
|
||||
op_write(OPMODE_ADDR, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_tclr_addr_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
} break;
|
||||
case 4: {
|
||||
regs.p.n = !!((rd & regs.a) & 0x80);
|
||||
regs.p.z = ((rd & regs.a) == 0);
|
||||
rd &=~ regs.a;
|
||||
} break;
|
||||
case 5: {
|
||||
op_write(OPMODE_ADDR, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_push_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
stack_write(regs.a);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_push_x() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
stack_write(regs.x);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_push_y() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
stack_write(regs.y);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_push_p() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
stack_write(regs.p);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_pop_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
regs.a = stack_read();
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_pop_x() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
regs.x = stack_read();
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_pop_y() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
regs.y = stack_read();
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_pop_p() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
regs.p = stack_read();
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mul_ya() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
} break;
|
||||
case 5: {
|
||||
} break;
|
||||
case 6: {
|
||||
} break;
|
||||
case 7: {
|
||||
} break;
|
||||
case 8: {
|
||||
ya = regs.y * regs.a;
|
||||
regs.a = ya;
|
||||
regs.y = ya >> 8;
|
||||
//result is set based on y (high-byte) only
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_div_ya_x() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
} break;
|
||||
case 5: {
|
||||
} break;
|
||||
case 6: {
|
||||
} break;
|
||||
case 7: {
|
||||
} break;
|
||||
case 8: {
|
||||
} break;
|
||||
case 9: {
|
||||
} break;
|
||||
case 10: {
|
||||
} break;
|
||||
case 11: {
|
||||
ya = regs.ya;
|
||||
//overflow set if quotient >= 256
|
||||
regs.p.v = !!(regs.y >= regs.x);
|
||||
regs.p.h = !!((regs.y & 15) >= (regs.x & 15));
|
||||
if(regs.y < (regs.x << 1)) {
|
||||
//if quotient is <= 511 (will fit into 9-bit result)
|
||||
regs.a = ya / regs.x;
|
||||
regs.y = ya % regs.x;
|
||||
} else {
|
||||
//otherwise, the quotient won't fit into regs.p.v + regs.a
|
||||
//this emulates the odd behavior of the SPC700 in this case
|
||||
regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x);
|
||||
regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x);
|
||||
}
|
||||
//result is set based on a (quotient) only
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
mov_a_x(0x7d, a, x),
|
||||
mov_a_y(0xdd, a, y),
|
||||
mov_x_a(0x5d, x, a),
|
||||
mov_y_a(0xfd, y, a),
|
||||
mov_x_sp(0x9d, x, sp) {
|
||||
1:regs.$1 = regs.$2;
|
||||
regs.p.n = !!(regs.$1 & 0x80);
|
||||
regs.p.z = (regs.$1 == 0);
|
||||
}
|
||||
|
||||
mov_sp_x(0xbd, sp, x) {
|
||||
1:regs.$1 = regs.$2;
|
||||
}
|
||||
|
||||
mov_a_const(0xe8, a),
|
||||
mov_x_const(0xcd, x),
|
||||
mov_y_const(0x8d, y) {
|
||||
1:regs.$1 = op_read();
|
||||
regs.p.n = !!(regs.$1 & 0x80);
|
||||
regs.p.z = (regs.$1 == 0);
|
||||
}
|
||||
|
||||
mov_a_ix(0xe6) {
|
||||
1:
|
||||
2:regs.a = op_read(OPMODE_DP, regs.x);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
mov_a_ixinc(0xbf) {
|
||||
1:
|
||||
2:
|
||||
3:regs.a = op_read(OPMODE_DP, regs.x++);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
mov_a_dp(0xe4, a),
|
||||
mov_x_dp(0xf8, x),
|
||||
mov_y_dp(0xeb, y) {
|
||||
1:sp = op_read();
|
||||
2:regs.$1 = op_read(OPMODE_DP, sp);
|
||||
regs.p.n = !!(regs.$1 & 0x80);
|
||||
regs.p.z = (regs.$1 == 0);
|
||||
}
|
||||
|
||||
mov_a_dpx(0xf4, a, x),
|
||||
mov_x_dpy(0xf9, x, y),
|
||||
mov_y_dpx(0xfb, y, x) {
|
||||
1:sp = op_read();
|
||||
2:
|
||||
3:regs.$1 = op_read(OPMODE_DP, sp + regs.$2);
|
||||
regs.p.n = !!(regs.$1 & 0x80);
|
||||
regs.p.z = (regs.$1 == 0);
|
||||
}
|
||||
|
||||
mov_a_addr(0xe5, a),
|
||||
mov_x_addr(0xe9, x),
|
||||
mov_y_addr(0xec, y) {
|
||||
1:sp = op_read();
|
||||
2:sp |= op_read() << 8;
|
||||
3:regs.$1 = op_read(OPMODE_ADDR, sp);
|
||||
regs.p.n = !!(regs.$1 & 0x80);
|
||||
regs.p.z = (regs.$1 == 0);
|
||||
}
|
||||
|
||||
mov_a_addrx(0xf5, x),
|
||||
mov_a_addry(0xf6, y) {
|
||||
1:sp = op_read();
|
||||
2:sp |= op_read() << 8;
|
||||
3:
|
||||
4:regs.a = op_read(OPMODE_ADDR, sp + regs.$1);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
mov_a_idpx(0xe7) {
|
||||
1:dp = op_read() + regs.x;
|
||||
2:
|
||||
3:sp = op_read(OPMODE_DP, dp);
|
||||
4:sp |= op_read(OPMODE_DP, dp + 1) << 8;
|
||||
5:regs.a = op_read(OPMODE_ADDR, sp);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
mov_a_idpy(0xf7) {
|
||||
1:dp = op_read();
|
||||
2:
|
||||
3:sp = op_read(OPMODE_DP, dp);
|
||||
4:sp |= op_read(OPMODE_DP, dp + 1) << 8;
|
||||
5:regs.a = op_read(OPMODE_ADDR, sp + regs.y);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
mov_dp_dp(0xfa) {
|
||||
1:sp = op_read();
|
||||
2:dp = op_read();
|
||||
3:rd = op_read(OPMODE_DP, sp);
|
||||
4:op_write(OPMODE_DP, dp, rd);
|
||||
}
|
||||
|
||||
mov_dp_const(0x8f) {
|
||||
1:rd = op_read();
|
||||
2:dp = op_read();
|
||||
3:
|
||||
4:op_write(OPMODE_DP, dp, rd);
|
||||
}
|
||||
|
||||
mov_ix_a(0xc6) {
|
||||
1:
|
||||
2:
|
||||
3:op_write(OPMODE_DP, regs.x, regs.a);
|
||||
}
|
||||
|
||||
mov_ixinc_a(0xaf) {
|
||||
1:
|
||||
2:
|
||||
3:op_write(OPMODE_DP, regs.x++, regs.a);
|
||||
}
|
||||
|
||||
mov_dp_a(0xc4, a),
|
||||
mov_dp_x(0xd8, x),
|
||||
mov_dp_y(0xcb, y) {
|
||||
1:dp = op_read();
|
||||
2:
|
||||
3:op_write(OPMODE_DP, dp, regs.$1);
|
||||
}
|
||||
|
||||
mov_dpx_a(0xd4, x, a),
|
||||
mov_dpy_x(0xd9, y, x),
|
||||
mov_dpx_y(0xdb, x, y) {
|
||||
1:dp = op_read();
|
||||
2:
|
||||
3:
|
||||
4:op_write(OPMODE_DP, dp + regs.$1, regs.$2);
|
||||
}
|
||||
|
||||
mov_addr_a(0xc5, a),
|
||||
mov_addr_x(0xc9, x),
|
||||
mov_addr_y(0xcc, y) {
|
||||
1:dp = op_read();
|
||||
2:dp |= op_read() << 8;
|
||||
3:
|
||||
4:op_write(OPMODE_ADDR, dp, regs.$1);
|
||||
}
|
||||
|
||||
mov_addrx_a(0xd5, x),
|
||||
mov_addry_a(0xd6, y) {
|
||||
1:dp = op_read();
|
||||
2:dp |= op_read() << 8;
|
||||
3:
|
||||
4:
|
||||
5:op_write(OPMODE_ADDR, dp + regs.$1, regs.a);
|
||||
}
|
||||
|
||||
mov_idpx_a(0xc7) {
|
||||
1:sp = op_read() + regs.x;
|
||||
2:
|
||||
3:dp = op_read(OPMODE_DP, sp);
|
||||
4:dp |= op_read(OPMODE_DP, sp + 1) << 8;
|
||||
5:
|
||||
6:op_write(OPMODE_ADDR, dp, regs.a);
|
||||
}
|
||||
|
||||
mov_idpy_a(0xd7) {
|
||||
1:sp = op_read();
|
||||
2:
|
||||
3:dp = op_read(OPMODE_DP, sp);
|
||||
4:dp |= op_read(OPMODE_DP, sp + 1) << 8;
|
||||
5:
|
||||
6:op_write(OPMODE_ADDR, dp + regs.y, regs.a);
|
||||
}
|
||||
|
||||
movw_ya_dp(0xba) {
|
||||
1:sp = op_read();
|
||||
2:
|
||||
3:regs.a = op_read(OPMODE_DP, sp);
|
||||
4:regs.y = op_read(OPMODE_DP, sp + 1);
|
||||
regs.p.n = !!(regs.ya & 0x8000);
|
||||
regs.p.z = (regs.ya == 0);
|
||||
}
|
||||
|
||||
movw_dp_ya(0xda) {
|
||||
1:dp = op_read();
|
||||
2:
|
||||
3:op_write(OPMODE_DP, dp, regs.a);
|
||||
4:op_write(OPMODE_DP, dp + 1, regs.y);
|
||||
}
|
||||
|
||||
mov1_c_bit(0xaa) {
|
||||
1:sp = op_read();
|
||||
2:sp |= op_read() << 8;
|
||||
3:bit = sp >> 13;
|
||||
sp &= 0x1fff;
|
||||
rd = op_read(OPMODE_ADDR, sp);
|
||||
regs.p.c = !!(rd & (1 << bit));
|
||||
}
|
||||
|
||||
mov1_bit_c(0xca) {
|
||||
1:dp = op_read();
|
||||
2:dp |= op_read() << 8;
|
||||
3:bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
if(regs.p.c)rd |= (1 << bit);
|
||||
else rd &= ~(1 << bit);
|
||||
4:op_write(OPMODE_ADDR, dp, rd);
|
||||
}
|
||||
@@ -0,0 +1,708 @@
|
||||
void bAPU::op_mov_a_x() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.a = regs.x;
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_y() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.a = regs.y;
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_x_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.x = regs.a;
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_y_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.y = regs.a;
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_x_sp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.x = regs.sp;
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_sp_x() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.sp = regs.x;
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_const() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.a = op_read();
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_x_const() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.x = op_read();
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_y_const() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.y = op_read();
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_ix() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
regs.a = op_read(OPMODE_DP, regs.x);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_ixinc() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
regs.a = op_read(OPMODE_DP, regs.x++);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
regs.a = op_read(OPMODE_DP, sp);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_x_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
regs.x = op_read(OPMODE_DP, sp);
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_y_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
regs.y = op_read(OPMODE_DP, sp);
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_dpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
regs.a = op_read(OPMODE_DP, sp + regs.x);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_x_dpy() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
regs.x = op_read(OPMODE_DP, sp + regs.y);
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_y_dpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
regs.y = op_read(OPMODE_DP, sp + regs.x);
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
sp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
regs.a = op_read(OPMODE_ADDR, sp);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_x_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
sp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
regs.x = op_read(OPMODE_ADDR, sp);
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_y_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
sp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
regs.y = op_read(OPMODE_ADDR, sp);
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_addrx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
sp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
regs.a = op_read(OPMODE_ADDR, sp + regs.x);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_addry() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
sp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
regs.a = op_read(OPMODE_ADDR, sp + regs.y);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_idpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read() + regs.x;
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
sp = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 4: {
|
||||
sp |= op_read(OPMODE_DP, dp + 1) << 8;
|
||||
} break;
|
||||
case 5: {
|
||||
regs.a = op_read(OPMODE_ADDR, sp);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_idpy() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
sp = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 4: {
|
||||
sp |= op_read(OPMODE_DP, dp + 1) << 8;
|
||||
} break;
|
||||
case 5: {
|
||||
regs.a = op_read(OPMODE_ADDR, sp + regs.y);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_dp_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_DP, sp);
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_dp_const() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
rd = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_ix_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
op_write(OPMODE_DP, regs.x, regs.a);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_ixinc_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
op_write(OPMODE_DP, regs.x++, regs.a);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_dp_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
op_write(OPMODE_DP, dp, regs.a);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_dp_x() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
op_write(OPMODE_DP, dp, regs.x);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_dp_y() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
op_write(OPMODE_DP, dp, regs.y);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_dpx_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_DP, dp + regs.x, regs.a);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_dpy_x() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_DP, dp + regs.y, regs.x);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_dpx_y() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_DP, dp + regs.x, regs.y);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_addr_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_ADDR, dp, regs.a);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_addr_x() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_ADDR, dp, regs.x);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_addr_y() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_ADDR, dp, regs.y);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_addrx_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
} break;
|
||||
case 5: {
|
||||
op_write(OPMODE_ADDR, dp + regs.x, regs.a);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_addry_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
} break;
|
||||
case 5: {
|
||||
op_write(OPMODE_ADDR, dp + regs.y, regs.a);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_idpx_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
sp = op_read() + regs.x;
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
dp = op_read(OPMODE_DP, sp);
|
||||
} break;
|
||||
case 4: {
|
||||
dp |= op_read(OPMODE_DP, sp + 1) << 8;
|
||||
} break;
|
||||
case 5: {
|
||||
} break;
|
||||
case 6: {
|
||||
op_write(OPMODE_ADDR, dp, regs.a);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_idpy_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
dp = op_read(OPMODE_DP, sp);
|
||||
} break;
|
||||
case 4: {
|
||||
dp |= op_read(OPMODE_DP, sp + 1) << 8;
|
||||
} break;
|
||||
case 5: {
|
||||
} break;
|
||||
case 6: {
|
||||
op_write(OPMODE_ADDR, dp + regs.y, regs.a);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_movw_ya_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
regs.a = op_read(OPMODE_DP, sp);
|
||||
} break;
|
||||
case 4: {
|
||||
regs.y = op_read(OPMODE_DP, sp + 1);
|
||||
regs.p.n = !!(regs.ya & 0x8000);
|
||||
regs.p.z = (regs.ya == 0);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_movw_dp_ya() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
op_write(OPMODE_DP, dp, regs.a);
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_DP, dp + 1, regs.y);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov1_c_bit() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
sp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
bit = sp >> 13;
|
||||
sp &= 0x1fff;
|
||||
rd = op_read(OPMODE_ADDR, sp);
|
||||
regs.p.c = !!(rd & (1 << bit));
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov1_bit_c() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
if(regs.p.c)rd |= (1 << bit);
|
||||
else rd &= ~(1 << bit);
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_ADDR, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
bra(0x2f, 0),
|
||||
beq(0xf0, !regs.p.z),
|
||||
bne(0xd0, regs.p.z),
|
||||
bcs(0xb0, !regs.p.c),
|
||||
bcc(0x90, regs.p.c),
|
||||
bvs(0x70, !regs.p.v),
|
||||
bvc(0x50, regs.p.v),
|
||||
bmi(0x30, !regs.p.n),
|
||||
bpl(0x10, regs.p.n) {
|
||||
1:rd = op_read();
|
||||
if($1)end;
|
||||
2:
|
||||
3:regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
bbs0(0x03, 0x01, !=),
|
||||
bbc0(0x13, 0x01, ==),
|
||||
bbs1(0x23, 0x02, !=),
|
||||
bbc1(0x33, 0x02, ==),
|
||||
bbs2(0x43, 0x04, !=),
|
||||
bbc2(0x53, 0x04, ==),
|
||||
bbs3(0x63, 0x08, !=),
|
||||
bbc3(0x73, 0x08, ==),
|
||||
bbs4(0x83, 0x10, !=),
|
||||
bbc4(0x93, 0x10, ==),
|
||||
bbs5(0xa3, 0x20, !=),
|
||||
bbc5(0xb3, 0x20, ==),
|
||||
bbs6(0xc3, 0x40, !=),
|
||||
bbc6(0xd3, 0x40, ==),
|
||||
bbs7(0xe3, 0x80, !=),
|
||||
bbc7(0xf3, 0x80, ==) {
|
||||
1:dp = op_read();
|
||||
2:rd = op_read();
|
||||
3:sp = op_read(OPMODE_DP, dp);
|
||||
4:if((sp & $1) $2 $1)end;
|
||||
5:
|
||||
6:regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
cbne_dp(0x2e) {
|
||||
1:dp = op_read();
|
||||
2:rd = op_read();
|
||||
3:sp = op_read(OPMODE_DP, dp);
|
||||
4:if(regs.a == sp)end;
|
||||
5:
|
||||
6:regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
cbne_dpx(0xde) {
|
||||
1:dp = op_read();
|
||||
2:rd = op_read();
|
||||
3:
|
||||
4:sp = op_read(OPMODE_DP, dp + regs.x);
|
||||
5:if(regs.a == sp)end;
|
||||
6:
|
||||
7:regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
dbnz_dp(0x6e) {
|
||||
1:dp = op_read();
|
||||
2:rd = op_read();
|
||||
3:wr = op_read(OPMODE_DP, dp);
|
||||
4:wr--;
|
||||
op_write(OPMODE_DP, dp, wr);
|
||||
if(wr == 0x00)end;
|
||||
5:
|
||||
6:regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
dbnz_y(0xfe) {
|
||||
1:rd = op_read();
|
||||
2:regs.y--;
|
||||
3:if(regs.y == 0x00)end;
|
||||
4:
|
||||
5:regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
jmp_addr(0x5f) {
|
||||
1:rd = op_read();
|
||||
2:rd |= op_read() << 8;
|
||||
regs.pc = rd;
|
||||
}
|
||||
|
||||
jmp_iaddrx(0x1f) {
|
||||
1:dp = op_read();
|
||||
2:dp |= op_read() << 8;
|
||||
3:dp += regs.x;
|
||||
4:rd = op_read(OPMODE_ADDR, dp);
|
||||
5:rd |= op_read(OPMODE_ADDR, dp + 1) << 8;
|
||||
regs.pc = rd;
|
||||
}
|
||||
|
||||
call(0x3f) {
|
||||
1:rd = op_read();
|
||||
2:rd |= op_read() << 8;
|
||||
3:
|
||||
4:
|
||||
5:
|
||||
6:stack_write(regs.pc >> 8);
|
||||
7:stack_write(regs.pc);
|
||||
regs.pc = rd;
|
||||
}
|
||||
|
||||
pcall(0x4f) {
|
||||
1:rd = op_read();
|
||||
2:
|
||||
3:
|
||||
4:stack_write(regs.pc >> 8);
|
||||
5:stack_write(regs.pc);
|
||||
regs.pc = 0xff00 | rd;
|
||||
}
|
||||
|
||||
tcall_0(0x01, 0),
|
||||
tcall_1(0x11, 1),
|
||||
tcall_2(0x21, 2),
|
||||
tcall_3(0x31, 3),
|
||||
tcall_4(0x41, 4),
|
||||
tcall_5(0x51, 5),
|
||||
tcall_6(0x61, 6),
|
||||
tcall_7(0x71, 7),
|
||||
tcall_8(0x81, 8),
|
||||
tcall_9(0x91, 9),
|
||||
tcall_10(0xa1, 10),
|
||||
tcall_11(0xb1, 11),
|
||||
tcall_12(0xc1, 12),
|
||||
tcall_13(0xd1, 13),
|
||||
tcall_14(0xe1, 14),
|
||||
tcall_15(0xf1, 15) {
|
||||
1:dp = 0xffde - ($1 << 1);
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
2:rd |= op_read(OPMODE_ADDR, dp + 1) << 8;
|
||||
3:
|
||||
4:
|
||||
5:
|
||||
6:stack_write(regs.pc >> 8);
|
||||
7:stack_write(regs.pc);
|
||||
regs.pc = rd;
|
||||
}
|
||||
|
||||
brk(0x0f) {
|
||||
1:rd = op_read(OPMODE_ADDR, 0xffde);
|
||||
2:rd |= op_read(OPMODE_ADDR, 0xffdf) << 8;
|
||||
3:
|
||||
4:
|
||||
5:stack_write(regs.pc >> 8);
|
||||
6:stack_write(regs.pc);
|
||||
7:stack_write(regs.p);
|
||||
regs.pc = rd;
|
||||
regs.p.b = 1;
|
||||
regs.p.i = 0;
|
||||
}
|
||||
|
||||
ret(0x6f) {
|
||||
1:rd = stack_read();
|
||||
2:rd |= stack_read() << 8;
|
||||
3:
|
||||
4:regs.pc = rd;
|
||||
}
|
||||
|
||||
reti(0x7f) {
|
||||
1:regs.p = stack_read();
|
||||
2:rd = stack_read();
|
||||
3:rd |= stack_read() << 8;
|
||||
4:
|
||||
5:regs.pc = rd;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,194 @@
|
||||
adc_a_const(0x88, adc, a),
|
||||
and_a_const(0x28, and, a),
|
||||
cmp_a_const(0x68, cmp, a),
|
||||
cmp_x_const(0xc8, cmp, x),
|
||||
cmp_y_const(0xad, cmp, y),
|
||||
eor_a_const(0x48, eor, a),
|
||||
or_a_const(0x08, or, a),
|
||||
sbc_a_const(0xa8, sbc, a) {
|
||||
1:rd = op_read();
|
||||
regs.$2 = op_$1(regs.$2, rd);
|
||||
}
|
||||
|
||||
adc_a_ix(0x86, adc),
|
||||
and_a_ix(0x26, and),
|
||||
cmp_a_ix(0x66, cmp),
|
||||
eor_a_ix(0x46, eor),
|
||||
or_a_ix(0x06, or),
|
||||
sbc_a_ix(0xa6, sbc) {
|
||||
1:rd = op_read(OPMODE_DP, regs.x);
|
||||
2:regs.a = op_$1(regs.a, rd);
|
||||
}
|
||||
|
||||
adc_a_dp(0x84, adc, a),
|
||||
and_a_dp(0x24, and, a),
|
||||
cmp_a_dp(0x64, cmp, a),
|
||||
cmp_x_dp(0x3e, cmp, x),
|
||||
cmp_y_dp(0x7e, cmp, y),
|
||||
eor_a_dp(0x44, eor, a),
|
||||
or_a_dp(0x04, or, a),
|
||||
sbc_a_dp(0xa4, sbc, a) {
|
||||
1:dp = op_read();
|
||||
2:rd = op_read(OPMODE_DP, dp);
|
||||
regs.$2 = op_$1(regs.$2, rd);
|
||||
}
|
||||
|
||||
adc_a_dpx(0x94, adc),
|
||||
and_a_dpx(0x34, and),
|
||||
cmp_a_dpx(0x74, cmp),
|
||||
eor_a_dpx(0x54, eor),
|
||||
or_a_dpx(0x14, or),
|
||||
sbc_a_dpx(0xb4, sbc) {
|
||||
1:dp = op_read();
|
||||
2:
|
||||
3:rd = op_read(OPMODE_DP, dp + regs.x);
|
||||
regs.a = op_$1(regs.a, rd);
|
||||
}
|
||||
|
||||
adc_a_addr(0x85, adc, a),
|
||||
and_a_addr(0x25, and, a),
|
||||
cmp_a_addr(0x65, cmp, a),
|
||||
cmp_x_addr(0x1e, cmp, x),
|
||||
cmp_y_addr(0x5e, cmp, y),
|
||||
eor_a_addr(0x45, eor, a),
|
||||
or_a_addr(0x05, or, a),
|
||||
sbc_a_addr(0xa5, sbc, a) {
|
||||
1:dp = op_read();
|
||||
2:dp |= op_read() << 8;
|
||||
3:rd = op_read(OPMODE_ADDR, dp);
|
||||
regs.$2 = op_$1(regs.$2, rd);
|
||||
}
|
||||
|
||||
adc_a_addrx(0x95, adc, x),
|
||||
adc_a_addry(0x96, adc, y),
|
||||
and_a_addrx(0x35, and, x),
|
||||
and_a_addry(0x36, and, y),
|
||||
cmp_a_addrx(0x75, cmp, x),
|
||||
cmp_a_addry(0x76, cmp, y),
|
||||
eor_a_addrx(0x55, eor, x),
|
||||
eor_a_addry(0x56, eor, y),
|
||||
or_a_addrx(0x15, or, x),
|
||||
or_a_addry(0x16, or, y),
|
||||
sbc_a_addrx(0xb5, sbc, x),
|
||||
sbc_a_addry(0xb6, sbc, y) {
|
||||
1:dp = op_read();
|
||||
2:dp |= op_read() << 8;
|
||||
3:
|
||||
4:rd = op_read(OPMODE_ADDR, dp + regs.$2);
|
||||
regs.a = op_$1(regs.a, rd);
|
||||
}
|
||||
|
||||
adc_a_idpx(0x87, adc),
|
||||
and_a_idpx(0x27, and),
|
||||
cmp_a_idpx(0x67, cmp),
|
||||
eor_a_idpx(0x47, eor),
|
||||
or_a_idpx(0x07, or),
|
||||
sbc_a_idpx(0xa7, sbc) {
|
||||
1:dp = op_read() + regs.x;
|
||||
2:
|
||||
3:sp = op_read(OPMODE_DP, dp);
|
||||
4:sp |= op_read(OPMODE_DP, dp + 1) << 8;
|
||||
5:rd = op_read(OPMODE_ADDR, sp);
|
||||
regs.a = op_$1(regs.a, rd);
|
||||
}
|
||||
|
||||
adc_a_idpy(0x97, adc),
|
||||
and_a_idpy(0x37, and),
|
||||
cmp_a_idpy(0x77, cmp),
|
||||
eor_a_idpy(0x57, eor),
|
||||
or_a_idpy(0x17, or),
|
||||
sbc_a_idpy(0xb7, sbc) {
|
||||
1:dp = op_read();
|
||||
2:
|
||||
3:sp = op_read(OPMODE_DP, dp);
|
||||
4:sp |= op_read(OPMODE_DP, dp + 1) << 8;
|
||||
5:rd = op_read(OPMODE_ADDR, sp + regs.y);
|
||||
regs.a = op_$1(regs.a, rd);
|
||||
}
|
||||
|
||||
adc_ix_iy(0x99, adc, 1),
|
||||
and_ix_iy(0x39, and, 1),
|
||||
cmp_ix_iy(0x79, cmp, 0),
|
||||
eor_ix_iy(0x59, eor, 1),
|
||||
or_ix_iy(0x19, or, 1),
|
||||
sbc_ix_iy(0xb9, sbc, 1) {
|
||||
1:wr = op_read(OPMODE_DP, regs.x);
|
||||
2:rd = op_read(OPMODE_DP, regs.y);
|
||||
3:wr = op_$1(wr, rd);
|
||||
4:if($2)op_write(OPMODE_DP, regs.x, wr);
|
||||
}
|
||||
|
||||
adc_dp_dp(0x89, adc, 1),
|
||||
and_dp_dp(0x29, and, 1),
|
||||
cmp_dp_dp(0x69, cmp, 0),
|
||||
eor_dp_dp(0x49, eor, 1),
|
||||
or_dp_dp(0x09, or, 1),
|
||||
sbc_dp_dp(0xa9, sbc, 1) {
|
||||
1:sp = op_read();
|
||||
2:dp = op_read();
|
||||
3:wr = op_read(OPMODE_DP, dp);
|
||||
4:rd = op_read(OPMODE_DP, sp);
|
||||
5:wr = op_$1(wr, rd);
|
||||
if($2)op_write(OPMODE_DP, dp, wr);
|
||||
}
|
||||
|
||||
adc_dp_const(0x98, adc, 1),
|
||||
and_dp_const(0x38, and, 1),
|
||||
cmp_dp_const(0x78, cmp, 0),
|
||||
eor_dp_const(0x58, eor, 1),
|
||||
or_dp_const(0x18, or, 1),
|
||||
sbc_dp_const(0xb8, sbc, 1) {
|
||||
1:rd = op_read();
|
||||
2:dp = op_read();
|
||||
3:wr = op_read(OPMODE_DP, dp);
|
||||
4:wr = op_$1(wr, rd);
|
||||
if($2)op_write(OPMODE_DP, dp, wr);
|
||||
}
|
||||
|
||||
addw_ya_dp(0x7a, addw),
|
||||
cmpw_ya_dp(0x5a, cmpw),
|
||||
subw_ya_dp(0x9a, subw) {
|
||||
1:dp = op_read();
|
||||
2:rd = op_read(OPMODE_DP, dp);
|
||||
3:rd |= op_read(OPMODE_DP, dp + 1) << 8;
|
||||
4:regs.ya = op_$1(regs.ya, rd);
|
||||
}
|
||||
|
||||
and1_bit(0x4a, !!),
|
||||
and1_notbit(0x6a, !) {
|
||||
1:dp = op_read();
|
||||
2:dp |= op_read() << 8;
|
||||
3:bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
regs.p.c = regs.p.c & $1(rd & (1 << bit));
|
||||
}
|
||||
|
||||
eor1_bit(0x8a) {
|
||||
1:dp = op_read();
|
||||
2:dp |= op_read() << 8;
|
||||
3:bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
4:regs.p.c = regs.p.c ^ !!(rd & (1 << bit));
|
||||
}
|
||||
|
||||
not1_bit(0xea) {
|
||||
1:dp = op_read();
|
||||
2:dp |= op_read() << 8;
|
||||
3:bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
rd ^= (1 << bit);
|
||||
4:op_write(OPMODE_ADDR, dp, rd);
|
||||
}
|
||||
|
||||
or1_bit(0x0a, !!),
|
||||
or1_notbit(0x2a, !) {
|
||||
1:dp = op_read();
|
||||
2:dp |= op_read() << 8;
|
||||
3:bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
4:regs.p.c = regs.p.c | $1(rd & (1 << bit));
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,60 @@
|
||||
inc_a(0xbc, inc, a),
|
||||
inc_x(0x3d, inc, x),
|
||||
inc_y(0xfc, inc, y),
|
||||
dec_a(0x9c, dec, a),
|
||||
dec_x(0x1d, dec, x),
|
||||
dec_y(0xdc, dec, y),
|
||||
asl_a(0x1c, asl, a),
|
||||
lsr_a(0x5c, lsr, a),
|
||||
rol_a(0x3c, rol, a),
|
||||
ror_a(0x7c, ror, a) {
|
||||
1:regs.$2 = op_$1(regs.$2);
|
||||
}
|
||||
|
||||
inc_dp(0xab, inc),
|
||||
dec_dp(0x8b, dec),
|
||||
asl_dp(0x0b, asl),
|
||||
lsr_dp(0x4b, lsr),
|
||||
rol_dp(0x2b, rol),
|
||||
ror_dp(0x6b, ror) {
|
||||
1:dp = op_read();
|
||||
2:rd = op_read(OPMODE_DP, dp);
|
||||
3:rd = op_$1(rd);
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
}
|
||||
|
||||
inc_dpx(0xbb, inc),
|
||||
dec_dpx(0x9b, dec),
|
||||
asl_dpx(0x1b, asl),
|
||||
lsr_dpx(0x5b, lsr),
|
||||
rol_dpx(0x3b, rol),
|
||||
ror_dpx(0x7b, ror) {
|
||||
1:dp = op_read();
|
||||
2:
|
||||
3:rd = op_read(OPMODE_DP, dp + regs.x);
|
||||
4:rd = op_$1(rd);
|
||||
op_write(OPMODE_DP, dp + regs.x, rd);
|
||||
}
|
||||
|
||||
inc_addr(0xac, inc),
|
||||
dec_addr(0x8c, dec),
|
||||
asl_addr(0x0c, asl),
|
||||
lsr_addr(0x4c, lsr),
|
||||
rol_addr(0x2c, rol),
|
||||
ror_addr(0x6c, ror) {
|
||||
1:dp = op_read();
|
||||
2:dp |= op_read() << 8;
|
||||
3:rd = op_read(OPMODE_ADDR, dp);
|
||||
4:rd = op_$1(rd);
|
||||
op_write(OPMODE_ADDR, dp, rd);
|
||||
}
|
||||
|
||||
incw_dp(0x3a, incw),
|
||||
decw_dp(0x1a, decw) {
|
||||
1:dp = op_read();
|
||||
2:rd = op_read(OPMODE_DP, dp);
|
||||
3:rd |= op_read(OPMODE_DP, dp + 1) << 8;
|
||||
4:rd = op_$1(rd);
|
||||
op_write(OPMODE_DP, dp + 1, rd >> 8);
|
||||
5:op_write(OPMODE_DP, dp, rd);
|
||||
}
|
||||
@@ -0,0 +1,452 @@
|
||||
void bAPU::op_inc_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.a = op_inc(regs.a);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_inc_x() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.x = op_inc(regs.x);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_inc_y() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.y = op_inc(regs.y);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_dec_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.a = op_dec(regs.a);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_dec_x() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.x = op_dec(regs.x);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_dec_y() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.y = op_dec(regs.y);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_asl_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.a = op_asl(regs.a);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_lsr_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.a = op_lsr(regs.a);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_rol_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.a = op_rol(regs.a);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_ror_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
regs.a = op_ror(regs.a);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_inc_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_inc(rd);
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_dec_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_dec(rd);
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_asl_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_asl(rd);
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_lsr_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_lsr(rd);
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_rol_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_rol(rd);
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_ror_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_ror(rd);
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_inc_dpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_DP, dp + regs.x);
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_inc(rd);
|
||||
op_write(OPMODE_DP, dp + regs.x, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_dec_dpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_DP, dp + regs.x);
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_dec(rd);
|
||||
op_write(OPMODE_DP, dp + regs.x, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_asl_dpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_DP, dp + regs.x);
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_asl(rd);
|
||||
op_write(OPMODE_DP, dp + regs.x, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_lsr_dpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_DP, dp + regs.x);
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_lsr(rd);
|
||||
op_write(OPMODE_DP, dp + regs.x, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_rol_dpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_DP, dp + regs.x);
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_rol(rd);
|
||||
op_write(OPMODE_DP, dp + regs.x, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_ror_dpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_DP, dp + regs.x);
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_ror(rd);
|
||||
op_write(OPMODE_DP, dp + regs.x, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_inc_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_inc(rd);
|
||||
op_write(OPMODE_ADDR, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_dec_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_dec(rd);
|
||||
op_write(OPMODE_ADDR, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_asl_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_asl(rd);
|
||||
op_write(OPMODE_ADDR, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_lsr_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_lsr(rd);
|
||||
op_write(OPMODE_ADDR, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_rol_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_rol(rd);
|
||||
op_write(OPMODE_ADDR, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_ror_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_ror(rd);
|
||||
op_write(OPMODE_ADDR, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_incw_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= op_read(OPMODE_DP, dp + 1) << 8;
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_incw(rd);
|
||||
op_write(OPMODE_DP, dp + 1, rd >> 8);
|
||||
} break;
|
||||
case 5: {
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_decw_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= op_read(OPMODE_DP, dp + 1) << 8;
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_decw(rd);
|
||||
op_write(OPMODE_DP, dp + 1, rd >> 8);
|
||||
} break;
|
||||
case 5: {
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
uint8 bAPU::op_adc(uint8 x, uint8 y) {
|
||||
int16 r = x + y + regs.p.c;
|
||||
regs.p.n = !!(r & 0x80);
|
||||
regs.p.v = !!(~(x ^ y) & (y ^ (uint8)r) & 0x80);
|
||||
regs.p.h = !!((x ^ y ^ (uint8)r) & 0x10);
|
||||
regs.p.z = ((uint8)r == 0);
|
||||
regs.p.c = (r > 0xff);
|
||||
return r;
|
||||
}
|
||||
|
||||
uint16 bAPU::op_addw(uint16 x, uint16 y) {
|
||||
int16 r;
|
||||
regs.p.c = 0;
|
||||
r = op_adc(x, y);
|
||||
r |= op_adc(x >> 8, y >> 8) << 8;
|
||||
regs.p.z = ((uint16)r == 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
uint8 bAPU::op_and(uint8 x, uint8 y) {
|
||||
x &= y;
|
||||
regs.p.n = !!(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 bAPU::op_cmp(uint8 x, uint8 y) {
|
||||
int16 r = x - y;
|
||||
regs.p.n = !!(r & 0x80);
|
||||
regs.p.z = ((uint8)r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint16 bAPU::op_cmpw(uint16 x, uint16 y) {
|
||||
int32 r = x - y;
|
||||
regs.p.n = !!(r & 0x8000);
|
||||
regs.p.z = ((uint16)r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 bAPU::op_eor(uint8 x, uint8 y) {
|
||||
x ^= y;
|
||||
regs.p.n = !!(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 bAPU::op_or(uint8 x, uint8 y) {
|
||||
x |= y;
|
||||
regs.p.n = !!(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 bAPU::op_sbc(uint8 x, uint8 y) {
|
||||
int16 r = x - y - !regs.p.c;
|
||||
regs.p.n = !!(r & 0x80);
|
||||
regs.p.v = !!((x ^ y) & (x ^ (uint8)r) & 0x80);
|
||||
regs.p.h = !((x ^ y ^ (uint8)r) & 0x10);
|
||||
regs.p.z = ((uint8)r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
uint16 bAPU::op_subw(uint16 x, uint16 y) {
|
||||
int16 r;
|
||||
regs.p.c = 1;
|
||||
r = op_sbc(x, y);
|
||||
r |= op_sbc(x >> 8, y >> 8) << 8;
|
||||
regs.p.z = ((uint16)r == 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
uint8 bAPU::op_inc(uint8 x) {
|
||||
x++;
|
||||
regs.p.n = !!(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint16 bAPU::op_incw(uint16 x) {
|
||||
x++;
|
||||
regs.p.n = !!(x & 0x8000);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 bAPU::op_dec(uint8 x) {
|
||||
x--;
|
||||
regs.p.n = !!(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint16 bAPU::op_decw(uint16 x) {
|
||||
x--;
|
||||
regs.p.n = !!(x & 0x8000);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 bAPU::op_asl(uint8 x) {
|
||||
regs.p.c = !!(x & 0x80);
|
||||
x <<= 1;
|
||||
regs.p.n = !!(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 bAPU::op_lsr(uint8 x) {
|
||||
regs.p.c = !!(x & 0x01);
|
||||
x >>= 1;
|
||||
regs.p.n = !!(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 bAPU::op_rol(uint8 x) {
|
||||
uint8 c = regs.p.c;
|
||||
regs.p.c = !!(x & 0x80);
|
||||
x <<= 1;
|
||||
x |= c;
|
||||
regs.p.n = !!(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 bAPU::op_ror(uint8 x) {
|
||||
uint8 c = (regs.p.c)?0x80:0x00;
|
||||
regs.p.c = !!(x & 0x01);
|
||||
x >>= 1;
|
||||
x |= c;
|
||||
regs.p.n = !!(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
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;
|
||||
@@ -0,0 +1,191 @@
|
||||
uint8 bAPU::spcram_read(uint16 addr) {
|
||||
uint8 r;
|
||||
if(addr >= 0x00f0 && addr <= 0x00ff) {
|
||||
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 bAPU::spcram_write(uint16 addr, uint8 value) {
|
||||
if(addr >= 0x00f0 && addr <= 0x00ff) {
|
||||
switch(addr) {
|
||||
case 0xf0: //TEST -- operation unknown
|
||||
break;
|
||||
case 0xf1: //CONTROL
|
||||
status.iplrom_enabled = !!(value & 0x80);
|
||||
|
||||
//one-time clearing of APU port read registers,
|
||||
//emulated by simulating CPU writes of 0x00
|
||||
if(value & 0x20) {
|
||||
r_cpu->port_write(2, 0x00);
|
||||
r_cpu->port_write(3, 0x00);
|
||||
}
|
||||
if(value & 0x10) {
|
||||
r_cpu->port_write(0, 0x00);
|
||||
r_cpu->port_write(1, 0x00);
|
||||
}
|
||||
|
||||
//0->1 transistion resets timers
|
||||
if(t2.enabled == false && (value & 0x04)) {
|
||||
t2.stage2_ticks = 0;
|
||||
t2.stage3_ticks = 0;
|
||||
}
|
||||
t2.enabled = !!(value & 0x04);
|
||||
|
||||
if(t1.enabled == false && (value & 0x02)) {
|
||||
t1.stage2_ticks = 0;
|
||||
t1.stage3_ticks = 0;
|
||||
}
|
||||
t1.enabled = !!(value & 0x02);
|
||||
|
||||
if(t0.enabled == false && (value & 0x01)) {
|
||||
t0.stage2_ticks = 0;
|
||||
t0.stage3_ticks = 0;
|
||||
}
|
||||
t0.enabled = !!(value & 0x01);
|
||||
break;
|
||||
case 0xf2: //DSPADDR
|
||||
status.dsp_addr = value;
|
||||
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, value);
|
||||
}
|
||||
break;
|
||||
case 0xf4: //CPUIO0
|
||||
case 0xf5: //CPUIO1
|
||||
case 0xf6: //CPUIO2
|
||||
case 0xf7: //CPUIO3
|
||||
port_write(addr & 3, value);
|
||||
break;
|
||||
case 0xf8: //???
|
||||
case 0xf9: //??? - Mapped to SPCRAM
|
||||
spcram[addr] = value;
|
||||
break;
|
||||
case 0xfa: //T0TARGET
|
||||
t0.target = value;
|
||||
break;
|
||||
case 0xfb: //T1TARGET
|
||||
t1.target = value;
|
||||
break;
|
||||
case 0xfc: //T2TARGET
|
||||
t2.target = value;
|
||||
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] = value;
|
||||
}
|
||||
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::SPCRAM_WRITE, addr, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8 bAPU::port_read(uint8 port) {
|
||||
return spcram[0xf4 + (port & 3)];
|
||||
}
|
||||
|
||||
void bAPU::port_write(uint8 port, uint8 value) {
|
||||
spcram[0xf4 + (port & 0x03)] = value;
|
||||
}
|
||||
|
||||
uint8 bAPU::op_read() {
|
||||
uint8 r;
|
||||
r = spcram_read(regs.pc);
|
||||
regs.pc++;
|
||||
return r;
|
||||
}
|
||||
|
||||
uint8 bAPU::op_read(uint8 mode, uint16 addr) {
|
||||
uint8 r;
|
||||
switch(mode) {
|
||||
case OPMODE_ADDR:
|
||||
r = spcram_read(addr);
|
||||
break;
|
||||
case OPMODE_DP:
|
||||
r = spcram_read(((regs.p.p)?0x100:0x000) + (addr & 0xff));
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void bAPU::op_write(uint8 mode, uint16 addr, uint8 value) {
|
||||
switch(mode) {
|
||||
case OPMODE_ADDR:
|
||||
spcram_write(addr, value);
|
||||
break;
|
||||
case OPMODE_DP:
|
||||
spcram_write(((regs.p.p)?0x100:0x000) + (addr & 0xff), value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 bAPU::stack_read() {
|
||||
regs.sp++;
|
||||
return spcram_read(0x0100 | regs.sp);
|
||||
}
|
||||
|
||||
void bAPU::stack_write(uint8 value) {
|
||||
spcram_write(0x0100 | regs.sp, value);
|
||||
regs.sp--;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
enum { OPMODE_ADDR, OPMODE_DP };
|
||||
inline uint8 spcram_read (uint16 addr);
|
||||
inline void spcram_write(uint16 addr, uint8 value);
|
||||
inline uint8 port_read (uint8 port);
|
||||
inline void port_write(uint8 port, uint8 value);
|
||||
|
||||
inline uint8 op_read();
|
||||
inline uint8 op_read (uint8 mode, uint16 addr);
|
||||
inline void op_write(uint8 mode, uint16 addr, uint8 value);
|
||||
inline uint8 stack_read();
|
||||
inline void stack_write(uint8 value);
|
||||
@@ -0,0 +1,35 @@
|
||||
void bAPU::add_cycles(int cycles) {
|
||||
status.clocks_executed += cycles;
|
||||
|
||||
t0.add_cycles(cycles);
|
||||
t1.add_cycles(cycles);
|
||||
t2.add_cycles(cycles);
|
||||
}
|
||||
|
||||
uint32 bAPU::clocks_executed() {
|
||||
uint32 r = status.clocks_executed;
|
||||
status.clocks_executed = 0;
|
||||
return (r << 4) + (r << 3);
|
||||
}
|
||||
|
||||
//cycles should never be greater than 12. since the minimum
|
||||
//cycle_frequency value is 16, we don't have to worry about
|
||||
//two ticks occuring in one call to this function.
|
||||
void bAPU::bAPUTimer::add_cycles(int cycles) {
|
||||
//stage 1 increment
|
||||
stage1_ticks += cycles;
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
class bAPUTimer {
|
||||
public:
|
||||
uint8 cycle_frequency, target;
|
||||
uint8 stage1_ticks, stage2_ticks, stage3_ticks;
|
||||
bool enabled;
|
||||
inline void add_cycles(int cycles);
|
||||
} t0, t1, t2;
|
||||
inline void add_cycles(int cycles);
|
||||
inline uint32 clocks_executed();
|
||||
@@ -0,0 +1,306 @@
|
||||
//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);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
//This is the IPLROM for the SPC700 coprocessor.
|
||||
//This array is *read-only*. The SPC700 does not
|
||||
//allow writing to the IPLROM, all writes are
|
||||
//instead mapped to the extended SPC700 RAM region,
|
||||
//accessible when $f1 bit 7 is clear.
|
||||
|
||||
const uint8 APU::iplrom[64] = {
|
||||
/*ffc0*/ 0xcd, 0xef, //mov x,#$ef
|
||||
/*ffc2*/ 0xbd, //mov sp,x
|
||||
/*ffc3*/ 0xe8, 0x00, //mov a,#$00
|
||||
/*ffc5*/ 0xc6, //mov (x),a
|
||||
/*ffc6*/ 0x1d, //dec x
|
||||
/*ffc7*/ 0xd0, 0xfc, //bne $ffc5
|
||||
/*ffc9*/ 0x8f, 0xaa, 0xf4, //mov $f4,#$aa
|
||||
/*ffcc*/ 0x8f, 0xbb, 0xf5, //mov $f5,#$bb
|
||||
/*ffcf*/ 0x78, 0xcc, 0xf4, //cmp $f4,#$cc
|
||||
/*ffd2*/ 0xd0, 0xfb, //bne $ffcf
|
||||
/*ffd4*/ 0x2f, 0x19, //bra $ffef
|
||||
/*ffd6*/ 0xeb, 0xf4, //mov y,$f4
|
||||
/*ffd8*/ 0xd0, 0xfc, //bne $ffd6
|
||||
/*ffda*/ 0x7e, 0xf4, //cmp y,$f4
|
||||
/*ffdc*/ 0xd0, 0x0b, //bne $ffe9
|
||||
/*ffde*/ 0xe4, 0xf5, //mov a,$f5
|
||||
/*ffe0*/ 0xcb, 0xf4, //mov $f4,y
|
||||
/*ffe2*/ 0xd7, 0x00, //mov ($00)+y,a
|
||||
/*ffe4*/ 0xfc, //inc y
|
||||
/*ffe5*/ 0xd0, 0xf3, //bne $ffda
|
||||
/*ffe7*/ 0xab, 0x01, //inc $01
|
||||
/*ffe9*/ 0x10, 0xef, //bpl $ffda
|
||||
/*ffeb*/ 0x7e, 0xf4, //cmp y,$f4
|
||||
/*ffed*/ 0x10, 0xeb, //bpl $ffda
|
||||
/*ffef*/ 0xba, 0xf6, //movw ya,$f6
|
||||
/*fff1*/ 0xda, 0x00, //movw $00,ya
|
||||
/*fff3*/ 0xba, 0xf4, //movw ya,$f4
|
||||
/*fff5*/ 0xc4, 0xf4, //mov $f4,a
|
||||
/*fff7*/ 0xdd, //mov a,y
|
||||
/*fff8*/ 0x5d, //mov x,a
|
||||
/*fff9*/ 0xd0, 0xdb, //bne $ffd6
|
||||
/*fffb*/ 0x1f, 0x00, 0x00, //jmp ($0000+x)
|
||||
/*fffe*/ 0xc0, 0xff //---reset vector location ($ffc0)
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
cl /O2 /wd4996 sapugen.cpp
|
||||
@pause
|
||||
@del *.obj
|
||||
@@ -0,0 +1 @@
|
||||
@del *.exe
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "opfn.cpp"
|
||||
|
||||
void sAPU::main() {
|
||||
for(;;) {
|
||||
status.in_opcode = true;
|
||||
|
||||
switch(op_readpc()) {
|
||||
#include "op_mov.cpp"
|
||||
#include "op_pc.cpp"
|
||||
#include "op_read.cpp"
|
||||
#include "op_rmw.cpp"
|
||||
#include "op_misc.cpp"
|
||||
}
|
||||
|
||||
status.in_opcode = false;
|
||||
|
||||
#ifdef FAVOR_SPEED
|
||||
co_return();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
//void (sAPU::*optbl[256])();
|
||||
|
||||
uint16 dp, sp, rd, wr, bit, ya;
|
||||
bool in_opcode() { return status.in_opcode; }
|
||||
|
||||
uint8 op_adc (uint8 x, uint8 y);
|
||||
uint16 op_addw(uint16 x, uint16 y);
|
||||
uint8 op_and (uint8 x, uint8 y);
|
||||
uint8 op_cmp (uint8 x, uint8 y);
|
||||
uint16 op_cmpw(uint16 x, uint16 y);
|
||||
uint8 op_eor (uint8 x, uint8 y);
|
||||
uint8 op_inc (uint8 x);
|
||||
uint16 op_incw(uint16 x);
|
||||
uint8 op_dec (uint8 x);
|
||||
uint16 op_decw(uint16 x);
|
||||
uint8 op_or (uint8 x, uint8 y);
|
||||
uint8 op_sbc (uint8 x, uint8 y);
|
||||
uint16 op_subw(uint16 x, uint16 y);
|
||||
uint8 op_asl (uint8 x);
|
||||
uint8 op_lsr (uint8 x);
|
||||
uint8 op_rol (uint8 x);
|
||||
uint8 op_ror (uint8 x);
|
||||
|
||||
//#include "op.h"
|
||||
@@ -0,0 +1,175 @@
|
||||
nop(0x00) {
|
||||
1:op_io();
|
||||
}
|
||||
|
||||
sleep(0xef),
|
||||
stop(0xff) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
regs.pc--;
|
||||
}
|
||||
|
||||
xcn(0x9f) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
3:op_io();
|
||||
4:op_io();
|
||||
regs.a = (regs.a >> 4) | (regs.a << 4);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
daa(0xdf) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
if(regs.p.c || (regs.a) > 0x99) {
|
||||
regs.a += 0x60;
|
||||
regs.p.c = 1;
|
||||
}
|
||||
if(regs.p.h || (regs.a & 15) > 0x09) {
|
||||
regs.a += 0x06;
|
||||
}
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
das(0xbe) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
if(!regs.p.c || (regs.a) > 0x99) {
|
||||
regs.a -= 0x60;
|
||||
regs.p.c = 0;
|
||||
}
|
||||
if(!regs.p.h || (regs.a & 15) > 0x09) {
|
||||
regs.a -= 0x06;
|
||||
}
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
clrc(0x60, regs.p.c = 0),
|
||||
clrp(0x20, regs.p.p = 0),
|
||||
setc(0x80, regs.p.c = 1),
|
||||
setp(0x40, regs.p.p = 1) {
|
||||
1:op_io();
|
||||
$1;
|
||||
}
|
||||
|
||||
clrv(0xe0) {
|
||||
1:op_io();
|
||||
regs.p.v = 0;
|
||||
regs.p.h = 0;
|
||||
}
|
||||
|
||||
notc(0xed) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
regs.p.c ^= 1;
|
||||
}
|
||||
|
||||
ei(0xa0, 1),
|
||||
di(0xc0, 0) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
regs.p.i = $1;
|
||||
}
|
||||
|
||||
set0_dp(0x02, rd |= 0x01),
|
||||
clr0_dp(0x12, rd &= ~0x01),
|
||||
set1_dp(0x22, rd |= 0x02),
|
||||
clr1_dp(0x32, rd &= ~0x02),
|
||||
set2_dp(0x42, rd |= 0x04),
|
||||
clr2_dp(0x52, rd &= ~0x04),
|
||||
set3_dp(0x62, rd |= 0x08),
|
||||
clr3_dp(0x72, rd &= ~0x08),
|
||||
set4_dp(0x82, rd |= 0x10),
|
||||
clr4_dp(0x92, rd &= ~0x10),
|
||||
set5_dp(0xa2, rd |= 0x20),
|
||||
clr5_dp(0xb2, rd &= ~0x20),
|
||||
set6_dp(0xc2, rd |= 0x40),
|
||||
clr6_dp(0xd2, rd &= ~0x40),
|
||||
set7_dp(0xe2, rd |= 0x80),
|
||||
clr7_dp(0xf2, rd &= ~0x80) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readdp(dp);
|
||||
3:$1;
|
||||
op_writedp(dp, rd);
|
||||
}
|
||||
|
||||
tset_addr_a(0x0e, |=),
|
||||
tclr_addr_a(0x4e, &=~) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:rd = op_readaddr(dp);
|
||||
4:op_io();
|
||||
regs.p.n = !!((rd & regs.a) & 0x80);
|
||||
regs.p.z = ((rd & regs.a) == 0);
|
||||
rd $1 regs.a;
|
||||
5:op_writeaddr(dp, rd);
|
||||
}
|
||||
|
||||
push_a(0x2d, a),
|
||||
push_x(0x4d, x),
|
||||
push_y(0x6d, y),
|
||||
push_p(0x0d, p) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
3:op_writestack(regs.$1);
|
||||
}
|
||||
|
||||
pop_a(0xae, a),
|
||||
pop_x(0xce, x),
|
||||
pop_y(0xee, y),
|
||||
pop_p(0x8e, p) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
3:regs.$1 = op_readstack();
|
||||
}
|
||||
|
||||
mul_ya(0xcf) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
3:op_io();
|
||||
4:op_io();
|
||||
5:op_io();
|
||||
6:op_io();
|
||||
7:op_io();
|
||||
8:op_io();
|
||||
ya = regs.y * regs.a;
|
||||
regs.a = ya;
|
||||
regs.y = ya >> 8;
|
||||
//result is set based on y (high-byte) only
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
}
|
||||
|
||||
div_ya_x(0x9e) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
3:op_io();
|
||||
4:op_io();
|
||||
5:op_io();
|
||||
6:op_io();
|
||||
7:op_io();
|
||||
8:op_io();
|
||||
9:op_io();
|
||||
10:op_io();
|
||||
11:op_io();
|
||||
ya = regs.ya;
|
||||
//overflow set if quotient >= 256
|
||||
regs.p.v = !!(regs.y >= regs.x);
|
||||
regs.p.h = !!((regs.y & 15) >= (regs.x & 15));
|
||||
if(regs.y < (regs.x << 1)) {
|
||||
//if quotient is <= 511 (will fit into 9-bit result)
|
||||
regs.a = ya / regs.x;
|
||||
regs.y = ya % regs.x;
|
||||
} else {
|
||||
//otherwise, the quotient won't fit into regs.p.v + regs.a
|
||||
//this emulates the odd behavior of the SPC700 in this case
|
||||
regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x);
|
||||
regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x);
|
||||
}
|
||||
//result is set based on a (quotient) only
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
@@ -0,0 +1,370 @@
|
||||
//nop
|
||||
case 0x00: {
|
||||
op_io();
|
||||
} break;
|
||||
|
||||
//sleep
|
||||
case 0xef: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc--;
|
||||
} break;
|
||||
|
||||
//stop
|
||||
case 0xff: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc--;
|
||||
} break;
|
||||
|
||||
//xcn
|
||||
case 0x9f: {
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
regs.a = (regs.a >> 4) | (regs.a << 4);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
|
||||
//daa
|
||||
case 0xdf: {
|
||||
op_io();
|
||||
op_io();
|
||||
if(regs.p.c || (regs.a) > 0x99) {
|
||||
regs.a += 0x60;
|
||||
regs.p.c = 1;
|
||||
}
|
||||
if(regs.p.h || (regs.a & 15) > 0x09) {
|
||||
regs.a += 0x06;
|
||||
}
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
|
||||
//das
|
||||
case 0xbe: {
|
||||
op_io();
|
||||
op_io();
|
||||
if(!regs.p.c || (regs.a) > 0x99) {
|
||||
regs.a -= 0x60;
|
||||
regs.p.c = 0;
|
||||
}
|
||||
if(!regs.p.h || (regs.a & 15) > 0x09) {
|
||||
regs.a -= 0x06;
|
||||
}
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
|
||||
//clrc
|
||||
case 0x60: {
|
||||
op_io();
|
||||
regs.p.c = 0;
|
||||
} break;
|
||||
|
||||
//clrp
|
||||
case 0x20: {
|
||||
op_io();
|
||||
regs.p.p = 0;
|
||||
} break;
|
||||
|
||||
//setc
|
||||
case 0x80: {
|
||||
op_io();
|
||||
regs.p.c = 1;
|
||||
} break;
|
||||
|
||||
//setp
|
||||
case 0x40: {
|
||||
op_io();
|
||||
regs.p.p = 1;
|
||||
} break;
|
||||
|
||||
//clrv
|
||||
case 0xe0: {
|
||||
op_io();
|
||||
regs.p.v = 0;
|
||||
regs.p.h = 0;
|
||||
} break;
|
||||
|
||||
//notc
|
||||
case 0xed: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.p.c ^= 1;
|
||||
} break;
|
||||
|
||||
//ei
|
||||
case 0xa0: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.p.i = 1;
|
||||
} break;
|
||||
|
||||
//di
|
||||
case 0xc0: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.p.i = 0;
|
||||
} break;
|
||||
|
||||
//set0_dp
|
||||
case 0x02: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x01;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//clr0_dp
|
||||
case 0x12: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x01;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//set1_dp
|
||||
case 0x22: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x02;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//clr1_dp
|
||||
case 0x32: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x02;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//set2_dp
|
||||
case 0x42: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x04;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//clr2_dp
|
||||
case 0x52: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x04;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//set3_dp
|
||||
case 0x62: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x08;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//clr3_dp
|
||||
case 0x72: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x08;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//set4_dp
|
||||
case 0x82: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x10;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//clr4_dp
|
||||
case 0x92: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x10;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//set5_dp
|
||||
case 0xa2: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x20;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//clr5_dp
|
||||
case 0xb2: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x20;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//set6_dp
|
||||
case 0xc2: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x40;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//clr6_dp
|
||||
case 0xd2: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x40;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//set7_dp
|
||||
case 0xe2: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x80;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//clr7_dp
|
||||
case 0xf2: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x80;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//tset_addr_a
|
||||
case 0x0e: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
op_io();
|
||||
regs.p.n = !!((rd & regs.a) & 0x80);
|
||||
regs.p.z = ((rd & regs.a) == 0);
|
||||
rd |= regs.a;
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
|
||||
//tclr_addr_a
|
||||
case 0x4e: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
op_io();
|
||||
regs.p.n = !!((rd & regs.a) & 0x80);
|
||||
regs.p.z = ((rd & regs.a) == 0);
|
||||
rd &=~ regs.a;
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
|
||||
//push_a
|
||||
case 0x2d: {
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.a);
|
||||
} break;
|
||||
|
||||
//push_x
|
||||
case 0x4d: {
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.x);
|
||||
} break;
|
||||
|
||||
//push_y
|
||||
case 0x6d: {
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.y);
|
||||
} break;
|
||||
|
||||
//push_p
|
||||
case 0x0d: {
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.p);
|
||||
} break;
|
||||
|
||||
//pop_a
|
||||
case 0xae: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.a = op_readstack();
|
||||
} break;
|
||||
|
||||
//pop_x
|
||||
case 0xce: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.x = op_readstack();
|
||||
} break;
|
||||
|
||||
//pop_y
|
||||
case 0xee: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.y = op_readstack();
|
||||
} break;
|
||||
|
||||
//pop_p
|
||||
case 0x8e: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.p = op_readstack();
|
||||
} break;
|
||||
|
||||
//mul_ya
|
||||
case 0xcf: {
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
ya = regs.y * regs.a;
|
||||
regs.a = ya;
|
||||
regs.y = ya >> 8;
|
||||
//result is set based on y (high-byte) only
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
} break;
|
||||
|
||||
//div_ya_x
|
||||
case 0x9e: {
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
ya = regs.ya;
|
||||
//overflow set if quotient >= 256
|
||||
regs.p.v = !!(regs.y >= regs.x);
|
||||
regs.p.h = !!((regs.y & 15) >= (regs.x & 15));
|
||||
if(regs.y < (regs.x << 1)) {
|
||||
//if quotient is <= 511 (will fit into 9-bit result)
|
||||
regs.a = ya / regs.x;
|
||||
regs.y = ya % regs.x;
|
||||
} else {
|
||||
//otherwise, the quotient won't fit into regs.p.v + regs.a
|
||||
//this emulates the odd behavior of the SPC700 in this case
|
||||
regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x);
|
||||
regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x);
|
||||
}
|
||||
//result is set based on a (quotient) only
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
mov_a_x(0x7d, a, x),
|
||||
mov_a_y(0xdd, a, y),
|
||||
mov_x_a(0x5d, x, a),
|
||||
mov_y_a(0xfd, y, a),
|
||||
mov_x_sp(0x9d, x, sp) {
|
||||
1:op_io();
|
||||
regs.$1 = regs.$2;
|
||||
regs.p.n = !!(regs.$1 & 0x80);
|
||||
regs.p.z = (regs.$1 == 0);
|
||||
}
|
||||
|
||||
mov_sp_x(0xbd, sp, x) {
|
||||
1:op_io();
|
||||
regs.$1 = regs.$2;
|
||||
}
|
||||
|
||||
mov_a_const(0xe8, a),
|
||||
mov_x_const(0xcd, x),
|
||||
mov_y_const(0x8d, y) {
|
||||
1:regs.$1 = op_readpc();
|
||||
regs.p.n = !!(regs.$1 & 0x80);
|
||||
regs.p.z = (regs.$1 == 0);
|
||||
}
|
||||
|
||||
mov_a_ix(0xe6) {
|
||||
1:op_io();
|
||||
2:regs.a = op_readdp(regs.x);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
mov_a_ixinc(0xbf) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
3:regs.a = op_readdp(regs.x++);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
mov_a_dp(0xe4, a),
|
||||
mov_x_dp(0xf8, x),
|
||||
mov_y_dp(0xeb, y) {
|
||||
1:sp = op_readpc();
|
||||
2:regs.$1 = op_readdp(sp);
|
||||
regs.p.n = !!(regs.$1 & 0x80);
|
||||
regs.p.z = (regs.$1 == 0);
|
||||
}
|
||||
|
||||
mov_a_dpx(0xf4, a, x),
|
||||
mov_x_dpy(0xf9, x, y),
|
||||
mov_y_dpx(0xfb, y, x) {
|
||||
1:sp = op_readpc();
|
||||
2:op_io();
|
||||
3:regs.$1 = op_readdp(sp + regs.$2);
|
||||
regs.p.n = !!(regs.$1 & 0x80);
|
||||
regs.p.z = (regs.$1 == 0);
|
||||
}
|
||||
|
||||
mov_a_addr(0xe5, a),
|
||||
mov_x_addr(0xe9, x),
|
||||
mov_y_addr(0xec, y) {
|
||||
1:sp = op_readpc();
|
||||
2:sp |= op_readpc() << 8;
|
||||
3:regs.$1 = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.$1 & 0x80);
|
||||
regs.p.z = (regs.$1 == 0);
|
||||
}
|
||||
|
||||
mov_a_addrx(0xf5, x),
|
||||
mov_a_addry(0xf6, y) {
|
||||
1:sp = op_readpc();
|
||||
2:sp |= op_readpc() << 8;
|
||||
3:op_io();
|
||||
4:regs.a = op_readaddr(sp + regs.$1);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
mov_a_idpx(0xe7) {
|
||||
1:dp = op_readpc() + regs.x;
|
||||
2:op_io();
|
||||
3:sp = op_readdp(dp);
|
||||
4:sp |= op_readdp(dp + 1) << 8;
|
||||
5:regs.a = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
mov_a_idpy(0xf7) {
|
||||
1:dp = op_readpc();
|
||||
2:op_io();
|
||||
3:sp = op_readdp(dp);
|
||||
4:sp |= op_readdp(dp + 1) << 8;
|
||||
5:regs.a = op_readaddr(sp + regs.y);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
mov_dp_dp(0xfa) {
|
||||
1:sp = op_readpc();
|
||||
2:dp = op_readpc();
|
||||
3:rd = op_readdp(sp);
|
||||
4:op_writedp(dp, rd);
|
||||
}
|
||||
|
||||
mov_dp_const(0x8f) {
|
||||
1:rd = op_readpc();
|
||||
2:dp = op_readpc();
|
||||
3:op_io();
|
||||
4:op_writedp(dp, rd);
|
||||
}
|
||||
|
||||
mov_ix_a(0xc6) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
3:op_writedp(regs.x, regs.a);
|
||||
}
|
||||
|
||||
mov_ixinc_a(0xaf) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
3:op_writedp(regs.x++, regs.a);
|
||||
}
|
||||
|
||||
mov_dp_a(0xc4, a),
|
||||
mov_dp_x(0xd8, x),
|
||||
mov_dp_y(0xcb, y) {
|
||||
1:dp = op_readpc();
|
||||
2:op_io();
|
||||
3:op_writedp(dp, regs.$1);
|
||||
}
|
||||
|
||||
mov_dpx_a(0xd4, x, a),
|
||||
mov_dpy_x(0xd9, y, x),
|
||||
mov_dpx_y(0xdb, x, y) {
|
||||
1:dp = op_readpc();
|
||||
2:op_io();
|
||||
3:op_io();
|
||||
4:op_writedp(dp + regs.$1, regs.$2);
|
||||
}
|
||||
|
||||
mov_addr_a(0xc5, a),
|
||||
mov_addr_x(0xc9, x),
|
||||
mov_addr_y(0xcc, y) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:op_io();
|
||||
4:op_writeaddr(dp, regs.$1);
|
||||
}
|
||||
|
||||
mov_addrx_a(0xd5, x),
|
||||
mov_addry_a(0xd6, y) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:op_io();
|
||||
4:op_io();
|
||||
5:op_writeaddr(dp + regs.$1, regs.a);
|
||||
}
|
||||
|
||||
mov_idpx_a(0xc7) {
|
||||
1:sp = op_readpc() + regs.x;
|
||||
2:op_io();
|
||||
3:dp = op_readdp(sp);
|
||||
4:dp |= op_readdp(sp + 1) << 8;
|
||||
5:op_io();
|
||||
6:op_writeaddr(dp, regs.a);
|
||||
}
|
||||
|
||||
mov_idpy_a(0xd7) {
|
||||
1:sp = op_readpc();
|
||||
2:op_io();
|
||||
3:dp = op_readdp(sp);
|
||||
4:dp |= op_readdp(sp + 1) << 8;
|
||||
5:op_io();
|
||||
6:op_writeaddr(dp + regs.y, regs.a);
|
||||
}
|
||||
|
||||
movw_ya_dp(0xba) {
|
||||
1:sp = op_readpc();
|
||||
2:op_io();
|
||||
3:regs.a = op_readdp(sp);
|
||||
4:regs.y = op_readdp(sp + 1);
|
||||
regs.p.n = !!(regs.ya & 0x8000);
|
||||
regs.p.z = (regs.ya == 0);
|
||||
}
|
||||
|
||||
movw_dp_ya(0xda) {
|
||||
1:dp = op_readpc();
|
||||
2:op_io();
|
||||
3:op_writedp(dp, regs.a);
|
||||
4:op_writedp(dp + 1, regs.y);
|
||||
}
|
||||
|
||||
mov1_c_bit(0xaa) {
|
||||
1:sp = op_readpc();
|
||||
2:sp |= op_readpc() << 8;
|
||||
3:bit = sp >> 13;
|
||||
sp &= 0x1fff;
|
||||
rd = op_readaddr(sp);
|
||||
regs.p.c = !!(rd & (1 << bit));
|
||||
}
|
||||
|
||||
mov1_bit_c(0xca) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
if(regs.p.c)rd |= (1 << bit);
|
||||
else rd &= ~(1 << bit);
|
||||
4:op_writeaddr(dp, rd);
|
||||
}
|
||||
@@ -0,0 +1,381 @@
|
||||
//mov_a_x
|
||||
case 0x7d: {
|
||||
op_io();
|
||||
regs.a = regs.x;
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
|
||||
//mov_a_y
|
||||
case 0xdd: {
|
||||
op_io();
|
||||
regs.a = regs.y;
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
|
||||
//mov_x_a
|
||||
case 0x5d: {
|
||||
op_io();
|
||||
regs.x = regs.a;
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
} break;
|
||||
|
||||
//mov_y_a
|
||||
case 0xfd: {
|
||||
op_io();
|
||||
regs.y = regs.a;
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
} break;
|
||||
|
||||
//mov_x_sp
|
||||
case 0x9d: {
|
||||
op_io();
|
||||
regs.x = regs.sp;
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
} break;
|
||||
|
||||
//mov_sp_x
|
||||
case 0xbd: {
|
||||
op_io();
|
||||
regs.sp = regs.x;
|
||||
} break;
|
||||
|
||||
//mov_a_const
|
||||
case 0xe8: {
|
||||
regs.a = op_readpc();
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
|
||||
//mov_x_const
|
||||
case 0xcd: {
|
||||
regs.x = op_readpc();
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
} break;
|
||||
|
||||
//mov_y_const
|
||||
case 0x8d: {
|
||||
regs.y = op_readpc();
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
} break;
|
||||
|
||||
//mov_a_ix
|
||||
case 0xe6: {
|
||||
op_io();
|
||||
regs.a = op_readdp(regs.x);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
|
||||
//mov_a_ixinc
|
||||
case 0xbf: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.a = op_readdp(regs.x++);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
|
||||
//mov_a_dp
|
||||
case 0xe4: {
|
||||
sp = op_readpc();
|
||||
regs.a = op_readdp(sp);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
|
||||
//mov_x_dp
|
||||
case 0xf8: {
|
||||
sp = op_readpc();
|
||||
regs.x = op_readdp(sp);
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
} break;
|
||||
|
||||
//mov_y_dp
|
||||
case 0xeb: {
|
||||
sp = op_readpc();
|
||||
regs.y = op_readdp(sp);
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
} break;
|
||||
|
||||
//mov_a_dpx
|
||||
case 0xf4: {
|
||||
sp = op_readpc();
|
||||
op_io();
|
||||
regs.a = op_readdp(sp + regs.x);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
|
||||
//mov_x_dpy
|
||||
case 0xf9: {
|
||||
sp = op_readpc();
|
||||
op_io();
|
||||
regs.x = op_readdp(sp + regs.y);
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
} break;
|
||||
|
||||
//mov_y_dpx
|
||||
case 0xfb: {
|
||||
sp = op_readpc();
|
||||
op_io();
|
||||
regs.y = op_readdp(sp + regs.x);
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
} break;
|
||||
|
||||
//mov_a_addr
|
||||
case 0xe5: {
|
||||
sp = op_readpc();
|
||||
sp |= op_readpc() << 8;
|
||||
regs.a = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
|
||||
//mov_x_addr
|
||||
case 0xe9: {
|
||||
sp = op_readpc();
|
||||
sp |= op_readpc() << 8;
|
||||
regs.x = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
} break;
|
||||
|
||||
//mov_y_addr
|
||||
case 0xec: {
|
||||
sp = op_readpc();
|
||||
sp |= op_readpc() << 8;
|
||||
regs.y = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
} break;
|
||||
|
||||
//mov_a_addrx
|
||||
case 0xf5: {
|
||||
sp = op_readpc();
|
||||
sp |= op_readpc() << 8;
|
||||
op_io();
|
||||
regs.a = op_readaddr(sp + regs.x);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
|
||||
//mov_a_addry
|
||||
case 0xf6: {
|
||||
sp = op_readpc();
|
||||
sp |= op_readpc() << 8;
|
||||
op_io();
|
||||
regs.a = op_readaddr(sp + regs.y);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
|
||||
//mov_a_idpx
|
||||
case 0xe7: {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
regs.a = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
|
||||
//mov_a_idpy
|
||||
case 0xf7: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
regs.a = op_readaddr(sp + regs.y);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
|
||||
//mov_dp_dp
|
||||
case 0xfa: {
|
||||
sp = op_readpc();
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(sp);
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//mov_dp_const
|
||||
case 0x8f: {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//mov_ix_a
|
||||
case 0xc6: {
|
||||
op_io();
|
||||
op_io();
|
||||
op_writedp(regs.x, regs.a);
|
||||
} break;
|
||||
|
||||
//mov_ixinc_a
|
||||
case 0xaf: {
|
||||
op_io();
|
||||
op_io();
|
||||
op_writedp(regs.x++, regs.a);
|
||||
} break;
|
||||
|
||||
//mov_dp_a
|
||||
case 0xc4: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
op_writedp(dp, regs.a);
|
||||
} break;
|
||||
|
||||
//mov_dp_x
|
||||
case 0xd8: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
op_writedp(dp, regs.x);
|
||||
} break;
|
||||
|
||||
//mov_dp_y
|
||||
case 0xcb: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
op_writedp(dp, regs.y);
|
||||
} break;
|
||||
|
||||
//mov_dpx_a
|
||||
case 0xd4: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writedp(dp + regs.x, regs.a);
|
||||
} break;
|
||||
|
||||
//mov_dpy_x
|
||||
case 0xd9: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writedp(dp + regs.y, regs.x);
|
||||
} break;
|
||||
|
||||
//mov_dpx_y
|
||||
case 0xdb: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writedp(dp + regs.x, regs.y);
|
||||
} break;
|
||||
|
||||
//mov_addr_a
|
||||
case 0xc5: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
op_writeaddr(dp, regs.a);
|
||||
} break;
|
||||
|
||||
//mov_addr_x
|
||||
case 0xc9: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
op_writeaddr(dp, regs.x);
|
||||
} break;
|
||||
|
||||
//mov_addr_y
|
||||
case 0xcc: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
op_writeaddr(dp, regs.y);
|
||||
} break;
|
||||
|
||||
//mov_addrx_a
|
||||
case 0xd5: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_writeaddr(dp + regs.x, regs.a);
|
||||
} break;
|
||||
|
||||
//mov_addry_a
|
||||
case 0xd6: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_writeaddr(dp + regs.y, regs.a);
|
||||
} break;
|
||||
|
||||
//mov_idpx_a
|
||||
case 0xc7: {
|
||||
sp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
dp = op_readdp(sp);
|
||||
dp |= op_readdp(sp + 1) << 8;
|
||||
op_io();
|
||||
op_writeaddr(dp, regs.a);
|
||||
} break;
|
||||
|
||||
//mov_idpy_a
|
||||
case 0xd7: {
|
||||
sp = op_readpc();
|
||||
op_io();
|
||||
dp = op_readdp(sp);
|
||||
dp |= op_readdp(sp + 1) << 8;
|
||||
op_io();
|
||||
op_writeaddr(dp + regs.y, regs.a);
|
||||
} break;
|
||||
|
||||
//movw_ya_dp
|
||||
case 0xba: {
|
||||
sp = op_readpc();
|
||||
op_io();
|
||||
regs.a = op_readdp(sp);
|
||||
regs.y = op_readdp(sp + 1);
|
||||
regs.p.n = !!(regs.ya & 0x8000);
|
||||
regs.p.z = (regs.ya == 0);
|
||||
} break;
|
||||
|
||||
//movw_dp_ya
|
||||
case 0xda: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
op_writedp(dp, regs.a);
|
||||
op_writedp(dp + 1, regs.y);
|
||||
} break;
|
||||
|
||||
//mov1_c_bit
|
||||
case 0xaa: {
|
||||
sp = op_readpc();
|
||||
sp |= op_readpc() << 8;
|
||||
bit = sp >> 13;
|
||||
sp &= 0x1fff;
|
||||
rd = op_readaddr(sp);
|
||||
regs.p.c = !!(rd & (1 << bit));
|
||||
} break;
|
||||
|
||||
//mov1_bit_c
|
||||
case 0xca: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
if(regs.p.c)rd |= (1 << bit);
|
||||
else rd &= ~(1 << bit);
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
bra(0x2f, 0),
|
||||
beq(0xf0, !regs.p.z),
|
||||
bne(0xd0, regs.p.z),
|
||||
bcs(0xb0, !regs.p.c),
|
||||
bcc(0x90, regs.p.c),
|
||||
bvs(0x70, !regs.p.v),
|
||||
bvc(0x50, regs.p.v),
|
||||
bmi(0x30, !regs.p.n),
|
||||
bpl(0x10, regs.p.n) {
|
||||
1:rd = op_readpc();
|
||||
if($1)end;
|
||||
2:op_io();
|
||||
3:op_io();
|
||||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
bbs0(0x03, 0x01, !=),
|
||||
bbc0(0x13, 0x01, ==),
|
||||
bbs1(0x23, 0x02, !=),
|
||||
bbc1(0x33, 0x02, ==),
|
||||
bbs2(0x43, 0x04, !=),
|
||||
bbc2(0x53, 0x04, ==),
|
||||
bbs3(0x63, 0x08, !=),
|
||||
bbc3(0x73, 0x08, ==),
|
||||
bbs4(0x83, 0x10, !=),
|
||||
bbc4(0x93, 0x10, ==),
|
||||
bbs5(0xa3, 0x20, !=),
|
||||
bbc5(0xb3, 0x20, ==),
|
||||
bbs6(0xc3, 0x40, !=),
|
||||
bbc6(0xd3, 0x40, ==),
|
||||
bbs7(0xe3, 0x80, !=),
|
||||
bbc7(0xf3, 0x80, ==) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readpc();
|
||||
3:sp = op_readdp(dp);
|
||||
4:op_io();
|
||||
if((sp & $1) $2 $1)end;
|
||||
5:op_io();
|
||||
6:op_io();
|
||||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
cbne_dp(0x2e) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readpc();
|
||||
3:sp = op_readdp(dp);
|
||||
4:op_io();
|
||||
if(regs.a == sp)end;
|
||||
5:op_io();
|
||||
6:op_io();
|
||||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
cbne_dpx(0xde) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readpc();
|
||||
3:op_io();
|
||||
4:sp = op_readdp(dp + regs.x);
|
||||
5:op_io();
|
||||
if(regs.a == sp)end;
|
||||
6:op_io();
|
||||
7:op_io();
|
||||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
dbnz_dp(0x6e) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readpc();
|
||||
3:wr = op_readdp(dp);
|
||||
wr--;
|
||||
4:op_writedp(dp, wr);
|
||||
if(wr == 0x00)end;
|
||||
5:op_io();
|
||||
6:op_io();
|
||||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
dbnz_y(0xfe) {
|
||||
1:rd = op_readpc();
|
||||
2:op_io();
|
||||
regs.y--;
|
||||
3:op_io();
|
||||
if(regs.y == 0x00)end;
|
||||
4:op_io();
|
||||
5:op_io();
|
||||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
jmp_addr(0x5f) {
|
||||
1:rd = op_readpc();
|
||||
2:rd |= op_readpc() << 8;
|
||||
regs.pc = rd;
|
||||
}
|
||||
|
||||
jmp_iaddrx(0x1f) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:op_io();
|
||||
dp += regs.x;
|
||||
4:rd = op_readaddr(dp);
|
||||
5:rd |= op_readaddr(dp + 1) << 8;
|
||||
regs.pc = rd;
|
||||
}
|
||||
|
||||
call(0x3f) {
|
||||
1:rd = op_readpc();
|
||||
2:rd |= op_readpc() << 8;
|
||||
3:op_io();
|
||||
4:op_io();
|
||||
5:op_io();
|
||||
6:op_writestack(regs.pc >> 8);
|
||||
7:op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
}
|
||||
|
||||
pcall(0x4f) {
|
||||
1:rd = op_readpc();
|
||||
2:op_io();
|
||||
3:op_io();
|
||||
4:op_writestack(regs.pc >> 8);
|
||||
5:op_writestack(regs.pc);
|
||||
regs.pc = 0xff00 | rd;
|
||||
}
|
||||
|
||||
tcall_0(0x01, 0),
|
||||
tcall_1(0x11, 1),
|
||||
tcall_2(0x21, 2),
|
||||
tcall_3(0x31, 3),
|
||||
tcall_4(0x41, 4),
|
||||
tcall_5(0x51, 5),
|
||||
tcall_6(0x61, 6),
|
||||
tcall_7(0x71, 7),
|
||||
tcall_8(0x81, 8),
|
||||
tcall_9(0x91, 9),
|
||||
tcall_10(0xa1, 10),
|
||||
tcall_11(0xb1, 11),
|
||||
tcall_12(0xc1, 12),
|
||||
tcall_13(0xd1, 13),
|
||||
tcall_14(0xe1, 14),
|
||||
tcall_15(0xf1, 15) {
|
||||
1:dp = 0xffde - ($1 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
2:rd |= op_readaddr(dp + 1) << 8;
|
||||
3:op_io();
|
||||
4:op_io();
|
||||
5:op_io();
|
||||
6:op_writestack(regs.pc >> 8);
|
||||
7:op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
}
|
||||
|
||||
brk(0x0f) {
|
||||
1:rd = op_readaddr(0xffde);
|
||||
2:rd |= op_readaddr(0xffdf) << 8;
|
||||
3:op_io();
|
||||
4:op_io();
|
||||
5:op_writestack(regs.pc >> 8);
|
||||
6:op_writestack(regs.pc);
|
||||
7:op_writestack(regs.p);
|
||||
regs.pc = rd;
|
||||
regs.p.b = 1;
|
||||
regs.p.i = 0;
|
||||
}
|
||||
|
||||
ret(0x6f) {
|
||||
1:rd = op_readstack();
|
||||
2:rd |= op_readstack() << 8;
|
||||
3:op_io();
|
||||
4:op_io();
|
||||
regs.pc = rd;
|
||||
}
|
||||
|
||||
reti(0x7f) {
|
||||
1:regs.p = op_readstack();
|
||||
2:rd = op_readstack();
|
||||
3:rd |= op_readstack() << 8;
|
||||
4:op_io();
|
||||
5:op_io();
|
||||
regs.pc = rd;
|
||||
}
|
||||
@@ -0,0 +1,604 @@
|
||||
//bra
|
||||
case 0x2f: {
|
||||
rd = op_readpc();
|
||||
if(0)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//beq
|
||||
case 0xf0: {
|
||||
rd = op_readpc();
|
||||
if(!regs.p.z)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bne
|
||||
case 0xd0: {
|
||||
rd = op_readpc();
|
||||
if(regs.p.z)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bcs
|
||||
case 0xb0: {
|
||||
rd = op_readpc();
|
||||
if(!regs.p.c)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bcc
|
||||
case 0x90: {
|
||||
rd = op_readpc();
|
||||
if(regs.p.c)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bvs
|
||||
case 0x70: {
|
||||
rd = op_readpc();
|
||||
if(!regs.p.v)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bvc
|
||||
case 0x50: {
|
||||
rd = op_readpc();
|
||||
if(regs.p.v)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bmi
|
||||
case 0x30: {
|
||||
rd = op_readpc();
|
||||
if(!regs.p.n)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bpl
|
||||
case 0x10: {
|
||||
rd = op_readpc();
|
||||
if(regs.p.n)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bbs0
|
||||
case 0x03: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
op_io();
|
||||
if((sp & 0x01) != 0x01)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bbc0
|
||||
case 0x13: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
op_io();
|
||||
if((sp & 0x01) == 0x01)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bbs1
|
||||
case 0x23: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
op_io();
|
||||
if((sp & 0x02) != 0x02)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bbc1
|
||||
case 0x33: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
op_io();
|
||||
if((sp & 0x02) == 0x02)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bbs2
|
||||
case 0x43: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
op_io();
|
||||
if((sp & 0x04) != 0x04)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bbc2
|
||||
case 0x53: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
op_io();
|
||||
if((sp & 0x04) == 0x04)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bbs3
|
||||
case 0x63: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
op_io();
|
||||
if((sp & 0x08) != 0x08)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bbc3
|
||||
case 0x73: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
op_io();
|
||||
if((sp & 0x08) == 0x08)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bbs4
|
||||
case 0x83: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
op_io();
|
||||
if((sp & 0x10) != 0x10)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bbc4
|
||||
case 0x93: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
op_io();
|
||||
if((sp & 0x10) == 0x10)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bbs5
|
||||
case 0xa3: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
op_io();
|
||||
if((sp & 0x20) != 0x20)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bbc5
|
||||
case 0xb3: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
op_io();
|
||||
if((sp & 0x20) == 0x20)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bbs6
|
||||
case 0xc3: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
op_io();
|
||||
if((sp & 0x40) != 0x40)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bbc6
|
||||
case 0xd3: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
op_io();
|
||||
if((sp & 0x40) == 0x40)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bbs7
|
||||
case 0xe3: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
op_io();
|
||||
if((sp & 0x80) != 0x80)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//bbc7
|
||||
case 0xf3: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
op_io();
|
||||
if((sp & 0x80) == 0x80)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//cbne_dp
|
||||
case 0x2e: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
op_io();
|
||||
if(regs.a == sp)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//cbne_dpx
|
||||
case 0xde: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp + regs.x);
|
||||
op_io();
|
||||
if(regs.a == sp)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//dbnz_dp
|
||||
case 0x6e: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr--;
|
||||
op_writedp(dp, wr);
|
||||
if(wr == 0x00)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//dbnz_y
|
||||
case 0xfe: {
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
regs.y--;
|
||||
op_io();
|
||||
if(regs.y == 0x00)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//jmp_addr
|
||||
case 0x5f: {
|
||||
rd = op_readpc();
|
||||
rd |= op_readpc() << 8;
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//jmp_iaddrx
|
||||
case 0x1f: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
dp += regs.x;
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//call
|
||||
case 0x3f: {
|
||||
rd = op_readpc();
|
||||
rd |= op_readpc() << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//pcall
|
||||
case 0x4f: {
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = 0xff00 | rd;
|
||||
} break;
|
||||
|
||||
//tcall_0
|
||||
case 0x01: {
|
||||
dp = 0xffde - (0 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//tcall_1
|
||||
case 0x11: {
|
||||
dp = 0xffde - (1 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//tcall_2
|
||||
case 0x21: {
|
||||
dp = 0xffde - (2 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//tcall_3
|
||||
case 0x31: {
|
||||
dp = 0xffde - (3 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//tcall_4
|
||||
case 0x41: {
|
||||
dp = 0xffde - (4 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//tcall_5
|
||||
case 0x51: {
|
||||
dp = 0xffde - (5 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//tcall_6
|
||||
case 0x61: {
|
||||
dp = 0xffde - (6 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//tcall_7
|
||||
case 0x71: {
|
||||
dp = 0xffde - (7 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//tcall_8
|
||||
case 0x81: {
|
||||
dp = 0xffde - (8 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//tcall_9
|
||||
case 0x91: {
|
||||
dp = 0xffde - (9 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//tcall_10
|
||||
case 0xa1: {
|
||||
dp = 0xffde - (10 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//tcall_11
|
||||
case 0xb1: {
|
||||
dp = 0xffde - (11 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//tcall_12
|
||||
case 0xc1: {
|
||||
dp = 0xffde - (12 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//tcall_13
|
||||
case 0xd1: {
|
||||
dp = 0xffde - (13 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//tcall_14
|
||||
case 0xe1: {
|
||||
dp = 0xffde - (14 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//tcall_15
|
||||
case 0xf1: {
|
||||
dp = 0xffde - (15 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//brk
|
||||
case 0x0f: {
|
||||
rd = op_readaddr(0xffde);
|
||||
rd |= op_readaddr(0xffdf) << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
op_writestack(regs.p);
|
||||
regs.pc = rd;
|
||||
regs.p.b = 1;
|
||||
regs.p.i = 0;
|
||||
} break;
|
||||
|
||||
//ret
|
||||
case 0x6f: {
|
||||
rd = op_readstack();
|
||||
rd |= op_readstack() << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
//reti
|
||||
case 0x7f: {
|
||||
regs.p = op_readstack();
|
||||
rd = op_readstack();
|
||||
rd |= op_readstack() << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
adc_a_const(0x88, adc, a),
|
||||
and_a_const(0x28, and, a),
|
||||
cmp_a_const(0x68, cmp, a),
|
||||
cmp_x_const(0xc8, cmp, x),
|
||||
cmp_y_const(0xad, cmp, y),
|
||||
eor_a_const(0x48, eor, a),
|
||||
or_a_const(0x08, or, a),
|
||||
sbc_a_const(0xa8, sbc, a) {
|
||||
1:rd = op_readpc();
|
||||
regs.$2 = op_$1(regs.$2, rd);
|
||||
}
|
||||
|
||||
adc_a_ix(0x86, adc),
|
||||
and_a_ix(0x26, and),
|
||||
cmp_a_ix(0x66, cmp),
|
||||
eor_a_ix(0x46, eor),
|
||||
or_a_ix(0x06, or),
|
||||
sbc_a_ix(0xa6, sbc) {
|
||||
1:rd = op_readdp(regs.x);
|
||||
2:op_io();
|
||||
regs.a = op_$1(regs.a, rd);
|
||||
}
|
||||
|
||||
adc_a_dp(0x84, adc, a),
|
||||
and_a_dp(0x24, and, a),
|
||||
cmp_a_dp(0x64, cmp, a),
|
||||
cmp_x_dp(0x3e, cmp, x),
|
||||
cmp_y_dp(0x7e, cmp, y),
|
||||
eor_a_dp(0x44, eor, a),
|
||||
or_a_dp(0x04, or, a),
|
||||
sbc_a_dp(0xa4, sbc, a) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readdp(dp);
|
||||
regs.$2 = op_$1(regs.$2, rd);
|
||||
}
|
||||
|
||||
adc_a_dpx(0x94, adc),
|
||||
and_a_dpx(0x34, and),
|
||||
cmp_a_dpx(0x74, cmp),
|
||||
eor_a_dpx(0x54, eor),
|
||||
or_a_dpx(0x14, or),
|
||||
sbc_a_dpx(0xb4, sbc) {
|
||||
1:dp = op_readpc();
|
||||
2:op_io();
|
||||
3:rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_$1(regs.a, rd);
|
||||
}
|
||||
|
||||
adc_a_addr(0x85, adc, a),
|
||||
and_a_addr(0x25, and, a),
|
||||
cmp_a_addr(0x65, cmp, a),
|
||||
cmp_x_addr(0x1e, cmp, x),
|
||||
cmp_y_addr(0x5e, cmp, y),
|
||||
eor_a_addr(0x45, eor, a),
|
||||
or_a_addr(0x05, or, a),
|
||||
sbc_a_addr(0xa5, sbc, a) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:rd = op_readaddr(dp);
|
||||
regs.$2 = op_$1(regs.$2, rd);
|
||||
}
|
||||
|
||||
adc_a_addrx(0x95, adc, x),
|
||||
adc_a_addry(0x96, adc, y),
|
||||
and_a_addrx(0x35, and, x),
|
||||
and_a_addry(0x36, and, y),
|
||||
cmp_a_addrx(0x75, cmp, x),
|
||||
cmp_a_addry(0x76, cmp, y),
|
||||
eor_a_addrx(0x55, eor, x),
|
||||
eor_a_addry(0x56, eor, y),
|
||||
or_a_addrx(0x15, or, x),
|
||||
or_a_addry(0x16, or, y),
|
||||
sbc_a_addrx(0xb5, sbc, x),
|
||||
sbc_a_addry(0xb6, sbc, y) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:op_io();
|
||||
4:rd = op_readaddr(dp + regs.$2);
|
||||
regs.a = op_$1(regs.a, rd);
|
||||
}
|
||||
|
||||
adc_a_idpx(0x87, adc),
|
||||
and_a_idpx(0x27, and),
|
||||
cmp_a_idpx(0x67, cmp),
|
||||
eor_a_idpx(0x47, eor),
|
||||
or_a_idpx(0x07, or),
|
||||
sbc_a_idpx(0xa7, sbc) {
|
||||
1:dp = op_readpc() + regs.x;
|
||||
2:op_io();
|
||||
3:sp = op_readdp(dp);
|
||||
4:sp |= op_readdp(dp + 1) << 8;
|
||||
5:rd = op_readaddr(sp);
|
||||
regs.a = op_$1(regs.a, rd);
|
||||
}
|
||||
|
||||
adc_a_idpy(0x97, adc),
|
||||
and_a_idpy(0x37, and),
|
||||
cmp_a_idpy(0x77, cmp),
|
||||
eor_a_idpy(0x57, eor),
|
||||
or_a_idpy(0x17, or),
|
||||
sbc_a_idpy(0xb7, sbc) {
|
||||
1:dp = op_readpc();
|
||||
2:op_io();
|
||||
3:sp = op_readdp(dp);
|
||||
4:sp |= op_readdp(dp + 1) << 8;
|
||||
5:rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_$1(regs.a, rd);
|
||||
}
|
||||
|
||||
adc_ix_iy(0x99, adc, 1),
|
||||
and_ix_iy(0x39, and, 1),
|
||||
cmp_ix_iy(0x79, cmp, 0),
|
||||
eor_ix_iy(0x59, eor, 1),
|
||||
or_ix_iy(0x19, or, 1),
|
||||
sbc_ix_iy(0xb9, sbc, 1) {
|
||||
1:wr = op_readdp(regs.x);
|
||||
2:rd = op_readdp(regs.y);
|
||||
3:op_io();
|
||||
wr = op_$1(wr, rd);
|
||||
4:($2) ? op_writedp(regs.x, wr) : op_io();
|
||||
}
|
||||
|
||||
adc_dp_dp(0x89, adc, 1),
|
||||
and_dp_dp(0x29, and, 1),
|
||||
cmp_dp_dp(0x69, cmp, 0),
|
||||
eor_dp_dp(0x49, eor, 1),
|
||||
or_dp_dp(0x09, or, 1),
|
||||
sbc_dp_dp(0xa9, sbc, 1) {
|
||||
1:sp = op_readpc();
|
||||
2:dp = op_readpc();
|
||||
3:wr = op_readdp(dp);
|
||||
4:rd = op_readdp(sp);
|
||||
5:wr = op_$1(wr, rd);
|
||||
($2) ? op_writedp(dp, wr) : op_io();
|
||||
}
|
||||
|
||||
adc_dp_const(0x98, adc, 1),
|
||||
and_dp_const(0x38, and, 1),
|
||||
cmp_dp_const(0x78, cmp, 0),
|
||||
eor_dp_const(0x58, eor, 1),
|
||||
or_dp_const(0x18, or, 1),
|
||||
sbc_dp_const(0xb8, sbc, 1) {
|
||||
1:rd = op_readpc();
|
||||
2:dp = op_readpc();
|
||||
3:wr = op_readdp(dp);
|
||||
4:wr = op_$1(wr, rd);
|
||||
($2) ? op_writedp(dp, wr) : op_io();
|
||||
}
|
||||
|
||||
addw_ya_dp(0x7a, addw),
|
||||
cmpw_ya_dp(0x5a, cmpw),
|
||||
subw_ya_dp(0x9a, subw) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readdp(dp);
|
||||
3:rd |= op_readdp(dp + 1) << 8;
|
||||
4:op_io();
|
||||
regs.ya = op_$1(regs.ya, rd);
|
||||
}
|
||||
|
||||
and1_bit(0x4a, !!),
|
||||
and1_notbit(0x6a, !) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
regs.p.c = regs.p.c & $1(rd & (1 << bit));
|
||||
}
|
||||
|
||||
eor1_bit(0x8a) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
4:op_io();
|
||||
regs.p.c = regs.p.c ^ !!(rd & (1 << bit));
|
||||
}
|
||||
|
||||
not1_bit(0xea) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
rd ^= (1 << bit);
|
||||
4:op_writeaddr(dp, rd);
|
||||
}
|
||||
|
||||
or1_bit(0x0a, !!),
|
||||
or1_notbit(0x2a, !) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
4:op_io();
|
||||
regs.p.c = regs.p.c | $1(rd & (1 << bit));
|
||||
}
|
||||
@@ -0,0 +1,745 @@
|
||||
//adc_a_const
|
||||
case 0x88: {
|
||||
rd = op_readpc();
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//and_a_const
|
||||
case 0x28: {
|
||||
rd = op_readpc();
|
||||
regs.a = op_and(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//cmp_a_const
|
||||
case 0x68: {
|
||||
rd = op_readpc();
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//cmp_x_const
|
||||
case 0xc8: {
|
||||
rd = op_readpc();
|
||||
regs.x = op_cmp(regs.x, rd);
|
||||
} break;
|
||||
|
||||
//cmp_y_const
|
||||
case 0xad: {
|
||||
rd = op_readpc();
|
||||
regs.y = op_cmp(regs.y, rd);
|
||||
} break;
|
||||
|
||||
//eor_a_const
|
||||
case 0x48: {
|
||||
rd = op_readpc();
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//or_a_const
|
||||
case 0x08: {
|
||||
rd = op_readpc();
|
||||
regs.a = op_or(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//sbc_a_const
|
||||
case 0xa8: {
|
||||
rd = op_readpc();
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//adc_a_ix
|
||||
case 0x86: {
|
||||
rd = op_readdp(regs.x);
|
||||
op_io();
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//and_a_ix
|
||||
case 0x26: {
|
||||
rd = op_readdp(regs.x);
|
||||
op_io();
|
||||
regs.a = op_and(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//cmp_a_ix
|
||||
case 0x66: {
|
||||
rd = op_readdp(regs.x);
|
||||
op_io();
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//eor_a_ix
|
||||
case 0x46: {
|
||||
rd = op_readdp(regs.x);
|
||||
op_io();
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//or_a_ix
|
||||
case 0x06: {
|
||||
rd = op_readdp(regs.x);
|
||||
op_io();
|
||||
regs.a = op_or(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//sbc_a_ix
|
||||
case 0xa6: {
|
||||
rd = op_readdp(regs.x);
|
||||
op_io();
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//adc_a_dp
|
||||
case 0x84: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//and_a_dp
|
||||
case 0x24: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//cmp_a_dp
|
||||
case 0x64: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//cmp_x_dp
|
||||
case 0x3e: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.x = op_cmp(regs.x, rd);
|
||||
} break;
|
||||
|
||||
//cmp_y_dp
|
||||
case 0x7e: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.y = op_cmp(regs.y, rd);
|
||||
} break;
|
||||
|
||||
//eor_a_dp
|
||||
case 0x44: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//or_a_dp
|
||||
case 0x04: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//sbc_a_dp
|
||||
case 0xa4: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//adc_a_dpx
|
||||
case 0x94: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//and_a_dpx
|
||||
case 0x34: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//cmp_a_dpx
|
||||
case 0x74: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//eor_a_dpx
|
||||
case 0x54: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//or_a_dpx
|
||||
case 0x14: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//sbc_a_dpx
|
||||
case 0xb4: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//adc_a_addr
|
||||
case 0x85: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//and_a_addr
|
||||
case 0x25: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//cmp_a_addr
|
||||
case 0x65: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//cmp_x_addr
|
||||
case 0x1e: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.x = op_cmp(regs.x, rd);
|
||||
} break;
|
||||
|
||||
//cmp_y_addr
|
||||
case 0x5e: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.y = op_cmp(regs.y, rd);
|
||||
} break;
|
||||
|
||||
//eor_a_addr
|
||||
case 0x45: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//or_a_addr
|
||||
case 0x05: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//sbc_a_addr
|
||||
case 0xa5: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//adc_a_addrx
|
||||
case 0x95: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.x);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//adc_a_addry
|
||||
case 0x96: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.y);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//and_a_addrx
|
||||
case 0x35: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.x);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//and_a_addry
|
||||
case 0x36: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.y);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//cmp_a_addrx
|
||||
case 0x75: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.x);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//cmp_a_addry
|
||||
case 0x76: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.y);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//eor_a_addrx
|
||||
case 0x55: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.x);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//eor_a_addry
|
||||
case 0x56: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.y);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//or_a_addrx
|
||||
case 0x15: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.x);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//or_a_addry
|
||||
case 0x16: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.y);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//sbc_a_addrx
|
||||
case 0xb5: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.x);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//sbc_a_addry
|
||||
case 0xb6: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.y);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//adc_a_idpx
|
||||
case 0x87: {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//and_a_idpx
|
||||
case 0x27: {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//cmp_a_idpx
|
||||
case 0x67: {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//eor_a_idpx
|
||||
case 0x47: {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//or_a_idpx
|
||||
case 0x07: {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//sbc_a_idpx
|
||||
case 0xa7: {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//adc_a_idpy
|
||||
case 0x97: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//and_a_idpy
|
||||
case 0x37: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//cmp_a_idpy
|
||||
case 0x77: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//eor_a_idpy
|
||||
case 0x57: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//or_a_idpy
|
||||
case 0x17: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//sbc_a_idpy
|
||||
case 0xb7: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
} break;
|
||||
|
||||
//adc_ix_iy
|
||||
case 0x99: {
|
||||
wr = op_readdp(regs.x);
|
||||
rd = op_readdp(regs.y);
|
||||
op_io();
|
||||
wr = op_adc(wr, rd);
|
||||
(1) ? op_writedp(regs.x, wr) : op_io();
|
||||
} break;
|
||||
|
||||
//and_ix_iy
|
||||
case 0x39: {
|
||||
wr = op_readdp(regs.x);
|
||||
rd = op_readdp(regs.y);
|
||||
op_io();
|
||||
wr = op_and(wr, rd);
|
||||
(1) ? op_writedp(regs.x, wr) : op_io();
|
||||
} break;
|
||||
|
||||
//cmp_ix_iy
|
||||
case 0x79: {
|
||||
wr = op_readdp(regs.x);
|
||||
rd = op_readdp(regs.y);
|
||||
op_io();
|
||||
wr = op_cmp(wr, rd);
|
||||
(0) ? op_writedp(regs.x, wr) : op_io();
|
||||
} break;
|
||||
|
||||
//eor_ix_iy
|
||||
case 0x59: {
|
||||
wr = op_readdp(regs.x);
|
||||
rd = op_readdp(regs.y);
|
||||
op_io();
|
||||
wr = op_eor(wr, rd);
|
||||
(1) ? op_writedp(regs.x, wr) : op_io();
|
||||
} break;
|
||||
|
||||
//or_ix_iy
|
||||
case 0x19: {
|
||||
wr = op_readdp(regs.x);
|
||||
rd = op_readdp(regs.y);
|
||||
op_io();
|
||||
wr = op_or(wr, rd);
|
||||
(1) ? op_writedp(regs.x, wr) : op_io();
|
||||
} break;
|
||||
|
||||
//sbc_ix_iy
|
||||
case 0xb9: {
|
||||
wr = op_readdp(regs.x);
|
||||
rd = op_readdp(regs.y);
|
||||
op_io();
|
||||
wr = op_sbc(wr, rd);
|
||||
(1) ? op_writedp(regs.x, wr) : op_io();
|
||||
} break;
|
||||
|
||||
//adc_dp_dp
|
||||
case 0x89: {
|
||||
sp = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
rd = op_readdp(sp);
|
||||
wr = op_adc(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
|
||||
//and_dp_dp
|
||||
case 0x29: {
|
||||
sp = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
rd = op_readdp(sp);
|
||||
wr = op_and(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
|
||||
//cmp_dp_dp
|
||||
case 0x69: {
|
||||
sp = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
rd = op_readdp(sp);
|
||||
wr = op_cmp(wr, rd);
|
||||
(0) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
|
||||
//eor_dp_dp
|
||||
case 0x49: {
|
||||
sp = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
rd = op_readdp(sp);
|
||||
wr = op_eor(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
|
||||
//or_dp_dp
|
||||
case 0x09: {
|
||||
sp = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
rd = op_readdp(sp);
|
||||
wr = op_or(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
|
||||
//sbc_dp_dp
|
||||
case 0xa9: {
|
||||
sp = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
rd = op_readdp(sp);
|
||||
wr = op_sbc(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
|
||||
//adc_dp_const
|
||||
case 0x98: {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_adc(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
|
||||
//and_dp_const
|
||||
case 0x38: {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_and(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
|
||||
//cmp_dp_const
|
||||
case 0x78: {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_cmp(wr, rd);
|
||||
(0) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
|
||||
//eor_dp_const
|
||||
case 0x58: {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_eor(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
|
||||
//or_dp_const
|
||||
case 0x18: {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_or(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
|
||||
//sbc_dp_const
|
||||
case 0xb8: {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_sbc(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
|
||||
//addw_ya_dp
|
||||
case 0x7a: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= op_readdp(dp + 1) << 8;
|
||||
op_io();
|
||||
regs.ya = op_addw(regs.ya, rd);
|
||||
} break;
|
||||
|
||||
//cmpw_ya_dp
|
||||
case 0x5a: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= op_readdp(dp + 1) << 8;
|
||||
op_io();
|
||||
regs.ya = op_cmpw(regs.ya, rd);
|
||||
} break;
|
||||
|
||||
//subw_ya_dp
|
||||
case 0x9a: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= op_readdp(dp + 1) << 8;
|
||||
op_io();
|
||||
regs.ya = op_subw(regs.ya, rd);
|
||||
} break;
|
||||
|
||||
//and1_bit
|
||||
case 0x4a: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
regs.p.c = regs.p.c & !!(rd & (1 << bit));
|
||||
} break;
|
||||
|
||||
//and1_notbit
|
||||
case 0x6a: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
regs.p.c = regs.p.c & !(rd & (1 << bit));
|
||||
} break;
|
||||
|
||||
//eor1_bit
|
||||
case 0x8a: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
op_io();
|
||||
regs.p.c = regs.p.c ^ !!(rd & (1 << bit));
|
||||
} break;
|
||||
|
||||
//not1_bit
|
||||
case 0xea: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
rd ^= (1 << bit);
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
|
||||
//or1_bit
|
||||
case 0x0a: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
op_io();
|
||||
regs.p.c = regs.p.c | !!(rd & (1 << bit));
|
||||
} break;
|
||||
|
||||
//or1_notbit
|
||||
case 0x2a: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
op_io();
|
||||
regs.p.c = regs.p.c | !(rd & (1 << bit));
|
||||
} break;
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
inc_a(0xbc, inc, a),
|
||||
inc_x(0x3d, inc, x),
|
||||
inc_y(0xfc, inc, y),
|
||||
dec_a(0x9c, dec, a),
|
||||
dec_x(0x1d, dec, x),
|
||||
dec_y(0xdc, dec, y),
|
||||
asl_a(0x1c, asl, a),
|
||||
lsr_a(0x5c, lsr, a),
|
||||
rol_a(0x3c, rol, a),
|
||||
ror_a(0x7c, ror, a) {
|
||||
1:op_io();
|
||||
regs.$2 = op_$1(regs.$2);
|
||||
}
|
||||
|
||||
inc_dp(0xab, inc),
|
||||
dec_dp(0x8b, dec),
|
||||
asl_dp(0x0b, asl),
|
||||
lsr_dp(0x4b, lsr),
|
||||
rol_dp(0x2b, rol),
|
||||
ror_dp(0x6b, ror) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readdp(dp);
|
||||
3:rd = op_$1(rd);
|
||||
op_writedp(dp, rd);
|
||||
}
|
||||
|
||||
inc_dpx(0xbb, inc),
|
||||
dec_dpx(0x9b, dec),
|
||||
asl_dpx(0x1b, asl),
|
||||
lsr_dpx(0x5b, lsr),
|
||||
rol_dpx(0x3b, rol),
|
||||
ror_dpx(0x7b, ror) {
|
||||
1:dp = op_readpc();
|
||||
2:op_io();
|
||||
3:rd = op_readdp(dp + regs.x);
|
||||
4:rd = op_$1(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
}
|
||||
|
||||
inc_addr(0xac, inc),
|
||||
dec_addr(0x8c, dec),
|
||||
asl_addr(0x0c, asl),
|
||||
lsr_addr(0x4c, lsr),
|
||||
rol_addr(0x2c, rol),
|
||||
ror_addr(0x6c, ror) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:rd = op_readaddr(dp);
|
||||
4:rd = op_$1(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
}
|
||||
|
||||
incw_dp(0x3a, incw),
|
||||
decw_dp(0x1a, decw) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readdp(dp);
|
||||
3:rd |= op_readdp(dp + 1) << 8;
|
||||
4:rd = op_$1(rd);
|
||||
op_writedp(dp + 1, rd >> 8);
|
||||
5:op_writedp(dp, rd);
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
//inc_a
|
||||
case 0xbc: {
|
||||
op_io();
|
||||
regs.a = op_inc(regs.a);
|
||||
} break;
|
||||
|
||||
//inc_x
|
||||
case 0x3d: {
|
||||
op_io();
|
||||
regs.x = op_inc(regs.x);
|
||||
} break;
|
||||
|
||||
//inc_y
|
||||
case 0xfc: {
|
||||
op_io();
|
||||
regs.y = op_inc(regs.y);
|
||||
} break;
|
||||
|
||||
//dec_a
|
||||
case 0x9c: {
|
||||
op_io();
|
||||
regs.a = op_dec(regs.a);
|
||||
} break;
|
||||
|
||||
//dec_x
|
||||
case 0x1d: {
|
||||
op_io();
|
||||
regs.x = op_dec(regs.x);
|
||||
} break;
|
||||
|
||||
//dec_y
|
||||
case 0xdc: {
|
||||
op_io();
|
||||
regs.y = op_dec(regs.y);
|
||||
} break;
|
||||
|
||||
//asl_a
|
||||
case 0x1c: {
|
||||
op_io();
|
||||
regs.a = op_asl(regs.a);
|
||||
} break;
|
||||
|
||||
//lsr_a
|
||||
case 0x5c: {
|
||||
op_io();
|
||||
regs.a = op_lsr(regs.a);
|
||||
} break;
|
||||
|
||||
//rol_a
|
||||
case 0x3c: {
|
||||
op_io();
|
||||
regs.a = op_rol(regs.a);
|
||||
} break;
|
||||
|
||||
//ror_a
|
||||
case 0x7c: {
|
||||
op_io();
|
||||
regs.a = op_ror(regs.a);
|
||||
} break;
|
||||
|
||||
//inc_dp
|
||||
case 0xab: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd = op_inc(rd);
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//dec_dp
|
||||
case 0x8b: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd = op_dec(rd);
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//asl_dp
|
||||
case 0x0b: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd = op_asl(rd);
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//lsr_dp
|
||||
case 0x4b: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd = op_lsr(rd);
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//rol_dp
|
||||
case 0x2b: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd = op_rol(rd);
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//ror_dp
|
||||
case 0x6b: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd = op_ror(rd);
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//inc_dpx
|
||||
case 0xbb: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
rd = op_inc(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
} break;
|
||||
|
||||
//dec_dpx
|
||||
case 0x9b: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
rd = op_dec(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
} break;
|
||||
|
||||
//asl_dpx
|
||||
case 0x1b: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
rd = op_asl(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
} break;
|
||||
|
||||
//lsr_dpx
|
||||
case 0x5b: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
rd = op_lsr(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
} break;
|
||||
|
||||
//rol_dpx
|
||||
case 0x3b: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
rd = op_rol(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
} break;
|
||||
|
||||
//ror_dpx
|
||||
case 0x7b: {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
rd = op_ror(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
} break;
|
||||
|
||||
//inc_addr
|
||||
case 0xac: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
rd = op_inc(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
|
||||
//dec_addr
|
||||
case 0x8c: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
rd = op_dec(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
|
||||
//asl_addr
|
||||
case 0x0c: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
rd = op_asl(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
|
||||
//lsr_addr
|
||||
case 0x4c: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
rd = op_lsr(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
|
||||
//rol_addr
|
||||
case 0x2c: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
rd = op_rol(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
|
||||
//ror_addr
|
||||
case 0x6c: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
rd = op_ror(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
|
||||
//incw_dp
|
||||
case 0x3a: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= op_readdp(dp + 1) << 8;
|
||||
rd = op_incw(rd);
|
||||
op_writedp(dp + 1, rd >> 8);
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
//decw_dp
|
||||
case 0x1a: {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= op_readdp(dp + 1) << 8;
|
||||
rd = op_decw(rd);
|
||||
op_writedp(dp + 1, rd >> 8);
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
uint8 sAPU::op_adc(uint8 x, uint8 y) {
|
||||
int16 r = x + y + regs.p.c;
|
||||
regs.p.n = bool(r & 0x80);
|
||||
regs.p.v = bool(~(x ^ y) & (y ^ (uint8)r) & 0x80);
|
||||
regs.p.h = bool((x ^ y ^ (uint8)r) & 0x10);
|
||||
regs.p.z = ((uint8)r == 0);
|
||||
regs.p.c = (r > 0xff);
|
||||
return r;
|
||||
}
|
||||
|
||||
uint16 sAPU::op_addw(uint16 x, uint16 y) {
|
||||
int16 r;
|
||||
regs.p.c = 0;
|
||||
r = op_adc(x, y);
|
||||
r |= op_adc(x >> 8, y >> 8) << 8;
|
||||
regs.p.z = ((uint16)r == 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
uint8 sAPU::op_and(uint8 x, uint8 y) {
|
||||
x &= y;
|
||||
regs.p.n = bool(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sAPU::op_cmp(uint8 x, uint8 y) {
|
||||
int16 r = x - y;
|
||||
regs.p.n = bool(r & 0x80);
|
||||
regs.p.z = ((uint8)r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint16 sAPU::op_cmpw(uint16 x, uint16 y) {
|
||||
int32 r = x - y;
|
||||
regs.p.n = bool(r & 0x8000);
|
||||
regs.p.z = ((uint16)r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sAPU::op_eor(uint8 x, uint8 y) {
|
||||
x ^= y;
|
||||
regs.p.n = bool(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sAPU::op_or(uint8 x, uint8 y) {
|
||||
x |= y;
|
||||
regs.p.n = bool(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sAPU::op_sbc(uint8 x, uint8 y) {
|
||||
int16 r = x - y - !regs.p.c;
|
||||
regs.p.n = bool(r & 0x80);
|
||||
regs.p.v = bool((x ^ y) & (x ^ (uint8)r) & 0x80);
|
||||
regs.p.h = !((x ^ y ^ (uint8)r) & 0x10);
|
||||
regs.p.z = ((uint8)r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
uint16 sAPU::op_subw(uint16 x, uint16 y) {
|
||||
int16 r;
|
||||
regs.p.c = 1;
|
||||
r = op_sbc(x, y);
|
||||
r |= op_sbc(x >> 8, y >> 8) << 8;
|
||||
regs.p.z = ((uint16)r == 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
uint8 sAPU::op_inc(uint8 x) {
|
||||
x++;
|
||||
regs.p.n = bool(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint16 sAPU::op_incw(uint16 x) {
|
||||
x++;
|
||||
regs.p.n = bool(x & 0x8000);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sAPU::op_dec(uint8 x) {
|
||||
x--;
|
||||
regs.p.n = bool(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint16 sAPU::op_decw(uint16 x) {
|
||||
x--;
|
||||
regs.p.n = bool(x & 0x8000);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sAPU::op_asl(uint8 x) {
|
||||
regs.p.c = bool(x & 0x80);
|
||||
x <<= 1;
|
||||
regs.p.n = bool(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sAPU::op_lsr(uint8 x) {
|
||||
regs.p.c = bool(x & 0x01);
|
||||
x >>= 1;
|
||||
regs.p.n = bool(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sAPU::op_rol(uint8 x) {
|
||||
uint8 c = regs.p.c;
|
||||
regs.p.c = bool(x & 0x80);
|
||||
x <<= 1;
|
||||
x |= c;
|
||||
regs.p.n = bool(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sAPU::op_ror(uint8 x) {
|
||||
uint8 c = (regs.p.c)?0x80:0x00;
|
||||
regs.p.c = bool(x & 0x01);
|
||||
x >>= 1;
|
||||
x |= c;
|
||||
regs.p.n = bool(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#define CLASS_NAME "sAPU"
|
||||
#include "../../../lib/opgen_s.cpp"
|
||||
|
||||
int main() {
|
||||
//fph = fopen("op.h", "wb");
|
||||
//fpt = fopen("optable.cpp", "wb");
|
||||
|
||||
generate("op_mov.cpp", "op_mov.b");
|
||||
generate("op_pc.cpp", "op_pc.b");
|
||||
generate("op_read.cpp", "op_read.b");
|
||||
generate("op_rmw.cpp", "op_rmw.b");
|
||||
generate("op_misc.cpp", "op_misc.b");
|
||||
|
||||
//fclose(fph);
|
||||
//fclose(fpt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
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); }
|
||||
@@ -0,0 +1,24 @@
|
||||
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);
|
||||
@@ -0,0 +1,73 @@
|
||||
#include "../../base.h"
|
||||
|
||||
#include "core/core.cpp"
|
||||
#include "memory/memory.cpp"
|
||||
#include "timing/timing.cpp"
|
||||
|
||||
void sapu_entry_point() {
|
||||
r_apu->main();
|
||||
}
|
||||
|
||||
void sAPU::run() {
|
||||
co_call(thread);
|
||||
}
|
||||
|
||||
void sAPU::power() {
|
||||
memset(spcram, 0x00, 65536);
|
||||
reset();
|
||||
}
|
||||
|
||||
void sAPU::reset() {
|
||||
if(thread)co_delete(thread);
|
||||
thread = co_create(sapu_entry_point, 65536);
|
||||
|
||||
regs.pc = 0xffc0;
|
||||
regs.a = 0x00;
|
||||
regs.x = 0x00;
|
||||
regs.y = 0x00;
|
||||
regs.sp = 0xef;
|
||||
regs.p = 0x02;
|
||||
|
||||
status.clocks_executed = 0;
|
||||
|
||||
//$f1
|
||||
status.iplrom_enabled = true;
|
||||
|
||||
//$f2
|
||||
status.dsp_addr = 0x00;
|
||||
|
||||
t0.enabled = false;
|
||||
t1.enabled = false;
|
||||
t2.enabled = false;
|
||||
|
||||
t0.stage1_ticks = 0;
|
||||
t1.stage1_ticks = 0;
|
||||
t2.stage1_ticks = 0;
|
||||
|
||||
t0.stage2_ticks = 0;
|
||||
t1.stage2_ticks = 0;
|
||||
t2.stage2_ticks = 0;
|
||||
|
||||
t0.stage3_ticks = 0;
|
||||
t1.stage3_ticks = 0;
|
||||
t2.stage3_ticks = 0;
|
||||
}
|
||||
|
||||
sAPU::sAPU() {
|
||||
//#include "core/optable.cpp"
|
||||
|
||||
thread = 0;
|
||||
|
||||
t0.cycle_frequency = 128; //1.024mhz / 8khz = 128
|
||||
t1.cycle_frequency = 128; //1.024mhz / 8khz = 128
|
||||
t2.cycle_frequency = 16; //1.024mhz / 64khz = 16
|
||||
|
||||
//targets not initialized/changed upon reset
|
||||
t0.target = 0;
|
||||
t1.target = 0;
|
||||
t2.target = 0;
|
||||
}
|
||||
|
||||
sAPU::~sAPU() {
|
||||
if(thread)co_delete(thread);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
class sAPU : public APU {
|
||||
public:
|
||||
#include "core/core.h"
|
||||
#include "memory/memory.h"
|
||||
#include "timing/timing.h"
|
||||
|
||||
thread_t thread;
|
||||
|
||||
struct {
|
||||
uint8 opcode;
|
||||
bool in_opcode;
|
||||
|
||||
//timing
|
||||
uint32 clocks_executed;
|
||||
|
||||
//$f1
|
||||
bool iplrom_enabled;
|
||||
|
||||
//$f2
|
||||
uint8 dsp_addr;
|
||||
} status;
|
||||
|
||||
//sapu.cpp
|
||||
void main();
|
||||
|
||||
void run();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
sAPU();
|
||||
~sAPU();
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
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();
|
||||
+59
-23
@@ -1,32 +1,68 @@
|
||||
//platform-independant includes
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#define BSNES_VERSION "0.017"
|
||||
#define BSNES_TITLE "bsnes v" BSNES_VERSION
|
||||
|
||||
//typecasts
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short word;
|
||||
typedef unsigned long ulong;
|
||||
#define MEMCORE bMemBus
|
||||
#define CPUCORE sCPU
|
||||
#define APUCORE sAPU
|
||||
#define DSPCORE bDSP
|
||||
#define PPUCORE bPPU
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned long uint32;
|
||||
//#define FAVOR_ACCURACY
|
||||
#define FAVOR_SPEED
|
||||
|
||||
typedef signed char int8;
|
||||
typedef signed short int16;
|
||||
typedef signed long int32;
|
||||
//game genie + pro action replay code support (~1-3% speed hit)
|
||||
#define CHEAT_SYSTEM
|
||||
|
||||
//structs
|
||||
typedef struct {
|
||||
uint8 *data;
|
||||
uint32 size;
|
||||
}lfile;
|
||||
//enable GZ, ZIP format support
|
||||
#define GZIP_SUPPORT
|
||||
|
||||
//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)
|
||||
//#define POLYMORPHISM
|
||||
|
||||
#if defined(PROCESSOR_X86)
|
||||
#define ARCH_LSB
|
||||
#elif defined(PROCESSOR_X86_64)
|
||||
#define ARCH_LSB
|
||||
#elif defined(PROCESSOR_G5)
|
||||
#define ARCH_MSB
|
||||
#else
|
||||
#error "unsupported processor"
|
||||
#endif
|
||||
|
||||
#include "lib/libbase.h"
|
||||
#include "lib/libco_x86.h"
|
||||
#include "lib/libvector.h"
|
||||
#include "lib/libstring.h"
|
||||
#include "lib/libconfig.h"
|
||||
|
||||
inline uint16 read16(uint8 *addr, uint pos) {
|
||||
#ifdef ARCH_LSB
|
||||
return *((uint16*)(addr + pos));
|
||||
#else
|
||||
return (addr[pos]) | (addr[pos + 1] << 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
//platform-specific global functions
|
||||
void *memalloc(uint32 size, char *name = 0, ...);
|
||||
void memfree(void *mem, char *name = 0, ...);
|
||||
void alert(char *s, ...);
|
||||
void dprintf(char *s, ...);
|
||||
void alert(char *, ...);
|
||||
void dprintf(char *, ...);
|
||||
void dprintf(uint, char *, ...);
|
||||
|
||||
namespace source {
|
||||
enum {
|
||||
none = 0,
|
||||
debug,
|
||||
cpu,
|
||||
apu,
|
||||
};
|
||||
};
|
||||
|
||||
//various class interfaces
|
||||
#include "interface.h"
|
||||
@@ -0,0 +1,364 @@
|
||||
#include "../base.h"
|
||||
#include "database.cpp"
|
||||
|
||||
void Cartridge::read_dbi() {
|
||||
info.srtc = false;
|
||||
info.sdd1 = false;
|
||||
info.c4 = false;
|
||||
info.dsp1 = false;
|
||||
info.dsp2 = false;
|
||||
info.obc1 = false;
|
||||
|
||||
info.dsp1_mapper = 0;
|
||||
|
||||
info.header_index = 0x7fc0;
|
||||
info.mapper = PCB;
|
||||
strcpy(info.name, dbi.name);
|
||||
strcpy(info.pcb, dbi.pcb);
|
||||
info.region = NTSC;
|
||||
info.cart_mmio = false;
|
||||
|
||||
info.rom_size = dbi.rom;
|
||||
info.ram_size = dbi.ram;
|
||||
}
|
||||
|
||||
void Cartridge::read_header() {
|
||||
info.srtc = false;
|
||||
info.sdd1 = false;
|
||||
info.c4 = false;
|
||||
info.dsp1 = false;
|
||||
info.dsp2 = false;
|
||||
info.obc1 = false;
|
||||
|
||||
info.dsp1_mapper = 0;
|
||||
|
||||
if(info.header_index == 0x7fc0 && info.rom_size >= 0x401000) {
|
||||
info.mapper = EXLOROM;
|
||||
strcpy(info.pcb, "UNL-EXLOROM");
|
||||
} else if(info.header_index == 0x7fc0 && rom[info.header_index + MAPPER] == 0x32) {
|
||||
info.mapper = EXLOROM;
|
||||
strcpy(info.pcb, "UNL-EXLOROM");
|
||||
} else if(info.header_index == 0x7fc0) {
|
||||
info.mapper = LOROM;
|
||||
strcpy(info.pcb, "UNL-LOROM");
|
||||
} else if(info.header_index == 0xffc0) {
|
||||
info.mapper = HIROM;
|
||||
strcpy(info.pcb, "UNL-HIROM");
|
||||
} else { //info.header_index == 0x40ffc0
|
||||
info.mapper = EXHIROM;
|
||||
strcpy(info.pcb, "UNL-EXHIROM");
|
||||
}
|
||||
|
||||
uint8 mapper = rom[info.header_index + MAPPER];
|
||||
uint8 rom_type = rom[info.header_index + ROM_TYPE];
|
||||
if(mapper == 0x35 && rom_type == 0x55) {
|
||||
info.srtc = true;
|
||||
}
|
||||
|
||||
if(mapper == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
|
||||
info.sdd1 = true;
|
||||
}
|
||||
|
||||
if(mapper == 0x20 && rom_type == 0xf3) {
|
||||
info.c4 = true;
|
||||
}
|
||||
|
||||
if((mapper == 0x20 || mapper == 0x21) && rom_type == 0x03) {
|
||||
info.dsp1 = true;
|
||||
}
|
||||
|
||||
if(mapper == 0x30 && rom_type == 0x05) {
|
||||
info.dsp1 = true;
|
||||
}
|
||||
|
||||
if(mapper == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) {
|
||||
info.dsp1 = true;
|
||||
}
|
||||
|
||||
if(info.dsp1 == true) {
|
||||
if((mapper & 0x2f) == 0x20 && info.rom_size <= 0x100000) {
|
||||
info.dsp1_mapper = DSP1_LOROM_1MB;
|
||||
} else if((mapper & 0x2f) == 0x20) {
|
||||
info.dsp1_mapper = DSP1_LOROM_2MB;
|
||||
} else if((mapper & 0x2f) == 0x21) {
|
||||
info.dsp1_mapper = DSP1_HIROM;
|
||||
}
|
||||
}
|
||||
|
||||
if(mapper == 0x20 && rom_type == 0x05) {
|
||||
info.dsp2 = true;
|
||||
}
|
||||
|
||||
if(mapper == 0x30 && rom_type == 0x25) {
|
||||
info.obc1 = true;
|
||||
}
|
||||
|
||||
info.cart_mmio = info.c4 | info.dsp1 | info.dsp2 | info.obc1;
|
||||
|
||||
if(rom[info.header_index + SRAM_SIZE] & 7) {
|
||||
info.ram_size = 1024 << (rom[info.header_index + SRAM_SIZE] & 7);
|
||||
} else {
|
||||
info.ram_size = 0;
|
||||
}
|
||||
|
||||
memcpy(&info.name, &rom[info.header_index + CART_NAME], 21);
|
||||
info.name[21] = 0;
|
||||
|
||||
for(int i = 0; i < 22; i++) {
|
||||
if(info.name[i] & 0x80) {
|
||||
info.name[i] = '?';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::find_header() {
|
||||
int32 score_lo = 0,
|
||||
score_hi = 0,
|
||||
score_ex = 0;
|
||||
|
||||
if(info.rom_size < 0x010000) {
|
||||
//cart too small to be anything but lorom
|
||||
info.header_index = 0x007fc0;
|
||||
return;
|
||||
}
|
||||
|
||||
if((rom[0x7fc0 + MAPPER] & ~0x10) == 0x20)score_lo++;
|
||||
if((rom[0xffc0 + MAPPER] & ~0x10) == 0x21)score_hi++;
|
||||
|
||||
if(rom[0x7fc0 + ROM_TYPE] < 0x08)score_lo++;
|
||||
if(rom[0xffc0 + ROM_TYPE] < 0x08)score_hi++;
|
||||
|
||||
if(rom[0x7fc0 + ROM_SIZE] < 0x10)score_lo++;
|
||||
if(rom[0xffc0 + ROM_SIZE] < 0x10)score_hi++;
|
||||
|
||||
if(rom[0x7fc0 + SRAM_SIZE] < 0x08)score_lo++;
|
||||
if(rom[0xffc0 + SRAM_SIZE] < 0x08)score_hi++;
|
||||
|
||||
if(rom[0x7fc0 + REGION] < 14)score_lo++;
|
||||
if(rom[0xffc0 + REGION] < 14)score_hi++;
|
||||
|
||||
if(rom[0x7fc0 + LICENSE] < 3)score_lo++;
|
||||
if(rom[0xffc0 + LICENSE] < 3)score_hi++;
|
||||
|
||||
if(rom[0x7fc0 + RESH] & 0x80)score_lo += 2;
|
||||
if(rom[0xffc0 + RESH] & 0x80)score_hi += 2;
|
||||
|
||||
uint16 cksum, icksum;
|
||||
cksum = rom[0x7fc0 + CKSUM] | (rom[0x7fc0 + CKSUM + 1] << 8);
|
||||
icksum = rom[0x7fc0 + ICKSUM] | (rom[0x7fc0 + ICKSUM + 1] << 8);
|
||||
if((cksum + icksum) == 0xffff && (cksum != 0) && (icksum != 0)) {
|
||||
score_lo += 8;
|
||||
}
|
||||
|
||||
cksum = rom[0xffc0 + CKSUM] | (rom[0xffc0 + CKSUM + 1] << 8);
|
||||
icksum = rom[0xffc0 + ICKSUM] | (rom[0xffc0 + ICKSUM + 1] << 8);
|
||||
if((cksum + icksum) == 0xffff && (cksum != 0) && (icksum != 0)) {
|
||||
score_hi += 8;
|
||||
}
|
||||
|
||||
if(info.rom_size < 0x401000) {
|
||||
score_ex = 0;
|
||||
} else {
|
||||
if(rom[0x7fc0 + MAPPER] == 0x32)score_lo++;
|
||||
else score_ex += 16;
|
||||
}
|
||||
|
||||
if(score_lo >= score_hi && score_lo >= score_ex) {
|
||||
info.header_index = 0x007fc0;
|
||||
} else if(score_hi >= score_ex) {
|
||||
info.header_index = 0x00ffc0;
|
||||
} else {
|
||||
info.header_index = 0x40ffc0;
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::load_sram() {
|
||||
if(info.ram_size == 0) {
|
||||
sram = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
FileReader ff(sram_fn);
|
||||
if(!ff.ready()) {
|
||||
sram = (uint8*)malloc(info.ram_size);
|
||||
memset(sram, 0xff, info.ram_size);
|
||||
return;
|
||||
}
|
||||
|
||||
sram = ff.read(info.ram_size);
|
||||
}
|
||||
|
||||
void Cartridge::save_sram() {
|
||||
if(info.ram_size == 0)return;
|
||||
|
||||
FileWriter ff(sram_fn);
|
||||
if(!ff.ready())return;
|
||||
|
||||
ff.write(sram, info.ram_size);
|
||||
}
|
||||
|
||||
void Cartridge::load_rom(Reader &rf) {
|
||||
uint size = rf.size();
|
||||
bool header = ((size & 0x7fff) == 512);
|
||||
info.rom_size = size - (header ? 512 : 0);
|
||||
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);
|
||||
|
||||
info.crc32 = 0xffffffff;
|
||||
for(int32 i = 0; i < info.rom_size; i++) {
|
||||
info.crc32 = crc32_adjust(info.crc32, rom[i]);
|
||||
}
|
||||
info.crc32 = ~info.crc32;
|
||||
}
|
||||
|
||||
bool Cartridge::load(const char *fn) {
|
||||
if(cart_loaded == true)return false;
|
||||
if(strlen(fn) < 3)return false;
|
||||
|
||||
dprintf("* Loading \"%s\"...", fn);
|
||||
|
||||
strcpy(rom_fn, fn);
|
||||
|
||||
switch(Reader::detect(rom_fn)) {
|
||||
case Reader::RF_NORMAL: {
|
||||
FileReader ff(rom_fn);
|
||||
if(!ff.ready()) {
|
||||
alert("Error loading image file (%s)!", rom_fn);
|
||||
return false;
|
||||
}
|
||||
load_rom(ff);
|
||||
break;
|
||||
}
|
||||
#ifdef GZIP_SUPPORT
|
||||
case Reader::RF_GZ: {
|
||||
GZReader gf(rom_fn);
|
||||
if(!gf.ready()) {
|
||||
alert("Error loading image file (%s)!", rom_fn);
|
||||
return false;
|
||||
}
|
||||
load_rom(gf);
|
||||
break;
|
||||
}
|
||||
case Reader::RF_ZIP: {
|
||||
ZipReader zf(rom_fn);
|
||||
load_rom(zf);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef JMA_SUPPORT
|
||||
case Reader::RF_JMA: {
|
||||
try {
|
||||
JMAReader jf(rom_fn);
|
||||
load_rom(jf);
|
||||
} catch(JMA::jma_errors jma_error) {
|
||||
alert("Error loading image file (%s)!", rom_fn);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//remove ROM extension
|
||||
strcpy(sram_fn, fn);
|
||||
for(int i = strlen(fn) - 1; i >= 0; i--) {
|
||||
if(sram_fn[i] == '.') {
|
||||
sram_fn[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//add SRAM extension
|
||||
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;
|
||||
strcpy(new_fn, sram_fn);
|
||||
replace(new_fn, "\\", "/");
|
||||
split(parts, "/", new_fn);
|
||||
|
||||
//add new SRAM path
|
||||
strcpy(new_fn, config::fs.save_path.sget());
|
||||
|
||||
//append fs.base_path if fs.sram_path is not fully-qualified path
|
||||
if(strbegin(new_fn, "./") == true) {
|
||||
strltrim(new_fn, "./");
|
||||
strcpy(new_fn[1], new_fn[0]);
|
||||
strcpy(new_fn[0], config::fs.base_path.sget());
|
||||
strcat(new_fn[0], new_fn[1]);
|
||||
}
|
||||
|
||||
//finally, append SRAM file name
|
||||
strcat(new_fn, parts[count(parts) - 1]);
|
||||
strcpy(sram_fn, strptr(new_fn));
|
||||
}
|
||||
|
||||
//load cheat file if it exists
|
||||
strcpy(cheat_fn, sram_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);
|
||||
}
|
||||
|
||||
if(read_database() == true) {
|
||||
read_dbi();
|
||||
} else {
|
||||
find_header();
|
||||
read_header();
|
||||
}
|
||||
|
||||
load_sram();
|
||||
cart_loaded = true;
|
||||
|
||||
r_mem->load_cart();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Cartridge::unload() {
|
||||
if(cart_loaded == false)return false;
|
||||
|
||||
r_mem->unload_cart();
|
||||
|
||||
if(base_rom) {
|
||||
SafeFree(base_rom);
|
||||
}
|
||||
|
||||
if(sram) {
|
||||
save_sram();
|
||||
SafeFree(sram);
|
||||
}
|
||||
|
||||
if(cheat.count() > 0 || fexists(cheat_fn)) {
|
||||
FileWriter ff(cheat_fn);
|
||||
cheat.save(ff);
|
||||
cheat.clear();
|
||||
}
|
||||
|
||||
cart_loaded = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Cartridge::Cartridge() {
|
||||
load_database();
|
||||
|
||||
cart_loaded = false;
|
||||
|
||||
base_rom = 0;
|
||||
rom = 0;
|
||||
sram = 0;
|
||||
}
|
||||
|
||||
Cartridge::~Cartridge() {
|
||||
if(cart_loaded == true) {
|
||||
unload();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
class Cartridge {
|
||||
public:
|
||||
|
||||
/*****
|
||||
* cart database
|
||||
*****/
|
||||
|
||||
#include "db/db.h"
|
||||
db_item dbi;
|
||||
uint8 *database;
|
||||
uint database_size;
|
||||
uint database_blocksize;
|
||||
void load_database();
|
||||
bool read_database();
|
||||
|
||||
//
|
||||
|
||||
bool cart_loaded;
|
||||
char rom_fn[4096], sram_fn[4096], cheat_fn[4096], patch_fn[4096];
|
||||
|
||||
uint8 *base_rom, *rom, *sram;
|
||||
|
||||
enum {
|
||||
//header fields
|
||||
CART_NAME = 0x00,
|
||||
MAPPER = 0x15,
|
||||
ROM_TYPE = 0x16,
|
||||
ROM_SIZE = 0x17,
|
||||
SRAM_SIZE = 0x18,
|
||||
REGION = 0x19,
|
||||
LICENSE = 0x1a,
|
||||
VERSION = 0x1b,
|
||||
ICKSUM = 0x1c,
|
||||
CKSUM = 0x1e,
|
||||
RESL = 0x3c,
|
||||
RESH = 0x3d,
|
||||
|
||||
//regions
|
||||
NTSC = 0,
|
||||
PAL = 1,
|
||||
|
||||
//memory mappers
|
||||
PCB = 0x00,
|
||||
LOROM = 0x20,
|
||||
HIROM = 0x21,
|
||||
EXLOROM = 0x22,
|
||||
EXHIROM = 0x25,
|
||||
|
||||
//special chip memory mappers
|
||||
DSP1_LOROM_1MB = 1,
|
||||
DSP1_LOROM_2MB = 2,
|
||||
DSP1_HIROM = 3,
|
||||
};
|
||||
|
||||
struct {
|
||||
uint32 crc32;
|
||||
char name[128];
|
||||
char pcb[32];
|
||||
|
||||
uint region;
|
||||
uint mapper;
|
||||
uint rom_size;
|
||||
uint ram_size;
|
||||
|
||||
//set to true for games that need cart MMIO mapping (c4, dsp-n, ...),
|
||||
//for games that map outside the standard MMIO range of $2000-$5fff
|
||||
bool cart_mmio;
|
||||
bool srtc;
|
||||
bool sdd1;
|
||||
bool c4;
|
||||
bool dsp1;
|
||||
bool dsp2;
|
||||
bool obc1;
|
||||
|
||||
uint dsp1_mapper;
|
||||
|
||||
//HiROM / LoROM specific code
|
||||
uint header_index;
|
||||
} info;
|
||||
|
||||
void load_rom(Reader &rf);
|
||||
void load_sram();
|
||||
void save_sram();
|
||||
void read_dbi();
|
||||
void find_header();
|
||||
void read_header();
|
||||
bool loaded() { return cart_loaded; }
|
||||
bool load(const char *fn);
|
||||
bool unload();
|
||||
|
||||
Cartridge();
|
||||
~Cartridge();
|
||||
};
|
||||
|
||||
extern Cartridge cartridge;
|
||||
@@ -0,0 +1,37 @@
|
||||
void Cartridge::load_database() {
|
||||
database = 0;
|
||||
database_size = 0;
|
||||
|
||||
FILE *fp;
|
||||
fp = fopen("cart.db", "rb");
|
||||
if(!fp)return;
|
||||
|
||||
uint size = fsize(fp);
|
||||
if(size < 8) {
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
database = (uint8*)malloc(size);
|
||||
fread(database, 1, size, fp);
|
||||
fclose(fp);
|
||||
|
||||
database_blocksize = (database[6] << 0) | (database[7] << 8);
|
||||
database_size = (size - 8) / database_blocksize;
|
||||
}
|
||||
|
||||
bool Cartridge::read_database() {
|
||||
uint i, crc32;
|
||||
for(i = 0; i < database_size; i++) {
|
||||
uint8 *p = database + 8 + (i * database_blocksize);
|
||||
crc32 = *(p++) << 0;
|
||||
crc32 |= *(p++) << 8;
|
||||
crc32 |= *(p++) << 16;
|
||||
crc32 |= *(p++) << 24;
|
||||
if(crc32 == cartridge.info.crc32)break;
|
||||
}
|
||||
if(i >= database_size)return false;
|
||||
|
||||
db_read(dbi, database + 8 + (i * database_blocksize));
|
||||
return true;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,47 @@
|
||||
[0x7aedd703]
|
||||
name = "Der Langrisser (Japan) [!]"
|
||||
pcb = "SHVC-1A3M-30"
|
||||
rom = 16mbit
|
||||
ram = 64kbit
|
||||
|
||||
[0x35f9eecc]
|
||||
name = "Der Langrisser (Japan) (V1.1)"
|
||||
pcb = "SHVC-1A3M-30" ;unverified (guess)
|
||||
rom = 16mbit
|
||||
ram = 64kbit
|
||||
|
||||
[0x19bdcb19]
|
||||
name = "Derby Stallion '96 (Japan) [!]"
|
||||
pcb = "BSC-1A5M-01"
|
||||
rom = 24mbit
|
||||
ram = 256kbit
|
||||
|
||||
[0x9684526d]
|
||||
name = "Romancing SaGa (Japan) (V1.1) [!]"
|
||||
pcb = "SHVC-1A3B-12"
|
||||
rom = 8mbit
|
||||
ram = 64kbit
|
||||
|
||||
[0x675b6382]
|
||||
name = "RPG Tsukuru 2 (Japan)"
|
||||
pcb = "BSC-1A7M-01" ;unverified
|
||||
rom = 16mbit
|
||||
ram = 512kbit
|
||||
|
||||
[0xa5c0045e]
|
||||
name = "Secret of Evermore (USA) [!]"
|
||||
pcb = "SHVC-1J3M-20"
|
||||
rom = 32mbit
|
||||
ram = 64kbit
|
||||
|
||||
[0x5ebf7246]
|
||||
name = "Sound Novel Tsukuru (Japan) [!]"
|
||||
pcb = "BSC-1A7M-10"
|
||||
rom = 24mbit
|
||||
ram = 512kbit
|
||||
|
||||
[0x64a91e64]
|
||||
name = "Wanderers from Ys (USA) [!]"
|
||||
pcb = "SHVC-1A3B-12"
|
||||
rom = 8mbit
|
||||
ram = 64kbit
|
||||
@@ -0,0 +1,3 @@
|
||||
cl /nologo /O2 dbcreate.cpp
|
||||
@pause
|
||||
@del *.obj
|
||||
@@ -0,0 +1 @@
|
||||
@del *.exe
|
||||
@@ -0,0 +1,2 @@
|
||||
dbcreate
|
||||
@copy cart.db ..\..\..\cart.db
|
||||
@@ -0,0 +1,47 @@
|
||||
struct db_item {
|
||||
uint32 crc32;
|
||||
char name[128];
|
||||
char pcb [32];
|
||||
uint32 rom;
|
||||
uint32 ram;
|
||||
};
|
||||
|
||||
void db_write(FILE *fp, db_item &dbi) {
|
||||
fputc(dbi.crc32 >> 0, fp);
|
||||
fputc(dbi.crc32 >> 8, fp);
|
||||
fputc(dbi.crc32 >> 16, fp);
|
||||
fputc(dbi.crc32 >> 24, fp);
|
||||
|
||||
fwrite(dbi.name, 1, 128, fp);
|
||||
fwrite(dbi.pcb, 1, 32, fp);
|
||||
|
||||
fputc(dbi.rom >> 0, fp);
|
||||
fputc(dbi.rom >> 8, fp);
|
||||
fputc(dbi.rom >> 16, fp);
|
||||
fputc(dbi.rom >> 24, fp);
|
||||
|
||||
fputc(dbi.ram >> 0, fp);
|
||||
fputc(dbi.ram >> 8, fp);
|
||||
fputc(dbi.ram >> 16, fp);
|
||||
fputc(dbi.ram >> 24, fp);
|
||||
}
|
||||
|
||||
void db_read(db_item &dbi, uint8 *data) {
|
||||
dbi.crc32 = (*data++) << 0;
|
||||
dbi.crc32 |= (*data++) << 8;
|
||||
dbi.crc32 |= (*data++) << 16;
|
||||
dbi.crc32 |= (*data++) << 24;
|
||||
|
||||
memcpy(dbi.name, data, 128); dbi.name[127] = 0; data += 128;
|
||||
memcpy(dbi.pcb, data, 32); dbi.pcb [ 31] = 0; data += 32;
|
||||
|
||||
dbi.rom = (*data++) << 0;
|
||||
dbi.rom |= (*data++) << 8;
|
||||
dbi.rom |= (*data++) << 16;
|
||||
dbi.rom |= (*data++) << 24;
|
||||
|
||||
dbi.ram = (*data++) << 0;
|
||||
dbi.ram |= (*data++) << 8;
|
||||
dbi.ram |= (*data++) << 16;
|
||||
dbi.ram |= (*data++) << 24;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
#include "../../lib/libbase.h"
|
||||
#include "../../lib/libvector.h"
|
||||
#include "../../lib/libstring.h"
|
||||
|
||||
#include "../../lib/libstring.cpp"
|
||||
|
||||
#include "db.h"
|
||||
|
||||
FILE *fp;
|
||||
|
||||
uint decode_size(substring &str) {
|
||||
//hex encoding
|
||||
if(strbegin(str, "0x")) {
|
||||
strltrim(str, "0x");
|
||||
return strhex(str);
|
||||
}
|
||||
|
||||
//mbit encoding
|
||||
if(strend(str, "mbit")) {
|
||||
strrtrim(str, "mbit");
|
||||
return strdec(str) * 1024 * 1024 / 8;
|
||||
}
|
||||
|
||||
//kbit encoding
|
||||
if(strend(str, "kbit")) {
|
||||
strrtrim(str, "kbit");
|
||||
return strdec(str) * 1024 / 8;
|
||||
}
|
||||
|
||||
//decimal encoding
|
||||
return strdec(str);
|
||||
}
|
||||
|
||||
void build_block(substring &block) {
|
||||
string line, hashpart, part;
|
||||
split(line, "\n", block);
|
||||
|
||||
if(strbegin(line[0], "[") == false) {
|
||||
printf("error: invalid block detected: '%s'\n", strptr(line[0]));
|
||||
return;
|
||||
}
|
||||
|
||||
strltrim(line[0], "[");
|
||||
strrtrim(line[0], "]");
|
||||
replace(line[0], "0x", "");
|
||||
split(hashpart, ",", line[0]);
|
||||
|
||||
db_item dbi;
|
||||
dbi.crc32 = 0;
|
||||
*dbi.name = 0;
|
||||
*dbi.pcb = 0;
|
||||
dbi.rom = 0;
|
||||
dbi.ram = 0;
|
||||
|
||||
for(int i = 1; i < count(line); i++) {
|
||||
uint pos;
|
||||
if(strpos(line[i], ";", pos) == true) {
|
||||
strset(line[i], pos, 0);
|
||||
}
|
||||
|
||||
if(strmatch(line[i], ""))continue;
|
||||
|
||||
split(part, "=", line[i]);
|
||||
strunquote(part[1]);
|
||||
|
||||
if(strmatch(part[0], "name")) {
|
||||
strncpy(dbi.name, strptr(part[1]), 128);
|
||||
dbi.name[128] = 0;
|
||||
}
|
||||
|
||||
if(strmatch(part[0], "pcb")) {
|
||||
strncpy(dbi.pcb, strptr(part[1]), 32);
|
||||
dbi.pcb[31] = 0;
|
||||
}
|
||||
|
||||
if(strmatch(part[0], "rom")) {
|
||||
dbi.rom = decode_size(part[1]);
|
||||
}
|
||||
|
||||
if(strmatch(part[0], "ram")) {
|
||||
dbi.ram = decode_size(part[1]);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < count(hashpart); i++) {
|
||||
dbi.crc32 = strhex(hashpart[i]);
|
||||
db_write(fp, dbi);
|
||||
}
|
||||
}
|
||||
|
||||
void build_database() {
|
||||
string data, block;
|
||||
if(strfread(data, "cartdb.txt") == false)return;
|
||||
|
||||
fp = fopen("cart.db", "wb");
|
||||
fprintf(fp, "SNESDB");
|
||||
|
||||
uint blocksize = 4 + 128 + 32 + 4 + 4;
|
||||
fputc(blocksize >> 0, fp);
|
||||
fputc(blocksize >> 8, fp);
|
||||
|
||||
replace (data, "\r", "");
|
||||
qreplace(data, " ", "");
|
||||
qreplace(data, "\t", "");
|
||||
split(block, "\n\n", data);
|
||||
|
||||
for(int i = 0; i < count(block); i++) {
|
||||
build_block(block[i]);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
int main() {
|
||||
build_database();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
#include "../base.h"
|
||||
|
||||
/*****
|
||||
* string <> binary code translation routines
|
||||
* decode() "7e1234:56" -> 0x7e123456
|
||||
* encode() 0x7e123456 -> "7e1234:56"
|
||||
*****/
|
||||
|
||||
bool Cheat::decode(char *str, uint32 &addr, uint8 &data, uint8 &type) {
|
||||
string t, part;
|
||||
strcpy(t, str);
|
||||
strlower(t);
|
||||
if(strlen(t) == 8 || (strlen(t) == 9 && strptr(t)[6] == ':')) {
|
||||
type = CT_PRO_ACTION_REPLAY;
|
||||
replace(t, ":", "");
|
||||
uint32 r = strhex(t);
|
||||
addr = r >> 8;
|
||||
data = r & 0xff;
|
||||
return true;
|
||||
} else if(strlen(t) == 9 && strptr(t)[4] == '-') {
|
||||
type = CT_GAME_GENIE;
|
||||
replace(t, "-", "");
|
||||
strtr(t, "df4709156bc8a23e", "0123456789abcdef");
|
||||
uint32 r = strhex(t);
|
||||
//8421 8421 8421 8421 8421 8421
|
||||
//abcd efgh ijkl mnop qrst uvwx
|
||||
//ijkl qrst opab cduv wxef ghmn
|
||||
addr = (!!(r & 0x002000) << 23) | (!!(r & 0x001000) << 22) |
|
||||
(!!(r & 0x000800) << 21) | (!!(r & 0x000400) << 20) |
|
||||
(!!(r & 0x000020) << 19) | (!!(r & 0x000010) << 18) |
|
||||
(!!(r & 0x000008) << 17) | (!!(r & 0x000004) << 16) |
|
||||
(!!(r & 0x800000) << 15) | (!!(r & 0x400000) << 14) |
|
||||
(!!(r & 0x200000) << 13) | (!!(r & 0x100000) << 12) |
|
||||
(!!(r & 0x000002) << 11) | (!!(r & 0x000001) << 10) |
|
||||
(!!(r & 0x008000) << 9) | (!!(r & 0x004000) << 8) |
|
||||
(!!(r & 0x080000) << 7) | (!!(r & 0x040000) << 6) |
|
||||
(!!(r & 0x020000) << 5) | (!!(r & 0x010000) << 4) |
|
||||
(!!(r & 0x000200) << 3) | (!!(r & 0x000100) << 2) |
|
||||
(!!(r & 0x000080) << 1) | (!!(r & 0x000040) << 0);
|
||||
data = r >> 24;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Cheat::encode(char *str, uint32 addr, uint8 data, uint8 type) {
|
||||
if(type == CT_PRO_ACTION_REPLAY) {
|
||||
sprintf(str, "%0.6x:%0.2x", addr, data);
|
||||
return true;
|
||||
} else if(type == CT_GAME_GENIE) {
|
||||
uint32 r = addr;
|
||||
addr = (!!(r & 0x008000) << 23) | (!!(r & 0x004000) << 22) |
|
||||
(!!(r & 0x002000) << 21) | (!!(r & 0x001000) << 20) |
|
||||
(!!(r & 0x000080) << 19) | (!!(r & 0x000040) << 18) |
|
||||
(!!(r & 0x000020) << 17) | (!!(r & 0x000010) << 16) |
|
||||
(!!(r & 0x000200) << 15) | (!!(r & 0x000100) << 14) |
|
||||
(!!(r & 0x800000) << 13) | (!!(r & 0x400000) << 12) |
|
||||
(!!(r & 0x200000) << 11) | (!!(r & 0x100000) << 10) |
|
||||
(!!(r & 0x000008) << 9) | (!!(r & 0x000004) << 8) |
|
||||
(!!(r & 0x000002) << 7) | (!!(r & 0x000001) << 6) |
|
||||
(!!(r & 0x080000) << 5) | (!!(r & 0x040000) << 4) |
|
||||
(!!(r & 0x020000) << 3) | (!!(r & 0x010000) << 2) |
|
||||
(!!(r & 0x000800) << 1) | (!!(r & 0x000400) << 0);
|
||||
sprintf(str, "%0.2x%0.2x-%0.4x", data, addr >> 16, addr & 0xffff);
|
||||
strtr(str, "0123456789abcdef", "df4709156bc8a23e");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*****
|
||||
* address lookup table manipulation and mirroring
|
||||
* mirror_address() 0x000000 -> 0x7e0000
|
||||
* set() enable specified address, mirror accordingly
|
||||
* clear() disable specified address, mirror accordingly
|
||||
*****/
|
||||
|
||||
uint Cheat::mirror_address(uint addr) {
|
||||
if((addr & 0x40e000) != 0x0000)return addr;
|
||||
//8k WRAM mirror
|
||||
//$[00-3f|80-bf]:[0000-1fff] -> $7e:[0000-1fff]
|
||||
return (0x7e0000 + (addr & 0x1fff));
|
||||
}
|
||||
|
||||
void Cheat::set(uint32 addr) {
|
||||
addr = mirror_address(addr);
|
||||
|
||||
mask[addr >> 3] |= 1 << (addr & 7);
|
||||
if((addr & 0xffe000) == 0x7e0000) {
|
||||
//mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff]
|
||||
uint mirror;
|
||||
for(int x = 0; x <= 0x3f; x++) {
|
||||
mirror = ((0x00 + x) << 16) + (addr & 0x1fff);
|
||||
mask[mirror >> 3] |= 1 << (mirror & 7);
|
||||
mirror = ((0x80 + x) << 16) + (addr & 0x1fff);
|
||||
mask[mirror >> 3] |= 1 << (mirror & 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cheat::clear(uint32 addr) {
|
||||
addr = mirror_address(addr);
|
||||
|
||||
//is there more than one cheat code using the same address
|
||||
//(and likely a different override value) that is enabled?
|
||||
//if so, do not clear code lookup table entry for this address.
|
||||
uint8 r;
|
||||
if(read(addr, r) == true)return;
|
||||
|
||||
mask[addr >> 3] &= ~(1 << (addr & 7));
|
||||
if((addr & 0xffe000) == 0x7e0000) {
|
||||
//mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff]
|
||||
uint mirror;
|
||||
for(int x = 0; x <= 0x3f; x++) {
|
||||
mirror = ((0x00 + x) << 16) + (addr & 0x1fff);
|
||||
mask[mirror >> 3] &= ~(1 << (mirror & 7));
|
||||
mirror = ((0x80 + x) << 16) + (addr & 0x1fff);
|
||||
mask[mirror >> 3] &= ~(1 << (mirror & 7));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****
|
||||
* read() is used by MemBus::read() if Cheat::enabled(addr)
|
||||
* returns true to look up cheat code.
|
||||
* returns true if cheat code was found, false if it was not.
|
||||
* when true, cheat code substitution value is stored in data.
|
||||
*****/
|
||||
|
||||
bool Cheat::read(uint32 addr, uint8 &data) {
|
||||
addr = mirror_address(addr);
|
||||
for(int i = 0; i < cheat_count; i++) {
|
||||
if(enabled(i) == false)continue;
|
||||
if(addr == mirror_address(index[i].addr)) {
|
||||
data = index[i].data;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//code not found, or code is disabled
|
||||
return false;
|
||||
}
|
||||
|
||||
/*****
|
||||
* update_cheat_status() will scan to see if any codes are
|
||||
* enabled. if any are, make sure the cheat system is on.
|
||||
* otherwise, turn cheat system off to speed up emulation.
|
||||
*****/
|
||||
void Cheat::update_cheat_status() {
|
||||
for(int i = 0; i < cheat_count; i++) {
|
||||
if(index[i].enabled) {
|
||||
cheat_enabled = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
cheat_enabled = false;
|
||||
}
|
||||
|
||||
/*****
|
||||
* cheat list manipulation routines
|
||||
*****/
|
||||
|
||||
bool Cheat::add(bool enable, char *code, char *desc) {
|
||||
if(cheat_count >= CHEAT_LIMIT)return false;
|
||||
|
||||
uint32 addr, len;
|
||||
uint8 data, type;
|
||||
if(decode(code, addr, data, type) == false)return false;
|
||||
|
||||
index[cheat_count].enabled = enable;
|
||||
index[cheat_count].addr = addr;
|
||||
index[cheat_count].data = data;
|
||||
len = strlen(code);
|
||||
len = len > 16 ? 16 : len;
|
||||
memcpy(index[cheat_count].code, code, len);
|
||||
index[cheat_count].code[len] = 0;
|
||||
len = strlen(desc);
|
||||
len = len > 128 ? 128 : len;
|
||||
memcpy(index[cheat_count].desc, desc, len);
|
||||
index[cheat_count].desc[len] = 0;
|
||||
cheat_count++;
|
||||
(enable) ? set(addr) : clear(addr);
|
||||
|
||||
update_cheat_status();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Cheat::edit(uint32 n, bool enable, char *code, char *desc) {
|
||||
if(n >= cheat_count)return false;
|
||||
|
||||
uint32 addr, len;
|
||||
uint8 data, type;
|
||||
if(decode(code, addr, data, type) == false)return false;
|
||||
|
||||
//disable current code and clear from code lookup table
|
||||
index[n].enabled = false;
|
||||
clear(index[n].addr);
|
||||
|
||||
//update code and enable in code lookup table
|
||||
index[n].enabled = enable;
|
||||
index[n].addr = addr;
|
||||
index[n].data = data;
|
||||
len = strlen(code);
|
||||
len = len > 16 ? 16 : len;
|
||||
memcpy(index[n].code, code, len);
|
||||
index[n].code[len] = 0;
|
||||
len = strlen(desc);
|
||||
len = len > 128 ? 128 : len;
|
||||
memcpy(index[n].desc, desc, len);
|
||||
index[n].desc[len] = 0;
|
||||
set(addr);
|
||||
|
||||
update_cheat_status();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Cheat::remove(uint32 n) {
|
||||
if(n >= cheat_count)return false;
|
||||
|
||||
for(int i = n; i < cheat_count; i++) {
|
||||
index[i].enabled = index[i + 1].enabled;
|
||||
index[i].addr = index[i + 1].addr;
|
||||
index[i].data = index[i + 1].data;
|
||||
strcpy(index[i].desc, index[i + 1].desc);
|
||||
}
|
||||
|
||||
cheat_count--;
|
||||
|
||||
update_cheat_status();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Cheat::get(uint32 n, bool &enable, uint32 &addr, uint8 &data, char *code, char *desc) {
|
||||
if(n >= cheat_count)return false;
|
||||
enable = index[n].enabled;
|
||||
addr = index[n].addr;
|
||||
data = index[n].data;
|
||||
strcpy(code, index[n].code);
|
||||
strcpy(desc, index[n].desc);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*****
|
||||
* code status modifier routines
|
||||
*****/
|
||||
|
||||
bool Cheat::enabled(uint32 n) {
|
||||
if(n >= cheat_count)return false;
|
||||
return index[n].enabled;
|
||||
}
|
||||
|
||||
void Cheat::enable(uint32 n) {
|
||||
if(n >= cheat_count)return;
|
||||
index[n].enabled = true;
|
||||
set(index[n].addr);
|
||||
update_cheat_status();
|
||||
}
|
||||
|
||||
void Cheat::disable(uint32 n) {
|
||||
if(n >= cheat_count)return;
|
||||
index[n].enabled = false;
|
||||
clear(index[n].addr);
|
||||
update_cheat_status();
|
||||
}
|
||||
|
||||
/*****
|
||||
* cheat file manipulation routines
|
||||
*****/
|
||||
|
||||
bool Cheat::load(Reader &rf) {
|
||||
if(!rf.ready())return false;
|
||||
|
||||
uint8 *raw_data = rf.read();
|
||||
string data;
|
||||
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;
|
||||
uint8 en = *(strptr(line[i]));
|
||||
if(en == '+') {
|
||||
strltrim(line[i], "+");
|
||||
} else if(en == '-') {
|
||||
strltrim(line[i], "-");
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
qreplace(line[i], " ", "");
|
||||
qsplit(part, ",", line[i]);
|
||||
if(::count(part) != 2)continue;
|
||||
strunquote(part[1]);
|
||||
add(en == '+', strptr(part[0]), strptr(part[1]));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Cheat::save(Writer &wf) {
|
||||
if(!wf.ready())return false;
|
||||
|
||||
string data;
|
||||
char t[4096];
|
||||
strcpy(data, "");
|
||||
for(int i = 0; i < cheat_count; i++) {
|
||||
sprintf(t, "%c%s, \"%s\"\r\n", index[i].enabled ? '+' : '-', index[i].code, index[i].desc);
|
||||
strcat(data, t);
|
||||
}
|
||||
|
||||
wf.write((uint8*)strptr(data), strlen(data));
|
||||
return true;
|
||||
}
|
||||
|
||||
/*****
|
||||
* initialization routines
|
||||
*****/
|
||||
|
||||
void Cheat::clear() {
|
||||
cheat_enabled = false;
|
||||
cheat_count = 0;
|
||||
memset(mask, 0, 0x200000);
|
||||
for(int i = 0; i < CHEAT_LIMIT + 1; i++) {
|
||||
index[i].enabled = false;
|
||||
index[i].addr = 0x000000;
|
||||
index[i].data = 0x00;
|
||||
strcpy(index[i].code, "");
|
||||
strcpy(index[i].desc, "");
|
||||
}
|
||||
}
|
||||
|
||||
Cheat::Cheat() {
|
||||
clear();
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#define CHEAT_LIMIT 1024
|
||||
|
||||
class Cheat {
|
||||
public:
|
||||
enum { CT_PRO_ACTION_REPLAY, CT_GAME_GENIE };
|
||||
|
||||
struct CheatIndex {
|
||||
bool enabled;
|
||||
uint32 addr;
|
||||
uint8 data;
|
||||
char code[ 16 + 1];
|
||||
char desc[128 + 1];
|
||||
} index[CHEAT_LIMIT + 1];
|
||||
bool cheat_enabled;
|
||||
uint32 cheat_count;
|
||||
uint8 mask[0x200000];
|
||||
|
||||
inline bool enabled() { return cheat_enabled; }
|
||||
inline uint count() { return cheat_count; }
|
||||
inline bool exists(uint32 addr) { return bool(mask[addr >> 3] & 1 << (addr & 7)); }
|
||||
|
||||
bool decode(char *str, uint32 &addr, uint8 &data, uint8 &type);
|
||||
bool encode(char *str, uint32 addr, uint8 data, uint8 type);
|
||||
|
||||
private:
|
||||
uint mirror_address(uint addr);
|
||||
void set(uint32 addr);
|
||||
void clear(uint32 addr);
|
||||
public:
|
||||
|
||||
bool read(uint32 addr, uint8 &data);
|
||||
|
||||
void update_cheat_status();
|
||||
bool add(bool enable, char *code, char *desc);
|
||||
bool edit(uint32 n, bool enable, char *code, char *desc);
|
||||
bool get(uint32 n, bool &enable, uint32 &addr, uint8 &data, char *code, char *desc);
|
||||
bool remove (uint32 n);
|
||||
bool enabled(uint32 n);
|
||||
void enable (uint32 n);
|
||||
void disable(uint32 n);
|
||||
bool load(Reader &rf);
|
||||
bool save(Writer &wf);
|
||||
void clear();
|
||||
|
||||
Cheat();
|
||||
};
|
||||
|
||||
extern Cheat cheat;
|
||||
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
C4 emulation
|
||||
|
||||
Used in Rockman X2/X3 (Megaman X2/X3)
|
||||
Portions (c) anomie, Overload, zsKnight, Nach, byuu
|
||||
*/
|
||||
|
||||
#include "../../base.h"
|
||||
|
||||
#include "c4data.cpp"
|
||||
#include "c4fn.cpp"
|
||||
#include "c4oam.cpp"
|
||||
#include "c4ops.cpp"
|
||||
|
||||
void C4::init() {}
|
||||
void C4::enable() {}
|
||||
|
||||
uint32 C4::ldr(uint8 r) {
|
||||
uint16 addr = 0x0080 + (r * 3);
|
||||
return (reg[addr]) | (reg[addr + 1] << 8) | (reg[addr + 2] << 16);
|
||||
}
|
||||
|
||||
void C4::str(uint8 r, uint32 data) {
|
||||
uint16 addr = 0x0080 + (r * 3);
|
||||
reg[addr ] = (data);
|
||||
reg[addr + 1] = (data >> 8);
|
||||
reg[addr + 2] = (data >> 16);
|
||||
}
|
||||
|
||||
void C4::mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh) {
|
||||
int64 rx = x & 0xffffff;
|
||||
int64 ry = y & 0xffffff;
|
||||
if(rx & 0x800000)rx |= ~0x7fffff;
|
||||
if(ry & 0x800000)ry |= ~0x7fffff;
|
||||
|
||||
rx *= ry;
|
||||
|
||||
rl = (rx) & 0xffffff;
|
||||
rh = (rx >> 24) & 0xffffff;
|
||||
}
|
||||
|
||||
uint32 C4::sin(uint32 rx) {
|
||||
r0 = rx & 0x1ff;
|
||||
if(r0 & 0x100)r0 ^= 0x1ff;
|
||||
if(r0 & 0x080)r0 ^= 0x0ff;
|
||||
if(rx & 0x100) {
|
||||
return sin_table[r0 + 0x80];
|
||||
} else {
|
||||
return sin_table[r0];
|
||||
}
|
||||
}
|
||||
|
||||
uint32 C4::cos(uint32 rx) {
|
||||
return sin(rx + 0x080);
|
||||
}
|
||||
|
||||
void C4::immediate_reg(uint32 start) {
|
||||
r0 = ldr(0);
|
||||
for(uint32 i=start;i<48;i++) {
|
||||
if((r0 & 0x0fff) < 0x0c00) {
|
||||
ram[r0 & 0x0fff] = immediate_data[i];
|
||||
}
|
||||
r0++;
|
||||
}
|
||||
str(0, r0);
|
||||
}
|
||||
|
||||
void C4::transfer_data() {
|
||||
uint32 src;
|
||||
uint16 dest, count;
|
||||
src = (reg[0x40]) | (reg[0x41] << 8) | (reg[0x42] << 16);
|
||||
count = (reg[0x43]) | (reg[0x44] << 8);
|
||||
dest = (reg[0x45]) | (reg[0x46] << 8);
|
||||
|
||||
for(uint32 i=0;i<count;i++) {
|
||||
write(dest++, r_mem->read(src++));
|
||||
}
|
||||
}
|
||||
|
||||
void C4::write(uint16 addr, uint8 data) {
|
||||
addr &= 0x1fff;
|
||||
|
||||
if(addr < 0x0c00) {
|
||||
//ram
|
||||
ram[addr] = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr < 0x1f00) {
|
||||
//unmapped
|
||||
return;
|
||||
}
|
||||
|
||||
//command register
|
||||
reg[addr & 0xff] = data;
|
||||
|
||||
if(addr == 0x1f47) {
|
||||
//memory transfer
|
||||
transfer_data();
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0x1f4f) {
|
||||
//c4 command
|
||||
if(reg[0x4d] == 0x0e && !(data & 0xc3)) {
|
||||
//c4 test command
|
||||
reg[0x80] = data >> 2;
|
||||
return;
|
||||
}
|
||||
|
||||
switch(data) {
|
||||
case 0x00:op00();break;
|
||||
case 0x01:op01();break;
|
||||
case 0x05:op05();break;
|
||||
case 0x0d:op0d();break;
|
||||
case 0x10:op10();break;
|
||||
case 0x13:op13();break;
|
||||
case 0x15:op15();break;
|
||||
case 0x1f:op1f();break;
|
||||
case 0x22:op22();break;
|
||||
case 0x25:op25();break;
|
||||
case 0x2d:op2d();break;
|
||||
case 0x40:op40();break;
|
||||
case 0x54:op54();break;
|
||||
case 0x5c:op5c();break;
|
||||
case 0x5e:op5e();break;
|
||||
case 0x60:op60();break;
|
||||
case 0x62:op62();break;
|
||||
case 0x64:op64();break;
|
||||
case 0x66:op66();break;
|
||||
case 0x68:op68();break;
|
||||
case 0x6a:op6a();break;
|
||||
case 0x6c:op6c();break;
|
||||
case 0x6e:op6e();break;
|
||||
case 0x70:op70();break;
|
||||
case 0x72:op72();break;
|
||||
case 0x74:op74();break;
|
||||
case 0x76:op76();break;
|
||||
case 0x78:op78();break;
|
||||
case 0x7a:op7a();break;
|
||||
case 0x7c:op7c();break;
|
||||
case 0x89:op89();break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void C4::writeb(uint16 addr, uint8 data) {
|
||||
write(addr, data);
|
||||
}
|
||||
|
||||
void C4::writew(uint16 addr, uint16 data) {
|
||||
write(addr, data);
|
||||
write(addr + 1, data >> 8);
|
||||
}
|
||||
|
||||
void C4::writel(uint16 addr, uint32 data) {
|
||||
write(addr, data);
|
||||
write(addr + 1, data >> 8);
|
||||
write(addr + 2, data >> 16);
|
||||
}
|
||||
|
||||
uint8 C4::read(uint16 addr) {
|
||||
addr &= 0x1fff;
|
||||
|
||||
if(addr < 0x0c00) {
|
||||
return ram[addr];
|
||||
}
|
||||
|
||||
if(addr >= 0x1f00) {
|
||||
return reg[addr & 0xff];
|
||||
}
|
||||
|
||||
return r_cpu->regs.mdr;
|
||||
}
|
||||
|
||||
uint8 C4::readb(uint16 addr) {
|
||||
return read(addr);
|
||||
}
|
||||
|
||||
uint16 C4::readw(uint16 addr) {
|
||||
return read(addr) | (read(addr + 1) << 8);
|
||||
}
|
||||
|
||||
uint32 C4::readl(uint16 addr) {
|
||||
return read(addr) | (read(addr + 1) << 8) + (read(addr + 2) << 16);
|
||||
}
|
||||
|
||||
void C4::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void C4::reset() {
|
||||
memset(ram, 0, 0x0c00);
|
||||
memset(reg, 0, 0x0100);
|
||||
}
|
||||
|
||||
C4::C4() {}
|
||||
@@ -0,0 +1,94 @@
|
||||
class C4 {
|
||||
private:
|
||||
uint8 ram[0x0c00];
|
||||
uint8 reg[0x0100];
|
||||
uint32 r0, r1, r2, r3, r4, r5, r6, r7,
|
||||
r8, r9, r10, r11, r12, r13, r14, r15;
|
||||
|
||||
static const uint8 immediate_data[48];
|
||||
static const uint16 wave_data[40];
|
||||
static const uint32 sin_table[256];
|
||||
|
||||
static const int16 SinTable[512];
|
||||
static const int16 CosTable[512];
|
||||
|
||||
int16 C4WFXVal, C4WFYVal, C4WFZVal, C4WFX2Val, C4WFY2Val, C4WFDist, C4WFScale;
|
||||
int16 C41FXVal, C41FYVal, C41FAngleRes, C41FDist, C41FDistVal;
|
||||
|
||||
double tanval;
|
||||
double c4x,c4y,c4z, c4x2,c4y2,c4z2;
|
||||
|
||||
void C4TransfWireFrame();
|
||||
void C4TransfWireFrame2();
|
||||
void C4CalcWireFrame();
|
||||
void C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color);
|
||||
void C4DrawWireFrame();
|
||||
void C4DoScaleRotate(int row_padding);
|
||||
|
||||
public:
|
||||
uint32 ldr(uint8 r);
|
||||
void str(uint8 r, uint32 data);
|
||||
void mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh);
|
||||
uint32 sin(uint32 rx);
|
||||
uint32 cos(uint32 rx);
|
||||
|
||||
void transfer_data();
|
||||
void immediate_reg(uint32 num);
|
||||
|
||||
void op00_00();
|
||||
void op00_03();
|
||||
void op00_05();
|
||||
void op00_07();
|
||||
void op00_08();
|
||||
void op00_0b();
|
||||
void op00_0c();
|
||||
|
||||
void op00();
|
||||
void op01();
|
||||
void op05();
|
||||
void op0d();
|
||||
void op10();
|
||||
void op13();
|
||||
void op15();
|
||||
void op1f();
|
||||
void op22();
|
||||
void op25();
|
||||
void op2d();
|
||||
void op40();
|
||||
void op54();
|
||||
void op5c();
|
||||
void op5e();
|
||||
void op60();
|
||||
void op62();
|
||||
void op64();
|
||||
void op66();
|
||||
void op68();
|
||||
void op6a();
|
||||
void op6c();
|
||||
void op6e();
|
||||
void op70();
|
||||
void op72();
|
||||
void op74();
|
||||
void op76();
|
||||
void op78();
|
||||
void op7a();
|
||||
void op7c();
|
||||
void op89();
|
||||
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
void write (uint16 addr, uint8 data);
|
||||
void writeb(uint16 addr, uint8 data);
|
||||
void writew(uint16 addr, uint16 data);
|
||||
void writel(uint16 addr, uint32 data);
|
||||
|
||||
uint8 read (uint16 addr);
|
||||
uint8 readb(uint16 addr);
|
||||
uint16 readw(uint16 addr);
|
||||
uint32 readl(uint16 addr);
|
||||
|
||||
C4();
|
||||
};
|
||||
@@ -0,0 +1,183 @@
|
||||
const uint8 C4::immediate_data[48] = {
|
||||
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f,
|
||||
0x00, 0x80, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff,
|
||||
0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00
|
||||
};
|
||||
|
||||
const uint16 C4::wave_data[40] = {
|
||||
0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
|
||||
0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020a, 0x020c, 0x020e,
|
||||
0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e,
|
||||
0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060a, 0x060c, 0x060e,
|
||||
0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080a, 0x080c, 0x080e
|
||||
};
|
||||
|
||||
const uint32 C4::sin_table[256] = {
|
||||
0x000000, 0x000324, 0x000648, 0x00096c, 0x000c8f, 0x000fb2, 0x0012d5, 0x0015f6,
|
||||
0x001917, 0x001c37, 0x001f56, 0x002273, 0x002590, 0x0028aa, 0x002bc4, 0x002edb,
|
||||
0x0031f1, 0x003505, 0x003817, 0x003b26, 0x003e33, 0x00413e, 0x004447, 0x00474d,
|
||||
0x004a50, 0x004d50, 0x00504d, 0x005347, 0x00563e, 0x005931, 0x005c22, 0x005f0e,
|
||||
0x0061f7, 0x0064dc, 0x0067bd, 0x006a9b, 0x006d74, 0x007049, 0x007319, 0x0075e5,
|
||||
0x0078ad, 0x007b70, 0x007e2e, 0x0080e7, 0x00839c, 0x00864b, 0x0088f5, 0x008b9a,
|
||||
0x008e39, 0x0090d3, 0x009368, 0x0095f6, 0x00987f, 0x009b02, 0x009d7f, 0x009ff6,
|
||||
0x00a267, 0x00a4d2, 0x00a736, 0x00a994, 0x00abeb, 0x00ae3b, 0x00b085, 0x00b2c8,
|
||||
0x00b504, 0x00b73a, 0x00b968, 0x00bb8f, 0x00bdae, 0x00bfc7, 0x00c1d8, 0x00c3e2,
|
||||
0x00c5e4, 0x00c7de, 0x00c9d1, 0x00cbbb, 0x00cd9f, 0x00cf7a, 0x00d14d, 0x00d318,
|
||||
0x00d4db, 0x00d695, 0x00d848, 0x00d9f2, 0x00db94, 0x00dd2d, 0x00debe, 0x00e046,
|
||||
0x00e1c5, 0x00e33c, 0x00e4aa, 0x00e60f, 0x00e76b, 0x00e8bf, 0x00ea09, 0x00eb4b,
|
||||
0x00ec83, 0x00edb2, 0x00eed8, 0x00eff5, 0x00f109, 0x00f213, 0x00f314, 0x00f40b,
|
||||
0x00f4fa, 0x00f5de, 0x00f6ba, 0x00f78b, 0x00f853, 0x00f912, 0x00f9c7, 0x00fa73,
|
||||
0x00fb14, 0x00fbac, 0x00fc3b, 0x00fcbf, 0x00fd3a, 0x00fdab, 0x00fe13, 0x00fe70,
|
||||
0x00fec4, 0x00ff0e, 0x00ff4e, 0x00ff84, 0x00ffb1, 0x00ffd3, 0x00ffec, 0x00fffb,
|
||||
0x000000, 0xfffcdb, 0xfff9b7, 0xfff693, 0xfff370, 0xfff04d, 0xffed2a, 0xffea09,
|
||||
0xffe6e8, 0xffe3c8, 0xffe0a9, 0xffdd8c, 0xffda6f, 0xffd755, 0xffd43b, 0xffd124,
|
||||
0xffce0e, 0xffcafa, 0xffc7e8, 0xffc4d9, 0xffc1cc, 0xffbec1, 0xffbbb8, 0xffb8b2,
|
||||
0xffb5af, 0xffb2af, 0xffafb2, 0xffacb8, 0xffa9c1, 0xffa6ce, 0xffa3dd, 0xffa0f1,
|
||||
0xff9e08, 0xff9b23, 0xff9842, 0xff9564, 0xff928b, 0xff8fb6, 0xff8ce6, 0xff8a1a,
|
||||
0xff8752, 0xff848f, 0xff81d1, 0xff7f18, 0xff7c63, 0xff79b4, 0xff770a, 0xff7465,
|
||||
0xff71c6, 0xff6f2c, 0xff6c97, 0xff6a09, 0xff6780, 0xff64fd, 0xff6280, 0xff6009,
|
||||
0xff5d98, 0xff5b2d, 0xff58c9, 0xff566b, 0xff5414, 0xff51c4, 0xff4f7a, 0xff4d37,
|
||||
0xff4afb, 0xff48c5, 0xff4697, 0xff4470, 0xff4251, 0xff4038, 0xff3e27, 0xff3c1e,
|
||||
0xff3a1b, 0xff3821, 0xff362e, 0xff3444, 0xff3260, 0xff3085, 0xff2eb2, 0xff2ce7,
|
||||
0xff2b24, 0xff296a, 0xff27b7, 0xff260d, 0xff246b, 0xff22d2, 0xff2141, 0xff1fb9,
|
||||
0xff1e3a, 0xff1cc3, 0xff1b55, 0xff19f0, 0xff1894, 0xff1740, 0xff15f6, 0xff14b4,
|
||||
0xff137c, 0xff124d, 0xff1127, 0xff100a, 0xff0ef6, 0xff0dec, 0xff0ceb, 0xff0bf4,
|
||||
0xff0b05, 0xff0a21, 0xff0945, 0xff0874, 0xff07ac, 0xff06ed, 0xff0638, 0xff058d,
|
||||
0xff04eb, 0xff0453, 0xff03c4, 0xff0340, 0xff02c5, 0xff0254, 0xff01ec, 0xff018f,
|
||||
0xff013b, 0xff00f1, 0xff00b1, 0xff007b, 0xff004e, 0xff002c, 0xff0013, 0xff0004
|
||||
};
|
||||
|
||||
const int16 C4::SinTable[512] = {
|
||||
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
|
||||
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
|
||||
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
|
||||
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
|
||||
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
|
||||
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
|
||||
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
|
||||
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
|
||||
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
|
||||
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
|
||||
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
|
||||
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
|
||||
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
|
||||
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
|
||||
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
|
||||
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765,
|
||||
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
|
||||
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
|
||||
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
|
||||
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
|
||||
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
|
||||
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
|
||||
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
|
||||
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
|
||||
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
|
||||
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
|
||||
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
|
||||
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
|
||||
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
|
||||
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
|
||||
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
|
||||
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
|
||||
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
|
||||
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
|
||||
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
|
||||
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
|
||||
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
|
||||
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
|
||||
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
|
||||
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
|
||||
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
|
||||
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
|
||||
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
|
||||
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
|
||||
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
|
||||
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
|
||||
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
|
||||
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
|
||||
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
|
||||
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
|
||||
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
|
||||
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
|
||||
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
|
||||
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
|
||||
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
|
||||
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
|
||||
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
|
||||
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
|
||||
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
|
||||
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
|
||||
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
|
||||
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
|
||||
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
|
||||
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402
|
||||
};
|
||||
|
||||
const int16 C4::CosTable[512] = {
|
||||
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
|
||||
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
|
||||
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
|
||||
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
|
||||
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
|
||||
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
|
||||
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
|
||||
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
|
||||
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
|
||||
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
|
||||
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
|
||||
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
|
||||
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
|
||||
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
|
||||
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
|
||||
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
|
||||
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
|
||||
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
|
||||
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
|
||||
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
|
||||
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
|
||||
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
|
||||
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
|
||||
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
|
||||
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
|
||||
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
|
||||
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
|
||||
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
|
||||
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
|
||||
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
|
||||
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
|
||||
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
|
||||
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
|
||||
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
|
||||
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
|
||||
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
|
||||
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
|
||||
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
|
||||
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
|
||||
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
|
||||
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
|
||||
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
|
||||
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
|
||||
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
|
||||
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
|
||||
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
|
||||
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
|
||||
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402,
|
||||
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
|
||||
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
|
||||
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
|
||||
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
|
||||
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
|
||||
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
|
||||
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
|
||||
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
|
||||
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
|
||||
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
|
||||
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
|
||||
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
|
||||
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
|
||||
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
|
||||
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
|
||||
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765
|
||||
};
|
||||
@@ -0,0 +1,242 @@
|
||||
#include <math.h>
|
||||
#define Tan(a) (CosTable[a] ? ((((int32)SinTable[a]) << 16) / CosTable[a]) : 0x80000000)
|
||||
#define sar(b, n) ((b) >> (n))
|
||||
#ifdef PI
|
||||
#undef PI
|
||||
#endif
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
|
||||
//Wireframe Helpers
|
||||
void C4::C4TransfWireFrame() {
|
||||
c4x = (double)C4WFXVal;
|
||||
c4y = (double)C4WFYVal;
|
||||
c4z = (double)C4WFZVal - 0x95;
|
||||
|
||||
//Rotate X
|
||||
tanval = -(double)C4WFX2Val * PI * 2 / 128;
|
||||
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
|
||||
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
|
||||
|
||||
//Rotate Y
|
||||
tanval = -(double)C4WFY2Val * PI * 2 / 128;
|
||||
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
|
||||
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
|
||||
|
||||
//Rotate Z
|
||||
tanval = -(double)C4WFDist * PI * 2 / 128;
|
||||
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
|
||||
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
|
||||
|
||||
//Scale
|
||||
C4WFXVal = (int16)(c4x * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
|
||||
C4WFYVal = (int16)(c4y * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
|
||||
}
|
||||
|
||||
void C4::C4CalcWireFrame() {
|
||||
C4WFXVal = C4WFX2Val - C4WFXVal;
|
||||
C4WFYVal = C4WFY2Val - C4WFYVal;
|
||||
|
||||
if(abs(C4WFXVal) > abs(C4WFYVal)) {
|
||||
C4WFDist = abs(C4WFXVal) + 1;
|
||||
C4WFYVal = (256 * (long)C4WFYVal) / abs(C4WFXVal);
|
||||
C4WFXVal = (C4WFXVal < 0) ? -256 : 256;
|
||||
} else if(C4WFYVal != 0) {
|
||||
C4WFDist = abs(C4WFYVal) + 1;
|
||||
C4WFXVal = (256 * (long)C4WFXVal) / abs(C4WFYVal);
|
||||
C4WFYVal = (C4WFYVal < 0) ? -256 : 256;
|
||||
} else {
|
||||
C4WFDist = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void C4::C4TransfWireFrame2() {
|
||||
c4x = (double)C4WFXVal;
|
||||
c4y = (double)C4WFYVal;
|
||||
c4z = (double)C4WFZVal;
|
||||
|
||||
//Rotate X
|
||||
tanval = -(double)C4WFX2Val * PI * 2 / 128;
|
||||
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
|
||||
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
|
||||
|
||||
//Rotate Y
|
||||
tanval = -(double)C4WFY2Val * PI * 2 / 128;
|
||||
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
|
||||
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
|
||||
|
||||
//Rotate Z
|
||||
tanval = -(double)C4WFDist * PI * 2 / 128;
|
||||
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
|
||||
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
|
||||
|
||||
//Scale
|
||||
C4WFXVal = (int16)(c4x * C4WFScale / 0x100);
|
||||
C4WFYVal = (int16)(c4y * C4WFScale / 0x100);
|
||||
}
|
||||
|
||||
void C4::C4DrawWireFrame() {
|
||||
uint32 line = readl(0x1f80);
|
||||
uint32 point1, point2;
|
||||
int16 X1, Y1, Z1;
|
||||
int16 X2, Y2, Z2;
|
||||
uint8 Color;
|
||||
for(int32 i = ram[0x0295]; i > 0; i--, line += 5) {
|
||||
if(r_mem->read(line) == 0xff && r_mem->read(line + 1) == 0xff) {
|
||||
int32 tmp = line - 5;
|
||||
while(r_mem->read(tmp + 2) == 0xff && r_mem->read(tmp + 3) == 0xff && (tmp + 2) >= 0) { tmp -= 5; }
|
||||
point1 = (read(0x1f82) << 16) | (r_mem->read(tmp + 2) << 8) | r_mem->read(tmp + 3);
|
||||
} else {
|
||||
point1 = (read(0x1f82) << 16) | (r_mem->read(line) << 8) | r_mem->read(line + 1);
|
||||
}
|
||||
point2 = (read(0x1f82) << 16) | (r_mem->read(line + 2) << 8) | r_mem->read(line + 3);
|
||||
|
||||
X1=(r_mem->read(point1 + 0) << 8) | r_mem->read(point1 + 1);
|
||||
Y1=(r_mem->read(point1 + 2) << 8) | r_mem->read(point1 + 3);
|
||||
Z1=(r_mem->read(point1 + 4) << 8) | r_mem->read(point1 + 5);
|
||||
X2=(r_mem->read(point2 + 0) << 8) | r_mem->read(point2 + 1);
|
||||
Y2=(r_mem->read(point2 + 2) << 8) | r_mem->read(point2 + 3);
|
||||
Z2=(r_mem->read(point2 + 4) << 8) | r_mem->read(point2 + 5);
|
||||
Color = r_mem->read(line + 4);
|
||||
C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color);
|
||||
}
|
||||
}
|
||||
|
||||
void C4::C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color) {
|
||||
//Transform coordinates
|
||||
C4WFXVal = (int16)X1;
|
||||
C4WFYVal = (int16)Y1;
|
||||
C4WFZVal = Z1;
|
||||
C4WFScale = read(0x1f90);
|
||||
C4WFX2Val = read(0x1f86);
|
||||
C4WFY2Val = read(0x1f87);
|
||||
C4WFDist = read(0x1f88);
|
||||
C4TransfWireFrame2();
|
||||
X1 = (C4WFXVal + 48) << 8;
|
||||
Y1 = (C4WFYVal + 48) << 8;
|
||||
|
||||
C4WFXVal = (int16)X2;
|
||||
C4WFYVal = (int16)Y2;
|
||||
C4WFZVal = Z2;
|
||||
C4TransfWireFrame2();
|
||||
X2 = (C4WFXVal + 48) << 8;
|
||||
Y2 = (C4WFYVal + 48) << 8;
|
||||
|
||||
//Get line info
|
||||
C4WFXVal = (int16)(X1 >> 8);
|
||||
C4WFYVal = (int16)(Y1 >> 8);
|
||||
C4WFX2Val = (int16)(X2 >> 8);
|
||||
C4WFY2Val = (int16)(Y2 >> 8);
|
||||
C4CalcWireFrame();
|
||||
X2 = (int16)C4WFXVal;
|
||||
Y2 = (int16)C4WFYVal;
|
||||
|
||||
//Render line
|
||||
for(int32 i = C4WFDist ? C4WFDist : 1; i > 0; i--) {
|
||||
if(X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000) {
|
||||
uint16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2;
|
||||
uint8 bit = 0x80 >> ((X1 >> 8) & 7);
|
||||
ram[addr + 0x300] &= ~bit;
|
||||
ram[addr + 0x301] &= ~bit;
|
||||
if(Color & 1) { ram[addr + 0x300] |= bit; }
|
||||
if(Color & 2) { ram[addr + 0x301] |= bit; }
|
||||
}
|
||||
X1 += X2;
|
||||
Y1 += Y2;
|
||||
}
|
||||
}
|
||||
|
||||
void C4::C4DoScaleRotate(int row_padding) {
|
||||
int16 A, B, C, D;
|
||||
|
||||
//Calculate matrix
|
||||
int32 XScale = readw(0x1f8f);
|
||||
int32 YScale = readw(0x1f92);
|
||||
if(XScale & 0x8000)XScale = 0x7fff;
|
||||
if(YScale & 0x8000)YScale = 0x7fff;
|
||||
|
||||
if(readw(0x1f80) == 0) { //no rotation
|
||||
A = (int16)XScale;
|
||||
B = 0;
|
||||
C = 0;
|
||||
D = (int16)YScale;
|
||||
} else if(readw(0x1f80) == 128) { //90 degree rotation
|
||||
A = 0;
|
||||
B = (int16)(-YScale);
|
||||
C = (int16)XScale;
|
||||
D = 0;
|
||||
} else if(readw(0x1f80) == 256) { //180 degree rotation
|
||||
A = (int16)(-XScale);
|
||||
B = 0;
|
||||
C = 0;
|
||||
D = (int16)(-YScale);
|
||||
} else if(readw(0x1f80) == 384) { //270 degree rotation
|
||||
A = 0;
|
||||
B = (int16)YScale;
|
||||
C = (int16)(-XScale);
|
||||
D = 0;
|
||||
} else {
|
||||
A = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * XScale, 15);
|
||||
B = (int16)(-sar(SinTable[readw(0x1f80) & 0x1ff] * YScale, 15));
|
||||
C = (int16) sar(SinTable[readw(0x1f80) & 0x1ff] * XScale, 15);
|
||||
D = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * YScale, 15);
|
||||
}
|
||||
|
||||
//Calculate Pixel Resolution
|
||||
uint8 w = read(0x1f89) & ~7;
|
||||
uint8 h = read(0x1f8c) & ~7;
|
||||
|
||||
//Clear the output RAM
|
||||
memset(ram, 0, (w + row_padding / 4) * h / 2);
|
||||
|
||||
int32 Cx = (int16)readw(0x1f83);
|
||||
int32 Cy = (int16)readw(0x1f86);
|
||||
|
||||
//Calculate start position (i.e. (Ox, Oy) = (0, 0))
|
||||
//The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in
|
||||
//the function. We do Cx*A etc normally because the matrix parameters
|
||||
//already have the fractional parts.
|
||||
int32 LineX = (Cx << 12) - Cx * A - Cx * B;
|
||||
int32 LineY = (Cy << 12) - Cy * C - Cy * D;
|
||||
|
||||
//Start loop
|
||||
uint32 X, Y;
|
||||
uint8 byte;
|
||||
int32 outidx = 0;
|
||||
uint8 bit = 0x80;
|
||||
for(int32 y = 0; y < h; y++) {
|
||||
X = LineX;
|
||||
Y = LineY;
|
||||
for(int32 x = 0; x < w; x++) {
|
||||
if((X >> 12) >= w || (Y >> 12) >= h) {
|
||||
byte = 0;
|
||||
} else {
|
||||
uint32 addr = (Y >> 12) * w + (X >> 12);
|
||||
byte = read(0x600 + (addr >> 1));
|
||||
if(addr & 1) { byte >>= 4; }
|
||||
}
|
||||
|
||||
//De-bitplanify
|
||||
if(byte & 1) { ram[outidx ] |= bit; }
|
||||
if(byte & 2) { ram[outidx + 1] |= bit; }
|
||||
if(byte & 4) { ram[outidx + 16] |= bit; }
|
||||
if(byte & 8) { ram[outidx + 17] |= bit; }
|
||||
|
||||
bit >>= 1;
|
||||
if(!bit) {
|
||||
bit = 0x80;
|
||||
outidx += 32;
|
||||
}
|
||||
|
||||
X += A; //Add 1 to output x => add an A and a C
|
||||
Y += C;
|
||||
}
|
||||
outidx += 2 + row_padding;
|
||||
if(outidx & 0x10) {
|
||||
outidx &= ~0x10;
|
||||
} else {
|
||||
outidx -= w * 4 + row_padding;
|
||||
}
|
||||
LineX += B; //Add 1 to output y => add a B and a D
|
||||
LineY += D;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
//Build OAM
|
||||
void C4::op00_00() {
|
||||
uint32 oamptr = ram[0x626] << 2;
|
||||
for(int32 i = 0x1fd; i > oamptr && i >= 0; i -= 4) {
|
||||
//clear oam-to-be
|
||||
if(i >= 0)ram[i] = 0xe0;
|
||||
}
|
||||
|
||||
uint16 globalx, globaly;
|
||||
uint32 oamptr2;
|
||||
int16 sprx, spry;
|
||||
uint8 sprname, sprattr;
|
||||
uint8 sprcount;
|
||||
globalx = readw(0x621);
|
||||
globaly = readw(0x623);
|
||||
oamptr2 = 0x200 + (ram[0x626] >> 2);
|
||||
|
||||
if(!ram[0x620])return;
|
||||
|
||||
sprcount = 128 - ram[0x626];
|
||||
uint8 offset = (ram[0x626] & 3) * 2;
|
||||
uint32 srcptr = 0x220;
|
||||
for(int i = ram[0x620]; i > 0 && sprcount > 0; i--, srcptr += 16) {
|
||||
sprx = readw(srcptr) - globalx;
|
||||
spry = readw(srcptr + 2) - globaly;
|
||||
sprname = ram[srcptr + 5];
|
||||
sprattr = ram[srcptr + 4] | ram[srcptr + 6];
|
||||
|
||||
uint32 spraddr = readl(srcptr + 7);
|
||||
if(r_mem->read(spraddr)) {
|
||||
int16 x, y;
|
||||
for(int sprcnt = r_mem->read(spraddr++); sprcnt > 0 && sprcount > 0; sprcnt--, spraddr += 4) {
|
||||
x = (int8)r_mem->read(spraddr + 1);
|
||||
if(sprattr & 0x40) {
|
||||
x = -x - ((r_mem->read(spraddr) & 0x20) ? 16 : 8);
|
||||
}
|
||||
x += sprx;
|
||||
if(x >= -16 && x <= 272) {
|
||||
y = (int8)r_mem->read(spraddr + 2);
|
||||
if(sprattr & 0x80) {
|
||||
y = -y - ((r_mem->read(spraddr) & 0x20) ? 16 : 8);
|
||||
}
|
||||
y += spry;
|
||||
if(y >= -16 && y <= 224) {
|
||||
ram[oamptr ] = (uint8)x;
|
||||
ram[oamptr + 1] = (uint8)y;
|
||||
ram[oamptr + 2] = sprname + r_mem->read(spraddr + 3);
|
||||
ram[oamptr + 3] = sprattr ^ (r_mem->read(spraddr) & 0xc0);
|
||||
ram[oamptr2] &= ~(3 << offset);
|
||||
if(x & 0x100)ram[oamptr2] |= 1 << offset;
|
||||
if(r_mem->read(spraddr) & 0x20)ram[oamptr2] |= 2 << offset;
|
||||
oamptr += 4;
|
||||
sprcount--;
|
||||
offset = (offset + 2) & 6;
|
||||
if(!offset)oamptr2++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(sprcount > 0) {
|
||||
ram[oamptr ] = (uint8)sprx;
|
||||
ram[oamptr + 1] = (uint8)spry;
|
||||
ram[oamptr + 2] = sprname;
|
||||
ram[oamptr + 3] = sprattr;
|
||||
ram[oamptr2] &= ~(3 << offset);
|
||||
if(sprx & 0x100)ram[oamptr2] |= 3 << offset;
|
||||
else ram[oamptr2] |= 2 << offset;
|
||||
oamptr += 4;
|
||||
sprcount--;
|
||||
offset = (offset + 2) & 6;
|
||||
if(!offset)oamptr2++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Scale and Rotate
|
||||
void C4::op00_03() {
|
||||
C4DoScaleRotate(0);
|
||||
}
|
||||
|
||||
//Transform Lines
|
||||
void C4::op00_05() {
|
||||
C4WFX2Val = read(0x1f83);
|
||||
C4WFY2Val = read(0x1f86);
|
||||
C4WFDist = read(0x1f89);
|
||||
C4WFScale = read(0x1f8c);
|
||||
|
||||
//Transform Vertices
|
||||
uint32 ptr = 0;
|
||||
for(int32 i = readw(0x1f80); i > 0; i--, ptr += 0x10) {
|
||||
C4WFXVal = readw(ptr + 1);
|
||||
C4WFYVal = readw(ptr + 5);
|
||||
C4WFZVal = readw(ptr + 9);
|
||||
C4TransfWireFrame();
|
||||
|
||||
//Displace
|
||||
writew(ptr + 1, C4WFXVal + 0x80);
|
||||
writew(ptr + 5, C4WFYVal + 0x50);
|
||||
}
|
||||
|
||||
writew(0x600, 23);
|
||||
writew(0x602, 0x60);
|
||||
writew(0x605, 0x40);
|
||||
writew(0x600 + 8, 23);
|
||||
writew(0x602 + 8, 0x60);
|
||||
writew(0x605 + 8, 0x40);
|
||||
|
||||
ptr = 0xb02;
|
||||
uint32 ptr2 = 0;
|
||||
for(int32 i = readw(0xb00); i > 0; i--, ptr += 2, ptr2 += 8) {
|
||||
C4WFXVal = readw((read(ptr + 0) << 4) + 1);
|
||||
C4WFYVal = readw((read(ptr + 0) << 4) + 5);
|
||||
C4WFX2Val = readw((read(ptr + 1) << 4) + 1);
|
||||
C4WFY2Val = readw((read(ptr + 1) << 4) + 5);
|
||||
C4CalcWireFrame();
|
||||
writew(ptr2 + 0x600, C4WFDist ? C4WFDist : 1);
|
||||
writew(ptr2 + 0x602, C4WFXVal);
|
||||
writew(ptr2 + 0x605, C4WFYVal);
|
||||
}
|
||||
}
|
||||
|
||||
//Scale and Rotate
|
||||
void C4::op00_07() {
|
||||
C4DoScaleRotate(64);
|
||||
}
|
||||
|
||||
//Draw Wireframe
|
||||
void C4::op00_08() {
|
||||
C4DrawWireFrame();
|
||||
}
|
||||
|
||||
//Disintegrate
|
||||
void C4::op00_0b() {
|
||||
uint8 width, height;
|
||||
uint32 startx, starty;
|
||||
uint32 srcptr;
|
||||
uint32 x, y;
|
||||
int32 scalex, scaley;
|
||||
int32 cx, cy;
|
||||
int32 i, j;
|
||||
width = read(0x1f89);
|
||||
height = read(0x1f8c);
|
||||
cx = readw(0x1f80);
|
||||
cy = readw(0x1f83);
|
||||
|
||||
scalex = (int16)readw(0x1f86);
|
||||
scaley = (int16)readw(0x1f8f);
|
||||
startx = -cx * scalex + (cx << 8);
|
||||
starty = -cy * scaley + (cy << 8);
|
||||
srcptr = 0x600;
|
||||
|
||||
for(i = 0; i < (width * height) >> 1; i++) {
|
||||
write(i, 0);
|
||||
}
|
||||
|
||||
for(y = starty, i = 0;i < height; i++, y += scaley) {
|
||||
for(x = startx, j = 0;j < width; j++, x += scalex) {
|
||||
if((x >> 8) < width && (y >> 8) < height && (y >> 8) * width + (x >> 8) < 0x2000) {
|
||||
uint8 pixel = (j & 1) ? (ram[srcptr] >> 4) : (ram[srcptr]);
|
||||
int32 index = (y >> 11) * width * 4 + (x >> 11) * 32 + ((y >> 8) & 7) * 2;
|
||||
uint8 mask = 0x80 >> ((x >> 8) & 7);
|
||||
if(pixel & 1)ram[index ] |= mask;
|
||||
if(pixel & 2)ram[index + 1] |= mask;
|
||||
if(pixel & 4)ram[index + 16] |= mask;
|
||||
if(pixel & 8)ram[index + 17] |= mask;
|
||||
}
|
||||
if(j & 1)srcptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Bitplane Wave
|
||||
void C4::op00_0c() {
|
||||
uint32 destptr = 0;
|
||||
uint32 waveptr = read(0x1f83);
|
||||
uint16 mask1 = 0xc0c0;
|
||||
uint16 mask2 = 0x3f3f;
|
||||
|
||||
for(int j = 0; j < 0x10; j++) {
|
||||
do {
|
||||
int16 height = -((int8)read(waveptr + 0xb00)) - 16;
|
||||
for(int i = 0; i < 40; i++) {
|
||||
uint16 temp = readw(destptr + wave_data[i]) & mask2;
|
||||
if(height >= 0) {
|
||||
if(height < 8) {
|
||||
temp |= mask1 & readw(0xa00 + height * 2);
|
||||
} else {
|
||||
temp |= mask1 & 0xff00;
|
||||
}
|
||||
}
|
||||
writew(destptr + wave_data[i], temp);
|
||||
height++;
|
||||
}
|
||||
waveptr = (waveptr + 1) & 0x7f;
|
||||
mask1 = (mask1 >> 2) | (mask1 << 6);
|
||||
mask2 = (mask2 >> 2) | (mask2 << 6);
|
||||
} while(mask1 != 0xc0c0);
|
||||
destptr += 16;
|
||||
|
||||
do {
|
||||
int16 height = -((int8)read(waveptr + 0xb00)) - 16;
|
||||
for(int i = 0; i < 40; i++) {
|
||||
uint16 temp = readw(destptr + wave_data[i]) & mask2;
|
||||
if(height >= 0) {
|
||||
if(height < 8) {
|
||||
temp |= mask1 & readw(0xa10 + height * 2);
|
||||
} else {
|
||||
temp |= mask1 & 0xff00;
|
||||
}
|
||||
}
|
||||
writew(destptr + wave_data[i], temp);
|
||||
height++;
|
||||
}
|
||||
waveptr = (waveptr + 1) & 0x7f;
|
||||
mask1 = (mask1 >> 2) | (mask1 << 6);
|
||||
mask2 = (mask2 >> 2) | (mask2 << 6);
|
||||
} while(mask1 != 0xc0c0);
|
||||
destptr += 16;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
//Sprite Functions
|
||||
void C4::op00() {
|
||||
switch(reg[0x4d]) {
|
||||
case 0x00:op00_00();break;
|
||||
case 0x03:op00_03();break;
|
||||
case 0x05:op00_05();break;
|
||||
case 0x07:op00_07();break;
|
||||
case 0x08:op00_08();break;
|
||||
case 0x0b:op00_0b();break;
|
||||
case 0x0c:op00_0c();break;
|
||||
}
|
||||
}
|
||||
|
||||
//Draw Wireframe
|
||||
void C4::op01() {
|
||||
memset(ram + 0x300, 0, 2304);
|
||||
C4DrawWireFrame();
|
||||
}
|
||||
|
||||
//Propulsion
|
||||
void C4::op05() {
|
||||
int32 temp = 0x10000;
|
||||
if(readw(0x1f83)) {
|
||||
temp = sar((temp / readw(0x1f83)) * readw(0x1f81), 8);
|
||||
}
|
||||
writew(0x1f80, temp);
|
||||
}
|
||||
|
||||
//Set Vector length
|
||||
void C4::op0d() {
|
||||
C41FXVal = readw(0x1f80);
|
||||
C41FYVal = readw(0x1f83);
|
||||
C41FDistVal = readw(0x1f86);
|
||||
tanval = sqrt(((double)C41FYVal) * ((double)C41FYVal) + ((double)C41FXVal) * ((double)C41FXVal));
|
||||
tanval = (double)C41FDistVal / tanval;
|
||||
C41FYVal = (int16)(((double)C41FYVal * tanval) * 0.99);
|
||||
C41FXVal = (int16)(((double)C41FXVal * tanval) * 0.98);
|
||||
writew(0x1f89, C41FXVal);
|
||||
writew(0x1f8c, C41FYVal);
|
||||
}
|
||||
|
||||
//Triangle
|
||||
void C4::op10() {
|
||||
r0 = ldr(0);
|
||||
r1 = ldr(1);
|
||||
|
||||
r4 = r0 & 0x1ff;
|
||||
if(r1 & 0x8000)r1 |= ~0x7fff;
|
||||
|
||||
mul(cos(r4), r1, r5, r2);
|
||||
r5 = (r5 >> 16) & 0xff;
|
||||
r2 = (r2 << 8) + r5;
|
||||
|
||||
mul(sin(r4), r1, r5, r3);
|
||||
r5 = (r5 >> 16) & 0xff;
|
||||
r3 = (r3 << 8) + r5;
|
||||
|
||||
str(0, r0);
|
||||
str(1, r1);
|
||||
str(2, r2);
|
||||
str(3, r3);
|
||||
str(4, r4);
|
||||
str(5, r5);
|
||||
}
|
||||
|
||||
//Triangle
|
||||
void C4::op13() {
|
||||
r0 = ldr(0);
|
||||
r1 = ldr(1);
|
||||
|
||||
r4 = r0 & 0x1ff;
|
||||
|
||||
mul(cos(r4), r1, r5, r2);
|
||||
r5 = (r5 >> 8) & 0xffff;
|
||||
r2 = (r2 << 16) + r5;
|
||||
|
||||
mul(sin(r4), r1, r5, r3);
|
||||
r5 = (r5 >> 8) & 0xffff;
|
||||
r3 = (r3 << 16) + r5;
|
||||
|
||||
str(0, r0);
|
||||
str(1, r1);
|
||||
str(2, r2);
|
||||
str(3, r3);
|
||||
str(4, r4);
|
||||
str(5, r5);
|
||||
}
|
||||
|
||||
//Pythagorean
|
||||
void C4::op15() {
|
||||
C41FXVal = readw(0x1f80);
|
||||
C41FYVal = readw(0x1f83);
|
||||
C41FDist = (int16)sqrt((double)C41FXVal * (double)C41FXVal + (double)C41FYVal * (double)C41FYVal);
|
||||
writew(0x1f80, C41FDist);
|
||||
}
|
||||
|
||||
//Calculate distance
|
||||
void C4::op1f() {
|
||||
C41FXVal = readw(0x1f80);
|
||||
C41FYVal = readw(0x1f83);
|
||||
if(!C41FXVal) {
|
||||
C41FAngleRes = (C41FYVal > 0) ? 0x080 : 0x180;
|
||||
} else {
|
||||
tanval = ((double)C41FYVal) / ((double)C41FXVal);
|
||||
C41FAngleRes = (short)(atan(tanval) / (PI * 2) * 512);
|
||||
C41FAngleRes = C41FAngleRes;
|
||||
if(C41FXVal < 0) {
|
||||
C41FAngleRes += 0x100;
|
||||
}
|
||||
C41FAngleRes &= 0x1ff;
|
||||
}
|
||||
writew(0x1f86, C41FAngleRes);
|
||||
}
|
||||
|
||||
//Trapezoid
|
||||
void C4::op22() {
|
||||
int16 angle1 = readw(0x1f8c) & 0x1ff;
|
||||
int16 angle2 = readw(0x1f8f) & 0x1ff;
|
||||
int32 tan1 = Tan(angle1);
|
||||
int32 tan2 = Tan(angle2);
|
||||
int16 y = readw(0x1f83) - readw(0x1f89);
|
||||
int16 left, right;
|
||||
for(int32 j = 0; j < 225; j++, y++) {
|
||||
if(y >= 0) {
|
||||
left = sar((int32)tan1 * y, 16) - readw(0x1f80) + readw(0x1f86);
|
||||
right = sar((int32)tan2 * y, 16) - readw(0x1f80) + readw(0x1f86) + readw(0x1f93);
|
||||
|
||||
if(left < 0 && right < 0) {
|
||||
left = 1;
|
||||
right = 0;
|
||||
} else if(left < 0) {
|
||||
left = 0;
|
||||
} else if(right < 0) {
|
||||
right = 0;
|
||||
}
|
||||
|
||||
if(left > 255 && right > 255) {
|
||||
left = 255;
|
||||
right = 254;
|
||||
} else if(left > 255) {
|
||||
left = 255;
|
||||
} else if(right > 255) {
|
||||
right = 255;
|
||||
}
|
||||
} else {
|
||||
left = 1;
|
||||
right = 0;
|
||||
}
|
||||
ram[j + 0x800] = (uint8)left;
|
||||
ram[j + 0x900] = (uint8)right;
|
||||
}
|
||||
}
|
||||
|
||||
//Multiply
|
||||
void C4::op25() {
|
||||
r0 = ldr(0);
|
||||
r1 = ldr(1);
|
||||
mul(r0, r1, r0, r1);
|
||||
str(0, r0);
|
||||
str(1, r1);
|
||||
}
|
||||
|
||||
//Transform Coords
|
||||
void C4::op2d() {
|
||||
C4WFXVal = readw(0x1f81);
|
||||
C4WFYVal = readw(0x1f84);
|
||||
C4WFZVal = readw(0x1f87);
|
||||
C4WFX2Val = read (0x1f89);
|
||||
C4WFY2Val = read (0x1f8a);
|
||||
C4WFDist = read (0x1f8b);
|
||||
C4WFScale = readw(0x1f90);
|
||||
C4TransfWireFrame2();
|
||||
writew(0x1f80, C4WFXVal);
|
||||
writew(0x1f83, C4WFYVal);
|
||||
}
|
||||
|
||||
//Sum
|
||||
void C4::op40() {
|
||||
r0 = 0;
|
||||
for(uint32 i=0;i<0x800;i++) {
|
||||
r0 += ram[i];
|
||||
}
|
||||
str(0, r0);
|
||||
}
|
||||
|
||||
//Square
|
||||
void C4::op54() {
|
||||
r0 = ldr(0);
|
||||
mul(r0, r0, r1, r2);
|
||||
str(1, r1);
|
||||
str(2, r2);
|
||||
}
|
||||
|
||||
//Immediate Register
|
||||
void C4::op5c() {
|
||||
str(0, 0x000000);
|
||||
immediate_reg(0);
|
||||
}
|
||||
|
||||
//Immediate Register (Multiple)
|
||||
void C4::op5e() { immediate_reg( 0); }
|
||||
void C4::op60() { immediate_reg( 3); }
|
||||
void C4::op62() { immediate_reg( 6); }
|
||||
void C4::op64() { immediate_reg( 9); }
|
||||
void C4::op66() { immediate_reg(12); }
|
||||
void C4::op68() { immediate_reg(15); }
|
||||
void C4::op6a() { immediate_reg(18); }
|
||||
void C4::op6c() { immediate_reg(21); }
|
||||
void C4::op6e() { immediate_reg(24); }
|
||||
void C4::op70() { immediate_reg(27); }
|
||||
void C4::op72() { immediate_reg(30); }
|
||||
void C4::op74() { immediate_reg(33); }
|
||||
void C4::op76() { immediate_reg(36); }
|
||||
void C4::op78() { immediate_reg(39); }
|
||||
void C4::op7a() { immediate_reg(42); }
|
||||
void C4::op7c() { immediate_reg(45); }
|
||||
|
||||
//Immediate ROM
|
||||
void C4::op89() {
|
||||
str(0, 0x054336);
|
||||
str(1, 0xffffff);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#include "../../base.h"
|
||||
#include "dsp1emu.cpp"
|
||||
|
||||
void DSP1::init() {}
|
||||
void DSP1::enable() {}
|
||||
|
||||
void DSP1::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void DSP1::reset() {
|
||||
dsp1.reset();
|
||||
}
|
||||
|
||||
/*****
|
||||
* addr_decode()
|
||||
* determine whether address is accessing
|
||||
* data register (DR) or status register (SR)
|
||||
* -- 0 (false) = DR
|
||||
* -- 1 (true ) = SR
|
||||
*
|
||||
* note: there is no need to bounds check addresses,
|
||||
* as memory mapper will not allow DSP1 accesses outside
|
||||
* of expected ranges
|
||||
*****/
|
||||
bool DSP1::addr_decode(uint16 addr) {
|
||||
switch(cartridge.info.dsp1_mapper) {
|
||||
|
||||
case Cartridge::DSP1_LOROM_1MB:
|
||||
//$[20-3f]:[8000-bfff] = DR, $[20-3f]:[c000-ffff] = SR
|
||||
return (addr >= 0xc000);
|
||||
|
||||
case Cartridge::DSP1_LOROM_2MB:
|
||||
//$[60-6f]:[0000-3fff] = DR, $[60-6f]:[4000-7fff] = SR
|
||||
return (addr >= 0x4000);
|
||||
|
||||
case Cartridge::DSP1_HIROM:
|
||||
//$[00-1f]:[6000-6fff] = DR, $[00-1f]:[7000-7fff] = SR
|
||||
return (addr >= 0x7000);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8 DSP1::read(uint16 addr) {
|
||||
return (addr_decode(addr) == 0) ? dsp1.getDr() : dsp1.getSr();
|
||||
}
|
||||
|
||||
void DSP1::write(uint16 addr, uint8 data) {
|
||||
if(addr_decode(addr) == 0) {
|
||||
dsp1.setDr(data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "dsp1emu.h"
|
||||
|
||||
class DSP1 {
|
||||
private:
|
||||
Dsp1 dsp1;
|
||||
|
||||
public:
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
bool addr_decode(uint16 addr);
|
||||
uint8 read (uint16 addr);
|
||||
void write(uint16 addr, uint8 data);
|
||||
};
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,127 @@
|
||||
// DSP-1's emulation code
|
||||
//
|
||||
// Based on research by Overload, The Dumper, Neviksti and Andreas Naive
|
||||
// Date: June 2006
|
||||
|
||||
#ifndef __DSP1EMUL_H
|
||||
#define __DSP1EMUL_H
|
||||
|
||||
#define DSP1_VERSION 0x0102
|
||||
|
||||
class Dsp1
|
||||
{
|
||||
public:
|
||||
// The DSP-1 status register has 16 bits, but only
|
||||
// the upper 8 bits can be accessed from an external device, so all these
|
||||
// positions are referred to the upper byte (bits D8 to D15)
|
||||
enum SrFlags {DRC=0x04, DRS=0x10, RQM=0x80};
|
||||
|
||||
// According to Overload's docs, these are the meanings of the flags:
|
||||
// DRC: The Data Register Control (DRC) bit specifies the data transfer length to and from the host CPU.
|
||||
// 0: Data transfer to and from the DSP-1 is 16 bits.
|
||||
// 1: Data transfer to and from the DSP-1 is 8 bits.
|
||||
// DRS: The Data Register Status (DRS) bit indicates the data transfer status in the case of transfering 16-bit data.
|
||||
// 0: Data transfer has terminated.
|
||||
// 1: Data transfer in progress.
|
||||
// RQM: The Request for Master (RQM) indicates that the DSP1 is requesting host CPU for data read/write.
|
||||
// 0: Internal Data Register Transfer.
|
||||
// 1: External Data Register Transfer.
|
||||
|
||||
Dsp1();
|
||||
uint8 getSr(); // return the status register's high byte
|
||||
uint8 getDr();
|
||||
void setDr(uint8 iDr);
|
||||
void reset();
|
||||
|
||||
private:
|
||||
enum FsmMajorState {WAIT_COMMAND, READ_DATA, WRITE_DATA};
|
||||
enum MaxDataAccesses {MAX_READS=7, MAX_WRITES=1024};
|
||||
|
||||
struct Command {
|
||||
void (Dsp1::*callback)(int16 *, int16 *);
|
||||
unsigned int reads;
|
||||
unsigned int writes;
|
||||
};
|
||||
|
||||
static const Command mCommandTable[];
|
||||
static const int16 MaxAZS_Exp[16];
|
||||
static const int16 SinTable[];
|
||||
static const int16 MulTable[];
|
||||
static const uint16 DataRom[];
|
||||
|
||||
struct SharedData { // some RAM variables shared between commands
|
||||
int16 MatrixA[3][3]; // attitude matrix A
|
||||
int16 MatrixB[3][3];
|
||||
int16 MatrixC[3][3];
|
||||
int16 CentreX, CentreY, CentreZ; // center of projection
|
||||
int16 CentreZ_C, CentreZ_E;
|
||||
int16 VOffset; // vertical offset of the screen with regard to the centre of projection
|
||||
int16 Les, C_Les, E_Les;
|
||||
int16 SinAas, CosAas;
|
||||
int16 SinAzs, CosAzs;
|
||||
int16 SinAZS, CosAZS;
|
||||
int16 SecAZS_C1, SecAZS_E1;
|
||||
int16 SecAZS_C2, SecAZS_E2;
|
||||
int16 Nx, Ny, Nz; // normal vector to the screen (norm 1, points toward the center of projection)
|
||||
int16 Gx, Gy, Gz; // center of the screen (global coordinates)
|
||||
int16 Hx, Hy; // horizontal vector of the screen (Hz=0, norm 1, points toward the right of the screen)
|
||||
int16 Vx, Vy, Vz; // vertical vector of the screen (norm 1, points toward the top of the screen)
|
||||
|
||||
} shared;
|
||||
|
||||
uint8 mSr; // status register
|
||||
int mSrLowByteAccess;
|
||||
uint16 mDr; // "internal" representation of the data register
|
||||
FsmMajorState mFsmMajorState; // current major state of the FSM
|
||||
uint8 mCommand; // current command processed by the FSM
|
||||
uint8 mDataCounter; // #uint16 read/writes counter used by the FSM
|
||||
int16 mReadBuffer[MAX_READS];
|
||||
int16 mWriteBuffer[MAX_WRITES];
|
||||
bool mFreeze; // need explanation? ;)
|
||||
|
||||
void fsmStep(bool read, uint8 &data); // FSM logic
|
||||
|
||||
// commands
|
||||
void memoryTest(int16 *input, int16 *output);
|
||||
void memoryDump(int16 *input, int16 *output);
|
||||
void memorySize(int16 *input, int16 *output);
|
||||
void multiply(int16* input, int16* output);
|
||||
void multiply2(int16* input, int16* output);
|
||||
void inverse(int16 *input, int16 *output);
|
||||
void triangle(int16 *input, int16 *output);
|
||||
void radius(int16 *input, int16 *output);
|
||||
void range(int16 *input, int16 *output);
|
||||
void range2(int16 *input, int16 *output);
|
||||
void distance(int16 *input, int16 *output);
|
||||
void rotate(int16 *input, int16 *output);
|
||||
void polar(int16 *input, int16 *output);
|
||||
void attitudeA(int16 *input, int16 *output);
|
||||
void attitudeB(int16 *input, int16 *output);
|
||||
void attitudeC(int16 *input, int16 *output);
|
||||
void objectiveA(int16 *input, int16 *output);
|
||||
void objectiveB(int16 *input, int16 *output);
|
||||
void objectiveC(int16 *input, int16 *output);
|
||||
void subjectiveA(int16 *input, int16 *output);
|
||||
void subjectiveB(int16 *input, int16 *output);
|
||||
void subjectiveC(int16 *input, int16 *output);
|
||||
void scalarA(int16 *input, int16 *output);
|
||||
void scalarB(int16 *input, int16 *output);
|
||||
void scalarC(int16 *input, int16 *output);
|
||||
void gyrate(int16 *input, int16 *output);
|
||||
void parameter(int16 *input, int16 *output);
|
||||
void raster(int16 *input, int16 *output);
|
||||
void target(int16 *input, int16 *output);
|
||||
void project(int16 *input, int16 *output);
|
||||
|
||||
// auxiliar functions
|
||||
int16 sin(int16 Angle);
|
||||
int16 cos(int16 Angle);
|
||||
void inverse(int16 Coefficient, int16 Exponent, int16 &iCoefficient, int16 &iExponent);
|
||||
int16 denormalizeAndClip(int16 C, int16 E);
|
||||
void normalize(int16 m, int16 &Coefficient, int16 &Exponent);
|
||||
void normalizeDouble(int32 Product, int16 &Coefficient, int16 &Exponent);
|
||||
int16 shiftR(int16 C, int16 E);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
#include "../../base.h"
|
||||
#include "dsp2_op.cpp"
|
||||
|
||||
void DSP2::init() {}
|
||||
void DSP2::enable() {}
|
||||
|
||||
void DSP2::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void DSP2::reset() {
|
||||
status.waiting_for_command = true;
|
||||
status.in_count = 0;
|
||||
status.in_index = 0;
|
||||
status.out_count = 0;
|
||||
status.out_index = 0;
|
||||
|
||||
status.op05transparent = 0;
|
||||
status.op05haslen = false;
|
||||
status.op05len = 0;
|
||||
status.op06haslen = false;
|
||||
status.op06len = 0;
|
||||
status.op09word1 = 0;
|
||||
status.op09word2 = 0;
|
||||
status.op0dhaslen = false;
|
||||
status.op0doutlen = 0;
|
||||
status.op0dinlen = 0;
|
||||
}
|
||||
|
||||
uint8 DSP2::read(uint16 addr) {
|
||||
uint8 r = 0xff;
|
||||
if(status.out_count) {
|
||||
r = status.output[status.out_index++];
|
||||
status.out_index &= 511;
|
||||
if(status.out_count == status.out_index) {
|
||||
status.out_count = 0;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void DSP2::write(uint16 addr, uint8 data) {
|
||||
if(status.waiting_for_command) {
|
||||
status.command = data;
|
||||
status.in_index = 0;
|
||||
status.waiting_for_command = false;
|
||||
|
||||
switch(data) {
|
||||
case 0x01: status.in_count = 32; break;
|
||||
case 0x03: status.in_count = 1; break;
|
||||
case 0x05: status.in_count = 1; break;
|
||||
case 0x06: status.in_count = 1; break;
|
||||
case 0x07: break;
|
||||
case 0x08: break;
|
||||
case 0x09: status.in_count = 4; break;
|
||||
case 0x0d: status.in_count = 2; break;
|
||||
case 0x0f: status.in_count = 0; break;
|
||||
}
|
||||
} else {
|
||||
status.parameters[status.in_index++] = data;
|
||||
status.in_index &= 511;
|
||||
}
|
||||
|
||||
if(status.in_count == status.in_index) {
|
||||
status.waiting_for_command = true;
|
||||
status.out_index = 0;
|
||||
switch(status.command) {
|
||||
case 0x01: {
|
||||
status.out_count = 32;
|
||||
op01();
|
||||
} break;
|
||||
|
||||
case 0x03: {
|
||||
op03();
|
||||
} break;
|
||||
|
||||
case 0x05: {
|
||||
if(status.op05haslen) {
|
||||
status.op05haslen = false;
|
||||
status.out_count = status.op05len;
|
||||
op05();
|
||||
} else {
|
||||
status.op05len = status.parameters[0];
|
||||
status.in_index = 0;
|
||||
status.in_count = status.op05len * 2;
|
||||
status.op05haslen = true;
|
||||
if(data)status.waiting_for_command = false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case 0x06: {
|
||||
if(status.op06haslen) {
|
||||
status.op06haslen = false;
|
||||
status.out_count = status.op06len;
|
||||
op06();
|
||||
} else {
|
||||
status.op06len = status.parameters[0];
|
||||
status.in_index = 0;
|
||||
status.in_count = status.op06len;
|
||||
status.op06haslen = true;
|
||||
if(data)status.waiting_for_command = false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case 0x07: break;
|
||||
case 0x08: break;
|
||||
|
||||
case 0x09: {
|
||||
op09();
|
||||
} break;
|
||||
|
||||
case 0x0d: {
|
||||
if(status.op0dhaslen) {
|
||||
status.op0dhaslen = false;
|
||||
status.out_count = status.op0doutlen;
|
||||
op0d();
|
||||
} else {
|
||||
status.op0dinlen = status.parameters[0];
|
||||
status.op0doutlen = status.parameters[1];
|
||||
status.in_index = 0;
|
||||
status.in_count = (status.op0dinlen + 1) >> 1;
|
||||
status.op0dhaslen = true;
|
||||
if(data)status.waiting_for_command = false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case 0x0f: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DSP2::DSP2() {}
|
||||
DSP2::~DSP2() {}
|
||||
@@ -0,0 +1,41 @@
|
||||
class DSP2 {
|
||||
public:
|
||||
struct {
|
||||
bool waiting_for_command;
|
||||
uint command;
|
||||
uint in_count, in_index;
|
||||
uint out_count, out_index;
|
||||
|
||||
uint8 parameters[512];
|
||||
uint8 output[512];
|
||||
|
||||
uint8 op05transparent;
|
||||
bool op05haslen;
|
||||
int op05len;
|
||||
bool op06haslen;
|
||||
int op06len;
|
||||
uint16 op09word1;
|
||||
uint16 op09word2;
|
||||
bool op0dhaslen;
|
||||
int op0doutlen;
|
||||
int op0dinlen;
|
||||
} status;
|
||||
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
void op01();
|
||||
void op03();
|
||||
void op05();
|
||||
void op06();
|
||||
void op09();
|
||||
void op0d();
|
||||
|
||||
uint8 read (uint16 addr);
|
||||
void write(uint16 addr, uint8 data);
|
||||
|
||||
DSP2();
|
||||
~DSP2();
|
||||
};
|
||||
@@ -0,0 +1,173 @@
|
||||
//convert bitmap to bitplane tile
|
||||
void DSP2::op01() {
|
||||
//op01 size is always 32 bytes input and output
|
||||
//the hardware does strange things if you vary the size
|
||||
|
||||
unsigned char c0, c1, c2, c3;
|
||||
unsigned char *p1 = status.parameters;
|
||||
unsigned char *p2a = status.output;
|
||||
unsigned char *p2b = status.output + 16; //halfway
|
||||
|
||||
//process 8 blocks of 4 bytes each
|
||||
for(int j = 0; j < 8; j++) {
|
||||
c0 = *p1++;
|
||||
c1 = *p1++;
|
||||
c2 = *p1++;
|
||||
c3 = *p1++;
|
||||
|
||||
*p2a++ = (c0 & 0x10) << 3 |
|
||||
(c0 & 0x01) << 6 |
|
||||
(c1 & 0x10) << 1 |
|
||||
(c1 & 0x01) << 4 |
|
||||
(c2 & 0x10) >> 1 |
|
||||
(c2 & 0x01) << 2 |
|
||||
(c3 & 0x10) >> 3 |
|
||||
(c3 & 0x01);
|
||||
|
||||
*p2a++ = (c0 & 0x20) << 2 |
|
||||
(c0 & 0x02) << 5 |
|
||||
(c1 & 0x20) |
|
||||
(c1 & 0x02) << 3 |
|
||||
(c2 & 0x20) >> 2 |
|
||||
(c2 & 0x02) << 1 |
|
||||
(c3 & 0x20) >> 4 |
|
||||
(c3 & 0x02) >> 1;
|
||||
|
||||
*p2b++ = (c0 & 0x40) << 1 |
|
||||
(c0 & 0x04) << 4 |
|
||||
(c1 & 0x40) >> 1 |
|
||||
(c1 & 0x04) << 2 |
|
||||
(c2 & 0x40) >> 3 |
|
||||
(c2 & 0x04) |
|
||||
(c3 & 0x40) >> 5 |
|
||||
(c3 & 0x04) >> 2;
|
||||
|
||||
*p2b++ = (c0 & 0x80) |
|
||||
(c0 & 0x08) << 3 |
|
||||
(c1 & 0x80) >> 2 |
|
||||
(c1 & 0x08) << 1 |
|
||||
(c2 & 0x80) >> 4 |
|
||||
(c2 & 0x08) >> 1 |
|
||||
(c3 & 0x80) >> 6 |
|
||||
(c3 & 0x08) >> 3;
|
||||
}
|
||||
}
|
||||
|
||||
//set transparent color
|
||||
void DSP2::op03() {
|
||||
status.op05transparent = status.parameters[0];
|
||||
}
|
||||
|
||||
//replace bitmap using transparent color
|
||||
void DSP2::op05() {
|
||||
uint8 color;
|
||||
// Overlay bitmap with transparency.
|
||||
// Input:
|
||||
//
|
||||
// Bitmap 1: i[0] <=> i[size-1]
|
||||
// Bitmap 2: i[size] <=> i[2*size-1]
|
||||
//
|
||||
// Output:
|
||||
//
|
||||
// Bitmap 3: o[0] <=> o[size-1]
|
||||
//
|
||||
// Processing:
|
||||
//
|
||||
// Process all 4-bit pixels (nibbles) in the bitmap
|
||||
//
|
||||
// if ( BM2_pixel == transparent_color )
|
||||
// pixelout = BM1_pixel
|
||||
// else
|
||||
// pixelout = BM2_pixel
|
||||
|
||||
// The max size bitmap is limited to 255 because the size parameter is a byte
|
||||
// I think size=0 is an error. The behavior of the chip on size=0 is to
|
||||
// return the last value written to DR if you read DR on Op05 with
|
||||
// size = 0. I don't think it's worth implementing this quirk unless it's
|
||||
// proven necessary.
|
||||
|
||||
unsigned char c1, c2;
|
||||
unsigned char *p1 = status.parameters;
|
||||
unsigned char *p2 = status.parameters + status.op05len;
|
||||
unsigned char *p3 = status.output;
|
||||
|
||||
color = status.op05transparent & 0x0f;
|
||||
|
||||
for(int n = 0; n < status.op05len; n++) {
|
||||
c1 = *p1++;
|
||||
c2 = *p2++;
|
||||
*p3++ = ( ((c2 >> 4) == color ) ? c1 & 0xf0 : c2 & 0xf0 ) |
|
||||
( ((c2 & 0x0f) == color ) ? c1 & 0x0f : c2 & 0x0f );
|
||||
}
|
||||
}
|
||||
|
||||
//reverse bitmap
|
||||
void DSP2::op06() {
|
||||
// Input:
|
||||
// size
|
||||
// bitmap
|
||||
|
||||
int i, j;
|
||||
for(i = 0, j = status.op06len - 1; i < status.op06len; i++, j--) {
|
||||
status.output[j] = (status.parameters[i] << 4) | (status.parameters[i] >> 4);
|
||||
}
|
||||
}
|
||||
|
||||
//multiply
|
||||
void DSP2::op09() {
|
||||
status.out_count = 4;
|
||||
|
||||
status.op09word1 = status.parameters[0] | (status.parameters[1] << 8);
|
||||
status.op09word2 = status.parameters[2] | (status.parameters[3] << 8);
|
||||
|
||||
uint32 r;
|
||||
r = status.op09word1 * status.op09word2;
|
||||
status.output[0] = r;
|
||||
status.output[1] = r >> 8;
|
||||
status.output[2] = r >> 16;
|
||||
status.output[3] = r >> 24;
|
||||
}
|
||||
|
||||
//scale bitmap
|
||||
void DSP2::op0d() {
|
||||
// Bit accurate hardware algorithm - uses fixed point math
|
||||
// This should match the DSP2 Op0D output exactly
|
||||
// I wouldn't recommend using this unless you're doing hardware debug.
|
||||
// In some situations it has small visual artifacts that
|
||||
// are not readily apparent on a TV screen but show up clearly
|
||||
// on a monitor. Use Overload's scaling instead.
|
||||
// This is for hardware verification testing.
|
||||
//
|
||||
// One note: the HW can do odd byte scaling but since we divide
|
||||
// by two to get the count of bytes this won't work well for
|
||||
// odd byte scaling (in any of the current algorithm implementations).
|
||||
// So far I haven't seen Dungeon Master use it.
|
||||
// If it does we can adjust the parameters and code to work with it
|
||||
|
||||
uint32 multiplier; // Any size int >= 32-bits
|
||||
uint32 pixloc; // match size of multiplier
|
||||
int i, j;
|
||||
uint8 pixelarray[512];
|
||||
if(status.op0dinlen <= status.op0doutlen) {
|
||||
multiplier = 0x10000; // In our self defined fixed point 0x10000 == 1
|
||||
} else {
|
||||
multiplier = (status.op0dinlen << 17) / ((status.op0doutlen << 1) + 1);
|
||||
}
|
||||
|
||||
pixloc = 0;
|
||||
for(i = 0; i < status.op0doutlen * 2; i++) {
|
||||
j = pixloc >> 16;
|
||||
|
||||
if(j & 1) {
|
||||
pixelarray[i] = (status.parameters[j >> 1] & 0x0f);
|
||||
} else {
|
||||
pixelarray[i] = (status.parameters[j >> 1] & 0xf0) >> 4;
|
||||
}
|
||||
|
||||
pixloc += multiplier;
|
||||
}
|
||||
|
||||
for(i = 0; i < status.op0doutlen; i++) {
|
||||
status.output[i] = (pixelarray[i << 1] << 4) | pixelarray[(i << 1) + 1];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
#include "../../base.h"
|
||||
|
||||
void OBC1::init() {}
|
||||
void OBC1::enable() {}
|
||||
|
||||
void OBC1::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void OBC1::reset() {
|
||||
memset(cartridge.sram, 0xff, 0x2000);
|
||||
status.baseptr = (cartridge.sram[0x1ff5] & 1) ? 0x1800 : 0x1c00;
|
||||
status.address = (cartridge.sram[0x1ff6] & 0x7f);
|
||||
status.shift = (cartridge.sram[0x1ff6] & 3) << 1;
|
||||
}
|
||||
|
||||
uint8 OBC1::read(uint16 addr) {
|
||||
addr &= 0x1fff;
|
||||
|
||||
if((addr & 0x1ff8) != 0x1ff0) {
|
||||
return cartridge.sram[addr];
|
||||
}
|
||||
|
||||
switch(addr) {
|
||||
case 0x1ff0:
|
||||
return cartridge.sram[status.baseptr + (status.address << 2) + 0];
|
||||
case 0x1ff1:
|
||||
return cartridge.sram[status.baseptr + (status.address << 2) + 1];
|
||||
case 0x1ff2:
|
||||
return cartridge.sram[status.baseptr + (status.address << 2) + 2];
|
||||
case 0x1ff3:
|
||||
return cartridge.sram[status.baseptr + (status.address << 2) + 3];
|
||||
case 0x1ff4:
|
||||
return cartridge.sram[status.baseptr + (status.address >> 2) + 0x200];
|
||||
case 0x1ff5:
|
||||
case 0x1ff6:
|
||||
case 0x1ff7:
|
||||
return cartridge.sram[addr];
|
||||
}
|
||||
|
||||
//never used, blocks compiler warning
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void OBC1::write(uint16 addr, uint8 data) {
|
||||
addr &= 0x1fff;
|
||||
|
||||
if((addr & 0x1ff8) != 0x1ff0) {
|
||||
cartridge.sram[addr] = data;
|
||||
return;
|
||||
}
|
||||
|
||||
switch(addr) {
|
||||
case 0x1ff0:
|
||||
cartridge.sram[status.baseptr + (status.address << 2) + 0] = data;
|
||||
break;
|
||||
case 0x1ff1:
|
||||
cartridge.sram[status.baseptr + (status.address << 2) + 1] = data;
|
||||
break;
|
||||
case 0x1ff2:
|
||||
cartridge.sram[status.baseptr + (status.address << 2) + 2] = data;
|
||||
break;
|
||||
case 0x1ff3:
|
||||
cartridge.sram[status.baseptr + (status.address << 2) + 3] = data;
|
||||
break;
|
||||
case 0x1ff4: {
|
||||
uint8 temp;
|
||||
temp = cartridge.sram[status.baseptr + (status.address >> 2) + 0x200];
|
||||
temp = (temp & ~(3 << status.shift)) | ((data & 3) << status.shift);
|
||||
cartridge.sram[status.baseptr + (status.address >> 2) + 0x200] = temp;
|
||||
} break;
|
||||
case 0x1ff5:
|
||||
status.baseptr = (data & 1) ? 0x1800 : 0x1c00;
|
||||
cartridge.sram[addr] = data;
|
||||
break;
|
||||
case 0x1ff6:
|
||||
status.address = (data & 0x7f);
|
||||
status.shift = (data & 3) << 1;
|
||||
cartridge.sram[addr] = data;
|
||||
break;
|
||||
case 0x1ff7:
|
||||
cartridge.sram[addr] = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
OBC1::OBC1() {}
|
||||
OBC1::~OBC1() {}
|
||||
@@ -0,0 +1,18 @@
|
||||
class OBC1 {
|
||||
public:
|
||||
struct {
|
||||
uint16 address;
|
||||
uint16 baseptr;
|
||||
uint16 shift;
|
||||
} status;
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 read (uint16 addr);
|
||||
void write(uint16 addr, uint8 data);
|
||||
|
||||
OBC1();
|
||||
~OBC1();
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
#include "../../base.h"
|
||||
#include "sdd1emu.cpp"
|
||||
|
||||
void SDD1::init() {}
|
||||
|
||||
void SDD1::enable() {
|
||||
for(int i = 0x4800; i <= 0x4807; i++) {
|
||||
r_mem->set_mmio_mapper(i, this);
|
||||
}
|
||||
}
|
||||
|
||||
void SDD1::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void SDD1::reset() {
|
||||
sdd1.index[0] = 0x000000;
|
||||
sdd1.index[1] = 0x100000;
|
||||
sdd1.index[2] = 0x200000;
|
||||
sdd1.index[3] = 0x300000;
|
||||
|
||||
for(int i=0;i<8;i++) {
|
||||
sdd1.active[i] = false;
|
||||
}
|
||||
|
||||
sdd1.dma_active = false;
|
||||
}
|
||||
|
||||
uint32 SDD1::offset(uint32 addr) {
|
||||
uint8 b = (addr >> 16) & 0xff;
|
||||
if(b <= 0xbf)return 0;
|
||||
|
||||
b -= 0xc0; //b = 0x00-0x3f
|
||||
b >>= 4; //b = 0-3
|
||||
b &= 3; //bitmask
|
||||
|
||||
return sdd1.index[b] + (addr & 0x0fffff);
|
||||
}
|
||||
|
||||
uint8 SDD1::mmio_read(uint16 addr) {
|
||||
switch(addr) {
|
||||
//>>20 == 0x100000 == 1mb
|
||||
case 0x4804:return (sdd1.index[0] >> 20) & 7;
|
||||
case 0x4805:return (sdd1.index[1] >> 20) & 7;
|
||||
case 0x4806:return (sdd1.index[2] >> 20) & 7;
|
||||
case 0x4807:return (sdd1.index[3] >> 20) & 7;
|
||||
}
|
||||
|
||||
return r_cpu->regs.mdr;
|
||||
}
|
||||
|
||||
void SDD1::mmio_write(uint16 addr, uint8 data) {
|
||||
switch(addr) {
|
||||
case 0x4801:
|
||||
for(int i = 0; i < 8; i++) {
|
||||
sdd1.active[i] = !!(data & (1 << i));
|
||||
}
|
||||
break;
|
||||
//<<20 == 0x100000 == 1mb
|
||||
case 0x4804:sdd1.index[0] = (data & 7) << 20;break;
|
||||
case 0x4805:sdd1.index[1] = (data & 7) << 20;break;
|
||||
case 0x4806:sdd1.index[2] = (data & 7) << 20;break;
|
||||
case 0x4807:sdd1.index[3] = (data & 7) << 20;break;
|
||||
}
|
||||
}
|
||||
|
||||
void SDD1::dma_begin(uint8 channel, uint32 addr, uint16 length) {
|
||||
if(sdd1.active[channel] == true) {
|
||||
sdd1.active[channel] = false;
|
||||
sdd1.dma_active = true;
|
||||
sdd1.buffer_index = 0;
|
||||
sdd1.buffer_size = length;
|
||||
sdd1emu.decompress(addr, (length) ? length : 65536, sdd1.buffer);
|
||||
}
|
||||
}
|
||||
|
||||
bool SDD1::dma_active() {
|
||||
return sdd1.dma_active;
|
||||
}
|
||||
|
||||
uint8 SDD1::dma_read() {
|
||||
if(--sdd1.buffer_size == 0) {
|
||||
sdd1.dma_active = false;
|
||||
}
|
||||
|
||||
//sdd1.buffer[] is 65536 bytes, and sdd1.buffer_index
|
||||
//is of type uint16, so no buffer overflow is possible
|
||||
return sdd1.buffer[sdd1.buffer_index++];
|
||||
}
|
||||
|
||||
SDD1::SDD1() {}
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "sdd1emu.h"
|
||||
|
||||
class SDD1 : public MMIO {
|
||||
public:
|
||||
SDD1emu sdd1emu;
|
||||
|
||||
struct {
|
||||
uint32 index[4]; //memory mapping registers
|
||||
uint8 buffer[65536]; //pointer to decompressed S-DD1 data,
|
||||
//max. DMA length is 65536
|
||||
uint16 buffer_index; //DMA read index into S-DD1 decompression buffer
|
||||
uint16 buffer_size;
|
||||
bool active[8]; //true when DMA channel should pass through S-DD1
|
||||
bool dma_active;
|
||||
} sdd1;
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
uint32 offset(uint32 addr);
|
||||
|
||||
void dma_begin(uint8 channel, uint32 addr, uint16 length);
|
||||
bool dma_active();
|
||||
uint8 dma_read();
|
||||
|
||||
uint8 mmio_read (uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
SDD1();
|
||||
};
|
||||
@@ -0,0 +1,447 @@
|
||||
/************************************************************************
|
||||
|
||||
S-DD1'algorithm emulation code
|
||||
------------------------------
|
||||
|
||||
Author: Andreas Naive
|
||||
Date: August 2003
|
||||
Last update: October 2004
|
||||
|
||||
This code is Public Domain. There is no copyright holded by the author.
|
||||
Said this, the author wish to explicitly emphasize his inalienable moral rights
|
||||
over this piece of intelectual work and the previous research that made it
|
||||
possible, as recognized by most of the copyright laws around the world.
|
||||
|
||||
This code is provided 'as-is', with no warranty, expressed or implied.
|
||||
No responsability is assumed by the author in connection with it.
|
||||
|
||||
The author is greatly indebted with The Dumper, without whose help and
|
||||
patience providing him with real S-DD1 data the research would have never been
|
||||
possible. He also wish to note that in the very beggining of his research,
|
||||
Neviksti had done some steps in the right direction. By last, the author is
|
||||
indirectly indebted to all the people that worked and contributed in the
|
||||
S-DD1 issue in the past.
|
||||
|
||||
An algorithm's documentation is available as a separate document.
|
||||
The implementation is obvious when the algorithm is
|
||||
understood.
|
||||
|
||||
************************************************************************/
|
||||
|
||||
#define SDD1_read(__addr) (r_mem->read(__addr))
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_IM::prepareDecomp(uint32 in_buf) {
|
||||
|
||||
byte_ptr=in_buf;
|
||||
bit_count=4;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
||||
uint8 SDD1_IM::getCodeword(uint8 code_len) {
|
||||
|
||||
uint8 codeword;
|
||||
uint8 comp_count;
|
||||
|
||||
codeword = (SDD1_read(byte_ptr))<<bit_count;
|
||||
|
||||
++bit_count;
|
||||
|
||||
if (codeword & 0x80) {
|
||||
codeword |= SDD1_read(byte_ptr+1)>>(9-bit_count);
|
||||
bit_count+=code_len;
|
||||
}
|
||||
|
||||
if (bit_count & 0x08) {
|
||||
byte_ptr++;
|
||||
bit_count&=0x07;
|
||||
}
|
||||
|
||||
return codeword;
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1_GCD::SDD1_GCD(SDD1_IM *associatedIM) :
|
||||
IM(associatedIM)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_GCD::getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind) {
|
||||
|
||||
const uint8 run_count[] = {
|
||||
0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00,
|
||||
0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00,
|
||||
0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01,
|
||||
0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00,
|
||||
0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03,
|
||||
0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01,
|
||||
0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02,
|
||||
0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00,
|
||||
0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07,
|
||||
0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03,
|
||||
0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05,
|
||||
0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01,
|
||||
0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06,
|
||||
0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02,
|
||||
0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04,
|
||||
0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00,
|
||||
0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f,
|
||||
0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07,
|
||||
0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b,
|
||||
0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03,
|
||||
0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d,
|
||||
0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05,
|
||||
0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09,
|
||||
0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01,
|
||||
0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e,
|
||||
0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06,
|
||||
0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a,
|
||||
0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02,
|
||||
0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c,
|
||||
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04,
|
||||
0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
|
||||
0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00,
|
||||
};
|
||||
|
||||
uint8 codeword=IM->getCodeword(code_num);
|
||||
|
||||
if (codeword & 0x80) {
|
||||
*LPSind=1;
|
||||
*MPScount=run_count[codeword>>(code_num^0x07)];
|
||||
}
|
||||
else {
|
||||
*MPScount=(1<<code_num);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
SDD1_BG::SDD1_BG(SDD1_GCD *associatedGCD, uint8 code) :
|
||||
GCD(associatedGCD), code_num(code)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_BG::prepareDecomp(void) {
|
||||
|
||||
MPScount=0;
|
||||
LPSind=0;
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
|
||||
|
||||
uint8 SDD1_BG::getBit(bool8 *endOfRun) {
|
||||
|
||||
uint8 bit;
|
||||
|
||||
if (!(MPScount || LPSind)) GCD->getRunCount(code_num, &MPScount, &LPSind);
|
||||
|
||||
if (MPScount) {
|
||||
bit=0;
|
||||
MPScount--;
|
||||
}
|
||||
else {
|
||||
bit=1;
|
||||
LPSind=0;
|
||||
}
|
||||
|
||||
if (MPScount || LPSind) (*endOfRun)=0;
|
||||
else (*endOfRun)=1;
|
||||
|
||||
return bit;
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1_PEM::SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
|
||||
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
|
||||
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
|
||||
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7) {
|
||||
|
||||
BG[0]=associatedBG0;
|
||||
BG[1]=associatedBG1;
|
||||
BG[2]=associatedBG2;
|
||||
BG[3]=associatedBG3;
|
||||
BG[4]=associatedBG4;
|
||||
BG[5]=associatedBG5;
|
||||
BG[6]=associatedBG6;
|
||||
BG[7]=associatedBG7;
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
const SDD1_PEM::state SDD1_PEM::evolution_table[]={
|
||||
{ 0,25,25},
|
||||
{ 0, 2, 1},
|
||||
{ 0, 3, 1},
|
||||
{ 0, 4, 2},
|
||||
{ 0, 5, 3},
|
||||
{ 1, 6, 4},
|
||||
{ 1, 7, 5},
|
||||
{ 1, 8, 6},
|
||||
{ 1, 9, 7},
|
||||
{ 2,10, 8},
|
||||
{ 2,11, 9},
|
||||
{ 2,12,10},
|
||||
{ 2,13,11},
|
||||
{ 3,14,12},
|
||||
{ 3,15,13},
|
||||
{ 3,16,14},
|
||||
{ 3,17,15},
|
||||
{ 4,18,16},
|
||||
{ 4,19,17},
|
||||
{ 5,20,18},
|
||||
{ 5,21,19},
|
||||
{ 6,22,20},
|
||||
{ 6,23,21},
|
||||
{ 7,24,22},
|
||||
{ 7,24,23},
|
||||
{ 0,26, 1},
|
||||
{ 1,27, 2},
|
||||
{ 2,28, 4},
|
||||
{ 3,29, 8},
|
||||
{ 4,30,12},
|
||||
{ 5,31,16},
|
||||
{ 6,32,18},
|
||||
{ 7,24,22}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_PEM::prepareDecomp(void) {
|
||||
|
||||
for (uint8 i=0; i<32; i++) {
|
||||
contextInfo[i].status=0;
|
||||
contextInfo[i].MPS=0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
uint8 SDD1_PEM::getBit(uint8 context) {
|
||||
|
||||
bool8 endOfRun;
|
||||
uint8 bit;
|
||||
|
||||
SDD1_ContextInfo *pContInfo=&contextInfo[context];
|
||||
uint8 currStatus = pContInfo->status;
|
||||
const state *pState=&SDD1_PEM::evolution_table[currStatus];
|
||||
uint8 currentMPS=pContInfo->MPS;
|
||||
|
||||
bit=(BG[pState->code_num])->getBit(&endOfRun);
|
||||
|
||||
if (endOfRun)
|
||||
if (bit) {
|
||||
if (!(currStatus & 0xfe)) (pContInfo->MPS)^=0x01;
|
||||
(pContInfo->status)=pState->nextIfLPS;
|
||||
}
|
||||
else
|
||||
(pContInfo->status)=pState->nextIfMPS;
|
||||
|
||||
return bit^currentMPS;
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1_CM::SDD1_CM(SDD1_PEM *associatedPEM) :
|
||||
PEM(associatedPEM)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_CM::prepareDecomp(uint32 first_byte) {
|
||||
|
||||
bitplanesInfo = SDD1_read(first_byte) & 0xc0;
|
||||
contextBitsInfo = SDD1_read(first_byte) & 0x30;
|
||||
bit_number=0;
|
||||
for (int i=0; i<8; i++) prevBitplaneBits[i]=0;
|
||||
switch (bitplanesInfo) {
|
||||
case 0x00:
|
||||
currBitplane = 1;
|
||||
break;
|
||||
case 0x40:
|
||||
currBitplane = 7;
|
||||
break;
|
||||
case 0x80:
|
||||
currBitplane = 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
uint8 SDD1_CM::getBit(void) {
|
||||
|
||||
uint8 currContext;
|
||||
uint16 *context_bits;
|
||||
|
||||
switch (bitplanesInfo) {
|
||||
case 0x00:
|
||||
currBitplane ^= 0x01;
|
||||
break;
|
||||
case 0x40:
|
||||
currBitplane ^= 0x01;
|
||||
if (!(bit_number & 0x7f)) currBitplane = ((currBitplane+2) & 0x07);
|
||||
break;
|
||||
case 0x80:
|
||||
currBitplane ^= 0x01;
|
||||
if (!(bit_number & 0x7f)) currBitplane ^= 0x02;
|
||||
break;
|
||||
case 0xc0:
|
||||
currBitplane = bit_number & 0x07;
|
||||
}
|
||||
|
||||
context_bits = &prevBitplaneBits[currBitplane];
|
||||
|
||||
currContext=(currBitplane & 0x01)<<4;
|
||||
switch (contextBitsInfo) {
|
||||
case 0x00:
|
||||
currContext|=((*context_bits & 0x01c0)>>5)|(*context_bits & 0x0001);
|
||||
break;
|
||||
case 0x10:
|
||||
currContext|=((*context_bits & 0x0180)>>5)|(*context_bits & 0x0001);
|
||||
break;
|
||||
case 0x20:
|
||||
currContext|=((*context_bits & 0x00c0)>>5)|(*context_bits & 0x0001);
|
||||
break;
|
||||
case 0x30:
|
||||
currContext|=((*context_bits & 0x0180)>>5)|(*context_bits & 0x0003);
|
||||
}
|
||||
|
||||
uint8 bit=PEM->getBit(currContext);
|
||||
|
||||
*context_bits <<= 1;
|
||||
*context_bits |= bit;
|
||||
|
||||
bit_number++;
|
||||
|
||||
return bit;
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1_OL::SDD1_OL(SDD1_CM *associatedCM) :
|
||||
CM(associatedCM)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_OL::prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf) {
|
||||
|
||||
bitplanesInfo = SDD1_read(first_byte) & 0xc0;
|
||||
length=out_len;
|
||||
buffer=out_buf;
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_OL::launch(void) {
|
||||
|
||||
uint8 i;
|
||||
uint8 register1, register2;
|
||||
|
||||
switch (bitplanesInfo) {
|
||||
case 0x00:
|
||||
case 0x40:
|
||||
case 0x80:
|
||||
i=1;
|
||||
do { //if length==0, we output 2^16 bytes
|
||||
if (!i) {
|
||||
*(buffer++)=register2;
|
||||
i=~i;
|
||||
}
|
||||
else {
|
||||
for (register1=register2=0, i=0x80; i; i>>=1) {
|
||||
if (CM->getBit()) register1 |= i;
|
||||
if (CM->getBit()) register2 |= i;
|
||||
}
|
||||
*(buffer++)=register1;
|
||||
}
|
||||
} while (--length);
|
||||
break;
|
||||
case 0xc0:
|
||||
do {
|
||||
for (register1=0, i=0x01; i; i<<=1) {
|
||||
if (CM->getBit()) register1 |= i;
|
||||
}
|
||||
*(buffer++)=register1;
|
||||
} while (--length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1emu::decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf) {
|
||||
|
||||
IM.prepareDecomp(in_buf);
|
||||
BG0.prepareDecomp();
|
||||
BG1.prepareDecomp();
|
||||
BG2.prepareDecomp();
|
||||
BG3.prepareDecomp();
|
||||
BG4.prepareDecomp();
|
||||
BG5.prepareDecomp();
|
||||
BG6.prepareDecomp();
|
||||
BG7.prepareDecomp();
|
||||
PEM.prepareDecomp();
|
||||
CM.prepareDecomp(in_buf);
|
||||
OL.prepareDecomp(in_buf, out_len, out_buf);
|
||||
|
||||
OL.launch();
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1emu::SDD1emu() :
|
||||
GCD(&IM),
|
||||
BG0(&GCD, 0), BG1(&GCD, 1), BG2(&GCD, 2), BG3(&GCD, 3),
|
||||
BG4(&GCD, 4), BG5(&GCD, 5), BG6(&GCD, 6), BG7(&GCD, 7),
|
||||
PEM(&BG0, &BG1, &BG2, &BG3, &BG4, &BG5, &BG6, &BG7),
|
||||
CM(&PEM),
|
||||
OL(&CM)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,161 @@
|
||||
/************************************************************************
|
||||
|
||||
S-DD1'algorithm emulation code
|
||||
------------------------------
|
||||
|
||||
Author: Andreas Naive
|
||||
Date: August 2003
|
||||
Last update: October 2004
|
||||
|
||||
This code is Public Domain. There is no copyright holded by the author.
|
||||
Said this, the author wish to explicitly emphasize his inalienable moral rights
|
||||
over this piece of intelectual work and the previous research that made it
|
||||
possible, as recognized by most of the copyright laws around the world.
|
||||
|
||||
This code is provided 'as-is', with no warranty, expressed or implied.
|
||||
No responsability is assumed by the author in connection with it.
|
||||
|
||||
The author is greatly indebted with The Dumper, without whose help and
|
||||
patience providing him with real S-DD1 data the research would have never been
|
||||
possible. He also wish to note that in the very beggining of his research,
|
||||
Neviksti had done some steps in the right direction. By last, the author is
|
||||
indirectly indebted to all the people that worked and contributed in the
|
||||
S-DD1 issue in the past.
|
||||
|
||||
An algorithm's documentation is available as a separate document.
|
||||
The implementation is obvious when the algorithm is
|
||||
understood.
|
||||
|
||||
************************************************************************/
|
||||
|
||||
|
||||
class SDD1_IM { //Input Manager
|
||||
|
||||
public:
|
||||
SDD1_IM(void) {}
|
||||
void prepareDecomp(uint32 in_buf);
|
||||
uint8 getCodeword(const uint8 code_len);
|
||||
|
||||
private:
|
||||
uint32 byte_ptr;
|
||||
uint8 bit_count;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_GCD { //Golomb-Code Decoder
|
||||
|
||||
public:
|
||||
SDD1_GCD(SDD1_IM *associatedIM);
|
||||
void getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind);
|
||||
|
||||
private:
|
||||
SDD1_IM *const IM;
|
||||
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_BG { // Bits Generator
|
||||
|
||||
public:
|
||||
SDD1_BG(SDD1_GCD *associatedGCD, uint8 code);
|
||||
void prepareDecomp(void);
|
||||
uint8 getBit(bool8 *endOfRun);
|
||||
|
||||
private:
|
||||
const uint8 code_num;
|
||||
uint8 MPScount;
|
||||
bool8 LPSind;
|
||||
SDD1_GCD *const GCD;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_PEM { //Probability Estimation Module
|
||||
|
||||
public:
|
||||
SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
|
||||
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
|
||||
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
|
||||
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7);
|
||||
void prepareDecomp(void);
|
||||
uint8 getBit(uint8 context);
|
||||
|
||||
private:
|
||||
struct state {
|
||||
uint8 code_num;
|
||||
uint8 nextIfMPS;
|
||||
uint8 nextIfLPS;
|
||||
};
|
||||
static const state evolution_table[];
|
||||
struct SDD1_ContextInfo {
|
||||
uint8 status;
|
||||
uint8 MPS;
|
||||
} contextInfo[32];
|
||||
SDD1_BG * BG[8];
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_CM { //Context Model
|
||||
|
||||
public:
|
||||
SDD1_CM(SDD1_PEM *associatedPEM);
|
||||
void prepareDecomp(uint32 first_byte);
|
||||
uint8 getBit(void);
|
||||
|
||||
private:
|
||||
uint8 bitplanesInfo;
|
||||
uint8 contextBitsInfo;
|
||||
uint8 bit_number;
|
||||
uint8 currBitplane;
|
||||
uint16 prevBitplaneBits[8];
|
||||
SDD1_PEM *const PEM;
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_OL { //Output Logic
|
||||
|
||||
public:
|
||||
SDD1_OL(SDD1_CM *associatedCM);
|
||||
void prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf);
|
||||
void launch(void);
|
||||
|
||||
private:
|
||||
uint8 bitplanesInfo;
|
||||
uint16 length;
|
||||
uint8 *buffer;
|
||||
SDD1_CM *const CM;
|
||||
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1emu {
|
||||
|
||||
public:
|
||||
SDD1emu(void);
|
||||
void decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf);
|
||||
|
||||
private:
|
||||
SDD1_IM IM;
|
||||
SDD1_GCD GCD;
|
||||
SDD1_BG BG0; SDD1_BG BG1; SDD1_BG BG2; SDD1_BG BG3;
|
||||
SDD1_BG BG4; SDD1_BG BG5; SDD1_BG BG6; SDD1_BG BG7;
|
||||
SDD1_PEM PEM;
|
||||
SDD1_CM CM;
|
||||
SDD1_OL OL;
|
||||
|
||||
};
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
S-RTC chip emulation
|
||||
Used by Hudson Soft in Dai Kaijuu Monogatari II and Far East of Eden Zero.
|
||||
Currently, only the former is supported by bsnes.
|
||||
|
||||
Original S-RTC emulation code via John Weidman/SNES9x
|
||||
Rewritten for compatibility with bsnes via byuu
|
||||
|
||||
The S-RTC is a real-time clock chip that was added to the above two carts
|
||||
to allow the games to maintain the current time, even when the game was not
|
||||
powered on. Thus allowing special events at certain times, and on certain
|
||||
dates. Hudson Soft called this the PLG (Player's Life Gameplay System).
|
||||
|
||||
This chip is a special case to the term 'emulation' itself.
|
||||
There are a few different ways to go about emulating this chip, and each
|
||||
result in a different style of emulation.
|
||||
|
||||
The first is to simply return the current PC system time when the S-RTC is
|
||||
read from. This emulates the original S-RTC in the sense that it always
|
||||
returns the true current time, ignoring the speed that the SNES itself is
|
||||
running at. The downside to this method is that you lose the ability to set
|
||||
the time to whatever you choose inside the game itself. It will always return
|
||||
the true time, regardless. This can be overcome by changing the PC system time,
|
||||
which actually adds a greater degree of control over event timing, very useful
|
||||
for emulation. It also has a timeshifting flaw discussed below.
|
||||
|
||||
The second is to run the S-RTC relative to the SNES speed. This means that
|
||||
if the emulator is sped up (via fast forward key, frameskipping, etc), or
|
||||
slowed down (via slowdown key, system bottlenecking, etc); the time increments
|
||||
slower, thus ~60 frames on the SNES equal one second. Without this, timeshifting
|
||||
will occur between the S-RTC and the real SNES.
|
||||
|
||||
The third and final method is to save a copy of the local system time when the
|
||||
S-RTC is initially set, and compare the current system time against this value
|
||||
when setting the S-RTC time. This overcomes the first methods' shortcoming of
|
||||
not allowing the player to set the time in-game, however a new problem arises.
|
||||
You now have to save the time when the RTC was initially set to both savestates
|
||||
and to save-game data. This would require an extra file, or the breaking of
|
||||
perhaps the only standard format (.srm savegame backups) in the entire SNES
|
||||
emulation scene. You also give up the control of being able to override the
|
||||
RTC clock at will via the PC system time outside of emulation.
|
||||
The first method has another advantage over the third: Dai Kaijuu Monogatari II
|
||||
only allows dates in the range of the years 1996-2199. The first method gets
|
||||
around this limitation. But who knows, maybe it will break something in the
|
||||
game if the date exceeds 2199... I guess we'll worry about that in two hundred
|
||||
years from now.
|
||||
|
||||
For my implementation, I chose to go with the first method. Both for simplicity
|
||||
and because I did not wish to create a new method for saving the system time
|
||||
whenever the RTC is set.
|
||||
*/
|
||||
|
||||
#include "../../base.h"
|
||||
|
||||
void SRTC::set_time() {
|
||||
time_t rawtime;
|
||||
tm *t;
|
||||
::time(&rawtime);
|
||||
t = localtime(&rawtime);
|
||||
|
||||
//see srtc.h for format of srtc.data[]
|
||||
srtc.data[0] = t->tm_sec % 10;
|
||||
srtc.data[1] = t->tm_sec / 10;
|
||||
srtc.data[2] = t->tm_min % 10;
|
||||
srtc.data[3] = t->tm_min / 10;
|
||||
srtc.data[4] = t->tm_hour % 10;
|
||||
srtc.data[5] = t->tm_hour / 10;
|
||||
srtc.data[6] = t->tm_mday % 10;
|
||||
srtc.data[7] = t->tm_mday / 10;
|
||||
srtc.data[8] = t->tm_mon + 1;
|
||||
srtc.data[9] = t->tm_year % 10;
|
||||
srtc.data[10] = (t->tm_year / 10) % 10;
|
||||
srtc.data[11] = 9 + (t->tm_year / 100);
|
||||
srtc.data[12] = t->tm_wday;
|
||||
}
|
||||
|
||||
void SRTC::init() {}
|
||||
|
||||
void SRTC::enable() {
|
||||
r_mem->set_mmio_mapper(0x2800, this);
|
||||
r_mem->set_mmio_mapper(0x2801, this);
|
||||
}
|
||||
|
||||
void SRTC::power() {
|
||||
memset(&srtc, 0, sizeof(srtc));
|
||||
reset();
|
||||
}
|
||||
|
||||
void SRTC::reset() {
|
||||
srtc.index = -1;
|
||||
srtc.mode = SRTC_READ;
|
||||
}
|
||||
|
||||
uint8 SRTC::mmio_read(uint16 addr) {
|
||||
switch(addr) {
|
||||
|
||||
case 0x2800: {
|
||||
if(srtc.mode == SRTC_READ) {
|
||||
if(srtc.index < 0) {
|
||||
set_time();
|
||||
srtc.index++;
|
||||
return 0x0f; //send start message
|
||||
} else if(srtc.index > MAX_SRTC_INDEX) {
|
||||
srtc.index = -1;
|
||||
return 0x0f; //send finished message
|
||||
} else {
|
||||
return srtc.data[srtc.index++];
|
||||
}
|
||||
} else {
|
||||
return 0x00;
|
||||
}
|
||||
} break;
|
||||
|
||||
case 0x2801: {
|
||||
} break;
|
||||
|
||||
}
|
||||
|
||||
return r_cpu->regs.mdr;
|
||||
}
|
||||
|
||||
//Please see notes above about the implementation of the S-RTC
|
||||
//Writes are stored the srtc.data[] array, but they are ignored
|
||||
//as reads will refresh the data array with the current system
|
||||
//time. The write method is only here for the sake of faux
|
||||
//emulation of the real hardware.
|
||||
void SRTC::mmio_write(uint16 addr, uint8 data) {
|
||||
switch(addr) {
|
||||
|
||||
case 0x2800: {
|
||||
} break;
|
||||
|
||||
case 0x2801: {
|
||||
data &= 0x0f; //only the low four bits are used
|
||||
|
||||
if(data >= 0x0d) {
|
||||
switch(data) {
|
||||
case 0x0d:
|
||||
srtc.mode = SRTC_READ;
|
||||
srtc.index = -1;
|
||||
break;
|
||||
case 0x0e:
|
||||
srtc.mode = SRTC_COMMAND;
|
||||
break;
|
||||
case 0x0f:
|
||||
//unknown behaviour
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(srtc.mode == SRTC_WRITE) {
|
||||
if(srtc.index >= 0 && srtc.index < MAX_SRTC_INDEX) {
|
||||
srtc.data[srtc.index++] = data;
|
||||
|
||||
if(srtc.index == MAX_SRTC_INDEX) {
|
||||
//all S-RTC data has been loaded by program
|
||||
srtc.data[srtc.index++] = 0x00; //day_of_week
|
||||
}
|
||||
}
|
||||
} else if(srtc.mode == SRTC_COMMAND) {
|
||||
switch(data) {
|
||||
case SRTC_COMMAND_CLEAR:
|
||||
memset(srtc.data, 0, MAX_SRTC_INDEX + 1);
|
||||
srtc.index = -1;
|
||||
srtc.mode = SRTC_READY;
|
||||
break;
|
||||
case SRTC_COMMAND_WRITE:
|
||||
srtc.index = 0;
|
||||
srtc.mode = SRTC_WRITE;
|
||||
break;
|
||||
default:
|
||||
//unknown behaviour
|
||||
srtc.mode = SRTC_READY;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(srtc.mode == SRTC_READ) {
|
||||
//ignore writes while in read mode
|
||||
} else if(srtc.mode == SRTC_READY) {
|
||||
//unknown behaviour
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
SRTC::SRTC() {}
|
||||
@@ -0,0 +1,50 @@
|
||||
class SRTC : public MMIO {
|
||||
public:
|
||||
enum { MAX_SRTC_INDEX = 0x0c };
|
||||
|
||||
enum {
|
||||
SRTC_READ = 0,
|
||||
SRTC_WRITE,
|
||||
SRTC_COMMAND,
|
||||
SRTC_READY
|
||||
};
|
||||
|
||||
enum {
|
||||
SRTC_COMMAND_WRITE = 0,
|
||||
SRTC_COMMAND_CLEAR = 4
|
||||
};
|
||||
|
||||
/******************************
|
||||
[srtc.data structure]
|
||||
Index Description Range
|
||||
----- ----------- -----
|
||||
0 Seconds low 0-9
|
||||
1 Seconds high 0-5
|
||||
2 Minutes low 0-9
|
||||
3 Minutes high 0-5
|
||||
4 Hour low 0-9
|
||||
5 Hour high 0-2
|
||||
6 Day low 0-9
|
||||
7 Day high 0-3
|
||||
8 Month 1-12
|
||||
9 Year ones 0-9
|
||||
10 Year tens 0-9
|
||||
11 Year hundreds 9-11 (9=19xx, 10=20xx, 11=21xx)
|
||||
12 Day of week 0-6 (0=Sunday, ...)
|
||||
******************************/
|
||||
struct {
|
||||
int8 index;
|
||||
uint8 mode;
|
||||
uint8 data[MAX_SRTC_INDEX + 1];
|
||||
} srtc;
|
||||
void set_time();
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 mmio_read (uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
SRTC();
|
||||
};
|
||||
@@ -1,205 +0,0 @@
|
||||
#include "../../base.h"
|
||||
|
||||
void bClock::frameskip_update_status() {
|
||||
if(frameskip.changed == true) {
|
||||
frameskip.changed = false;
|
||||
frameskip.count = frameskip.new_count;
|
||||
frameskip.pos = 0;
|
||||
} else {
|
||||
frameskip.pos++;
|
||||
frameskip.pos %= (frameskip.count + 1);
|
||||
}
|
||||
|
||||
frameskip.notify_ppu = (frameskip.pos == 0)?true:false;
|
||||
}
|
||||
|
||||
void bClock::dram_refresh_test() {
|
||||
if(cc1.dram_refreshed == false && status.hcycles >= cc1.dram_refresh_pos) {
|
||||
cc1.dram_refreshed = true;
|
||||
|
||||
if(status.interlace != false || status.interlace_field != 1 || status.vcounter != 240) {
|
||||
if(cc1.dram_refresh_pos == 534) {
|
||||
cc1.dram_refresh_pos = 538;
|
||||
} else { //cc1.dram_refresh_pos == 538
|
||||
cc1.dram_refresh_pos = 534;
|
||||
}
|
||||
}
|
||||
|
||||
cc1.pos += 40;
|
||||
cc1.frame_pos += 40;
|
||||
status.hcycles += 40;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
all scanlines are 1364 cycles long, except scanline 240
|
||||
on non-interlace odd-frames, which is 1360 cycles long.
|
||||
interlace mode has 525 scanlines: 263 on the even frame,
|
||||
and 262 on the odd.
|
||||
non-interlace mode has 524 scanlines: 262 scanlines on
|
||||
both even and odd frames.
|
||||
|
||||
cycles per frame:
|
||||
263 * 1364 = 358732
|
||||
262 * 1364 = 357368
|
||||
262 * 1364 - 4 = 357364
|
||||
*/
|
||||
void bClock::inc_vcounter() {
|
||||
status.hcycles -= cc1.line_cycles;
|
||||
|
||||
status.vcounter++;
|
||||
if(status.vcounter >= cc1.frame_lines) {
|
||||
frameskip_update_status();
|
||||
|
||||
cc1.frame_pos -= cc1.frame_cycles;
|
||||
status.vcounter = 0;
|
||||
status.interlace_field ^= 1;
|
||||
if(status.interlace == true) {
|
||||
if(status.interlace_field == 0) {
|
||||
cc1.frame_cycles = 263 * 1364;
|
||||
cc1.frame_lines = 263;
|
||||
} else {
|
||||
cc1.frame_cycles = 262 * 1364;
|
||||
cc1.frame_lines = 262;
|
||||
}
|
||||
} else {
|
||||
if(status.interlace_field == 0) {
|
||||
cc1.frame_cycles = 262 * 1364;
|
||||
cc1.frame_lines = 262;
|
||||
} else {
|
||||
cc1.frame_cycles = (262 * 1364) - 4;
|
||||
cc1.frame_lines = 262;
|
||||
}
|
||||
}
|
||||
cc1.render_frame = true;
|
||||
cpu->frame();
|
||||
if(frameskip.notify_ppu == true)ppu->frame();
|
||||
}
|
||||
|
||||
if(status.interlace == false && status.interlace_field == 1 && status.vcounter == 240) {
|
||||
cc1.line_cycles = 1360;
|
||||
} else {
|
||||
cc1.line_cycles = 1364;
|
||||
}
|
||||
|
||||
cc1.dram_refreshed = false;
|
||||
|
||||
cpu->scanline();
|
||||
if(frameskip.notify_ppu == true)ppu->scanline();
|
||||
|
||||
//if(status.vcounter == visible_scanlines()) {
|
||||
// cc1.render_frame = true;
|
||||
//}
|
||||
}
|
||||
|
||||
/*
|
||||
all dots are 4 cycles long, except dots 322 and 326. dots 322 and 326
|
||||
are 6 cycles long. this holds true for all scanlines except scanline
|
||||
240 on non-interlace odd frames. the reason for this is because this
|
||||
scanline is only 1360 cycles long, instead of 1364 like all other
|
||||
scanlines.
|
||||
this makes the effective range of hscan_pos 0-339 at all times.
|
||||
dot 322 range = { 1288, 1290, 1292 }
|
||||
dot 326 range = { 1306, 1308, 1310 }
|
||||
*/
|
||||
void bClock::sync() {
|
||||
uint32 new_cycles, cycles;
|
||||
new_cycles = cc1.pos - cc1.last_pos;
|
||||
while(new_cycles) {
|
||||
if(new_cycles > 40) {
|
||||
cycles = 40;
|
||||
new_cycles -= 40;
|
||||
} else {
|
||||
cycles = new_cycles;
|
||||
new_cycles = 0;
|
||||
}
|
||||
|
||||
status.hcycles += cycles;
|
||||
cc1.frame_pos += cycles;
|
||||
dram_refresh_test();
|
||||
if(status.hcycles >= cc1.line_cycles) {
|
||||
inc_vcounter();
|
||||
}
|
||||
}
|
||||
cc1.last_pos = cc1.pos;
|
||||
|
||||
if(cc1.pos > cc1.frequency) {
|
||||
cc1.pos -= cc1.frequency;
|
||||
cc1.last_pos -= cc1.frequency;
|
||||
}
|
||||
|
||||
if(status.interlace == false && status.interlace_field == 1 && status.vcounter == 240) {
|
||||
status.hcounter = status.hcycles >> 2;
|
||||
} else {
|
||||
//1288 = 322 * 4, 1306 = 326 * 4 + 2
|
||||
status.hcounter = (status.hcycles - ((status.hcycles > 1288) << 1) - ((status.hcycles > 1306) << 1)) >> 2;
|
||||
}
|
||||
}
|
||||
|
||||
void bClock::set_frameskip(uint8 fs) {
|
||||
frameskip.changed = true;
|
||||
frameskip.new_count = fs;
|
||||
}
|
||||
|
||||
bool bClock::update_frame() {
|
||||
if(cc1.render_frame == true) {
|
||||
cc1.render_frame = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void bClock::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void bClock::reset() {
|
||||
cc1.render_frame = false;
|
||||
|
||||
//upon SNES reset, start at scanline 0 non-interlace
|
||||
cc1.frame_cycles = 262 * 1364;
|
||||
cc1.frame_lines = 262;
|
||||
cc1.line_cycles = 1364;
|
||||
|
||||
/*
|
||||
Initial latch values for $213c/$213d
|
||||
0035:0000 (53.0 -> 212) [lda $2137]
|
||||
0038:0000 (56.5 -> 226) [nop : lda $2137]
|
||||
*/
|
||||
cc1.pos = 188;
|
||||
cc1.last_pos = 0;
|
||||
cc1.frame_pos = 0;
|
||||
status.vcounter = 0;
|
||||
status.hcounter = 0;
|
||||
status.hcycles = 0;
|
||||
|
||||
cc1.dram_refresh_pos = 538;
|
||||
cc1.dram_refreshed = false;
|
||||
|
||||
cc2.pos = 0;
|
||||
|
||||
sync();
|
||||
}
|
||||
|
||||
void bClock::run() {
|
||||
cpu->run();
|
||||
if(frameskip.notify_ppu == true)ppu->run();
|
||||
sync();
|
||||
}
|
||||
|
||||
void bClock::add_cc1_cycles(uint32 cycles) {
|
||||
cc1.pos += cycles;
|
||||
}
|
||||
|
||||
void bClock::add_cc2_cycles(uint32 cycles) {
|
||||
cc2.pos += cycles;
|
||||
}
|
||||
|
||||
bClock::bClock() {
|
||||
cc1.frequency = 21477272;
|
||||
cc2.frequency = 24576000;
|
||||
|
||||
frameskip.changed = false;
|
||||
frameskip.count = 0;
|
||||
frameskip.pos = 0;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
class bClock : public Clock {
|
||||
private:
|
||||
struct {
|
||||
bool changed, notify_ppu;
|
||||
uint8 count, new_count, pos;
|
||||
}frameskip;
|
||||
void frameskip_update_status();
|
||||
void inc_vcounter();
|
||||
void dram_refresh_test();
|
||||
|
||||
public:
|
||||
struct {
|
||||
uint32 frequency;
|
||||
uint32 pos, last_pos;
|
||||
uint32 frame_cycles, frame_lines, frame_pos;
|
||||
uint16 line_cycles;
|
||||
bool dram_refreshed; //whether or not dram has been refreshed on this line
|
||||
uint16 dram_refresh_pos;
|
||||
|
||||
bool render_frame;
|
||||
}cc1;
|
||||
struct {
|
||||
uint32 frequency;
|
||||
uint32 pos, last_pos;
|
||||
}cc2;
|
||||
|
||||
void set_frameskip(uint8 fs);
|
||||
bool update_frame();
|
||||
|
||||
void add_cc1_cycles(uint32 cycles);
|
||||
void add_cc2_cycles(uint32 cycles);
|
||||
void sync();
|
||||
void run();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
bClock();
|
||||
~bClock();
|
||||
};
|
||||
@@ -1,49 +0,0 @@
|
||||
#include "../base.h"
|
||||
|
||||
void Clock::enable_overscan(bool n) {
|
||||
status.overscan = n;
|
||||
}
|
||||
|
||||
void Clock::enable_interlace(bool n) {
|
||||
status.interlace = n;
|
||||
}
|
||||
|
||||
bool Clock::overscan() {
|
||||
return status.overscan;
|
||||
}
|
||||
|
||||
bool Clock::interlace() {
|
||||
return status.interlace;
|
||||
}
|
||||
|
||||
bool Clock::interlace_field() {
|
||||
return status.interlace_field;
|
||||
}
|
||||
|
||||
uint16 Clock::vcounter() {
|
||||
return status.vcounter;
|
||||
}
|
||||
|
||||
uint16 Clock::hcounter() {
|
||||
return status.hcounter;
|
||||
}
|
||||
|
||||
uint16 Clock::hcycles() {
|
||||
return status.hcycles;
|
||||
}
|
||||
|
||||
uint16 Clock::visible_scanlines() {
|
||||
return (status.overscan)?239:224;
|
||||
}
|
||||
|
||||
void Clock::set_frameskip(uint8 fs) {}
|
||||
|
||||
Clock::Clock() {
|
||||
status.overscan = false;
|
||||
status.interlace = false;
|
||||
status.interlace_field = 0;
|
||||
|
||||
status.vcounter = 0;
|
||||
status.hcounter = 0;
|
||||
status.hcycles = 0;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
class Clock {
|
||||
private:
|
||||
struct {
|
||||
bool overscan;
|
||||
bool interlace;
|
||||
bool interlace_field;
|
||||
|
||||
uint16 vcounter;
|
||||
uint16 hcounter;
|
||||
uint16 hcycles;
|
||||
}status;
|
||||
|
||||
public:
|
||||
virtual void enable_overscan(bool n);
|
||||
virtual void enable_interlace(bool n);
|
||||
virtual bool overscan();
|
||||
virtual bool interlace();
|
||||
virtual bool interlace_field();
|
||||
virtual uint16 vcounter();
|
||||
virtual uint16 hcounter();
|
||||
virtual uint16 hcycles();
|
||||
virtual uint16 visible_scanlines();
|
||||
|
||||
virtual void set_frameskip(uint8 fs);
|
||||
virtual bool update_frame() = 0;
|
||||
|
||||
virtual void add_cc1_cycles(uint32 cycles) = 0;
|
||||
virtual void add_cc2_cycles(uint32 cycles) = 0;
|
||||
virtual void sync() = 0;
|
||||
virtual void run() = 0;
|
||||
virtual void power() = 0;
|
||||
virtual void reset() = 0;
|
||||
|
||||
Clock();
|
||||
|
||||
friend class bClock;
|
||||
};
|
||||
@@ -0,0 +1,75 @@
|
||||
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",
|
||||
"Default path to look for ROM files in (\"\" = use default directory)", "");
|
||||
Setting FS::save_path(&config_file, "fs.save_path",
|
||||
"Default path for all save RAM and cheat files (\"\" = use current directory)", "");
|
||||
|
||||
Setting FS::save_ext(&config_file, "fs.save_ext",
|
||||
"Extension to be used for all save RAM files", "srm");
|
||||
|
||||
Setting SNES::gamma_ramp(&config_file, "snes.colorfilter.gamma_ramp",
|
||||
"Use precalculated TV-style gamma ramp", true, Setting::TRUE_FALSE);
|
||||
Setting SNES::sepia(&config_file, "snes.colorfilter.sepia",
|
||||
"Convert color to sepia tone", false, Setting::TRUE_FALSE);
|
||||
Setting SNES::grayscale(&config_file, "snes.colorfilter.grayscale",
|
||||
"Convert color to grayscale tone", false, Setting::TRUE_FALSE);
|
||||
Setting SNES::invert(&config_file, "snes.colorfilter.invert",
|
||||
"Invert output image colors", false, Setting::TRUE_FALSE);
|
||||
Setting SNES::contrast(&config_file, "snes.colorfilter.contrast",
|
||||
"Contrast", 0, Setting::DEC);
|
||||
Setting SNES::brightness(&config_file, "snes.colorfilter.brightness",
|
||||
"Brightness", 0, Setting::DEC);
|
||||
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);
|
||||
|
||||
Setting SNES::mute(&config_file, "snes.mute", "Mutes SNES audio output when enabled",
|
||||
false, Setting::TRUE_FALSE);
|
||||
|
||||
//do not save these settings to config_file
|
||||
Setting CPU::hdma_enable(0, "cpu.hdma_enable", "Enable HDMA effects", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::opt_enable(0, "ppu.opt_enable", "Enable offset-per-tile effects", true, Setting::TRUE_FALSE);
|
||||
|
||||
Setting PPU::bg1_pri0_enable(0, "ppu.bg1_pri0_enable", "Enable BG1 Priority 0", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::bg1_pri1_enable(0, "ppu.bg1_pri1_enable", "Enable BG1 Priority 1", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::bg2_pri0_enable(0, "ppu.bg2_pri0_enable", "Enable BG2 Priority 0", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::bg2_pri1_enable(0, "ppu.bg2_pri1_enable", "Enable BG2 Priority 1", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::bg3_pri0_enable(0, "ppu.bg3_pri0_enable", "Enable BG3 Priority 0", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::bg3_pri1_enable(0, "ppu.bg3_pri1_enable", "Enable BG3 Priority 1", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::bg4_pri0_enable(0, "ppu.bg4_pri0_enable", "Enable BG4 Priority 0", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::bg4_pri1_enable(0, "ppu.bg4_pri1_enable", "Enable BG4 Priority 1", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::oam_pri0_enable(0, "ppu.oam_pri0_enable", "Enable OAM Priority 0", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::oam_pri1_enable(0, "ppu.oam_pri1_enable", "Enable OAM Priority 1", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::oam_pri2_enable(0, "ppu.oam_pri2_enable", "Enable OAM Priority 2", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::oam_pri3_enable(0, "ppu.oam_pri3_enable", "Enable OAM Priority 3", true, Setting::TRUE_FALSE);
|
||||
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
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;
|
||||
} fs;
|
||||
|
||||
extern struct SNES {
|
||||
static Setting gamma_ramp, sepia, grayscale, invert, contrast, brightness, gamma;
|
||||
static Setting ntsc_merge_fields;
|
||||
static Setting mute;
|
||||
} snes;
|
||||
|
||||
extern struct CPU {
|
||||
static Setting hdma_enable;
|
||||
} cpu;
|
||||
|
||||
extern struct PPU {
|
||||
static Setting opt_enable;
|
||||
|
||||
static Setting bg1_pri0_enable, bg1_pri1_enable;
|
||||
static Setting bg2_pri0_enable, bg2_pri1_enable;
|
||||
static Setting bg3_pri0_enable, bg3_pri1_enable;
|
||||
static Setting bg4_pri0_enable, bg4_pri1_enable;
|
||||
static Setting oam_pri0_enable, oam_pri1_enable;
|
||||
static Setting oam_pri2_enable, oam_pri3_enable;
|
||||
} ppu;
|
||||
|
||||
};
|
||||
+56
-257
@@ -1,157 +1,59 @@
|
||||
#include "../../base.h"
|
||||
|
||||
#include "bcpu_op_adc.cpp"
|
||||
#include "bcpu_op_and.cpp"
|
||||
#include "bcpu_op_cmp.cpp"
|
||||
#include "bcpu_op_eor.cpp"
|
||||
#include "bcpu_op_incdec.cpp"
|
||||
#include "bcpu_op_lda.cpp"
|
||||
#include "bcpu_op_misc.cpp"
|
||||
#include "bcpu_op_ora.cpp"
|
||||
#include "bcpu_op_pc.cpp"
|
||||
#include "bcpu_op_sbc.cpp"
|
||||
#include "bcpu_op_shift.cpp"
|
||||
#include "bcpu_op_sta.cpp"
|
||||
#include "bcpu_op_stack.cpp"
|
||||
#include "core/core.cpp"
|
||||
#include "memory/memory.cpp"
|
||||
#include "dma/dma.cpp"
|
||||
#include "timing/timing.cpp"
|
||||
|
||||
#include "bcpu_exec.cpp"
|
||||
#include "bcpu_mmio.cpp"
|
||||
#include "bcpu_int.cpp"
|
||||
|
||||
uint8 bCPU::pio_status() {
|
||||
return status.pio;
|
||||
}
|
||||
|
||||
/***********
|
||||
*** IRQ ***
|
||||
***********
|
||||
cycles:
|
||||
[1] pbr,pc ; io
|
||||
[2] pbr,pc ; io
|
||||
[3] 0,s ; pbr
|
||||
[4] 0,s-1 ; pch
|
||||
[5] 0,s-2 ; pcl
|
||||
[6] 0,s-3 ; p
|
||||
[7] 0,va ; aavl
|
||||
[8] 0,va+1 ; aavh
|
||||
*/
|
||||
void bCPU::irq(uint16 addr) {
|
||||
if(cpustate == CPUSTATE_WAI) {
|
||||
regs.pc.w++;
|
||||
cpustate = CPUSTATE_RUN;
|
||||
}
|
||||
|
||||
clock->add_cc1_cycles(mem_bus->speed(regs.pc)); //1
|
||||
clock->add_cc1_cycles(6); //2
|
||||
stack_write(regs.pc.b); //3
|
||||
stack_write(regs.pc.h); //4
|
||||
stack_write(regs.pc.l); //5
|
||||
stack_write(regs.p); //6
|
||||
rd.l = op_read(OPMODE_ADDR, addr); //7
|
||||
rd.h = op_read(OPMODE_ADDR, addr + 1); //8
|
||||
regs.pc.b = 0x00;
|
||||
regs.pc.w = rd.w;
|
||||
|
||||
regs.p.d = 0;
|
||||
regs.p.i = 1;
|
||||
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE);
|
||||
}
|
||||
uint8 bCPU::pio_status() { return status.pio; }
|
||||
|
||||
void bCPU::run() {
|
||||
uint16 v, h, hc, vs;
|
||||
switch(cpustate) {
|
||||
case CPUSTATE_RUN:
|
||||
case CPUSTATE_WAI:
|
||||
v = clock->vcounter();
|
||||
h = clock->hcounter();
|
||||
hc = clock->hcycles();
|
||||
vs = clock->visible_scanlines();
|
||||
if(run_state.hdma) {
|
||||
exec_hdma();
|
||||
return;
|
||||
}
|
||||
|
||||
//NMI test
|
||||
if(v >= (vs + 1) && status.nmi_triggered == false) {
|
||||
if((v == (vs + 1) && hc >= 12) || (v >= (vs + 1))) {
|
||||
status.nmi_triggered = true;
|
||||
status.nmi_pin = 0;
|
||||
if(status.nmi_enabled == true) {
|
||||
irq(0xffea);
|
||||
return;
|
||||
}
|
||||
if(run_state.dma) {
|
||||
exec_dma();
|
||||
return;
|
||||
}
|
||||
|
||||
if(status.cycle_pos == 0) { //interrupts only trigger on opcode edges
|
||||
if(run_state.irq && !run_state.stp) {
|
||||
run_state.irq = false;
|
||||
if(time.nmi_pending == true) {
|
||||
time.nmi_pending = false;
|
||||
aa.w = (regs.e == false) ? 0xffea : 0xfffa;
|
||||
} else if(time.irq_pending == true) {
|
||||
time.irq_pending = false;
|
||||
aa.w = (regs.e == false) ? 0xffee : 0xfffe;
|
||||
}
|
||||
irq_run();
|
||||
}
|
||||
|
||||
//IRQ test
|
||||
if(!regs.p.i) {
|
||||
if(status.virq_enabled == true && status.virq_enabled == true) {
|
||||
if(v == status.virq_pos && h >= status.hirq_pos && status.irq_pin == 1) {
|
||||
status.irq_triggered = true;
|
||||
status.irq_pin = 0;
|
||||
irq(0xffee);
|
||||
return;
|
||||
}
|
||||
} else if(status.virq_enabled == true) {
|
||||
if(v == status.virq_pos && status.irq_pin == 1) {
|
||||
status.irq_triggered = true;
|
||||
status.irq_pin = 0;
|
||||
irq(0xffee);
|
||||
return;
|
||||
}
|
||||
} else if(status.hirq_enabled == true) {
|
||||
if(h >= status.hirq_pos && status.irq_pin == 1) {
|
||||
status.irq_triggered = true;
|
||||
status.irq_pin = 0;
|
||||
irq(0xffee);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//HDMA test
|
||||
if(v < vs && h >= 278 && dma->hdma_triggered == false) {
|
||||
dma->hdma_run();
|
||||
dma->hdma_triggered = true;
|
||||
}
|
||||
|
||||
exec_opcode();
|
||||
break;
|
||||
case CPUSTATE_DMA:
|
||||
dma->run();
|
||||
break;
|
||||
case CPUSTATE_STP:
|
||||
exec_opcode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::scanline() {
|
||||
uint16 v = clock->vcounter();
|
||||
if(v == 225 && status.auto_joypad_poll == true) {
|
||||
snes->poll_input();
|
||||
}
|
||||
if(status.virq_enabled == false) {
|
||||
status.irq_pin = 1;
|
||||
}
|
||||
dma->hdma_triggered = false;
|
||||
}
|
||||
|
||||
void bCPU::frame() {
|
||||
status.nmi_triggered = false;
|
||||
status.r4210_read = false;
|
||||
|
||||
status.irq_pin = 1;
|
||||
|
||||
dma->hdma_initialize();
|
||||
exec_cycle();
|
||||
}
|
||||
|
||||
void bCPU::power() {
|
||||
region = snes->region();
|
||||
|
||||
regs.a = regs.x = regs.y = 0x0000;
|
||||
regs.s = 0x01ff;
|
||||
reset();
|
||||
}
|
||||
|
||||
void bCPU::reset() {
|
||||
/* reset vector location */
|
||||
regs.pc = mem_bus->read(0xfffc) | (mem_bus->read(0xfffd) << 8);
|
||||
//reset vector location
|
||||
regs.pc.d = 0;
|
||||
regs.pc.l = r_mem->read(0xfffc);
|
||||
regs.pc.h = r_mem->read(0xfffd);
|
||||
|
||||
/* registers are not fully reset by SNES */
|
||||
//registers are not fully reset by SNES
|
||||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
regs.s.h = 0x01;
|
||||
@@ -159,140 +61,37 @@ void bCPU::reset() {
|
||||
regs.db = 0x00;
|
||||
regs.p = 0x34;
|
||||
regs.e = 1;
|
||||
regs.mdr = 0x00;
|
||||
|
||||
cpustate = CPUSTATE_RUN;
|
||||
|
||||
dma->reset();
|
||||
time_reset();
|
||||
mmio_reset();
|
||||
dma_reset();
|
||||
|
||||
status.nmi_triggered = false;
|
||||
status.nmi_pin = 1;
|
||||
status.r4210_read = false;
|
||||
run_state.hdma = false;
|
||||
run_state.dma = false;
|
||||
run_state.irq = false;
|
||||
run_state.wai = false;
|
||||
run_state.stp = false;
|
||||
|
||||
status.irq_triggered = false;
|
||||
status.irq_pin = 1;
|
||||
}
|
||||
status.cycle_pos = 0;
|
||||
status.cycle_count = 0;
|
||||
status.cycles_executed = 0;
|
||||
|
||||
void bCPU::cpu_c2() {
|
||||
if(regs.d.l != 0x00) {
|
||||
clock->add_cc1_cycles(6);
|
||||
}
|
||||
}
|
||||
apu_port[0] = 0x00;
|
||||
apu_port[1] = 0x00;
|
||||
apu_port[2] = 0x00;
|
||||
apu_port[3] = 0x00;
|
||||
|
||||
void bCPU::cpu_c4(uint16 a, uint16 b) {
|
||||
if(((a & 0xff00) != (b & 0xff00)) || !regs.p.x) {
|
||||
clock->add_cc1_cycles(6);
|
||||
}
|
||||
}
|
||||
frame();
|
||||
|
||||
void bCPU::cpu_c6(uint16 a) {
|
||||
if(regs.e) {
|
||||
if((regs.pc.w & 0xff00) != (a & 0xff00)) {
|
||||
clock->add_cc1_cycles(6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::cpu_io() {
|
||||
clock->add_cc1_cycles(6);
|
||||
}
|
||||
|
||||
uint8 bCPU::op_read() {
|
||||
uint8 r;
|
||||
r = mem_bus->read(regs.pc);
|
||||
clock->add_cc1_cycles(mem_bus->speed(regs.pc));
|
||||
regs.pc.w++;
|
||||
return r;
|
||||
}
|
||||
|
||||
uint8 bCPU::op_read(uint8 mode, uint32 addr) {
|
||||
uint8 r;
|
||||
switch(mode) {
|
||||
case OPMODE_ADDR:
|
||||
addr &= 0xffff;
|
||||
break;
|
||||
case OPMODE_LONG:
|
||||
addr &= 0xffffff;
|
||||
break;
|
||||
case OPMODE_DBR:
|
||||
addr &= 0xffffff;
|
||||
addr = (regs.db << 16) + addr;
|
||||
break;
|
||||
case OPMODE_PBR:
|
||||
addr &= 0xffff;
|
||||
addr = (regs.pc.b << 16) | addr;
|
||||
break;
|
||||
case OPMODE_DP:
|
||||
addr &= 0xffff;
|
||||
addr = (regs.d + addr) & 0xffff;
|
||||
break;
|
||||
case OPMODE_SP:
|
||||
addr &= 0xffff;
|
||||
addr = (regs.s + addr) & 0xffff;
|
||||
break;
|
||||
}
|
||||
r = mem_bus->read(addr);
|
||||
clock->add_cc1_cycles(mem_bus->speed(addr));
|
||||
return r;
|
||||
}
|
||||
|
||||
void bCPU::op_write(uint8 mode, uint32 addr, uint8 value) {
|
||||
switch(mode) {
|
||||
case OPMODE_ADDR:
|
||||
addr &= 0xffff;
|
||||
break;
|
||||
case OPMODE_LONG:
|
||||
addr &= 0xffffff;
|
||||
break;
|
||||
case OPMODE_DBR:
|
||||
addr &= 0xffffff;
|
||||
addr = (regs.db << 16) + addr;
|
||||
break;
|
||||
case OPMODE_PBR:
|
||||
addr &= 0xffff;
|
||||
addr = (regs.pc.b << 16) | addr;
|
||||
break;
|
||||
case OPMODE_DP:
|
||||
addr &= 0xffff;
|
||||
addr = (regs.d + addr) & 0xffff;
|
||||
break;
|
||||
case OPMODE_SP:
|
||||
addr &= 0xffff;
|
||||
addr = (regs.s + addr) & 0xffff;
|
||||
break;
|
||||
}
|
||||
mem_bus->write(addr, value);
|
||||
clock->add_cc1_cycles(mem_bus->speed(addr));
|
||||
}
|
||||
|
||||
uint8 bCPU::stack_read() {
|
||||
byte r;
|
||||
if(regs.e) {
|
||||
regs.s.l++;
|
||||
} else {
|
||||
regs.s.w++;
|
||||
}
|
||||
r = mem_bus->read(regs.s);
|
||||
clock->add_cc1_cycles(mem_bus->speed(regs.s));
|
||||
return r;
|
||||
}
|
||||
|
||||
void bCPU::stack_write(uint8 value) {
|
||||
mem_bus->write(regs.s, value);
|
||||
clock->add_cc1_cycles(mem_bus->speed(regs.s));
|
||||
if(regs.e) {
|
||||
regs.s.l--;
|
||||
} else {
|
||||
regs.s.w--;
|
||||
}
|
||||
//initial latch values for $213c/$213d
|
||||
//[x]0035 : [y]0000 (53.0 -> 212) [lda $2137]
|
||||
//[x]0038 : [y]0000 (56.5 -> 226) [nop : lda $2137]
|
||||
add_cycles(186);
|
||||
}
|
||||
|
||||
bCPU::bCPU() {
|
||||
dma = new bDMA(this);
|
||||
mmio = new bCPUMMIO(this);
|
||||
init_op_tables();
|
||||
}
|
||||
|
||||
bCPU::~bCPU() {
|
||||
delete(mmio);
|
||||
delete(dma);
|
||||
}
|
||||
bCPU::~bCPU() {}
|
||||
+84
-799
@@ -1,90 +1,57 @@
|
||||
class bCPU;
|
||||
|
||||
class bDMA {
|
||||
public:
|
||||
bCPU *cpu;
|
||||
struct {
|
||||
//$420b
|
||||
bool active;
|
||||
//$420c
|
||||
bool hdma_active;
|
||||
//$43x0
|
||||
bool direction;
|
||||
bool hdma_indirect;
|
||||
int8 incmode;
|
||||
bool fixedxfer;
|
||||
uint8 xfermode;
|
||||
//$43x1
|
||||
uint8 destaddr;
|
||||
//$43x2-$43x4
|
||||
uint32 srcaddr;
|
||||
//$43x5-$43x6
|
||||
uint16 xfersize;
|
||||
//$43x7
|
||||
uint8 hdma_indirect_bank;
|
||||
|
||||
//hdma-specific
|
||||
bool hdma_first_line;
|
||||
bool hdma_repeat;
|
||||
uint16 hdma_line_counter;
|
||||
uint32 hdma_address, hdma_iaddress;
|
||||
bool hdma_completed;
|
||||
}channel[8];
|
||||
bool hdma_triggered;
|
||||
|
||||
void hdma_write(uint8 i, uint8 l, uint8 x);
|
||||
void hdma_run();
|
||||
void hdma_initialize();
|
||||
void run();
|
||||
void reset();
|
||||
uint16 dma_cputommio(uint8 i, uint8 index);
|
||||
uint16 dma_mmiotocpu(uint8 i, uint8 index);
|
||||
void dma_xfer_type0(uint8 i);
|
||||
void dma_xfer_type1(uint8 i);
|
||||
void dma_xfer_type2(uint8 i);
|
||||
void dma_xfer_type3(uint8 i);
|
||||
void dma_xfer_type4(uint8 i);
|
||||
void dma_xfer_type5(uint8 i);
|
||||
|
||||
bDMA(bCPU *_cpu);
|
||||
};
|
||||
|
||||
class bCPUMMIO : public MMIO {
|
||||
public:
|
||||
bCPU *cpu;
|
||||
uint8 read (uint32 addr);
|
||||
void write(uint32 addr, uint8 value);
|
||||
bCPUMMIO(bCPU *_cpu);
|
||||
};
|
||||
|
||||
class bCPU : public CPU {
|
||||
public:
|
||||
enum { CPUSTATE_RUN = 0, CPUSTATE_DMA, CPUSTATE_WAI, CPUSTATE_STP };
|
||||
uint8 cpustate;
|
||||
#include "core/core.h"
|
||||
#include "memory/memory.h"
|
||||
#include "dma/dma.h"
|
||||
#include "timing/timing.h"
|
||||
|
||||
bDMA *dma;
|
||||
enum {
|
||||
OPMODE_ADDR = 1, OPMODE_LONG = 2,
|
||||
OPMODE_DBR = 3, OPMODE_PBR = 4,
|
||||
OPMODE_DP = 5, OPMODE_SP = 6
|
||||
};
|
||||
CPUReg24 aa, rd;
|
||||
uint8 dp, sp;
|
||||
enum { NTSC = 0, PAL = 1 };
|
||||
uint8 region;
|
||||
|
||||
enum {
|
||||
DMASTATE_DMASYNC,
|
||||
DMASTATE_DMASYNC2,
|
||||
DMASTATE_DMASYNC3,
|
||||
DMASTATE_RUN,
|
||||
DMASTATE_CPUSYNC,
|
||||
|
||||
HDMASTATE_IDMASYNC,
|
||||
HDMASTATE_IDMASYNC2,
|
||||
HDMASTATE_IDMASYNC3,
|
||||
HDMASTATE_ICPUSYNC,
|
||||
|
||||
HDMASTATE_DMASYNC,
|
||||
HDMASTATE_DMASYNC2,
|
||||
HDMASTATE_DMASYNC3,
|
||||
HDMASTATE_RUN,
|
||||
HDMASTATE_CPUSYNC
|
||||
};
|
||||
|
||||
struct {
|
||||
bool nmi_triggered;
|
||||
bool nmi_pin;
|
||||
bool r4210_read;
|
||||
bool hdma;
|
||||
bool dma;
|
||||
bool irq;
|
||||
bool stp;
|
||||
bool wai;
|
||||
} run_state;
|
||||
|
||||
bool irq_triggered;
|
||||
bool irq_pin;
|
||||
struct {
|
||||
uint8 cycle_pos, cycle_count;
|
||||
uint8 opcode;
|
||||
uint32 cycles_executed;
|
||||
|
||||
uint8 dma_state, hdma_state;
|
||||
uint32 dma_cycle_count, hdma_cycle_count;
|
||||
|
||||
//$4207-$420a
|
||||
uint16 virq_trigger, hirq_trigger;
|
||||
|
||||
//$2181-$2183
|
||||
uint32 wram_addr;
|
||||
|
||||
//$4016
|
||||
uint8 joypad1_strobe_value;
|
||||
uint8 joypad1_read_pos;
|
||||
//$4016-$4017
|
||||
bool joypad_strobe_latch;
|
||||
uint8 joypad1_read_pos, joypad2_read_pos;
|
||||
|
||||
//$4200
|
||||
bool nmi_enabled;
|
||||
@@ -107,22 +74,25 @@ struct {
|
||||
//$4214-$4216
|
||||
uint16 r4214;
|
||||
uint16 r4216;
|
||||
}status;
|
||||
} status;
|
||||
|
||||
uint8 pio_status();
|
||||
void irq(uint16 addr);
|
||||
void run();
|
||||
void scanline();
|
||||
void frame();
|
||||
void power();
|
||||
void reset();
|
||||
inline bool hdma_test();
|
||||
inline bool nmi_test();
|
||||
inline bool irq_test();
|
||||
|
||||
inline uint8 pio_status();
|
||||
inline void run();
|
||||
inline uint32 clocks_executed();
|
||||
inline void power();
|
||||
inline void reset();
|
||||
|
||||
inline void irq_run();
|
||||
|
||||
//mmio commands
|
||||
void mmio_reset();
|
||||
uint8 mmio_r2180();
|
||||
uint8 mmio_r21c2();
|
||||
uint8 mmio_r21c3();
|
||||
uint8 mmio_r4016();
|
||||
uint8 mmio_r4017();
|
||||
uint8 mmio_r4210();
|
||||
uint8 mmio_r4211();
|
||||
uint8 mmio_r4212();
|
||||
@@ -133,6 +103,20 @@ struct {
|
||||
uint8 mmio_r4217();
|
||||
uint8 mmio_r4218();
|
||||
uint8 mmio_r4219();
|
||||
uint8 mmio_r421a();
|
||||
uint8 mmio_r421b();
|
||||
uint8 mmio_r43x0(uint8 i);
|
||||
uint8 mmio_r43x1(uint8 i);
|
||||
uint8 mmio_r43x2(uint8 i);
|
||||
uint8 mmio_r43x3(uint8 i);
|
||||
uint8 mmio_r43x4(uint8 i);
|
||||
uint8 mmio_r43x5(uint8 i);
|
||||
uint8 mmio_r43x6(uint8 i);
|
||||
uint8 mmio_r43x7(uint8 i);
|
||||
uint8 mmio_r43x8(uint8 i);
|
||||
uint8 mmio_r43x9(uint8 i);
|
||||
uint8 mmio_r43xa(uint8 i);
|
||||
uint8 mmio_r43xb(uint8 i);
|
||||
void mmio_w2180(uint8 value);
|
||||
void mmio_w2181(uint8 value);
|
||||
void mmio_w2182(uint8 value);
|
||||
@@ -160,720 +144,21 @@ struct {
|
||||
void mmio_w43x5(uint8 value, uint8 i);
|
||||
void mmio_w43x6(uint8 value, uint8 i);
|
||||
void mmio_w43x7(uint8 value, uint8 i);
|
||||
void mmio_w43x8(uint8 value, uint8 i);
|
||||
void mmio_w43x9(uint8 value, uint8 i);
|
||||
void mmio_w43xa(uint8 value, uint8 i);
|
||||
void mmio_w43xb(uint8 value, uint8 i);
|
||||
|
||||
void exec_opcode();
|
||||
uint8 mmio_read (uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
uint8 op_read ();
|
||||
uint8 op_read (uint8 mode, uint32 addr);
|
||||
void op_write(uint8 mode, uint32 addr, uint8 value);
|
||||
uint8 stack_read ();
|
||||
void stack_write(uint8 value);
|
||||
|
||||
//cpu extra-cycle conditions
|
||||
void cpu_c2();
|
||||
void cpu_c4(uint16 a, uint16 b);
|
||||
void cpu_c6(uint16 a);
|
||||
void cpu_io();
|
||||
|
||||
//op_adc
|
||||
void flags_adc_b();
|
||||
void flags_adc_w();
|
||||
void op_adc_constb();
|
||||
void op_adc_constw();
|
||||
void op_adc_const();
|
||||
void op_adc_addrb();
|
||||
void op_adc_addrw();
|
||||
void op_adc_addr();
|
||||
void op_adc_addrxb();
|
||||
void op_adc_addrxw();
|
||||
void op_adc_addrx();
|
||||
void op_adc_dpb();
|
||||
void op_adc_dpw();
|
||||
void op_adc_dp();
|
||||
void op_adc_idpb();
|
||||
void op_adc_idpw();
|
||||
void op_adc_idp();
|
||||
void op_adc_ildpb();
|
||||
void op_adc_ildpw();
|
||||
void op_adc_ildp();
|
||||
void op_adc_longb();
|
||||
void op_adc_longw();
|
||||
void op_adc_long();
|
||||
void op_adc_longxb();
|
||||
void op_adc_longxw();
|
||||
void op_adc_longx();
|
||||
void op_adc_addryb();
|
||||
void op_adc_addryw();
|
||||
void op_adc_addry();
|
||||
void op_adc_dpxb();
|
||||
void op_adc_dpxw();
|
||||
void op_adc_dpx();
|
||||
void op_adc_idpxb();
|
||||
void op_adc_idpxw();
|
||||
void op_adc_idpx();
|
||||
void op_adc_idpyb();
|
||||
void op_adc_idpyw();
|
||||
void op_adc_idpy();
|
||||
void op_adc_ildpyb();
|
||||
void op_adc_ildpyw();
|
||||
void op_adc_ildpy();
|
||||
void op_adc_srb();
|
||||
void op_adc_srw();
|
||||
void op_adc_sr();
|
||||
void op_adc_isryb();
|
||||
void op_adc_isryw();
|
||||
void op_adc_isry();
|
||||
//op_and
|
||||
void flags_and_b();
|
||||
void flags_and_w();
|
||||
void op_and_constb();
|
||||
void op_and_constw();
|
||||
void op_and_const();
|
||||
void op_and_addrb();
|
||||
void op_and_addrw();
|
||||
void op_and_addr();
|
||||
void op_and_addrxb();
|
||||
void op_and_addrxw();
|
||||
void op_and_addrx();
|
||||
void op_and_dpb();
|
||||
void op_and_dpw();
|
||||
void op_and_dp();
|
||||
void op_and_idpb();
|
||||
void op_and_idpw();
|
||||
void op_and_idp();
|
||||
void op_and_ildpb();
|
||||
void op_and_ildpw();
|
||||
void op_and_ildp();
|
||||
void op_and_longb();
|
||||
void op_and_longw();
|
||||
void op_and_long();
|
||||
void op_and_longxb();
|
||||
void op_and_longxw();
|
||||
void op_and_longx();
|
||||
void op_and_addryb();
|
||||
void op_and_addryw();
|
||||
void op_and_addry();
|
||||
void op_and_dpxb();
|
||||
void op_and_dpxw();
|
||||
void op_and_dpx();
|
||||
void op_and_idpxb();
|
||||
void op_and_idpxw();
|
||||
void op_and_idpx();
|
||||
void op_and_idpyb();
|
||||
void op_and_idpyw();
|
||||
void op_and_idpy();
|
||||
void op_and_ildpyb();
|
||||
void op_and_ildpyw();
|
||||
void op_and_ildpy();
|
||||
void op_and_srb();
|
||||
void op_and_srw();
|
||||
void op_and_sr();
|
||||
void op_and_isryb();
|
||||
void op_and_isryw();
|
||||
void op_and_isry();
|
||||
//op_cmp
|
||||
void flags_cmp_b();
|
||||
void flags_cmp_w();
|
||||
void op_cmp_constb();
|
||||
void op_cmp_constw();
|
||||
void op_cmp_const();
|
||||
void op_cmp_addrb();
|
||||
void op_cmp_addrw();
|
||||
void op_cmp_addr();
|
||||
void op_cmp_addrxb();
|
||||
void op_cmp_addrxw();
|
||||
void op_cmp_addrx();
|
||||
void op_cmp_dpb();
|
||||
void op_cmp_dpw();
|
||||
void op_cmp_dp();
|
||||
void op_cmp_idpb();
|
||||
void op_cmp_idpw();
|
||||
void op_cmp_idp();
|
||||
void op_cmp_ildpb();
|
||||
void op_cmp_ildpw();
|
||||
void op_cmp_ildp();
|
||||
void op_cmp_longb();
|
||||
void op_cmp_longw();
|
||||
void op_cmp_long();
|
||||
void op_cmp_longxb();
|
||||
void op_cmp_longxw();
|
||||
void op_cmp_longx();
|
||||
void op_cmp_addryb();
|
||||
void op_cmp_addryw();
|
||||
void op_cmp_addry();
|
||||
void op_cmp_dpxb();
|
||||
void op_cmp_dpxw();
|
||||
void op_cmp_dpx();
|
||||
void op_cmp_idpxb();
|
||||
void op_cmp_idpxw();
|
||||
void op_cmp_idpx();
|
||||
void op_cmp_idpyb();
|
||||
void op_cmp_idpyw();
|
||||
void op_cmp_idpy();
|
||||
void op_cmp_ildpyb();
|
||||
void op_cmp_ildpyw();
|
||||
void op_cmp_ildpy();
|
||||
void op_cmp_srb();
|
||||
void op_cmp_srw();
|
||||
void op_cmp_sr();
|
||||
void op_cmp_isryb();
|
||||
void op_cmp_isryw();
|
||||
void op_cmp_isry();
|
||||
//op_eor
|
||||
void flags_eor_b();
|
||||
void flags_eor_w();
|
||||
void op_eor_constb();
|
||||
void op_eor_constw();
|
||||
void op_eor_const();
|
||||
void op_eor_addrb();
|
||||
void op_eor_addrw();
|
||||
void op_eor_addr();
|
||||
void op_eor_addrxb();
|
||||
void op_eor_addrxw();
|
||||
void op_eor_addrx();
|
||||
void op_eor_dpb();
|
||||
void op_eor_dpw();
|
||||
void op_eor_dp();
|
||||
void op_eor_idpb();
|
||||
void op_eor_idpw();
|
||||
void op_eor_idp();
|
||||
void op_eor_ildpb();
|
||||
void op_eor_ildpw();
|
||||
void op_eor_ildp();
|
||||
void op_eor_longb();
|
||||
void op_eor_longw();
|
||||
void op_eor_long();
|
||||
void op_eor_longxb();
|
||||
void op_eor_longxw();
|
||||
void op_eor_longx();
|
||||
void op_eor_addryb();
|
||||
void op_eor_addryw();
|
||||
void op_eor_addry();
|
||||
void op_eor_dpxb();
|
||||
void op_eor_dpxw();
|
||||
void op_eor_dpx();
|
||||
void op_eor_idpxb();
|
||||
void op_eor_idpxw();
|
||||
void op_eor_idpx();
|
||||
void op_eor_idpyb();
|
||||
void op_eor_idpyw();
|
||||
void op_eor_idpy();
|
||||
void op_eor_ildpyb();
|
||||
void op_eor_ildpyw();
|
||||
void op_eor_ildpy();
|
||||
void op_eor_srb();
|
||||
void op_eor_srw();
|
||||
void op_eor_sr();
|
||||
void op_eor_isryb();
|
||||
void op_eor_isryw();
|
||||
void op_eor_isry();
|
||||
//op_incdec
|
||||
void op_incb();
|
||||
void op_incw();
|
||||
void op_inc();
|
||||
void op_inc_addrb();
|
||||
void op_inc_addrw();
|
||||
void op_inc_addr();
|
||||
void op_inc_addrxb();
|
||||
void op_inc_addrxw();
|
||||
void op_inc_addrx();
|
||||
void op_inc_dpb();
|
||||
void op_inc_dpw();
|
||||
void op_inc_dp();
|
||||
void op_inc_dpxb();
|
||||
void op_inc_dpxw();
|
||||
void op_inc_dpx();
|
||||
void op_inxb();
|
||||
void op_inxw();
|
||||
void op_inx();
|
||||
void op_inyb();
|
||||
void op_inyw();
|
||||
void op_iny();
|
||||
void op_decb();
|
||||
void op_decw();
|
||||
void op_dec();
|
||||
void op_dec_addrb();
|
||||
void op_dec_addrw();
|
||||
void op_dec_addr();
|
||||
void op_dec_addrxb();
|
||||
void op_dec_addrxw();
|
||||
void op_dec_addrx();
|
||||
void op_dec_dpb();
|
||||
void op_dec_dpw();
|
||||
void op_dec_dp();
|
||||
void op_dec_dpxb();
|
||||
void op_dec_dpxw();
|
||||
void op_dec_dpx();
|
||||
void op_dexb();
|
||||
void op_dexw();
|
||||
void op_dex();
|
||||
void op_deyb();
|
||||
void op_deyw();
|
||||
void op_dey();
|
||||
//op_lda
|
||||
void flags_lda_b();
|
||||
void flags_lda_w();
|
||||
void op_lda_constb();
|
||||
void op_lda_constw();
|
||||
void op_lda_const();
|
||||
void op_lda_addrb();
|
||||
void op_lda_addrw();
|
||||
void op_lda_addr();
|
||||
void op_lda_addrxb();
|
||||
void op_lda_addrxw();
|
||||
void op_lda_addrx();
|
||||
void op_lda_dpb();
|
||||
void op_lda_dpw();
|
||||
void op_lda_dp();
|
||||
void op_lda_idpb();
|
||||
void op_lda_idpw();
|
||||
void op_lda_idp();
|
||||
void op_lda_ildpb();
|
||||
void op_lda_ildpw();
|
||||
void op_lda_ildp();
|
||||
void op_lda_longb();
|
||||
void op_lda_longw();
|
||||
void op_lda_long();
|
||||
void op_lda_longxb();
|
||||
void op_lda_longxw();
|
||||
void op_lda_longx();
|
||||
void op_lda_addryb();
|
||||
void op_lda_addryw();
|
||||
void op_lda_addry();
|
||||
void op_lda_dpxb();
|
||||
void op_lda_dpxw();
|
||||
void op_lda_dpx();
|
||||
void op_lda_idpxb();
|
||||
void op_lda_idpxw();
|
||||
void op_lda_idpx();
|
||||
void op_lda_idpyb();
|
||||
void op_lda_idpyw();
|
||||
void op_lda_idpy();
|
||||
void op_lda_ildpyb();
|
||||
void op_lda_ildpyw();
|
||||
void op_lda_ildpy();
|
||||
void op_lda_srb();
|
||||
void op_lda_srw();
|
||||
void op_lda_sr();
|
||||
void op_lda_isryb();
|
||||
void op_lda_isryw();
|
||||
void op_lda_isry();
|
||||
//op_misc
|
||||
void flags_bit_b();
|
||||
void flags_bit_w();
|
||||
void op_bit_constb();
|
||||
void op_bit_constw();
|
||||
void op_bit_const();
|
||||
void op_bit_addrb();
|
||||
void op_bit_addrw();
|
||||
void op_bit_addr();
|
||||
void op_bit_addrxb();
|
||||
void op_bit_addrxw();
|
||||
void op_bit_addrx();
|
||||
void op_bit_dpb();
|
||||
void op_bit_dpw();
|
||||
void op_bit_dp();
|
||||
void op_bit_dpxb();
|
||||
void op_bit_dpxw();
|
||||
void op_bit_dpx();
|
||||
void flags_cpx_b();
|
||||
void flags_cpx_w();
|
||||
void op_cpx_constb();
|
||||
void op_cpx_constw();
|
||||
void op_cpx_const();
|
||||
void op_cpx_addrb();
|
||||
void op_cpx_addrw();
|
||||
void op_cpx_addr();
|
||||
void op_cpx_dpb();
|
||||
void op_cpx_dpw();
|
||||
void op_cpx_dp();
|
||||
void flags_cpy_b();
|
||||
void flags_cpy_w();
|
||||
void op_cpy_constb();
|
||||
void op_cpy_constw();
|
||||
void op_cpy_const();
|
||||
void op_cpy_addrb();
|
||||
void op_cpy_addrw();
|
||||
void op_cpy_addr();
|
||||
void op_cpy_dpb();
|
||||
void op_cpy_dpw();
|
||||
void op_cpy_dp();
|
||||
void flags_ldx_b();
|
||||
void flags_ldx_w();
|
||||
void op_ldx_constb();
|
||||
void op_ldx_constw();
|
||||
void op_ldx_const();
|
||||
void op_ldx_addrb();
|
||||
void op_ldx_addrw();
|
||||
void op_ldx_addr();
|
||||
void op_ldx_addryb();
|
||||
void op_ldx_addryw();
|
||||
void op_ldx_addry();
|
||||
void op_ldx_dpb();
|
||||
void op_ldx_dpw();
|
||||
void op_ldx_dp();
|
||||
void op_ldx_dpyb();
|
||||
void op_ldx_dpyw();
|
||||
void op_ldx_dpy();
|
||||
void flags_ldy_b();
|
||||
void flags_ldy_w();
|
||||
void op_ldy_constb();
|
||||
void op_ldy_constw();
|
||||
void op_ldy_const();
|
||||
void op_ldy_addrb();
|
||||
void op_ldy_addrw();
|
||||
void op_ldy_addr();
|
||||
void op_ldy_addrxb();
|
||||
void op_ldy_addrxw();
|
||||
void op_ldy_addrx();
|
||||
void op_ldy_dpb();
|
||||
void op_ldy_dpw();
|
||||
void op_ldy_dp();
|
||||
void op_ldy_dpxb();
|
||||
void op_ldy_dpxw();
|
||||
void op_ldy_dpx();
|
||||
void op_stx_addrb();
|
||||
void op_stx_addrw();
|
||||
void op_stx_addr();
|
||||
void op_stx_dpb();
|
||||
void op_stx_dpw();
|
||||
void op_stx_dp();
|
||||
void op_stx_dpyb();
|
||||
void op_stx_dpyw();
|
||||
void op_stx_dpy();
|
||||
void op_sty_addrb();
|
||||
void op_sty_addrw();
|
||||
void op_sty_addr();
|
||||
void op_sty_dpb();
|
||||
void op_sty_dpw();
|
||||
void op_sty_dp();
|
||||
void op_sty_dpxb();
|
||||
void op_sty_dpxw();
|
||||
void op_sty_dpx();
|
||||
void op_stz_addrb();
|
||||
void op_stz_addrw();
|
||||
void op_stz_addr();
|
||||
void op_stz_addrxb();
|
||||
void op_stz_addrxw();
|
||||
void op_stz_addrx();
|
||||
void op_stz_dpb();
|
||||
void op_stz_dpw();
|
||||
void op_stz_dp();
|
||||
void op_stz_dpxb();
|
||||
void op_stz_dpxw();
|
||||
void op_stz_dpx();
|
||||
void op_xba();
|
||||
void op_trb_addrb();
|
||||
void op_trb_addrw();
|
||||
void op_trb_addr();
|
||||
void op_trb_dpb();
|
||||
void op_trb_dpw();
|
||||
void op_trb_dp();
|
||||
void op_tsb_addrb();
|
||||
void op_tsb_addrw();
|
||||
void op_tsb_addr();
|
||||
void op_tsb_dpb();
|
||||
void op_tsb_dpw();
|
||||
void op_tsb_dp();
|
||||
void op_mvn();
|
||||
void op_mvp();
|
||||
void op_brk();
|
||||
void op_cop();
|
||||
void op_stp();
|
||||
void op_wai();
|
||||
void op_xce();
|
||||
void op_nop();
|
||||
void op_wdm();
|
||||
void op_clc();
|
||||
void op_cld();
|
||||
void op_cli();
|
||||
void op_clv();
|
||||
void op_sec();
|
||||
void op_sed();
|
||||
void op_sei();
|
||||
void op_rep();
|
||||
void op_sep();
|
||||
void op_taxb();
|
||||
void op_taxw();
|
||||
void op_tax();
|
||||
void op_tayb();
|
||||
void op_tayw();
|
||||
void op_tay();
|
||||
void op_tcd();
|
||||
void op_tcs();
|
||||
void op_tdc();
|
||||
void op_tsc();
|
||||
void op_tsxb();
|
||||
void op_tsxw();
|
||||
void op_tsx();
|
||||
void op_txab();
|
||||
void op_txaw();
|
||||
void op_txa();
|
||||
void op_txsb();
|
||||
void op_txsw();
|
||||
void op_txs();
|
||||
void op_txyb();
|
||||
void op_txyw();
|
||||
void op_txy();
|
||||
void op_tyab();
|
||||
void op_tyaw();
|
||||
void op_tya();
|
||||
void op_tyxb();
|
||||
void op_tyxw();
|
||||
void op_tyx();
|
||||
//op_ora
|
||||
void flags_ora_b();
|
||||
void flags_ora_w();
|
||||
void op_ora_constb();
|
||||
void op_ora_constw();
|
||||
void op_ora_const();
|
||||
void op_ora_addrb();
|
||||
void op_ora_addrw();
|
||||
void op_ora_addr();
|
||||
void op_ora_addrxb();
|
||||
void op_ora_addrxw();
|
||||
void op_ora_addrx();
|
||||
void op_ora_dpb();
|
||||
void op_ora_dpw();
|
||||
void op_ora_dp();
|
||||
void op_ora_idpb();
|
||||
void op_ora_idpw();
|
||||
void op_ora_idp();
|
||||
void op_ora_ildpb();
|
||||
void op_ora_ildpw();
|
||||
void op_ora_ildp();
|
||||
void op_ora_longb();
|
||||
void op_ora_longw();
|
||||
void op_ora_long();
|
||||
void op_ora_longxb();
|
||||
void op_ora_longxw();
|
||||
void op_ora_longx();
|
||||
void op_ora_addryb();
|
||||
void op_ora_addryw();
|
||||
void op_ora_addry();
|
||||
void op_ora_dpxb();
|
||||
void op_ora_dpxw();
|
||||
void op_ora_dpx();
|
||||
void op_ora_idpxb();
|
||||
void op_ora_idpxw();
|
||||
void op_ora_idpx();
|
||||
void op_ora_idpyb();
|
||||
void op_ora_idpyw();
|
||||
void op_ora_idpy();
|
||||
void op_ora_ildpyb();
|
||||
void op_ora_ildpyw();
|
||||
void op_ora_ildpy();
|
||||
void op_ora_srb();
|
||||
void op_ora_srw();
|
||||
void op_ora_sr();
|
||||
void op_ora_isryb();
|
||||
void op_ora_isryw();
|
||||
void op_ora_isry();
|
||||
//op_pc
|
||||
void op_jmp_addr();
|
||||
void op_jmp_long();
|
||||
void op_jmp_iaddr();
|
||||
void op_jmp_iaddrx();
|
||||
void op_jmp_iladdr();
|
||||
void op_jsr_addr();
|
||||
void op_jsr_long();
|
||||
void op_jsr_iaddrx();
|
||||
void op_rtie();
|
||||
void op_rtin();
|
||||
void op_rti();
|
||||
void op_rts();
|
||||
void op_rtl();
|
||||
void op_bra();
|
||||
void op_brl();
|
||||
void op_bcc();
|
||||
void op_bcs();
|
||||
void op_bne();
|
||||
void op_beq();
|
||||
void op_bpl();
|
||||
void op_bmi();
|
||||
void op_bvc();
|
||||
void op_bvs();
|
||||
//op_sbc
|
||||
void flags_sbc_b();
|
||||
void flags_sbc_w();
|
||||
void op_sbc_constb();
|
||||
void op_sbc_constw();
|
||||
void op_sbc_const();
|
||||
void op_sbc_addrb();
|
||||
void op_sbc_addrw();
|
||||
void op_sbc_addr();
|
||||
void op_sbc_addrxb();
|
||||
void op_sbc_addrxw();
|
||||
void op_sbc_addrx();
|
||||
void op_sbc_dpb();
|
||||
void op_sbc_dpw();
|
||||
void op_sbc_dp();
|
||||
void op_sbc_idpb();
|
||||
void op_sbc_idpw();
|
||||
void op_sbc_idp();
|
||||
void op_sbc_ildpb();
|
||||
void op_sbc_ildpw();
|
||||
void op_sbc_ildp();
|
||||
void op_sbc_longb();
|
||||
void op_sbc_longw();
|
||||
void op_sbc_long();
|
||||
void op_sbc_longxb();
|
||||
void op_sbc_longxw();
|
||||
void op_sbc_longx();
|
||||
void op_sbc_addryb();
|
||||
void op_sbc_addryw();
|
||||
void op_sbc_addry();
|
||||
void op_sbc_dpxb();
|
||||
void op_sbc_dpxw();
|
||||
void op_sbc_dpx();
|
||||
void op_sbc_idpxb();
|
||||
void op_sbc_idpxw();
|
||||
void op_sbc_idpx();
|
||||
void op_sbc_idpyb();
|
||||
void op_sbc_idpyw();
|
||||
void op_sbc_idpy();
|
||||
void op_sbc_ildpyb();
|
||||
void op_sbc_ildpyw();
|
||||
void op_sbc_ildpy();
|
||||
void op_sbc_srb();
|
||||
void op_sbc_srw();
|
||||
void op_sbc_sr();
|
||||
void op_sbc_isryb();
|
||||
void op_sbc_isryw();
|
||||
void op_sbc_isry();
|
||||
//op_shift
|
||||
void op_aslb();
|
||||
void op_aslw();
|
||||
void op_asl();
|
||||
void op_asl_addrb();
|
||||
void op_asl_addrw();
|
||||
void op_asl_addr();
|
||||
void op_asl_addrxb();
|
||||
void op_asl_addrxw();
|
||||
void op_asl_addrx();
|
||||
void op_asl_dpb();
|
||||
void op_asl_dpw();
|
||||
void op_asl_dp();
|
||||
void op_asl_dpxb();
|
||||
void op_asl_dpxw();
|
||||
void op_asl_dpx();
|
||||
void op_lsrb();
|
||||
void op_lsrw();
|
||||
void op_lsr();
|
||||
void op_lsr_addrb();
|
||||
void op_lsr_addrw();
|
||||
void op_lsr_addr();
|
||||
void op_lsr_addrxb();
|
||||
void op_lsr_addrxw();
|
||||
void op_lsr_addrx();
|
||||
void op_lsr_dpb();
|
||||
void op_lsr_dpw();
|
||||
void op_lsr_dp();
|
||||
void op_lsr_dpxb();
|
||||
void op_lsr_dpxw();
|
||||
void op_lsr_dpx();
|
||||
void op_rolb();
|
||||
void op_rolw();
|
||||
void op_rol();
|
||||
void op_rol_addrb();
|
||||
void op_rol_addrw();
|
||||
void op_rol_addr();
|
||||
void op_rol_addrxb();
|
||||
void op_rol_addrxw();
|
||||
void op_rol_addrx();
|
||||
void op_rol_dpb();
|
||||
void op_rol_dpw();
|
||||
void op_rol_dp();
|
||||
void op_rol_dpxb();
|
||||
void op_rol_dpxw();
|
||||
void op_rol_dpx();
|
||||
void op_rorb();
|
||||
void op_rorw();
|
||||
void op_ror();
|
||||
void op_ror_addrb();
|
||||
void op_ror_addrw();
|
||||
void op_ror_addr();
|
||||
void op_ror_addrxb();
|
||||
void op_ror_addrxw();
|
||||
void op_ror_addrx();
|
||||
void op_ror_dpb();
|
||||
void op_ror_dpw();
|
||||
void op_ror_dp();
|
||||
void op_ror_dpxb();
|
||||
void op_ror_dpxw();
|
||||
void op_ror_dpx();
|
||||
//op_sta
|
||||
void op_sta_addrb();
|
||||
void op_sta_addrw();
|
||||
void op_sta_addr();
|
||||
void op_sta_addrxb();
|
||||
void op_sta_addrxw();
|
||||
void op_sta_addrx();
|
||||
void op_sta_dpb();
|
||||
void op_sta_dpw();
|
||||
void op_sta_dp();
|
||||
void op_sta_idpb();
|
||||
void op_sta_idpw();
|
||||
void op_sta_idp();
|
||||
void op_sta_ildpb();
|
||||
void op_sta_ildpw();
|
||||
void op_sta_ildp();
|
||||
void op_sta_longb();
|
||||
void op_sta_longw();
|
||||
void op_sta_long();
|
||||
void op_sta_longxb();
|
||||
void op_sta_longxw();
|
||||
void op_sta_longx();
|
||||
void op_sta_addryb();
|
||||
void op_sta_addryw();
|
||||
void op_sta_addry();
|
||||
void op_sta_dpxb();
|
||||
void op_sta_dpxw();
|
||||
void op_sta_dpx();
|
||||
void op_sta_idpxb();
|
||||
void op_sta_idpxw();
|
||||
void op_sta_idpx();
|
||||
void op_sta_idpyb();
|
||||
void op_sta_idpyw();
|
||||
void op_sta_idpy();
|
||||
void op_sta_ildpyb();
|
||||
void op_sta_ildpyw();
|
||||
void op_sta_ildpy();
|
||||
void op_sta_srb();
|
||||
void op_sta_srw();
|
||||
void op_sta_sr();
|
||||
void op_sta_isryb();
|
||||
void op_sta_isryw();
|
||||
void op_sta_isry();
|
||||
//op_stack
|
||||
void op_phab();
|
||||
void op_phaw();
|
||||
void op_pha();
|
||||
void op_phb();
|
||||
void op_phd();
|
||||
void op_phk();
|
||||
void op_php();
|
||||
void op_phxb();
|
||||
void op_phxw();
|
||||
void op_phx();
|
||||
void op_phyb();
|
||||
void op_phyw();
|
||||
void op_phy();
|
||||
void op_plab();
|
||||
void op_plaw();
|
||||
void op_pla();
|
||||
void op_plb();
|
||||
void op_pld();
|
||||
void op_plp();
|
||||
void op_plxb();
|
||||
void op_plxw();
|
||||
void op_plx();
|
||||
void op_plyb();
|
||||
void op_plyw();
|
||||
void op_ply();
|
||||
void op_pea();
|
||||
void op_pei();
|
||||
void op_per();
|
||||
enum { CYCLE_OPREAD, CYCLE_READ, CYCLE_WRITE, CYCLE_IO };
|
||||
inline void pre_exec_cycle();
|
||||
inline void exec_hdma();
|
||||
inline void exec_dma();
|
||||
inline void exec_cycle();
|
||||
inline void last_cycle();
|
||||
inline bool in_opcode();
|
||||
|
||||
bCPU();
|
||||
~bCPU();
|
||||
|
||||
+160
-277
@@ -1,280 +1,163 @@
|
||||
void bCPU::exec_opcode() {
|
||||
byte op;
|
||||
op = op_read();
|
||||
switch(op) {
|
||||
/* 0x */
|
||||
case 0x00:op_brk(); break;
|
||||
case 0x01:op_ora_idpx(); break;
|
||||
case 0x02:op_cop(); break;
|
||||
case 0x03:op_ora_sr(); break;
|
||||
case 0x04:op_tsb_dp(); break;
|
||||
case 0x05:op_ora_dp(); break;
|
||||
case 0x06:op_asl_dp(); break;
|
||||
case 0x07:op_ora_ildp(); break;
|
||||
case 0x08:op_php(); break;
|
||||
case 0x09:op_ora_const();break;
|
||||
case 0x0a:op_asl(); break;
|
||||
case 0x0b:op_phd(); break;
|
||||
case 0x0c:op_tsb_addr(); break;
|
||||
case 0x0d:op_ora_addr(); break;
|
||||
case 0x0e:op_asl_addr(); break;
|
||||
case 0x0f:op_ora_long(); break;
|
||||
/* 1x */
|
||||
case 0x10:op_bpl(); break;
|
||||
case 0x11:op_ora_idpy(); break;
|
||||
case 0x12:op_ora_idp(); break;
|
||||
case 0x13:op_ora_isry(); break;
|
||||
case 0x14:op_trb_dp(); break;
|
||||
case 0x15:op_ora_dpx(); break;
|
||||
case 0x16:op_asl_dpx(); break;
|
||||
case 0x17:op_ora_ildpy();break;
|
||||
case 0x18:op_clc(); break;
|
||||
case 0x19:op_ora_addry();break;
|
||||
case 0x1a:op_inc(); break;
|
||||
case 0x1b:op_tcs(); break;
|
||||
case 0x1c:op_trb_addr(); break;
|
||||
case 0x1d:op_ora_addrx();break;
|
||||
case 0x1e:op_asl_addrx();break;
|
||||
case 0x1f:op_ora_longx();break;
|
||||
/* 2x */
|
||||
case 0x20:op_jsr_addr(); break;
|
||||
case 0x21:op_and_idpx(); break;
|
||||
case 0x22:op_jsr_long(); break;
|
||||
case 0x23:op_and_sr(); break;
|
||||
case 0x24:op_bit_dp(); break;
|
||||
case 0x25:op_and_dp(); break;
|
||||
case 0x26:op_rol_dp(); break;
|
||||
case 0x27:op_and_ildp(); break;
|
||||
case 0x28:op_plp(); break;
|
||||
case 0x29:op_and_const();break;
|
||||
case 0x2a:op_rol(); break;
|
||||
case 0x2b:op_pld(); break;
|
||||
case 0x2c:op_bit_addr(); break;
|
||||
case 0x2d:op_and_addr(); break;
|
||||
case 0x2e:op_rol_addr(); break;
|
||||
case 0x2f:op_and_long(); break;
|
||||
/* 3x */
|
||||
case 0x30:op_bmi(); break;
|
||||
case 0x31:op_and_idpy(); break;
|
||||
case 0x32:op_and_idp(); break;
|
||||
case 0x33:op_and_isry(); break;
|
||||
case 0x34:op_bit_dpx(); break;
|
||||
case 0x35:op_and_dpx(); break;
|
||||
case 0x36:op_rol_dpx(); break;
|
||||
case 0x37:op_and_ildpy();break;
|
||||
case 0x38:op_sec(); break;
|
||||
case 0x39:op_and_addry();break;
|
||||
case 0x3a:op_dec(); break;
|
||||
case 0x3b:op_tsc(); break;
|
||||
case 0x3c:op_bit_addrx();break;
|
||||
case 0x3d:op_and_addrx();break;
|
||||
case 0x3e:op_rol_addrx();break;
|
||||
case 0x3f:op_and_longx();break;
|
||||
/* 4x */
|
||||
case 0x40:op_rti(); break;
|
||||
case 0x41:op_eor_idpx(); break;
|
||||
case 0x42:op_wdm(); break;
|
||||
case 0x43:op_eor_sr(); break;
|
||||
case 0x44:op_mvp(); break;
|
||||
case 0x45:op_eor_dp(); break;
|
||||
case 0x46:op_lsr_dp(); break;
|
||||
case 0x47:op_eor_ildp(); break;
|
||||
case 0x48:op_pha(); break;
|
||||
case 0x49:op_eor_const();break;
|
||||
case 0x4a:op_lsr(); break;
|
||||
case 0x4b:op_phk(); break;
|
||||
case 0x4c:op_jmp_addr(); break;
|
||||
case 0x4d:op_eor_addr(); break;
|
||||
case 0x4e:op_lsr_addr(); break;
|
||||
case 0x4f:op_eor_long(); break;
|
||||
/* 5x */
|
||||
case 0x50:op_bvc(); break;
|
||||
case 0x51:op_eor_idpy(); break;
|
||||
case 0x52:op_eor_idp(); break;
|
||||
case 0x53:op_eor_isry(); break;
|
||||
case 0x54:op_mvn(); break;
|
||||
case 0x55:op_eor_dpx(); break;
|
||||
case 0x56:op_lsr_dpx(); break;
|
||||
case 0x57:op_eor_ildpy();break;
|
||||
case 0x58:op_cli(); break;
|
||||
case 0x59:op_eor_addry();break;
|
||||
case 0x5a:op_phy(); break;
|
||||
case 0x5b:op_tcd(); break;
|
||||
case 0x5c:op_jmp_long(); break;
|
||||
case 0x5d:op_eor_addrx();break;
|
||||
case 0x5e:op_lsr_addrx();break;
|
||||
case 0x5f:op_eor_longx();break;
|
||||
/* 6x */
|
||||
case 0x60:op_rts(); break;
|
||||
case 0x61:op_adc_idpx(); break;
|
||||
case 0x62:op_per(); break;
|
||||
case 0x63:op_adc_sr(); break;
|
||||
case 0x64:op_stz_dp(); break;
|
||||
case 0x65:op_adc_dp(); break;
|
||||
case 0x66:op_ror_dp(); break;
|
||||
case 0x67:op_adc_ildp(); break;
|
||||
case 0x68:op_pla(); break;
|
||||
case 0x69:op_adc_const();break;
|
||||
case 0x6a:op_ror(); break;
|
||||
case 0x6b:op_rtl(); break;
|
||||
case 0x6c:op_jmp_iaddr();break;
|
||||
case 0x6d:op_adc_addr(); break;
|
||||
case 0x6e:op_ror_addr(); break;
|
||||
case 0x6f:op_adc_long(); break;
|
||||
/* 7x */
|
||||
case 0x70:op_bvs(); break;
|
||||
case 0x71:op_adc_idpy(); break;
|
||||
case 0x72:op_adc_idp(); break;
|
||||
case 0x73:op_adc_isry(); break;
|
||||
case 0x74:op_stz_dpx(); break;
|
||||
case 0x75:op_adc_dpx(); break;
|
||||
case 0x76:op_ror_dpx(); break;
|
||||
case 0x77:op_adc_ildpy(); break;
|
||||
case 0x78:op_sei(); break;
|
||||
case 0x79:op_adc_addry(); break;
|
||||
case 0x7a:op_ply(); break;
|
||||
case 0x7b:op_tdc(); break;
|
||||
case 0x7c:op_jmp_iaddrx();break;
|
||||
case 0x7d:op_adc_addrx(); break;
|
||||
case 0x7e:op_ror_addrx(); break;
|
||||
case 0x7f:op_adc_longx(); break;
|
||||
/* 8x */
|
||||
case 0x80:op_bra(); break;
|
||||
case 0x81:op_sta_idpx(); break;
|
||||
case 0x82:op_brl(); break;
|
||||
case 0x83:op_sta_sr(); break;
|
||||
case 0x84:op_sty_dp(); break;
|
||||
case 0x85:op_sta_dp(); break;
|
||||
case 0x86:op_stx_dp(); break;
|
||||
case 0x87:op_sta_ildp(); break;
|
||||
case 0x88:op_dey(); break;
|
||||
case 0x89:op_bit_const();break;
|
||||
case 0x8a:op_txa(); break;
|
||||
case 0x8b:op_phb(); break;
|
||||
case 0x8c:op_sty_addr(); break;
|
||||
case 0x8d:op_sta_addr(); break;
|
||||
case 0x8e:op_stx_addr(); break;
|
||||
case 0x8f:op_sta_long(); break;
|
||||
/* 9x */
|
||||
case 0x90:op_bcc(); break;
|
||||
case 0x91:op_sta_idpy(); break;
|
||||
case 0x92:op_sta_idp(); break;
|
||||
case 0x93:op_sta_isry(); break;
|
||||
case 0x94:op_sty_dpx(); break;
|
||||
case 0x95:op_sta_dpx(); break;
|
||||
case 0x96:op_stx_dpy(); break;
|
||||
case 0x97:op_sta_ildpy();break;
|
||||
case 0x98:op_tya(); break;
|
||||
case 0x99:op_sta_addry();break;
|
||||
case 0x9a:op_txs(); break;
|
||||
case 0x9b:op_txy(); break;
|
||||
case 0x9c:op_stz_addr(); break;
|
||||
case 0x9d:op_sta_addrx();break;
|
||||
case 0x9e:op_stz_addrx();break;
|
||||
case 0x9f:op_sta_longx();break;
|
||||
/* ax */
|
||||
case 0xa0:op_ldy_const();break;
|
||||
case 0xa1:op_lda_idpx(); break;
|
||||
case 0xa2:op_ldx_const();break;
|
||||
case 0xa3:op_lda_sr(); break;
|
||||
case 0xa4:op_ldy_dp(); break;
|
||||
case 0xa5:op_lda_dp(); break;
|
||||
case 0xa6:op_ldx_dp(); break;
|
||||
case 0xa7:op_lda_ildp(); break;
|
||||
case 0xa8:op_tay(); break;
|
||||
case 0xa9:op_lda_const();break;
|
||||
case 0xaa:op_tax(); break;
|
||||
case 0xab:op_plb(); break;
|
||||
case 0xac:op_ldy_addr(); break;
|
||||
case 0xad:op_lda_addr(); break;
|
||||
case 0xae:op_ldx_addr(); break;
|
||||
case 0xaf:op_lda_long(); break;
|
||||
/* bx */
|
||||
case 0xb0:op_bcs(); break;
|
||||
case 0xb1:op_lda_idpy(); break;
|
||||
case 0xb2:op_lda_idp(); break;
|
||||
case 0xb3:op_lda_isry(); break;
|
||||
case 0xb4:op_ldy_dpx(); break;
|
||||
case 0xb5:op_lda_dpx(); break;
|
||||
case 0xb6:op_ldx_dpy(); break;
|
||||
case 0xb7:op_lda_ildpy();break;
|
||||
case 0xb8:op_clv(); break;
|
||||
case 0xb9:op_lda_addry();break;
|
||||
case 0xba:op_tsx(); break;
|
||||
case 0xbb:op_tyx(); break;
|
||||
case 0xbc:op_ldy_addrx();break;
|
||||
case 0xbd:op_lda_addrx();break;
|
||||
case 0xbe:op_ldx_addry();break;
|
||||
case 0xbf:op_lda_longx();break;
|
||||
/* cx */
|
||||
case 0xc0:op_cpy_const();break;
|
||||
case 0xc1:op_cmp_idpx(); break;
|
||||
case 0xc2:op_rep(); break;
|
||||
case 0xc3:op_cmp_sr(); break;
|
||||
case 0xc4:op_cpy_dp(); break;
|
||||
case 0xc5:op_cmp_dp(); break;
|
||||
case 0xc6:op_dec_dp(); break;
|
||||
case 0xc7:op_cmp_ildp(); break;
|
||||
case 0xc8:op_iny(); break;
|
||||
case 0xc9:op_cmp_const();break;
|
||||
case 0xca:op_dex(); break;
|
||||
case 0xcb:op_wai(); break;
|
||||
case 0xcc:op_cpy_addr(); break;
|
||||
case 0xcd:op_cmp_addr(); break;
|
||||
case 0xce:op_dec_addr(); break;
|
||||
case 0xcf:op_cmp_long(); break;
|
||||
/* dx */
|
||||
case 0xd0:op_bne(); break;
|
||||
case 0xd1:op_cmp_idpy(); break;
|
||||
case 0xd2:op_cmp_idp(); break;
|
||||
case 0xd3:op_cmp_isry(); break;
|
||||
case 0xd4:op_pei(); break;
|
||||
case 0xd5:op_cmp_dpx(); break;
|
||||
case 0xd6:op_dec_dpx(); break;
|
||||
case 0xd7:op_cmp_ildpy(); break;
|
||||
case 0xd8:op_cld(); break;
|
||||
case 0xd9:op_cmp_addry(); break;
|
||||
case 0xda:op_phx(); break;
|
||||
case 0xdb:op_stp(); break;
|
||||
case 0xdc:op_jmp_iladdr();break;
|
||||
case 0xdd:op_cmp_addrx(); break;
|
||||
case 0xde:op_dec_addrx(); break;
|
||||
case 0xdf:op_cmp_longx(); break;
|
||||
/* ex */
|
||||
case 0xe0:op_cpx_const();break;
|
||||
case 0xe1:op_sbc_idpx(); break;
|
||||
case 0xe2:op_sep(); break;
|
||||
case 0xe3:op_sbc_sr(); break;
|
||||
case 0xe4:op_cpx_dp(); break;
|
||||
case 0xe5:op_sbc_dp(); break;
|
||||
case 0xe6:op_inc_dp(); break;
|
||||
case 0xe7:op_sbc_ildp(); break;
|
||||
case 0xe8:op_inx(); break;
|
||||
case 0xe9:op_sbc_const();break;
|
||||
case 0xea:op_nop(); break;
|
||||
case 0xeb:op_xba(); break;
|
||||
case 0xec:op_cpx_addr(); break;
|
||||
case 0xed:op_sbc_addr(); break;
|
||||
case 0xee:op_inc_addr(); break;
|
||||
case 0xef:op_sbc_long(); break;
|
||||
/* fx */
|
||||
case 0xf0:op_beq(); break;
|
||||
case 0xf1:op_sbc_idpy(); break;
|
||||
case 0xf2:op_sbc_idp(); break;
|
||||
case 0xf3:op_sbc_isry(); break;
|
||||
case 0xf4:op_pea(); break;
|
||||
case 0xf5:op_sbc_dpx(); break;
|
||||
case 0xf6:op_inc_dpx(); break;
|
||||
case 0xf7:op_sbc_ildpy(); break;
|
||||
case 0xf8:op_sed(); break;
|
||||
case 0xf9:op_sbc_addry(); break;
|
||||
case 0xfa:op_plx(); break;
|
||||
case 0xfb:op_xce(); break;
|
||||
case 0xfc:op_jsr_iaddrx();break;
|
||||
case 0xfd:op_sbc_addrx(); break;
|
||||
case 0xfe:op_inc_addrx(); break;
|
||||
case 0xff:op_sbc_longx(); break;
|
||||
void bCPU::last_cycle() {
|
||||
time.nmi_pending |= nmi_test();
|
||||
time.irq_pending |= irq_test();
|
||||
|
||||
run_state.irq = (time.nmi_pending || time.irq_pending);
|
||||
}
|
||||
|
||||
void bCPU::pre_exec_cycle() {
|
||||
if(!run_state.dma && !run_state.hdma)return;
|
||||
|
||||
int c, z;
|
||||
if(run_state.hdma) {
|
||||
switch(status.hdma_state) {
|
||||
case HDMASTATE_ICPUSYNC:
|
||||
case HDMASTATE_CPUSYNC:
|
||||
c = status.cycle_count;
|
||||
z = c - (status.hdma_cycle_count % c);
|
||||
if(!z)z = c;
|
||||
add_cycles(z);
|
||||
run_state.hdma = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE);
|
||||
if(run_state.dma) {
|
||||
switch(status.dma_state) {
|
||||
case DMASTATE_CPUSYNC:
|
||||
c = status.cycle_count;
|
||||
z = c - (status.dma_cycle_count % c);
|
||||
if(!z)z = c;
|
||||
add_cycles(z);
|
||||
run_state.dma = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::exec_hdma() {
|
||||
int n;
|
||||
static int z;
|
||||
switch(status.hdma_state) {
|
||||
case HDMASTATE_IDMASYNC:
|
||||
status.hdma_cycle_count = 0;
|
||||
z = 0;
|
||||
if(!run_state.dma) {
|
||||
exec_cycle();
|
||||
status.hdma_state = HDMASTATE_IDMASYNC2;
|
||||
} else {
|
||||
status.hdma_state = HDMASTATE_IDMASYNC3;
|
||||
}
|
||||
break;
|
||||
case HDMASTATE_IDMASYNC2:
|
||||
n = 8 - dma_counter() + 8;
|
||||
add_cycles(n);
|
||||
status.hdma_cycle_count += n;
|
||||
status.hdma_state = HDMASTATE_IDMASYNC3;
|
||||
break;
|
||||
case HDMASTATE_IDMASYNC3:
|
||||
hdma_init();
|
||||
if(!run_state.dma) {
|
||||
status.hdma_state = HDMASTATE_ICPUSYNC;
|
||||
} else {
|
||||
run_state.hdma = false;
|
||||
}
|
||||
break;
|
||||
case HDMASTATE_ICPUSYNC:
|
||||
exec_cycle();
|
||||
break;
|
||||
|
||||
case HDMASTATE_DMASYNC:
|
||||
status.hdma_cycle_count = 0;
|
||||
z = 0;
|
||||
if(!run_state.dma) {
|
||||
exec_cycle();
|
||||
status.hdma_state = HDMASTATE_DMASYNC2;
|
||||
} else {
|
||||
status.hdma_state = HDMASTATE_DMASYNC3;
|
||||
}
|
||||
break;
|
||||
case HDMASTATE_DMASYNC2:
|
||||
n = 8 - dma_counter() + 8;
|
||||
add_cycles(n);
|
||||
status.hdma_cycle_count += n;
|
||||
status.hdma_state = HDMASTATE_DMASYNC3;
|
||||
break;
|
||||
case HDMASTATE_DMASYNC3:
|
||||
if(channel[z].hdma_line_counter) {
|
||||
add_cycles(8);
|
||||
status.hdma_cycle_count += 8;
|
||||
}
|
||||
if(++z < 8)break;
|
||||
status.hdma_state = HDMASTATE_RUN;
|
||||
break;
|
||||
case HDMASTATE_RUN:
|
||||
hdma_run(); //updates status.hdma_cycle_count
|
||||
if(!run_state.dma) {
|
||||
status.hdma_state = HDMASTATE_CPUSYNC;
|
||||
} else {
|
||||
run_state.hdma = false;
|
||||
}
|
||||
break;
|
||||
case HDMASTATE_CPUSYNC:
|
||||
exec_cycle();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::exec_dma() {
|
||||
int n;
|
||||
static int z;
|
||||
switch(status.dma_state) {
|
||||
case DMASTATE_DMASYNC:
|
||||
exec_cycle();
|
||||
status.dma_state = DMASTATE_DMASYNC2;
|
||||
break;
|
||||
case DMASTATE_DMASYNC2:
|
||||
n = 8 - dma_counter() + 8;
|
||||
add_cycles(n);
|
||||
status.dma_cycle_count = n;
|
||||
z = 0;
|
||||
status.dma_state = DMASTATE_DMASYNC3;
|
||||
break;
|
||||
case DMASTATE_DMASYNC3:
|
||||
if(channel[z].dma_enabled == true) {
|
||||
add_cycles(8);
|
||||
status.dma_cycle_count += 8;
|
||||
}
|
||||
if(++z < 8)break;
|
||||
status.dma_state = DMASTATE_RUN;
|
||||
break;
|
||||
case DMASTATE_RUN:
|
||||
dma_run(); //updates status.dma_cycle_count
|
||||
cycle_edge();
|
||||
break;
|
||||
case DMASTATE_CPUSYNC:
|
||||
exec_cycle();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::exec_cycle() {
|
||||
if(status.cycle_pos) {
|
||||
(this->*optbl[status.opcode])();
|
||||
#ifdef DEBUGGER
|
||||
if(status.cycle_pos == 0) {
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_END);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
//on first cycle?
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_BEGIN);
|
||||
#endif
|
||||
status.opcode = op_readpc();
|
||||
status.cycle_pos = 1;
|
||||
}
|
||||
|
||||
//only return true when we are on an opcode edge
|
||||
bool bCPU::in_opcode() {
|
||||
return (status.cycle_pos != 0);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
void bCPU::irq_run() {
|
||||
mem_read(regs.pc.d);
|
||||
cpu_io();
|
||||
if(!regs.e)op_writestack(regs.pc.b);
|
||||
op_writestack(regs.pc.h);
|
||||
op_writestack(regs.pc.l);
|
||||
op_writestack(regs.e ? (regs.p & ~0x10) : regs.p);
|
||||
rd.l = op_readaddr(aa.w + 0);
|
||||
regs.pc.b = 0x00;
|
||||
regs.p.i = 1;
|
||||
regs.p.d = 0;
|
||||
rd.h = op_readaddr(aa.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
#ifdef DEBUGGER
|
||||
//let debugger know the new IRQ opcode address
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_END);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool bCPU::nmi_test() {
|
||||
if(time.nmi_transition == 0)return false;
|
||||
time.nmi_transition = 0;
|
||||
|
||||
run_state.wai = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bCPU::irq_test() {
|
||||
if(time.irq_transition == 1)goto _true;
|
||||
|
||||
if(time.irq_read == 0) {
|
||||
if(time.irq_line == 1 && (irq_trigger_pos_match(0) || irq_trigger_pos_match(2))) {
|
||||
return false;
|
||||
}
|
||||
goto _true;
|
||||
}
|
||||
|
||||
if(time.irq_line == 0) {
|
||||
time.irq_line = 1;
|
||||
goto _true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
_true:
|
||||
time.irq_transition = 0;
|
||||
|
||||
run_state.wai = false;
|
||||
return (regs.p.i) ? false : true;
|
||||
}
|
||||
+405
-452
File diff suppressed because it is too large.
Load diff
Loaded 100 of 432 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user