Compare commits

..

9 Commits
v010 ... v016

Author SHA1 Message Date
byuu
a3945e5772 Update to bsnes v016 release.
- Added Direct3D renderer with options for disabling hardware filtering and scanlines
    - Screenshots can now be captured in BMP, JPEG, or PNG format
    - Added config file option to specify default ROM and SRAM paths
    - Config file is always loaded from path to bsnes executable
    - Added support for analog mode joypad input
    - Up to 32 joypads can be used at once now
    - Fixed bug regarding enabling interlace mid-frame
    - Moved PPU rendering to V=240, from V=0
    - Started on new debugger. So far only debug messages and memory editor added
    - Added joypad axis resistance option for analog input mode
    - Added config file option to set window style attributes
    - Added color adjustment settings for brightness, contrast, gamma, and scanline intensity
    - Added grayscale, sepia, and invert color settings
    - Added NTSC filter by blargg, HQ2x filter by MaxSt, and Scale2x filter
    - PPU now renders scanline 224
    - Revampled about box
    - Added Game Genie / PAR cheat code support + editor, saves codes to .cht files
    - HDMA channels are no longer disabled when starting DMA, fixes Dracula X [DMV27]
    - Fixes to OAM priority mode (not perfect), fixes Final Fantasy: Mystic Quest [DMV27]
    - Fixed ENDX sound bug, fixes voices in Earthworm Jim 2 [DMV27]
    - bsnes should now compile with MinGW [DMV27]
    - Added DSP-2 support
    - Added OBC-1 support
    - Major rewrite of SNES address bus mirroring and MMIO handlers
    - Many address mirroring corrections, fixes Dezaemon, etc
    - Blocked invalid (H)DMA transfers, fixes Kirby's Super Funhouse
    - Wrote Win32 API wrapper and ported all GUI code to use it, should help to create Linux GUI later on
    - Revampled input system, should lead to customizable GUI shortcut keys later on
    - Fixed numerous bugs with input registers. Fixes many games that previous had their intro cut off (Super Conflict, etc), and many that never accepted input (Super Double Dragon, etc)
    - Moved auto joypad strobing from V=225 to V=227
    - Killed OAM table caching and window range caching, as they were actually hindering speed
    - Rewrote input configuration screen to show currently mapped keys
    - Greatly enhanced configuration options for each video profile
    - Modified fullscreen mode to exit to windowed mode when menu is activated, use F11 to toggle fullscreen mode
    - Fixed bugs in txs, wai, brk, cop, and rti opcodes [DMV27]
    - Fixed bug with emulation-mode IRQs [DMV27]
    - Initializing DMA registers to $ff [DMV27]
    - Memory writes now update CPU MDR register (open bus) [DMV27]
    - Improved ROM header detection, fixes Chou Jikuu Yousai Macross [DMV27]
    - Reading OAM no longer updates OAM latch
    - Writing to OAM high table no longer updates OAM latch
    - Writing CGRAM now updates CGRAM latch
    - Improved pseudo-hires rendering [blargg]
    - Much, much more
2006-04-25 15:51:10 +00:00
byuu
6b6233b3af Update to bsnes v015 rc3 release.
[No changelog available]
2006-04-22 01:02:32 +00:00
byuu
9f63cb1b99 Update to bsnes v015 rc2 release.
[No changelog available]
2006-04-20 00:26:54 +00:00
byuu
49c39e0e4d Update to bsnes v015 release.
- Added GZ / ZIP / JMA archive support [Nach, NSRT team]
    - Fixed bug in APU ADDW/SUBW opcode flags, thanks to DMV27, anomymous for info
    - Mosaic support is now (mostly) hardware accurate, thanks to TRAC for info
    - Fixed a bug in SC tilemap clipping, fixes Seiken Densetsu 3
    - Emulated pseudo-hires mode, uses a fairly poor color filter to simulate TV effect, the same one that SNES9x and Super Sleuth use
    - Rewrote the ROM loading code to be more port-friendly, and improved header detection
    - Added C4 emulation -- mostly correct. Only minor bugs remain, possibly not C4 related [Nach, byuu], also uses code from zsKnight, Overload, and anomie
    - Fixed noise channel generation for DSP, fixes Dual Orb 2 opening. Thanks to DMV27 for info
    - Fixed bug with DSP VxSRCN registers, fixes horrible sound corruption in Mortal Kombat 2/3
    - Modified DSP KON register reading to act according to anomie's research, while still allowing Der Langrisser, etc. to play sounds correctly
    - Fixed a bug in CPU BCD math, fixes numbers in SimEarth, thanks to DMV27 for info
    - Rewrote the windows port from scratch
    - -- Added triple buffering support (buggy)
    - -- Added DirectInput (joypad) support, allows both keyboard and joypad to be mapped to the same SNES controller button. Only one controller supported for this release, will be improved shortly
    - -- Added pause key (mapped to Pause/Break)
    - -- bsnes no longer consumes CPU time when paused or when no ROM is loaded
    - -- Updated DirectDraw to 7, and added video mode configuration options to configuration file
    - -- Video modes can specify screen width+height, refresh rate, and render width+height
    - -- Added CTRL+[1-0] hotkeys for swapping video modes
    - -- Added +/- hotkeys for adjusting frameskipping rate
    - -- Added adjustable speed regulation. There are five modes, all can be adjusted inside the configuration file. CTRL+[+/-] will adjust the speed mode.
    - -- Added PPU options to toggle any BG / OAM layers with any priority, HDMA effects, and offset per tile effects
    - -- Added option to accept invalid button combinations (up+down, left+right) to joypad config menu
    - -- bsnes now properly clears the main window when unloading games
    - [code] Made destructors for base classes virtual, so the correct destructors will be called now
2005-12-03 21:05:52 +00:00
byuu
7dec0b2a3c Update to bsnes v014 release.
This version adds speed regulation, greatly improves PPU rendering, and increases speed by ~30% over the previous version.
Changelog:
    - Rewrote offset-per-tile mode emulation, should be correct now. Fixes Chrono Trigger, Contra III, Tetris Attack, etc.
    - Fixed a bug with HDMA occuring during interrupts. Fixes Tales of Phantasia souond test screen
    - Updated compiler to Visual Studio 2005, and enabled profile guided optimizations
    - Added conditional compilation of debugging functions (faster without them)
    - Added conditional compilation of core classes as pointers (allowing polymorphism) or objects (allowing inlining). The latter results in a speed increase
    - Small fixes to BG and OAM rendering routines
    - Corrected sprite tile bounds wrapping
    - Corrected sprite rendering in hires video modes
    - Rewrote color add/sub routines, should be correct now. Fixes Illusion of Gaia menu, etc.
    - Optimized video blitting routines, will temporarilly break mixed video mode screenshots
    - Prevented selecting menu options via return key from being recognized as keypresses by the emulator
    - Added system speed regulation (60hz/NTSC or 50hz/PAL)! Many thanks to kode54, GIGO, and Richard Bannister for their assistance
I disabled the debugger and polymorphism, and enabled profile guided optimizations for this build, to maximize speed. The debugger and polymorphism can be re-enabled via uncommenting the respective #defines in src/base.h and recompiling, or bsnes v0.013 can be used. I may start releasing two separate builds in the future... not sure yet.
2005-11-12 16:49:26 +00:00
byuu
f288280ceb Update to bsnes v013r02 release.
[No changelog available]
2005-10-25 23:25:28 +00:00
byuu
c6c5f4669c Update to bsnes v013 release.
- Greatly improved HDMA timing and accuracy with help from anomie and DMV27 -- fixes bugs in Energy Breaker and Street Fighter Alpha 2
    - Fixed a problem with color add/sub code -- fixes opening battle in Tales of Phantasia and clouds in Energy Breaker
    - Temporarily added DMV27's bugfix for the DSP KON register -- fixes sound in Der Langrisser, but this is not a hardware-accurate fix
    - Disabled VRAM writes outside of vblank -- fixes Hook, but breaks many PD ROMs and fan translations (Roto's BS Zelda hack, Gideon Zhi's Ys 4 translation, etc). I might add an option in the future to toggle this behavior, but for now these games will no longer work. Please keep in mind these games will not run properly on real SNES hardware, either.
    - Improved frameskipping code thanks to a suggestion from Richard Bannister
    - Misc. other code cleanups and improvements (notably in the color table generation code)
    - bsnes is now endian-safe and runs on Mac OS X
    - Added caching support for window clipping tables resulting in a slight speedup. Please let me know if you spot any errors as a result of this change.
2005-10-23 23:32:30 +00:00
byuu
397b9c4505 Update to bsnes v012 release.
Changelog:
    - Added S-DSP emulation
    - Added sound output support via DirectSound -- no sound buffering though, so sound is muted by default
    - Added option to record raw sound output to WAV files
    - Added multiple color adjustment filters to the video output
    - Added mode3/4 direct color support
    - Added mode7 direct color and mosaic support
    - Greatly improved mode7 rendering algorithm thanks to anomie
    - Fixed mode7 screen repitition and EXTBG effects
    - Greatly increased accuracy of NMI and IRQ timing, and emulated many newly discovered hardware quirks involving the two
    - A few speed improvements courtesy of Nach for profiling the code for me
I'm now looking for assistance with sound buffering. Specifically, I need help modifying the DirectSound code to allow the emulator to be ran between 50%-400% normal speed, while keeping the sound output relatively good. If you have experience with this and can help, please get in touch with me (setsunakun0 at hotmail dot com).
2005-10-02 00:38:34 +00:00
byuu
7e2cfb6d40 Update to bsnes v011 release.
- Fixed Mode 0 color palette index problem. Fixes ToP, DQ5, etc.
    - Improved LoROM memory mapper to support 32mbit images. Fixes Tokimeki Memorial, etc.
    - Added full S-DD1 support, SFA2 and Star Ocean are now playable. Special thanks to Andreas Naive
    - Updated BGnxOFS / Mode7 registers with anomie's latest findings
    - Added basic ROM mirroring support. Fixes copy protection issues in MMX, etc.
    - Rewrote string library to work better on gcc/linux
    - Cleaned up S-RTC/S-DD1 emulation to make way for future add-on chip emulation
    - Rewrote DMA code, now runs cycle-by-cycle
    - Rewrote HDMA code, now allows HDMA to be enabled mid-frame, fixes many games
    - Fixed a bug in Mode7 vertical screen flip mode. Fixes FF5 title screen, etc.
    - Greatly improved IRQ triggering. Fixes Der Langrisser, etc.
    - Added full support for open bus. This includes PPU1 and PPU2 open bus support
    - Modified CPU core back to cycle-based system. Slower, but improves debugger
    - Implemented temporary fix for debugger to handle new cycle-based cores
    - Modified CGRAM to ignore highest bit, since it is not used at all by the SNES, and is impossible to read on real hardware. Lowers memory usage by ~1.2mb
    - Added mostly accurate PAL timing support. This should increase compatibility by ~30% or so
    - More stuff I'm forgetting at the moment...
2005-08-26 20:38:00 +00:00
354 changed files with 49288 additions and 13465 deletions

View File

@@ -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

BIN
bsnes.exe

Binary file not shown.

View File

@@ -17,5 +17,10 @@ emulators.
The Simple DirectMedia Layer library source code is available from:
http://www.libsdl.org/
This library is distributed under the terms of the GNU LGPL license:
This library is distributed under the terms of the GNU LGPL:
http://www.gnu.org/copyleft/lesser.html
Licensing Exemptions:
---------------------
Richard Bannister has asked for and received my permission to distribute
a binary-only port of bsnes on the Mac OS X platform.

View File

@@ -1,2 +1,3 @@
#include "../base.h"
#include "iplrom.h"
#include "dapu.cpp"

View File

@@ -1,10 +1,9 @@
#define _APU_IPLROM
#include "iplrom.h"
#include "apuregs.h"
class APU {
public:
APURegs regs;
static const uint8 iplrom[64];
enum {
FLAG_N = 0x80, FLAG_V = 0x40,
FLAG_P = 0x20, FLAG_B = 0x10,
@@ -18,11 +17,17 @@ APURegs regs;
virtual uint8 port_read (uint8 port) = 0;
virtual void port_write(uint8 port, uint8 value) = 0;
virtual uint8 *get_spcram_handle() = 0;
virtual void run() = 0;
virtual uint32 cycles_executed() = 0;
virtual void power() = 0;
virtual void reset() = 0;
//debugging functions
virtual bool in_opcode();
void disassemble_opcode(char *output);
inline uint16 __relb(int8 offset, int op_len);
APU() {}
virtual ~APU() {}
};

View File

@@ -13,7 +13,7 @@ private:
inline bool operator ^= (bool i) { if(i)_b ^= B; return (_b & B); }
};
public:
union {
union {
uint8 _b;
bit<0x80> n;
bit<0x40> v;
@@ -23,7 +23,7 @@ public:
bit<0x04> i;
bit<0x02> z;
bit<0x01> c;
};
};
APURegFlags() { _b = 0; }
inline operator uint8() { return _b; }
@@ -38,10 +38,11 @@ public:
uint16 pc;
union {
uint16 ya;
//not endian-safe
struct {
uint8 a, y;
};
#ifdef ARCH_LSB
struct { uint8 a, y; };
#else
struct { uint8 y, a; };
#endif
};
uint8 x, sp;
APURegFlags p;

View File

@@ -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.cycles_executed = 0;
//$f1
status.iplrom_enabled = true;
@@ -246,15 +42,12 @@ void bAPU::reset() {
t0.stage3_ticks = 0;
t1.stage3_ticks = 0;
t2.stage3_ticks = 0;
memset(dsp_regs, 0, 128);
}
bAPU::bAPU() {
init_op_table();
spcram = (uint8*)malloc(65536);
memcpy(iplrom, spc700_iplrom, 64);
t0.cycle_frequency = 128; //1.024mhz / 8khz = 128
t1.cycle_frequency = 128; //1.024mhz / 8khz = 128
@@ -269,25 +62,3 @@ bAPU::bAPU() {
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;
}

View File

@@ -1,20 +1,8 @@
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;
@@ -25,54 +13,11 @@ struct {
//$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();

View File

@@ -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"
}

View File

@@ -1,168 +0,0 @@
#include "../../lib/libbase.h"
#include "../../lib/libstring.h"
#include "../../lib/libstring.cpp"
FILE *fp, *fph, *fpt;
string data, line, part, subpart;
string output_table, output_header, output_op;
int op_count;
struct _op_list {
string name;
string arg;
}op_list[64];
int line_num;
void clear_op_list() {
op_count = 0;
for(int i=0;i<64;i++) {
strcpy(op_list[i].name, "");
for(int l=0;l<8;l++) {
strcpy(op_list[i].arg[l], "");
}
}
}
void gen_header() {
int i = line_num, l, n, z;
char t[4096];
clear_op_list();
while(1) {
z = op_count++;
strcpy(part, line[i]);
strrtrim(part, "),");
strrtrim(part, ") {");
split(subpart, "(", part);
strcpy(op_list[z].name, subpart[0]);
split(part, ", ", subpart[1]);
for(l=0;l<count(part);l++) {
strcpy(op_list[z].arg[l], part[l]);
}
if(!strend(line[i], " {"))break;
i++;
}
sprintf(output_op, "void bAPU::op_$$() {\r\n switch(status.cycle_pos++) {\r\n");
sprintf(output_header, "void op_$$();\r\n");
sprintf(output_table, "optbl[$0] = &bAPU::op_$$;\r\n");
line_num = i + 1;
}
void update_line(int i, int n) {
replace(line[i], "end;", "status.cycle_pos = 0;");
}
void gen_op() {
int i = line_num, n;
char t[4096];
while(1) {
if(!strcmp(line[i], "}"))break;
n = strdec(line[i]);
sprintf(t, "%d:", n);
strltrim(line[i], t);
sprintf(t, " case %d:\r\n", n);
strcat(output_op, t);
update_line(i, n);
if(strcmp(line[i], "")) {
strcat(output_op, " ");
strcat(output_op, line[i]);
strcat(output_op, "\r\n");
}
i++;
while(1) {
if((strptr(line[i])[1]) == ':' || (strptr(line[i])[2]) == ':' || !strcmp(line[i], "}"))break;
update_line(i, n);
strcat(output_op, " ");
strcat(output_op, line[i]);
strcat(output_op, "\r\n");
i++;
}
if(!strcmp(line[i], "}"))strcat(output_op, " status.cycle_pos = 0;\r\n");
strcat(output_op, " break;\r\n");
}
strcat(output_op, " }\r\n}");
line_num = i + 1;
}
void gen_final() {
string t;
int i, l;
for(i=0;i<op_count;i++) {
strcpy(t, output_op);
replace(t, "$$", op_list[i].name);
replace(t, "$0", op_list[i].arg[0]);
replace(t, "$1", op_list[i].arg[1]);
replace(t, "$2", op_list[i].arg[2]);
replace(t, "$3", op_list[i].arg[3]);
replace(t, "$4", op_list[i].arg[4]);
replace(t, "$5", op_list[i].arg[5]);
replace(t, "$6", op_list[i].arg[6]);
replace(t, "$7", op_list[i].arg[7]);
fprintf(fp, "%s\r\n\r\n", *t);
strcpy(t, output_header);
replace(t, "$$", op_list[i].name);
fprintf(fph, "%s", *t);
strcpy(t, output_table);
replace(t, "$$", op_list[i].name);
replace(t, "$0", op_list[i].arg[0]);
fprintf(fpt, "%s", *t);
}
}
void generate(char *dest, char *src) {
fp = fopen(src, "rb");
fseek(fp, 0, SEEK_END);
int fsize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *buf = (char*)malloc(fsize + 1);
fread(buf, 1, fsize, fp);
fclose(fp);
buf[fsize] = 0;
strcpy(data, buf);
free(buf);
replace(data, "\r\n", "\n");
split(line, "\n", data);
fp = fopen(dest, "wb");
line_num = 0;
while(line_num < count(line)) {
while(!strcmp(line[line_num], "") && line_num < count(line))line_num++;
if(line_num >= count(line))break;
gen_header();
gen_op();
gen_final();
}
fclose(fp);
}
int main() {
fph = fopen("bapu_op.h", "wb");
fpt = fopen("bapu_optable.cpp", "wb");
generate("bapu_op_mov.cpp", "op_mov.b");
generate("bapu_op_pc.cpp", "op_pc.b");
generate("bapu_op_read.cpp", "op_read.b");
generate("bapu_op_rmw.cpp", "op_rmw.b");
generate("bapu_op_misc.cpp", "op_misc.b");
fclose(fph);
fclose(fpt);
return 0;
}

Binary file not shown.

View File

@@ -1,3 +0,0 @@
cl /ML /O2 bapugen.cpp
@pause
@del *.obj

View File

@@ -1 +0,0 @@
@del *.exe

View File

@@ -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;
}

3
src/apu/bapu/core/cc.bat Normal file
View File

@@ -0,0 +1,3 @@
cl /O2 /wd4996 bapugen.cpp
@pause
@del *.obj

View File

@@ -0,0 +1,8 @@
@del *.exe
@del op.h
@del optable.cpp
@del op_mov.cpp
@del op_pc.cpp
@del op_read.cpp
@del op_rmw.cpp
@del op_misc.cpp

View File

@@ -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"
}

25
src/apu/bapu/core/core.h Normal file
View File

@@ -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"

View File

@@ -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;
}
}

View File

@@ -1,710 +1,710 @@
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;
}
}

View File

@@ -37,16 +37,25 @@ bbc7(0xf3, 0x80, ==) {
6:regs.pc += (int8)rd;
}
cbne_dp(0x2e, 0),
cbne_dpx(0xde, regs.x) {
cbne_dp(0x2e) {
1:dp = op_read();
2:rd = op_read();
3:sp = op_read(OPMODE_DP, dp + $1);
3:sp = op_read(OPMODE_DP, dp);
4:if(regs.a == sp)end;
5:
6:regs.pc += (int8)rd;
}
cbne_dpx(0xde) {
1:dp = op_read();
2:rd = op_read();
3:
4:sp = op_read(OPMODE_DP, dp + regs.x);
5:if(regs.a == sp)end;
6:
7:regs.pc += (int8)rd;
}
dbnz_dp(0x6e) {
1:dp = op_read();
2:rd = op_read();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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;
}
}

View File

@@ -9,12 +9,11 @@ int16 r = x + y + regs.p.c;
}
uint16 bAPU::op_addw(uint16 x, uint16 y) {
int32 r = x + y;
regs.p.n = !!(r & 0x8000);
regs.p.v = !!(~(x ^ y) & (y ^ (uint16)r) & 0x8000);
regs.p.h = !!((x ^ y ^ (uint16)r) & 0x10);
int16 r;
regs.p.c = 0;
r = op_adc(x, y);
r |= op_adc(x >> 8, y >> 8) << 8;
regs.p.z = ((uint16)r == 0);
regs.p.c = (r > 0xffff);
return r;
}
@@ -66,12 +65,11 @@ int16 r = x - y - !regs.p.c;
}
uint16 bAPU::op_subw(uint16 x, uint16 y) {
int32 r = x - y;
regs.p.n = !!(r & 0x8000);
regs.p.v = !!((x ^ y) & (x ^ (uint16)r) & 0x8000);
regs.p.h = !((x ^ y ^ (uint16)r) & 0x10);
int16 r;
regs.p.c = 1;
r = op_sbc(x, y);
r |= op_sbc(x >> 8, y >> 8) << 8;
regs.p.z = ((uint16)r == 0);
regs.p.c = (r >= 0);
return r;
}

View File

@@ -0,0 +1,199 @@
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--;
}
uint8 *bAPU::get_spcram_handle() {
if(!spcram) {
alert("bAPU::get_spcram_handle() -- spcram uninitialized");
}
return spcram;
}

View File

@@ -0,0 +1,14 @@
enum { OPMODE_ADDR, OPMODE_DP };
uint8 *spcram;
inline uint8 spcram_read (uint16 addr);
inline void spcram_write(uint16 addr, uint8 value);
inline uint8 port_read (uint8 port);
inline void port_write(uint8 port, uint8 value);
inline uint8 *get_spcram_handle();
inline 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);

View File

@@ -0,0 +1,35 @@
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);
}
//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;
}

View File

@@ -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 cycles_executed();

View File

@@ -1,171 +0,0 @@
#include "../../base.h"
uint8 bAPUSkip::spcram_read (uint16 addr) { return 0xff; }
void bAPUSkip::spcram_write(uint16 addr, uint8 value) {}
/*
This routine is very serious. It will eat holes through
the ROM to skip APU test conditions. Or in other words,
it will disable and/or force branches when neccesary.
It can very easily break or corrupt a game and prevent it
from being playable until the ROM is reloaded (ROM writes
are only performed in memory, of course).
However, this kind of brute force approach is required to
get many games playable without proper SPC700 emulation.
*/
uint8 bAPUSkip::port_read(uint8 port) {
port &= 3;
_apu_port *p = &apu_port[port];
int i, x, y, z, t;
uint32 addr;
addr = cpu->regs.pc.d;
p->read_addr[p->read_pos & 31] = addr;
//- lda $214x
// cmp $214x
// bne -
// cmp ???
// beq/bne -
__test1:
//look for an lda/cmp read pattern
if(addr == p->read_addr[(p->read_pos - 1) & 31])goto __test2;
if(addr != p->read_addr[(p->read_pos - 2) & 31])goto __test2;
if(addr == p->read_addr[(p->read_pos - 3) & 31])goto __test2;
if(addr != p->read_addr[(p->read_pos - 4) & 31])goto __test2;
if(p->read_addr[(p->read_pos - 1) & 31] != p->read_addr[(p->read_pos - 3) & 31])goto __test2;
//try and find compare opcode
for(i=0;i<24;i++) {
x = mem_bus->read(addr + i);
if(x == OP_CMP_CONST || x == OP_CPX_CONST || x == OP_CPY_CONST)break;
if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) break;
if(x == OP_CMP_LONG)break;
}
if(i == 24)goto __test2;
//seek to next opcode
if(x == OP_CMP_CONST) {
i += (cpu->regs.p.m)?2:3;
} else if(x == OP_CPX_CONST || x == OP_CPY_CONST) {
i += (cpu->regs.p.x)?2:3;
} else if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) {
i += 3;
} else { //(x == OP_CMP_LONG) {
i += 4;
}
x = mem_bus->read(addr + i);
if(x == OP_BNE) {
mem_bus->cart->write_protect(false);
mem_bus->write(addr + i, OP_NOP);
mem_bus->write(addr + i + 1, OP_NOP);
mem_bus->cart->write_protect(true);
} else if(x == OP_BEQ) {
mem_bus->cart->write_protect(false);
mem_bus->write(addr + i, OP_BRA);
mem_bus->cart->write_protect(true);
} else goto __test2;
goto __pass;
//- lda $214x
// cmp ???
// beq/bne -
__test2:
//look for a repeated read pattern
if(addr != p->read_addr[(p->read_pos - 1) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 2) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 3) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 4) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 5) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 6) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 7) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 8) & 31])goto __test3;
//try and find compare opcode
for(i=0;i<24;i++) {
x = mem_bus->read(addr + i);
if(x == OP_CMP_CONST || x == OP_CPX_CONST || x == OP_CPY_CONST)break;
if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) break;
if(x == OP_CMP_LONG)break;
}
if(i == 24)goto __test3;
//seek to next opcode
if(x == OP_CMP_CONST) {
i += (cpu->regs.p.m)?2:3;
} else if(x == OP_CPX_CONST || x == OP_CPY_CONST) {
i += (cpu->regs.p.x)?2:3;
} else if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) {
i += 3;
} else if(x == OP_CMP_LONG) {
i += 4;
}
x = mem_bus->read(addr + i);
if(x == OP_BNE) {
mem_bus->cart->write_protect(false);
mem_bus->write(addr + i, OP_NOP);
mem_bus->write(addr + i + 1, OP_NOP);
mem_bus->cart->write_protect(true);
} else if(x == OP_BEQ) {
mem_bus->cart->write_protect(false);
mem_bus->write(addr + i, OP_BRA);
mem_bus->cart->write_protect(true);
} else goto __test3;
goto __pass;
//fallback
__test3:
if(p->pos < 4) {
if(!(port & 1)) {
p->value = cpu->regs.a.l;
} else {
p->value = cpu->regs.a.h;
}
} else if(p->pos < 8) {
if(!(port & 1)) {
p->value = cpu->regs.x.l;
} else {
p->value = cpu->regs.x.h;
}
} else if(p->pos < 12) {
if(!(port & 1)) {
p->value = cpu->regs.y.l;
} else {
p->value = cpu->regs.y.h;
}
} else if(p->pos < 16) {
p->value = rand();
}
if(++p->pos == 16)p->pos = 0;
__pass:
p->read_pos++;
p->read_pos &= 31;
return p->value;
}
void bAPUSkip::port_write(uint8 port, uint8 value) {
port &= 3;
apu_port[port].value = value;
}
void bAPUSkip::run() {
snes->notify(SNES::APU_EXEC_OPCODE_BEGIN);
snes->notify(SNES::APU_EXEC_OPCODE_END);
}
void bAPUSkip::power() {
reset();
}
void bAPUSkip::reset() {
regs.a = 0x00;
regs.x = 0x00;
regs.y = 0x00;
regs.sp = 0x00;
regs.p = 0x02;
regs.pc = 0xffc0;
memset(&apu_port[0], 0, sizeof(_apu_port));
memset(&apu_port[1], 0, sizeof(_apu_port));
memset(&apu_port[2], 0, sizeof(_apu_port));
memset(&apu_port[3], 0, sizeof(_apu_port));
}

View File

@@ -1,33 +0,0 @@
class bAPUSkip : public APU {
public:
struct _apu_port {
uint8 value;
uint8 step, pos;
uint32 read_addr[32], read_pos;
}apu_port[4];
enum {
OP_CMP_CONST = 0xc9,
OP_CPX_CONST = 0xe0,
OP_CPY_CONST = 0xc0,
OP_CMP_ADDR = 0xcd,
OP_CPX_ADDR = 0xec,
OP_CPY_ADDR = 0xcc,
OP_CMP_LONG = 0xcf,
OP_BNE = 0xd0,
OP_BEQ = 0xf0,
OP_BRA = 0x80,
OP_NOP = 0xea
};
uint8 spcram_read (uint16 addr);
void spcram_write(uint16 addr, uint8 value);
uint8 port_read (uint8 port);
void port_write (uint8 port, uint8 value);
void run();
uint32 cycles_executed() { return 12 * 24; }
void power();
void reset();
};

View File

@@ -1,12 +1,23 @@
//virtual function, see src/cpu/dcpu.cpp
//for explanation of this function
bool APU::in_opcode() { return false; }
uint16 APU::__relb(int8 offset, int op_len) {
uint16 pc = regs.pc + op_len;
return pc + offset;
}
void APU::disassemble_opcode(char *output) {
char *s = output, t[512];
char *s, t[512];
uint8 op, op0, op1;
uint16 opw, opdp0, opdp1;
s = output;
if(in_opcode() == true) {
strcpy(s, "..???? <APU within opcode>");
return;
}
sprintf(s, "..%0.4x ", regs.pc);
op = spcram_read(regs.pc);

View File

@@ -3,12 +3,8 @@
//allow writing to the IPLROM, all writes are
//instead mapped to the extended SPC700 RAM region,
//accessible when $f1 bit 7 is clear.
//If you use this buffer directly, make sure not
//to write to it, as this will break other APU
//implementations that attempt to use this buffer.
#ifdef _APU_IPLROM
const uint8 spc700_iplrom[64] = {
const uint8 APU::iplrom[64] = {
/*ffc0*/ 0xcd, 0xef, //mov x,#$ef
/*ffc2*/ 0xbd, //mov sp,x
/*ffc3*/ 0xe8, 0x00, //mov a,#$00
@@ -43,6 +39,3 @@ const uint8 spc700_iplrom[64] = {
/*fffb*/ 0x1f, 0x00, 0x00, //jmp ($0000+x)
/*fffe*/ 0xc0, 0xff //---reset vector location ($ffc0)
};
#else
extern const uint8 spc700_iplrom[64];
#endif

View File

@@ -1,15 +1,63 @@
#include <time.h>
#include "lib/libbase.h"
#define BSNES_VERSION "0.016"
#define BSNES_TITLE "bsnes v" BSNES_VERSION
//structs
typedef struct {
uint8 *data;
uint32 size;
}lfile;
#define MEMCORE bMemBus
#define CPUCORE bCPU
#define APUCORE bAPU
#define DSPCORE bDSP
#define PPUCORE bPPU
//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
//this should be declared in the port-specific makefiles
//#define ARCH_LSB
//#define ARCH_MSB
#ifndef ARCH_LSB
#ifndef ARCH_MSB
#define ARCH_LSB
#endif
#endif
#if defined(_WIN32)
#define _WIN32_
#undef _UNIX_
#elif defined(__GNUC__)
#define _UNIX_
#undef _WIN32_
#else
#error "unknown architecture"
#endif
#include "lib/libbase.h"
#include "lib/libvector.h"
#include "lib/libstring.h"
#include "lib/libconfig.h"
#include "lib/libbpf.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, ...);

369
src/cart/cart.cpp Normal file
View File

@@ -0,0 +1,369 @@
#include "../base.h"
void Cartridge::read_header() {
cart.srtc = false;
cart.sdd1 = false;
cart.c4 = false;
cart.dsp2 = false;
cart.obc1 = false;
if(cart.header_index == 0x7fc0 && cart.rom_size >= 0x401000) {
cart.mapper = EXLOROM;
} else if(cart.header_index == 0x7fc0 && rom[cart.header_index + MAPPER] == 0x32) {
cart.mapper = EXLOROM;
} else if(cart.header_index == 0x7fc0) {
cart.mapper = LOROM;
} else if(cart.header_index == 0xffc0) {
cart.mapper = HIROM;
} else { //cart.header_index == 0x40ffc0
cart.mapper = EXHIROM;
}
uint8 mapper = rom[cart.header_index + MAPPER];
uint8 rom_type = rom[cart.header_index + ROM_TYPE];
if(mapper == 0x35 && rom_type == 0x55) {
cart.srtc = true;
}
if(mapper == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
cart.sdd1 = true;
}
if(mapper == 0x20 && rom_type == 0xf3) {
cart.c4 = true;
}
if(mapper == 0x20 && rom_type == 0x05) {
cart.dsp2 = true;
}
if(mapper == 0x30 && rom_type == 0x25) {
cart.obc1 = true;
}
cart.cart_mmio = cart.c4 | cart.dsp2 | cart.obc1;
if(rom[cart.header_index + SRAM_SIZE] & 7) {
cart.sram_size = 1024 << (rom[cart.header_index + SRAM_SIZE] & 7);
} else {
cart.sram_size = 0;
}
cart.region = ((rom[cart.header_index + REGION] & 0x7f) < 2) ? NTSC : PAL;
memcpy(&cart.name, &rom[cart.header_index + CART_NAME], 21);
cart.name[21] = 0;
for(int i = 0; i < 22; i++) {
if(cart.name[i] & 0x80) {
cart.name[i] = '?';
}
}
}
void Cartridge::find_header() {
int32 score_lo = 0,
score_hi = 0,
score_ex = 0;
if(rom_size < 0x010000) {
//cart too small to be anything else
cart.header_index = 0x007fc0;
return;
}
if((rom[0x7fc0 + MAPPER] & ~0x10) == 0x20)score_lo++;
if((rom[0xffc0 + MAPPER] & ~0x10) == 0x21)score_hi++;
if(rom[0x7fc0 + ROM_TYPE] < 0x08)score_lo++;
if(rom[0xffc0 + ROM_TYPE] < 0x08)score_hi++;
if(rom[0x7fc0 + ROM_SIZE] < 0x10)score_lo++;
if(rom[0xffc0 + ROM_SIZE] < 0x10)score_hi++;
if(rom[0x7fc0 + SRAM_SIZE] < 0x08)score_lo++;
if(rom[0xffc0 + SRAM_SIZE] < 0x08)score_hi++;
if(rom[0x7fc0 + REGION] < 14)score_lo++;
if(rom[0xffc0 + REGION] < 14)score_hi++;
if(rom[0x7fc0 + LICENSE] < 3)score_lo++;
if(rom[0xffc0 + LICENSE] < 3)score_hi++;
uint16 cksum, icksum;
cksum = rom[0x7fc0 + CKSUM] | (rom[0x7fc0 + CKSUM + 1] << 8);
icksum = rom[0x7fc0 + ICKSUM] | (rom[0x7fc0 + ICKSUM + 1] << 8);
if((cksum + icksum) == 0xffff && (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(rom_size < 0x401000) {
score_ex = 0;
} else {
if(rom[0x7fc0 + MAPPER] == 0x32)score_lo++;
else score_ex += 16;
}
if(score_lo >= score_hi && score_lo >= score_ex) {
cart.header_index = 0x007fc0;
} else if(score_hi >= score_ex) {
cart.header_index = 0x00ffc0;
} else {
cart.header_index = 0x40ffc0;
}
}
void Cartridge::load_sram() {
if(cart.sram_size == 0) {
sram = 0;
return;
}
FileReader ff(sram_fn);
if(!ff.ready()) {
sram = (uint8*)malloc(cart.sram_size);
memset(sram, 0, cart.sram_size);
return;
}
sram = ff.read(cart.sram_size);
}
void Cartridge::save_sram() {
if(cart.sram_size == 0)return;
FileWriter ff(sram_fn);
if(!ff.ready())return;
ff.write(sram, cart.sram_size);
}
void Cartridge::load_rom(Reader *rf) {
base_rom = rf->read();
rom_size = rf->size();
if((rom_size & 0x7fff) == 0x0200) {
rom = base_rom + 512;
rom_size -= 512;
} else {
rom = base_rom;
}
cart.rom_size = rom_size;
cart.crc32 = 0xffffffff;
for(int32 i = 0; i < cart.rom_size; i++) {
cart.crc32 = crc32_adjust(cart.crc32, rom[i]);
}
cart.crc32 = ~cart.crc32;
}
void Cartridge::patch_rom(Reader *rf) {
uint8 *patch_data = rf->read();
uint32 patch_size = rf->size();
BPF bpf;
if(patch_size < 34)return;
uint32 target;
target = patch_data[BPF::INDEX_FORMAT + 0] << 0;
target |= patch_data[BPF::INDEX_FORMAT + 1] << 8;
target |= patch_data[BPF::INDEX_FORMAT + 2] << 16;
target |= patch_data[BPF::INDEX_FORMAT + 3] << 24;
if(target != BPF::FORMAT_SNES) {
alert("Warning: BPF patch file is not in SNES format!\n\n"
"The patch will still be applied, but it will not be "
"possible to determine whether the patch was created "
"against an image with a header or without a header.\n\n"
"bsnes is now forced to assume the patch was created "
"against a headerless source image. If this is not the "
"case, then patching will fail!\n\n"
"If you are the author of this patch, please recreate "
"the patch in SNES format.\n\n"
"If you are not the patch author, please contact the "
"author and ask them to create an SNES format BPF patch.");
}
if(bpf.apply_patch(patch_size, patch_data, rom_size, rom) == true) {
SafeFree(base_rom);
uint8 *temp = bpf.get_output_handle(rom_size);
base_rom = (uint8*)malloc(rom_size);
memcpy(base_rom, temp, rom_size);
rom = base_rom;
cart.rom_size = rom_size;
} else {
alert("Failed to apply patch.\n\nThis could be because the patch itself "
"does not match its internal checksum, because the ROM loaded does not "
"match the patch information for either the original or modified file, "
"or because the patched file does not match the checksum of either the "
"original or modified file that is stored inside the patch.\n\n"
"The original ROM image will be used instead.");
}
SafeFree(patch_data);
}
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(static_cast<Reader*>(&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(static_cast<Reader*>(&gf));
break;
}
case Reader::RF_ZIP: {
ZipReader zf(rom_fn);
load_rom(static_cast<Reader*>(&zf));
break;
}
#endif
#ifdef JMA_SUPPORT
case Reader::RF_JMA: {
try {
JMAReader jf(rom_fn);
load_rom(static_cast<Reader*>(&jf));
} catch(JMA::jma_errors jma_error) {
alert("Error loading image file (%s)!", rom_fn);
return false;
}
break;
}
#endif
}
//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;
}
}
//check for bpf patch
#ifdef GZIP_SUPPORT
strcpy(patch_fn, sram_fn);
strcat(patch_fn, ".bpz");
if(fexists(patch_fn)) {
ZipReader zf(patch_fn);
patch_rom(static_cast<Reader*>(&zf));
} else {
#endif
strcpy(patch_fn, sram_fn);
strcat(patch_fn, ".bpf");
if(fexists(patch_fn)) {
FileReader ff(patch_fn);
patch_rom(static_cast<Reader*>(&ff));
}
#ifdef GZIP_SUPPORT
}
#endif
//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(static_cast<Reader*>(&ff));
}
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(static_cast<Writer*>(&ff));
cheat.clear();
}
cart_loaded = false;
return true;
}
Cartridge::Cartridge() {
cart_loaded = false;
base_rom = 0;
rom = 0;
sram = 0;
rom_size = 0;
}
Cartridge::~Cartridge() {
if(cart_loaded == true) {
unload();
}
}

68
src/cart/cart.h Normal file
View File

@@ -0,0 +1,68 @@
class Cartridge {
public:
bool cart_loaded;
char rom_fn[4096], sram_fn[4096], cheat_fn[4096], patch_fn[4096];
uint8 *base_rom, *rom, *sram;
uint32 rom_size;
enum {
//header fields
CART_NAME = 0x00,
MAPPER = 0x15,
ROM_TYPE = 0x16,
ROM_SIZE = 0x17,
SRAM_SIZE = 0x18,
REGION = 0x19,
LICENSE = 0x1a,
VERSION = 0x1b,
ICKSUM = 0x1c,
CKSUM = 0x1e,
//regions
NTSC = 0,
PAL = 1,
//memory mappers
LOROM = 0x20,
HIROM = 0x21,
EXLOROM = 0x22,
EXHIROM = 0x25,
};
struct {
uint32 crc32;
uint32 header_index;
char name[32];
uint32 rom_size;
uint32 sram_size;
bool region;
uint32 mapper;
//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 dsp2;
bool obc1;
} cart;
void load_rom(Reader *rf);
void patch_rom(Reader *rf);
void load_sram();
void save_sram();
void find_header();
void read_header();
bool loaded() { return cart_loaded; }
bool load(const char *fn);
bool unload();
Cartridge();
~Cartridge();
};
extern Cartridge cartridge;

334
src/cheat/cheat.cpp Normal file
View File

@@ -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();
}

48
src/cheat/cheat.h Normal file
View File

@@ -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;

197
src/chip/c4/c4.cpp Normal file
View File

@@ -0,0 +1,197 @@
/*
C4 emulation
Used in Rockman X2/X3 (Megaman X2/X3)
Portions (c) anomie, Overload, zsKnight, Nach, byuu
*/
#include "../../base.h"
#include "c4data.cpp"
#include "c4fn.cpp"
#include "c4oam.cpp"
#include "c4ops.cpp"
void C4::init() {}
void C4::enable() {}
uint32 C4::ldr(uint8 r) {
uint16 addr = 0x0080 + (r * 3);
return (reg[addr]) | (reg[addr + 1] << 8) | (reg[addr + 2] << 16);
}
void C4::str(uint8 r, uint32 data) {
uint16 addr = 0x0080 + (r * 3);
reg[addr ] = (data);
reg[addr + 1] = (data >> 8);
reg[addr + 2] = (data >> 16);
}
void C4::mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh) {
int64 rx = x & 0xffffff;
int64 ry = y & 0xffffff;
if(rx & 0x800000)rx |= ~0x7fffff;
if(ry & 0x800000)ry |= ~0x7fffff;
rx *= ry;
rl = (rx) & 0xffffff;
rh = (rx >> 24) & 0xffffff;
}
uint32 C4::sin(uint32 rx) {
r0 = rx & 0x1ff;
if(r0 & 0x100)r0 ^= 0x1ff;
if(r0 & 0x080)r0 ^= 0x0ff;
if(rx & 0x100) {
return sin_table[r0 + 0x80];
} else {
return sin_table[r0];
}
}
uint32 C4::cos(uint32 rx) {
return sin(rx + 0x080);
}
void C4::immediate_reg(uint32 start) {
r0 = ldr(0);
for(uint32 i=start;i<48;i++) {
if((r0 & 0x0fff) < 0x0c00) {
ram[r0 & 0x0fff] = immediate_data[i];
}
r0++;
}
str(0, r0);
}
void C4::transfer_data() {
uint32 src;
uint16 dest, count;
src = (reg[0x40]) | (reg[0x41] << 8) | (reg[0x42] << 16);
count = (reg[0x43]) | (reg[0x44] << 8);
dest = (reg[0x45]) | (reg[0x46] << 8);
for(uint32 i=0;i<count;i++) {
write(dest++, r_mem->read(src++));
}
}
void C4::write(uint16 addr, uint8 data) {
addr &= 0x1fff;
if(addr < 0x0c00) {
//ram
ram[addr] = data;
return;
}
if(addr < 0x1f00) {
//unmapped
return;
}
//command register
reg[addr & 0xff] = data;
if(addr == 0x1f47) {
//memory transfer
transfer_data();
return;
}
if(addr == 0x1f4f) {
//c4 command
if(reg[0x4d] == 0x0e && !(data & 0xc3)) {
//c4 test command
reg[0x80] = data >> 2;
return;
}
switch(data) {
case 0x00:op00();break;
case 0x01:op01();break;
case 0x05:op05();break;
case 0x0d:op0d();break;
case 0x10:op10();break;
case 0x13:op13();break;
case 0x15:op15();break;
case 0x1f:op1f();break;
case 0x22:op22();break;
case 0x25:op25();break;
case 0x2d:op2d();break;
case 0x40:op40();break;
case 0x54:op54();break;
case 0x5c:op5c();break;
case 0x5e:op5e();break;
case 0x60:op60();break;
case 0x62:op62();break;
case 0x64:op64();break;
case 0x66:op66();break;
case 0x68:op68();break;
case 0x6a:op6a();break;
case 0x6c:op6c();break;
case 0x6e:op6e();break;
case 0x70:op70();break;
case 0x72:op72();break;
case 0x74:op74();break;
case 0x76:op76();break;
case 0x78:op78();break;
case 0x7a:op7a();break;
case 0x7c:op7c();break;
case 0x89:op89();break;
}
}
}
void C4::writeb(uint16 addr, uint8 data) {
write(addr, data);
}
void C4::writew(uint16 addr, uint16 data) {
write(addr, data);
write(addr + 1, data >> 8);
}
void C4::writel(uint16 addr, uint32 data) {
write(addr, data);
write(addr + 1, data >> 8);
write(addr + 2, data >> 16);
}
uint8 C4::read(uint16 addr) {
addr &= 0x1fff;
if(addr < 0x0c00) {
return ram[addr];
}
if(addr >= 0x1f00) {
return reg[addr & 0xff];
}
return r_cpu->regs.mdr;
}
uint8 C4::readb(uint16 addr) {
return read(addr);
}
uint16 C4::readw(uint16 addr) {
return read(addr) | (read(addr + 1) << 8);
}
uint32 C4::readl(uint16 addr) {
return read(addr) | (read(addr + 1) << 8) + (read(addr + 2) << 16);
}
void C4::power() {
reset();
}
void C4::reset() {
memset(ram, 0, 0x0c00);
memset(reg, 0, 0x0100);
}
C4::C4() {}

94
src/chip/c4/c4.h Normal file
View File

@@ -0,0 +1,94 @@
class C4 {
private:
uint8 ram[0x0c00];
uint8 reg[0x0100];
uint32 r0, r1, r2, r3, r4, r5, r6, r7,
r8, r9, r10, r11, r12, r13, r14, r15;
static const uint8 immediate_data[48];
static const uint16 wave_data[40];
static const uint32 sin_table[256];
static const int16 SinTable[512];
static const int16 CosTable[512];
int16 C4WFXVal, C4WFYVal, C4WFZVal, C4WFX2Val, C4WFY2Val, C4WFDist, C4WFScale;
int16 C41FXVal, C41FYVal, C41FAngleRes, C41FDist, C41FDistVal;
double tanval;
double c4x,c4y,c4z, c4x2,c4y2,c4z2;
void C4TransfWireFrame();
void C4TransfWireFrame2();
void C4CalcWireFrame();
void C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color);
void C4DrawWireFrame();
void C4DoScaleRotate(int row_padding);
public:
uint32 ldr(uint8 r);
void str(uint8 r, uint32 data);
void mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh);
uint32 sin(uint32 rx);
uint32 cos(uint32 rx);
void transfer_data();
void immediate_reg(uint32 num);
void op00_00();
void op00_03();
void op00_05();
void op00_07();
void op00_08();
void op00_0b();
void op00_0c();
void op00();
void op01();
void op05();
void op0d();
void op10();
void op13();
void op15();
void op1f();
void op22();
void op25();
void op2d();
void op40();
void op54();
void op5c();
void op5e();
void op60();
void op62();
void op64();
void op66();
void op68();
void op6a();
void op6c();
void op6e();
void op70();
void op72();
void op74();
void op76();
void op78();
void op7a();
void op7c();
void op89();
void init();
void enable();
void power();
void reset();
void write (uint16 addr, uint8 data);
void writeb(uint16 addr, uint8 data);
void writew(uint16 addr, uint16 data);
void writel(uint16 addr, uint32 data);
uint8 read (uint16 addr);
uint8 readb(uint16 addr);
uint16 readw(uint16 addr);
uint32 readl(uint16 addr);
C4();
};

183
src/chip/c4/c4data.cpp Normal file
View File

@@ -0,0 +1,183 @@
const uint8 C4::immediate_data[48] = {
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f,
0x00, 0x80, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff,
0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00
};
const uint16 C4::wave_data[40] = {
0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020a, 0x020c, 0x020e,
0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e,
0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060a, 0x060c, 0x060e,
0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080a, 0x080c, 0x080e
};
const uint32 C4::sin_table[256] = {
0x000000, 0x000324, 0x000648, 0x00096c, 0x000c8f, 0x000fb2, 0x0012d5, 0x0015f6,
0x001917, 0x001c37, 0x001f56, 0x002273, 0x002590, 0x0028aa, 0x002bc4, 0x002edb,
0x0031f1, 0x003505, 0x003817, 0x003b26, 0x003e33, 0x00413e, 0x004447, 0x00474d,
0x004a50, 0x004d50, 0x00504d, 0x005347, 0x00563e, 0x005931, 0x005c22, 0x005f0e,
0x0061f7, 0x0064dc, 0x0067bd, 0x006a9b, 0x006d74, 0x007049, 0x007319, 0x0075e5,
0x0078ad, 0x007b70, 0x007e2e, 0x0080e7, 0x00839c, 0x00864b, 0x0088f5, 0x008b9a,
0x008e39, 0x0090d3, 0x009368, 0x0095f6, 0x00987f, 0x009b02, 0x009d7f, 0x009ff6,
0x00a267, 0x00a4d2, 0x00a736, 0x00a994, 0x00abeb, 0x00ae3b, 0x00b085, 0x00b2c8,
0x00b504, 0x00b73a, 0x00b968, 0x00bb8f, 0x00bdae, 0x00bfc7, 0x00c1d8, 0x00c3e2,
0x00c5e4, 0x00c7de, 0x00c9d1, 0x00cbbb, 0x00cd9f, 0x00cf7a, 0x00d14d, 0x00d318,
0x00d4db, 0x00d695, 0x00d848, 0x00d9f2, 0x00db94, 0x00dd2d, 0x00debe, 0x00e046,
0x00e1c5, 0x00e33c, 0x00e4aa, 0x00e60f, 0x00e76b, 0x00e8bf, 0x00ea09, 0x00eb4b,
0x00ec83, 0x00edb2, 0x00eed8, 0x00eff5, 0x00f109, 0x00f213, 0x00f314, 0x00f40b,
0x00f4fa, 0x00f5de, 0x00f6ba, 0x00f78b, 0x00f853, 0x00f912, 0x00f9c7, 0x00fa73,
0x00fb14, 0x00fbac, 0x00fc3b, 0x00fcbf, 0x00fd3a, 0x00fdab, 0x00fe13, 0x00fe70,
0x00fec4, 0x00ff0e, 0x00ff4e, 0x00ff84, 0x00ffb1, 0x00ffd3, 0x00ffec, 0x00fffb,
0x000000, 0xfffcdb, 0xfff9b7, 0xfff693, 0xfff370, 0xfff04d, 0xffed2a, 0xffea09,
0xffe6e8, 0xffe3c8, 0xffe0a9, 0xffdd8c, 0xffda6f, 0xffd755, 0xffd43b, 0xffd124,
0xffce0e, 0xffcafa, 0xffc7e8, 0xffc4d9, 0xffc1cc, 0xffbec1, 0xffbbb8, 0xffb8b2,
0xffb5af, 0xffb2af, 0xffafb2, 0xffacb8, 0xffa9c1, 0xffa6ce, 0xffa3dd, 0xffa0f1,
0xff9e08, 0xff9b23, 0xff9842, 0xff9564, 0xff928b, 0xff8fb6, 0xff8ce6, 0xff8a1a,
0xff8752, 0xff848f, 0xff81d1, 0xff7f18, 0xff7c63, 0xff79b4, 0xff770a, 0xff7465,
0xff71c6, 0xff6f2c, 0xff6c97, 0xff6a09, 0xff6780, 0xff64fd, 0xff6280, 0xff6009,
0xff5d98, 0xff5b2d, 0xff58c9, 0xff566b, 0xff5414, 0xff51c4, 0xff4f7a, 0xff4d37,
0xff4afb, 0xff48c5, 0xff4697, 0xff4470, 0xff4251, 0xff4038, 0xff3e27, 0xff3c1e,
0xff3a1b, 0xff3821, 0xff362e, 0xff3444, 0xff3260, 0xff3085, 0xff2eb2, 0xff2ce7,
0xff2b24, 0xff296a, 0xff27b7, 0xff260d, 0xff246b, 0xff22d2, 0xff2141, 0xff1fb9,
0xff1e3a, 0xff1cc3, 0xff1b55, 0xff19f0, 0xff1894, 0xff1740, 0xff15f6, 0xff14b4,
0xff137c, 0xff124d, 0xff1127, 0xff100a, 0xff0ef6, 0xff0dec, 0xff0ceb, 0xff0bf4,
0xff0b05, 0xff0a21, 0xff0945, 0xff0874, 0xff07ac, 0xff06ed, 0xff0638, 0xff058d,
0xff04eb, 0xff0453, 0xff03c4, 0xff0340, 0xff02c5, 0xff0254, 0xff01ec, 0xff018f,
0xff013b, 0xff00f1, 0xff00b1, 0xff007b, 0xff004e, 0xff002c, 0xff0013, 0xff0004
};
const int16 C4::SinTable[512] = {
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765,
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402
};
const int16 C4::CosTable[512] = {
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402,
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765
};

242
src/chip/c4/c4fn.cpp Normal file
View File

@@ -0,0 +1,242 @@
#include <math.h>
#define Tan(a) (CosTable[a] ? ((((int32)SinTable[a]) << 16) / CosTable[a]) : 0x80000000)
#define sar(b, n) ((b) >> (n))
#ifdef PI
#undef PI
#endif
#define PI 3.1415926535897932384626433832795
//Wireframe Helpers
void C4::C4TransfWireFrame() {
c4x = (double)C4WFXVal;
c4y = (double)C4WFYVal;
c4z = (double)C4WFZVal - 0x95;
//Rotate X
tanval = -(double)C4WFX2Val * PI * 2 / 128;
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
//Rotate Y
tanval = -(double)C4WFY2Val * PI * 2 / 128;
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
//Rotate Z
tanval = -(double)C4WFDist * PI * 2 / 128;
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
//Scale
C4WFXVal = (int16)(c4x * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
C4WFYVal = (int16)(c4y * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
}
void C4::C4CalcWireFrame() {
C4WFXVal = C4WFX2Val - C4WFXVal;
C4WFYVal = C4WFY2Val - C4WFYVal;
if(abs(C4WFXVal) > abs(C4WFYVal)) {
C4WFDist = abs(C4WFXVal) + 1;
C4WFYVal = (256 * (long)C4WFYVal) / abs(C4WFXVal);
C4WFXVal = (C4WFXVal < 0) ? -256 : 256;
} else if(C4WFYVal != 0) {
C4WFDist = abs(C4WFYVal) + 1;
C4WFXVal = (256 * (long)C4WFXVal) / abs(C4WFYVal);
C4WFYVal = (C4WFYVal < 0) ? -256 : 256;
} else {
C4WFDist = 0;
}
}
void C4::C4TransfWireFrame2() {
c4x = (double)C4WFXVal;
c4y = (double)C4WFYVal;
c4z = (double)C4WFZVal;
//Rotate X
tanval = -(double)C4WFX2Val * PI * 2 / 128;
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
//Rotate Y
tanval = -(double)C4WFY2Val * PI * 2 / 128;
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
//Rotate Z
tanval = -(double)C4WFDist * PI * 2 / 128;
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
//Scale
C4WFXVal = (int16)(c4x * C4WFScale / 0x100);
C4WFYVal = (int16)(c4y * C4WFScale / 0x100);
}
void C4::C4DrawWireFrame() {
uint32 line = readl(0x1f80);
uint32 point1, point2;
int16 X1, Y1, Z1;
int16 X2, Y2, Z2;
uint8 Color;
for(int32 i = ram[0x0295]; i > 0; i--, line += 5) {
if(r_mem->read(line) == 0xff && r_mem->read(line + 1) == 0xff) {
int32 tmp = line - 5;
while(r_mem->read(tmp + 2) == 0xff && r_mem->read(tmp + 3) == 0xff && (tmp + 2) >= 0) { tmp -= 5; }
point1 = (read(0x1f82) << 16) | (r_mem->read(tmp + 2) << 8) | r_mem->read(tmp + 3);
} else {
point1 = (read(0x1f82) << 16) | (r_mem->read(line) << 8) | r_mem->read(line + 1);
}
point2 = (read(0x1f82) << 16) | (r_mem->read(line + 2) << 8) | r_mem->read(line + 3);
X1=(r_mem->read(point1 + 0) << 8) | r_mem->read(point1 + 1);
Y1=(r_mem->read(point1 + 2) << 8) | r_mem->read(point1 + 3);
Z1=(r_mem->read(point1 + 4) << 8) | r_mem->read(point1 + 5);
X2=(r_mem->read(point2 + 0) << 8) | r_mem->read(point2 + 1);
Y2=(r_mem->read(point2 + 2) << 8) | r_mem->read(point2 + 3);
Z2=(r_mem->read(point2 + 4) << 8) | r_mem->read(point2 + 5);
Color = r_mem->read(line + 4);
C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color);
}
}
void C4::C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color) {
//Transform coordinates
C4WFXVal = (int16)X1;
C4WFYVal = (int16)Y1;
C4WFZVal = Z1;
C4WFScale = read(0x1f90);
C4WFX2Val = read(0x1f86);
C4WFY2Val = read(0x1f87);
C4WFDist = read(0x1f88);
C4TransfWireFrame2();
X1 = (C4WFXVal + 48) << 8;
Y1 = (C4WFYVal + 48) << 8;
C4WFXVal = (int16)X2;
C4WFYVal = (int16)Y2;
C4WFZVal = Z2;
C4TransfWireFrame2();
X2 = (C4WFXVal + 48) << 8;
Y2 = (C4WFYVal + 48) << 8;
//Get line info
C4WFXVal = (int16)(X1 >> 8);
C4WFYVal = (int16)(Y1 >> 8);
C4WFX2Val = (int16)(X2 >> 8);
C4WFY2Val = (int16)(Y2 >> 8);
C4CalcWireFrame();
X2 = (int16)C4WFXVal;
Y2 = (int16)C4WFYVal;
//Render line
for(int32 i = C4WFDist ? C4WFDist : 1; i > 0; i--) {
if(X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000) {
uint16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2;
uint8 bit = 0x80 >> ((X1 >> 8) & 7);
ram[addr + 0x300] &= ~bit;
ram[addr + 0x301] &= ~bit;
if(Color & 1) { ram[addr + 0x300] |= bit; }
if(Color & 2) { ram[addr + 0x301] |= bit; }
}
X1 += X2;
Y1 += Y2;
}
}
void C4::C4DoScaleRotate(int row_padding) {
int16 A, B, C, D;
//Calculate matrix
int32 XScale = readw(0x1f8f);
int32 YScale = readw(0x1f92);
if(XScale & 0x8000)XScale = 0x7fff;
if(YScale & 0x8000)YScale = 0x7fff;
if(readw(0x1f80) == 0) { //no rotation
A = (int16)XScale;
B = 0;
C = 0;
D = (int16)YScale;
} else if(readw(0x1f80) == 128) { //90 degree rotation
A = 0;
B = (int16)(-YScale);
C = (int16)XScale;
D = 0;
} else if(readw(0x1f80) == 256) { //180 degree rotation
A = (int16)(-XScale);
B = 0;
C = 0;
D = (int16)(-YScale);
} else if(readw(0x1f80) == 384) { //270 degree rotation
A = 0;
B = (int16)YScale;
C = (int16)(-XScale);
D = 0;
} else {
A = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * XScale, 15);
B = (int16)(-sar(SinTable[readw(0x1f80) & 0x1ff] * YScale, 15));
C = (int16) sar(SinTable[readw(0x1f80) & 0x1ff] * XScale, 15);
D = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * YScale, 15);
}
//Calculate Pixel Resolution
uint8 w = read(0x1f89) & ~7;
uint8 h = read(0x1f8c) & ~7;
//Clear the output RAM
memset(ram, 0, (w + row_padding / 4) * h / 2);
int32 Cx = (int16)readw(0x1f83);
int32 Cy = (int16)readw(0x1f86);
//Calculate start position (i.e. (Ox, Oy) = (0, 0))
//The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in
//the function. We do Cx*A etc normally because the matrix parameters
//already have the fractional parts.
int32 LineX = (Cx << 12) - Cx * A - Cx * B;
int32 LineY = (Cy << 12) - Cy * C - Cy * D;
//Start loop
uint32 X, Y;
uint8 byte;
int32 outidx = 0;
uint8 bit = 0x80;
for(int32 y = 0; y < h; y++) {
X = LineX;
Y = LineY;
for(int32 x = 0; x < w; x++) {
if((X >> 12) >= w || (Y >> 12) >= h) {
byte = 0;
} else {
uint32 addr = (Y >> 12) * w + (X >> 12);
byte = read(0x600 + (addr >> 1));
if(addr & 1) { byte >>= 4; }
}
//De-bitplanify
if(byte & 1) { ram[outidx ] |= bit; }
if(byte & 2) { ram[outidx + 1] |= bit; }
if(byte & 4) { ram[outidx + 16] |= bit; }
if(byte & 8) { ram[outidx + 17] |= bit; }
bit >>= 1;
if(!bit) {
bit = 0x80;
outidx += 32;
}
X += A; //Add 1 to output x => add an A and a C
Y += C;
}
outidx += 2 + row_padding;
if(outidx & 0x10) {
outidx &= ~0x10;
} else {
outidx -= w * 4 + row_padding;
}
LineX += B; //Add 1 to output y => add a B and a D
LineY += D;
}
}

224
src/chip/c4/c4oam.cpp Normal file
View File

@@ -0,0 +1,224 @@
//Build OAM
void C4::op00_00() {
uint32 oamptr = ram[0x626] << 2;
for(int32 i=0x1fd;i>oamptr && i>=0;i-=4) {
//clear oam-to-be
if(i >= 0)ram[i] = 0xe0;
}
uint16 globalx, globaly;
uint32 oamptr2;
int16 sprx, spry;
uint8 sprname, sprattr;
uint8 sprcount;
globalx = readw(0x621);
globaly = readw(0x623);
oamptr2 = 0x200 + (ram[0x626] >> 2);
if(!ram[0x620])return;
sprcount = 128 - ram[0x626];
uint8 offset = (ram[0x626] & 3) * 2;
for(int pri=0x30;pri>=0;pri-=0x10) {
uint32 srcptr = 0x220;
for(int i=ram[0x620];i>0 && sprcount>0;i--, srcptr+=16) {
if((ram[srcptr + 4] & 0x30) != pri)continue;
sprx = readw(srcptr) - globalx;
spry = readw(srcptr + 2) - globaly;
sprname = ram[srcptr + 5];
sprattr = ram[srcptr + 4] | ram[srcptr + 6];
uint32 spraddr = readl(srcptr + 7);
if(r_mem->read(spraddr)) {
int16 x, y;
for(int sprcnt=r_mem->read(spraddr++);sprcnt>0 && sprcount>0;sprcnt--, spraddr+=4) {
x = (int8)r_mem->read(spraddr + 1);
if(sprattr & 0x40) {
x = -x - ((r_mem->read(spraddr) & 0x20) ? 16 : 8);
}
x += sprx;
if(x >= -16 && x <= 272) {
y = (int8)r_mem->read(spraddr + 2);
if(sprattr & 0x80) {
y = -y - ((r_mem->read(spraddr) & 0x20) ? 16 : 8);
}
y += spry;
if(y >= -16 && y <= 224) {
ram[oamptr ] = (uint8)x;
ram[oamptr + 1] = (uint8)y;
ram[oamptr + 2] = sprname + r_mem->read(spraddr + 3);
ram[oamptr + 3] = sprattr ^ (r_mem->read(spraddr) & 0xc0);
ram[oamptr2] &= ~(3 << offset);
if(x & 0x100)ram[oamptr2] |= 1 << offset;
if(r_mem->read(spraddr) & 0x20)ram[oamptr2] |= 2 << offset;
oamptr += 4;
sprcount--;
offset = (offset + 2) & 6;
if(!offset)oamptr2++;
}
}
}
} else if(sprcount > 0) {
ram[oamptr ] = (uint8)sprx;
ram[oamptr + 1] = (uint8)spry;
ram[oamptr + 2] = sprname;
ram[oamptr + 3] = sprattr;
ram[oamptr2] &= ~(3 << offset);
if(sprx & 0x100)ram[oamptr2] |= 3 << offset;
else ram[oamptr2] |= 2 << offset;
oamptr += 4;
sprcount--;
offset = (offset + 2) & 6;
if(!offset)oamptr2++;
}
}
}
}
//Scale and Rotate
void C4::op00_03() {
C4DoScaleRotate(0);
}
//Transform Lines
void C4::op00_05() {
C4WFX2Val = read(0x1f83);
C4WFY2Val = read(0x1f86);
C4WFDist = read(0x1f89);
C4WFScale = read(0x1f8c);
//Transform Vertices
uint32 ptr = 0;
for(int32 i = readw(0x1f80); i > 0; i--, ptr += 0x10) {
C4WFXVal = readw(ptr + 1);
C4WFYVal = readw(ptr + 5);
C4WFZVal = readw(ptr + 9);
C4TransfWireFrame();
//Displace
writew(ptr + 1, C4WFXVal + 0x80);
writew(ptr + 5, C4WFYVal + 0x50);
}
writew(0x600, 23);
writew(0x602, 0x60);
writew(0x605, 0x40);
writew(0x600 + 8, 23);
writew(0x602 + 8, 0x60);
writew(0x605 + 8, 0x40);
ptr = 0xb02;
uint32 ptr2 = 0;
for(int32 i = readw(0xb00); i > 0; i--, ptr += 2, ptr2 += 8) {
C4WFXVal = readw((read(ptr + 0) << 4) + 1);
C4WFYVal = readw((read(ptr + 0) << 4) + 5);
C4WFX2Val = readw((read(ptr + 1) << 4) + 1);
C4WFY2Val = readw((read(ptr + 1) << 4) + 5);
C4CalcWireFrame();
writew(ptr2 + 0x600, C4WFDist ? C4WFDist : 1);
writew(ptr2 + 0x602, C4WFXVal);
writew(ptr2 + 0x605, C4WFYVal);
}
}
//Scale and Rotate
void C4::op00_07() {
C4DoScaleRotate(64);
}
//Draw Wireframe
void C4::op00_08() {
C4DrawWireFrame();
}
//Disintegrate
void C4::op00_0b() {
uint8 width, height;
uint32 startx, starty;
uint32 srcptr;
uint32 x, y;
int32 scalex, scaley;
int32 cx, cy;
int32 i, j;
width = read(0x1f89);
height = read(0x1f8c);
cx = readw(0x1f80);
cy = readw(0x1f83);
scalex = (int16)readw(0x1f86);
scaley = (int16)readw(0x1f8f);
startx = -cx * scalex + (cx << 8);
starty = -cy * scaley + (cy << 8);
srcptr = 0x600;
for(i = 0; i < (width * height) >> 1; i++) {
write(i, 0);
}
for(y = starty, i = 0;i < height; i++, y += scaley) {
for(x = startx, j = 0;j < width; j++, x += scalex) {
if((x >> 8) < width && (y >> 8) < height && (y >> 8) * width + (x >> 8) < 0x2000) {
uint8 pixel = (j & 1) ? (ram[srcptr] >> 4) : (ram[srcptr]);
int32 index = (y >> 11) * width * 4 + (x >> 11) * 32 + ((y >> 8) & 7) * 2;
uint8 mask = 0x80 >> ((x >> 8) & 7);
if(pixel & 1)ram[index ] |= mask;
if(pixel & 2)ram[index + 1] |= mask;
if(pixel & 4)ram[index + 16] |= mask;
if(pixel & 8)ram[index + 17] |= mask;
}
if(j & 1)srcptr++;
}
}
}
//Bitplane Wave
void C4::op00_0c() {
uint32 destptr = 0;
uint32 waveptr = read(0x1f83);
uint16 mask1 = 0xc0c0;
uint16 mask2 = 0x3f3f;
int32 i, j;
int16 height, temp;
for(j = 0; j < 0x10; j++) {
do {
height = -((int8)ram[waveptr + 0xb00]) - 16;
for(i = 0; i < 40; i++) {
temp = readw(destptr + wave_data[i]) & mask2;
if(height >= 0) {
if(height < 8) {
temp |= mask1 & readw(0xa00 + height * 2);
} else {
temp |= mask1 & 0xff00;
}
}
writew(destptr + wave_data[i], temp);
height++;
}
waveptr = (waveptr + 1) & 0x7f;
mask1 = (mask1 >> 2) | (mask1 << 6);
mask2 = (mask2 >> 2) | (mask2 << 6);
} while(mask1 != 0xc0c0);
destptr += 16;
do {
height = -((int8)ram[waveptr + 0xb00]) - 16;
for(i = 0; i < 40; i++) {
temp = readw(destptr + wave_data[i]) & mask2;
if(height >= 0) {
if(height < 8) {
temp |= mask1 & readw(0xa10 + height * 2);
} else {
temp |= mask1 & 0xff00;
}
writew(destptr + wave_data[i], temp);
height++;
}
waveptr = (waveptr + 1) & 0x7f;
mask1 = (mask1 >> 2) | (mask1 << 6);
mask2 = (mask2 >> 2) | (mask2 << 6);
}
} while(mask1 != 0xc0c0);
destptr += 16;
}
}

222
src/chip/c4/c4ops.cpp Normal file
View File

@@ -0,0 +1,222 @@
//Sprite Functions
void C4::op00() {
switch(reg[0x4d]) {
case 0x00:op00_00();break;
case 0x03:op00_03();break;
case 0x05:op00_05();break;
case 0x07:op00_07();break;
case 0x08:op00_08();break;
case 0x0b:op00_0b();break;
case 0x0c:op00_0c();break;
}
}
//Draw Wireframe
void C4::op01() {
memset(ram + 0x300, 0, 2304);
C4DrawWireFrame();
}
//Propulsion
void C4::op05() {
int32 temp = 0x10000;
if(readw(0x1f83)) {
temp = sar((temp / readw(0x1f83)) * readw(0x1f81), 8);
}
writew(0x1f80, temp);
}
//Set Vector length
void C4::op0d() {
C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83);
C41FDistVal = readw(0x1f86);
tanval = sqrt(((double)C41FYVal) * ((double)C41FYVal) + ((double)C41FXVal) * ((double)C41FXVal));
tanval = (double)C41FDistVal / tanval;
C41FYVal = (int16)(((double)C41FYVal * tanval) * 0.99);
C41FXVal = (int16)(((double)C41FXVal * tanval) * 0.98);
writew(0x1f89, C41FXVal);
writew(0x1f8c, C41FYVal);
}
//Triangle
void C4::op10() {
r0 = ldr(0);
r1 = ldr(1);
r4 = r0 & 0x1ff;
if(r1 & 0x8000)r1 |= ~0x7fff;
mul(cos(r4), r1, r5, r2);
r5 = (r5 >> 16) & 0xff;
r2 = (r2 << 8) + r5;
mul(sin(r4), r1, r5, r3);
r5 = (r5 >> 16) & 0xff;
r3 = (r3 << 8) + r5;
str(0, r0);
str(1, r1);
str(2, r2);
str(3, r3);
str(4, r4);
str(5, r5);
}
//Triangle
void C4::op13() {
r0 = ldr(0);
r1 = ldr(1);
r4 = r0 & 0x1ff;
mul(cos(r4), r1, r5, r2);
r5 = (r5 >> 8) & 0xffff;
r2 = (r2 << 16) + r5;
mul(sin(r4), r1, r5, r3);
r5 = (r5 >> 8) & 0xffff;
r3 = (r3 << 16) + r5;
str(0, r0);
str(1, r1);
str(2, r2);
str(3, r3);
str(4, r4);
str(5, r5);
}
//Pythagorean
void C4::op15() {
C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83);
C41FDist = (int16)sqrt((double)C41FXVal * (double)C41FXVal + (double)C41FYVal * (double)C41FYVal);
writew(0x1f80, C41FDist);
}
//Calculate distance
void C4::op1f() {
C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83);
if(!C41FXVal) {
C41FAngleRes = (C41FYVal > 0) ? 0x080 : 0x180;
} else {
tanval = ((double)C41FYVal) / ((double)C41FXVal);
C41FAngleRes = (short)(atan(tanval) / (PI * 2) * 512);
C41FAngleRes = C41FAngleRes;
if(C41FXVal < 0) {
C41FAngleRes += 0x100;
}
C41FAngleRes &= 0x1ff;
}
writew(0x1f86, C41FAngleRes);
}
//Trapezoid
void C4::op22() {
int16 angle1 = readw(0x1f8c) & 0x1ff;
int16 angle2 = readw(0x1f8f) & 0x1ff;
int32 tan1 = Tan(angle1);
int32 tan2 = Tan(angle2);
int16 y = readw(0x1f83) - readw(0x1f89);
int16 left, right;
for(int32 j = 0; j < 225; j++, y++) {
if(y >= 0) {
left = sar((int32)tan1 * y, 16) - readw(0x1f80) + readw(0x1f86);
right = sar((int32)tan2 * y, 16) - readw(0x1f80) + readw(0x1f86) + readw(0x1f93);
if(left < 0 && right < 0) {
left = 1;
right = 0;
} else if(left < 0) {
left = 0;
} else if(right < 0) {
right = 0;
}
if(left > 255 && right > 255) {
left = 255;
right = 254;
} else if(left > 255) {
left = 255;
} else if(right > 255) {
right = 255;
}
} else {
left = 1;
right = 0;
}
ram[j + 0x800] = (uint8)left;
ram[j + 0x900] = (uint8)right;
}
}
//Multiply
void C4::op25() {
r0 = ldr(0);
r1 = ldr(1);
mul(r0, r1, r0, r1);
str(0, r0);
str(1, r1);
}
//Transform Coords
void C4::op2d() {
C4WFXVal = readw(0x1f81);
C4WFYVal = readw(0x1f84);
C4WFZVal = readw(0x1f87);
C4WFX2Val = read (0x1f89);
C4WFY2Val = read (0x1f8a);
C4WFDist = read (0x1f8b);
C4WFScale = readw(0x1f90);
C4TransfWireFrame2();
writew(0x1f80, C4WFXVal);
writew(0x1f83, C4WFYVal);
}
//Sum
void C4::op40() {
r0 = 0;
for(uint32 i=0;i<0x800;i++) {
r0 += ram[i];
}
str(0, r0);
}
//Square
void C4::op54() {
r0 = ldr(0);
mul(r0, r0, r1, r2);
str(1, r1);
str(2, r2);
}
//Immediate Register
void C4::op5c() {
str(0, 0x000000);
immediate_reg(0);
}
//Immediate Register (Multiple)
void C4::op5e() { immediate_reg( 0); }
void C4::op60() { immediate_reg( 3); }
void C4::op62() { immediate_reg( 6); }
void C4::op64() { immediate_reg( 9); }
void C4::op66() { immediate_reg(12); }
void C4::op68() { immediate_reg(15); }
void C4::op6a() { immediate_reg(18); }
void C4::op6c() { immediate_reg(21); }
void C4::op6e() { immediate_reg(24); }
void C4::op70() { immediate_reg(27); }
void C4::op72() { immediate_reg(30); }
void C4::op74() { immediate_reg(33); }
void C4::op76() { immediate_reg(36); }
void C4::op78() { immediate_reg(39); }
void C4::op7a() { immediate_reg(42); }
void C4::op7c() { immediate_reg(45); }
//Immediate ROM
void C4::op89() {
str(0, 0x054336);
str(1, 0xffffff);
}

133
src/chip/dsp2/dsp2.cpp Normal file
View File

@@ -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() {}

40
src/chip/dsp2/dsp2.h Normal file
View File

@@ -0,0 +1,40 @@
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();
};

173
src/chip/dsp2/dsp2_op.cpp Normal file
View File

@@ -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];
}
}

88
src/chip/obc1/obc1.cpp Normal file
View File

@@ -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() {}

18
src/chip/obc1/obc1.h Normal file
View File

@@ -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();
};

91
src/chip/sdd1/sdd1.cpp Normal file
View File

@@ -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() {}

30
src/chip/sdd1/sdd1.h Normal file
View File

@@ -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();
};

447
src/chip/sdd1/sdd1emu.cpp Normal file
View File

@@ -0,0 +1,447 @@
/************************************************************************
S-DD1'algorithm emulation code
------------------------------
Author: Andreas Naive
Date: August 2003
Last update: October 2004
This code is Public Domain. There is no copyright holded by the author.
Said this, the author wish to explicitly emphasize his inalienable moral rights
over this piece of intelectual work and the previous research that made it
possible, as recognized by most of the copyright laws around the world.
This code is provided 'as-is', with no warranty, expressed or implied.
No responsability is assumed by the author in connection with it.
The author is greatly indebted with The Dumper, without whose help and
patience providing him with real S-DD1 data the research would have never been
possible. He also wish to note that in the very beggining of his research,
Neviksti had done some steps in the right direction. By last, the author is
indirectly indebted to all the people that worked and contributed in the
S-DD1 issue in the past.
An algorithm's documentation is available as a separate document.
The implementation is obvious when the algorithm is
understood.
************************************************************************/
#define SDD1_read(__addr) (r_mem->read(__addr))
////////////////////////////////////////////////////
void SDD1_IM::prepareDecomp(uint32 in_buf) {
byte_ptr=in_buf;
bit_count=4;
}
////////////////////////////////////////////////////
uint8 SDD1_IM::getCodeword(uint8 code_len) {
uint8 codeword;
uint8 comp_count;
codeword = (SDD1_read(byte_ptr))<<bit_count;
++bit_count;
if (codeword & 0x80) {
codeword |= SDD1_read(byte_ptr+1)>>(9-bit_count);
bit_count+=code_len;
}
if (bit_count & 0x08) {
byte_ptr++;
bit_count&=0x07;
}
return codeword;
}
//////////////////////////////////////////////////////
SDD1_GCD::SDD1_GCD(SDD1_IM *associatedIM) :
IM(associatedIM)
{
}
//////////////////////////////////////////////////////
void SDD1_GCD::getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind) {
const uint8 run_count[] = {
0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00,
0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00,
0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01,
0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00,
0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03,
0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01,
0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02,
0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00,
0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07,
0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03,
0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05,
0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01,
0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06,
0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02,
0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04,
0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00,
0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f,
0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07,
0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b,
0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03,
0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d,
0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05,
0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09,
0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01,
0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e,
0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06,
0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a,
0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02,
0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c,
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04,
0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00,
};
uint8 codeword=IM->getCodeword(code_num);
if (codeword & 0x80) {
*LPSind=1;
*MPScount=run_count[codeword>>(code_num^0x07)];
}
else {
*MPScount=(1<<code_num);
}
}
///////////////////////////////////////////////////////
SDD1_BG::SDD1_BG(SDD1_GCD *associatedGCD, uint8 code) :
GCD(associatedGCD), code_num(code)
{
}
///////////////////////////////////////////////
void SDD1_BG::prepareDecomp(void) {
MPScount=0;
LPSind=0;
}
//////////////////////////////////////////////
uint8 SDD1_BG::getBit(bool8 *endOfRun) {
uint8 bit;
if (!(MPScount || LPSind)) GCD->getRunCount(code_num, &MPScount, &LPSind);
if (MPScount) {
bit=0;
MPScount--;
}
else {
bit=1;
LPSind=0;
}
if (MPScount || LPSind) (*endOfRun)=0;
else (*endOfRun)=1;
return bit;
}
/////////////////////////////////////////////////
SDD1_PEM::SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7) {
BG[0]=associatedBG0;
BG[1]=associatedBG1;
BG[2]=associatedBG2;
BG[3]=associatedBG3;
BG[4]=associatedBG4;
BG[5]=associatedBG5;
BG[6]=associatedBG6;
BG[7]=associatedBG7;
}
/////////////////////////////////////////////////////////
const SDD1_PEM::state SDD1_PEM::evolution_table[]={
{ 0,25,25},
{ 0, 2, 1},
{ 0, 3, 1},
{ 0, 4, 2},
{ 0, 5, 3},
{ 1, 6, 4},
{ 1, 7, 5},
{ 1, 8, 6},
{ 1, 9, 7},
{ 2,10, 8},
{ 2,11, 9},
{ 2,12,10},
{ 2,13,11},
{ 3,14,12},
{ 3,15,13},
{ 3,16,14},
{ 3,17,15},
{ 4,18,16},
{ 4,19,17},
{ 5,20,18},
{ 5,21,19},
{ 6,22,20},
{ 6,23,21},
{ 7,24,22},
{ 7,24,23},
{ 0,26, 1},
{ 1,27, 2},
{ 2,28, 4},
{ 3,29, 8},
{ 4,30,12},
{ 5,31,16},
{ 6,32,18},
{ 7,24,22}
};
//////////////////////////////////////////////////////
void SDD1_PEM::prepareDecomp(void) {
for (uint8 i=0; i<32; i++) {
contextInfo[i].status=0;
contextInfo[i].MPS=0;
}
}
/////////////////////////////////////////////////////////
uint8 SDD1_PEM::getBit(uint8 context) {
bool8 endOfRun;
uint8 bit;
SDD1_ContextInfo *pContInfo=&contextInfo[context];
uint8 currStatus = pContInfo->status;
const state *pState=&SDD1_PEM::evolution_table[currStatus];
uint8 currentMPS=pContInfo->MPS;
bit=(BG[pState->code_num])->getBit(&endOfRun);
if (endOfRun)
if (bit) {
if (!(currStatus & 0xfe)) (pContInfo->MPS)^=0x01;
(pContInfo->status)=pState->nextIfLPS;
}
else
(pContInfo->status)=pState->nextIfMPS;
return bit^currentMPS;
}
//////////////////////////////////////////////////////////////
SDD1_CM::SDD1_CM(SDD1_PEM *associatedPEM) :
PEM(associatedPEM)
{
}
//////////////////////////////////////////////////////////////
void SDD1_CM::prepareDecomp(uint32 first_byte) {
bitplanesInfo = SDD1_read(first_byte) & 0xc0;
contextBitsInfo = SDD1_read(first_byte) & 0x30;
bit_number=0;
for (int i=0; i<8; i++) prevBitplaneBits[i]=0;
switch (bitplanesInfo) {
case 0x00:
currBitplane = 1;
break;
case 0x40:
currBitplane = 7;
break;
case 0x80:
currBitplane = 3;
}
}
/////////////////////////////////////////////////////////////
uint8 SDD1_CM::getBit(void) {
uint8 currContext;
uint16 *context_bits;
switch (bitplanesInfo) {
case 0x00:
currBitplane ^= 0x01;
break;
case 0x40:
currBitplane ^= 0x01;
if (!(bit_number & 0x7f)) currBitplane = ((currBitplane+2) & 0x07);
break;
case 0x80:
currBitplane ^= 0x01;
if (!(bit_number & 0x7f)) currBitplane ^= 0x02;
break;
case 0xc0:
currBitplane = bit_number & 0x07;
}
context_bits = &prevBitplaneBits[currBitplane];
currContext=(currBitplane & 0x01)<<4;
switch (contextBitsInfo) {
case 0x00:
currContext|=((*context_bits & 0x01c0)>>5)|(*context_bits & 0x0001);
break;
case 0x10:
currContext|=((*context_bits & 0x0180)>>5)|(*context_bits & 0x0001);
break;
case 0x20:
currContext|=((*context_bits & 0x00c0)>>5)|(*context_bits & 0x0001);
break;
case 0x30:
currContext|=((*context_bits & 0x0180)>>5)|(*context_bits & 0x0003);
}
uint8 bit=PEM->getBit(currContext);
*context_bits <<= 1;
*context_bits |= bit;
bit_number++;
return bit;
}
//////////////////////////////////////////////////
SDD1_OL::SDD1_OL(SDD1_CM *associatedCM) :
CM(associatedCM)
{
}
///////////////////////////////////////////////////
void SDD1_OL::prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf) {
bitplanesInfo = SDD1_read(first_byte) & 0xc0;
length=out_len;
buffer=out_buf;
}
///////////////////////////////////////////////////
void SDD1_OL::launch(void) {
uint8 i;
uint8 register1, register2;
switch (bitplanesInfo) {
case 0x00:
case 0x40:
case 0x80:
i=1;
do { //if length==0, we output 2^16 bytes
if (!i) {
*(buffer++)=register2;
i=~i;
}
else {
for (register1=register2=0, i=0x80; i; i>>=1) {
if (CM->getBit()) register1 |= i;
if (CM->getBit()) register2 |= i;
}
*(buffer++)=register1;
}
} while (--length);
break;
case 0xc0:
do {
for (register1=0, i=0x01; i; i<<=1) {
if (CM->getBit()) register1 |= i;
}
*(buffer++)=register1;
} while (--length);
}
}
///////////////////////////////////////////////////////
void SDD1emu::decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf) {
IM.prepareDecomp(in_buf);
BG0.prepareDecomp();
BG1.prepareDecomp();
BG2.prepareDecomp();
BG3.prepareDecomp();
BG4.prepareDecomp();
BG5.prepareDecomp();
BG6.prepareDecomp();
BG7.prepareDecomp();
PEM.prepareDecomp();
CM.prepareDecomp(in_buf);
OL.prepareDecomp(in_buf, out_len, out_buf);
OL.launch();
}
////////////////////////////////////////////////////////////
SDD1emu::SDD1emu() :
GCD(&IM),
BG0(&GCD, 0), BG1(&GCD, 1), BG2(&GCD, 2), BG3(&GCD, 3),
BG4(&GCD, 4), BG5(&GCD, 5), BG6(&GCD, 6), BG7(&GCD, 7),
PEM(&BG0, &BG1, &BG2, &BG3, &BG4, &BG5, &BG6, &BG7),
CM(&PEM),
OL(&CM)
{
}
///////////////////////////////////////////////////////////

161
src/chip/sdd1/sdd1emu.h Normal file
View File

@@ -0,0 +1,161 @@
/************************************************************************
S-DD1'algorithm emulation code
------------------------------
Author: Andreas Naive
Date: August 2003
Last update: October 2004
This code is Public Domain. There is no copyright holded by the author.
Said this, the author wish to explicitly emphasize his inalienable moral rights
over this piece of intelectual work and the previous research that made it
possible, as recognized by most of the copyright laws around the world.
This code is provided 'as-is', with no warranty, expressed or implied.
No responsability is assumed by the author in connection with it.
The author is greatly indebted with The Dumper, without whose help and
patience providing him with real S-DD1 data the research would have never been
possible. He also wish to note that in the very beggining of his research,
Neviksti had done some steps in the right direction. By last, the author is
indirectly indebted to all the people that worked and contributed in the
S-DD1 issue in the past.
An algorithm's documentation is available as a separate document.
The implementation is obvious when the algorithm is
understood.
************************************************************************/
class SDD1_IM { //Input Manager
public:
SDD1_IM(void) {}
void prepareDecomp(uint32 in_buf);
uint8 getCodeword(const uint8 code_len);
private:
uint32 byte_ptr;
uint8 bit_count;
};
////////////////////////////////////////////////////
class SDD1_GCD { //Golomb-Code Decoder
public:
SDD1_GCD(SDD1_IM *associatedIM);
void getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind);
private:
SDD1_IM *const IM;
};
//////////////////////////////////////////////////////
class SDD1_BG { // Bits Generator
public:
SDD1_BG(SDD1_GCD *associatedGCD, uint8 code);
void prepareDecomp(void);
uint8 getBit(bool8 *endOfRun);
private:
const uint8 code_num;
uint8 MPScount;
bool8 LPSind;
SDD1_GCD *const GCD;
};
////////////////////////////////////////////////
class SDD1_PEM { //Probability Estimation Module
public:
SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7);
void prepareDecomp(void);
uint8 getBit(uint8 context);
private:
struct state {
uint8 code_num;
uint8 nextIfMPS;
uint8 nextIfLPS;
};
static const state evolution_table[];
struct SDD1_ContextInfo {
uint8 status;
uint8 MPS;
} contextInfo[32];
SDD1_BG * BG[8];
};
///////////////////////////////////////////////////
class SDD1_CM { //Context Model
public:
SDD1_CM(SDD1_PEM *associatedPEM);
void prepareDecomp(uint32 first_byte);
uint8 getBit(void);
private:
uint8 bitplanesInfo;
uint8 contextBitsInfo;
uint8 bit_number;
uint8 currBitplane;
uint16 prevBitplaneBits[8];
SDD1_PEM *const PEM;
};
///////////////////////////////////////////////////
class SDD1_OL { //Output Logic
public:
SDD1_OL(SDD1_CM *associatedCM);
void prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf);
void launch(void);
private:
uint8 bitplanesInfo;
uint16 length;
uint8 *buffer;
SDD1_CM *const CM;
};
/////////////////////////////////////////////////////////
class SDD1emu {
public:
SDD1emu(void);
void decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf);
private:
SDD1_IM IM;
SDD1_GCD GCD;
SDD1_BG BG0; SDD1_BG BG1; SDD1_BG BG2; SDD1_BG BG3;
SDD1_BG BG4; SDD1_BG BG5; SDD1_BG BG6; SDD1_BG BG7;
SDD1_PEM PEM;
SDD1_CM CM;
SDD1_OL OL;
};

View File

@@ -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() {}

View File

@@ -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();
};

80
src/config/config.cpp Normal file
View File

@@ -0,0 +1,80 @@
Config config_file;
namespace config {
FS::Path FS::base_path(0, "fs.base_path", "Directory that bsnes resides in", "");
FS::Path FS::rom_path(&config_file, "fs.rom_path",
"Default path to look for ROM files in (\"\" = use default directory)", "");
FS::Path FS::save_path(&config_file, "fs.save_path",
"Default path for all save RAM and cheat files (\"\" = use current directory)", "");
void FS::Path::sset(const char *_data) {
string path;
strcpy(path, _data);
strunquote(path);
replace(path, "\\", "/");
//blank path?
if(strlen(path) == 0) {
Setting::sset(strptr(path));
return;
}
//missing final directory marker?
if(strptr(path)[strlen(path) - 1] != '/') {
strcat(path, "/");
}
Setting::sset(strptr(path));
}
Setting FS::save_ext(&config_file, "fs.save_ext",
"Extension to be used for all save RAM files", "srm");
SNES::VideoColorAdjust SNES::gamma_ramp(&config_file, "snes.colorfilter.gamma_ramp",
"Use precalculated TV-style gamma ramp", true, Setting::TRUE_FALSE);
SNES::VideoColorAdjust SNES::sepia(&config_file, "snes.colorfilter.sepia",
"Convert color to sepia tone", false, Setting::TRUE_FALSE);
SNES::VideoColorAdjust SNES::grayscale(&config_file, "snes.colorfilter.grayscale",
"Convert color to grayscale tone", false, Setting::TRUE_FALSE);
SNES::VideoColorAdjust SNES::invert(&config_file, "snes.colorfilter.invert",
"Invert output image colors", false, Setting::TRUE_FALSE);
SNES::VideoColorAdjust SNES::contrast(&config_file, "snes.colorfilter.contrast",
"", 0, Setting::DEC);
SNES::VideoColorAdjust SNES::brightness(&config_file, "snes.colorfilter.brightness",
"", 0, Setting::DEC);
SNES::VideoColorAdjust SNES::gamma(&config_file, "snes.colorfilter.gamma",
"", 100, Setting::DEC);
void SNES::VideoColorAdjust::set(uint32 _data) {
Setting::set(_data);
::snes->update_color_lookup_table();
}
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"
"", false, 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);
};

40
src/config/config.h Normal file
View File

@@ -0,0 +1,40 @@
extern Config config_file;
namespace config {
extern struct FS {
static class Path : public Setting {
public:
void sset(const char *_data);
SettingOperators(Path);
} base_path, rom_path, save_path;
static Setting save_ext;
} fs;
extern struct SNES {
static class VideoColorAdjust : public Setting {
public:
void set(uint32 _data);
SettingOperators(VideoColorAdjust);
} 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;
};

View File

@@ -1,186 +1,76 @@
#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(irq_test() == true) {
irq(0xffee);
break;
}
exec_opcode();
break;
case CPUSTATE_STP:
exec_opcode();
break;
if(run_state.hdma) {
exec_hdma();
return;
}
if(run_state.dma) {
exec_dma();
return;
}
if(status.cycle_pos == 0) {
//interrupts only trigger on opcode edges
if(!run_state.irq && !run_state.stp) {
if(time.nmi_pending == true) {
time.nmi_pending = false;
aa.w = 0xffea;
run_state.irq = true;
} else if(time.irq_pending == true) {
time.irq_pending = false;
aa.w = 0xffee;
run_state.irq = true;
}
}
}
exec_cycle();
}
void bCPU::scanline() {
status.hdma_triggered = false;
time.hdma_triggered = false;
if(vcounter() == 225 && status.auto_joypad_poll == true) {
snes->poll_input();
if(vcounter() == (overscan() == false ? 227 : 242) && status.auto_joypad_poll == true) {
snes->poll_input(SNES::DEV_JOYPAD1);
snes->poll_input(SNES::DEV_JOYPAD2);
//When the SNES auto-polls the joypads, it writes 1, then 0 to
//$4016, then reads from each 16 times to get the joypad state
//information. As a result, the joypad read positions are set
//to 16 after such a poll. Position 16 is the controller
//connected status bit.
status.joypad1_read_pos = 16;
}
if(status.virq_enabled == false) {
status.irq_pin = 1;
status.joypad2_read_pos = 16;
}
}
void bCPU::frame() {
hdma_initialize();
time.nmi_read = 1;
time.nmi_line = 1;
time.nmi_transition = 0;
status.nmi_triggered = false;
status.nmi_pin = 1;
status.r4210_read = false;
status.irq_triggered = false;
status.irq_pin = 1;
if(cpu_version == 2) {
time.hdmainit_trigger_pos = 12 + dma_counter();
} else {
time.hdmainit_trigger_pos = 12 + 8 - dma_counter();
}
time.hdmainit_triggered = false;
}
void bCPU::power() {
srtc_power();
region = snes->region();
regs.a = regs.x = regs.y = 0x0000;
regs.s = 0x01ff;
@@ -188,12 +78,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 +91,40 @@ void bCPU::reset() {
regs.db = 0x00;
regs.p = 0x34;
regs.e = 1;
regs.mdr = 0x00;
//simulate pbr:pc push during reset irq vector
regs.s.l -= 3;
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() {}

View File

@@ -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,27 @@ 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 cycles_executed();
inline void scanline();
inline void frame();
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 +105,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 +151,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();

View File

@@ -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;
}
}

View File

@@ -1,42 +1,174 @@
inline void bCPU::cycle_edge() {
int c, n, z;
if(status.dma_state != DMASTATE_STOP) {
switch(status.dma_state) {
case DMASTATE_INIT:
status.dma_state = DMASTATE_DMASYNC;
void bCPU::last_cycle() {
//DMV27: keep previous nmi value,
//to allow wai and irq to work properly
time.nmi_pending = nmi_test() || time.nmi_pending;
time.irq_pending = irq_test();
}
void bCPU::pre_exec_cycle() {
if(!run_state.dma && !run_state.hdma)return;
int c, z;
if(run_state.hdma) {
switch(status.hdma_state) {
case HDMASTATE_ICPUSYNC:
case HDMASTATE_CPUSYNC:
c = status.cycle_count;
z = c - (status.hdma_cycle_count % c);
if(!z)z = c;
add_cycles(z);
run_state.hdma = false;
break;
case DMASTATE_DMASYNC:
n = 8 - dma_counter() + 8;
add_cycles(n);
status.dma_cycle_count = n;
for(z=0;z<8;z++) {
if(channel[z].active == false)continue;
add_cycles(8);
status.dma_cycle_count += 8;
status.dma_cycle_count += channel[z].xfersize << 3;
}
status.cpu_state = CPUSTATE_DMA;
status.dma_state = DMASTATE_RUN;
while(status.dma_state == DMASTATE_RUN) {
dma_run();
}
status.cpu_state = CPUSTATE_RUN;
}
}
if(run_state.dma) {
switch(status.dma_state) {
case DMASTATE_CPUSYNC:
c = status.cycle_count;
z = c - (status.dma_cycle_count % c);
if(!z)z = c;
add_cycles(z);
status.dma_state = DMASTATE_STOP;
run_state.dma = false;
break;
}
}
}
void bCPU::exec_opcode() {
snes->notify(SNES::CPU_EXEC_OPCODE_BEGIN);
(this->*optbl[op_read()])();
snes->notify(SNES::CPU_EXEC_OPCODE_END);
void bCPU::exec_hdma() {
int n;
static int z;
switch(status.hdma_state) {
case HDMASTATE_IDMASYNC:
status.hdma_cycle_count = 0;
z = 0;
if(!run_state.dma) {
exec_cycle();
status.hdma_state = HDMASTATE_IDMASYNC2;
} else {
status.hdma_state = HDMASTATE_IDMASYNC3;
}
break;
case HDMASTATE_IDMASYNC2:
n = 8 - dma_counter() + 8;
add_cycles(n);
status.hdma_cycle_count += n;
status.hdma_state = HDMASTATE_IDMASYNC3;
break;
case HDMASTATE_IDMASYNC3:
channel[z].hdma_active = channel[z].hdma_enabled;
if(channel[z].hdma_enabled) {
channel[z].hdma_addr = channel[z].srcaddr;
hdma_update(z); //updates status.hdma_cycle_count
}
if(++z < 8)break;
if(!run_state.dma) {
status.hdma_state = HDMASTATE_ICPUSYNC;
} else {
run_state.hdma = false;
}
break;
case HDMASTATE_ICPUSYNC:
exec_cycle();
break;
case HDMASTATE_DMASYNC:
status.hdma_cycle_count = 0;
z = 0;
if(!run_state.dma) {
exec_cycle();
status.hdma_state = HDMASTATE_DMASYNC2;
} else {
status.hdma_state = HDMASTATE_DMASYNC3;
}
break;
case HDMASTATE_DMASYNC2:
n = 8 - dma_counter() + 8;
add_cycles(n);
status.hdma_cycle_count += n;
status.hdma_state = HDMASTATE_DMASYNC3;
break;
case HDMASTATE_DMASYNC3:
if(channel[z].hdma_active) {
add_cycles(8);
status.hdma_cycle_count += 8;
}
if(++z < 8)break;
status.hdma_state = HDMASTATE_RUN;
break;
case HDMASTATE_RUN:
hdma_run(); //updates status.hdma_cycle_count
if(!run_state.dma) {
status.hdma_state = HDMASTATE_CPUSYNC;
} else {
run_state.hdma = false;
}
break;
case HDMASTATE_CPUSYNC:
exec_cycle();
break;
}
}
void bCPU::init_op_tables() {
#include "bcpu_optable.cpp"
void bCPU::exec_dma() {
int n;
static int z;
switch(status.dma_state) {
case DMASTATE_DMASYNC:
exec_cycle();
status.dma_state = DMASTATE_DMASYNC2;
break;
case DMASTATE_DMASYNC2:
n = 8 - dma_counter() + 8;
add_cycles(n);
status.dma_cycle_count = n;
z = 0;
status.dma_state = DMASTATE_DMASYNC3;
break;
case DMASTATE_DMASYNC3:
if(channel[z].active == true) {
add_cycles(8);
status.dma_cycle_count += 8;
}
if(++z < 8)break;
status.dma_state = DMASTATE_RUN;
break;
case DMASTATE_RUN:
dma_run(); //updates status.dma_cycle_count
cycle_edge();
break;
case DMASTATE_CPUSYNC:
exec_cycle();
break;
}
}
void bCPU::exec_cycle() {
//irq active? run one bus cycle of the irq event and return
if(run_state.irq) {
irq_run();
return;
}
if(status.cycle_pos) {
(this->*optbl[status.opcode])();
#ifdef DEBUGGER
if(status.cycle_pos == 0) {
snes->notify(SNES::CPU_EXEC_OPCODE_END);
}
#endif
return;
}
//on first cycle?
#ifdef DEBUGGER
snes->notify(SNES::CPU_EXEC_OPCODE_BEGIN);
#endif
status.opcode = op_read();
status.cycle_pos = 1;
}
//only return true when we are on an opcode edge
bool bCPU::in_opcode() {
return (status.cycle_pos != 0);
}

88
src/cpu/bcpu/bcpu_int.cpp Normal file
View File

@@ -0,0 +1,88 @@
/*
[IRQ cycles]
[0] pbr,pc ; opcode
[1] pbr,pc ; io
[2] 0,s ; pbr
[3] 0,s-1 ; pch
[4] 0,s-2 ; pcl
[5] 0,s-3 ; p
[6] 0,va ; aavl
[7] 0,va+1 ; aavh
*/
void bCPU::irq_run() {
//WDC documentation is incorrect, first cycle
//is a memory read fetch from PBR:PC
switch(status.cycle_pos++) {
case 0:
//read from PBR:PC, but do not increment PC counter
mem_read(regs.pc.d);
break;
case 1:
cpu_io();
if(regs.e)status.cycle_pos++;
break;
case 2:
stack_write(regs.pc.b);
break;
case 3:
stack_write(regs.pc.h);
break;
case 4:
stack_write(regs.pc.l);
break;
case 5:
//emulation-mode irqs clear brk bit 0x10
stack_write((regs.e) ? (regs.p & ~0x10) : regs.p);
break;
case 6:
//todo: test if NMI can override IRQ here...
rd.l = op_read(OPMODE_ADDR, aa.w);
regs.pc.b = 0x00;
regs.p.i = 1;
regs.p.d = 0;
break;
case 7:
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
regs.pc.w = rd.w;
#ifdef DEBUGGER
//let debugger know the new IRQ opcode address
snes->notify(SNES::CPU_EXEC_OPCODE_END);
#endif
status.cycle_pos = 0;
run_state.irq = false;
break;
}
}
bool bCPU::nmi_test() {
if(time.nmi_transition == 0)return false;
time.nmi_transition = 0;
run_state.wai = false;
return true;
}
bool bCPU::irq_test() {
if(time.irq_transition == 1)goto _true;
if(time.irq_read == 0) {
if(time.irq_line == 1 && (irq_trigger_pos_match(0) || irq_trigger_pos_match(2))) {
return false;
}
goto _true;
}
if(time.irq_line == 0) {
time.irq_line = 1;
goto _true;
}
return false;
_true:
time.irq_transition = 0;
run_state.wai = false;
if(regs.p.i)return false;
return true;
}

View File

@@ -2,9 +2,10 @@ void bCPU::mmio_reset() {
//$2181-$2183
status.wram_addr = 0x000000;
//$4016
status.joypad1_strobe_value = 0x00;
status.joypad1_read_pos = 0;
//$4016-$4017
status.joypad_strobe_latch = 0;
status.joypad1_read_pos = 0;
status.joypad2_read_pos = 0;
//$4200
status.nmi_enabled = false;
@@ -16,16 +17,16 @@ void bCPU::mmio_reset() {
status.pio = 0xff;
//$4202-$4203
status.mul_a = 0x00;
status.mul_b = 0x00;
status.mul_a = 0xff;
status.mul_b = 0xff;
//$4204-$4206
status.div_a = 0x0000;
status.div_b = 0x00;
status.div_a = 0xffff;
status.div_b = 0xff;
//$4207-$420a
status.hirq_pos = 0;
status.virq_pos = 0;
status.hirq_pos = 0x01ff;
status.virq_pos = 0x01ff;
//$4214-$4217
status.r4214 = 0x0000;
@@ -35,109 +36,149 @@ void bCPU::mmio_reset() {
//WMDATA
uint8 bCPU::mmio_r2180() {
uint8 r;
r = mem_bus->read(0x7e0000 | status.wram_addr);
r = r_mem->read(0x7e0000 | status.wram_addr);
status.wram_addr++;
status.wram_addr &= 0x01ffff;
return r;
}
//???
uint8 bCPU::mmio_r21c2() {
return 0x20;
}
//???
uint8 bCPU::mmio_r21c3() {
return 0x00;
}
/*
The joypad contains a small bit shifter that has 16 bits.
Reading from 4016 reads one bit from this buffer, then moves
the buffer left one, and adds a '1' to the rightmost bit.
Writing a one to $4016 will fill the buffer with the current
joypad button states, and lock the bit shifter at position
zero. All reads will be the first buffer state, or 'B'.
A zero must be written back to $4016 to unlock the buffer,
so that reads will increment the bit shifting position.
*/
//JOYSER0
//7-2 = MDR
//1-0 = Joypad serial data
/* The joypad contains a small bit shifter that has 16 bits.
* Reading from 4016 reads one bit from this buffer, then moves
* the buffer left one, and adds a '1' to the rightmost bit.
* Writing a one to $4016 will fill the buffer with the current
* joypad button states, and lock the bit shifter at position
* zero. All reads will be the first buffer state, or 'B'.
* A zero must be written back to $4016 to unlock the buffer,
* so that reads will increment the bit shifting position.
*/
uint8 bCPU::mmio_r4016() {
uint8 r = 0x00;
if(status.joypad1_strobe_value == 1) {
uint8 r;
r = regs.mdr & 0xfc;
if(status.joypad_strobe_latch == 1) {
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_B);
} else {
switch(status.joypad1_read_pos) {
case 0:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_B); break;
case 1:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_Y); break;
case 2:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_SELECT);break;
case 3:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_START); break;
case 4:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_UP); break;
case 5:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_DOWN); break;
case 6:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_LEFT); break;
case 7:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_RIGHT); break;
case 8:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_A); break;
case 9:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_X); break;
case 10:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_L); break;
case 11:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_R); break;
case 16:r |= 1;break; //joypad connected bit
default:r |= 1;break; //after 16th read, all subsequent reads return 1
case 0: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_B); break;
case 1: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_Y); break;
case 2: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_SELECT); break;
case 3: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_START); break;
case 4: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_UP); break;
case 5: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_DOWN); break;
case 6: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_LEFT); break;
case 7: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_RIGHT); break;
case 8: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_A); break;
case 9: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_X); break;
case 10: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_L); break;
case 11: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_R); break;
case 12: break;
case 13: break;
case 14: break;
case 15: break; //bits 12-15 always return 0
//all subsequent reads return joypad connection status
case 16: r |= 1; break; //joypad connected bit
}
if(++status.joypad1_read_pos > 17)status.joypad1_read_pos = 17;
if(++status.joypad1_read_pos > 16)status.joypad1_read_pos = 16;
}
return r;
}
//JOYSER1
//7-5 = MDR
//4-2 = Always 1 (pins are connected to GND)
//1-0 = Joypad serial data
uint8 bCPU::mmio_r4017() {
uint8 r;
r = regs.mdr & 0xe0;
r |= 0x1c;
if(status.joypad_strobe_latch == 1) {
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_B);
} else {
switch(status.joypad2_read_pos) {
case 0: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_B); break;
case 1: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_Y); break;
case 2: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_SELECT); break;
case 3: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_START); break;
case 4: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_UP); break;
case 5: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_DOWN); break;
case 6: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_LEFT); break;
case 7: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_RIGHT); break;
case 8: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_A); break;
case 9: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_X); break;
case 10: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_L); break;
case 11: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_R); break;
case 12: break;
case 13: break;
case 14: break;
case 15: break; //bits 12-15 always return 0
//all subsequent reads return joypad connection status
case 16: r |= 1; break; //joypad connected bit
}
if(++status.joypad2_read_pos > 16)status.joypad2_read_pos = 16;
}
return r;
}
//RDNMI
//7 = NMI acknowledge
//6-4 = MDR
//3-0 = CPU (5a22) version
uint8 bCPU::mmio_r4210() {
uint8 r = 0x00;
uint16 v, h, hc, vs;
v = vcounter();
h = hcounter();
hc = hcycles();
vs = (overscan()?239:224);
uint8 r;
r = regs.mdr & 0x70;
r |= uint8(!time.nmi_read) << 7;
if(status.r4210_read == false) {
if((v == (vs + 1) && hc >= 2) || v > (vs + 1)) {
r |= 0x80;
status.r4210_read = true;
status.nmi_pin = 1;
}
if(!nmi_trigger_pos_match(0) && !nmi_trigger_pos_match(2)) {
time.nmi_read = 1;
}
r |= 0x40;
r |= 0x02; //cpu version number
r |= (cpu_version & 0x0f);
return r;
}
//TIMEUP
//7 = IRQ acknowledge
//6-0 = MDR
uint8 bCPU::mmio_r4211() {
uint8 r = 0x00;
r |= 0x40;
if(status.irq_triggered == true)r |= 0x80;
status.irq_triggered = false;
uint8 r;
r = regs.mdr & 0x7f;
r |= uint8(!time.irq_read) << 7;
if(!irq_trigger_pos_match(0) && !irq_trigger_pos_match(2)) {
time.irq_read = 1;
time.irq_line = 1;
time.irq_transition = 0;
}
return r;
}
//HVBJOY
//7 = in vblank
//6 = in hblank
//5-1 = MDR
//0 = joypad ready
uint8 bCPU::mmio_r4212() {
uint8 r;
uint16 v, h, hc, vs;
r = 0x00;
uint8 r;
r = regs.mdr & 0x3e;
v = vcounter();
h = hcounter();
hc = hcycles();
vs = (overscan()?239:224);
uint16 vs = overscan() ? 240 : 225;
//auto joypad polling
if(v >= (vs + 1) && v <= (vs + 3))r |= 0x01;
if(time.v >= vs && time.v <= (vs + 2))r |= 0x01;
//hblank
if(hc <= 2 || hc >= 1096)r |= 0x40;
if(time.hc <= 2 || time.hc >= 1096)r |= 0x40;
//vblank
if(v >= (vs + 1))r |= 0x80;
if(time.v >= vs)r |= 0x80;
return r;
}
@@ -168,7 +209,7 @@ uint8 bCPU::mmio_r4217() {
//JOY1L
uint8 bCPU::mmio_r4218() {
uint8 r = 0x00;
uint8 r = 0x00;
uint16 v = vcounter();
if(status.auto_joypad_poll == false)return 0x00; //can't read joypad if auto polling not enabled
//if(v >= 225 && v <= 227)return 0x00; //can't read joypad while SNES is polling input
@@ -181,7 +222,7 @@ uint16 v = vcounter();
//JOY1H
uint8 bCPU::mmio_r4219() {
uint8 r = 0x00;
uint8 r = 0x00;
uint16 v = vcounter();
if(status.auto_joypad_poll == false)return 0x00; //can't read joypad if auto polling not enabled
//if(v >= 225 && v <= 227)return 0x00; //can't read joypad while SNES is polling input
@@ -196,6 +237,36 @@ uint16 v = vcounter();
return r;
}
//JOY2L
uint8 bCPU::mmio_r421a() {
uint8 r = 0x00;
uint16 v = vcounter();
if(status.auto_joypad_poll == false)return 0x00; //can't read joypad if auto polling not enabled
//if(v >= 225 && v <= 227)return 0x00; //can't read joypad while SNES is polling input
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_A) << 7;
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_X) << 6;
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_L) << 5;
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_R) << 4;
return r;
}
//JOY2H
uint8 bCPU::mmio_r421b() {
uint8 r = 0x00;
uint16 v = vcounter();
if(status.auto_joypad_poll == false)return 0x00; //can't read joypad if auto polling not enabled
//if(v >= 225 && v <= 227)return 0x00; //can't read joypad while SNES is polling input
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_B) << 7;
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_Y) << 6;
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_SELECT) << 5;
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_START) << 4;
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_UP) << 3;
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_DOWN) << 2;
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_LEFT) << 1;
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_RIGHT);
return r;
}
//DMAPx
uint8 bCPU::mmio_r43x0(uint8 i) {
return channel[i].dmap;
@@ -218,7 +289,7 @@ uint8 bCPU::mmio_r43x3(uint8 i) {
//A1Bx
uint8 bCPU::mmio_r43x4(uint8 i) {
return channel[i].srcaddr >> 16;
return channel[i].srcbank;
}
//DASxL
@@ -233,17 +304,17 @@ uint8 bCPU::mmio_r43x6(uint8 i) {
//DASBx
uint8 bCPU::mmio_r43x7(uint8 i) {
return channel[i].hdma_indirect_bank;
return channel[i].hdma_ibank;
}
//A2AxL
uint8 bCPU::mmio_r43x8(uint8 i) {
return channel[i].hdma_taddr;
return channel[i].hdma_addr;
}
//A2AxH
uint8 bCPU::mmio_r43x9(uint8 i) {
return channel[i].hdma_taddr >> 8;
return channel[i].hdma_addr >> 8;
}
//NTRLx
@@ -256,62 +327,63 @@ uint8 bCPU::mmio_r43xb(uint8 i) {
return channel[i].hdma_unknown;
}
uint8 bCPUMMIO::read(uint32 addr) {
uint8 i;
//cpu->sync();
uint8 bCPU::mmio_read(uint16 addr) {
//APU
if(addr >= 0x2140 && addr <= 0x217f) {
return apu->port_read(addr & 3);
return r_apu->port_read(addr & 3);
}
//HDMA
if(addr >= 0x4300 && addr <= 0x437f) {
i = (addr >> 4) & 7;
uint i = (addr >> 4) & 7;
switch(addr & 0xf) {
case 0x0:return cpu->mmio_r43x0(i);
case 0x1:return cpu->mmio_r43x1(i);
case 0x2:return cpu->mmio_r43x2(i);
case 0x3:return cpu->mmio_r43x3(i);
case 0x4:return cpu->mmio_r43x4(i);
case 0x5:return cpu->mmio_r43x5(i);
case 0x6:return cpu->mmio_r43x6(i);
case 0x7:return cpu->mmio_r43x7(i);
case 0x8:return cpu->mmio_r43x8(i);
case 0x9:return cpu->mmio_r43x9(i);
case 0xa:return cpu->mmio_r43xa(i);
case 0xb:return cpu->mmio_r43xb(i);
case 0xc:return 0x43; //unmapped
case 0xd:return 0x43; //unmapped
case 0xe:return 0x43; //unmapped
case 0xf:return cpu->mmio_r43xb(i); //mirror of 43xb
case 0x0: return mmio_r43x0(i);
case 0x1: return mmio_r43x1(i);
case 0x2: return mmio_r43x2(i);
case 0x3: return mmio_r43x3(i);
case 0x4: return mmio_r43x4(i);
case 0x5: return mmio_r43x5(i);
case 0x6: return mmio_r43x6(i);
case 0x7: return mmio_r43x7(i);
case 0x8: return mmio_r43x8(i);
case 0x9: return mmio_r43x9(i);
case 0xa: return mmio_r43xa(i);
case 0xb: return mmio_r43xb(i);
case 0xc: return regs.mdr; //unmapped
case 0xd: return regs.mdr; //unmapped
case 0xe: return regs.mdr; //unmapped
case 0xf: return mmio_r43xb(i); //mirror of 43xb
}
}
switch(addr) {
case 0x2180:return cpu->mmio_r2180(); //WMDATA
case 0x21c2:return cpu->mmio_r21c2(); //???
case 0x21c3:return cpu->mmio_r21c3(); //???
case 0x2800:return cpu->srtc_read();
case 0x4016:return cpu->mmio_r4016(); //JOYSER0
case 0x4210:return cpu->mmio_r4210(); //RDNMI
case 0x4211:return cpu->mmio_r4211(); //TIMEUP
case 0x4212:return cpu->mmio_r4212(); //HVBJOY
case 0x4213:return cpu->mmio_r4213(); //RDIO
case 0x4214:return cpu->mmio_r4214(); //RDDIVL
case 0x4215:return cpu->mmio_r4215(); //RDDIVH
case 0x4216:return cpu->mmio_r4216(); //RDMPYL
case 0x4217:return cpu->mmio_r4217(); //RDMPYH
case 0x4218:return cpu->mmio_r4218(); //JOY1L
case 0x4219:return cpu->mmio_r4219(); //JOY1H
case 0x421a:case 0x421b:case 0x421c:case 0x421d:case 0x421e:case 0x421f:return 0x00;
case 0x2180: return mmio_r2180(); //WMDATA
case 0x4016: return mmio_r4016(); //JOYSER0
case 0x4017: return mmio_r4017(); //JOYSER1
case 0x4210: return mmio_r4210(); //RDNMI
case 0x4211: return mmio_r4211(); //TIMEUP
case 0x4212: return mmio_r4212(); //HVBJOY
case 0x4213: return mmio_r4213(); //RDIO
case 0x4214: return mmio_r4214(); //RDDIVL
case 0x4215: return mmio_r4215(); //RDDIVH
case 0x4216: return mmio_r4216(); //RDMPYL
case 0x4217: return mmio_r4217(); //RDMPYH
case 0x4218: return mmio_r4218(); //JOY1L
case 0x4219: return mmio_r4219(); //JOY1H
case 0x421a: return mmio_r421a(); //JOY2L
case 0x421b: return mmio_r421b(); //JOY2H
case 0x421c: return 0x00;
case 0x421d: return 0x00;
case 0x421e: return 0x00;
case 0x421f: return 0x00;
}
return 0x00;
return regs.mdr;
}
//WMDATA
void bCPU::mmio_w2180(uint8 value) {
mem_bus->write(0x7e0000 | status.wram_addr, value);
r_mem->write(0x7e0000 | status.wram_addr, value);
status.wram_addr++;
status.wram_addr &= 0x01ffff;
}
@@ -335,34 +407,47 @@ void bCPU::mmio_w2183(uint8 value) {
}
//JOYSER0
//bit 0 is shared between JOYSER0 and JOYSER1, therefore
//strobing $4016.d0 affects both controller port latches.
//$4017 bit 0 writes are ignored.
void bCPU::mmio_w4016(uint8 value) {
status.joypad1_strobe_value = (value & 1);
if(value == 1) {
snes->poll_input();
status.joypad_strobe_latch = bool(value & 1);
if(status.joypad_strobe_latch == 1) {
snes->poll_input(SNES::DEV_JOYPAD1);
snes->poll_input(SNES::DEV_JOYPAD2);
status.joypad1_read_pos = 0;
status.joypad2_read_pos = 0;
}
}
//NMITIMEN
void bCPU::mmio_w4200(uint8 value) {
status.nmi_enabled = !!(value & 0x80);
status.virq_enabled = !!(value & 0x20);
status.hirq_enabled = !!(value & 0x10);
status.auto_joypad_poll = !!(value & 0x01);
status.nmi_enabled = bool(value & 0x80);
status.virq_enabled = bool(value & 0x20);
status.hirq_enabled = bool(value & 0x10);
status.auto_joypad_poll = bool(value & 0x01);
if(status.nmi_enabled == false) {
status.nmi_pin = 0;
if(time.nmi_read == 0) {
if(time.nmi_line == 1 && !status.nmi_enabled == 0) {
time.nmi_transition = 1;
}
time.nmi_line = !status.nmi_enabled;
}
if(status.virq_enabled == false && status.hirq_enabled == false) {
status.irq_pin = 0;
time.irq_line = 1;
time.irq_read = 1;
time.irq_transition = 0;
}
update_interrupts();
}
//WRIO
void bCPU::mmio_w4201(uint8 value) {
if((status.pio & 0x80) && !(value & 0x80)) {
ppu->latch_counters();
r_ppu->latch_counters();
}
status.pio = value;
}
@@ -390,67 +475,70 @@ void bCPU::mmio_w4205(uint8 value) {
//WRDIVB
void bCPU::mmio_w4206(uint8 value) {
status.div_b = value;
status.r4214 = (status.div_b)?status.div_a / status.div_b : 0xffff;
status.r4216 = (status.div_b)?status.div_a % status.div_b : status.div_a;
status.r4214 = (status.div_b) ? status.div_a / status.div_b : 0xffff;
status.r4216 = (status.div_b) ? status.div_a % status.div_b : status.div_a;
}
//HTIMEL
void bCPU::mmio_w4207(uint8 value) {
status.hirq_pos = (status.hirq_pos & 0xff00) | value;
if(status.irq_triggered == false)status.irq_pin = 1;
update_interrupts();
}
//HTIMEH
void bCPU::mmio_w4208(uint8 value) {
status.hirq_pos = (status.hirq_pos & 0x00ff) | (value << 8);
if(status.irq_triggered == false)status.irq_pin = 1;
update_interrupts();
}
//VTIMEL
void bCPU::mmio_w4209(uint8 value) {
status.virq_pos = (status.virq_pos & 0xff00) | value;
if(status.irq_triggered == false)status.irq_pin = 1;
update_interrupts();
}
//VTIMEH
void bCPU::mmio_w420a(uint8 value) {
status.virq_pos = (status.virq_pos & 0x00ff) | (value << 8);
if(status.irq_triggered == false)status.irq_pin = 1;
update_interrupts();
}
//DMAEN
void bCPU::mmio_w420b(uint8 value) {
if(value != 0x00) {
status.dma_state = DMASTATE_INIT;
run_state.dma = true;
status.dma_state = DMASTATE_DMASYNC;
}
for(int i=0;i<8;i++) {
for(int i = 0; i < 8; i++) {
if(value & (1 << i)) {
channel[i].active = true;
channel[i].hdma_active = false;
//DMA enable does not disable active HDMA channels
channel[i].active = true;
channel[i].read_index = 0;
}
}
}
//HDMAEN
void bCPU::mmio_w420c(uint8 value) {
for(int i=0;i<8;i++) {
channel[i].hdma_active = !!(value & (1 << i));
for(int i = 0; i < 8; i++) {
channel[i].hdma_enabled = bool(value & (1 << i));
channel[i].hdma_active = bool(value & (1 << i));
}
}
//MEMSEL
void bCPU::mmio_w420d(uint8 value) {
mem_bus->fastROM = value & 1;
r_mem->set_speed(value & 1);
}
//DMAPx
void bCPU::mmio_w43x0(uint8 value, uint8 i) {
channel[i].dmap = value;
channel[i].direction = !!(value & 0x80);
channel[i].hdma_indirect = !!(value & 0x40);
channel[i].incmode = (value & 0x10)?-1:1;
channel[i].fixedxfer = !!(value & 0x08);
channel[i].direction = bool(value & 0x80);
channel[i].hdma_indirect = bool(value & 0x40);
channel[i].incmode = (value & 0x10) ? -1 : 1;
channel[i].fixedxfer = bool(value & 0x08);
channel[i].xfermode = value & 7;
}
@@ -461,17 +549,17 @@ void bCPU::mmio_w43x1(uint8 value, uint8 i) {
//A1TxL
void bCPU::mmio_w43x2(uint8 value, uint8 i) {
channel[i].srcaddr = (channel[i].srcaddr & 0xffff00) | value;
channel[i].srcaddr = (channel[i].srcaddr & 0xff00) | value;
}
//A1TxH
void bCPU::mmio_w43x3(uint8 value, uint8 i) {
channel[i].srcaddr = (channel[i].srcaddr & 0xff00ff) | (value << 8);
channel[i].srcaddr = (channel[i].srcaddr & 0x00ff) | (value << 8);
}
//A1Bx
void bCPU::mmio_w43x4(uint8 value, uint8 i) {
channel[i].srcaddr = (channel[i].srcaddr & 0x00ffff) | (value << 16);
channel[i].srcbank = value;
}
//DASxL
@@ -486,17 +574,17 @@ void bCPU::mmio_w43x6(uint8 value, uint8 i) {
//DASBx
void bCPU::mmio_w43x7(uint8 value, uint8 i) {
channel[i].hdma_indirect_bank = value;
channel[i].hdma_ibank = value;
}
//A2AxL
void bCPU::mmio_w43x8(uint8 value, uint8 i) {
channel[i].hdma_taddr = (channel[i].hdma_taddr & 0xffff00) | value;
channel[i].hdma_addr = (channel[i].hdma_addr & 0xff00) | value;
}
//A2AxH
void bCPU::mmio_w43x9(uint8 value, uint8 i) {
channel[i].hdma_taddr = (channel[i].hdma_taddr & 0xff00ff) | (value << 8);
channel[i].hdma_addr = (channel[i].hdma_addr & 0x00ff) | (value << 8);
}
//NTRLx
@@ -509,63 +597,56 @@ void bCPU::mmio_w43xb(uint8 value, uint8 i) {
channel[i].hdma_unknown = value;
}
void bCPUMMIO::write(uint32 addr, uint8 value) {
uint8 i;
//cpu->sync();
void bCPU::mmio_write(uint16 addr, uint8 data) {
//APU
if(addr >= 0x2140 && addr <= 0x217f) {
cpu->port_write(addr & 3, value);
port_write(addr & 3, data);
return;
}
//HDMA
if(addr >= 0x4300 && addr <= 0x437f) {
i = (addr >> 4) & 7;
uint i = (addr >> 4) & 7;
switch(addr & 0xf) {
case 0x0:cpu->mmio_w43x0(value, i);return;
case 0x1:cpu->mmio_w43x1(value, i);return;
case 0x2:cpu->mmio_w43x2(value, i);return;
case 0x3:cpu->mmio_w43x3(value, i);return;
case 0x4:cpu->mmio_w43x4(value, i);return;
case 0x5:cpu->mmio_w43x5(value, i);return;
case 0x6:cpu->mmio_w43x6(value, i);return;
case 0x7:cpu->mmio_w43x7(value, i);return;
case 0x8:cpu->mmio_w43x8(value, i);return;
case 0x9:cpu->mmio_w43x9(value, i);return;
case 0xa:cpu->mmio_w43xa(value, i);return;
case 0xb:cpu->mmio_w43xb(value, i);return;
case 0xc:return; //unmapped
case 0xd:return; //unmapped
case 0xe:return; //unmapped
case 0xf:cpu->mmio_w43xb(value, i);return; //mirror of 43xb
case 0x0: mmio_w43x0(data, i); return;
case 0x1: mmio_w43x1(data, i); return;
case 0x2: mmio_w43x2(data, i); return;
case 0x3: mmio_w43x3(data, i); return;
case 0x4: mmio_w43x4(data, i); return;
case 0x5: mmio_w43x5(data, i); return;
case 0x6: mmio_w43x6(data, i); return;
case 0x7: mmio_w43x7(data, i); return;
case 0x8: mmio_w43x8(data, i); return;
case 0x9: mmio_w43x9(data, i); return;
case 0xa: mmio_w43xa(data, i); return;
case 0xb: mmio_w43xb(data, i); return;
case 0xc: return; //unmapped
case 0xd: return; //unmapped
case 0xe: return; //unmapped
case 0xf: mmio_w43xb(data, i); return; //mirror of 43xb
}
}
switch(addr) {
case 0x2180:cpu->mmio_w2180(value);return; //WMDATA
case 0x2181:cpu->mmio_w2181(value);return; //WMADDL
case 0x2182:cpu->mmio_w2182(value);return; //WMADDM
case 0x2183:cpu->mmio_w2183(value);return; //WMADDH
case 0x2801:cpu->srtc_write(value);return;
case 0x4016:cpu->mmio_w4016(value);return; //JOYSER0
case 0x4200:cpu->mmio_w4200(value);return; //NMITIMEN
case 0x4201:cpu->mmio_w4201(value);return; //WRIO
case 0x4202:cpu->mmio_w4202(value);return; //WRMPYA
case 0x4203:cpu->mmio_w4203(value);return; //WRMPYB
case 0x4204:cpu->mmio_w4204(value);return; //WRDIVL
case 0x4205:cpu->mmio_w4205(value);return; //WRDIVH
case 0x4206:cpu->mmio_w4206(value);return; //WRDIVB
case 0x4207:cpu->mmio_w4207(value);return; //HTIMEL
case 0x4208:cpu->mmio_w4208(value);return; //HTIMEH
case 0x4209:cpu->mmio_w4209(value);return; //VTIMEL
case 0x420a:cpu->mmio_w420a(value);return; //VTIMEH
case 0x420b:cpu->mmio_w420b(value);return; //DMAEN
case 0x420c:cpu->mmio_w420c(value);return; //HDMAEN
case 0x420d:cpu->mmio_w420d(value);return; //MEMSEL
case 0x2180: mmio_w2180(data); return; //WMDATA
case 0x2181: mmio_w2181(data); return; //WMADDL
case 0x2182: mmio_w2182(data); return; //WMADDM
case 0x2183: mmio_w2183(data); return; //WMADDH
case 0x4016: mmio_w4016(data); return; //JOYSER0
case 0x4017: return; //unmapped
case 0x4200: mmio_w4200(data); return; //NMITIMEN
case 0x4201: mmio_w4201(data); return; //WRIO
case 0x4202: mmio_w4202(data); return; //WRMPYA
case 0x4203: mmio_w4203(data); return; //WRMPYB
case 0x4204: mmio_w4204(data); return; //WRDIVL
case 0x4205: mmio_w4205(data); return; //WRDIVH
case 0x4206: mmio_w4206(data); return; //WRDIVB
case 0x4207: mmio_w4207(data); return; //HTIMEL
case 0x4208: mmio_w4208(data); return; //HTIMEH
case 0x4209: mmio_w4209(data); return; //VTIMEL
case 0x420a: mmio_w420a(data); return; //VTIMEH
case 0x420b: mmio_w420b(data); return; //DMAEN
case 0x420c: mmio_w420c(data); return; //HDMAEN
case 0x420d: mmio_w420d(data); return; //MEMSEL
}
}
bCPUMMIO::bCPUMMIO(bCPU *_cpu) {
cpu = _cpu;
}

View File

@@ -1,551 +0,0 @@
void bCPU::op_nop() {
l1:
cpu_io();
}
void bCPU::op_wdm() {
l1:
cpu_io();
regs.pc.w++;
}
void bCPU::op_xba() {
l1:
cpu_io();
l2:
cpu_io();
regs.a.l ^= regs.a.h;
regs.a.h ^= regs.a.l;
regs.a.l ^= regs.a.h;
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
}
void bCPU::op_mvn() {
l1:
dp = op_read();
l2:
sp = op_read();
l3:
regs.db = dp;
rd.l = op_read(OPMODE_LONG, (sp << 16) | regs.x.w);
l4:
op_write(OPMODE_LONG, (dp << 16) | regs.y.w, rd.l);
l5:
cpu_io();
if(regs.p.x) { regs.x.l++; regs.y.l++; }
else { regs.x.w++; regs.y.w++; }
l6:
cpu_io();
if(regs.a.w--)regs.pc.w -= 3;
}
void bCPU::op_mvp() {
l1:
dp = op_read();
l2:
sp = op_read();
l3:
regs.db = dp;
rd.l = op_read(OPMODE_LONG, (sp << 16) | regs.x.w);
l4:
op_write(OPMODE_LONG, (dp << 16) | regs.y.w, rd.l);
l5:
cpu_io();
if(regs.p.x) { regs.x.l--; regs.y.l--; }
else { regs.x.w--; regs.y.w--; }
l6:
cpu_io();
if(regs.a.w--)regs.pc.w -= 3;
}
void bCPU::op_brk() {
l1:
op_read();
if(regs.e)goto l3;
l2:
stack_write(regs.pc.b);
l3:
stack_write(regs.pc.h);
l4:
stack_write(regs.pc.l);
l5:
stack_write(regs.p);
l6:
rd.l = op_read(OPMODE_LONG, (regs.e)?0xfffe:0xffe6);
l7:
rd.h = op_read(OPMODE_LONG, (regs.e)?0xffff:0xffe7);
regs.pc.b = 0x00;
regs.pc.w = rd.w;
regs.p.i = 1;
regs.p.d = 0;
}
void bCPU::op_cop() {
l1:
op_read();
if(regs.e)goto l3;
l2:
stack_write(regs.pc.b);
l3:
stack_write(regs.pc.h);
l4:
stack_write(regs.pc.l);
l5:
stack_write(regs.p);
l6:
rd.l = op_read(OPMODE_LONG, (regs.e)?0xfff4:0xffe4);
l7:
rd.h = op_read(OPMODE_LONG, (regs.e)?0xfff5:0xffe5);
regs.pc.b = 0x00;
regs.pc.w = rd.w;
regs.p.i = 1;
regs.p.d = 0;
}
void bCPU::op_stp() {
l1:
cpu_io();
status.cpu_state = CPUSTATE_STP;
l2:
cpu_io();
regs.pc.w--;
}
void bCPU::op_wai() {
l1:
cpu_io();
status.cpu_state = CPUSTATE_WAI;
l2:
cpu_io();
regs.pc.w--;
}
void bCPU::op_xce() {
l1:
cpu_io();
bool c = regs.p.c;
regs.p.c = regs.e;
regs.e = c;
if(regs.e) {
regs.p |= 0x30;
regs.x.h = 0x00;
regs.y.h = 0x00;
regs.s.h = 0x01;
}
}
void bCPU::op_clc() {
l1:
cpu_io();
regs.p.c = 0;
}
void bCPU::op_cld() {
l1:
cpu_io();
regs.p.d = 0;
}
void bCPU::op_cli() {
l1:
cpu_io();
regs.p.i = 0;
}
void bCPU::op_clv() {
l1:
cpu_io();
regs.p.v = 0;
}
void bCPU::op_sec() {
l1:
cpu_io();
regs.p.c = 1;
}
void bCPU::op_sed() {
l1:
cpu_io();
regs.p.d = 1;
}
void bCPU::op_sei() {
l1:
cpu_io();
regs.p.i = 1;
}
void bCPU::op_rep() {
l1:
rd.l = op_read();
l2:
cpu_io();
regs.p &=~ rd.l;
if(regs.e)regs.p |= 0x30;
if(regs.p.x) {
regs.x.h = 0x00;
regs.y.h = 0x00;
}
}
void bCPU::op_sep() {
l1:
rd.l = op_read();
l2:
cpu_io();
regs.p |= rd.l;
if(regs.e)regs.p |= 0x30;
if(regs.p.x) {
regs.x.h = 0x00;
regs.y.h = 0x00;
}
}
void bCPU::op_tax() {
l1:
cpu_io();
if(regs.p.x) {
regs.x.l = regs.a.l;
regs.p.n = !!(regs.x.l & 0x80);
regs.p.z = (regs.x.l == 0);
} else {
regs.x.w = regs.a.w;
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
}
}
void bCPU::op_tay() {
l1:
cpu_io();
if(regs.p.x) {
regs.y.l = regs.a.l;
regs.p.n = !!(regs.y.l & 0x80);
regs.p.z = (regs.y.l == 0);
} else {
regs.y.w = regs.a.w;
regs.p.n = !!(regs.y.w & 0x8000);
regs.p.z = (regs.y.w == 0);
}
}
void bCPU::op_txa() {
l1:
cpu_io();
if(regs.p.m) {
regs.a.l = regs.x.l;
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
regs.a.w = regs.x.w;
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
}
void bCPU::op_txy() {
l1:
cpu_io();
if(regs.p.x) {
regs.y.l = regs.x.l;
regs.p.n = !!(regs.y.l & 0x80);
regs.p.z = (regs.y.l == 0);
} else {
regs.y.w = regs.x.w;
regs.p.n = !!(regs.y.w & 0x8000);
regs.p.z = (regs.y.w == 0);
}
}
void bCPU::op_tya() {
l1:
cpu_io();
if(regs.p.m) {
regs.a.l = regs.y.l;
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
regs.a.w = regs.y.w;
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
}
void bCPU::op_tyx() {
l1:
cpu_io();
if(regs.p.x) {
regs.x.l = regs.y.l;
regs.p.n = !!(regs.x.l & 0x80);
regs.p.z = (regs.x.l == 0);
} else {
regs.x.w = regs.y.w;
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
}
}
void bCPU::op_tcd() {
l1:
cpu_io();
regs.d.w = regs.a.w;
regs.p.n = !!(regs.d.w & 0x8000);
regs.p.z = (regs.d.w == 0);
}
void bCPU::op_tcs() {
l1:
cpu_io();
regs.s.w = regs.a.w;
if(regs.e)regs.s.h = 0x01;
}
void bCPU::op_tdc() {
l1:
cpu_io();
regs.a.w = regs.d.w;
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
void bCPU::op_tsc() {
l1:
cpu_io();
regs.a.w = regs.s.w;
if(regs.e) {
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
}
void bCPU::op_tsx() {
l1:
cpu_io();
if(regs.p.x) {
regs.x.l = regs.s.l;
regs.p.n = !!(regs.x.l & 0x80);
regs.p.z = (regs.x.l == 0);
} else {
regs.x.w = regs.s.w;
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
}
}
void bCPU::op_txs() {
l1:
cpu_io();
if(regs.e) {
regs.s.l = regs.x.l;
regs.p.n = !!(regs.s.l & 0x80);
regs.p.z = (regs.s.l == 0);
} else {
regs.s.w = regs.x.w;
regs.p.n = !!(regs.s.w & 0x8000);
regs.p.z = (regs.s.w == 0);
}
}
void bCPU::op_pha() {
l1:
cpu_io();
if(regs.p.m)goto l3;
l2:
stack_write(regs.a.h);
l3:
stack_write(regs.a.l);
}
void bCPU::op_phx() {
l1:
cpu_io();
if(regs.p.x)goto l3;
l2:
stack_write(regs.x.h);
l3:
stack_write(regs.x.l);
}
void bCPU::op_phy() {
l1:
cpu_io();
if(regs.p.x)goto l3;
l2:
stack_write(regs.y.h);
l3:
stack_write(regs.y.l);
}
void bCPU::op_phd() {
l1:
cpu_io();
if(0)goto l3;
l2:
stack_write(regs. d.h);
l3:
stack_write(regs. d.l);
}
void bCPU::op_phb() {
l1:
cpu_io();
l2:
stack_write(regs.db);
}
void bCPU::op_phk() {
l1:
cpu_io();
l2:
stack_write(regs.pc.b);
}
void bCPU::op_php() {
l1:
cpu_io();
l2:
stack_write(regs.p);
}
void bCPU::op_pla() {
l1:
cpu_io();
l2:
cpu_io();
l3:
regs.a.l = stack_read();
if(regs.p.m) {
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
return;
}
l4:
regs.a.h = stack_read();
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
void bCPU::op_plx() {
l1:
cpu_io();
l2:
cpu_io();
l3:
regs.x.l = stack_read();
if(regs.p.x) {
regs.p.n = !!(regs.x.l & 0x80);
regs.p.z = (regs.x.l == 0);
return;
}
l4:
regs.x.h = stack_read();
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
}
void bCPU::op_ply() {
l1:
cpu_io();
l2:
cpu_io();
l3:
regs.y.l = stack_read();
if(regs.p.x) {
regs.p.n = !!(regs.y.l & 0x80);
regs.p.z = (regs.y.l == 0);
return;
}
l4:
regs.y.h = stack_read();
regs.p.n = !!(regs.y.w & 0x8000);
regs.p.z = (regs.y.w == 0);
}
void bCPU::op_pld() {
l1:
cpu_io();
l2:
cpu_io();
l3:
regs. d.l = stack_read();
if(0) {
regs.p.n = !!(regs. d.l & 0x80);
regs.p.z = (regs. d.l == 0);
return;
}
l4:
regs. d.h = stack_read();
regs.p.n = !!(regs. d.w & 0x8000);
regs.p.z = (regs. d.w == 0);
}
void bCPU::op_plb() {
l1:
cpu_io();
l2:
cpu_io();
l3:
regs.db = stack_read();
regs.p.n = !!(regs.db & 0x80);
regs.p.z = (regs.db == 0);
}
void bCPU::op_plp() {
l1:
cpu_io();
l2:
cpu_io();
l3:
regs.p = stack_read();
if(regs.e)regs.p |= 0x30;
if(regs.p.x) {
regs.x.h = 0x00;
regs.y.h = 0x00;
}
}
void bCPU::op_pea() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
stack_write(aa.h);
l4:
stack_write(aa.l);
}
void bCPU::op_pei() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
aa.l = op_read(OPMODE_DP, dp);
l4:
aa.h = op_read(OPMODE_DP, dp + 1);
l5:
stack_write(aa.h);
l6:
stack_write(aa.l);
}
void bCPU::op_per() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_io();
rd.w = regs.pc.d + (int16)aa.w;
l4:
stack_write(rd.h);
l5:
stack_write(rd.l);
}

View File

@@ -1,310 +0,0 @@
void bCPU::op_bra() {
l1:
rd.l = op_read();
if(1) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bcc() {
l1:
rd.l = op_read();
if(!regs.p.c) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bcs() {
l1:
rd.l = op_read();
if(regs.p.c) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bne() {
l1:
rd.l = op_read();
if(!regs.p.z) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_beq() {
l1:
rd.l = op_read();
if(regs.p.z) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bpl() {
l1:
rd.l = op_read();
if(!regs.p.n) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bmi() {
l1:
rd.l = op_read();
if(regs.p.n) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bvc() {
l1:
rd.l = op_read();
if(!regs.p.v) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bvs() {
l1:
rd.l = op_read();
if(regs.p.v) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_brl() {
l1:
rd.l = op_read();
l2:
rd.h = op_read();
l3:
cpu_io();
regs.pc.w = regs.pc.d + (int16)rd.w;
}
void bCPU::op_jmp_addr() {
l1:
rd.l = op_read();
l2:
rd.h = op_read();
regs.pc.w = rd.w;
}
void bCPU::op_jmp_long() {
l1:
rd.l = op_read();
l2:
rd.h = op_read();
l3:
rd.b = op_read();
regs.pc.d = rd.d & 0xffffff;
}
void bCPU::op_jmp_iaddr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
rd.l = op_read(OPMODE_ADDR, aa.w);
l4:
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
regs.pc.w = rd.w;
}
void bCPU::op_jmp_iaddrx() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_io();
l4:
rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
l5:
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
regs.pc.w = rd.w;
}
void bCPU::op_jmp_iladdr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
rd.l = op_read(OPMODE_ADDR, aa.w);
l4:
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
l5:
rd.b = op_read(OPMODE_ADDR, aa.w + 2);
regs.pc.d = rd.d & 0xffffff;
}
void bCPU::op_jsr_addr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_io();
l4:
regs.pc.w--;
stack_write(regs.pc.h);
l5:
stack_write(regs.pc.l);
regs.pc.w = aa.w;
}
void bCPU::op_jsr_long() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
stack_write(regs.pc.b);
l4:
cpu_io();
l5:
aa.b = op_read();
l6:
regs.pc.w--;
stack_write(regs.pc.h);
l7:
stack_write(regs.pc.l);
regs.pc.d = aa.d & 0xffffff;
}
void bCPU::op_jsr_iaddrx() {
l1:
aa.l = op_read();
l2:
stack_write(regs.pc.h);
l3:
stack_write(regs.pc.l);
l4:
aa.h = op_read();
l5:
cpu_io();
l6:
rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
l7:
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
regs.pc.w = rd.w;
}
void bCPU::op_rti() {
l1:
cpu_io();
l2:
cpu_io();
l3:
regs.p = stack_read();
if(regs.e)regs.p |= 0x30;
if(regs.p.x) {
regs.x.h = 0x00;
regs.y.h = 0x00;
}
l4:
rd.l = stack_read();
l5:
rd.h = stack_read();
if(regs.e) {
regs.pc.w = rd.w;
return;
}
l6:
rd.b = stack_read();
regs.pc.d = rd.d & 0xffffff;
}
void bCPU::op_rts() {
l1:
cpu_io();
l2:
cpu_io();
l3:
rd.l = stack_read();
l4:
rd.h = stack_read();
l5:
cpu_io();
regs.pc.w = rd.w;
regs.pc.w++;
}
void bCPU::op_rtl() {
l1:
cpu_io();
l2:
cpu_io();
l3:
rd.l = stack_read();
l4:
rd.h = stack_read();
l5:
rd.b = stack_read();
regs.pc.d = rd.d & 0xffffff;
regs.pc.w++;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,740 +0,0 @@
void bCPU::op_inc() {
l1:
cpu_io();
if(regs.p.m) {
regs.a.l++;
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
regs.a.w++;
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
}
void bCPU::op_inx() {
l1:
cpu_io();
if(regs.p.x) {
regs.x.l++;
regs.p.n = !!(regs.x.l & 0x80);
regs.p.z = (regs.x.l == 0);
} else {
regs.x.w++;
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
}
}
void bCPU::op_iny() {
l1:
cpu_io();
if(regs.p.x) {
regs.y.l++;
regs.p.n = !!(regs.y.l & 0x80);
regs.p.z = (regs.y.l == 0);
} else {
regs.y.w++;
regs.p.n = !!(regs.y.w & 0x8000);
regs.p.z = (regs.y.w == 0);
}
}
void bCPU::op_dec() {
l1:
cpu_io();
if(regs.p.m) {
regs.a.l--;
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
regs.a.w--;
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
}
void bCPU::op_dex() {
l1:
cpu_io();
if(regs.p.x) {
regs.x.l--;
regs.p.n = !!(regs.x.l & 0x80);
regs.p.z = (regs.x.l == 0);
} else {
regs.x.w--;
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
}
}
void bCPU::op_dey() {
l1:
cpu_io();
if(regs.p.x) {
regs.y.l--;
regs.p.n = !!(regs.y.l & 0x80);
regs.p.z = (regs.y.l == 0);
} else {
regs.y.w--;
regs.p.n = !!(regs.y.w & 0x8000);
regs.p.z = (regs.y.w == 0);
}
}
void bCPU::op_asl() {
l1:
cpu_io();
if(regs.p.m) {
regs.p.c = !!(regs.a.l & 0x80);
regs.a.l <<= 1;
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
regs.p.c = !!(regs.a.w & 0x8000);
regs.a.w <<= 1;
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
}
void bCPU::op_lsr() {
l1:
cpu_io();
if(regs.p.m) {
regs.p.c = regs.a.l & 1;
regs.a.l >>= 1;
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
regs.p.c = regs.a.w & 1;
regs.a.w >>= 1;
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
}
void bCPU::op_rol() {
l1:
cpu_io();
uint16 c = regs.p.c;
if(regs.p.m) {
regs.p.c = !!(regs.a.l & 0x80);
regs.a.l <<= 1;
regs.a.l |= c;
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
regs.p.c = !!(regs.a.w & 0x8000);
regs.a.w <<= 1;
regs.a.w |= c;
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
}
void bCPU::op_ror() {
l1:
cpu_io();
uint16 c;
if(regs.p.m) {
c = (regs.p.c)?0x80:0;
regs.p.c = regs.a.l & 1;
regs.a.l >>= 1;
regs.a.l |= c;
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
c = (regs.p.c)?0x8000:0;
regs.p.c = regs.a.w & 1;
regs.a.w >>= 1;
regs.a.w |= c;
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
}
void bCPU::op_inc_addr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
rd.l = op_read(OPMODE_DBR, aa.w);
if(regs.p.m)goto l5;
l4:
rd.h = op_read(OPMODE_DBR, aa.w + 1);
l5:
cpu_io();
if(regs.p.m) { op_inc_b(); goto l7; }
else op_inc_w();
l6:
op_write(OPMODE_DBR, aa.w + 1, rd.h);
l7:
op_write(OPMODE_DBR, aa.w, rd.l);
}
void bCPU::op_dec_addr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
rd.l = op_read(OPMODE_DBR, aa.w);
if(regs.p.m)goto l5;
l4:
rd.h = op_read(OPMODE_DBR, aa.w + 1);
l5:
cpu_io();
if(regs.p.m) { op_dec_b(); goto l7; }
else op_dec_w();
l6:
op_write(OPMODE_DBR, aa.w + 1, rd.h);
l7:
op_write(OPMODE_DBR, aa.w, rd.l);
}
void bCPU::op_asl_addr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
rd.l = op_read(OPMODE_DBR, aa.w);
if(regs.p.m)goto l5;
l4:
rd.h = op_read(OPMODE_DBR, aa.w + 1);
l5:
cpu_io();
if(regs.p.m) { op_asl_b(); goto l7; }
else op_asl_w();
l6:
op_write(OPMODE_DBR, aa.w + 1, rd.h);
l7:
op_write(OPMODE_DBR, aa.w, rd.l);
}
void bCPU::op_lsr_addr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
rd.l = op_read(OPMODE_DBR, aa.w);
if(regs.p.m)goto l5;
l4:
rd.h = op_read(OPMODE_DBR, aa.w + 1);
l5:
cpu_io();
if(regs.p.m) { op_lsr_b(); goto l7; }
else op_lsr_w();
l6:
op_write(OPMODE_DBR, aa.w + 1, rd.h);
l7:
op_write(OPMODE_DBR, aa.w, rd.l);
}
void bCPU::op_rol_addr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
rd.l = op_read(OPMODE_DBR, aa.w);
if(regs.p.m)goto l5;
l4:
rd.h = op_read(OPMODE_DBR, aa.w + 1);
l5:
cpu_io();
if(regs.p.m) { op_rol_b(); goto l7; }
else op_rol_w();
l6:
op_write(OPMODE_DBR, aa.w + 1, rd.h);
l7:
op_write(OPMODE_DBR, aa.w, rd.l);
}
void bCPU::op_ror_addr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
rd.l = op_read(OPMODE_DBR, aa.w);
if(regs.p.m)goto l5;
l4:
rd.h = op_read(OPMODE_DBR, aa.w + 1);
l5:
cpu_io();
if(regs.p.m) { op_ror_b(); goto l7; }
else op_ror_w();
l6:
op_write(OPMODE_DBR, aa.w + 1, rd.h);
l7:
op_write(OPMODE_DBR, aa.w, rd.l);
}
void bCPU::op_trb_addr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
rd.l = op_read(OPMODE_DBR, aa.w);
if(regs.p.m)goto l5;
l4:
rd.h = op_read(OPMODE_DBR, aa.w + 1);
l5:
cpu_io();
if(regs.p.m) { op_trb_b(); goto l7; }
else op_trb_w();
l6:
op_write(OPMODE_DBR, aa.w + 1, rd.h);
l7:
op_write(OPMODE_DBR, aa.w, rd.l);
}
void bCPU::op_tsb_addr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
rd.l = op_read(OPMODE_DBR, aa.w);
if(regs.p.m)goto l5;
l4:
rd.h = op_read(OPMODE_DBR, aa.w + 1);
l5:
cpu_io();
if(regs.p.m) { op_tsb_b(); goto l7; }
else op_tsb_w();
l6:
op_write(OPMODE_DBR, aa.w + 1, rd.h);
l7:
op_write(OPMODE_DBR, aa.w, rd.l);
}
void bCPU::op_inc_addrx() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_io();
l4:
rd.l = op_read(OPMODE_DBR, aa.w + regs.x.w);
if(regs.p.m)goto l6;
l5:
rd.h = op_read(OPMODE_DBR, aa.w + regs.x.w + 1);
l6:
cpu_io();
if(regs.p.m) { op_inc_b(); goto l8; }
else op_inc_w();
l7:
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
l8:
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
}
void bCPU::op_dec_addrx() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_io();
l4:
rd.l = op_read(OPMODE_DBR, aa.w + regs.x.w);
if(regs.p.m)goto l6;
l5:
rd.h = op_read(OPMODE_DBR, aa.w + regs.x.w + 1);
l6:
cpu_io();
if(regs.p.m) { op_dec_b(); goto l8; }
else op_dec_w();
l7:
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
l8:
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
}
void bCPU::op_asl_addrx() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_io();
l4:
rd.l = op_read(OPMODE_DBR, aa.w + regs.x.w);
if(regs.p.m)goto l6;
l5:
rd.h = op_read(OPMODE_DBR, aa.w + regs.x.w + 1);
l6:
cpu_io();
if(regs.p.m) { op_asl_b(); goto l8; }
else op_asl_w();
l7:
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
l8:
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
}
void bCPU::op_lsr_addrx() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_io();
l4:
rd.l = op_read(OPMODE_DBR, aa.w + regs.x.w);
if(regs.p.m)goto l6;
l5:
rd.h = op_read(OPMODE_DBR, aa.w + regs.x.w + 1);
l6:
cpu_io();
if(regs.p.m) { op_lsr_b(); goto l8; }
else op_lsr_w();
l7:
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
l8:
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
}
void bCPU::op_rol_addrx() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_io();
l4:
rd.l = op_read(OPMODE_DBR, aa.w + regs.x.w);
if(regs.p.m)goto l6;
l5:
rd.h = op_read(OPMODE_DBR, aa.w + regs.x.w + 1);
l6:
cpu_io();
if(regs.p.m) { op_rol_b(); goto l8; }
else op_rol_w();
l7:
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
l8:
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
}
void bCPU::op_ror_addrx() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_io();
l4:
rd.l = op_read(OPMODE_DBR, aa.w + regs.x.w);
if(regs.p.m)goto l6;
l5:
rd.h = op_read(OPMODE_DBR, aa.w + regs.x.w + 1);
l6:
cpu_io();
if(regs.p.m) { op_ror_b(); goto l8; }
else op_ror_w();
l7:
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
l8:
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
}
void bCPU::op_inc_dp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
rd.l = op_read(OPMODE_DP, dp);
if(regs.p.m)goto l5;
l4:
rd.h = op_read(OPMODE_DP, dp + 1);
l5:
cpu_io();
if(regs.p.m) { op_inc_b(); goto l7; }
else op_inc_w();
l6:
op_write(OPMODE_DP, dp + 1, rd.h);
l7:
op_write(OPMODE_DP, dp, rd.l);
}
void bCPU::op_dec_dp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
rd.l = op_read(OPMODE_DP, dp);
if(regs.p.m)goto l5;
l4:
rd.h = op_read(OPMODE_DP, dp + 1);
l5:
cpu_io();
if(regs.p.m) { op_dec_b(); goto l7; }
else op_dec_w();
l6:
op_write(OPMODE_DP, dp + 1, rd.h);
l7:
op_write(OPMODE_DP, dp, rd.l);
}
void bCPU::op_asl_dp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
rd.l = op_read(OPMODE_DP, dp);
if(regs.p.m)goto l5;
l4:
rd.h = op_read(OPMODE_DP, dp + 1);
l5:
cpu_io();
if(regs.p.m) { op_asl_b(); goto l7; }
else op_asl_w();
l6:
op_write(OPMODE_DP, dp + 1, rd.h);
l7:
op_write(OPMODE_DP, dp, rd.l);
}
void bCPU::op_lsr_dp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
rd.l = op_read(OPMODE_DP, dp);
if(regs.p.m)goto l5;
l4:
rd.h = op_read(OPMODE_DP, dp + 1);
l5:
cpu_io();
if(regs.p.m) { op_lsr_b(); goto l7; }
else op_lsr_w();
l6:
op_write(OPMODE_DP, dp + 1, rd.h);
l7:
op_write(OPMODE_DP, dp, rd.l);
}
void bCPU::op_rol_dp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
rd.l = op_read(OPMODE_DP, dp);
if(regs.p.m)goto l5;
l4:
rd.h = op_read(OPMODE_DP, dp + 1);
l5:
cpu_io();
if(regs.p.m) { op_rol_b(); goto l7; }
else op_rol_w();
l6:
op_write(OPMODE_DP, dp + 1, rd.h);
l7:
op_write(OPMODE_DP, dp, rd.l);
}
void bCPU::op_ror_dp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
rd.l = op_read(OPMODE_DP, dp);
if(regs.p.m)goto l5;
l4:
rd.h = op_read(OPMODE_DP, dp + 1);
l5:
cpu_io();
if(regs.p.m) { op_ror_b(); goto l7; }
else op_ror_w();
l6:
op_write(OPMODE_DP, dp + 1, rd.h);
l7:
op_write(OPMODE_DP, dp, rd.l);
}
void bCPU::op_trb_dp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
rd.l = op_read(OPMODE_DP, dp);
if(regs.p.m)goto l5;
l4:
rd.h = op_read(OPMODE_DP, dp + 1);
l5:
cpu_io();
if(regs.p.m) { op_trb_b(); goto l7; }
else op_trb_w();
l6:
op_write(OPMODE_DP, dp + 1, rd.h);
l7:
op_write(OPMODE_DP, dp, rd.l);
}
void bCPU::op_tsb_dp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
rd.l = op_read(OPMODE_DP, dp);
if(regs.p.m)goto l5;
l4:
rd.h = op_read(OPMODE_DP, dp + 1);
l5:
cpu_io();
if(regs.p.m) { op_tsb_b(); goto l7; }
else op_tsb_w();
l6:
op_write(OPMODE_DP, dp + 1, rd.h);
l7:
op_write(OPMODE_DP, dp, rd.l);
}
void bCPU::op_inc_dpx() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
rd.l = op_read(OPMODE_DP, dp + regs.x.w);
if(regs.p.m)goto l6;
l5:
rd.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
l6:
cpu_io();
if(regs.p.m) { op_inc_b(); goto l8; }
else op_inc_w();
l7:
op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
l8:
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
}
void bCPU::op_dec_dpx() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
rd.l = op_read(OPMODE_DP, dp + regs.x.w);
if(regs.p.m)goto l6;
l5:
rd.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
l6:
cpu_io();
if(regs.p.m) { op_dec_b(); goto l8; }
else op_dec_w();
l7:
op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
l8:
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
}
void bCPU::op_asl_dpx() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
rd.l = op_read(OPMODE_DP, dp + regs.x.w);
if(regs.p.m)goto l6;
l5:
rd.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
l6:
cpu_io();
if(regs.p.m) { op_asl_b(); goto l8; }
else op_asl_w();
l7:
op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
l8:
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
}
void bCPU::op_lsr_dpx() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
rd.l = op_read(OPMODE_DP, dp + regs.x.w);
if(regs.p.m)goto l6;
l5:
rd.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
l6:
cpu_io();
if(regs.p.m) { op_lsr_b(); goto l8; }
else op_lsr_w();
l7:
op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
l8:
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
}
void bCPU::op_rol_dpx() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
rd.l = op_read(OPMODE_DP, dp + regs.x.w);
if(regs.p.m)goto l6;
l5:
rd.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
l6:
cpu_io();
if(regs.p.m) { op_rol_b(); goto l8; }
else op_rol_w();
l7:
op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
l8:
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
}
void bCPU::op_ror_dpx() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
rd.l = op_read(OPMODE_DP, dp + regs.x.w);
if(regs.p.m)goto l6;
l5:
rd.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
l6:
cpu_io();
if(regs.p.m) { op_ror_b(); goto l8; }
else op_ror_w();
l7:
op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
l8:
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
}

View File

@@ -1,340 +0,0 @@
void bCPU::op_sta_addr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
op_write(OPMODE_DBR, aa.w, regs.a.w);
if(regs.p.m)return;
l4:
op_write(OPMODE_DBR, aa.w + 1, regs.a.w >> 8);
}
void bCPU::op_stx_addr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
op_write(OPMODE_DBR, aa.w, regs.x.w);
if(regs.p.x)return;
l4:
op_write(OPMODE_DBR, aa.w + 1, regs.x.w >> 8);
}
void bCPU::op_sty_addr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
op_write(OPMODE_DBR, aa.w, regs.y.w);
if(regs.p.x)return;
l4:
op_write(OPMODE_DBR, aa.w + 1, regs.y.w >> 8);
}
void bCPU::op_stz_addr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
op_write(OPMODE_DBR, aa.w, 0x0000);
if(regs.p.m)return;
l4:
op_write(OPMODE_DBR, aa.w + 1, 0x0000 >> 8);
}
void bCPU::op_sta_addrx() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_c4(aa.w, aa.w + regs.x.w);
l4:
op_write(OPMODE_DBR, aa.w + regs.x.w, regs.a.w);
if(regs.p.m)return;
l5:
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, regs.a.w >> 8);
}
void bCPU::op_stz_addrx() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_c4(aa.w, aa.w + regs.x.w);
l4:
op_write(OPMODE_DBR, aa.w + regs.x.w, 0x0000);
if(regs.p.m)return;
l5:
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, 0x0000 >> 8);
}
void bCPU::op_sta_addry() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_c4(aa.w, aa.w + regs.y.w);
l4:
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
if(regs.p.m)return;
l5:
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
}
void bCPU::op_sta_long() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
aa.b = op_read();
l4:
op_write(OPMODE_LONG, aa.d, regs.a.l);
if(regs.p.m)return;
l5:
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
}
void bCPU::op_sta_longx() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
aa.b = op_read();
l4:
op_write(OPMODE_LONG, aa.d + regs.x.w, regs.a.l);
if(regs.p.m)return;
l5:
op_write(OPMODE_LONG, aa.d + regs.x.w + 1, regs.a.h);
}
void bCPU::op_sta_dp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
op_write(OPMODE_DP, dp, regs.a.w);
if(regs.p.m)return;
l4:
op_write(OPMODE_DP, dp + 1, regs.a.w >> 8);
}
void bCPU::op_stx_dp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
op_write(OPMODE_DP, dp, regs.x.w);
if(regs.p.x)return;
l4:
op_write(OPMODE_DP, dp + 1, regs.x.w >> 8);
}
void bCPU::op_sty_dp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
op_write(OPMODE_DP, dp, regs.y.w);
if(regs.p.x)return;
l4:
op_write(OPMODE_DP, dp + 1, regs.y.w >> 8);
}
void bCPU::op_stz_dp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
op_write(OPMODE_DP, dp, 0x0000);
if(regs.p.m)return;
l4:
op_write(OPMODE_DP, dp + 1, 0x0000 >> 8);
}
void bCPU::op_sta_dpx() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
op_write(OPMODE_DP, dp + regs.x.w, regs.a.w);
if(regs.p.m)return;
l5:
op_write(OPMODE_DP, dp + regs.x.w + 1, regs.a.w >> 8);
}
void bCPU::op_sty_dpx() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
op_write(OPMODE_DP, dp + regs.x.w, regs.y.w);
if(regs.p.x)return;
l5:
op_write(OPMODE_DP, dp + regs.x.w + 1, regs.y.w >> 8);
}
void bCPU::op_stz_dpx() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
op_write(OPMODE_DP, dp + regs.x.w, 0x0000);
if(regs.p.m)return;
l5:
op_write(OPMODE_DP, dp + regs.x.w + 1, 0x0000 >> 8);
}
void bCPU::op_stx_dpy() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
op_write(OPMODE_DP, dp + regs.y.w, regs.x.l);
if(regs.p.x)return;
l5:
op_write(OPMODE_DP, dp + regs.y.w + 1, regs.x.h);
}
void bCPU::op_sta_idp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
aa.l = op_read(OPMODE_DP, dp);
l4:
aa.h = op_read(OPMODE_DP, dp + 1);
l5:
op_write(OPMODE_DBR, aa.w, regs.a.l);
if(regs.p.m)return;
l6:
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
}
void bCPU::op_sta_ildp() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
aa.l = op_read(OPMODE_DP, dp);
l4:
aa.h = op_read(OPMODE_DP, dp + 1);
l5:
aa.b = op_read(OPMODE_DP, dp + 2);
l6:
op_write(OPMODE_LONG, aa.d, regs.a.l);
if(regs.p.m)return;
l7:
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
}
void bCPU::op_sta_idpx() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
aa.l = op_read(OPMODE_DP, dp + regs.x.w);
l5:
aa.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
l6:
op_write(OPMODE_DBR, aa.w, regs.a.l);
if(regs.p.m)return;
l7:
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
}
void bCPU::op_sta_idpy() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
aa.l = op_read(OPMODE_DP, dp);
l4:
aa.h = op_read(OPMODE_DP, dp + 1);
l5:
cpu_c4(aa.w, aa.w + regs.y.w);
l6:
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
if(regs.p.m)return;
l7:
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
}
void bCPU::op_sta_ildpy() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
aa.l = op_read(OPMODE_DP, dp);
l4:
aa.h = op_read(OPMODE_DP, dp + 1);
l5:
aa.b = op_read(OPMODE_DP, dp + 2);
l6:
op_write(OPMODE_LONG, aa.d + regs.y.w, regs.a.l);
if(regs.p.m)return;
l7:
op_write(OPMODE_LONG, aa.d + regs.y.w + 1, regs.a.h);
}
void bCPU::op_sta_sr() {
l1:
sp = op_read();
l2:
cpu_io();
l3:
op_write(OPMODE_SP, sp, regs.a.l);
if(regs.p.m)return;
l4:
op_write(OPMODE_SP, sp + 1, regs.a.h);
}
void bCPU::op_sta_isry() {
l1:
sp = op_read();
l2:
cpu_io();
l3:
aa.l = op_read(OPMODE_SP, sp);
l4:
aa.h = op_read(OPMODE_SP, sp + 1);
l5:
cpu_io();
l6:
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
if(regs.p.m)return;
l7:
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
}

View File

@@ -1,141 +0,0 @@
uint16 bCPU::vcounter() { return time.v; }
uint16 bCPU::hcounter() { return get_hcounter(); }
uint16 bCPU::hcycles() { return time.hc; }
bool bCPU::interlace() { return time.interlace; }
bool bCPU::interlace_field() { return time.interlace_field; }
bool bCPU::overscan() { return time.overscan; }
void bCPU::set_interlace(bool r) { time.interlace = r; }
void bCPU::set_overscan(bool r) { time.overscan = r; }
uint8 bCPU::dma_counter() { return (time.dma_counter + time.hc) & 6; }
//all scanlines are 1364 cycles long, except scanline 240
//on non-interlace odd-frames, which is 1360 cycles long.
//interlace mode has 525 scanlines: 263 on the even frame,
//and 262 on the odd.
//non-interlace mode has 524 scanlines: 262 scanlines on
//both even and odd frames.
//
//cycles per frame:
// 263 * 1364 = 358732
// 262 * 1364 = 357368
// 262 * 1364 - 4 = 357364
void bCPU::inc_vcounter() {
time.v++;
if(time.v >= time.frame_lines) {
time.v = 0;
time.interlace_field ^= 1;
if(time.interlace == true && time.interlace_field == 0) {
time.frame_lines = 263;
} else {
time.frame_lines = 262;
}
}
time.hc = 0;
time.dma_counter = time.line_cycles & 6;
if(time.v == 240 && time.interlace == false && time.interlace_field == 1) {
time.line_cycles = 1360;
} else {
time.line_cycles = 1364;
}
time.dram_refreshed = false;
}
//all dots are 4 cycles long, except dots 322 and 326. dots 322 and 326
//are 6 cycles long. this holds true for all scanlines except scanline
//240 on non-interlace odd frames. the reason for this is because this
//scanline is only 1360 cycles long, instead of 1364 like all other
//scanlines.
//this makes the effective range of hscan_pos 0-339 at all times.
//dot 322 range = { 1288, 1290, 1292 }
//dot 326 range = { 1306, 1308, 1310 }
uint16 bCPU::get_hcounter() {
if(time.v == 240 && time.interlace == false && time.interlace_field == 1) {
return time.hc >> 2;
}
return (time.hc - ((time.hc > 1288) << 1) - ((time.hc > 1306) << 1)) >> 2;
}
void bCPU::apu_sync() {
int cycles;
while(apusync.cycles >= 0) {
apu->run();
cycles = apu->cycles_executed();
if(cycles) {
apusync.cycles -= apusync.cpu_multbl[cycles];
}
}
}
void bCPU::dram_refresh() {
time.dram_refreshed = true;
add_cycles(40);
if(time.v != 240 || time.interlace != false || time.interlace_field != 1) {
//alternate between 534 and 538 every scanline except 240ni1
time.dram_refresh_pos ^= 12;
}
}
void bCPU::add_cycles(int cycles) {
cycles >>= 1;
while(cycles--) {
apusync.cycles += apusync.apu_freq << 1;
apu_sync();
time.hc += 2;
if(time.hc >= time.line_cycles) {
inc_vcounter();
if(time.v == 0) {
frame();
ppu->frame();
}
scanline();
ppu->scanline();
}
if(time.dram_refreshed == false && time.hc >= time.dram_refresh_pos) {
dram_refresh();
}
if(hdma_test() == true) {
hdma_run();
}
}
}
void bCPU::time_reset() {
//initial latch values for $213c/$213d
//[x]0035 : [y]0000 (53.0 -> 212) [lda $2137]
//[x]0038 : [y]0000 (56.5 -> 226) [nop : lda $2137]
time.v = 0;
time.hc = 186;
//upon SNES reset, start at scanline 0 non-interlace
time.interlace = false;
time.interlace_field = false;
time.overscan = false;
time.line_cycles = 1364;
time.frame_lines = 262;
time.dram_refreshed = false;
time.dram_refresh_pos = 538;
time.dma_counter = 0;
apusync.cycles = apusync.cpu_multbl[255];
}
void bCPU::time_init() {
apusync.cpu_freq = 21477272 >> 3;
apusync.apu_freq = 24576000 >> 3;
int i;
for(i=0;i<1024;i++) {
apusync.cpu_multbl[i] = i * apusync.cpu_freq;
apusync.apu_multbl[i] = i * apusync.apu_freq;
}
}

View File

@@ -1,38 +0,0 @@
struct {
uint16 v, hc;
bool interlace, interlace_field, overscan;
uint16 line_cycles, frame_lines;
bool dram_refreshed;
uint16 dram_refresh_pos;
uint8 dma_counter;
}time;
inline uint16 vcounter();
inline uint16 hcounter();
inline uint16 hcycles();
inline bool interlace();
inline bool interlace_field();
inline bool overscan();
inline void set_interlace(bool r);
inline void set_overscan (bool r);
inline uint8 dma_counter();
inline void inc_vcounter();
inline uint16 get_hcounter();
inline void apu_sync();
inline void dram_refresh();
inline void add_cycles(int cycles);
inline void time_reset();
inline void time_init();
//APU synchronization
struct {
int32 cpu_freq, apu_freq;
int32 cpu_multbl[1024], apu_multbl[1024];
int32 cycles;
}apusync;

Binary file not shown.

View File

@@ -1,3 +0,0 @@
cl /ML /O2 bcpugen.cpp
@pause
@del *.obj

View File

@@ -1,8 +0,0 @@
@del *.exe
@del bcpu_op_misc.cpp
@del bcpu_op_pc.cpp
@del bcpu_op_read.cpp
@del bcpu_op_rmw.cpp
@del bcpu_op_write.cpp
@del bcpu_optable.cpp
@del bcpu_op.h

View File

@@ -0,0 +1,18 @@
#define CLASS_NAME "bCPU"
#include "../../../lib/opgen.cpp"
int main() {
fph = fopen("op.h", "wb");
fpt = fopen("optable.cpp", "wb");
generate("op_read.cpp", "op_read.b");
generate("op_rmw.cpp", "op_rmw.b");
generate("op_write.cpp", "op_write.b");
generate("op_pc.cpp", "op_pc.b");
generate("op_misc.cpp", "op_misc.b");
fclose(fph);
fclose(fpt);
return 0;
}

3
src/cpu/bcpu/core/cc.bat Normal file
View File

@@ -0,0 +1,3 @@
cl /O2 /wd4996 bcpugen.cpp
@pause
@del *.obj

View File

@@ -0,0 +1,8 @@
@del *.exe
@del op_misc.cpp
@del op_pc.cpp
@del op_read.cpp
@del op_rmw.cpp
@del op_write.cpp
@del optable.cpp
@del op.h

View File

@@ -0,0 +1,90 @@
#include "opfn.cpp"
#include "op_read.cpp"
#include "op_rmw.cpp"
#include "op_write.cpp"
#include "op_pc.cpp"
#include "op_misc.cpp"
void bCPU::cpu_c2() {
if(regs.d.l != 0x00) {
cpu_io();
}
}
void bCPU::cpu_c4(uint16 x, uint16 y) {
if(!regs.p.x && (x & 0xff00) != (y & 0xff00)) {
cpu_io();
}
}
void bCPU::cpu_c6(uint16 addr) {
if(regs.e && (regs.pc.w & 0xff00) != (addr & 0xff00)) {
cpu_io();
}
}
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 = ((regs.db << 16) + addr) & 0xffffff;
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--;
}
}
void bCPU::init_op_tables() {
#include "optable.cpp"
}

74
src/cpu/bcpu/core/core.h Normal file
View File

@@ -0,0 +1,74 @@
/* External functions:
* void last_cycle();
* void cpu_io();
* uint8 mem_read(uint32 addr);
* void mem_write(uint32 addr, uint8 value);
*/
void (bCPU::*optbl[256])();
CPUReg24 aa, rd;
uint8 dp, sp;
//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();
inline void cpu_c2();
inline void cpu_c4(uint16 x, uint16 y);
inline void cpu_c6(uint16 addr);
enum {
OPMODE_ADDR, OPMODE_LONG,
OPMODE_DBR, OPMODE_PBR,
OPMODE_DP, OPMODE_SP
};
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);
inline void init_op_tables();
#include "op.h"

View File

@@ -186,7 +186,6 @@ void op_sta_idpy();
void op_sta_ildpy();
void op_sta_sr();
void op_sta_isry();
void op_bra();
void op_bcc();
void op_bcs();
void op_bne();
@@ -195,6 +194,7 @@ void op_bpl();
void op_bmi();
void op_bvc();
void op_bvs();
void op_bra();
void op_brl();
void op_jmp_addr();
void op_jmp_long();

View File

@@ -1,15 +1,17 @@
nop(0xea) {
1:cpu_io();
1:last_cycle();
cpu_io();
}
wdm(0x42) {
1:cpu_io();
regs.pc.w++;
1:last_cycle();
op_read();
}
xba(0xeb) {
1:cpu_io();
2:cpu_io();
2:last_cycle();
cpu_io();
regs.a.l ^= regs.a.h;
regs.a.h ^= regs.a.l;
regs.a.l ^= regs.a.h;
@@ -27,7 +29,8 @@ mvp(0x44, --) {
5:cpu_io();
if(regs.p.x) { regs.x.l$1; regs.y.l$1; }
else { regs.x.w$1; regs.y.w$1; }
6:cpu_io();
6:last_cycle();
cpu_io();
if(regs.a.w--)regs.pc.w -= 3;
}
@@ -39,30 +42,43 @@ cop(0x02, 0xfff4, 0xfff5, 0xffe4, 0xffe5) {
3:stack_write(regs.pc.h);
4:stack_write(regs.pc.l);
5:stack_write(regs.p);
6:rd.l = op_read(OPMODE_LONG, (regs.e)?$1:$3);
7:rd.h = op_read(OPMODE_LONG, (regs.e)?$2:$4);
6:rd.l = op_read(OPMODE_LONG, (regs.e) ? $1 : $3);
regs.pc.b = 0x00;
regs.pc.w = rd.w;
regs.p.i = 1;
regs.p.d = 0;
7:last_cycle();
rd.h = op_read(OPMODE_LONG, (regs.e) ? $2 : $4);
regs.pc.w = rd.w;
}
stp(0xdb) {
1:cpu_io();
status.cpu_state = CPUSTATE_STP;
2:cpu_io();
run_state.stp = true;
2:last_cycle();
cpu_io();
regs.pc.w--;
}
wai(0xcb) {
1:cpu_io();
status.cpu_state = CPUSTATE_WAI;
2:cpu_io();
regs.pc.w--;
run_state.wai = true;
2:last_cycle();
cpu_io();
//no wakeup delay if last_cycle() cancelled wai
if(run_state.wai == false)end;
3:last_cycle();
cpu_io();
//sleep another i/o cycle
//note: this should alert the debugger that wai is continuing...
if(run_state.wai == true)status.cycle_pos--;
//wai wakeup delay (one i/o cycle)
4:last_cycle();
cpu_io();
}
xce(0xfb) {
1:cpu_io();
1:last_cycle();
cpu_io();
bool c = regs.p.c;
regs.p.c = regs.e;
regs.e = c;
@@ -81,14 +97,16 @@ clv(0xb8, regs.p.v = 0),
sec(0x38, regs.p.c = 1),
sed(0xf8, regs.p.d = 1),
sei(0x78, regs.p.i = 1) {
1:cpu_io();
1:last_cycle();
cpu_io();
$1;
}
rep(0xc2, &=~),
sep(0xe2, |=) {
1:rd.l = op_read();
2:cpu_io();
2:last_cycle();
cpu_io();
regs.p $1 rd.l;
if(regs.e)regs.p |= 0x30;
if(regs.p.x) {
@@ -103,7 +121,8 @@ txa(0x8a, regs.p.m, a, x),
txy(0x9b, regs.p.x, y, x),
tya(0x98, regs.p.m, a, y),
tyx(0xbb, regs.p.x, x, y) {
1:cpu_io();
1:last_cycle();
cpu_io();
if($1) {
regs.$2.l = regs.$3.l;
regs.p.n = !!(regs.$2.l & 0x80);
@@ -116,27 +135,31 @@ tyx(0xbb, regs.p.x, x, y) {
}
tcd(0x5b) {
1:cpu_io();
1:last_cycle();
cpu_io();
regs.d.w = regs.a.w;
regs.p.n = !!(regs.d.w & 0x8000);
regs.p.z = (regs.d.w == 0);
}
tcs(0x1b) {
1:cpu_io();
1:last_cycle();
cpu_io();
regs.s.w = regs.a.w;
if(regs.e)regs.s.h = 0x01;
}
tdc(0x7b) {
1:cpu_io();
1:last_cycle();
cpu_io();
regs.a.w = regs.d.w;
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
tsc(0x3b) {
1:cpu_io();
1:last_cycle();
cpu_io();
regs.a.w = regs.s.w;
if(regs.e) {
regs.p.n = !!(regs.a.l & 0x80);
@@ -148,7 +171,8 @@ tsc(0x3b) {
}
tsx(0xba) {
1:cpu_io();
1:last_cycle();
cpu_io();
if(regs.p.x) {
regs.x.l = regs.s.l;
regs.p.n = !!(regs.x.l & 0x80);
@@ -161,15 +185,12 @@ tsx(0xba) {
}
txs(0x9a) {
1:cpu_io();
1:last_cycle();
cpu_io();
if(regs.e) {
regs.s.l = regs.x.l;
regs.p.n = !!(regs.s.l & 0x80);
regs.p.z = (regs.s.l == 0);
} else {
regs.s.w = regs.x.w;
regs.p.n = !!(regs.s.w & 0x8000);
regs.p.z = (regs.s.w == 0);
}
}
@@ -180,14 +201,16 @@ phd(0x0b, 0, d) {
1:cpu_io();
if($1)skip;
2:stack_write(regs.$2.h);
3:stack_write(regs.$2.l);
3:last_cycle();
stack_write(regs.$2.l);
}
phb(0x8b, regs.db),
phk(0x4b, regs.pc.b),
php(0x08, regs.p) {
1:cpu_io();
2:stack_write($1);
2:last_cycle();
stack_write($1);
}
pla(0x68, regs.p.m, a),
@@ -196,13 +219,15 @@ ply(0x7a, regs.p.x, y),
pld(0x2b, 0, d) {
1:cpu_io();
2:cpu_io();
3:regs.$2.l = stack_read();
3:if($1)last_cycle();
regs.$2.l = stack_read();
if($1) {
regs.p.n = !!(regs.$2.l & 0x80);
regs.p.z = (regs.$2.l == 0);
end;
}
4:regs.$2.h = stack_read();
4:last_cycle();
regs.$2.h = stack_read();
regs.p.n = !!(regs.$2.w & 0x8000);
regs.p.z = (regs.$2.w == 0);
}
@@ -210,7 +235,8 @@ pld(0x2b, 0, d) {
plb(0xab) {
1:cpu_io();
2:cpu_io();
3:regs.db = stack_read();
3:last_cycle();
regs.db = stack_read();
regs.p.n = !!(regs.db & 0x80);
regs.p.z = (regs.db == 0);
}
@@ -218,7 +244,8 @@ plb(0xab) {
plp(0x28) {
1:cpu_io();
2:cpu_io();
3:regs.p = stack_read();
3:last_cycle();
regs.p = stack_read();
if(regs.e)regs.p |= 0x30;
if(regs.p.x) {
regs.x.h = 0x00;
@@ -230,7 +257,8 @@ pea(0xf4) {
1:aa.l = op_read();
2:aa.h = op_read();
3:stack_write(aa.h);
4:stack_write(aa.l);
4:last_cycle();
stack_write(aa.l);
}
pei(0xd4) {
@@ -239,7 +267,8 @@ pei(0xd4) {
3:aa.l = op_read(OPMODE_DP, dp);
4:aa.h = op_read(OPMODE_DP, dp + 1);
5:stack_write(aa.h);
6:stack_write(aa.l);
6:last_cycle();
stack_write(aa.l);
}
per(0x62) {
@@ -248,5 +277,6 @@ per(0x62) {
3:cpu_io();
rd.w = regs.pc.d + (int16)aa.w;
4:stack_write(rd.h);
5:stack_write(rd.l);
5:last_cycle();
stack_write(rd.l);
}

View File

@@ -0,0 +1,864 @@
void bCPU::op_nop() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_wdm() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
op_read();
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_xba() {
switch(status.cycle_pos++) {
case 1: {
cpu_io();
} break;
case 2: {
last_cycle();
cpu_io();
regs.a.l ^= regs.a.h;
regs.a.h ^= regs.a.l;
regs.a.l ^= regs.a.h;
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_mvn() {
switch(status.cycle_pos++) {
case 1: {
dp = op_read();
} break;
case 2: {
sp = op_read();
} break;
case 3: {
regs.db = dp;
rd.l = op_read(OPMODE_LONG, (sp << 16) | regs.x.w);
} break;
case 4: {
op_write(OPMODE_LONG, (dp << 16) | regs.y.w, rd.l);
} break;
case 5: {
cpu_io();
if(regs.p.x) { regs.x.l++; regs.y.l++; }
else { regs.x.w++; regs.y.w++; }
} break;
case 6: {
last_cycle();
cpu_io();
if(regs.a.w--)regs.pc.w -= 3;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_mvp() {
switch(status.cycle_pos++) {
case 1: {
dp = op_read();
} break;
case 2: {
sp = op_read();
} break;
case 3: {
regs.db = dp;
rd.l = op_read(OPMODE_LONG, (sp << 16) | regs.x.w);
} break;
case 4: {
op_write(OPMODE_LONG, (dp << 16) | regs.y.w, rd.l);
} break;
case 5: {
cpu_io();
if(regs.p.x) { regs.x.l--; regs.y.l--; }
else { regs.x.w--; regs.y.w--; }
} break;
case 6: {
last_cycle();
cpu_io();
if(regs.a.w--)regs.pc.w -= 3;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_brk() {
switch(status.cycle_pos++) {
case 1: {
op_read();
if(regs.e)status.cycle_pos++;
} break;
case 2: {
stack_write(regs.pc.b);
} break;
case 3: {
stack_write(regs.pc.h);
} break;
case 4: {
stack_write(regs.pc.l);
} break;
case 5: {
stack_write(regs.p);
} break;
case 6: {
rd.l = op_read(OPMODE_LONG, (regs.e) ? 0xfffe : 0xffe6);
regs.pc.b = 0x00;
regs.p.i = 1;
regs.p.d = 0;
} break;
case 7: {
last_cycle();
rd.h = op_read(OPMODE_LONG, (regs.e) ? 0xffff : 0xffe7);
regs.pc.w = rd.w;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_cop() {
switch(status.cycle_pos++) {
case 1: {
op_read();
if(regs.e)status.cycle_pos++;
} break;
case 2: {
stack_write(regs.pc.b);
} break;
case 3: {
stack_write(regs.pc.h);
} break;
case 4: {
stack_write(regs.pc.l);
} break;
case 5: {
stack_write(regs.p);
} break;
case 6: {
rd.l = op_read(OPMODE_LONG, (regs.e) ? 0xfff4 : 0xffe4);
regs.pc.b = 0x00;
regs.p.i = 1;
regs.p.d = 0;
} break;
case 7: {
last_cycle();
rd.h = op_read(OPMODE_LONG, (regs.e) ? 0xfff5 : 0xffe5);
regs.pc.w = rd.w;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_stp() {
switch(status.cycle_pos++) {
case 1: {
cpu_io();
run_state.stp = true;
} break;
case 2: {
last_cycle();
cpu_io();
regs.pc.w--;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_wai() {
switch(status.cycle_pos++) {
case 1: {
cpu_io();
run_state.wai = true;
} break;
case 2: {
last_cycle();
cpu_io();
//no wakeup delay if last_cycle() cancelled wai
if(run_state.wai == false)status.cycle_pos = 0;
} break;
case 3: {
last_cycle();
cpu_io();
//sleep another i/o cycle
//note: this should alert the debugger that wai is continuing...
if(run_state.wai == true)status.cycle_pos--;
//wai wakeup delay (one i/o cycle)
} break;
case 4: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_xce() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
bool c = regs.p.c;
regs.p.c = regs.e;
regs.e = c;
if(regs.e) {
regs.p |= 0x30;
regs.x.h = 0x00;
regs.y.h = 0x00;
regs.s.h = 0x01;
}
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_clc() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
regs.p.c = 0;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_cld() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
regs.p.d = 0;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_cli() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
regs.p.i = 0;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_clv() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
regs.p.v = 0;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sec() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
regs.p.c = 1;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sed() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
regs.p.d = 1;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sei() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
regs.p.i = 1;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_rep() {
switch(status.cycle_pos++) {
case 1: {
rd.l = op_read();
} break;
case 2: {
last_cycle();
cpu_io();
regs.p &=~ rd.l;
if(regs.e)regs.p |= 0x30;
if(regs.p.x) {
regs.x.h = 0x00;
regs.y.h = 0x00;
}
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sep() {
switch(status.cycle_pos++) {
case 1: {
rd.l = op_read();
} break;
case 2: {
last_cycle();
cpu_io();
regs.p |= rd.l;
if(regs.e)regs.p |= 0x30;
if(regs.p.x) {
regs.x.h = 0x00;
regs.y.h = 0x00;
}
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_tax() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
if(regs.p.x) {
regs.x.l = regs.a.l;
regs.p.n = !!(regs.x.l & 0x80);
regs.p.z = (regs.x.l == 0);
} else {
regs.x.w = regs.a.w;
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
}
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_tay() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
if(regs.p.x) {
regs.y.l = regs.a.l;
regs.p.n = !!(regs.y.l & 0x80);
regs.p.z = (regs.y.l == 0);
} else {
regs.y.w = regs.a.w;
regs.p.n = !!(regs.y.w & 0x8000);
regs.p.z = (regs.y.w == 0);
}
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_txa() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
if(regs.p.m) {
regs.a.l = regs.x.l;
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
regs.a.w = regs.x.w;
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_txy() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
if(regs.p.x) {
regs.y.l = regs.x.l;
regs.p.n = !!(regs.y.l & 0x80);
regs.p.z = (regs.y.l == 0);
} else {
regs.y.w = regs.x.w;
regs.p.n = !!(regs.y.w & 0x8000);
regs.p.z = (regs.y.w == 0);
}
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_tya() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
if(regs.p.m) {
regs.a.l = regs.y.l;
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
regs.a.w = regs.y.w;
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_tyx() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
if(regs.p.x) {
regs.x.l = regs.y.l;
regs.p.n = !!(regs.x.l & 0x80);
regs.p.z = (regs.x.l == 0);
} else {
regs.x.w = regs.y.w;
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
}
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_tcd() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
regs.d.w = regs.a.w;
regs.p.n = !!(regs.d.w & 0x8000);
regs.p.z = (regs.d.w == 0);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_tcs() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
regs.s.w = regs.a.w;
if(regs.e)regs.s.h = 0x01;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_tdc() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
regs.a.w = regs.d.w;
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_tsc() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
regs.a.w = regs.s.w;
if(regs.e) {
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_tsx() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
if(regs.p.x) {
regs.x.l = regs.s.l;
regs.p.n = !!(regs.x.l & 0x80);
regs.p.z = (regs.x.l == 0);
} else {
regs.x.w = regs.s.w;
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
}
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_txs() {
switch(status.cycle_pos++) {
case 1: {
last_cycle();
cpu_io();
if(regs.e) {
regs.s.l = regs.x.l;
} else {
regs.s.w = regs.x.w;
}
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_pha() {
switch(status.cycle_pos++) {
case 1: {
cpu_io();
if(regs.p.m)status.cycle_pos++;
} break;
case 2: {
stack_write(regs.a.h);
} break;
case 3: {
last_cycle();
stack_write(regs.a.l);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_phx() {
switch(status.cycle_pos++) {
case 1: {
cpu_io();
if(regs.p.x)status.cycle_pos++;
} break;
case 2: {
stack_write(regs.x.h);
} break;
case 3: {
last_cycle();
stack_write(regs.x.l);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_phy() {
switch(status.cycle_pos++) {
case 1: {
cpu_io();
if(regs.p.x)status.cycle_pos++;
} break;
case 2: {
stack_write(regs.y.h);
} break;
case 3: {
last_cycle();
stack_write(regs.y.l);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_phd() {
switch(status.cycle_pos++) {
case 1: {
cpu_io();
if(0)status.cycle_pos++;
} break;
case 2: {
stack_write(regs. d.h);
} break;
case 3: {
last_cycle();
stack_write(regs. d.l);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_phb() {
switch(status.cycle_pos++) {
case 1: {
cpu_io();
} break;
case 2: {
last_cycle();
stack_write(regs.db);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_phk() {
switch(status.cycle_pos++) {
case 1: {
cpu_io();
} break;
case 2: {
last_cycle();
stack_write(regs.pc.b);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_php() {
switch(status.cycle_pos++) {
case 1: {
cpu_io();
} break;
case 2: {
last_cycle();
stack_write(regs.p);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_pla() {
switch(status.cycle_pos++) {
case 1: {
cpu_io();
} break;
case 2: {
cpu_io();
} break;
case 3: {
if(regs.p.m)last_cycle();
regs.a.l = stack_read();
if(regs.p.m) {
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
status.cycle_pos = 0;
}
} break;
case 4: {
last_cycle();
regs.a.h = stack_read();
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_plx() {
switch(status.cycle_pos++) {
case 1: {
cpu_io();
} break;
case 2: {
cpu_io();
} break;
case 3: {
if(regs.p.x)last_cycle();
regs.x.l = stack_read();
if(regs.p.x) {
regs.p.n = !!(regs.x.l & 0x80);
regs.p.z = (regs.x.l == 0);
status.cycle_pos = 0;
}
} break;
case 4: {
last_cycle();
regs.x.h = stack_read();
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_ply() {
switch(status.cycle_pos++) {
case 1: {
cpu_io();
} break;
case 2: {
cpu_io();
} break;
case 3: {
if(regs.p.x)last_cycle();
regs.y.l = stack_read();
if(regs.p.x) {
regs.p.n = !!(regs.y.l & 0x80);
regs.p.z = (regs.y.l == 0);
status.cycle_pos = 0;
}
} break;
case 4: {
last_cycle();
regs.y.h = stack_read();
regs.p.n = !!(regs.y.w & 0x8000);
regs.p.z = (regs.y.w == 0);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_pld() {
switch(status.cycle_pos++) {
case 1: {
cpu_io();
} break;
case 2: {
cpu_io();
} break;
case 3: {
if(0)last_cycle();
regs. d.l = stack_read();
if(0) {
regs.p.n = !!(regs. d.l & 0x80);
regs.p.z = (regs. d.l == 0);
status.cycle_pos = 0;
}
} break;
case 4: {
last_cycle();
regs. d.h = stack_read();
regs.p.n = !!(regs. d.w & 0x8000);
regs.p.z = (regs. d.w == 0);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_plb() {
switch(status.cycle_pos++) {
case 1: {
cpu_io();
} break;
case 2: {
cpu_io();
} break;
case 3: {
last_cycle();
regs.db = stack_read();
regs.p.n = !!(regs.db & 0x80);
regs.p.z = (regs.db == 0);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_plp() {
switch(status.cycle_pos++) {
case 1: {
cpu_io();
} break;
case 2: {
cpu_io();
} break;
case 3: {
last_cycle();
regs.p = stack_read();
if(regs.e)regs.p |= 0x30;
if(regs.p.x) {
regs.x.h = 0x00;
regs.y.h = 0x00;
}
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_pea() {
switch(status.cycle_pos++) {
case 1: {
aa.l = op_read();
} break;
case 2: {
aa.h = op_read();
} break;
case 3: {
stack_write(aa.h);
} break;
case 4: {
last_cycle();
stack_write(aa.l);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_pei() {
switch(status.cycle_pos++) {
case 1: {
dp = op_read();
} break;
case 2: {
cpu_c2();
} break;
case 3: {
aa.l = op_read(OPMODE_DP, dp);
} break;
case 4: {
aa.h = op_read(OPMODE_DP, dp + 1);
} break;
case 5: {
stack_write(aa.h);
} break;
case 6: {
last_cycle();
stack_write(aa.l);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_per() {
switch(status.cycle_pos++) {
case 1: {
aa.l = op_read();
} break;
case 2: {
aa.h = op_read();
} break;
case 3: {
cpu_io();
rd.w = regs.pc.d + (int16)aa.w;
} break;
case 4: {
stack_write(rd.h);
} break;
case 5: {
last_cycle();
stack_write(rd.l);
status.cycle_pos = 0;
} break;
}
}

View File

@@ -1,4 +1,3 @@
bra(0x80, 1),
bcc(0x90, !regs.p.c),
bcs(0xb0, regs.p.c),
bne(0xd0, !regs.p.z),
@@ -7,7 +6,8 @@ bpl(0x10, !regs.p.n),
bmi(0x30, regs.p.n),
bvc(0x50, !regs.p.v),
bvs(0x70, regs.p.v) {
1:rd.l = op_read();
1:if(!$1)last_cycle();
rd.l = op_read();
if($1) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
@@ -15,26 +15,39 @@ bvs(0x70, regs.p.v) {
end;
}
2:cpu_c6(aa.w);
3:cpu_io();
3:last_cycle();
cpu_io();
}
bra(0x80) {
1:rd.l = op_read();
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
2:cpu_c6(aa.w);
3:last_cycle();
cpu_io();
}
brl(0x82) {
1:rd.l = op_read();
2:rd.h = op_read();
3:cpu_io();
3:last_cycle();
cpu_io();
regs.pc.w = regs.pc.d + (int16)rd.w;
}
jmp_addr(0x4c) {
1:rd.l = op_read();
2:rd.h = op_read();
2:last_cycle();
rd.h = op_read();
regs.pc.w = rd.w;
}
jmp_long(0x5c) {
1:rd.l = op_read();
2:rd.h = op_read();
3:rd.b = op_read();
3:last_cycle();
rd.b = op_read();
regs.pc.d = rd.d & 0xffffff;
}
@@ -42,7 +55,8 @@ jmp_iaddr(0x6c) {
1:aa.l = op_read();
2:aa.h = op_read();
3:rd.l = op_read(OPMODE_ADDR, aa.w);
4:rd.h = op_read(OPMODE_ADDR, aa.w + 1);
4:last_cycle();
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
regs.pc.w = rd.w;
}
@@ -51,7 +65,8 @@ jmp_iaddrx(0x7c) {
2:aa.h = op_read();
3:cpu_io();
4:rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
5:rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
5:last_cycle();
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
regs.pc.w = rd.w;
}
@@ -60,7 +75,8 @@ jmp_iladdr(0xdc) {
2:aa.h = op_read();
3:rd.l = op_read(OPMODE_ADDR, aa.w);
4:rd.h = op_read(OPMODE_ADDR, aa.w + 1);
5:rd.b = op_read(OPMODE_ADDR, aa.w + 2);
5:last_cycle();
rd.b = op_read(OPMODE_ADDR, aa.w + 2);
regs.pc.d = rd.d & 0xffffff;
}
@@ -70,7 +86,8 @@ jsr_addr(0x20) {
3:cpu_io();
4:regs.pc.w--;
stack_write(regs.pc.h);
5:stack_write(regs.pc.l);
5:last_cycle();
stack_write(regs.pc.l);
regs.pc.w = aa.w;
}
@@ -82,7 +99,8 @@ jsr_long(0x22) {
5:aa.b = op_read();
6:regs.pc.w--;
stack_write(regs.pc.h);
7:stack_write(regs.pc.l);
7:last_cycle();
stack_write(regs.pc.l);
regs.pc.d = aa.d & 0xffffff;
}
@@ -93,7 +111,8 @@ jsr_iaddrx(0xfc) {
4:aa.h = op_read();
5:cpu_io();
6:rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
7:rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
7:last_cycle();
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
regs.pc.w = rd.w;
}
@@ -107,12 +126,14 @@ rti(0x40) {
regs.y.h = 0x00;
}
4:rd.l = stack_read();
5:rd.h = stack_read();
5:if(regs.e)last_cycle();
rd.h = stack_read();
if(regs.e) {
regs.pc.w = rd.w;
end;
}
6:rd.b = stack_read();
6:last_cycle();
rd.b = stack_read();
regs.pc.d = rd.d & 0xffffff;
}
@@ -121,7 +142,8 @@ rts(0x60) {
2:cpu_io();
3:rd.l = stack_read();
4:rd.h = stack_read();
5:cpu_io();
5:last_cycle();
cpu_io();
regs.pc.w = rd.w;
regs.pc.w++;
}
@@ -131,7 +153,8 @@ rtl(0x6b) {
2:cpu_io();
3:rd.l = stack_read();
4:rd.h = stack_read();
5:rd.b = stack_read();
5:last_cycle();
rd.b = stack_read();
regs.pc.d = rd.d & 0xffffff;
regs.pc.w++;
}

483
src/cpu/bcpu/core/op_pc.cpp Normal file
View File

@@ -0,0 +1,483 @@
void bCPU::op_bcc() {
switch(status.cycle_pos++) {
case 1: {
if(!!regs.p.c)last_cycle();
rd.l = op_read();
if(!regs.p.c) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
} break;
case 2: {
cpu_c6(aa.w);
} break;
case 3: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_bcs() {
switch(status.cycle_pos++) {
case 1: {
if(!regs.p.c)last_cycle();
rd.l = op_read();
if(regs.p.c) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
} break;
case 2: {
cpu_c6(aa.w);
} break;
case 3: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_bne() {
switch(status.cycle_pos++) {
case 1: {
if(!!regs.p.z)last_cycle();
rd.l = op_read();
if(!regs.p.z) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
} break;
case 2: {
cpu_c6(aa.w);
} break;
case 3: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_beq() {
switch(status.cycle_pos++) {
case 1: {
if(!regs.p.z)last_cycle();
rd.l = op_read();
if(regs.p.z) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
} break;
case 2: {
cpu_c6(aa.w);
} break;
case 3: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_bpl() {
switch(status.cycle_pos++) {
case 1: {
if(!!regs.p.n)last_cycle();
rd.l = op_read();
if(!regs.p.n) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
} break;
case 2: {
cpu_c6(aa.w);
} break;
case 3: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_bmi() {
switch(status.cycle_pos++) {
case 1: {
if(!regs.p.n)last_cycle();
rd.l = op_read();
if(regs.p.n) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
} break;
case 2: {
cpu_c6(aa.w);
} break;
case 3: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_bvc() {
switch(status.cycle_pos++) {
case 1: {
if(!!regs.p.v)last_cycle();
rd.l = op_read();
if(!regs.p.v) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
} break;
case 2: {
cpu_c6(aa.w);
} break;
case 3: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_bvs() {
switch(status.cycle_pos++) {
case 1: {
if(!regs.p.v)last_cycle();
rd.l = op_read();
if(regs.p.v) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
} break;
case 2: {
cpu_c6(aa.w);
} break;
case 3: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_bra() {
switch(status.cycle_pos++) {
case 1: {
rd.l = op_read();
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} break;
case 2: {
cpu_c6(aa.w);
} break;
case 3: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_brl() {
switch(status.cycle_pos++) {
case 1: {
rd.l = op_read();
} break;
case 2: {
rd.h = op_read();
} break;
case 3: {
last_cycle();
cpu_io();
regs.pc.w = regs.pc.d + (int16)rd.w;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_jmp_addr() {
switch(status.cycle_pos++) {
case 1: {
rd.l = op_read();
} break;
case 2: {
last_cycle();
rd.h = op_read();
regs.pc.w = rd.w;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_jmp_long() {
switch(status.cycle_pos++) {
case 1: {
rd.l = op_read();
} break;
case 2: {
rd.h = op_read();
} break;
case 3: {
last_cycle();
rd.b = op_read();
regs.pc.d = rd.d & 0xffffff;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_jmp_iaddr() {
switch(status.cycle_pos++) {
case 1: {
aa.l = op_read();
} break;
case 2: {
aa.h = op_read();
} break;
case 3: {
rd.l = op_read(OPMODE_ADDR, aa.w);
} break;
case 4: {
last_cycle();
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
regs.pc.w = rd.w;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_jmp_iaddrx() {
switch(status.cycle_pos++) {
case 1: {
aa.l = op_read();
} break;
case 2: {
aa.h = op_read();
} break;
case 3: {
cpu_io();
} break;
case 4: {
rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
} break;
case 5: {
last_cycle();
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
regs.pc.w = rd.w;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_jmp_iladdr() {
switch(status.cycle_pos++) {
case 1: {
aa.l = op_read();
} break;
case 2: {
aa.h = op_read();
} break;
case 3: {
rd.l = op_read(OPMODE_ADDR, aa.w);
} break;
case 4: {
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
} break;
case 5: {
last_cycle();
rd.b = op_read(OPMODE_ADDR, aa.w + 2);
regs.pc.d = rd.d & 0xffffff;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_jsr_addr() {
switch(status.cycle_pos++) {
case 1: {
aa.l = op_read();
} break;
case 2: {
aa.h = op_read();
} break;
case 3: {
cpu_io();
} break;
case 4: {
regs.pc.w--;
stack_write(regs.pc.h);
} break;
case 5: {
last_cycle();
stack_write(regs.pc.l);
regs.pc.w = aa.w;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_jsr_long() {
switch(status.cycle_pos++) {
case 1: {
aa.l = op_read();
} break;
case 2: {
aa.h = op_read();
} break;
case 3: {
stack_write(regs.pc.b);
} break;
case 4: {
cpu_io();
} break;
case 5: {
aa.b = op_read();
} break;
case 6: {
regs.pc.w--;
stack_write(regs.pc.h);
} break;
case 7: {
last_cycle();
stack_write(regs.pc.l);
regs.pc.d = aa.d & 0xffffff;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_jsr_iaddrx() {
switch(status.cycle_pos++) {
case 1: {
aa.l = op_read();
} break;
case 2: {
stack_write(regs.pc.h);
} break;
case 3: {
stack_write(regs.pc.l);
} break;
case 4: {
aa.h = op_read();
} break;
case 5: {
cpu_io();
} break;
case 6: {
rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
} break;
case 7: {
last_cycle();
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
regs.pc.w = rd.w;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_rti() {
switch(status.cycle_pos++) {
case 1: {
cpu_io();
} break;
case 2: {
cpu_io();
} break;
case 3: {
regs.p = stack_read();
if(regs.e)regs.p |= 0x30;
if(regs.p.x) {
regs.x.h = 0x00;
regs.y.h = 0x00;
}
} break;
case 4: {
rd.l = stack_read();
} break;
case 5: {
if(regs.e)last_cycle();
rd.h = stack_read();
if(regs.e) {
regs.pc.w = rd.w;
status.cycle_pos = 0;
}
} break;
case 6: {
last_cycle();
rd.b = stack_read();
regs.pc.d = rd.d & 0xffffff;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_rts() {
switch(status.cycle_pos++) {
case 1: {
cpu_io();
} break;
case 2: {
cpu_io();
} break;
case 3: {
rd.l = stack_read();
} break;
case 4: {
rd.h = stack_read();
} break;
case 5: {
last_cycle();
cpu_io();
regs.pc.w = rd.w;
regs.pc.w++;
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_rtl() {
switch(status.cycle_pos++) {
case 1: {
cpu_io();
} break;
case 2: {
cpu_io();
} break;
case 3: {
rd.l = stack_read();
} break;
case 4: {
rd.h = stack_read();
} break;
case 5: {
last_cycle();
rd.b = stack_read();
regs.pc.d = rd.d & 0xffffff;
regs.pc.w++;
status.cycle_pos = 0;
} break;
}
}

View File

@@ -9,9 +9,11 @@ ldx_const(0xa2, ldx, regs.p.x),
ldy_const(0xa0, ldy, regs.p.x),
ora_const(0x09, ora, regs.p.m),
sbc_const(0xe9, sbc, regs.p.m) {
1:rd.l = op_read();
1:if($2)last_cycle();
rd.l = op_read();
if($2) { op_$1_b(); end; }
2:rd.h = op_read();
2:last_cycle();
rd.h = op_read();
op_$1_w();
}
@@ -29,9 +31,11 @@ ora_addr(0x0d, ora, regs.p.m),
sbc_addr(0xed, sbc, regs.p.m) {
1:aa.l = op_read();
2:aa.h = op_read();
3:rd.l = op_read(OPMODE_DBR, aa.w);
3:if($2)last_cycle();
rd.l = op_read(OPMODE_DBR, aa.w);
if($2) { op_$1_b(); end; }
4:rd.h = op_read(OPMODE_DBR, aa.w + 1);
4:last_cycle();
rd.h = op_read(OPMODE_DBR, aa.w + 1);
op_$1_w();
}
@@ -47,9 +51,11 @@ sbc_addrx(0xfd, sbc, regs.p.m) {
1:aa.l = op_read();
2:aa.h = op_read();
3:cpu_c4(aa.w, aa.w + regs.x.w);
4:rd.l = op_read(OPMODE_DBR, aa.w + regs.x.w);
4:if($2)last_cycle();
rd.l = op_read(OPMODE_DBR, aa.w + regs.x.w);
if($2) { op_$1_b(); end; }
5:rd.h = op_read(OPMODE_DBR, aa.w + regs.x.w + 1);
5:last_cycle();
rd.h = op_read(OPMODE_DBR, aa.w + regs.x.w + 1);
op_$1_w();
}
@@ -64,9 +70,11 @@ sbc_addry(0xf9, sbc, regs.p.m) {
1:aa.l = op_read();
2:aa.h = op_read();
3:cpu_c4(aa.w, aa.w + regs.y.w);
4:rd.l = op_read(OPMODE_DBR, aa.w + regs.y.w);
4:if($2)last_cycle();
rd.l = op_read(OPMODE_DBR, aa.w + regs.y.w);
if($2) { op_$1_b(); end; }
5:rd.h = op_read(OPMODE_DBR, aa.w + regs.y.w + 1);
5:last_cycle();
rd.h = op_read(OPMODE_DBR, aa.w + regs.y.w + 1);
op_$1_w();
}
@@ -80,9 +88,11 @@ sbc_long(0xef, sbc, regs.p.m) {
1:aa.l = op_read();
2:aa.h = op_read();
3:aa.b = op_read();
4:rd.l = op_read(OPMODE_LONG, aa.d);
4:if($2)last_cycle();
rd.l = op_read(OPMODE_LONG, aa.d);
if($2) { op_$1_b(); end; }
5:rd.h = op_read(OPMODE_LONG, aa.d + 1);
5:last_cycle();
rd.h = op_read(OPMODE_LONG, aa.d + 1);
op_$1_w();
}
@@ -96,9 +106,11 @@ sbc_longx(0xff, sbc, regs.p.m) {
1:aa.l = op_read();
2:aa.h = op_read();
3:aa.b = op_read();
4:rd.l = op_read(OPMODE_LONG, aa.d + regs.x.w);
4:if($2)last_cycle();
rd.l = op_read(OPMODE_LONG, aa.d + regs.x.w);
if($2) { op_$1_b(); end; }
5:rd.h = op_read(OPMODE_LONG, aa.d + regs.x.w + 1);
5:last_cycle();
rd.h = op_read(OPMODE_LONG, aa.d + regs.x.w + 1);
op_$1_w();
}
@@ -116,9 +128,11 @@ ora_dp(0x05, ora, regs.p.m),
sbc_dp(0xe5, sbc, regs.p.m) {
1:dp = op_read();
2:cpu_c2();
3:rd.l = op_read(OPMODE_DP, dp);
3:if($2)last_cycle();
rd.l = op_read(OPMODE_DP, dp);
if($2) { op_$1_b(); end; }
4:rd.h = op_read(OPMODE_DP, dp + 1);
4:last_cycle();
rd.h = op_read(OPMODE_DP, dp + 1);
op_$1_w();
}
@@ -134,9 +148,11 @@ sbc_dpx(0xf5, sbc, regs.p.m) {
1:dp = op_read();
2:cpu_c2();
3:cpu_io();
4:rd.l = op_read(OPMODE_DP, dp + regs.x.w);
4:if($2)last_cycle();
rd.l = op_read(OPMODE_DP, dp + regs.x.w);
if($2) { op_$1_b(); end; }
5:rd.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
5:last_cycle();
rd.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
op_$1_w();
}
@@ -144,9 +160,11 @@ ldx_dpy(0xb6, ldx, regs.p.x) {
1:dp = op_read();
2:cpu_c2();
3:cpu_io();
4:rd.l = op_read(OPMODE_DP, dp + regs.y.w);
4:if($2)last_cycle();
rd.l = op_read(OPMODE_DP, dp + regs.y.w);
if($2) { op_$1_b(); end; }
5:rd.h = op_read(OPMODE_DP, dp + regs.y.w + 1);
5:last_cycle();
rd.h = op_read(OPMODE_DP, dp + regs.y.w + 1);
op_$1_w();
}
@@ -161,9 +179,11 @@ sbc_idp(0xf2, sbc, regs.p.m) {
2:cpu_c2();
3:aa.l = op_read(OPMODE_DP, dp);
4:aa.h = op_read(OPMODE_DP, dp + 1);
5:rd.l = op_read(OPMODE_DBR, aa.w);
5:if($2)last_cycle();
rd.l = op_read(OPMODE_DBR, aa.w);
if($2) { op_$1_b(); end; }
6:rd.h = op_read(OPMODE_DBR, aa.w + 1);
6:last_cycle();
rd.h = op_read(OPMODE_DBR, aa.w + 1);
op_$1_w();
}
@@ -179,9 +199,11 @@ sbc_idpx(0xe1, sbc, regs.p.m) {
3:cpu_io();
4:aa.l = op_read(OPMODE_DP, dp + regs.x.w);
5:aa.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
6:rd.l = op_read(OPMODE_DBR, aa.w);
6:if($2)last_cycle();
rd.l = op_read(OPMODE_DBR, aa.w);
if($2) { op_$1_b(); end; }
7:rd.h = op_read(OPMODE_DBR, aa.w + 1);
7:last_cycle();
rd.h = op_read(OPMODE_DBR, aa.w + 1);
op_$1_w();
}
@@ -197,9 +219,11 @@ sbc_idpy(0xf1, sbc, regs.p.m) {
3:aa.l = op_read(OPMODE_DP, dp);
4:aa.h = op_read(OPMODE_DP, dp + 1);
5:cpu_c4(aa.w, aa.w + regs.y.w);
6:rd.l = op_read(OPMODE_DBR, aa.w + regs.y.w);
6:if($2)last_cycle();
rd.l = op_read(OPMODE_DBR, aa.w + regs.y.w);
if($2) { op_$1_b(); end; }
7:rd.h = op_read(OPMODE_DBR, aa.w + regs.y.w + 1);
7:last_cycle();
rd.h = op_read(OPMODE_DBR, aa.w + regs.y.w + 1);
op_$1_w();
}
@@ -215,9 +239,11 @@ sbc_ildp(0xe7, sbc, regs.p.m) {
3:aa.l = op_read(OPMODE_DP, dp);
4:aa.h = op_read(OPMODE_DP, dp + 1);
5:aa.b = op_read(OPMODE_DP, dp + 2);
6:rd.l = op_read(OPMODE_LONG, aa.d);
6:if($2)last_cycle();
rd.l = op_read(OPMODE_LONG, aa.d);
if($2) { op_$1_b(); end; }
7:rd.h = op_read(OPMODE_LONG, aa.d + 1);
7:last_cycle();
rd.h = op_read(OPMODE_LONG, aa.d + 1);
op_$1_w();
}
@@ -233,9 +259,11 @@ sbc_ildpy(0xf7, sbc, regs.p.m) {
3:aa.l = op_read(OPMODE_DP, dp);
4:aa.h = op_read(OPMODE_DP, dp + 1);
5:aa.b = op_read(OPMODE_DP, dp + 2);
6:rd.l = op_read(OPMODE_LONG, aa.d + regs.y.w);
6:if($2)last_cycle();
rd.l = op_read(OPMODE_LONG, aa.d + regs.y.w);
if($2) { op_$1_b(); end; }
7:rd.h = op_read(OPMODE_LONG, aa.d + regs.y.w + 1);
7:last_cycle();
rd.h = op_read(OPMODE_LONG, aa.d + regs.y.w + 1);
op_$1_w();
}
@@ -248,9 +276,11 @@ ora_sr(0x03, ora, regs.p.m),
sbc_sr(0xe3, sbc, regs.p.m) {
1:sp = op_read();
2:cpu_io();
3:rd.l = op_read(OPMODE_SP, sp);
3:if($2)last_cycle();
rd.l = op_read(OPMODE_SP, sp);
if($2) { op_$1_b(); end; }
4:rd.h = op_read(OPMODE_SP, sp + 1);
4:last_cycle();
rd.h = op_read(OPMODE_SP, sp + 1);
op_$1_w();
}
@@ -266,18 +296,22 @@ sbc_isry(0xf3, sbc) {
3:aa.l = op_read(OPMODE_SP, sp);
4:aa.h = op_read(OPMODE_SP, sp + 1);
5:cpu_io();
6:rd.l = op_read(OPMODE_DBR, aa.w + regs.y.w);
6:if(regs.p.m)last_cycle();
rd.l = op_read(OPMODE_DBR, aa.w + regs.y.w);
if(regs.p.m) { op_$1_b(); end; }
7:rd.h = op_read(OPMODE_DBR, aa.w + regs.y.w + 1);
7:last_cycle();
rd.h = op_read(OPMODE_DBR, aa.w + regs.y.w + 1);
op_$1_w();
}
bit_const(0x89) {
1:rd.l = op_read();
1:if(regs.p.m)last_cycle();
rd.l = op_read();
if(regs.p.m) {
regs.p.z = ((rd.l & regs.a.l) == 0);
end;
}
2:rd.h = op_read();
2:last_cycle();
rd.h = op_read();
regs.p.z = ((rd.w & regs.a.w) == 0);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,8 @@
inc(0x1a, regs.p.m, a),
inx(0xe8, regs.p.x, x),
iny(0xc8, regs.p.x, y) {
1:cpu_io();
1:last_cycle();
cpu_io();
if($1) {
regs.$2.l++;
regs.p.n = !!(regs.$2.l & 0x80);
@@ -16,7 +17,8 @@ iny(0xc8, regs.p.x, y) {
dec(0x3a, regs.p.m, a),
dex(0xca, regs.p.x, x),
dey(0x88, regs.p.x, y) {
1:cpu_io();
1:last_cycle();
cpu_io();
if($1) {
regs.$2.l--;
regs.p.n = !!(regs.$2.l & 0x80);
@@ -29,7 +31,8 @@ dey(0x88, regs.p.x, y) {
}
asl(0x0a) {
1:cpu_io();
1:last_cycle();
cpu_io();
if(regs.p.m) {
regs.p.c = !!(regs.a.l & 0x80);
regs.a.l <<= 1;
@@ -44,7 +47,8 @@ asl(0x0a) {
}
lsr(0x4a) {
1:cpu_io();
1:last_cycle();
cpu_io();
if(regs.p.m) {
regs.p.c = regs.a.l & 1;
regs.a.l >>= 1;
@@ -59,7 +63,8 @@ lsr(0x4a) {
}
rol(0x2a) {
1:cpu_io();
1:last_cycle();
cpu_io();
uint16 c = regs.p.c;
if(regs.p.m) {
regs.p.c = !!(regs.a.l & 0x80);
@@ -77,7 +82,8 @@ rol(0x2a) {
}
ror(0x6a) {
1:cpu_io();
1:last_cycle();
cpu_io();
uint16 c;
if(regs.p.m) {
c = (regs.p.c)?0x80:0;
@@ -113,7 +119,8 @@ tsb_addr(0x0c, tsb) {
if(regs.p.m) { op_$1_b(); skip; }
else op_$1_w();
6:op_write(OPMODE_DBR, aa.w + 1, rd.h);
7:op_write(OPMODE_DBR, aa.w, rd.l);
7:last_cycle();
op_write(OPMODE_DBR, aa.w, rd.l);
}
inc_addrx(0xfe, inc),
@@ -132,7 +139,8 @@ ror_addrx(0x7e, ror) {
if(regs.p.m) { op_$1_b(); skip; }
else op_$1_w();
7:op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
8:op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
8:last_cycle();
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
}
inc_dp(0xe6, inc),
@@ -152,7 +160,8 @@ tsb_dp(0x04, tsb) {
if(regs.p.m) { op_$1_b(); skip; }
else op_$1_w();
6:op_write(OPMODE_DP, dp + 1, rd.h);
7:op_write(OPMODE_DP, dp, rd.l);
7:last_cycle();
op_write(OPMODE_DP, dp, rd.l);
}
inc_dpx(0xf6, inc),
@@ -171,5 +180,6 @@ ror_dpx(0x76, ror) {
if(regs.p.m) { op_$1_b(); skip; }
else op_$1_w();
7:op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
8:op_write(OPMODE_DP, dp + regs.x.w, rd.l);
8:last_cycle();
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
}

1110
src/cpu/bcpu/core/op_rmw.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,181 @@
sta_addr(0x8d, regs.p.m, regs.a.w),
stx_addr(0x8e, regs.p.x, regs.x.w),
sty_addr(0x8c, regs.p.x, regs.y.w),
stz_addr(0x9c, regs.p.m, 0x0000) {
1:aa.l = op_read();
2:aa.h = op_read();
3:if($1)last_cycle();
op_write(OPMODE_DBR, aa.w, $2);
if($1)end;
4:last_cycle();
op_write(OPMODE_DBR, aa.w + 1, $2 >> 8);
}
sta_addrx(0x9d, regs.p.m, regs.a.w),
stz_addrx(0x9e, regs.p.m, 0x0000) {
1:aa.l = op_read();
2:aa.h = op_read();
3:cpu_c4(aa.w, aa.w + regs.x.w);
4:if($1)last_cycle();
op_write(OPMODE_DBR, aa.w + regs.x.w, $2);
if($1)end;
5:last_cycle();
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, $2 >> 8);
}
sta_addry(0x99) {
1:aa.l = op_read();
2:aa.h = op_read();
3:cpu_c4(aa.w, aa.w + regs.y.w);
4:if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
if(regs.p.m)end;
5:last_cycle();
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
}
sta_long(0x8f) {
1:aa.l = op_read();
2:aa.h = op_read();
3:aa.b = op_read();
4:if(regs.p.m)last_cycle();
op_write(OPMODE_LONG, aa.d, regs.a.l);
if(regs.p.m)end;
5:last_cycle();
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
}
sta_longx(0x9f) {
1:aa.l = op_read();
2:aa.h = op_read();
3:aa.b = op_read();
4:if(regs.p.m)last_cycle();
op_write(OPMODE_LONG, aa.d + regs.x.w, regs.a.l);
if(regs.p.m)end;
5:last_cycle();
op_write(OPMODE_LONG, aa.d + regs.x.w + 1, regs.a.h);
}
sta_dp(0x85, regs.p.m, regs.a.w),
stx_dp(0x86, regs.p.x, regs.x.w),
sty_dp(0x84, regs.p.x, regs.y.w),
stz_dp(0x64, regs.p.m, 0x0000) {
1:dp = op_read();
2:cpu_c2();
3:if($1)last_cycle();
op_write(OPMODE_DP, dp, $2);
if($1)end;
4:last_cycle();
op_write(OPMODE_DP, dp + 1, $2 >> 8);
}
sta_dpx(0x95, regs.p.m, regs.a.w),
sty_dpx(0x94, regs.p.x, regs.y.w),
stz_dpx(0x74, regs.p.m, 0x0000) {
1:dp = op_read();
2:cpu_c2();
3:cpu_io();
4:if($1)last_cycle();
op_write(OPMODE_DP, dp + regs.x.w, $2);
if($1)end;
5:last_cycle();
op_write(OPMODE_DP, dp + regs.x.w + 1, $2 >> 8);
}
stx_dpy(0x96) {
1:dp = op_read();
2:cpu_c2();
3:cpu_io();
4:if(regs.p.x)last_cycle();
op_write(OPMODE_DP, dp + regs.y.w, regs.x.l);
if(regs.p.x)end;
5:last_cycle();
op_write(OPMODE_DP, dp + regs.y.w + 1, regs.x.h);
}
sta_idp(0x92) {
1:dp = op_read();
2:cpu_c2();
3:aa.l = op_read(OPMODE_DP, dp);
4:aa.h = op_read(OPMODE_DP, dp + 1);
5:if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w, regs.a.l);
if(regs.p.m)end;
6:last_cycle();
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
}
sta_ildp(0x87) {
1:dp = op_read();
2:cpu_c2();
3:aa.l = op_read(OPMODE_DP, dp);
4:aa.h = op_read(OPMODE_DP, dp + 1);
5:aa.b = op_read(OPMODE_DP, dp + 2);
6:if(regs.p.m)last_cycle();
op_write(OPMODE_LONG, aa.d, regs.a.l);
if(regs.p.m)end;
7:last_cycle();
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
}
sta_idpx(0x81) {
1:dp = op_read();
2:cpu_c2();
3:cpu_io();
4:aa.l = op_read(OPMODE_DP, dp + regs.x.w);
5:aa.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
6:if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w, regs.a.l);
if(regs.p.m)end;
7:last_cycle();
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
}
sta_idpy(0x91) {
1:dp = op_read();
2:cpu_c2();
3:aa.l = op_read(OPMODE_DP, dp);
4:aa.h = op_read(OPMODE_DP, dp + 1);
5:cpu_c4(aa.w, aa.w + regs.y.w);
6:if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
if(regs.p.m)end;
7:last_cycle();
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
}
sta_ildpy(0x97) {
1:dp = op_read();
2:cpu_c2();
3:aa.l = op_read(OPMODE_DP, dp);
4:aa.h = op_read(OPMODE_DP, dp + 1);
5:aa.b = op_read(OPMODE_DP, dp + 2);
6:if(regs.p.m)last_cycle();
op_write(OPMODE_LONG, aa.d + regs.y.w, regs.a.l);
if(regs.p.m)end;
7:last_cycle();
op_write(OPMODE_LONG, aa.d + regs.y.w + 1, regs.a.h);
}
sta_sr(0x83) {
1:sp = op_read();
2:cpu_io();
3:if(regs.p.m)last_cycle();
op_write(OPMODE_SP, sp, regs.a.l);
if(regs.p.m)end;
4:last_cycle();
op_write(OPMODE_SP, sp + 1, regs.a.h);
}
sta_isry(0x93) {
1:sp = op_read();
2:cpu_io();
3:aa.l = op_read(OPMODE_SP, sp);
4:aa.h = op_read(OPMODE_SP, sp + 1);
5:cpu_io();
6:if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
if(regs.p.m)end;
7:last_cycle();
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
}

View File

@@ -0,0 +1,582 @@
void bCPU::op_sta_addr() {
switch(status.cycle_pos++) {
case 1: {
aa.l = op_read();
} break;
case 2: {
aa.h = op_read();
} break;
case 3: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w, regs.a.w);
if(regs.p.m)status.cycle_pos = 0;
} break;
case 4: {
last_cycle();
op_write(OPMODE_DBR, aa.w + 1, regs.a.w >> 8);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_stx_addr() {
switch(status.cycle_pos++) {
case 1: {
aa.l = op_read();
} break;
case 2: {
aa.h = op_read();
} break;
case 3: {
if(regs.p.x)last_cycle();
op_write(OPMODE_DBR, aa.w, regs.x.w);
if(regs.p.x)status.cycle_pos = 0;
} break;
case 4: {
last_cycle();
op_write(OPMODE_DBR, aa.w + 1, regs.x.w >> 8);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sty_addr() {
switch(status.cycle_pos++) {
case 1: {
aa.l = op_read();
} break;
case 2: {
aa.h = op_read();
} break;
case 3: {
if(regs.p.x)last_cycle();
op_write(OPMODE_DBR, aa.w, regs.y.w);
if(regs.p.x)status.cycle_pos = 0;
} break;
case 4: {
last_cycle();
op_write(OPMODE_DBR, aa.w + 1, regs.y.w >> 8);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_stz_addr() {
switch(status.cycle_pos++) {
case 1: {
aa.l = op_read();
} break;
case 2: {
aa.h = op_read();
} break;
case 3: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w, 0x0000);
if(regs.p.m)status.cycle_pos = 0;
} break;
case 4: {
last_cycle();
op_write(OPMODE_DBR, aa.w + 1, 0x0000 >> 8);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sta_addrx() {
switch(status.cycle_pos++) {
case 1: {
aa.l = op_read();
} break;
case 2: {
aa.h = op_read();
} break;
case 3: {
cpu_c4(aa.w, aa.w + regs.x.w);
} break;
case 4: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w + regs.x.w, regs.a.w);
if(regs.p.m)status.cycle_pos = 0;
} break;
case 5: {
last_cycle();
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, regs.a.w >> 8);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_stz_addrx() {
switch(status.cycle_pos++) {
case 1: {
aa.l = op_read();
} break;
case 2: {
aa.h = op_read();
} break;
case 3: {
cpu_c4(aa.w, aa.w + regs.x.w);
} break;
case 4: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w + regs.x.w, 0x0000);
if(regs.p.m)status.cycle_pos = 0;
} break;
case 5: {
last_cycle();
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, 0x0000 >> 8);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sta_addry() {
switch(status.cycle_pos++) {
case 1: {
aa.l = op_read();
} break;
case 2: {
aa.h = op_read();
} break;
case 3: {
cpu_c4(aa.w, aa.w + regs.y.w);
} break;
case 4: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
} break;
case 5: {
last_cycle();
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sta_long() {
switch(status.cycle_pos++) {
case 1: {
aa.l = op_read();
} break;
case 2: {
aa.h = op_read();
} break;
case 3: {
aa.b = op_read();
} break;
case 4: {
if(regs.p.m)last_cycle();
op_write(OPMODE_LONG, aa.d, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
} break;
case 5: {
last_cycle();
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sta_longx() {
switch(status.cycle_pos++) {
case 1: {
aa.l = op_read();
} break;
case 2: {
aa.h = op_read();
} break;
case 3: {
aa.b = op_read();
} break;
case 4: {
if(regs.p.m)last_cycle();
op_write(OPMODE_LONG, aa.d + regs.x.w, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
} break;
case 5: {
last_cycle();
op_write(OPMODE_LONG, aa.d + regs.x.w + 1, regs.a.h);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sta_dp() {
switch(status.cycle_pos++) {
case 1: {
dp = op_read();
} break;
case 2: {
cpu_c2();
} break;
case 3: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DP, dp, regs.a.w);
if(regs.p.m)status.cycle_pos = 0;
} break;
case 4: {
last_cycle();
op_write(OPMODE_DP, dp + 1, regs.a.w >> 8);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_stx_dp() {
switch(status.cycle_pos++) {
case 1: {
dp = op_read();
} break;
case 2: {
cpu_c2();
} break;
case 3: {
if(regs.p.x)last_cycle();
op_write(OPMODE_DP, dp, regs.x.w);
if(regs.p.x)status.cycle_pos = 0;
} break;
case 4: {
last_cycle();
op_write(OPMODE_DP, dp + 1, regs.x.w >> 8);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sty_dp() {
switch(status.cycle_pos++) {
case 1: {
dp = op_read();
} break;
case 2: {
cpu_c2();
} break;
case 3: {
if(regs.p.x)last_cycle();
op_write(OPMODE_DP, dp, regs.y.w);
if(regs.p.x)status.cycle_pos = 0;
} break;
case 4: {
last_cycle();
op_write(OPMODE_DP, dp + 1, regs.y.w >> 8);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_stz_dp() {
switch(status.cycle_pos++) {
case 1: {
dp = op_read();
} break;
case 2: {
cpu_c2();
} break;
case 3: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DP, dp, 0x0000);
if(regs.p.m)status.cycle_pos = 0;
} break;
case 4: {
last_cycle();
op_write(OPMODE_DP, dp + 1, 0x0000 >> 8);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sta_dpx() {
switch(status.cycle_pos++) {
case 1: {
dp = op_read();
} break;
case 2: {
cpu_c2();
} break;
case 3: {
cpu_io();
} break;
case 4: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DP, dp + regs.x.w, regs.a.w);
if(regs.p.m)status.cycle_pos = 0;
} break;
case 5: {
last_cycle();
op_write(OPMODE_DP, dp + regs.x.w + 1, regs.a.w >> 8);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sty_dpx() {
switch(status.cycle_pos++) {
case 1: {
dp = op_read();
} break;
case 2: {
cpu_c2();
} break;
case 3: {
cpu_io();
} break;
case 4: {
if(regs.p.x)last_cycle();
op_write(OPMODE_DP, dp + regs.x.w, regs.y.w);
if(regs.p.x)status.cycle_pos = 0;
} break;
case 5: {
last_cycle();
op_write(OPMODE_DP, dp + regs.x.w + 1, regs.y.w >> 8);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_stz_dpx() {
switch(status.cycle_pos++) {
case 1: {
dp = op_read();
} break;
case 2: {
cpu_c2();
} break;
case 3: {
cpu_io();
} break;
case 4: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DP, dp + regs.x.w, 0x0000);
if(regs.p.m)status.cycle_pos = 0;
} break;
case 5: {
last_cycle();
op_write(OPMODE_DP, dp + regs.x.w + 1, 0x0000 >> 8);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_stx_dpy() {
switch(status.cycle_pos++) {
case 1: {
dp = op_read();
} break;
case 2: {
cpu_c2();
} break;
case 3: {
cpu_io();
} break;
case 4: {
if(regs.p.x)last_cycle();
op_write(OPMODE_DP, dp + regs.y.w, regs.x.l);
if(regs.p.x)status.cycle_pos = 0;
} break;
case 5: {
last_cycle();
op_write(OPMODE_DP, dp + regs.y.w + 1, regs.x.h);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sta_idp() {
switch(status.cycle_pos++) {
case 1: {
dp = op_read();
} break;
case 2: {
cpu_c2();
} break;
case 3: {
aa.l = op_read(OPMODE_DP, dp);
} break;
case 4: {
aa.h = op_read(OPMODE_DP, dp + 1);
} break;
case 5: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
} break;
case 6: {
last_cycle();
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sta_ildp() {
switch(status.cycle_pos++) {
case 1: {
dp = op_read();
} break;
case 2: {
cpu_c2();
} break;
case 3: {
aa.l = op_read(OPMODE_DP, dp);
} break;
case 4: {
aa.h = op_read(OPMODE_DP, dp + 1);
} break;
case 5: {
aa.b = op_read(OPMODE_DP, dp + 2);
} break;
case 6: {
if(regs.p.m)last_cycle();
op_write(OPMODE_LONG, aa.d, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
} break;
case 7: {
last_cycle();
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sta_idpx() {
switch(status.cycle_pos++) {
case 1: {
dp = op_read();
} break;
case 2: {
cpu_c2();
} break;
case 3: {
cpu_io();
} break;
case 4: {
aa.l = op_read(OPMODE_DP, dp + regs.x.w);
} break;
case 5: {
aa.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
} break;
case 6: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
} break;
case 7: {
last_cycle();
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sta_idpy() {
switch(status.cycle_pos++) {
case 1: {
dp = op_read();
} break;
case 2: {
cpu_c2();
} break;
case 3: {
aa.l = op_read(OPMODE_DP, dp);
} break;
case 4: {
aa.h = op_read(OPMODE_DP, dp + 1);
} break;
case 5: {
cpu_c4(aa.w, aa.w + regs.y.w);
} break;
case 6: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
} break;
case 7: {
last_cycle();
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sta_ildpy() {
switch(status.cycle_pos++) {
case 1: {
dp = op_read();
} break;
case 2: {
cpu_c2();
} break;
case 3: {
aa.l = op_read(OPMODE_DP, dp);
} break;
case 4: {
aa.h = op_read(OPMODE_DP, dp + 1);
} break;
case 5: {
aa.b = op_read(OPMODE_DP, dp + 2);
} break;
case 6: {
if(regs.p.m)last_cycle();
op_write(OPMODE_LONG, aa.d + regs.y.w, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
} break;
case 7: {
last_cycle();
op_write(OPMODE_LONG, aa.d + regs.y.w + 1, regs.a.h);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sta_sr() {
switch(status.cycle_pos++) {
case 1: {
sp = op_read();
} break;
case 2: {
cpu_io();
} break;
case 3: {
if(regs.p.m)last_cycle();
op_write(OPMODE_SP, sp, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
} break;
case 4: {
last_cycle();
op_write(OPMODE_SP, sp + 1, regs.a.h);
status.cycle_pos = 0;
} break;
}
}
void bCPU::op_sta_isry() {
switch(status.cycle_pos++) {
case 1: {
sp = op_read();
} break;
case 2: {
cpu_io();
} break;
case 3: {
aa.l = op_read(OPMODE_SP, sp);
} break;
case 4: {
aa.h = op_read(OPMODE_SP, sp + 1);
} break;
case 5: {
cpu_io();
} break;
case 6: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
} break;
case 7: {
last_cycle();
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
status.cycle_pos = 0;
} break;
}
}

View File

@@ -1,31 +1,75 @@
//op_read
inline void bCPU::op_adc_b() {
int32 r = regs.a.l + rd.l + regs.p.c;
//bcd
if(regs.p.d) {
if(((r ) & 15) > 9)r += 6;
if(((r >> 4) & 15) > 9)r += 6 << 4;
uint8 n0 = (regs.a.l ) & 15;
uint8 n1 = (regs.a.l >> 4) & 15;
n0 += ((rd.l) & 15) + regs.p.c;
if(n0 > 9) {
n0 -= 10;
n0 &= 15;
n1++;
}
n1 += ((rd.l >> 4) & 15);
if(n1 > 9) {
n1 -= 10;
n1 &= 15;
regs.p.c = 1;
} else {
regs.p.c = 0;
}
r = (n1 << 4) | (n0);
} else {
r = regs.a.l + rd.l + regs.p.c;
regs.p.c = (r > 0xff);
}
regs.p.n = !!(r & 0x80);
regs.p.v = !!(~(regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80);
regs.p.z = ((uint8)r == 0);
regs.p.c = (r > 0xff);
regs.a.l = r;
}
inline void bCPU::op_adc_w() {
int32 r = regs.a.w + rd.w + regs.p.c;
//bcd
int32 r;
if(regs.p.d) {
if(((r ) & 15) > 9)r += 6;
if(((r >> 4) & 15) > 9)r += 6 << 4;
if(((r >> 8) & 15) > 9)r += 6 << 8;
if(((r >> 12) & 15) > 9)r += 6 << 12;
uint8 n0 = (regs.a.w ) & 15;
uint8 n1 = (regs.a.w >> 4) & 15;
uint8 n2 = (regs.a.w >> 8) & 15;
uint8 n3 = (regs.a.w >> 12) & 15;
n0 += ((rd.w) & 15) + regs.p.c;
if(n0 > 9) {
n0 -= 10;
n0 &= 15;
n1++;
}
n1 += ((rd.w >> 4) & 15);
if(n1 > 9) {
n1 -= 10;
n1 &= 15;
n2++;
}
n2 += ((rd.w >> 8) & 15);
if(n2 > 9) {
n2 -= 10;
n2 &= 15;
n3++;
}
n3 += ((rd.w >> 12) & 15);
if(n3 > 9) {
n3 -= 10;
n3 &= 15;
regs.p.c = 1;
} else {
regs.p.c = 0;
}
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | (n0);
} else {
r = regs.a.w + rd.w + regs.p.c;
regs.p.c = (r > 0xffff);
}
regs.p.n = !!(r & 0x8000);
regs.p.v = !!(~(regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000);
regs.p.z = ((uint16)r == 0);
regs.p.c = (r > 0xffff);
regs.a.w = r;
}
@@ -156,32 +200,70 @@ inline void bCPU::op_ora_w() {
}
inline void bCPU::op_sbc_b() {
int32 r = regs.a.l - rd.l - !regs.p.c;
//bcd
int32 r;
if(regs.p.d) {
if(((r ) & 15) > 9)r -= 6;
if(((r >> 4) & 15) > 9)r -= 6 << 4;
uint8 n0 = (regs.a.l ) & 15;
uint8 n1 = (regs.a.l >> 4) & 15;
n0 -= ((rd.l ) & 15) + !regs.p.c;
n1 -= ((rd.l >> 4) & 15);
if(n0 > 9) {
n0 += 10;
n1--;
}
if(n1 > 9) {
n1 += 10;
regs.p.c = 0;
} else {
regs.p.c = 1;
}
r = (n1 << 4) | (n0);
} else {
r = regs.a.l - rd.l - !regs.p.c;
regs.p.c = (r >= 0);
}
regs.p.n = !!(r & 0x80);
regs.p.v = !!((regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80);
regs.p.z = ((byte)r == 0);
regs.p.c = (r >= 0);
regs.p.z = ((uint8)r == 0);
regs.a.l = r;
}
inline void bCPU::op_sbc_w() {
int32 r = regs.a.w - rd.w - !regs.p.c;
//bcd
int32 r;
if(regs.p.d) {
if(((r ) & 15) > 9)r -= 6;
if(((r >> 4) & 15) > 9)r -= 6 << 4;
if(((r >> 8) & 15) > 9)r -= 6 << 8;
if(((r >> 12) & 15) > 9)r -= 6 << 12;
uint8 n0 = (regs.a.w ) & 15;
uint8 n1 = (regs.a.w >> 4) & 15;
uint8 n2 = (regs.a.w >> 8) & 15;
uint8 n3 = (regs.a.w >> 12) & 15;
n0 -= ((rd.w ) & 15) + !regs.p.c;
n1 -= ((rd.w >> 4) & 15);
n2 -= ((rd.w >> 8) & 15);
n3 -= ((rd.w >> 12) & 15);
if(n0 > 9) {
n0 += 10;
n1--;
}
if(n1 > 9) {
n1 += 10;
n2--;
}
if(n2 > 9) {
n2 += 10;
n3--;
}
if(n3 > 9) {
n3 += 10;
regs.p.c = 0;
} else {
regs.p.c = 1;
}
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | (n0);
} else {
r = regs.a.w - rd.w - !regs.p.c;
regs.p.c = (r >= 0);
}
regs.p.n = !!(r & 0x8000);
regs.p.v = !!((regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000);
regs.p.z = ((word)r == 0);
regs.p.c = (r >= 0);
regs.p.z = ((uint16)r == 0);
regs.a.w = r;
}

View File

@@ -186,7 +186,6 @@ optbl[0x91] = &bCPU::op_sta_idpy;
optbl[0x97] = &bCPU::op_sta_ildpy;
optbl[0x83] = &bCPU::op_sta_sr;
optbl[0x93] = &bCPU::op_sta_isry;
optbl[0x80] = &bCPU::op_bra;
optbl[0x90] = &bCPU::op_bcc;
optbl[0xb0] = &bCPU::op_bcs;
optbl[0xd0] = &bCPU::op_bne;
@@ -195,6 +194,7 @@ optbl[0x10] = &bCPU::op_bpl;
optbl[0x30] = &bCPU::op_bmi;
optbl[0x50] = &bCPU::op_bvc;
optbl[0x70] = &bCPU::op_bvs;
optbl[0x80] = &bCPU::op_bra;
optbl[0x82] = &bCPU::op_brl;
optbl[0x4c] = &bCPU::op_jmp_addr;
optbl[0x5c] = &bCPU::op_jmp_long;

265
src/cpu/bcpu/dma/dma.cpp Normal file
View File

@@ -0,0 +1,265 @@
/* used by both DMA and HDMA
* prevents transfer across same bus (a->a or b->b)
*/
void bCPU::dma_transfer_byte(bool direction, uint8 bbus, uint32 abus) {
uint8 r;
if(direction == 0) {
//read from address bus a, write to address bus b
//DMA address bus a cannot read from or write to the following addresses:
//$[00-3f|80-bf]:21[00-ff] <address bus b>
//$[00-3f|80-bf]:43[00-7f] <DMA control registers>
//$[00-3f|80-bf]:420b <DMA enable register>
//$[00-3f|80-bf]:420c <HDMA enable register>
if((abus & 0x40ff00) == 0x2100 || (abus & 0x40ff80) == 0x4300 ||
(abus & 0x40ffff) == 0x420b || (abus & 0x40ffff) == 0x420c) {
//these invalid reads will return open bus
r = r_cpu->regs.mdr;
} else {
r = r_mem->read(abus);
}
r_mem->write(0x2100 | bbus, r);
} else {
//read from address bus b, write to address bus a
//block invalid writes, see comments above
r = (bbus == 0x80) ? r_cpu->regs.mdr : r_mem->read(0x2100 | bbus);
if((abus & 0x40ff00) == 0x2100 || (abus & 0x40ff80) == 0x4300 ||
(abus & 0x40ffff) == 0x420b || (abus & 0x40ffff) == 0x420c)return;
r_mem->write(abus, r);
}
}
void bCPU::dma_add_cycles(uint32 cycles) {
status.dma_cycle_count += cycles;
}
void bCPU::hdma_add_cycles(uint32 cycles) {
if(run_state.dma) {
status.dma_cycle_count += cycles;
}
status.hdma_cycle_count += cycles;
}
uint32 bCPU::dma_addr(uint8 i) {
uint32 r;
r = (channel[i].srcbank << 16) | (channel[i].srcaddr);
if(channel[i].fixedxfer == false) {
channel[i].srcaddr += channel[i].incmode;
}
return r;
}
void bCPU::dma_cputommio(uint8 i, uint8 index) {
if(sdd1->dma_active() == true) {
r_mem->write(0x2100 | ((channel[i].destaddr + index) & 0xff), sdd1->dma_read());
} else {
dma_transfer_byte(0, ((channel[i].destaddr + index) & 0xff), dma_addr(i));
}
add_cycles(8);
channel[i].xfersize--;
}
void bCPU::dma_mmiotocpu(uint8 i, uint8 index) {
dma_transfer_byte(1, ((channel[i].destaddr + index) & 0xff), dma_addr(i));
add_cycles(8);
channel[i].xfersize--;
}
void bCPU::dma_write(uint8 i, uint8 index) {
if(channel[i].direction == 0) {
dma_cputommio(i, index);
} else {
dma_mmiotocpu(i, index);
}
}
void bCPU::dma_run() {
for(int i = 0; i < 8; i++) {
if(channel[i].active == false)continue;
//first byte transferred?
if(channel[i].read_index == 0) {
sdd1->dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr),
channel[i].xfersize);
}
switch(channel[i].xfermode) {
case 0: dma_write(i, 0); break; //0
case 1: dma_write(i, channel[i].read_index & 1); break; //0,1
case 2: dma_write(i, 0); break; //0,0
case 3: dma_write(i, (channel[i].read_index >> 1) & 1); break; //0,0,1,1
case 4: dma_write(i, channel[i].read_index & 3); break; //0,1,2,3
case 5: dma_write(i, channel[i].read_index & 1); break; //0,1,0,1
case 6: dma_write(i, 0); break; //0,0 [2]
case 7: dma_write(i, (channel[i].read_index >> 1) & 1); break; //0,0,1,1 [3]
}
channel[i].read_index++;
dma_add_cycles(8);
if(channel[i].xfersize == 0) {
channel[i].active = false;
}
return;
}
status.dma_state = DMASTATE_CPUSYNC;
}
uint32 bCPU::hdma_addr(uint8 i) {
return (channel[i].srcbank << 16) | (channel[i].hdma_addr++);
}
uint32 bCPU::hdma_iaddr(uint8 i) {
return (channel[i].hdma_ibank << 16) | (channel[i].hdma_iaddr++);
}
uint16 bCPU::hdma_mmio(uint8 i) {
uint8 l = channel[i].read_index;
uint16 index;
switch(channel[i].xfermode) {
case 0: index = 0; break; //0
case 1: index = l & 1; break; //0,1
case 2: index = 0; break; //0,0
case 3: index = (l >> 1) & 1; break; //0,0,1,1
case 4: index = l & 3; break; //0,1,2,3
case 5: index = l & 1; break; //0,1,0,1
case 6: index = 0; break; //0,0 [2]
case 7: index = (l >> 1) & 1; break; //0,0,1,1 [3]
}
return (0x2100 | ((channel[i].destaddr + index) & 0xff));
}
void bCPU::hdma_update(uint8 i) {
channel[i].hdma_line_counter = r_mem->read(hdma_addr(i));
add_cycles(8);
hdma_add_cycles(8);
if(channel[i].hdma_indirect) {
channel[i].hdma_iaddr = r_mem->read(hdma_addr(i)) << 8;
add_cycles(8);
hdma_add_cycles(8);
}
if(channel[i].hdma_line_counter == 0) {
channel[i].hdma_active = false;
channel[i].hdma_do_transfer = false;
return;
}
channel[i].hdma_do_transfer = true;
if(channel[i].hdma_indirect) {
channel[i].hdma_iaddr >>= 8;
channel[i].hdma_iaddr |= r_mem->read(hdma_addr(i)) << 8;
add_cycles(8);
hdma_add_cycles(8);
}
}
void bCPU::hdma_run() {
static uint8 hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
for(int i = 0; i < 8; i++) {
if(!channel[i].hdma_enabled || !channel[i].hdma_active)continue;
if(channel[i].hdma_do_transfer) {
int xferlen = hdma_xferlen[channel[i].xfermode];
for(channel[i].read_index = 0; channel[i].read_index < xferlen; channel[i].read_index++) {
if(bool(config::cpu.hdma_enable) == true) {
dma_transfer_byte(channel[i].direction, hdma_mmio(i),
channel[i].hdma_indirect ? hdma_iaddr(i) : hdma_addr(i));
}
add_cycles(8);
hdma_add_cycles(8);
}
}
channel[i].hdma_line_counter--;
channel[i].hdma_do_transfer = bool(channel[i].hdma_line_counter & 0x80);
if((channel[i].hdma_line_counter & 0x7f) == 0) {
hdma_update(i);
}
}
}
uint8 bCPU::hdma_enabled_channels() {
int r = 0;
for(int i = 0; i < 8; i++) {
if(channel[i].hdma_enabled)r++;
}
return r;
}
uint8 bCPU::hdma_active_channels() {
int r = 0;
for(int i = 0; i < 8; i++) {
if(channel[i].hdma_enabled && channel[i].hdma_active)r++;
}
return r;
}
/* hdmainit_activate()
* hdma_activate()
*
* Functions are called by CPU timing routine
* when an HDMA event (init or run) occurs.
*/
void bCPU::hdmainit_activate() {
for(int i = 0; i < 8; i++) {
channel[i].hdma_active = false;
channel[i].hdma_do_transfer = false;
}
if(hdma_enabled_channels() != 0) {
status.hdma_state = HDMASTATE_IDMASYNC;
run_state.hdma = true;
}
}
void bCPU::hdma_activate() {
if(hdma_active_channels() != 0) {
status.hdma_state = HDMASTATE_DMASYNC;
run_state.hdma = true;
}
}
void bCPU::dma_reset() {
status.dma_state = DMASTATE_CPUSYNC;
status.hdma_state = HDMASTATE_CPUSYNC;
status.dma_cycle_count = 0;
status.hdma_cycle_count = 0;
for(int i = 0; i < 8; i++) {
channel[i].read_index = 0;
channel[i].active = false;
channel[i].hdma_enabled = false;
channel[i].dmap = 0xff;
channel[i].direction = 1;
channel[i].hdma_indirect = 1;
channel[i].incmode = -1;
channel[i].fixedxfer = 1;
channel[i].xfermode = 7;
channel[i].destaddr = 0xff;
channel[i].srcaddr = 0xffff;
channel[i].srcbank = 0xff;
channel[i].xfersize = 0xffff;
//xfersize and hdma_iaddr are of union { uint16 };
//channel[i].hdma_iaddr = 0xffff;
channel[i].hdma_ibank = 0xff;
channel[i].hdma_addr = 0xffff;
channel[i].hdma_line_counter = 0xff;
channel[i].hdma_unknown = 0xff;
channel[i].hdma_active = false;
channel[i].hdma_do_transfer = false;
}
}

60
src/cpu/bcpu/dma/dma.h Normal file
View File

@@ -0,0 +1,60 @@
struct {
uint32 read_index; //set to 0 at beginning of DMA/HDMA
//$420b
bool active;
//$420c
bool hdma_enabled;
//$43x0
uint8 dmap;
bool direction;
bool hdma_indirect;
int8 incmode;
bool fixedxfer;
uint8 xfermode;
//$43x1
uint8 destaddr;
//$43x2-$43x3
uint16 srcaddr;
//$43x4
uint8 srcbank;
//$43x5-$43x6
union {
uint16 xfersize;
uint16 hdma_iaddr;
};
//$43x7
uint8 hdma_ibank;
//$43x8-$43x9
uint16 hdma_addr;
//$43xa
uint8 hdma_line_counter;
//$43xb/$43xf
uint8 hdma_unknown;
//hdma-specific
bool hdma_active;
bool hdma_do_transfer;
uint8 hdma_current_channel;
uint8 hdma_current_pos;
} channel[8];
inline void dma_transfer_byte(bool direction, uint8 bbus, uint32 abus);
inline void dma_add_cycles(uint32 cycles);
inline void hdma_add_cycles(uint32 cycles);
inline void dma_run();
inline void hdma_run();
inline void hdma_update(uint8 i);
inline uint8 hdma_enabled_channels();
inline uint8 hdma_active_channels();
inline void hdmainit_activate();
inline void hdma_activate();
inline void dma_cputommio(uint8 i, uint8 index);
inline void dma_mmiotocpu(uint8 i, uint8 index);
inline void dma_write(uint8 i, uint8 index);
inline uint32 dma_addr(uint8 i);
inline uint32 hdma_addr(uint8 i);
inline uint32 hdma_iaddr(uint8 i);
inline uint16 hdma_mmio(uint8 i);
inline void dma_reset();

View File

@@ -0,0 +1,40 @@
uint8 bCPU::port_read(uint8 port) {
return apu_port[port & 3];
}
void bCPU::port_write(uint8 port, uint8 value) {
apu_port[port & 3] = value;
}
/* The next 3 functions control bus timing for the CPU.
* cpu_io is an I/O cycle, and always 6 clock cycles long.
* mem_read / mem_write indicate memory access bus cycle,
* they are either 6, 8, or 12 bus cycles long, depending
* both on location and the $420d.d0 FastROM enable bit.
*/
void bCPU::cpu_io() {
status.cycle_count = 6;
pre_exec_cycle();
add_cycles(6);
cycle_edge();
}
uint8 bCPU::mem_read(uint32 addr) {
status.cycle_count = r_mem->speed(addr);
pre_exec_cycle();
add_cycles(status.cycle_count - 4);
regs.mdr = r_mem->read(addr);
add_cycles(4);
cycle_edge();
return regs.mdr;
}
void bCPU::mem_write(uint32 addr, uint8 value) {
status.cycle_count = r_mem->speed(addr);
pre_exec_cycle();
add_cycles(status.cycle_count);
regs.mdr = value;
r_mem->write(addr, value);
cycle_edge();
}

Some files were not shown because too many files have changed in this diff Show More