mirror of
https://github.com/ares-emulator/ares.git
synced 2026-11-09 17:03:16 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e308cf4275 | ||
|
|
192e53bb87 | ||
|
|
0ed9edfcdb | ||
|
|
764fe1974a | ||
|
|
a55d640459 | ||
|
|
6010bffe5d | ||
|
|
e492268025 | ||
|
|
a36c26c997 | ||
|
|
a3945e5772 | ||
|
|
6b6233b3af | ||
|
|
9f63cb1b99 | ||
|
|
49c39e0e4d | ||
|
|
7dec0b2a3c | ||
|
|
f288280ceb | ||
|
|
c6c5f4669c | ||
|
|
397b9c4505 | ||
|
|
7e2cfb6d40 |
No files matched your search
@@ -1,57 +0,0 @@
|
||||
#[bsnes v0.009 configuration file]
|
||||
|
||||
#[apu enable]
|
||||
apu.enabled = true
|
||||
|
||||
#[video mode]
|
||||
# 0: 256x224w
|
||||
# 1: 512x448w
|
||||
# 2: 960x720w
|
||||
# 3: 640x480f
|
||||
# 4: 1024x768f
|
||||
video.mode = 1
|
||||
|
||||
#[video memory type]
|
||||
# true: video ram (VRAM)
|
||||
# false: system ram (SRAM)
|
||||
#
|
||||
# VRAM results in the image being stretched in hardware,
|
||||
# which is generally much faster, and automatically adds
|
||||
# bilinear filtering (if the card supports it).
|
||||
#
|
||||
# However, some video cards end up taking a major speed
|
||||
# loss when this option is enabled. It is also the only
|
||||
# way to guarantee that the output image will not be
|
||||
# filtered.
|
||||
video.use_vram = true
|
||||
|
||||
#[color curve]
|
||||
# gives a more NTSC TV-style feel to the color palette
|
||||
# by darkening the image contrast.
|
||||
video.color_curve = enabled
|
||||
|
||||
#[show fps]
|
||||
# true: show fps in titlebar
|
||||
# false: do not show fps in titlebar
|
||||
gui.show_fps = true
|
||||
|
||||
#[wait for vertical retrace]
|
||||
video.vblank = false
|
||||
|
||||
#[joypad 1 configuration]
|
||||
# Key numbers are standard windows VK_* keys.
|
||||
# Unfortunately, I don't have a table of common
|
||||
# key mappings to list here... use GUI joypad
|
||||
# configuration utility to edit these.
|
||||
input.joypad1.up = 0x26
|
||||
input.joypad1.down = 0x28
|
||||
input.joypad1.left = 0x25
|
||||
input.joypad1.right = 0x27
|
||||
input.joypad1.a = 0x58
|
||||
input.joypad1.b = 0x5a
|
||||
input.joypad1.x = 0x53
|
||||
input.joypad1.y = 0x41
|
||||
input.joypad1.l = 0x44
|
||||
input.joypad1.r = 0x43
|
||||
input.joypad1.select = 0x10
|
||||
input.joypad1.start = 0x0d
|
||||
+18
-4
@@ -4,9 +4,10 @@ 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, 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.
|
||||
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:
|
||||
---------------------------------
|
||||
@@ -17,5 +18,18 @@ emulators.
|
||||
The Simple DirectMedia Layer library source code is available from:
|
||||
http://www.libsdl.org/
|
||||
|
||||
This library is distributed under the terms of the GNU LGPL license:
|
||||
This library is distributed under the terms of the GNU LGPL:
|
||||
http://www.gnu.org/copyleft/lesser.html
|
||||
|
||||
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)
|
||||
@@ -1,2 +1,3 @@
|
||||
#include "../base.h"
|
||||
#include "iplrom.h"
|
||||
#include "dapu.cpp"
|
||||
+12
-7
@@ -1,15 +1,13 @@
|
||||
#define _APU_IPLROM
|
||||
#include "iplrom.h"
|
||||
#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
|
||||
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;
|
||||
@@ -18,11 +16,18 @@ APURegs regs;
|
||||
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 cycles_executed() = 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() {}
|
||||
};
|
||||
+19
-23
@@ -1,20 +1,18 @@
|
||||
class APURegFlags {
|
||||
private:
|
||||
template <uint8 B> class bit {
|
||||
template<uint mask> class bit {
|
||||
public:
|
||||
uint8 _b;
|
||||
inline operator bool() { return (_b & B); }
|
||||
inline bool operator = (bool i) { (i) ? _b |= B : _b &= ~B; return (_b & B); }
|
||||
inline bool operator & (bool i) { if(i)_b &= ~B; return (_b & B); }
|
||||
inline bool operator &= (bool i) { if(i)_b &= ~B; return (_b & B); }
|
||||
inline bool operator | (bool i) { if(i)_b |= B; return (_b & B); }
|
||||
inline bool operator |= (bool i) { if(i)_b |= B; return (_b & B); }
|
||||
inline bool operator ^ (bool i) { if(i)_b ^= B; return (_b & B); }
|
||||
inline bool operator ^= (bool i) { if(i)_b ^= B; return (_b & B); }
|
||||
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 _b;
|
||||
union {
|
||||
uint8 data;
|
||||
bit<0x80> n;
|
||||
bit<0x40> v;
|
||||
bit<0x20> p;
|
||||
@@ -23,14 +21,15 @@ public:
|
||||
bit<0x04> i;
|
||||
bit<0x02> z;
|
||||
bit<0x01> c;
|
||||
};
|
||||
};
|
||||
|
||||
APURegFlags() { _b = 0; }
|
||||
inline operator uint8() { return _b; }
|
||||
inline unsigned operator = (uint8 i) { _b = i; return _b; }
|
||||
inline unsigned operator &= (uint8 i) { _b &= i; return _b; }
|
||||
inline unsigned operator |= (uint8 i) { _b |= i; return _b; }
|
||||
inline unsigned operator ^= (uint8 i) { _b ^= i; return _b; }
|
||||
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 {
|
||||
@@ -38,10 +37,7 @@ public:
|
||||
uint16 pc;
|
||||
union {
|
||||
uint16 ya;
|
||||
//not endian-safe
|
||||
struct {
|
||||
uint8 a, y;
|
||||
};
|
||||
struct { uint8 order_lsb2(a, y); };
|
||||
};
|
||||
uint8 x, sp;
|
||||
APURegFlags p;
|
||||
|
||||
+7
-240
@@ -1,216 +1,11 @@
|
||||
#include "../../base.h"
|
||||
|
||||
#include "bapu_op_fn.cpp"
|
||||
#include "bapu_op_mov.cpp"
|
||||
#include "bapu_op_pc.cpp"
|
||||
#include "bapu_op_read.cpp"
|
||||
#include "bapu_op_rmw.cpp"
|
||||
#include "bapu_op_misc.cpp"
|
||||
|
||||
#include "bapu_exec.cpp"
|
||||
|
||||
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 = dsp_regs[status.dsp_addr & 0x7f];
|
||||
break;
|
||||
case 0xf4: //CPUIO0
|
||||
case 0xf5: //CPUIO1
|
||||
case 0xf6: //CPUIO2
|
||||
case 0xf7: //CPUIO3
|
||||
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];
|
||||
}
|
||||
}
|
||||
snes->notify(SNES::SPCRAM_READ, addr, r);
|
||||
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) {
|
||||
cpu->port_write(2, 0x00);
|
||||
cpu->port_write(3, 0x00);
|
||||
}
|
||||
if(value & 0x10) {
|
||||
cpu->port_write(0, 0x00);
|
||||
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) {
|
||||
dsp_regs[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;
|
||||
}
|
||||
snes->notify(SNES::SPCRAM_WRITE, addr, value);
|
||||
}
|
||||
|
||||
uint8 bAPU::port_read(uint8 port) {
|
||||
return spcram[0xf4 + (port & 3)];
|
||||
}
|
||||
|
||||
void bAPU::port_write(uint8 port, uint8 value) {
|
||||
spcram[0xf4 + (port & 0x03)] = value;
|
||||
}
|
||||
|
||||
void bAPU::add_cycles(int cycles) {
|
||||
status.cycles_executed += cycles;
|
||||
|
||||
t0.add_cycles(cycles);
|
||||
t1.add_cycles(cycles);
|
||||
t2.add_cycles(cycles);
|
||||
}
|
||||
|
||||
uint32 bAPU::cycles_executed() {
|
||||
uint32 r = status.cycles_executed;
|
||||
status.cycles_executed = 0;
|
||||
return (r << 4) + (r << 3);
|
||||
}
|
||||
|
||||
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--;
|
||||
}
|
||||
#include "core/core.cpp"
|
||||
#include "memory/memory.cpp"
|
||||
#include "timing/timing.cpp"
|
||||
|
||||
void bAPU::run() {
|
||||
exec_cycle();
|
||||
exec();
|
||||
}
|
||||
|
||||
void bAPU::power() {
|
||||
@@ -226,7 +21,8 @@ void bAPU::reset() {
|
||||
regs.sp = 0xef;
|
||||
regs.p = 0x02;
|
||||
|
||||
status.cycle_pos = 0;
|
||||
status.cycle_pos = 0;
|
||||
status.clocks_executed = 0;
|
||||
|
||||
//$f1
|
||||
status.iplrom_enabled = true;
|
||||
@@ -246,16 +42,11 @@ void bAPU::reset() {
|
||||
t0.stage3_ticks = 0;
|
||||
t1.stage3_ticks = 0;
|
||||
t2.stage3_ticks = 0;
|
||||
|
||||
memset(dsp_regs, 0, 128);
|
||||
}
|
||||
|
||||
bAPU::bAPU() {
|
||||
init_op_table();
|
||||
|
||||
spcram = (uint8*)malloc(65536);
|
||||
memcpy(iplrom, spc700_iplrom, 64);
|
||||
|
||||
t0.cycle_frequency = 128; //1.024mhz / 8khz = 128
|
||||
t1.cycle_frequency = 128; //1.024mhz / 8khz = 128
|
||||
t2.cycle_frequency = 16; //1.024mhz / 64khz = 16
|
||||
@@ -266,28 +57,4 @@ bAPU::bAPU() {
|
||||
t2.target = 0;
|
||||
}
|
||||
|
||||
bAPU::~bAPU() {
|
||||
if(spcram)free(spcram);
|
||||
}
|
||||
|
||||
//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 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;
|
||||
}
|
||||
bAPU::~bAPU() {}
|
||||
+8
-63
@@ -1,78 +1,23 @@
|
||||
class bAPU;
|
||||
|
||||
class bAPUTimer {
|
||||
public:
|
||||
uint8 cycle_frequency, target;
|
||||
uint8 stage1_ticks, stage2_ticks, stage3_ticks;
|
||||
bool enabled;
|
||||
inline void add_cycles(int cycles);
|
||||
};
|
||||
|
||||
class bAPU : public APU {
|
||||
private:
|
||||
typedef void (bAPU::*op)();
|
||||
op optbl[256];
|
||||
|
||||
public:
|
||||
uint16 dp, sp, rd, wr, bit, ya;
|
||||
#include "core/core.h"
|
||||
#include "memory/memory.h"
|
||||
#include "timing/timing.h"
|
||||
|
||||
struct {
|
||||
uint8 cycle_pos, opcode;
|
||||
uint32 cycles_executed;
|
||||
uint32 clocks_executed;
|
||||
|
||||
//$f1
|
||||
bool iplrom_enabled;
|
||||
|
||||
//$f2
|
||||
uint8 dsp_addr;
|
||||
}status;
|
||||
} status;
|
||||
|
||||
bAPUTimer t0, t1, t2;
|
||||
|
||||
uint8 *spcram, iplrom[64], dsp_regs[128];
|
||||
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 void run();
|
||||
inline uint32 cycles_executed();
|
||||
inline void power();
|
||||
inline void reset();
|
||||
|
||||
inline void add_cycles(int cycles);
|
||||
|
||||
enum {
|
||||
OPMODE_ADDR = 0,
|
||||
OPMODE_DP = 1
|
||||
};
|
||||
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);
|
||||
|
||||
inline void exec_cycle();
|
||||
inline void init_op_table();
|
||||
|
||||
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);
|
||||
#include "bapu_op.h"
|
||||
inline void run();
|
||||
inline void power();
|
||||
inline void reset();
|
||||
|
||||
bAPU();
|
||||
~bAPU();
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
void bAPU::exec_cycle() {
|
||||
uint8 op;
|
||||
if(status.cycle_pos == 0) {
|
||||
op = spcram_read(regs.pc);
|
||||
snes->notify(SNES::APU_EXEC_OPCODE_BEGIN);
|
||||
status.opcode = op_read();
|
||||
status.cycle_pos = 1;
|
||||
add_cycles(1);
|
||||
} else {
|
||||
(this->*optbl[status.opcode])();
|
||||
add_cycles(1);
|
||||
if(status.cycle_pos == 0) {
|
||||
snes->notify(SNES::APU_EXEC_OPCODE_END);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::init_op_table() {
|
||||
#include "bapu_optable.cpp"
|
||||
}
|
||||
Binary file not shown.
@@ -1,3 +0,0 @@
|
||||
cl /ML /O2 bapugen.cpp
|
||||
@pause
|
||||
@del *.obj
|
||||
@@ -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
|
||||
File renamed without changes.
@@ -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"
|
||||
File renamed without changes.
File renamed without changes.
@@ -1,55 +1,55 @@
|
||||
void bAPU::op_nop() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_sleep() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
regs.pc--;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_stop() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
regs.pc--;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_xcn() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
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;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_daa() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
if(regs.p.c || (regs.a) > 0x99) {
|
||||
regs.a += 0x60;
|
||||
regs.p.c = 1;
|
||||
@@ -60,15 +60,15 @@ void bAPU::op_daa() {
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_das() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
if(!regs.p.c || (regs.a) > 0x99) {
|
||||
regs.a -= 0x60;
|
||||
regs.p.c = 0;
|
||||
@@ -79,512 +79,512 @@ void bAPU::op_das() {
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clrc() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.p.c = 0;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clrp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.p.p = 0;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_setc() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.p.c = 1;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_setp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.p.p = 1;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clrv() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.p.v = 0;
|
||||
regs.p.h = 0;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_notc() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
regs.p.c ^= 1;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_ei() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
regs.p.i = 1;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_di() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
regs.p.i = 0;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_set0_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= 0x01;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clr0_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd &= ~0x01;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_set1_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= 0x02;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clr1_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd &= ~0x02;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_set2_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= 0x04;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clr2_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd &= ~0x04;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_set3_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= 0x08;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clr3_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd &= ~0x08;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_set4_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= 0x10;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clr4_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd &= ~0x10;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_set5_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= 0x20;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clr5_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd &= ~0x20;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_set6_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= 0x40;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clr6_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd &= ~0x40;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_set7_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= 0x80;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_clr7_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd &= ~0x80;
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_tset_addr_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
regs.p.n = !!((rd & regs.a) & 0x80);
|
||||
regs.p.z = ((rd & regs.a) == 0);
|
||||
rd |= regs.a;
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 5: {
|
||||
op_write(OPMODE_ADDR, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_tclr_addr_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
regs.p.n = !!((rd & regs.a) & 0x80);
|
||||
regs.p.z = ((rd & regs.a) == 0);
|
||||
rd &=~ regs.a;
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 5: {
|
||||
op_write(OPMODE_ADDR, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_push_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
stack_write(regs.a);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_push_x() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
stack_write(regs.x);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_push_y() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
stack_write(regs.y);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_push_p() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
stack_write(regs.p);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_pop_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
regs.a = stack_read();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_pop_x() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
regs.x = stack_read();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_pop_y() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
regs.y = stack_read();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_pop_p() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
regs.p = stack_read();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} 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:
|
||||
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;
|
||||
@@ -592,33 +592,33 @@ void bAPU::op_mul_ya() {
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} 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:
|
||||
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);
|
||||
@@ -637,7 +637,7 @@ void bAPU::op_div_ya_x() {
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,16 @@ 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),
|
||||
mov_sp_x(0xbd, sp, x) {
|
||||
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,710 +1,708 @@
|
||||
void bAPU::op_mov_a_x() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.a = regs.x;
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_y() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.a = regs.y;
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_x_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.x = regs.a;
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_y_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.y = regs.a;
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_x_sp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.x = regs.sp;
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_sp_x() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.sp = regs.x;
|
||||
regs.p.n = !!(regs.sp & 0x80);
|
||||
regs.p.z = (regs.sp == 0);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_const() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.a = op_read();
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_x_const() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.x = op_read();
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_y_const() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.y = op_read();
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_ix() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
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;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_ixinc() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
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;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} 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;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_x_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} 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;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_y_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} 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;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_dpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
} 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;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_x_dpy() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
} 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;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_y_dpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
} 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;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
sp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
} 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;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_x_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
sp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
} 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;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_y_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
sp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
} 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;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_addrx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
sp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
} 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;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_addry() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
sp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
} 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;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_idpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read() + regs.x;
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
sp = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
sp |= op_read(OPMODE_DP, dp + 1) << 8;
|
||||
break;
|
||||
case 5:
|
||||
} 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;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_a_idpy() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
sp = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
sp |= op_read(OPMODE_DP, dp + 1) << 8;
|
||||
break;
|
||||
case 5:
|
||||
} 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;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_dp_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_DP, sp);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_dp_const() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
rd = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_ix_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
op_write(OPMODE_DP, regs.x, regs.a);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_ixinc_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
case 1: {
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
op_write(OPMODE_DP, regs.x++, regs.a);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_dp_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
op_write(OPMODE_DP, dp, regs.a);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_dp_x() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
op_write(OPMODE_DP, dp, regs.x);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_dp_y() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
op_write(OPMODE_DP, dp, regs.y);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_dpx_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_DP, dp + regs.x, regs.a);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_dpy_x() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_DP, dp + regs.y, regs.x);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_dpx_y() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_DP, dp + regs.x, regs.y);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_addr_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_ADDR, dp, regs.a);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_addr_x() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_ADDR, dp, regs.x);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_addr_y() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_ADDR, dp, regs.y);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_addrx_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
} break;
|
||||
case 5: {
|
||||
op_write(OPMODE_ADDR, dp + regs.x, regs.a);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_addry_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 3: {
|
||||
} break;
|
||||
case 4: {
|
||||
} break;
|
||||
case 5: {
|
||||
op_write(OPMODE_ADDR, dp + regs.y, regs.a);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_idpx_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
sp = op_read() + regs.x;
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
dp = op_read(OPMODE_DP, sp);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
dp |= op_read(OPMODE_DP, sp + 1) << 8;
|
||||
break;
|
||||
case 5:
|
||||
break;
|
||||
case 6:
|
||||
} break;
|
||||
case 5: {
|
||||
} break;
|
||||
case 6: {
|
||||
op_write(OPMODE_ADDR, dp, regs.a);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov_idpy_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
dp = op_read(OPMODE_DP, sp);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
dp |= op_read(OPMODE_DP, sp + 1) << 8;
|
||||
break;
|
||||
case 5:
|
||||
break;
|
||||
case 6:
|
||||
} break;
|
||||
case 5: {
|
||||
} break;
|
||||
case 6: {
|
||||
op_write(OPMODE_ADDR, dp + regs.y, regs.a);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_movw_ya_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
regs.a = op_read(OPMODE_DP, sp);
|
||||
break;
|
||||
case 4:
|
||||
} 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;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_movw_dp_ya() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
op_write(OPMODE_DP, dp, regs.a);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_DP, dp + 1, regs.y);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov1_c_bit() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
sp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
} 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;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_mov1_bit_c() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
} 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:
|
||||
} break;
|
||||
case 4: {
|
||||
op_write(OPMODE_ADDR, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,16 +37,25 @@ bbc7(0xf3, 0x80, ==) {
|
||||
6:regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
cbne_dp(0x2e, 0),
|
||||
cbne_dpx(0xde, regs.x) {
|
||||
cbne_dp(0x2e) {
|
||||
1:dp = op_read();
|
||||
2:rd = op_read();
|
||||
3:sp = op_read(OPMODE_DP, dp + $1);
|
||||
3:sp = op_read(OPMODE_DP, dp);
|
||||
4:if(regs.a == sp)end;
|
||||
5:
|
||||
6:regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
cbne_dpx(0xde) {
|
||||
1:dp = op_read();
|
||||
2:rd = op_read();
|
||||
3:
|
||||
4:sp = op_read(OPMODE_DP, dp + regs.x);
|
||||
5:if(regs.a == sp)end;
|
||||
6:
|
||||
7:regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
dbnz_dp(0x6e) {
|
||||
1:dp = op_read();
|
||||
2:rd = op_read();
|
||||
File diff suppressed because it is too large.
Load diff
File renamed without changes.
File diff suppressed because it is too large.
Load diff
File renamed without changes.
@@ -1,452 +1,452 @@
|
||||
void bAPU::op_inc_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.a = op_inc(regs.a);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_inc_x() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.x = op_inc(regs.x);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_inc_y() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.y = op_inc(regs.y);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_dec_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.a = op_dec(regs.a);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_dec_x() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.x = op_dec(regs.x);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_dec_y() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.y = op_dec(regs.y);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_asl_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.a = op_asl(regs.a);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_lsr_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.a = op_lsr(regs.a);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_rol_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.a = op_rol(regs.a);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_ror_a() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
regs.a = op_ror(regs.a);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_inc_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_inc(rd);
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_dec_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_dec(rd);
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_asl_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_asl(rd);
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_lsr_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_lsr(rd);
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_rol_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_rol(rd);
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_ror_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_ror(rd);
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_inc_dpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_DP, dp + regs.x);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_inc(rd);
|
||||
op_write(OPMODE_DP, dp + regs.x, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_dec_dpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_DP, dp + regs.x);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_dec(rd);
|
||||
op_write(OPMODE_DP, dp + regs.x, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_asl_dpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_DP, dp + regs.x);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_asl(rd);
|
||||
op_write(OPMODE_DP, dp + regs.x, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_lsr_dpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_DP, dp + regs.x);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_lsr(rd);
|
||||
op_write(OPMODE_DP, dp + regs.x, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_rol_dpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_DP, dp + regs.x);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_rol(rd);
|
||||
op_write(OPMODE_DP, dp + regs.x, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_ror_dpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 2: {
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_DP, dp + regs.x);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_ror(rd);
|
||||
op_write(OPMODE_DP, dp + regs.x, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_inc_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_inc(rd);
|
||||
op_write(OPMODE_ADDR, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_dec_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_dec(rd);
|
||||
op_write(OPMODE_ADDR, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_asl_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_asl(rd);
|
||||
op_write(OPMODE_ADDR, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_lsr_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_lsr(rd);
|
||||
op_write(OPMODE_ADDR, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_rol_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_rol(rd);
|
||||
op_write(OPMODE_ADDR, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_ror_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
dp |= op_read() << 8;
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd = op_read(OPMODE_ADDR, dp);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_ror(rd);
|
||||
op_write(OPMODE_ADDR, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_incw_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= op_read(OPMODE_DP, dp + 1) << 8;
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_incw(rd);
|
||||
op_write(OPMODE_DP, dp + 1, rd >> 8);
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 5: {
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bAPU::op_decw_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
rd = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
rd |= op_read(OPMODE_DP, dp + 1) << 8;
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
rd = op_decw(rd);
|
||||
op_write(OPMODE_DP, dp + 1, rd >> 8);
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 5: {
|
||||
op_write(OPMODE_DP, dp, rd);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,11 @@ int16 r = x + y + regs.p.c;
|
||||
}
|
||||
|
||||
uint16 bAPU::op_addw(uint16 x, uint16 y) {
|
||||
int32 r = x + y;
|
||||
regs.p.n = !!(r & 0x8000);
|
||||
regs.p.v = !!(~(x ^ y) & (y ^ (uint16)r) & 0x8000);
|
||||
regs.p.h = !!((x ^ y ^ (uint16)r) & 0x10);
|
||||
int16 r;
|
||||
regs.p.c = 0;
|
||||
r = op_adc(x, y);
|
||||
r |= op_adc(x >> 8, y >> 8) << 8;
|
||||
regs.p.z = ((uint16)r == 0);
|
||||
regs.p.c = (r > 0xffff);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -66,12 +65,11 @@ int16 r = x - y - !regs.p.c;
|
||||
}
|
||||
|
||||
uint16 bAPU::op_subw(uint16 x, uint16 y) {
|
||||
int32 r = x - y;
|
||||
regs.p.n = !!(r & 0x8000);
|
||||
regs.p.v = !!((x ^ y) & (x ^ (uint16)r) & 0x8000);
|
||||
regs.p.h = !((x ^ y ^ (uint16)r) & 0x10);
|
||||
int16 r;
|
||||
regs.p.c = 1;
|
||||
r = op_sbc(x, y);
|
||||
r |= op_sbc(x >> 8, y >> 8) << 8;
|
||||
regs.p.z = ((uint16)r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
File renamed without changes.
@@ -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();
|
||||
@@ -1,171 +0,0 @@
|
||||
#include "../../base.h"
|
||||
|
||||
uint8 bAPUSkip::spcram_read (uint16 addr) { return 0xff; }
|
||||
void bAPUSkip::spcram_write(uint16 addr, uint8 value) {}
|
||||
|
||||
/*
|
||||
This routine is very serious. It will eat holes through
|
||||
the ROM to skip APU test conditions. Or in other words,
|
||||
it will disable and/or force branches when neccesary.
|
||||
|
||||
It can very easily break or corrupt a game and prevent it
|
||||
from being playable until the ROM is reloaded (ROM writes
|
||||
are only performed in memory, of course).
|
||||
|
||||
However, this kind of brute force approach is required to
|
||||
get many games playable without proper SPC700 emulation.
|
||||
*/
|
||||
uint8 bAPUSkip::port_read(uint8 port) {
|
||||
port &= 3;
|
||||
_apu_port *p = &apu_port[port];
|
||||
int i, x, y, z, t;
|
||||
uint32 addr;
|
||||
|
||||
addr = cpu->regs.pc.d;
|
||||
p->read_addr[p->read_pos & 31] = addr;
|
||||
|
||||
//- lda $214x
|
||||
// cmp $214x
|
||||
// bne -
|
||||
// cmp ???
|
||||
// beq/bne -
|
||||
__test1:
|
||||
//look for an lda/cmp read pattern
|
||||
if(addr == p->read_addr[(p->read_pos - 1) & 31])goto __test2;
|
||||
if(addr != p->read_addr[(p->read_pos - 2) & 31])goto __test2;
|
||||
if(addr == p->read_addr[(p->read_pos - 3) & 31])goto __test2;
|
||||
if(addr != p->read_addr[(p->read_pos - 4) & 31])goto __test2;
|
||||
if(p->read_addr[(p->read_pos - 1) & 31] != p->read_addr[(p->read_pos - 3) & 31])goto __test2;
|
||||
//try and find compare opcode
|
||||
for(i=0;i<24;i++) {
|
||||
x = mem_bus->read(addr + i);
|
||||
if(x == OP_CMP_CONST || x == OP_CPX_CONST || x == OP_CPY_CONST)break;
|
||||
if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) break;
|
||||
if(x == OP_CMP_LONG)break;
|
||||
}
|
||||
if(i == 24)goto __test2;
|
||||
//seek to next opcode
|
||||
if(x == OP_CMP_CONST) {
|
||||
i += (cpu->regs.p.m)?2:3;
|
||||
} else if(x == OP_CPX_CONST || x == OP_CPY_CONST) {
|
||||
i += (cpu->regs.p.x)?2:3;
|
||||
} else if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) {
|
||||
i += 3;
|
||||
} else { //(x == OP_CMP_LONG) {
|
||||
i += 4;
|
||||
}
|
||||
x = mem_bus->read(addr + i);
|
||||
if(x == OP_BNE) {
|
||||
mem_bus->cart->write_protect(false);
|
||||
mem_bus->write(addr + i, OP_NOP);
|
||||
mem_bus->write(addr + i + 1, OP_NOP);
|
||||
mem_bus->cart->write_protect(true);
|
||||
} else if(x == OP_BEQ) {
|
||||
mem_bus->cart->write_protect(false);
|
||||
mem_bus->write(addr + i, OP_BRA);
|
||||
mem_bus->cart->write_protect(true);
|
||||
} else goto __test2;
|
||||
goto __pass;
|
||||
|
||||
//- lda $214x
|
||||
// cmp ???
|
||||
// beq/bne -
|
||||
__test2:
|
||||
//look for a repeated read pattern
|
||||
if(addr != p->read_addr[(p->read_pos - 1) & 31])goto __test3;
|
||||
if(addr != p->read_addr[(p->read_pos - 2) & 31])goto __test3;
|
||||
if(addr != p->read_addr[(p->read_pos - 3) & 31])goto __test3;
|
||||
if(addr != p->read_addr[(p->read_pos - 4) & 31])goto __test3;
|
||||
if(addr != p->read_addr[(p->read_pos - 5) & 31])goto __test3;
|
||||
if(addr != p->read_addr[(p->read_pos - 6) & 31])goto __test3;
|
||||
if(addr != p->read_addr[(p->read_pos - 7) & 31])goto __test3;
|
||||
if(addr != p->read_addr[(p->read_pos - 8) & 31])goto __test3;
|
||||
//try and find compare opcode
|
||||
for(i=0;i<24;i++) {
|
||||
x = mem_bus->read(addr + i);
|
||||
if(x == OP_CMP_CONST || x == OP_CPX_CONST || x == OP_CPY_CONST)break;
|
||||
if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) break;
|
||||
if(x == OP_CMP_LONG)break;
|
||||
}
|
||||
if(i == 24)goto __test3;
|
||||
//seek to next opcode
|
||||
if(x == OP_CMP_CONST) {
|
||||
i += (cpu->regs.p.m)?2:3;
|
||||
} else if(x == OP_CPX_CONST || x == OP_CPY_CONST) {
|
||||
i += (cpu->regs.p.x)?2:3;
|
||||
} else if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) {
|
||||
i += 3;
|
||||
} else if(x == OP_CMP_LONG) {
|
||||
i += 4;
|
||||
}
|
||||
x = mem_bus->read(addr + i);
|
||||
if(x == OP_BNE) {
|
||||
mem_bus->cart->write_protect(false);
|
||||
mem_bus->write(addr + i, OP_NOP);
|
||||
mem_bus->write(addr + i + 1, OP_NOP);
|
||||
mem_bus->cart->write_protect(true);
|
||||
} else if(x == OP_BEQ) {
|
||||
mem_bus->cart->write_protect(false);
|
||||
mem_bus->write(addr + i, OP_BRA);
|
||||
mem_bus->cart->write_protect(true);
|
||||
} else goto __test3;
|
||||
goto __pass;
|
||||
|
||||
//fallback
|
||||
__test3:
|
||||
if(p->pos < 4) {
|
||||
if(!(port & 1)) {
|
||||
p->value = cpu->regs.a.l;
|
||||
} else {
|
||||
p->value = cpu->regs.a.h;
|
||||
}
|
||||
} else if(p->pos < 8) {
|
||||
if(!(port & 1)) {
|
||||
p->value = cpu->regs.x.l;
|
||||
} else {
|
||||
p->value = cpu->regs.x.h;
|
||||
}
|
||||
} else if(p->pos < 12) {
|
||||
if(!(port & 1)) {
|
||||
p->value = cpu->regs.y.l;
|
||||
} else {
|
||||
p->value = cpu->regs.y.h;
|
||||
}
|
||||
} else if(p->pos < 16) {
|
||||
p->value = rand();
|
||||
}
|
||||
if(++p->pos == 16)p->pos = 0;
|
||||
|
||||
__pass:
|
||||
p->read_pos++;
|
||||
p->read_pos &= 31;
|
||||
return p->value;
|
||||
}
|
||||
|
||||
void bAPUSkip::port_write(uint8 port, uint8 value) {
|
||||
port &= 3;
|
||||
apu_port[port].value = value;
|
||||
}
|
||||
|
||||
void bAPUSkip::run() {
|
||||
snes->notify(SNES::APU_EXEC_OPCODE_BEGIN);
|
||||
snes->notify(SNES::APU_EXEC_OPCODE_END);
|
||||
}
|
||||
|
||||
void bAPUSkip::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void bAPUSkip::reset() {
|
||||
regs.a = 0x00;
|
||||
regs.x = 0x00;
|
||||
regs.y = 0x00;
|
||||
regs.sp = 0x00;
|
||||
regs.p = 0x02;
|
||||
regs.pc = 0xffc0;
|
||||
|
||||
memset(&apu_port[0], 0, sizeof(_apu_port));
|
||||
memset(&apu_port[1], 0, sizeof(_apu_port));
|
||||
memset(&apu_port[2], 0, sizeof(_apu_port));
|
||||
memset(&apu_port[3], 0, sizeof(_apu_port));
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
class bAPUSkip : public APU {
|
||||
public:
|
||||
|
||||
struct _apu_port {
|
||||
uint8 value;
|
||||
uint8 step, pos;
|
||||
uint32 read_addr[32], read_pos;
|
||||
}apu_port[4];
|
||||
|
||||
enum {
|
||||
OP_CMP_CONST = 0xc9,
|
||||
OP_CPX_CONST = 0xe0,
|
||||
OP_CPY_CONST = 0xc0,
|
||||
OP_CMP_ADDR = 0xcd,
|
||||
OP_CPX_ADDR = 0xec,
|
||||
OP_CPY_ADDR = 0xcc,
|
||||
OP_CMP_LONG = 0xcf,
|
||||
OP_BNE = 0xd0,
|
||||
OP_BEQ = 0xf0,
|
||||
OP_BRA = 0x80,
|
||||
OP_NOP = 0xea
|
||||
};
|
||||
|
||||
uint8 spcram_read (uint16 addr);
|
||||
void spcram_write(uint16 addr, uint8 value);
|
||||
uint8 port_read (uint8 port);
|
||||
void port_write (uint8 port, uint8 value);
|
||||
|
||||
void run();
|
||||
uint32 cycles_executed() { return 12 * 24; }
|
||||
void power();
|
||||
void reset();
|
||||
};
|
||||
+12
-1
@@ -1,12 +1,23 @@
|
||||
//virtual function, see src/cpu/dcpu.cpp
|
||||
//for explanation of this function
|
||||
bool APU::in_opcode() { return false; }
|
||||
|
||||
uint16 APU::__relb(int8 offset, int op_len) {
|
||||
uint16 pc = regs.pc + op_len;
|
||||
return pc + offset;
|
||||
}
|
||||
|
||||
void APU::disassemble_opcode(char *output) {
|
||||
char *s = output, t[512];
|
||||
char *s, t[512];
|
||||
uint8 op, op0, op1;
|
||||
uint16 opw, opdp0, opdp1;
|
||||
s = output;
|
||||
|
||||
if(in_opcode() == true) {
|
||||
strcpy(s, "..???? <APU within opcode>");
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(s, "..%0.4x ", regs.pc);
|
||||
|
||||
op = spcram_read(regs.pc);
|
||||
|
||||
+1
-8
@@ -3,12 +3,8 @@
|
||||
//allow writing to the IPLROM, all writes are
|
||||
//instead mapped to the extended SPC700 RAM region,
|
||||
//accessible when $f1 bit 7 is clear.
|
||||
//If you use this buffer directly, make sure not
|
||||
//to write to it, as this will break other APU
|
||||
//implementations that attempt to use this buffer.
|
||||
|
||||
#ifdef _APU_IPLROM
|
||||
const uint8 spc700_iplrom[64] = {
|
||||
const uint8 APU::iplrom[64] = {
|
||||
/*ffc0*/ 0xcd, 0xef, //mov x,#$ef
|
||||
/*ffc2*/ 0xbd, //mov sp,x
|
||||
/*ffc3*/ 0xe8, 0x00, //mov a,#$00
|
||||
@@ -43,6 +39,3 @@ const uint8 spc700_iplrom[64] = {
|
||||
/*fffb*/ 0x1f, 0x00, 0x00, //jmp ($0000+x)
|
||||
/*fffe*/ 0xc0, 0xff //---reset vector location ($ffc0)
|
||||
};
|
||||
#else
|
||||
extern const uint8 spc700_iplrom[64];
|
||||
#endif
|
||||
@@ -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();
|
||||
+62
-11
@@ -1,17 +1,68 @@
|
||||
#include <time.h>
|
||||
#include "lib/libbase.h"
|
||||
#define BSNES_VERSION "0.017"
|
||||
#define BSNES_TITLE "bsnes v" BSNES_VERSION
|
||||
|
||||
//structs
|
||||
typedef struct {
|
||||
uint8 *data;
|
||||
uint32 size;
|
||||
}lfile;
|
||||
#define MEMCORE bMemBus
|
||||
#define CPUCORE sCPU
|
||||
#define APUCORE sAPU
|
||||
#define DSPCORE bDSP
|
||||
#define PPUCORE bPPU
|
||||
|
||||
//#define FAVOR_ACCURACY
|
||||
#define FAVOR_SPEED
|
||||
|
||||
//game genie + pro action replay code support (~1-3% speed hit)
|
||||
#define CHEAT_SYSTEM
|
||||
|
||||
//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;
|
||||
|
||||
};
|
||||
@@ -50,7 +50,9 @@
|
||||
whenever the RTC is set.
|
||||
*/
|
||||
|
||||
void bCPU::srtc_set_time() {
|
||||
#include "../../base.h"
|
||||
|
||||
void SRTC::set_time() {
|
||||
time_t rawtime;
|
||||
tm *t;
|
||||
::time(&rawtime);
|
||||
@@ -72,14 +74,49 @@ tm *t;
|
||||
srtc.data[12] = t->tm_wday;
|
||||
}
|
||||
|
||||
void bCPU::srtc_power() {
|
||||
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 bCPU::srtc_reset() {
|
||||
void SRTC::reset() {
|
||||
srtc.index = -1;
|
||||
srtc.mode = SRTC_READ;
|
||||
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
|
||||
@@ -87,72 +124,66 @@ void bCPU::srtc_reset() {
|
||||
//as reads will refresh the data array with the current system
|
||||
//time. The write method is only here for the sake of faux
|
||||
//emulation of the real hardware.
|
||||
void bCPU::srtc_write(uint8 data) {
|
||||
data &= 0x0f; //only the low four bits are used
|
||||
void SRTC::mmio_write(uint16 addr, uint8 data) {
|
||||
switch(addr) {
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(srtc.mode == SRTC_WRITE) {
|
||||
if(srtc.index >= 0 && srtc.index < MAX_SRTC_INDEX) {
|
||||
srtc.data[srtc.index++] = data;
|
||||
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
|
||||
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
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
uint8 bCPU::srtc_read() {
|
||||
if(srtc.mode == SRTC_READ) {
|
||||
if(srtc.index < 0) {
|
||||
srtc_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;
|
||||
}
|
||||
}
|
||||
SRTC::SRTC() {}
|
||||
@@ -1,10 +1,6 @@
|
||||
void srtc_set_time();
|
||||
void srtc_power();
|
||||
void srtc_reset();
|
||||
void srtc_write(uint8 data);
|
||||
uint8 srtc_read();
|
||||
|
||||
#define MAX_SRTC_INDEX 0x0c
|
||||
class SRTC : public MMIO {
|
||||
public:
|
||||
enum { MAX_SRTC_INDEX = 0x0c };
|
||||
|
||||
enum {
|
||||
SRTC_READ = 0,
|
||||
@@ -18,10 +14,6 @@ enum {
|
||||
SRTC_COMMAND_CLEAR = 4
|
||||
};
|
||||
|
||||
#define DAYTICKS (60*60*24)
|
||||
#define HOURTICKS (60*60)
|
||||
#define MINUTETICKS (60)
|
||||
|
||||
/******************************
|
||||
[srtc.data structure]
|
||||
Index Description Range
|
||||
@@ -38,11 +30,21 @@ Index Description Range
|
||||
9 Year ones 0-9
|
||||
10 Year tens 0-9
|
||||
11 Year hundreds 9-11 (9=19xx, 10=20xx, 11=21xx)
|
||||
12 Day of week 0-6 (0=Sunday, ...)
|
||||
12 Day of week 0-6 (0=Sunday, ...)
|
||||
******************************/
|
||||
|
||||
struct {
|
||||
int8 index;
|
||||
uint8 mode;
|
||||
uint8 data[MAX_SRTC_INDEX + 1];
|
||||
}srtc;
|
||||
int8 index;
|
||||
uint8 mode;
|
||||
uint8 data[MAX_SRTC_INDEX + 1];
|
||||
} srtc;
|
||||
void set_time();
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 mmio_read (uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
SRTC();
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
};
|
||||
+47
-306
@@ -1,186 +1,46 @@
|
||||
#include "../../base.h"
|
||||
|
||||
#include "srtc.cpp"
|
||||
|
||||
#include "bcpu_opfn.cpp"
|
||||
#include "bcpu_op_read.cpp"
|
||||
#include "bcpu_op_rmw.cpp"
|
||||
#include "bcpu_op_write.cpp"
|
||||
#include "bcpu_op_pc.cpp"
|
||||
#include "bcpu_op_misc.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_dma.cpp"
|
||||
#include "bcpu_int.cpp"
|
||||
|
||||
#include "bcpu_timing.cpp"
|
||||
|
||||
uint8 bCPU::pio_status() {
|
||||
return status.pio;
|
||||
}
|
||||
|
||||
/***********
|
||||
*** IRQ ***
|
||||
***********
|
||||
cycles:
|
||||
[1] pbr,pc ; io/opcode
|
||||
[2] pbr,pc ; io
|
||||
[3] 0,s ; pbr
|
||||
[4] 0,s-1 ; pch
|
||||
[5] 0,s-2 ; pcl
|
||||
[6] 0,s-3 ; p
|
||||
[7] 0,va ; aavl
|
||||
[8] 0,va+1 ; aavh
|
||||
*/
|
||||
void bCPU::irq(uint16 addr) {
|
||||
if(status.cpu_state == CPUSTATE_WAI) {
|
||||
status.cpu_state = CPUSTATE_RUN;
|
||||
regs.pc.w++;
|
||||
}
|
||||
|
||||
//GTE documentation is incorrect, first cycle
|
||||
//is a memory read fetch from PBR:PC
|
||||
add_cycles(mem_bus->speed(regs.pc.d));
|
||||
add_cycles(6);
|
||||
stack_write(regs.pc.b);
|
||||
stack_write(regs.pc.h);
|
||||
stack_write(regs.pc.l);
|
||||
stack_write(regs.p);
|
||||
rd.l = op_read(OPMODE_ADDR, addr);
|
||||
rd.h = op_read(OPMODE_ADDR, addr + 1);
|
||||
|
||||
regs.pc.b = 0x00;
|
||||
regs.pc.w = rd.w;
|
||||
regs.p.i = 1;
|
||||
regs.p.d = 0;
|
||||
|
||||
//let debugger know the new IRQ opcode address
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_END);
|
||||
}
|
||||
|
||||
bool bCPU::hdma_test() {
|
||||
if(status.hdma_triggered == false) {
|
||||
if(vcounter() < (overscan()?239:224) && hcounter() >= 278) {
|
||||
status.hdma_triggered = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bCPU::nmi_test() {
|
||||
if(vcounter() >= ((overscan()?239:224) + 1) && status.nmi_triggered == false) {
|
||||
if((vcounter() == ((overscan()?239:224) + 1) && hcycles() >= 12) || (vcounter() > ((overscan()?239:224) + 1))) {
|
||||
status.nmi_triggered = true;
|
||||
status.nmi_pin = 0;
|
||||
if(status.nmi_enabled == true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bCPU::irq_test() {
|
||||
int vpos, hpos;
|
||||
if(regs.p.i)return false; //no interrupt can occur with I flag set
|
||||
if(status.irq_pin == 0)return false; //same as above
|
||||
if(status.virq_enabled == false && status.hirq_enabled == false)return false;
|
||||
|
||||
//calculate V/H positions required for IRQ to trigger
|
||||
vpos = status.virq_pos;
|
||||
hpos = (status.hirq_enabled) ? status.hirq_pos : 0;
|
||||
|
||||
//positions that can never be latched
|
||||
if(vpos == 261 && hpos == 339 && interlace() == false)return false;
|
||||
if(vpos == 262 && interlace() == false)return false;
|
||||
if(vpos == 262 && hpos == 339)return false;
|
||||
if(vpos > 262)return false;
|
||||
if(hpos > 339)return false;
|
||||
|
||||
if(hpos == 0) {
|
||||
hpos = 24;
|
||||
} else {
|
||||
hpos <<= 2;
|
||||
hpos += 24; //30 - status.cycle_count;
|
||||
//it should be OK to use the current line cycles/frame lines,
|
||||
//as the IRQ will only trigger on the correct scanline anyway...
|
||||
if(hpos >= time.line_cycles) {
|
||||
hpos -= time.line_cycles;
|
||||
vpos++;
|
||||
if(vpos >= time.frame_lines) {
|
||||
vpos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(status.virq_enabled == true && vcounter() != vpos)return false;
|
||||
|
||||
if(hcycles() >= hpos && status.irq_pin == 1) {
|
||||
//dprintf("* vpos=%3d,hpos=%4d; v=%3d,h=%4d; lc=%d,virq=%3d,hirq=%3d",
|
||||
// vpos, hpos, vcounter(), hcycles(), status.cycle_count, status.virq_pos, status.hirq_pos);
|
||||
status.irq_triggered = true;
|
||||
status.irq_pin = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
uint8 bCPU::pio_status() { return status.pio; }
|
||||
|
||||
void bCPU::run() {
|
||||
switch(status.cpu_state) {
|
||||
case CPUSTATE_DMA:
|
||||
dma_run();
|
||||
break;
|
||||
case CPUSTATE_RUN:
|
||||
case CPUSTATE_WAI:
|
||||
if(nmi_test() == true) {
|
||||
irq(0xffea);
|
||||
break;
|
||||
if(run_state.hdma) {
|
||||
exec_hdma();
|
||||
return;
|
||||
}
|
||||
|
||||
if(run_state.dma) {
|
||||
exec_dma();
|
||||
return;
|
||||
}
|
||||
|
||||
if(status.cycle_pos == 0) { //interrupts only trigger on opcode edges
|
||||
if(run_state.irq && !run_state.stp) {
|
||||
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();
|
||||
}
|
||||
if(irq_test() == true) {
|
||||
irq(0xffee);
|
||||
break;
|
||||
}
|
||||
exec_opcode();
|
||||
break;
|
||||
case CPUSTATE_STP:
|
||||
exec_opcode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::scanline() {
|
||||
status.hdma_triggered = false;
|
||||
|
||||
if(vcounter() == 225 && status.auto_joypad_poll == true) {
|
||||
snes->poll_input();
|
||||
//When the SNES auto-polls the joypads, it writes 1, then 0 to
|
||||
//$4016, then reads from each 16 times to get the joypad state
|
||||
//information. As a result, the joypad read positions are set
|
||||
//to 16 after such a poll. Position 16 is the controller
|
||||
//connected status bit.
|
||||
status.joypad1_read_pos = 16;
|
||||
}
|
||||
|
||||
if(status.virq_enabled == false) {
|
||||
status.irq_pin = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::frame() {
|
||||
hdma_initialize();
|
||||
|
||||
status.nmi_triggered = false;
|
||||
status.nmi_pin = 1;
|
||||
status.r4210_read = false;
|
||||
|
||||
status.irq_triggered = false;
|
||||
status.irq_pin = 1;
|
||||
exec_cycle();
|
||||
}
|
||||
|
||||
void bCPU::power() {
|
||||
srtc_power();
|
||||
region = snes->region();
|
||||
|
||||
regs.a = regs.x = regs.y = 0x0000;
|
||||
regs.s = 0x01ff;
|
||||
@@ -188,12 +48,10 @@ void bCPU::power() {
|
||||
}
|
||||
|
||||
void bCPU::reset() {
|
||||
srtc_reset();
|
||||
|
||||
frame();
|
||||
|
||||
//reset vector location
|
||||
regs.pc = mem_bus->read(0xfffc) | (mem_bus->read(0xfffd) << 8);
|
||||
regs.pc.d = 0;
|
||||
regs.pc.l = r_mem->read(0xfffc);
|
||||
regs.pc.h = r_mem->read(0xfffd);
|
||||
|
||||
//registers are not fully reset by SNES
|
||||
regs.x.h = 0x00;
|
||||
@@ -203,154 +61,37 @@ void bCPU::reset() {
|
||||
regs.db = 0x00;
|
||||
regs.p = 0x34;
|
||||
regs.e = 1;
|
||||
regs.mdr = 0x00;
|
||||
|
||||
time_reset();
|
||||
mmio_reset();
|
||||
dma_reset();
|
||||
|
||||
status.cpu_state = CPUSTATE_RUN;
|
||||
run_state.hdma = false;
|
||||
run_state.dma = false;
|
||||
run_state.irq = false;
|
||||
run_state.wai = false;
|
||||
run_state.stp = false;
|
||||
|
||||
status.hdma_triggered = false;
|
||||
|
||||
status.nmi_triggered = false;
|
||||
status.nmi_pin = 1;
|
||||
status.r4210_read = false;
|
||||
|
||||
status.irq_triggered = false;
|
||||
status.irq_pin = 1;
|
||||
status.cycle_pos = 0;
|
||||
status.cycle_count = 0;
|
||||
status.cycles_executed = 0;
|
||||
|
||||
apu_port[0] = 0x00;
|
||||
apu_port[1] = 0x00;
|
||||
apu_port[2] = 0x00;
|
||||
apu_port[3] = 0x00;
|
||||
}
|
||||
|
||||
uint8 bCPU::port_read(uint8 port) {
|
||||
return apu_port[port & 3];
|
||||
}
|
||||
frame();
|
||||
|
||||
void bCPU::port_write(uint8 port, uint8 value) {
|
||||
apu_port[port & 3] = value;
|
||||
}
|
||||
|
||||
void bCPU::cpu_c2() {
|
||||
if(regs.d.l != 0x00) {
|
||||
status.cycle_count = 6;
|
||||
cycle_edge();
|
||||
add_cycles(6);
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::cpu_c4(uint16 x, uint16 y) {
|
||||
if(!regs.p.x && (x & 0xff00) != (y & 0xff00)) {
|
||||
status.cycle_count = 6;
|
||||
cycle_edge();
|
||||
add_cycles(6);
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::cpu_c6(uint16 addr) {
|
||||
if(regs.e && (regs.pc.w & 0xff00) != (addr & 0xff00)) {
|
||||
status.cycle_count = 6;
|
||||
cycle_edge();
|
||||
add_cycles(6);
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::cpu_io() {
|
||||
status.cycle_count = 6;
|
||||
cycle_edge();
|
||||
add_cycles(6);
|
||||
}
|
||||
|
||||
uint8 bCPU::mem_read(uint32 addr) {
|
||||
uint8 r;
|
||||
status.cycle_count = mem_bus->speed(addr);
|
||||
cycle_edge();
|
||||
add_cycles(2);
|
||||
r = mem_bus->read(addr);
|
||||
add_cycles(status.cycle_count - 2);
|
||||
return r;
|
||||
}
|
||||
|
||||
void bCPU::mem_write(uint32 addr, uint8 value) {
|
||||
status.cycle_count = mem_bus->speed(addr);
|
||||
cycle_edge();
|
||||
add_cycles(6);
|
||||
mem_bus->write(addr, value);
|
||||
add_cycles(status.cycle_count - 6);
|
||||
}
|
||||
|
||||
uint32 bCPU::op_addr(uint8 mode, uint32 addr) {
|
||||
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;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
uint8 bCPU::op_read() {
|
||||
uint8 r;
|
||||
r = mem_read(regs.pc.d);
|
||||
regs.pc.w++;
|
||||
return r;
|
||||
}
|
||||
|
||||
uint8 bCPU::op_read(uint8 mode, uint32 addr) {
|
||||
addr = op_addr(mode, addr);
|
||||
return mem_read(addr);
|
||||
}
|
||||
|
||||
void bCPU::op_write(uint8 mode, uint32 addr, uint8 value) {
|
||||
addr = op_addr(mode, addr);
|
||||
mem_write(addr, value);
|
||||
}
|
||||
|
||||
uint8 bCPU::stack_read() {
|
||||
if(regs.e) {
|
||||
regs.s.l++;
|
||||
} else {
|
||||
regs.s.w++;
|
||||
}
|
||||
return mem_read(regs.s);
|
||||
}
|
||||
|
||||
void bCPU::stack_write(uint8 value) {
|
||||
mem_write(regs.s, value);
|
||||
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() {
|
||||
time_init();
|
||||
mmio = new bCPUMMIO(this);
|
||||
|
||||
init_op_tables();
|
||||
}
|
||||
|
||||
bCPU::~bCPU() {
|
||||
delete(mmio);
|
||||
}
|
||||
bCPU::~bCPU() {}
|
||||
+58
-175
@@ -1,71 +1,57 @@
|
||||
class bCPU;
|
||||
|
||||
class bCPUMMIO : public MMIO {
|
||||
public:
|
||||
bCPU *cpu;
|
||||
inline uint8 read (uint32 addr);
|
||||
inline void write(uint32 addr, uint8 value);
|
||||
bCPUMMIO(bCPU *_cpu);
|
||||
};
|
||||
|
||||
class bCPU : public CPU {
|
||||
private:
|
||||
typedef void (bCPU::*op)();
|
||||
op optbl[256];
|
||||
|
||||
public:
|
||||
#include "srtc.h"
|
||||
#include "bcpu_timing.h"
|
||||
#include "core/core.h"
|
||||
#include "memory/memory.h"
|
||||
#include "dma/dma.h"
|
||||
#include "timing/timing.h"
|
||||
|
||||
uint8 apu_port[4];
|
||||
inline uint8 port_read (uint8 port);
|
||||
inline void port_write(uint8 port, uint8 value);
|
||||
enum { NTSC = 0, PAL = 1 };
|
||||
uint8 region;
|
||||
|
||||
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 {
|
||||
CPUSTATE_RUN = 0,
|
||||
CPUSTATE_WAI,
|
||||
CPUSTATE_STP,
|
||||
CPUSTATE_DMA
|
||||
};
|
||||
|
||||
enum {
|
||||
DMASTATE_STOP = 0,
|
||||
DMASTATE_INIT,
|
||||
DMASTATE_DMASYNC,
|
||||
DMASTATE_DMASYNC2,
|
||||
DMASTATE_DMASYNC3,
|
||||
DMASTATE_RUN,
|
||||
DMASTATE_CPUSYNC
|
||||
DMASTATE_CPUSYNC,
|
||||
|
||||
HDMASTATE_IDMASYNC,
|
||||
HDMASTATE_IDMASYNC2,
|
||||
HDMASTATE_IDMASYNC3,
|
||||
HDMASTATE_ICPUSYNC,
|
||||
|
||||
HDMASTATE_DMASYNC,
|
||||
HDMASTATE_DMASYNC2,
|
||||
HDMASTATE_DMASYNC3,
|
||||
HDMASTATE_RUN,
|
||||
HDMASTATE_CPUSYNC
|
||||
};
|
||||
|
||||
struct {
|
||||
uint8 cpu_state, cycle_count;
|
||||
bool hdma;
|
||||
bool dma;
|
||||
bool irq;
|
||||
bool stp;
|
||||
bool wai;
|
||||
} run_state;
|
||||
|
||||
uint8 dma_state;
|
||||
uint32 dma_cycle_count;
|
||||
bool hdma_triggered;
|
||||
struct {
|
||||
uint8 cycle_pos, cycle_count;
|
||||
uint8 opcode;
|
||||
uint32 cycles_executed;
|
||||
|
||||
bool nmi_triggered;
|
||||
bool nmi_pin;
|
||||
bool r4210_read;
|
||||
uint8 dma_state, hdma_state;
|
||||
uint32 dma_cycle_count, hdma_cycle_count;
|
||||
|
||||
bool irq_triggered;
|
||||
bool irq_pin;
|
||||
//$4207-$420a
|
||||
uint16 virq_trigger, hirq_trigger;
|
||||
|
||||
//$2181-$2183
|
||||
uint32 wram_addr;
|
||||
|
||||
//$4016
|
||||
uint8 joypad1_strobe_value;
|
||||
uint8 joypad1_read_pos;
|
||||
//$4016-$4017
|
||||
bool joypad_strobe_latch;
|
||||
uint8 joypad1_read_pos, joypad2_read_pos;
|
||||
|
||||
//$4200
|
||||
bool nmi_enabled;
|
||||
@@ -88,75 +74,25 @@ struct {
|
||||
//$4214-$4216
|
||||
uint16 r4214;
|
||||
uint16 r4216;
|
||||
}status;
|
||||
} status;
|
||||
|
||||
struct {
|
||||
//$420b
|
||||
bool active;
|
||||
//$420c
|
||||
bool hdma_active;
|
||||
//$43x0
|
||||
uint8 dmap;
|
||||
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;
|
||||
//$43x8-$43x9
|
||||
uint32 hdma_taddr;
|
||||
//$43xa
|
||||
uint8 hdma_line_counter;
|
||||
//$43xb/$43xf
|
||||
uint8 hdma_unknown;
|
||||
inline bool hdma_test();
|
||||
inline bool nmi_test();
|
||||
inline bool irq_test();
|
||||
|
||||
//hdma-specific
|
||||
bool hdma_first_line;
|
||||
bool hdma_repeat;
|
||||
uint32 hdma_itaddr;
|
||||
bool hdma_completed;
|
||||
}channel[8];
|
||||
inline uint8 pio_status();
|
||||
inline void run();
|
||||
inline uint32 clocks_executed();
|
||||
inline void power();
|
||||
inline void reset();
|
||||
|
||||
inline bool hdma_test();
|
||||
inline bool nmi_test();
|
||||
inline bool irq_test();
|
||||
inline void irq(uint16 addr);
|
||||
|
||||
inline uint8 pio_status();
|
||||
inline void run();
|
||||
inline void scanline();
|
||||
inline void frame();
|
||||
inline void power();
|
||||
inline void reset();
|
||||
|
||||
//dma commands
|
||||
inline void dma_run();
|
||||
inline void hdma_run();
|
||||
inline void hdma_initialize();
|
||||
inline uint16 dma_cputommio(uint8 i, uint8 index);
|
||||
inline uint16 dma_mmiotocpu(uint8 i, uint8 index);
|
||||
inline void dma_xfer_type0(uint8 i);
|
||||
inline void dma_xfer_type1(uint8 i);
|
||||
inline void dma_xfer_type2(uint8 i);
|
||||
inline void dma_xfer_type3(uint8 i);
|
||||
inline void dma_xfer_type4(uint8 i);
|
||||
inline void dma_xfer_type5(uint8 i);
|
||||
inline void hdma_write(uint8 i, uint8 l, uint8 x);
|
||||
inline void dma_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();
|
||||
@@ -167,6 +103,8 @@ struct {
|
||||
uint8 mmio_r4217();
|
||||
uint8 mmio_r4218();
|
||||
uint8 mmio_r4219();
|
||||
uint8 mmio_r421a();
|
||||
uint8 mmio_r421b();
|
||||
uint8 mmio_r43x0(uint8 i);
|
||||
uint8 mmio_r43x1(uint8 i);
|
||||
uint8 mmio_r43x2(uint8 i);
|
||||
@@ -211,71 +149,16 @@ struct {
|
||||
void mmio_w43xa(uint8 value, uint8 i);
|
||||
void mmio_w43xb(uint8 value, uint8 i);
|
||||
|
||||
enum { CYCLE_OPREAD = 0, CYCLE_READ, CYCLE_WRITE, CYCLE_IO };
|
||||
inline void exec_opcode();
|
||||
inline void cycle_edge();
|
||||
uint8 mmio_read (uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
//cpu extra-cycle conditions
|
||||
inline void cpu_c2();
|
||||
inline void cpu_c4(uint16 x, uint16 y);
|
||||
inline void cpu_c6(uint16 addr);
|
||||
inline void cpu_io();
|
||||
|
||||
inline uint8 mem_read (uint32 addr);
|
||||
inline void mem_write(uint32 addr, uint8 value);
|
||||
inline uint32 op_addr(uint8 mode, uint32 addr);
|
||||
inline uint8 op_read();
|
||||
inline uint8 op_read(uint8 mode, uint32 addr);
|
||||
inline void op_write(uint8 mode, uint32 addr, uint8 value);
|
||||
inline uint8 stack_read();
|
||||
inline void stack_write(uint8 value);
|
||||
|
||||
//opcode functions
|
||||
inline void init_op_tables();
|
||||
|
||||
//op_read
|
||||
inline void op_adc_b();
|
||||
inline void op_adc_w();
|
||||
inline void op_and_b();
|
||||
inline void op_and_w();
|
||||
inline void op_bit_b();
|
||||
inline void op_bit_w();
|
||||
inline void op_cmp_b();
|
||||
inline void op_cmp_w();
|
||||
inline void op_cpx_b();
|
||||
inline void op_cpx_w();
|
||||
inline void op_cpy_b();
|
||||
inline void op_cpy_w();
|
||||
inline void op_eor_b();
|
||||
inline void op_eor_w();
|
||||
inline void op_lda_b();
|
||||
inline void op_lda_w();
|
||||
inline void op_ldx_b();
|
||||
inline void op_ldx_w();
|
||||
inline void op_ldy_b();
|
||||
inline void op_ldy_w();
|
||||
inline void op_ora_b();
|
||||
inline void op_ora_w();
|
||||
inline void op_sbc_b();
|
||||
inline void op_sbc_w();
|
||||
//op_rmw
|
||||
inline void op_inc_b();
|
||||
inline void op_inc_w();
|
||||
inline void op_dec_b();
|
||||
inline void op_dec_w();
|
||||
inline void op_asl_b();
|
||||
inline void op_asl_w();
|
||||
inline void op_lsr_b();
|
||||
inline void op_lsr_w();
|
||||
inline void op_rol_b();
|
||||
inline void op_rol_w();
|
||||
inline void op_ror_b();
|
||||
inline void op_ror_w();
|
||||
inline void op_trb_b();
|
||||
inline void op_trb_w();
|
||||
inline void op_tsb_b();
|
||||
inline void op_tsb_w();
|
||||
#include "bcpu_op.h"
|
||||
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();
|
||||
|
||||
@@ -1,241 +0,0 @@
|
||||
uint16 bCPU::dma_cputommio(uint8 i, uint8 index) {
|
||||
uint8 x;
|
||||
x = mem_bus->read(channel[i].srcaddr);
|
||||
mem_bus->write(0x2100 | ((channel[i].destaddr + index) & 0xff), x);
|
||||
if(channel[i].fixedxfer == false) {
|
||||
channel[i].srcaddr = (channel[i].srcaddr & 0xff0000) + ((channel[i].srcaddr + channel[i].incmode) & 0xffff);
|
||||
}
|
||||
add_cycles(8);
|
||||
return --channel[i].xfersize;
|
||||
}
|
||||
|
||||
uint16 bCPU::dma_mmiotocpu(uint8 i, uint8 index) {
|
||||
uint8 x;
|
||||
x = mem_bus->read(0x2100 | ((channel[i].destaddr + index) & 0xff));
|
||||
mem_bus->write(channel[i].srcaddr, x);
|
||||
if(channel[i].fixedxfer == false) {
|
||||
channel[i].srcaddr = (channel[i].srcaddr & 0xff0000) + ((channel[i].srcaddr + channel[i].incmode) & 0xffff);
|
||||
}
|
||||
add_cycles(8);
|
||||
return --channel[i].xfersize;
|
||||
}
|
||||
|
||||
void bCPU::dma_xfer_type0(uint8 i) {
|
||||
if(channel[i].direction == 0) {
|
||||
if(dma_cputommio(i, 0) == 0)return;
|
||||
} else {
|
||||
if(dma_mmiotocpu(i, 0) == 0)return;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::dma_xfer_type1(uint8 i) {
|
||||
if(channel[i].direction == 0) {
|
||||
if(dma_cputommio(i, 0) == 0)return;
|
||||
if(dma_cputommio(i, 1) == 0)return;
|
||||
} else {
|
||||
if(dma_mmiotocpu(i, 0) == 0)return;
|
||||
if(dma_mmiotocpu(i, 1) == 0)return;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::dma_xfer_type2(uint8 i) {
|
||||
if(channel[i].direction == 0) {
|
||||
if(dma_cputommio(i, 0) == 0)return;
|
||||
if(dma_cputommio(i, 0) == 0)return;
|
||||
} else {
|
||||
if(dma_mmiotocpu(i, 0) == 0)return;
|
||||
if(dma_mmiotocpu(i, 0) == 0)return;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::dma_xfer_type3(uint8 i) {
|
||||
if(channel[i].direction == 0) {
|
||||
if(dma_cputommio(i, 0) == 0)return;
|
||||
if(dma_cputommio(i, 0) == 0)return;
|
||||
if(dma_cputommio(i, 1) == 0)return;
|
||||
if(dma_cputommio(i, 1) == 0)return;
|
||||
} else {
|
||||
if(dma_mmiotocpu(i, 0) == 0)return;
|
||||
if(dma_mmiotocpu(i, 0) == 0)return;
|
||||
if(dma_mmiotocpu(i, 1) == 0)return;
|
||||
if(dma_mmiotocpu(i, 1) == 0)return;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::dma_xfer_type4(uint8 i) {
|
||||
if(channel[i].direction == 0) {
|
||||
if(dma_cputommio(i, 0) == 0)return;
|
||||
if(dma_cputommio(i, 1) == 0)return;
|
||||
if(dma_cputommio(i, 2) == 0)return;
|
||||
if(dma_cputommio(i, 3) == 0)return;
|
||||
} else {
|
||||
if(dma_mmiotocpu(i, 0) == 0)return;
|
||||
if(dma_mmiotocpu(i, 1) == 0)return;
|
||||
if(dma_mmiotocpu(i, 2) == 0)return;
|
||||
if(dma_mmiotocpu(i, 3) == 0)return;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::dma_xfer_type5(uint8 i) {
|
||||
if(channel[i].direction == 0) {
|
||||
if(dma_cputommio(i, 0) == 0)return;
|
||||
if(dma_cputommio(i, 1) == 0)return;
|
||||
if(dma_cputommio(i, 0) == 0)return;
|
||||
if(dma_cputommio(i, 1) == 0)return;
|
||||
} else {
|
||||
if(dma_mmiotocpu(i, 0) == 0)return;
|
||||
if(dma_mmiotocpu(i, 1) == 0)return;
|
||||
if(dma_mmiotocpu(i, 0) == 0)return;
|
||||
if(dma_mmiotocpu(i, 1) == 0)return;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::dma_run() {
|
||||
int i;
|
||||
for(i=0;i<8;i++) {
|
||||
if(channel[i].active == false)continue;
|
||||
|
||||
switch(channel[i].xfermode) {
|
||||
case 0:dma_xfer_type0(i);break;
|
||||
case 1:dma_xfer_type1(i);break;
|
||||
case 2:dma_xfer_type2(i);break;
|
||||
case 3:dma_xfer_type3(i);break;
|
||||
case 4:dma_xfer_type4(i);break;
|
||||
case 5:dma_xfer_type5(i);break;
|
||||
case 6:dma_xfer_type2(i);break;
|
||||
case 7:dma_xfer_type3(i);break;
|
||||
}
|
||||
|
||||
if(channel[i].xfersize == 0) {
|
||||
channel[i].active = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
status.dma_state = DMASTATE_CPUSYNC;
|
||||
}
|
||||
|
||||
void bCPU::hdma_write(uint8 i, uint8 l, uint8 x) {
|
||||
switch(channel[i].xfermode) {
|
||||
case 0:mem_bus->write(0x2100 | ((channel[i].destaddr) & 0xff), x);break;
|
||||
case 1:mem_bus->write(0x2100 | ((channel[i].destaddr + l) & 0xff), x);break;
|
||||
case 2:mem_bus->write(0x2100 | ((channel[i].destaddr) & 0xff), x);break;
|
||||
case 3:mem_bus->write(0x2100 | ((channel[i].destaddr + (l >> 1)) & 0xff), x);break;
|
||||
case 4:mem_bus->write(0x2100 | ((channel[i].destaddr + l) & 0xff), x);break;
|
||||
case 5:mem_bus->write(0x2100 | ((channel[i].destaddr + (l & 1)) & 0xff), x);break;
|
||||
case 6:mem_bus->write(0x2100 | ((channel[i].destaddr) & 0xff), x);break;
|
||||
case 7:mem_bus->write(0x2100 | ((channel[i].destaddr + (l >> 1)) & 0xff), x);break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::hdma_run() {
|
||||
int l, xferlen;
|
||||
uint8 x, active_channels = 0;
|
||||
for(int i=0;i<8;i++) {
|
||||
if(channel[i].hdma_completed == true)continue;
|
||||
// add_cycles(8);
|
||||
active_channels++;
|
||||
if(channel[i].hdma_line_counter == 0) {
|
||||
channel[i].hdma_line_counter = mem_bus->read(channel[i].hdma_taddr++);
|
||||
if(channel[i].hdma_line_counter == 0) {
|
||||
channel[i].hdma_completed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(channel[i].hdma_line_counter > 0x80) {
|
||||
channel[i].hdma_repeat = true;
|
||||
channel[i].hdma_line_counter -= 0x80;
|
||||
} else {
|
||||
channel[i].hdma_repeat = false;
|
||||
}
|
||||
|
||||
channel[i].hdma_first_line = true;
|
||||
if(channel[i].hdma_indirect == false) {
|
||||
channel[i].hdma_itaddr = channel[i].hdma_taddr;
|
||||
} else {
|
||||
channel[i].hdma_itaddr = mem_bus->read(channel[i].hdma_taddr++);
|
||||
channel[i].hdma_itaddr |= mem_bus->read(channel[i].hdma_taddr++) << 8;
|
||||
channel[i].hdma_itaddr |= channel[i].hdma_indirect_bank << 16;
|
||||
// add_cycles(16);
|
||||
}
|
||||
}
|
||||
|
||||
channel[i].hdma_line_counter--;
|
||||
if(channel[i].hdma_first_line == false && channel[i].hdma_repeat == false)continue;
|
||||
channel[i].hdma_first_line = false;
|
||||
|
||||
if(channel[i].hdma_indirect == false) {
|
||||
channel[i].hdma_itaddr = channel[i].hdma_taddr;
|
||||
}
|
||||
|
||||
switch(channel[i].xfermode) {
|
||||
case 0: xferlen = 1;break;
|
||||
case 1:case 2:case 6: xferlen = 2;break;
|
||||
case 3:case 4:case 5:case 7:xferlen = 4;break;
|
||||
}
|
||||
|
||||
for(l=0;l<xferlen;l++) {
|
||||
x = mem_bus->read(channel[i].hdma_itaddr++);
|
||||
if(channel[i].hdma_indirect == false) {
|
||||
channel[i].hdma_taddr++;
|
||||
}
|
||||
hdma_write(i, l, x);
|
||||
// add_cycles(8);
|
||||
}
|
||||
}
|
||||
|
||||
if(active_channels != 0) {
|
||||
// add_cycles(18);
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::hdma_initialize() {
|
||||
uint8 active_channels = 0;
|
||||
for(int i=0;i<8;i++) {
|
||||
if(channel[i].hdma_active == false) {
|
||||
channel[i].hdma_completed = true;
|
||||
continue;
|
||||
}
|
||||
active_channels++;
|
||||
channel[i].hdma_first_line = true;
|
||||
channel[i].hdma_repeat = false;
|
||||
channel[i].hdma_taddr = channel[i].srcaddr;
|
||||
channel[i].hdma_line_counter = 0x00;
|
||||
channel[i].hdma_completed = false;
|
||||
if(channel[i].hdma_indirect == false) {
|
||||
add_cycles(8);
|
||||
} else {
|
||||
add_cycles(24);
|
||||
}
|
||||
}
|
||||
|
||||
if(active_channels != 0) {
|
||||
add_cycles(18);
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::dma_reset() {
|
||||
for(int i=0;i<8;i++) {
|
||||
channel[i].active = false;
|
||||
channel[i].hdma_active = false;
|
||||
channel[i].dmap = 0x00;
|
||||
channel[i].direction = 0;
|
||||
channel[i].hdma_indirect = false;
|
||||
channel[i].incmode = 1;
|
||||
channel[i].fixedxfer = false;
|
||||
channel[i].xfermode = 0;
|
||||
channel[i].destaddr = 0;
|
||||
channel[i].srcaddr = 0;
|
||||
channel[i].xfersize = 0;
|
||||
channel[i].hdma_indirect_bank = 0;
|
||||
channel[i].hdma_taddr = 0x000000;
|
||||
channel[i].hdma_line_counter = 0x00;
|
||||
channel[i].hdma_unknown = 0x00;
|
||||
|
||||
channel[i].hdma_first_line = false;
|
||||
channel[i].hdma_repeat = false;
|
||||
channel[i].hdma_itaddr = 0x000000;
|
||||
channel[i].hdma_completed = true;
|
||||
}
|
||||
}
|
||||
Loaded 100 of 452 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user