mirror of https://github.com/bsnes-emu/bsnes.git
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).
This commit is contained in:
parent
7e2cfb6d40
commit
397b9c4505
106
bsnes.cfg
106
bsnes.cfg
|
@ -1,57 +1,87 @@
|
|||
#[bsnes v0.009 configuration file]
|
||||
# Applies contrast adjust filter to video output when enabled
|
||||
# Works by lowering the brightness of darker colors,
|
||||
# while leaving brighter colors alone; thus reducing saturation
|
||||
# (default = true)
|
||||
snes.video_color_curve = true
|
||||
|
||||
#[apu enable]
|
||||
apu.enabled = true
|
||||
# Selects color adjustment filter for video output
|
||||
# 0 = Normal (no filter, rgb555)
|
||||
# 1 = Grayscale mode (l5)
|
||||
# 2 = VGA mode (rgb332)
|
||||
# 3 = Genesis mode (rgb333)
|
||||
# (default = 0)
|
||||
snes.video_color_adjust_mode = 0
|
||||
|
||||
#[video mode]
|
||||
# 0: 256x224w
|
||||
# 1: 512x448w
|
||||
# 2: 960x720w
|
||||
# 3: 640x480f
|
||||
# 4: 1024x768f
|
||||
# Mutes SNES audio output when enabled
|
||||
# (default = true)
|
||||
snes.mute = true
|
||||
|
||||
# Video mode
|
||||
# 0 = 256x224w
|
||||
# 1 = 512x448w
|
||||
# 2 = 960x720w
|
||||
# 3 = 640x480f
|
||||
# 4 = 1024x768f
|
||||
# (default = 1)
|
||||
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.
|
||||
# Use Video RAM instead of System RAM
|
||||
# (default = true)
|
||||
video.use_vram = true
|
||||
|
||||
#[color curve]
|
||||
# gives a more NTSC TV-style feel to the color palette
|
||||
# by darkening the image contrast.
|
||||
video.color_curve = enabled
|
||||
|
||||
#[show fps]
|
||||
# true: show fps in titlebar
|
||||
# false: do not show fps in titlebar
|
||||
gui.show_fps = true
|
||||
|
||||
#[wait for vertical retrace]
|
||||
# Wait for vertical retrace when updating screen
|
||||
# (default = false)
|
||||
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.
|
||||
# Show framerate in window title
|
||||
# (default = true)
|
||||
gui.show_fps = false
|
||||
|
||||
# Joypad1 up
|
||||
# (default = 0x26)
|
||||
input.joypad1.up = 0x26
|
||||
|
||||
# Joypad1 down
|
||||
# (default = 0x28)
|
||||
input.joypad1.down = 0x28
|
||||
|
||||
# Joypad1 left
|
||||
# (default = 0x25)
|
||||
input.joypad1.left = 0x25
|
||||
|
||||
# Joypad1 right
|
||||
# (default = 0x27)
|
||||
input.joypad1.right = 0x27
|
||||
|
||||
# Joypad1 A
|
||||
# (default = 0x58)
|
||||
input.joypad1.a = 0x58
|
||||
|
||||
# Joypad1 B
|
||||
# (default = 0x5a)
|
||||
input.joypad1.b = 0x5a
|
||||
|
||||
# Joypad1 X
|
||||
# (default = 0x53)
|
||||
input.joypad1.x = 0x53
|
||||
|
||||
# Joypad1 Y
|
||||
# (default = 0x41)
|
||||
input.joypad1.y = 0x41
|
||||
|
||||
# Joypad1 L
|
||||
# (default = 0x44)
|
||||
input.joypad1.l = 0x44
|
||||
|
||||
# Joypad1 R
|
||||
# (default = 0x43)
|
||||
input.joypad1.r = 0x43
|
||||
|
||||
# Joypad1 select
|
||||
# (default = 0x10)
|
||||
input.joypad1.select = 0x10
|
||||
input.joypad1.start = 0x0d
|
||||
|
||||
# Joypad1 start
|
||||
# (default = 0xd)
|
||||
input.joypad1.start = 0xd
|
||||
|
||||
|
|
|
@ -17,5 +17,5 @@ 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
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
#include "../base.h"
|
||||
#include "iplrom.h"
|
||||
#include "dapu.cpp"
|
||||
|
|
|
@ -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,6 +17,7 @@ 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;
|
||||
|
|
|
@ -24,7 +24,7 @@ uint8 r;
|
|||
break;
|
||||
case 0xf3: //DSPDATA
|
||||
//0x80-0xff is a read-only mirror of 0x00-0x7f
|
||||
r = dsp_regs[status.dsp_addr & 0x7f];
|
||||
r = dsp->read(status.dsp_addr & 0x7f);
|
||||
break;
|
||||
case 0xf4: //CPUIO0
|
||||
case 0xf5: //CPUIO1
|
||||
|
@ -111,7 +111,7 @@ void bAPU::spcram_write(uint16 addr, uint8 value) {
|
|||
case 0xf3: //DSPDATA
|
||||
//0x80-0xff is a read-only mirror of 0x00-0x7f
|
||||
if(status.dsp_addr < 0x80) {
|
||||
dsp_regs[status.dsp_addr & 0x7f] = value;
|
||||
dsp->write(status.dsp_addr & 0x7f, value);
|
||||
}
|
||||
break;
|
||||
case 0xf4: //CPUIO0
|
||||
|
@ -209,6 +209,14 @@ void bAPU::stack_write(uint8 value) {
|
|||
regs.sp--;
|
||||
}
|
||||
|
||||
uint8 *bAPU::get_spcram_handle() {
|
||||
if(!spcram) {
|
||||
alert("bAPU::get_spcram_handle() -- spcram uninitialized");
|
||||
}
|
||||
|
||||
return spcram;
|
||||
}
|
||||
|
||||
void bAPU::run() {
|
||||
exec_cycle();
|
||||
}
|
||||
|
@ -247,15 +255,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
|
||||
|
|
|
@ -29,12 +29,13 @@ struct {
|
|||
|
||||
bAPUTimer t0, t1, t2;
|
||||
|
||||
uint8 *spcram, iplrom[64], dsp_regs[128];
|
||||
uint8 *spcram;
|
||||
inline uint8 spcram_read (uint16 addr);
|
||||
inline void spcram_write(uint16 addr, uint8 value);
|
||||
inline uint8 port_read (uint8 port);
|
||||
inline void port_write(uint8 port, uint8 value);
|
||||
|
||||
inline uint8 *get_spcram_handle();
|
||||
inline void run();
|
||||
inline uint32 cycles_executed();
|
||||
inline void power();
|
||||
|
|
Binary file not shown.
|
@ -1,4 +1,7 @@
|
|||
class bAPUSkip : public APU {
|
||||
private:
|
||||
uint8 spcram[65536];
|
||||
|
||||
public:
|
||||
|
||||
struct _apu_port {
|
||||
|
@ -26,6 +29,7 @@ enum {
|
|||
uint8 port_read (uint8 port);
|
||||
void port_write (uint8 port, uint8 value);
|
||||
|
||||
uint8 *get_spcram_handle() { return spcram; }
|
||||
void run();
|
||||
uint32 cycles_executed() { return 12 * 24; }
|
||||
void power();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#include <time.h>
|
||||
#include "lib/libbase.h"
|
||||
#include "lib/libvector.h"
|
||||
#include "lib/libstring.h"
|
||||
#include "lib/libconfig.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define _WIN32_
|
||||
|
@ -11,12 +14,6 @@
|
|||
#error "unknown architecture"
|
||||
#endif
|
||||
|
||||
//structs
|
||||
typedef struct {
|
||||
uint8 *data;
|
||||
uint32 size;
|
||||
}lfile;
|
||||
|
||||
//platform-specific global functions
|
||||
void *memalloc(uint32 size, char *name = 0, ...);
|
||||
void memfree(void *mem, char *name = 0, ...);
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
#include "../../base.h"
|
||||
#include "sdd1emu.cpp"
|
||||
|
||||
void SDD1::init() {
|
||||
}
|
||||
|
||||
void SDD1::enable() {
|
||||
for(int i=0x4800;i<=0x4807;i++) {
|
||||
mem_bus->set_mmio_mapper(i, mmio);
|
||||
}
|
||||
}
|
||||
|
||||
void SDD1::power() {
|
||||
reset();
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ struct {
|
|||
bool dma_active;
|
||||
}sdd1;
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
uint32 offset(uint32 addr);
|
||||
|
|
|
@ -74,6 +74,14 @@ tm *t;
|
|||
srtc.data[12] = t->tm_wday;
|
||||
}
|
||||
|
||||
void SRTC::init() {
|
||||
}
|
||||
|
||||
void SRTC::enable() {
|
||||
mem_bus->set_mmio_mapper(0x2800, mmio);
|
||||
mem_bus->set_mmio_mapper(0x2801, mmio);
|
||||
}
|
||||
|
||||
void SRTC::power() {
|
||||
memset(&srtc, 0, sizeof(srtc));
|
||||
reset();
|
||||
|
|
|
@ -41,11 +41,13 @@ Index Description Range
|
|||
12 Day of week 0-6 (0=Sunday, ...)
|
||||
******************************/
|
||||
struct {
|
||||
int8 index;
|
||||
uint8 mode;
|
||||
uint8 data[MAX_SRTC_INDEX + 1];
|
||||
}srtc;
|
||||
int8 index;
|
||||
uint8 mode;
|
||||
uint8 data[MAX_SRTC_INDEX + 1];
|
||||
} srtc;
|
||||
void set_time();
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
void write(uint8 data);
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
Config config_file;
|
||||
|
||||
namespace config {
|
||||
|
||||
SNES::VideoColorAdjust SNES::video_color_curve(&config_file, "snes.video_color_curve",
|
||||
"Applies contrast adjust filter to video output when enabled\n"
|
||||
"Works by lowering the brightness of darker colors,\n"
|
||||
"while leaving brighter colors alone; thus reducing saturation",
|
||||
true, Setting::TRUE_FALSE);
|
||||
|
||||
SNES::VideoColorAdjust SNES::video_color_adjust_mode(&config_file, "snes.video_color_adjust_mode",
|
||||
"Selects color adjustment filter for video output\n"
|
||||
" 0 = Normal (no filter, rgb555)\n"
|
||||
" 1 = Grayscale mode (l5)\n"
|
||||
" 2 = VGA mode (rgb332)\n"
|
||||
" 3 = Genesis mode (rgb333)",
|
||||
0, Setting::DEC);
|
||||
|
||||
void SNES::VideoColorAdjust::set(uint32 _data) {
|
||||
data = _data;
|
||||
::snes->update_color_lookup_table();
|
||||
}
|
||||
|
||||
Setting SNES::mute(&config_file, "snes.mute",
|
||||
"Mutes SNES audio output when enabled",
|
||||
true, Setting::TRUE_FALSE);
|
||||
|
||||
};
|
|
@ -0,0 +1,15 @@
|
|||
extern Config config_file;
|
||||
|
||||
namespace config {
|
||||
|
||||
extern struct SNES {
|
||||
static class VideoColorAdjust : public Setting {
|
||||
public:
|
||||
void set(uint32 _data);
|
||||
SettingOperators(VideoColorAdjust);
|
||||
} video_color_curve, video_color_adjust_mode;
|
||||
|
||||
static Setting mute;
|
||||
} snes;
|
||||
|
||||
};
|
|
@ -13,152 +13,26 @@
|
|||
|
||||
#include "bcpu_timing.cpp"
|
||||
|
||||
uint8 bCPU::pio_status() {
|
||||
return status.pio;
|
||||
}
|
||||
#include "bcpu_int.cpp"
|
||||
|
||||
/***********
|
||||
*** IRQ ***
|
||||
***********
|
||||
cycles:
|
||||
[1] pbr,pc ; io/opcode
|
||||
[2] pbr,pc ; io
|
||||
[3] 0,s ; pbr
|
||||
[4] 0,s-1 ; pch
|
||||
[5] 0,s-2 ; pcl
|
||||
[6] 0,s-3 ; p
|
||||
[7] 0,va ; aavl
|
||||
[8] 0,va+1 ; aavh
|
||||
*/
|
||||
void bCPU::irq(uint16 addr) {
|
||||
if(status.cpu_state == CPUSTATE_WAI) {
|
||||
status.cpu_state = CPUSTATE_RUN;
|
||||
regs.pc.w++;
|
||||
}
|
||||
|
||||
//GTE documentation is incorrect, first cycle
|
||||
//is a memory read fetch from PBR:PC
|
||||
add_cycles(mem_bus->speed(regs.pc.d));
|
||||
add_cycles(6);
|
||||
stack_write(regs.pc.b);
|
||||
stack_write(regs.pc.h);
|
||||
stack_write(regs.pc.l);
|
||||
stack_write(regs.p);
|
||||
rd.l = op_read(OPMODE_ADDR, addr);
|
||||
rd.h = op_read(OPMODE_ADDR, addr + 1);
|
||||
|
||||
regs.pc.b = 0x00;
|
||||
regs.pc.w = rd.w;
|
||||
regs.p.i = 1;
|
||||
regs.p.d = 0;
|
||||
|
||||
//let debugger know the new IRQ opcode address
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_END);
|
||||
}
|
||||
|
||||
//vcounter range verified on real hardware,
|
||||
//HDMA runs on the very first scanline of vblank
|
||||
bool bCPU::hdma_test() {
|
||||
if(status.hdma_triggered == false) {
|
||||
if(vcounter() <= (overscan()?239:224) && hcounter() >= 278) {
|
||||
status.hdma_triggered = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//NMI range: V==225/240,H>=12 ; V>225/240
|
||||
bool bCPU::nmi_test() {
|
||||
if(status.nmi_exec == true)return false;
|
||||
|
||||
//[status.cycle_count index]
|
||||
// 6->12
|
||||
// 8->14
|
||||
int hc = status.cycle_count + 6;
|
||||
if(vcounter() == ((overscan()?239:224) + 1) && hcycles() < hc) {
|
||||
//dprintf("* miss at %3d,%4d,%3x : %d x=%0.4x", vcounter(), hcycles(), hcounter(), status.cycle_count, regs.x.w);
|
||||
}
|
||||
|
||||
if(
|
||||
(vcounter() == ((overscan()?239:224) + 1) && hcycles() >= hc) ||
|
||||
(vcounter() > ((overscan()?239:224) + 1))
|
||||
) {
|
||||
//dprintf("* %3d,%4d,%3x : %d x=%0.4x", vcounter(), hcycles(), hcounter(), status.cycle_count, regs.x.w);
|
||||
status.nmi_exec = true;
|
||||
return status.nmi_enabled;
|
||||
}
|
||||
|
||||
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_read == true)return false; //same as above
|
||||
if(status.virq_enabled == false && status.hirq_enabled == false)return false;
|
||||
|
||||
//if irq_exec is true, then an IRQ occurred already.
|
||||
//IRQs will continue to fire until $4211 is read from, or
|
||||
//$4200 is written to, where irq_exec is set back to false.
|
||||
if(status.irq_exec == true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//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
|
||||
//region_scanlines() = 262/NTSC, 312/PAL
|
||||
//PAL results are unverified on hardware
|
||||
if(vpos == 240 && hpos == 339 && interlace() == false && interlace_field() == 1)return false;
|
||||
if(vpos == (region_scanlines() - 1) && hpos == 339 && interlace() == false)return false;
|
||||
if(vpos == region_scanlines() && interlace() == false)return false;
|
||||
if(vpos == region_scanlines() && hpos == 339)return false;
|
||||
if(vpos > region_scanlines())return false;
|
||||
if(hpos > 339)return false;
|
||||
|
||||
if(hpos == 0) {
|
||||
hpos = status.cycle_count + 14;
|
||||
} else {
|
||||
hpos <<= 2;
|
||||
hpos += status.cycle_count + 18;
|
||||
//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_exec = true;
|
||||
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:
|
||||
case CPUSTATE_RUN:
|
||||
if(status.cycle_pos == 0) {
|
||||
//interrupts only trigger on opcode edges
|
||||
if(nmi_test() == true) {
|
||||
if(time.nmi_pending == true) {
|
||||
time.nmi_pending = false;
|
||||
irq(0xffea);
|
||||
break;
|
||||
}
|
||||
if(irq_test() == true) {
|
||||
if(time.irq_pending == true) {
|
||||
time.irq_pending = false;
|
||||
irq(0xffee);
|
||||
break;
|
||||
}
|
||||
|
@ -184,19 +58,14 @@ void bCPU::scanline() {
|
|||
//connected status bit.
|
||||
status.joypad1_read_pos = 16;
|
||||
}
|
||||
|
||||
if(status.virq_enabled == false) {
|
||||
status.irq_read = false;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::frame() {
|
||||
hdma_initialize();
|
||||
|
||||
status.nmi_read = false;
|
||||
status.nmi_exec = false;
|
||||
|
||||
status.irq_read = false;
|
||||
time.nmi_read = 1;
|
||||
time.nmi_line = 1;
|
||||
time.nmi_transition = 0;
|
||||
}
|
||||
|
||||
void bCPU::power() {
|
||||
|
@ -234,12 +103,6 @@ void bCPU::reset() {
|
|||
|
||||
status.hdma_triggered = false;
|
||||
|
||||
status.nmi_read = false;
|
||||
status.nmi_exec = false;
|
||||
|
||||
status.irq_read = false;
|
||||
status.irq_exec = false;
|
||||
|
||||
apu_port[0] = 0x00;
|
||||
apu_port[1] = 0x00;
|
||||
apu_port[2] = 0x00;
|
||||
|
@ -258,43 +121,52 @@ void bCPU::port_write(uint8 port, uint8 value) {
|
|||
|
||||
void bCPU::cpu_c2() {
|
||||
if(regs.d.l != 0x00) {
|
||||
status.cycle_count = 6;
|
||||
add_cycles(6);
|
||||
cpu_io();
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::cpu_c4(uint16 x, uint16 y) {
|
||||
if(!regs.p.x && (x & 0xff00) != (y & 0xff00)) {
|
||||
status.cycle_count = 6;
|
||||
add_cycles(6);
|
||||
cpu_io();
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::cpu_c6(uint16 addr) {
|
||||
if(regs.e && (regs.pc.w & 0xff00) != (addr & 0xff00)) {
|
||||
status.cycle_count = 6;
|
||||
add_cycles(6);
|
||||
cpu_io();
|
||||
}
|
||||
}
|
||||
|
||||
/* The next 3 functions control bus timing for the CPU.
|
||||
* cpu_io is an I/O cycle, and always 6 clock cycles long.
|
||||
* mem_read / mem_write indicate memory access bus cycle,
|
||||
* they are either 6, 8, or 12 bus cycles long, depending
|
||||
* both on location and the $420d.1 FastROM enable bit.
|
||||
*/
|
||||
|
||||
void bCPU::cpu_io() {
|
||||
if(status.is_last_cycle)last_cycle_exec();
|
||||
|
||||
status.cycle_count = 6;
|
||||
add_cycles(6);
|
||||
}
|
||||
|
||||
uint8 bCPU::mem_read(uint32 addr) {
|
||||
if(status.is_last_cycle)last_cycle_exec();
|
||||
|
||||
status.cycle_count = mem_bus->speed(addr);
|
||||
add_cycles(2);
|
||||
add_cycles(status.cycle_count - 4);
|
||||
regs.mdr = mem_bus->read(addr);
|
||||
add_cycles(status.cycle_count - 2);
|
||||
add_cycles(4);
|
||||
return regs.mdr;
|
||||
}
|
||||
|
||||
void bCPU::mem_write(uint32 addr, uint8 value) {
|
||||
if(status.is_last_cycle)last_cycle_exec();
|
||||
|
||||
status.cycle_count = mem_bus->speed(addr);
|
||||
add_cycles(6);
|
||||
add_cycles(status.cycle_count);
|
||||
mem_bus->write(addr, value);
|
||||
add_cycles(status.cycle_count - 6);
|
||||
}
|
||||
|
||||
uint32 bCPU::op_addr(uint8 mode, uint32 addr) {
|
||||
|
@ -306,12 +178,11 @@ uint32 bCPU::op_addr(uint8 mode, uint32 addr) {
|
|||
addr &= 0xffffff;
|
||||
break;
|
||||
case OPMODE_DBR:
|
||||
addr &= 0xffffff;
|
||||
addr = (regs.db << 16) + addr;
|
||||
addr = ((regs.db << 16) + addr) & 0xffffff;
|
||||
break;
|
||||
case OPMODE_PBR:
|
||||
addr &= 0xffff;
|
||||
addr = (regs.pc.b << 16) | addr;
|
||||
addr = (regs.pc.b << 16) + addr;
|
||||
break;
|
||||
case OPMODE_DP:
|
||||
addr &= 0xffff;
|
||||
|
|
|
@ -10,8 +10,7 @@ bCPU *cpu;
|
|||
|
||||
class bCPU : public CPU {
|
||||
private:
|
||||
typedef void (bCPU::*op)();
|
||||
op optbl[256];
|
||||
void (bCPU::*optbl[256])();
|
||||
|
||||
enum { NTSC = 0, PAL = 1 };
|
||||
uint8 region;
|
||||
|
@ -53,20 +52,13 @@ struct {
|
|||
uint8 opcode;
|
||||
uint32 cycles_executed;
|
||||
|
||||
//set by last_cycle(), cleared by last_cycle_exec()
|
||||
bool is_last_cycle;
|
||||
|
||||
uint8 dma_state;
|
||||
uint32 dma_cycle_count;
|
||||
bool hdma_triggered;
|
||||
|
||||
//used by $4210 read bit 7
|
||||
bool nmi_read;
|
||||
//used by NMI test, set when NMI executed this frame
|
||||
bool nmi_exec;
|
||||
|
||||
//IRQ is level-sensitive, so $4211 must be read to
|
||||
//prevent multiple interrupts from occurring
|
||||
bool irq_read;
|
||||
//this is used to return $4211 bit 7
|
||||
bool irq_exec;
|
||||
//$4207-$420a
|
||||
uint16 virq_trigger, hirq_trigger;
|
||||
|
||||
|
@ -98,7 +90,7 @@ struct {
|
|||
//$4214-$4216
|
||||
uint16 r4214;
|
||||
uint16 r4216;
|
||||
}status;
|
||||
} status;
|
||||
|
||||
struct {
|
||||
uint32 read_index; //set to 0 at beginning of DMA/HDMA
|
||||
|
@ -136,12 +128,13 @@ struct {
|
|||
bool hdma_repeat;
|
||||
uint16 hdma_iaddr;
|
||||
bool hdma_active;
|
||||
}channel[8];
|
||||
} channel[8];
|
||||
|
||||
inline bool hdma_test();
|
||||
|
||||
inline void irq(uint16 addr);
|
||||
inline bool nmi_test();
|
||||
inline bool irq_test();
|
||||
inline void irq(uint16 addr);
|
||||
|
||||
inline uint8 pio_status();
|
||||
inline void run();
|
||||
|
@ -225,6 +218,8 @@ struct {
|
|||
|
||||
enum { CYCLE_OPREAD = 0, CYCLE_READ, CYCLE_WRITE, CYCLE_IO };
|
||||
inline void exec_cycle();
|
||||
inline void last_cycle();
|
||||
inline void last_cycle_exec();
|
||||
inline void cycle_edge();
|
||||
inline bool in_opcode();
|
||||
|
||||
|
|
|
@ -113,11 +113,11 @@ uint16 index;
|
|||
void bCPU::hdma_run() {
|
||||
int l, xferlen;
|
||||
uint8 x, active_channels = 0;
|
||||
static hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
|
||||
static uint8 hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
|
||||
for(int i=0;i<8;i++) {
|
||||
if(channel[i].hdma_active == false)continue;
|
||||
|
||||
// add_cycles(8);
|
||||
add_cycles(8);
|
||||
active_channels++;
|
||||
|
||||
if(channel[i].hdma_line_counter == 0) {
|
||||
|
@ -140,7 +140,7 @@ static hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
|
|||
if(channel[i].hdma_indirect == true) {
|
||||
channel[i].hdma_iaddr = mem_bus->read(hdma_addr(i));
|
||||
channel[i].hdma_iaddr |= mem_bus->read(hdma_addr(i)) << 8;
|
||||
// add_cycles(16);
|
||||
add_cycles(16);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,12 +157,12 @@ static hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
|
|||
}
|
||||
|
||||
hdma_write(i, l, x);
|
||||
// add_cycles(8);
|
||||
add_cycles(8);
|
||||
}
|
||||
}
|
||||
|
||||
if(active_channels != 0) {
|
||||
// add_cycles(18);
|
||||
add_cycles(18);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,15 @@
|
|||
inline void bCPU::cycle_edge() {
|
||||
void bCPU::last_cycle() {
|
||||
status.is_last_cycle = true;
|
||||
}
|
||||
|
||||
void bCPU::last_cycle_exec() {
|
||||
status.is_last_cycle = false;
|
||||
|
||||
time.nmi_pending = nmi_test();
|
||||
time.irq_pending = irq_test();
|
||||
}
|
||||
|
||||
void bCPU::cycle_edge() {
|
||||
int c, n, z;
|
||||
if(status.dma_state != DMASTATE_STOP) {
|
||||
switch(status.dma_state) {
|
||||
|
@ -36,15 +47,17 @@ int c, n, z;
|
|||
}
|
||||
|
||||
void bCPU::exec_cycle() {
|
||||
//on first cycle?
|
||||
if(status.cycle_pos == 0) {
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_BEGIN);
|
||||
status.opcode = op_read();
|
||||
status.cycle_pos = 1;
|
||||
} else {
|
||||
(this->*optbl[status.opcode])();
|
||||
if(status.cycle_pos == 0) {
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_END);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
(this->*optbl[status.opcode])();
|
||||
if(status.cycle_pos == 0) {
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_END);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
[IRQ cycles]
|
||||
[1] pbr,pc ; 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) {
|
||||
//WDC 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::nmi_test() {
|
||||
if(time.nmi_transition == 0)return false;
|
||||
time.nmi_transition = 0;
|
||||
|
||||
if(status.cpu_state == CPUSTATE_WAI) {
|
||||
status.cpu_state = CPUSTATE_RUN;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if(status.cpu_state == CPUSTATE_WAI) {
|
||||
status.cpu_state = CPUSTATE_RUN;
|
||||
}
|
||||
|
||||
if(regs.p.i)return false;
|
||||
return true;
|
||||
}
|
|
@ -42,18 +42,17 @@ uint8 r;
|
|||
}
|
||||
|
||||
//JOYSER0
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//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;
|
||||
r = regs.mdr & 0xfc;
|
||||
|
@ -96,44 +95,19 @@ uint8 r;
|
|||
}
|
||||
|
||||
//RDNMI
|
||||
/* $4210 bit 7 (NMI triggered bit) is set at:
|
||||
* V=225/240,HC>=2,
|
||||
* V>225
|
||||
* The bit is only set once per NMI trigger, so
|
||||
* subsequent reads return this bit as being clear.
|
||||
* There is but one exception: if the $4210 read
|
||||
* occurs at *exactly* V=225/240,HC==2, then $4210
|
||||
* bit 7 will be set, and the next read will also
|
||||
* have this bit set.
|
||||
*/
|
||||
//7 = NMI acknowledge
|
||||
//6-4 = MDR
|
||||
//3-0 = CPU (5a22) version
|
||||
uint8 bCPU::mmio_r4210() {
|
||||
uint8 r;
|
||||
uint16 v, h, hc, vs;
|
||||
r = regs.mdr & 0x70;
|
||||
uint8 r;
|
||||
r = regs.mdr & 0x70;
|
||||
r |= uint8(!time.nmi_read) << 7;
|
||||
|
||||
v = vcounter();
|
||||
h = hcounter();
|
||||
hc = hcycles();
|
||||
vs = (overscan()?239:224);
|
||||
|
||||
if(status.nmi_read == false) {
|
||||
if(
|
||||
(v == (vs + 1) && hc >= 2) ||
|
||||
(v > (vs + 1))
|
||||
) {
|
||||
r |= 0x80;
|
||||
|
||||
//test for special case where NMI read not raised
|
||||
if(v != (vs + 1) || hc != 2) {
|
||||
status.nmi_read = true;
|
||||
}
|
||||
}
|
||||
if(!nmi_trigger_pos_match(0) && !nmi_trigger_pos_match(2)) {
|
||||
time.nmi_read = 1;
|
||||
}
|
||||
|
||||
r |= 0x02; //cpu version number
|
||||
r |= (cpu_version & 0x0f);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -142,10 +116,15 @@ uint16 v, h, hc, vs;
|
|||
//6-0 = MDR
|
||||
uint8 bCPU::mmio_r4211() {
|
||||
uint8 r;
|
||||
r = regs.mdr & 0x7f;
|
||||
if(status.irq_exec == true)r |= 0x80;
|
||||
status.irq_exec = false;
|
||||
status.irq_read = true;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -155,23 +134,20 @@ uint8 r;
|
|||
//5-1 = MDR
|
||||
//0 = joypad ready
|
||||
uint8 bCPU::mmio_r4212() {
|
||||
uint8 r;
|
||||
uint16 v, h, hc, vs;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -291,9 +267,7 @@ uint8 bCPU::mmio_r43xb(uint8 i) {
|
|||
}
|
||||
|
||||
uint8 bCPUMMIO::read(uint32 addr) {
|
||||
uint8 i;
|
||||
//cpu->sync();
|
||||
|
||||
uint i;
|
||||
//APU
|
||||
if(addr >= 0x2140 && addr <= 0x217f) {
|
||||
return apu->port_read(addr & 3);
|
||||
|
@ -337,6 +311,8 @@ uint8 i;
|
|||
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 0x4000:dprintf("* 4000 read at %3d,%4d <%d>", cpu->time.v, cpu->time.hc, cpu->status.cycle_count);break;
|
||||
case 0x4200:dprintf("* 4200 read at %3d,%4d", cpu->time.v, cpu->time.hc);break;
|
||||
}
|
||||
|
||||
return cpu->regs.mdr;
|
||||
|
@ -383,14 +359,20 @@ void bCPU::mmio_w4200(uint8 value) {
|
|||
status.hirq_enabled = !!(value & 0x10);
|
||||
status.auto_joypad_poll = !!(value & 0x01);
|
||||
|
||||
if(status.nmi_enabled == false) {
|
||||
status.nmi_read = false;
|
||||
if(time.nmi_read == 0) {
|
||||
if(time.nmi_line == 1 && !status.nmi_enabled == 0) {
|
||||
time.nmi_transition = 1;
|
||||
}
|
||||
time.nmi_line = !status.nmi_enabled;
|
||||
}
|
||||
|
||||
status.irq_exec = false;
|
||||
if(status.virq_enabled == true || status.hirq_enabled == true) {
|
||||
status.irq_read = false;
|
||||
if(status.virq_enabled == false && status.hirq_enabled == false) {
|
||||
time.irq_line = 1;
|
||||
time.irq_read = 1;
|
||||
time.irq_transition = 0;
|
||||
}
|
||||
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//WRIO
|
||||
|
@ -424,32 +406,32 @@ 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;
|
||||
status.irq_read = false;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//HTIMEH
|
||||
void bCPU::mmio_w4208(uint8 value) {
|
||||
status.hirq_pos = (status.hirq_pos & 0x00ff) | (value << 8);
|
||||
status.irq_read = false;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//VTIMEL
|
||||
void bCPU::mmio_w4209(uint8 value) {
|
||||
status.virq_pos = (status.virq_pos & 0xff00) | value;
|
||||
status.irq_read = false;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//VTIMEH
|
||||
void bCPU::mmio_w420a(uint8 value) {
|
||||
status.virq_pos = (status.virq_pos & 0x00ff) | (value << 8);
|
||||
status.irq_read = false;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//DMAEN
|
||||
|
@ -479,7 +461,7 @@ void bCPU::mmio_w420c(uint8 value) {
|
|||
|
||||
//MEMSEL
|
||||
void bCPU::mmio_w420d(uint8 value) {
|
||||
mem_bus->fastROM = value & 1;
|
||||
mem_bus->set_speed(value & 1);
|
||||
}
|
||||
|
||||
//DMAPx
|
||||
|
@ -549,8 +531,6 @@ void bCPU::mmio_w43xb(uint8 value, uint8 i) {
|
|||
|
||||
void bCPUMMIO::write(uint32 addr, uint8 value) {
|
||||
uint8 i;
|
||||
//cpu->sync();
|
||||
|
||||
//APU
|
||||
if(addr >= 0x2140 && addr <= 0x217f) {
|
||||
cpu->port_write(addr & 3, value);
|
||||
|
@ -600,6 +580,7 @@ uint8 i;
|
|||
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 0x4000:dprintf("* 4000 write at %3d,%4d", cpu->time.v, cpu->time.hc);break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
void bCPU::op_nop() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -10,6 +11,7 @@ void bCPU::op_nop() {
|
|||
void bCPU::op_wdm() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
op_read();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -22,6 +24,7 @@ void bCPU::op_xba() {
|
|||
cpu_io();
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.a.l ^= regs.a.h;
|
||||
regs.a.h ^= regs.a.l;
|
||||
|
@ -54,6 +57,7 @@ void bCPU::op_mvn() {
|
|||
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;
|
||||
|
@ -82,6 +86,7 @@ void bCPU::op_mvp() {
|
|||
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;
|
||||
|
@ -111,6 +116,7 @@ void bCPU::op_brk() {
|
|||
rd.l = op_read(OPMODE_LONG, (regs.e)?0xfffe:0xffe6);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
rd.h = op_read(OPMODE_LONG, (regs.e)?0xffff:0xffe7);
|
||||
regs.pc.b = 0x00;
|
||||
regs.pc.w = rd.w;
|
||||
|
@ -143,6 +149,7 @@ void bCPU::op_cop() {
|
|||
rd.l = op_read(OPMODE_LONG, (regs.e)?0xfff4:0xffe4);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
rd.h = op_read(OPMODE_LONG, (regs.e)?0xfff5:0xffe5);
|
||||
regs.pc.b = 0x00;
|
||||
regs.pc.w = rd.w;
|
||||
|
@ -160,6 +167,7 @@ void bCPU::op_stp() {
|
|||
status.cpu_state = CPUSTATE_STP;
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.pc.w--;
|
||||
status.cycle_pos = 0;
|
||||
|
@ -174,8 +182,11 @@ void bCPU::op_wai() {
|
|||
status.cpu_state = CPUSTATE_WAI;
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.pc.w--;
|
||||
if(status.cpu_state == CPUSTATE_WAI) {
|
||||
regs.pc.w--;
|
||||
}
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -184,6 +195,7 @@ void bCPU::op_wai() {
|
|||
void bCPU::op_xce() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
bool c = regs.p.c;
|
||||
regs.p.c = regs.e;
|
||||
|
@ -202,6 +214,7 @@ void bCPU::op_xce() {
|
|||
void bCPU::op_clc() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.p.c = 0;
|
||||
status.cycle_pos = 0;
|
||||
|
@ -212,6 +225,7 @@ void bCPU::op_clc() {
|
|||
void bCPU::op_cld() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.p.d = 0;
|
||||
status.cycle_pos = 0;
|
||||
|
@ -222,6 +236,7 @@ void bCPU::op_cld() {
|
|||
void bCPU::op_cli() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.p.i = 0;
|
||||
status.cycle_pos = 0;
|
||||
|
@ -232,6 +247,7 @@ void bCPU::op_cli() {
|
|||
void bCPU::op_clv() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.p.v = 0;
|
||||
status.cycle_pos = 0;
|
||||
|
@ -242,6 +258,7 @@ void bCPU::op_clv() {
|
|||
void bCPU::op_sec() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.p.c = 1;
|
||||
status.cycle_pos = 0;
|
||||
|
@ -252,6 +269,7 @@ void bCPU::op_sec() {
|
|||
void bCPU::op_sed() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.p.d = 1;
|
||||
status.cycle_pos = 0;
|
||||
|
@ -262,6 +280,7 @@ void bCPU::op_sed() {
|
|||
void bCPU::op_sei() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.p.i = 1;
|
||||
status.cycle_pos = 0;
|
||||
|
@ -275,6 +294,7 @@ void bCPU::op_rep() {
|
|||
rd.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.p &=~ rd.l;
|
||||
if(regs.e)regs.p |= 0x30;
|
||||
|
@ -293,6 +313,7 @@ void bCPU::op_sep() {
|
|||
rd.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.p |= rd.l;
|
||||
if(regs.e)regs.p |= 0x30;
|
||||
|
@ -308,6 +329,7 @@ void bCPU::op_sep() {
|
|||
void bCPU::op_tax() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.x.l = regs.a.l;
|
||||
|
@ -326,6 +348,7 @@ void bCPU::op_tax() {
|
|||
void bCPU::op_tay() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.y.l = regs.a.l;
|
||||
|
@ -344,6 +367,7 @@ void bCPU::op_tay() {
|
|||
void bCPU::op_txa() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.m) {
|
||||
regs.a.l = regs.x.l;
|
||||
|
@ -362,6 +386,7 @@ void bCPU::op_txa() {
|
|||
void bCPU::op_txy() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.y.l = regs.x.l;
|
||||
|
@ -380,6 +405,7 @@ void bCPU::op_txy() {
|
|||
void bCPU::op_tya() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.m) {
|
||||
regs.a.l = regs.y.l;
|
||||
|
@ -398,6 +424,7 @@ void bCPU::op_tya() {
|
|||
void bCPU::op_tyx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.x.l = regs.y.l;
|
||||
|
@ -416,6 +443,7 @@ void bCPU::op_tyx() {
|
|||
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);
|
||||
|
@ -428,6 +456,7 @@ void bCPU::op_tcd() {
|
|||
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;
|
||||
|
@ -439,6 +468,7 @@ void bCPU::op_tcs() {
|
|||
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);
|
||||
|
@ -451,6 +481,7 @@ void bCPU::op_tdc() {
|
|||
void bCPU::op_tsc() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.a.w = regs.s.w;
|
||||
if(regs.e) {
|
||||
|
@ -468,6 +499,7 @@ void bCPU::op_tsc() {
|
|||
void bCPU::op_tsx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.x.l = regs.s.l;
|
||||
|
@ -486,6 +518,7 @@ void bCPU::op_tsx() {
|
|||
void bCPU::op_txs() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.e) {
|
||||
regs.s.l = regs.x.l;
|
||||
|
@ -511,6 +544,7 @@ void bCPU::op_pha() {
|
|||
stack_write(regs.a.h);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
stack_write(regs.a.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -527,6 +561,7 @@ void bCPU::op_phx() {
|
|||
stack_write(regs.x.h);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
stack_write(regs.x.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -543,6 +578,7 @@ void bCPU::op_phy() {
|
|||
stack_write(regs.y.h);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
stack_write(regs.y.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -559,6 +595,7 @@ void bCPU::op_phd() {
|
|||
stack_write(regs. d.h);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
stack_write(regs. d.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -571,6 +608,7 @@ void bCPU::op_phb() {
|
|||
cpu_io();
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
stack_write(regs.db);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -583,6 +621,7 @@ void bCPU::op_phk() {
|
|||
cpu_io();
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
stack_write(regs.pc.b);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -595,6 +634,7 @@ void bCPU::op_php() {
|
|||
cpu_io();
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
stack_write(regs.p);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -610,6 +650,7 @@ void bCPU::op_pla() {
|
|||
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);
|
||||
|
@ -618,6 +659,7 @@ void bCPU::op_pla() {
|
|||
}
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
regs.a.h = stack_read();
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
|
@ -635,6 +677,7 @@ void bCPU::op_plx() {
|
|||
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);
|
||||
|
@ -643,6 +686,7 @@ void bCPU::op_plx() {
|
|||
}
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
regs.x.h = stack_read();
|
||||
regs.p.n = !!(regs.x.w & 0x8000);
|
||||
regs.p.z = (regs.x.w == 0);
|
||||
|
@ -660,6 +704,7 @@ void bCPU::op_ply() {
|
|||
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);
|
||||
|
@ -668,6 +713,7 @@ void bCPU::op_ply() {
|
|||
}
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
regs.y.h = stack_read();
|
||||
regs.p.n = !!(regs.y.w & 0x8000);
|
||||
regs.p.z = (regs.y.w == 0);
|
||||
|
@ -685,6 +731,7 @@ void bCPU::op_pld() {
|
|||
cpu_io();
|
||||
break;
|
||||
case 3:
|
||||
if(0)last_cycle();
|
||||
regs. d.l = stack_read();
|
||||
if(0) {
|
||||
regs.p.n = !!(regs. d.l & 0x80);
|
||||
|
@ -693,6 +740,7 @@ void bCPU::op_pld() {
|
|||
}
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
regs. d.h = stack_read();
|
||||
regs.p.n = !!(regs. d.w & 0x8000);
|
||||
regs.p.z = (regs. d.w == 0);
|
||||
|
@ -710,6 +758,7 @@ void bCPU::op_plb() {
|
|||
cpu_io();
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
regs.db = stack_read();
|
||||
regs.p.n = !!(regs.db & 0x80);
|
||||
regs.p.z = (regs.db == 0);
|
||||
|
@ -727,6 +776,7 @@ void bCPU::op_plp() {
|
|||
cpu_io();
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
regs.p = stack_read();
|
||||
if(regs.e)regs.p |= 0x30;
|
||||
if(regs.p.x) {
|
||||
|
@ -750,6 +800,7 @@ void bCPU::op_pea() {
|
|||
stack_write(aa.h);
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
stack_write(aa.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -774,6 +825,7 @@ void bCPU::op_pei() {
|
|||
stack_write(aa.h);
|
||||
break;
|
||||
case 6:
|
||||
last_cycle();
|
||||
stack_write(aa.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -796,6 +848,7 @@ void bCPU::op_per() {
|
|||
stack_write(rd.h);
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
stack_write(rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
|
|
@ -1,27 +1,7 @@
|
|||
void bCPU::op_bra() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
rd.l = op_read();
|
||||
if(1) {
|
||||
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:
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -34,6 +14,7 @@ void bCPU::op_bcc() {
|
|||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -43,6 +24,7 @@ void bCPU::op_bcc() {
|
|||
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;
|
||||
|
@ -55,6 +37,7 @@ void bCPU::op_bcs() {
|
|||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -64,6 +47,7 @@ void bCPU::op_bcs() {
|
|||
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;
|
||||
|
@ -76,6 +60,7 @@ void bCPU::op_bne() {
|
|||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -85,6 +70,7 @@ void bCPU::op_bne() {
|
|||
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;
|
||||
|
@ -97,6 +83,7 @@ void bCPU::op_beq() {
|
|||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -106,6 +93,7 @@ void bCPU::op_beq() {
|
|||
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;
|
||||
|
@ -118,6 +106,7 @@ void bCPU::op_bpl() {
|
|||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -127,6 +116,7 @@ void bCPU::op_bpl() {
|
|||
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;
|
||||
|
@ -139,6 +129,7 @@ void bCPU::op_bmi() {
|
|||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -148,6 +139,7 @@ void bCPU::op_bmi() {
|
|||
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;
|
||||
|
@ -160,6 +152,7 @@ void bCPU::op_bvc() {
|
|||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -169,6 +162,7 @@ void bCPU::op_bvc() {
|
|||
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;
|
||||
|
@ -181,6 +175,25 @@ void bCPU::op_bvs() {
|
|||
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;
|
||||
|
@ -196,6 +209,7 @@ void bCPU::op_brl() {
|
|||
rd.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.pc.w = regs.pc.d + (int16)rd.w;
|
||||
status.cycle_pos = 0;
|
||||
|
@ -209,6 +223,7 @@ void bCPU::op_jmp_addr() {
|
|||
rd.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
rd.h = op_read();
|
||||
regs.pc.w = rd.w;
|
||||
status.cycle_pos = 0;
|
||||
|
@ -225,6 +240,7 @@ void bCPU::op_jmp_long() {
|
|||
rd.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
rd.b = op_read();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
status.cycle_pos = 0;
|
||||
|
@ -244,6 +260,7 @@ void bCPU::op_jmp_iaddr() {
|
|||
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;
|
||||
|
@ -266,6 +283,7 @@ void bCPU::op_jmp_iaddrx() {
|
|||
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;
|
||||
|
@ -288,6 +306,7 @@ void bCPU::op_jmp_iladdr() {
|
|||
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;
|
||||
|
@ -311,6 +330,7 @@ void bCPU::op_jsr_addr() {
|
|||
stack_write(regs.pc.h);
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
stack_write(regs.pc.l);
|
||||
regs.pc.w = aa.w;
|
||||
status.cycle_pos = 0;
|
||||
|
@ -340,6 +360,7 @@ void bCPU::op_jsr_long() {
|
|||
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;
|
||||
|
@ -368,6 +389,7 @@ void bCPU::op_jsr_iaddrx() {
|
|||
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;
|
||||
|
@ -402,6 +424,7 @@ void bCPU::op_rti() {
|
|||
}
|
||||
break;
|
||||
case 6:
|
||||
last_cycle();
|
||||
rd.b = stack_read();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
status.cycle_pos = 0;
|
||||
|
@ -424,6 +447,7 @@ void bCPU::op_rts() {
|
|||
rd.h = stack_read();
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.pc.w = rd.w;
|
||||
regs.pc.w++;
|
||||
|
@ -447,6 +471,7 @@ void bCPU::op_rtl() {
|
|||
rd.h = stack_read();
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
rd.b = stack_read();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
regs.pc.w++;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,7 @@
|
|||
void bCPU::op_inc() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.m) {
|
||||
regs.a.l++;
|
||||
|
@ -19,6 +20,7 @@ void bCPU::op_inc() {
|
|||
void bCPU::op_inx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.x.l++;
|
||||
|
@ -37,6 +39,7 @@ void bCPU::op_inx() {
|
|||
void bCPU::op_iny() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.y.l++;
|
||||
|
@ -55,6 +58,7 @@ void bCPU::op_iny() {
|
|||
void bCPU::op_dec() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.m) {
|
||||
regs.a.l--;
|
||||
|
@ -73,6 +77,7 @@ void bCPU::op_dec() {
|
|||
void bCPU::op_dex() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.x.l--;
|
||||
|
@ -91,6 +96,7 @@ void bCPU::op_dex() {
|
|||
void bCPU::op_dey() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.y.l--;
|
||||
|
@ -109,6 +115,7 @@ void bCPU::op_dey() {
|
|||
void bCPU::op_asl() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.m) {
|
||||
regs.p.c = !!(regs.a.l & 0x80);
|
||||
|
@ -129,6 +136,7 @@ void bCPU::op_asl() {
|
|||
void bCPU::op_lsr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.m) {
|
||||
regs.p.c = regs.a.l & 1;
|
||||
|
@ -149,6 +157,7 @@ void bCPU::op_lsr() {
|
|||
void bCPU::op_rol() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
uint16 c = regs.p.c;
|
||||
if(regs.p.m) {
|
||||
|
@ -172,6 +181,7 @@ void bCPU::op_rol() {
|
|||
void bCPU::op_ror() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
uint16 c;
|
||||
if(regs.p.m) {
|
||||
|
@ -218,6 +228,7 @@ void bCPU::op_inc_addr() {
|
|||
op_write(OPMODE_DBR, aa.w + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -248,6 +259,7 @@ void bCPU::op_dec_addr() {
|
|||
op_write(OPMODE_DBR, aa.w + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -278,6 +290,7 @@ void bCPU::op_asl_addr() {
|
|||
op_write(OPMODE_DBR, aa.w + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -308,6 +321,7 @@ void bCPU::op_lsr_addr() {
|
|||
op_write(OPMODE_DBR, aa.w + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -338,6 +352,7 @@ void bCPU::op_rol_addr() {
|
|||
op_write(OPMODE_DBR, aa.w + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -368,6 +383,7 @@ void bCPU::op_ror_addr() {
|
|||
op_write(OPMODE_DBR, aa.w + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -398,6 +414,7 @@ void bCPU::op_trb_addr() {
|
|||
op_write(OPMODE_DBR, aa.w + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -428,6 +445,7 @@ void bCPU::op_tsb_addr() {
|
|||
op_write(OPMODE_DBR, aa.w + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -461,6 +479,7 @@ void bCPU::op_inc_addrx() {
|
|||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -494,6 +513,7 @@ void bCPU::op_dec_addrx() {
|
|||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -527,6 +547,7 @@ void bCPU::op_asl_addrx() {
|
|||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -560,6 +581,7 @@ void bCPU::op_lsr_addrx() {
|
|||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -593,6 +615,7 @@ void bCPU::op_rol_addrx() {
|
|||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -626,6 +649,7 @@ void bCPU::op_ror_addrx() {
|
|||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -656,6 +680,7 @@ void bCPU::op_inc_dp() {
|
|||
op_write(OPMODE_DP, dp + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -686,6 +711,7 @@ void bCPU::op_dec_dp() {
|
|||
op_write(OPMODE_DP, dp + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -716,6 +742,7 @@ void bCPU::op_asl_dp() {
|
|||
op_write(OPMODE_DP, dp + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -746,6 +773,7 @@ void bCPU::op_lsr_dp() {
|
|||
op_write(OPMODE_DP, dp + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -776,6 +804,7 @@ void bCPU::op_rol_dp() {
|
|||
op_write(OPMODE_DP, dp + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -806,6 +835,7 @@ void bCPU::op_ror_dp() {
|
|||
op_write(OPMODE_DP, dp + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -836,6 +866,7 @@ void bCPU::op_trb_dp() {
|
|||
op_write(OPMODE_DP, dp + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -866,6 +897,7 @@ void bCPU::op_tsb_dp() {
|
|||
op_write(OPMODE_DP, dp + 1, rd.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -899,6 +931,7 @@ void bCPU::op_inc_dpx() {
|
|||
op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -932,6 +965,7 @@ void bCPU::op_dec_dpx() {
|
|||
op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -965,6 +999,7 @@ void bCPU::op_asl_dpx() {
|
|||
op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -998,6 +1033,7 @@ void bCPU::op_lsr_dpx() {
|
|||
op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -1031,6 +1067,7 @@ void bCPU::op_rol_dpx() {
|
|||
op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
@ -1064,6 +1101,7 @@ void bCPU::op_ror_dpx() {
|
|||
op_write(OPMODE_DP, dp + regs.x.w + 1, rd.h);
|
||||
break;
|
||||
case 8:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, rd.l);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
|
|
@ -7,10 +7,12 @@ void bCPU::op_sta_addr() {
|
|||
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;
|
||||
|
@ -26,10 +28,12 @@ void bCPU::op_stx_addr() {
|
|||
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;
|
||||
|
@ -45,10 +49,12 @@ void bCPU::op_sty_addr() {
|
|||
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;
|
||||
|
@ -64,10 +70,12 @@ void bCPU::op_stz_addr() {
|
|||
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;
|
||||
|
@ -86,10 +94,12 @@ void bCPU::op_sta_addrx() {
|
|||
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;
|
||||
|
@ -108,10 +118,12 @@ void bCPU::op_stz_addrx() {
|
|||
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;
|
||||
|
@ -130,10 +142,12 @@ void bCPU::op_sta_addry() {
|
|||
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;
|
||||
|
@ -152,10 +166,12 @@ void bCPU::op_sta_long() {
|
|||
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;
|
||||
|
@ -174,10 +190,12 @@ void bCPU::op_sta_longx() {
|
|||
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;
|
||||
|
@ -193,10 +211,12 @@ void bCPU::op_sta_dp() {
|
|||
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;
|
||||
|
@ -212,10 +232,12 @@ void bCPU::op_stx_dp() {
|
|||
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;
|
||||
|
@ -231,10 +253,12 @@ void bCPU::op_sty_dp() {
|
|||
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;
|
||||
|
@ -250,10 +274,12 @@ void bCPU::op_stz_dp() {
|
|||
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;
|
||||
|
@ -272,10 +298,12 @@ void bCPU::op_sta_dpx() {
|
|||
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;
|
||||
|
@ -294,10 +322,12 @@ void bCPU::op_sty_dpx() {
|
|||
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;
|
||||
|
@ -316,10 +346,12 @@ void bCPU::op_stz_dpx() {
|
|||
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;
|
||||
|
@ -338,10 +370,12 @@ void bCPU::op_stx_dpy() {
|
|||
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;
|
||||
|
@ -363,10 +397,12 @@ void bCPU::op_sta_idp() {
|
|||
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;
|
||||
|
@ -391,10 +427,12 @@ void bCPU::op_sta_ildp() {
|
|||
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;
|
||||
|
@ -419,10 +457,12 @@ void bCPU::op_sta_idpx() {
|
|||
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;
|
||||
|
@ -447,10 +487,12 @@ void bCPU::op_sta_idpy() {
|
|||
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;
|
||||
|
@ -475,10 +517,12 @@ void bCPU::op_sta_ildpy() {
|
|||
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;
|
||||
|
@ -494,10 +538,12 @@ void bCPU::op_sta_sr() {
|
|||
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;
|
||||
|
@ -522,10 +568,12 @@ void bCPU::op_sta_isry() {
|
|||
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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -25,19 +25,158 @@
|
|||
* 4 cycles short?
|
||||
*/
|
||||
|
||||
uint16 bCPU::vcounter() { return time.v; }
|
||||
uint16 bCPU::hcounter() { return get_hcounter(); }
|
||||
uint16 bCPU::hcycles() { return time.hc; }
|
||||
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; }
|
||||
uint16 bCPU::region_scanlines() { return time.region_scanlines; }
|
||||
|
||||
void bCPU::set_interlace(bool r) { time.interlace = r; }
|
||||
void bCPU::set_overscan(bool r) { time.overscan = r; }
|
||||
void bCPU::set_interlace(bool r) { time.interlace = r; update_interrupts(); }
|
||||
void bCPU::set_overscan (bool r) { time.overscan = r; update_interrupts(); }
|
||||
|
||||
uint8 bCPU::dma_counter() { return (time.dma_counter + time.hc) & 6; }
|
||||
|
||||
bool bCPU::nmi_trigger_pos_match(uint32 offset) {
|
||||
uint16 v = overscan() ? 240 : 225;
|
||||
uint16 hc = 2 + offset;
|
||||
return (time.v == v && time.hc == hc);
|
||||
}
|
||||
|
||||
bool bCPU::irq_trigger_pos_match(uint32 offset) {
|
||||
uint16 v = status.virq_pos;
|
||||
uint16 hc = (status.hirq_enabled) ? status.hirq_pos : 0;
|
||||
|
||||
//positions that can never be latched
|
||||
//region_scanlines() = 262/NTSC, 312/PAL
|
||||
//PAL results are unverified on hardware
|
||||
if(v == 240 && hc == 339 && interlace() == false && interlace_field() == 1)return false;
|
||||
if(v == (region_scanlines() - 1) && hc == 339 && interlace() == false)return false;
|
||||
if(v == region_scanlines() && interlace() == false)return false;
|
||||
if(v == region_scanlines() && hc == 339)return false;
|
||||
if(v > region_scanlines())return false;
|
||||
if(hc > 339)return false;
|
||||
|
||||
hc = (hc != 0) ? ((hc << 2) + 14) : 10;
|
||||
hc += offset;
|
||||
if(hc >= time.line_cycles) {
|
||||
hc -= time.line_cycles;
|
||||
if(++v >= time.frame_lines) {
|
||||
v = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if((status.virq_enabled == true && time.v == v) || status.virq_enabled == false) {
|
||||
return (time.hc == hc);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void bCPU::update_nmi() {
|
||||
if(time.v == (overscan() ? 240 : 225)) {
|
||||
time.nmi_read_trigger_pos = 2;
|
||||
time.nmi_line_trigger_pos = 6;
|
||||
} else {
|
||||
time.nmi_read_trigger_pos = -64;
|
||||
time.nmi_line_trigger_pos = -64;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::update_irq() {
|
||||
int vpos = status.virq_pos;
|
||||
int hpos = (status.hirq_enabled) ? status.hirq_pos : 0;
|
||||
|
||||
//positions that can never be latched
|
||||
//region_scanlines() = 262/NTSC, 312/PAL
|
||||
//PAL results are unverified on hardware
|
||||
if(vpos == 240 && hpos == 339 && interlace() == false && interlace_field() == 1)goto _nolatch;
|
||||
if(vpos == (region_scanlines() - 1) && hpos == 339 && interlace() == false)goto _nolatch;
|
||||
if(vpos == region_scanlines() && interlace() == false)goto _nolatch;
|
||||
if(vpos == region_scanlines() && hpos == 339)goto _nolatch;
|
||||
if(vpos > region_scanlines())goto _nolatch;
|
||||
if(hpos > 339)goto _nolatch;
|
||||
|
||||
hpos = (hpos != 0) ? ((hpos << 2) + 14) : 10;
|
||||
if(hpos >= time.line_cycles) {
|
||||
hpos -= time.line_cycles;
|
||||
if(++vpos >= time.frame_lines) {
|
||||
vpos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if((status.virq_enabled == true && time.v == vpos) || status.virq_enabled == false) {
|
||||
time.irq_read_trigger_pos = hpos;
|
||||
} else {
|
||||
time.irq_read_trigger_pos = -64;
|
||||
}
|
||||
|
||||
hpos += 4;
|
||||
if(hpos >= time.line_cycles) {
|
||||
hpos -= time.line_cycles;
|
||||
if(++vpos >= time.frame_lines) {
|
||||
vpos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if((status.virq_enabled == true && time.v == vpos) || status.virq_enabled == false) {
|
||||
time.irq_line_trigger_pos = hpos;
|
||||
} else {
|
||||
time.irq_line_trigger_pos = -64;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
_nolatch:
|
||||
time.irq_read_trigger_pos = -64;
|
||||
time.irq_line_trigger_pos = -64;
|
||||
}
|
||||
|
||||
void bCPU::update_interrupts() {
|
||||
update_nmi();
|
||||
update_irq();
|
||||
}
|
||||
|
||||
void bCPU::poll_interrupts(int cycles) {
|
||||
int16 hc, hc_end;
|
||||
if(time.hc == 0) {
|
||||
hc = -1;
|
||||
hc_end = cycles;
|
||||
} else {
|
||||
hc = time.hc;
|
||||
hc_end = time.hc + cycles;
|
||||
}
|
||||
|
||||
if(hc < time.nmi_read_trigger_pos && time.nmi_read_trigger_pos <= hc_end) {
|
||||
//nmi_read can go low even with NMI interrupts disabled in $4200.d7
|
||||
time.nmi_read = 0;
|
||||
}
|
||||
|
||||
if(hc < time.nmi_line_trigger_pos && time.nmi_line_trigger_pos <= hc_end) {
|
||||
if(status.nmi_enabled == true) {
|
||||
if(time.nmi_line == 1) {
|
||||
time.nmi_transition = 1;
|
||||
}
|
||||
time.nmi_line = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(hc < time.irq_read_trigger_pos && time.irq_read_trigger_pos <= hc_end) {
|
||||
if(status.virq_enabled == true || status.hirq_enabled == true) {
|
||||
time.irq_read = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(hc < time.irq_line_trigger_pos && time.irq_line_trigger_pos <= hc_end) {
|
||||
if(status.virq_enabled == true || status.hirq_enabled == true) {
|
||||
time.irq_line = 0;
|
||||
time.irq_transition = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//all scanlines are 1364 cycles long, except scanline 240
|
||||
//on non-interlace odd-frames, which is 1360 cycles long.
|
||||
//[NTSC]
|
||||
|
@ -68,7 +207,6 @@ void bCPU::inc_vcounter() {
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -76,6 +214,8 @@ void bCPU::inc_vcounter() {
|
|||
time.line_cycles = 1364;
|
||||
}
|
||||
time.dram_refreshed = false;
|
||||
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//all dots are 4 cycles long, except dots 323 and 327. dots 323 and 327
|
||||
|
@ -93,16 +233,6 @@ uint16 bCPU::get_hcounter() {
|
|||
return (time.hc - ((time.hc > 1292) << 1) - ((time.hc > 1310) << 1)) >> 2;
|
||||
}
|
||||
|
||||
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
|
||||
//in reality, this is probably based on frame cycle length...
|
||||
time.dram_refresh_pos ^= 12;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 bCPU::cycles_executed() {
|
||||
uint32 r = status.cycles_executed;
|
||||
status.cycles_executed = 0;
|
||||
|
@ -112,28 +242,73 @@ uint32 r = status.cycles_executed;
|
|||
void bCPU::add_cycles(int cycles) {
|
||||
status.cycles_executed += cycles;
|
||||
|
||||
cycles >>= 1;
|
||||
while(cycles--) {
|
||||
time.hc += 2;
|
||||
poll_interrupts(cycles);
|
||||
|
||||
if(time.hc >= time.line_cycles) {
|
||||
inc_vcounter();
|
||||
if(time.v == 0) {
|
||||
frame();
|
||||
ppu->frame();
|
||||
}
|
||||
scanline();
|
||||
ppu->scanline();
|
||||
if(time.hc + cycles >= time.line_cycles) {
|
||||
cycles = (time.hc + cycles) - time.line_cycles;
|
||||
time.hc = 0;
|
||||
|
||||
inc_vcounter();
|
||||
poll_interrupts(cycles);
|
||||
|
||||
if(time.v == 0) {
|
||||
frame();
|
||||
ppu->frame();
|
||||
snes->frame();
|
||||
}
|
||||
|
||||
if(time.dram_refreshed == false && time.hc >= time.dram_refresh_pos) {
|
||||
dram_refresh();
|
||||
}
|
||||
scanline();
|
||||
ppu->scanline();
|
||||
// ppu->render_scanline();
|
||||
snes->scanline();
|
||||
time.line_rendered = false;
|
||||
}
|
||||
|
||||
if(hdma_test() == true) {
|
||||
hdma_run();
|
||||
if(time.line_rendered == false) {
|
||||
//rendering should start at H=22, but due to inaccurate
|
||||
//timing, and due to using a scanline-based renderer, use
|
||||
//a higher value to allow more games to run properly...
|
||||
//H=48 fixes off-by-one HDMA effects with FF6's battles
|
||||
if(time.hc + cycles >= (48 * 4)) {
|
||||
cycles = (time.hc + cycles) - (48 * 4);
|
||||
time.hc = (48 * 4);
|
||||
time.line_rendered = true;
|
||||
ppu->render_scanline();
|
||||
}
|
||||
}
|
||||
|
||||
if(time.dram_refreshed == false) {
|
||||
if(time.hc + cycles >= time.dram_refresh_pos) {
|
||||
time.dram_refreshed = true;
|
||||
status.cycles_executed += 40;
|
||||
cycles = (time.hc + cycles) - time.dram_refresh_pos;
|
||||
time.hc = time.dram_refresh_pos + 40;
|
||||
|
||||
if(cpu_version == 2) {
|
||||
if(time.v != 240 || time.interlace != false || time.interlace_field != 1) {
|
||||
if(time.dram_refresh_pos == 534) {
|
||||
time.dram_refresh_pos = 538;
|
||||
} else {
|
||||
time.dram_refresh_pos = 534;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(status.hdma_triggered == false) {
|
||||
//vcounter range verified on hardware
|
||||
if(time.v <= (overscan() ? 239 : 224)) {
|
||||
if(time.hc + cycles >= 1112) { //278 * 4 = 1112
|
||||
cycles = (time.hc + cycles) - 1112;
|
||||
time.hc = 1112;
|
||||
status.hdma_triggered = true;
|
||||
hdma_run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
time.hc += cycles;
|
||||
}
|
||||
|
||||
void bCPU::time_reset() {
|
||||
|
@ -150,10 +325,20 @@ void bCPU::time_reset() {
|
|||
time.line_cycles = 1364;
|
||||
|
||||
time.dram_refreshed = false;
|
||||
time.dram_refresh_pos = 538;
|
||||
time.dram_refresh_pos = (cpu_version == 2) ? 538 : 530;
|
||||
|
||||
time.dma_counter = 0;
|
||||
|
||||
time.nmi_pending = false;
|
||||
time.irq_pending = false;
|
||||
time.nmi_line = time.nmi_read = 1;
|
||||
time.irq_line = time.irq_read = 1;
|
||||
|
||||
time.nmi_transition = 0;
|
||||
time.irq_transition = 0;
|
||||
|
||||
update_interrupts();
|
||||
|
||||
switch(region) {
|
||||
case NTSC:
|
||||
time.region_scanlines = 262;
|
||||
|
|
|
@ -4,13 +4,42 @@ struct {
|
|||
bool interlace, interlace_field, overscan;
|
||||
uint16 line_cycles, frame_lines;
|
||||
|
||||
bool line_rendered;
|
||||
|
||||
bool dram_refreshed;
|
||||
uint16 dram_refresh_pos;
|
||||
|
||||
uint8 dma_counter;
|
||||
|
||||
uint16 region_scanlines;
|
||||
}time;
|
||||
|
||||
//nmi_pending, irq_pending are used by last_cycle()
|
||||
//nmi_line = /NMI, nmi_read = $4210.7
|
||||
//irq_line = /IRQ, irq_read = $4211.7
|
||||
bool nmi_pending, nmi_line, nmi_read;
|
||||
bool irq_pending, irq_line, irq_read;
|
||||
|
||||
//NMI is edge-sensitive, meaning it triggers when /NMI
|
||||
//transitions from high to low. This value is set to 1
|
||||
//when that happens, and cleared after the nmi_test()
|
||||
//routine acknowledges it and invokes the NMI interrupt
|
||||
bool nmi_transition;
|
||||
|
||||
//IRQ is level-sensitive, so it does not need to keep
|
||||
//track of transitions from high to low. IRQs will
|
||||
//continue to fire as long as /IRQ stays low.
|
||||
//However, if a write to $4200 forces IRQs high at the
|
||||
//exact same clock cycle that /IRQ goes low, the /IRQ
|
||||
//will still occur. Hence the need for this variable.
|
||||
bool irq_transition;
|
||||
|
||||
//position is relative to time.hc, set at start of each scanline
|
||||
//-64 means no trigger point on this scanline
|
||||
//$4210/$4211 status bits get set before /NMI and /IRQ go low,
|
||||
//hence the need for two variables for each.
|
||||
int32 nmi_read_trigger_pos, nmi_line_trigger_pos;
|
||||
int32 irq_read_trigger_pos, irq_line_trigger_pos;
|
||||
} time;
|
||||
|
||||
inline uint16 vcounter();
|
||||
inline uint16 hcounter();
|
||||
|
@ -20,6 +49,14 @@ inline bool interlace_field();
|
|||
inline bool overscan();
|
||||
inline uint16 region_scanlines();
|
||||
|
||||
inline bool nmi_trigger_pos_match(uint32 offset);
|
||||
inline bool irq_trigger_pos_match(uint32 offset);
|
||||
|
||||
inline void update_nmi();
|
||||
inline void update_irq();
|
||||
inline void update_interrupts();
|
||||
inline void poll_interrupts(int cycles);
|
||||
|
||||
inline void set_interlace(bool r);
|
||||
inline void set_overscan (bool r);
|
||||
|
||||
|
@ -27,6 +64,5 @@ inline uint8 dma_counter();
|
|||
|
||||
inline void inc_vcounter();
|
||||
inline uint16 get_hcounter();
|
||||
inline void dram_refresh();
|
||||
inline void add_cycles(int cycles);
|
||||
inline void time_reset();
|
||||
|
|
|
@ -53,7 +53,6 @@ char t[4096];
|
|||
|
||||
void update_line(int i, int n) {
|
||||
char t[4096];
|
||||
sprintf(t, "goto l%d;", n + 2);
|
||||
replace(line[i], "end;", "status.cycle_pos = 0;");
|
||||
replace(line[i], "skip;", "status.cycle_pos++;");
|
||||
}
|
||||
|
@ -88,7 +87,11 @@ char t[4096];
|
|||
|
||||
i++;
|
||||
}
|
||||
if(!strcmp(line[i], "}"))strcat(output_op, " status.cycle_pos = 0;\r\n");
|
||||
|
||||
if(!strcmp(line[i], "}")) {
|
||||
strcat(output_op, " status.cycle_pos = 0;\r\n");
|
||||
}
|
||||
|
||||
strcat(output_op, " break;\r\n");
|
||||
}
|
||||
strcat(output_op, " }\r\n}");
|
||||
|
|
Binary file not shown.
|
@ -1,14 +1,17 @@
|
|||
nop(0xea) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
}
|
||||
|
||||
wdm(0x42) {
|
||||
1:op_read();
|
||||
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;
|
||||
|
@ -26,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,7 +43,8 @@ cop(0x02, 0xfff4, 0xfff5, 0xffe4, 0xffe5) {
|
|||
4:stack_write(regs.pc.l);
|
||||
5:stack_write(regs.p);
|
||||
6:rd.l = op_read(OPMODE_LONG, (regs.e)?$1:$3);
|
||||
7:rd.h = op_read(OPMODE_LONG, (regs.e)?$2:$4);
|
||||
7:last_cycle();
|
||||
rd.h = op_read(OPMODE_LONG, (regs.e)?$2:$4);
|
||||
regs.pc.b = 0x00;
|
||||
regs.pc.w = rd.w;
|
||||
regs.p.i = 1;
|
||||
|
@ -49,19 +54,24 @@ cop(0x02, 0xfff4, 0xfff5, 0xffe4, 0xffe5) {
|
|||
stp(0xdb) {
|
||||
1:cpu_io();
|
||||
status.cpu_state = CPUSTATE_STP;
|
||||
2:cpu_io();
|
||||
2:last_cycle();
|
||||
cpu_io();
|
||||
regs.pc.w--;
|
||||
}
|
||||
|
||||
wai(0xcb) {
|
||||
1:cpu_io();
|
||||
status.cpu_state = CPUSTATE_WAI;
|
||||
2:cpu_io();
|
||||
regs.pc.w--;
|
||||
2:last_cycle();
|
||||
cpu_io();
|
||||
if(status.cpu_state == CPUSTATE_WAI) {
|
||||
regs.pc.w--;
|
||||
}
|
||||
}
|
||||
|
||||
xce(0xfb) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
bool c = regs.p.c;
|
||||
regs.p.c = regs.e;
|
||||
regs.e = c;
|
||||
|
@ -80,14 +90,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) {
|
||||
|
@ -102,7 +114,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);
|
||||
|
@ -115,27 +128,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);
|
||||
|
@ -147,7 +164,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);
|
||||
|
@ -160,7 +178,8 @@ tsx(0xba) {
|
|||
}
|
||||
|
||||
txs(0x9a) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
if(regs.e) {
|
||||
regs.s.l = regs.x.l;
|
||||
regs.p.n = !!(regs.s.l & 0x80);
|
||||
|
@ -179,14 +198,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),
|
||||
|
@ -195,13 +216,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);
|
||||
}
|
||||
|
@ -209,7 +232,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);
|
||||
}
|
||||
|
@ -217,7 +241,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;
|
||||
|
@ -229,7 +254,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) {
|
||||
|
@ -238,7 +264,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) {
|
||||
|
@ -247,5 +274,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);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
bra(0x80, 1),
|
||||
bcc(0x90, !regs.p.c),
|
||||
bcs(0xb0, regs.p.c),
|
||||
bne(0xd0, !regs.p.z),
|
||||
|
@ -7,7 +6,8 @@ bpl(0x10, !regs.p.n),
|
|||
bmi(0x30, regs.p.n),
|
||||
bvc(0x50, !regs.p.v),
|
||||
bvs(0x70, regs.p.v) {
|
||||
1:rd.l = op_read();
|
||||
1:if(!$1)last_cycle();
|
||||
rd.l = op_read();
|
||||
if($1) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
|
@ -15,26 +15,39 @@ bvs(0x70, regs.p.v) {
|
|||
end;
|
||||
}
|
||||
2:cpu_c6(aa.w);
|
||||
3:cpu_io();
|
||||
3:last_cycle();
|
||||
cpu_io();
|
||||
}
|
||||
|
||||
bra(0x80) {
|
||||
1:rd.l = op_read();
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
2:cpu_c6(aa.w);
|
||||
3:last_cycle();
|
||||
cpu_io();
|
||||
}
|
||||
|
||||
brl(0x82) {
|
||||
1:rd.l = op_read();
|
||||
2:rd.h = op_read();
|
||||
3:cpu_io();
|
||||
3:last_cycle();
|
||||
cpu_io();
|
||||
regs.pc.w = regs.pc.d + (int16)rd.w;
|
||||
}
|
||||
|
||||
jmp_addr(0x4c) {
|
||||
1:rd.l = op_read();
|
||||
2:rd.h = op_read();
|
||||
2:last_cycle();
|
||||
rd.h = op_read();
|
||||
regs.pc.w = rd.w;
|
||||
}
|
||||
|
||||
jmp_long(0x5c) {
|
||||
1:rd.l = op_read();
|
||||
2:rd.h = op_read();
|
||||
3:rd.b = op_read();
|
||||
3:last_cycle();
|
||||
rd.b = op_read();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
}
|
||||
|
||||
|
@ -42,7 +55,8 @@ jmp_iaddr(0x6c) {
|
|||
1:aa.l = op_read();
|
||||
2:aa.h = op_read();
|
||||
3:rd.l = op_read(OPMODE_ADDR, aa.w);
|
||||
4:rd.h = op_read(OPMODE_ADDR, aa.w + 1);
|
||||
4:last_cycle();
|
||||
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
}
|
||||
|
||||
|
@ -51,7 +65,8 @@ jmp_iaddrx(0x7c) {
|
|||
2:aa.h = op_read();
|
||||
3:cpu_io();
|
||||
4:rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
|
||||
5:rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
|
||||
5:last_cycle();
|
||||
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
}
|
||||
|
||||
|
@ -60,7 +75,8 @@ jmp_iladdr(0xdc) {
|
|||
2:aa.h = op_read();
|
||||
3:rd.l = op_read(OPMODE_ADDR, aa.w);
|
||||
4:rd.h = op_read(OPMODE_ADDR, aa.w + 1);
|
||||
5:rd.b = op_read(OPMODE_ADDR, aa.w + 2);
|
||||
5:last_cycle();
|
||||
rd.b = op_read(OPMODE_ADDR, aa.w + 2);
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
}
|
||||
|
||||
|
@ -70,7 +86,8 @@ jsr_addr(0x20) {
|
|||
3:cpu_io();
|
||||
4:regs.pc.w--;
|
||||
stack_write(regs.pc.h);
|
||||
5:stack_write(regs.pc.l);
|
||||
5:last_cycle();
|
||||
stack_write(regs.pc.l);
|
||||
regs.pc.w = aa.w;
|
||||
}
|
||||
|
||||
|
@ -82,7 +99,8 @@ jsr_long(0x22) {
|
|||
5:aa.b = op_read();
|
||||
6:regs.pc.w--;
|
||||
stack_write(regs.pc.h);
|
||||
7:stack_write(regs.pc.l);
|
||||
7:last_cycle();
|
||||
stack_write(regs.pc.l);
|
||||
regs.pc.d = aa.d & 0xffffff;
|
||||
}
|
||||
|
||||
|
@ -93,7 +111,8 @@ jsr_iaddrx(0xfc) {
|
|||
4:aa.h = op_read();
|
||||
5:cpu_io();
|
||||
6:rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
|
||||
7:rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
|
||||
7:last_cycle();
|
||||
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
}
|
||||
|
||||
|
@ -112,7 +131,8 @@ rti(0x40) {
|
|||
regs.pc.w = rd.w;
|
||||
end;
|
||||
}
|
||||
6:rd.b = stack_read();
|
||||
6:last_cycle();
|
||||
rd.b = stack_read();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
}
|
||||
|
||||
|
@ -121,7 +141,8 @@ rts(0x60) {
|
|||
2:cpu_io();
|
||||
3:rd.l = stack_read();
|
||||
4:rd.h = stack_read();
|
||||
5:cpu_io();
|
||||
5:last_cycle();
|
||||
cpu_io();
|
||||
regs.pc.w = rd.w;
|
||||
regs.pc.w++;
|
||||
}
|
||||
|
@ -131,7 +152,8 @@ rtl(0x6b) {
|
|||
2:cpu_io();
|
||||
3:rd.l = stack_read();
|
||||
4:rd.h = stack_read();
|
||||
5:rd.b = stack_read();
|
||||
5:last_cycle();
|
||||
rd.b = stack_read();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
regs.pc.w++;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -4,9 +4,11 @@ sty_addr(0x8c, regs.p.x, regs.y.w),
|
|||
stz_addr(0x9c, regs.p.m, 0x0000) {
|
||||
1:aa.l = op_read();
|
||||
2:aa.h = op_read();
|
||||
3:op_write(OPMODE_DBR, aa.w, $2);
|
||||
3:if($1)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, $2);
|
||||
if($1)end;
|
||||
4:op_write(OPMODE_DBR, aa.w + 1, $2 >> 8);
|
||||
4:last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, $2 >> 8);
|
||||
}
|
||||
|
||||
sta_addrx(0x9d, regs.p.m, regs.a.w),
|
||||
|
@ -14,36 +16,44 @@ stz_addrx(0x9e, regs.p.m, 0x0000) {
|
|||
1:aa.l = op_read();
|
||||
2:aa.h = op_read();
|
||||
3:cpu_c4(aa.w, aa.w + regs.x.w);
|
||||
4:op_write(OPMODE_DBR, aa.w + regs.x.w, $2);
|
||||
4:if($1)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, $2);
|
||||
if($1)end;
|
||||
5:op_write(OPMODE_DBR, aa.w + regs.x.w + 1, $2 >> 8);
|
||||
5:last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, $2 >> 8);
|
||||
}
|
||||
|
||||
sta_addry(0x99) {
|
||||
1:aa.l = op_read();
|
||||
2:aa.h = op_read();
|
||||
3:cpu_c4(aa.w, aa.w + regs.y.w);
|
||||
4:op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
4:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
5:op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
5:last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
}
|
||||
|
||||
sta_long(0x8f) {
|
||||
1:aa.l = op_read();
|
||||
2:aa.h = op_read();
|
||||
3:aa.b = op_read();
|
||||
4:op_write(OPMODE_LONG, aa.d, regs.a.l);
|
||||
4:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
5:op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
|
||||
5:last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
|
||||
}
|
||||
|
||||
sta_longx(0x9f) {
|
||||
1:aa.l = op_read();
|
||||
2:aa.h = op_read();
|
||||
3:aa.b = op_read();
|
||||
4:op_write(OPMODE_LONG, aa.d + regs.x.w, regs.a.l);
|
||||
4:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.x.w, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
5:op_write(OPMODE_LONG, aa.d + regs.x.w + 1, regs.a.h);
|
||||
5:last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.x.w + 1, regs.a.h);
|
||||
}
|
||||
|
||||
sta_dp(0x85, regs.p.m, regs.a.w),
|
||||
|
@ -52,9 +62,11 @@ sty_dp(0x84, regs.p.x, regs.y.w),
|
|||
stz_dp(0x64, regs.p.m, 0x0000) {
|
||||
1:dp = op_read();
|
||||
2:cpu_c2();
|
||||
3:op_write(OPMODE_DP, dp, $2);
|
||||
3:if($1)last_cycle();
|
||||
op_write(OPMODE_DP, dp, $2);
|
||||
if($1)end;
|
||||
4:op_write(OPMODE_DP, dp + 1, $2 >> 8);
|
||||
4:last_cycle();
|
||||
op_write(OPMODE_DP, dp + 1, $2 >> 8);
|
||||
}
|
||||
|
||||
sta_dpx(0x95, regs.p.m, regs.a.w),
|
||||
|
@ -63,18 +75,22 @@ stz_dpx(0x74, regs.p.m, 0x0000) {
|
|||
1:dp = op_read();
|
||||
2:cpu_c2();
|
||||
3:cpu_io();
|
||||
4:op_write(OPMODE_DP, dp + regs.x.w, $2);
|
||||
4:if($1)last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, $2);
|
||||
if($1)end;
|
||||
5:op_write(OPMODE_DP, dp + regs.x.w + 1, $2 >> 8);
|
||||
5:last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, $2 >> 8);
|
||||
}
|
||||
|
||||
stx_dpy(0x96) {
|
||||
1:dp = op_read();
|
||||
2:cpu_c2();
|
||||
3:cpu_io();
|
||||
4:op_write(OPMODE_DP, dp + regs.y.w, regs.x.l);
|
||||
4:if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.y.w, regs.x.l);
|
||||
if(regs.p.x)end;
|
||||
5:op_write(OPMODE_DP, dp + regs.y.w + 1, regs.x.h);
|
||||
5:last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.y.w + 1, regs.x.h);
|
||||
}
|
||||
|
||||
sta_idp(0x92) {
|
||||
|
@ -82,9 +98,11 @@ sta_idp(0x92) {
|
|||
2:cpu_c2();
|
||||
3:aa.l = op_read(OPMODE_DP, dp);
|
||||
4:aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
5:op_write(OPMODE_DBR, aa.w, regs.a.l);
|
||||
5:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
6:op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
|
||||
6:last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
|
||||
}
|
||||
|
||||
sta_ildp(0x87) {
|
||||
|
@ -93,9 +111,11 @@ sta_ildp(0x87) {
|
|||
3:aa.l = op_read(OPMODE_DP, dp);
|
||||
4:aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
5:aa.b = op_read(OPMODE_DP, dp + 2);
|
||||
6:op_write(OPMODE_LONG, aa.d, regs.a.l);
|
||||
6:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
7:op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
|
||||
7:last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
|
||||
}
|
||||
|
||||
sta_idpx(0x81) {
|
||||
|
@ -104,9 +124,11 @@ sta_idpx(0x81) {
|
|||
3:cpu_io();
|
||||
4:aa.l = op_read(OPMODE_DP, dp + regs.x.w);
|
||||
5:aa.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
|
||||
6:op_write(OPMODE_DBR, aa.w, regs.a.l);
|
||||
6:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
7:op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
|
||||
7:last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
|
||||
}
|
||||
|
||||
sta_idpy(0x91) {
|
||||
|
@ -115,9 +137,11 @@ sta_idpy(0x91) {
|
|||
3:aa.l = op_read(OPMODE_DP, dp);
|
||||
4:aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
5:cpu_c4(aa.w, aa.w + regs.y.w);
|
||||
6:op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
6:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
7:op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
7:last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
}
|
||||
|
||||
sta_ildpy(0x97) {
|
||||
|
@ -126,17 +150,21 @@ sta_ildpy(0x97) {
|
|||
3:aa.l = op_read(OPMODE_DP, dp);
|
||||
4:aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
5:aa.b = op_read(OPMODE_DP, dp + 2);
|
||||
6:op_write(OPMODE_LONG, aa.d + regs.y.w, regs.a.l);
|
||||
6:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
7:op_write(OPMODE_LONG, aa.d + regs.y.w + 1, regs.a.h);
|
||||
7:last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.y.w + 1, regs.a.h);
|
||||
}
|
||||
|
||||
sta_sr(0x83) {
|
||||
1:sp = op_read();
|
||||
2:cpu_io();
|
||||
3:op_write(OPMODE_SP, sp, regs.a.l);
|
||||
3:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_SP, sp, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
4:op_write(OPMODE_SP, sp + 1, regs.a.h);
|
||||
4:last_cycle();
|
||||
op_write(OPMODE_SP, sp + 1, regs.a.h);
|
||||
}
|
||||
|
||||
sta_isry(0x93) {
|
||||
|
@ -145,7 +173,9 @@ sta_isry(0x93) {
|
|||
3:aa.l = op_read(OPMODE_SP, sp);
|
||||
4:aa.h = op_read(OPMODE_SP, sp + 1);
|
||||
5:cpu_io();
|
||||
6:op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
6:if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)end;
|
||||
7:op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
7:last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
}
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
#include "dcpu.cpp"
|
||||
|
||||
CPU::CPU() {
|
||||
cpu_version = 2;
|
||||
mmio = &mmio_unmapped;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,12 @@
|
|||
|
||||
class CPU {
|
||||
public:
|
||||
//CPU version number
|
||||
//* 1 and 2 are known
|
||||
//* reported by $4210
|
||||
//* affects DRAM refresh behavior
|
||||
uint8 cpu_version;
|
||||
|
||||
//timing
|
||||
virtual uint16 vcounter() = 0;
|
||||
virtual uint16 hcounter() = 0;
|
||||
|
@ -9,7 +15,6 @@ public:
|
|||
virtual bool interlace() = 0;
|
||||
virtual bool interlace_field() = 0;
|
||||
virtual bool overscan() = 0;
|
||||
|
||||
virtual void set_interlace(bool r) = 0;
|
||||
virtual void set_overscan (bool r) = 0;
|
||||
|
||||
|
|
|
@ -0,0 +1,583 @@
|
|||
#include "../../base.h"
|
||||
#include "bdsp_tables.cpp"
|
||||
|
||||
uint8 bDSP::read_8 (uint16 addr) { return (spcram[addr]); }
|
||||
uint16 bDSP::read_16 (uint16 addr) { return (spcram[(addr + 1) & 0xffff] << 8) + (spcram[addr]); }
|
||||
void bDSP::write_8 (uint16 addr, uint8 data) { spcram[addr] = data; }
|
||||
void bDSP::write_16(uint16 addr, uint16 data) { spcram[addr++] = data; spcram[addr] = data >> 8; }
|
||||
|
||||
uint8 bDSP::read(uint8 addr) {
|
||||
int i, v, n;
|
||||
addr &= 127;
|
||||
v = addr >> 4;
|
||||
n = addr & 15;
|
||||
|
||||
switch(addr) {
|
||||
case 0x00:case 0x10:case 0x20:case 0x30:
|
||||
case 0x40:case 0x50:case 0x60:case 0x70:
|
||||
return voice[v].VOLL;
|
||||
case 0x01:case 0x11:case 0x21:case 0x31:
|
||||
case 0x41:case 0x51:case 0x61:case 0x71:
|
||||
return voice[v].VOLR;
|
||||
case 0x02:case 0x12:case 0x22:case 0x32:
|
||||
case 0x42:case 0x52:case 0x62:case 0x72:
|
||||
return voice[v].PITCH >> 8;
|
||||
case 0x03:case 0x13:case 0x23:case 0x33:
|
||||
case 0x43:case 0x53:case 0x63:case 0x73:
|
||||
return voice[v].PITCH;
|
||||
case 0x04:case 0x14:case 0x24:case 0x34:
|
||||
case 0x44:case 0x54:case 0x64:case 0x74:
|
||||
return voice[v].SRCN;
|
||||
case 0x05:case 0x15:case 0x25:case 0x35:
|
||||
case 0x45:case 0x55:case 0x65:case 0x75:
|
||||
return voice[v].ADSR1;
|
||||
case 0x06:case 0x16:case 0x26:case 0x36:
|
||||
case 0x46:case 0x56:case 0x66:case 0x76:
|
||||
return voice[v].ADSR2;
|
||||
case 0x07:case 0x17:case 0x27:case 0x37:
|
||||
case 0x47:case 0x57:case 0x67:case 0x77:
|
||||
return voice[v].GAIN;
|
||||
case 0x08:case 0x18:case 0x28:case 0x38:
|
||||
case 0x48:case 0x58:case 0x68:case 0x78:
|
||||
return voice[v].ENVX;
|
||||
case 0x09:case 0x19:case 0x29:case 0x39:
|
||||
case 0x49:case 0x59:case 0x69:case 0x79:
|
||||
return voice[v].OUTX;
|
||||
|
||||
case 0x0f:case 0x1f:case 0x2f:case 0x3f:
|
||||
case 0x4f:case 0x5f:case 0x6f:case 0x7f:
|
||||
return status.FIR[v];
|
||||
|
||||
case 0x0c:return status.MVOLL;
|
||||
case 0x1c:return status.MVOLR;
|
||||
case 0x2c:return status.EVOLL;
|
||||
case 0x3c:return status.EVOLR;
|
||||
case 0x4c:return status.KON;
|
||||
case 0x5c:return status.KOFF;
|
||||
case 0x6c:return status.FLG;
|
||||
case 0x7c:return status.ENDX;
|
||||
|
||||
case 0x0d:return status.EFB;
|
||||
case 0x2d:return status.PMON;
|
||||
case 0x3d:return status.NON;
|
||||
case 0x4d:return status.EON;
|
||||
case 0x5d:return status.DIR;
|
||||
case 0x6d:return status.ESA;
|
||||
case 0x7d:return status.EDL;
|
||||
}
|
||||
|
||||
return dspram[addr];
|
||||
}
|
||||
|
||||
void bDSP::write(uint8 addr, uint8 data) {
|
||||
int i, v, n;
|
||||
//0x80-0xff is a read-only mirror of 0x00-0x7f
|
||||
if(addr & 0x80)return;
|
||||
|
||||
v = addr >> 4;
|
||||
n = addr & 15;
|
||||
|
||||
switch(addr) {
|
||||
case 0x00:case 0x10:case 0x20:case 0x30:
|
||||
case 0x40:case 0x50:case 0x60:case 0x70:
|
||||
voice[v].VOLL = data;
|
||||
break;
|
||||
case 0x01:case 0x11:case 0x21:case 0x31:
|
||||
case 0x41:case 0x51:case 0x61:case 0x71:
|
||||
voice[v].VOLR = data;
|
||||
break;
|
||||
case 0x02:case 0x12:case 0x22:case 0x32:
|
||||
case 0x42:case 0x52:case 0x62:case 0x72:
|
||||
voice[v].PITCH &= 0xff00;
|
||||
voice[v].PITCH |= data;
|
||||
break;
|
||||
case 0x03:case 0x13:case 0x23:case 0x33:
|
||||
case 0x43:case 0x53:case 0x63:case 0x73:
|
||||
voice[v].PITCH &= 0x00ff;
|
||||
voice[v].PITCH |= data << 8;
|
||||
break;
|
||||
case 0x04:case 0x14:case 0x24:case 0x34:
|
||||
case 0x44:case 0x54:case 0x64:case 0x74:
|
||||
//voice[v].SRCN = data;
|
||||
//below is anomie's code, but TRAC says writing SRCN doesn't affect anything until a
|
||||
//BRR-with-end block is encountered, where it loads the loop address from the new SRCN
|
||||
if(voice[v].SRCN != data) {
|
||||
voice[v].SRCN = data;
|
||||
voice[v].brr_ptr = read_16((status.DIR << 8) + (voice[v].SRCN << 2) + ((voice[v].brr_looped)?2:0));
|
||||
voice[v].brr_index = 0;
|
||||
}
|
||||
break;
|
||||
case 0x05:case 0x15:case 0x25:case 0x35:
|
||||
case 0x45:case 0x55:case 0x65:case 0x75:
|
||||
voice[v].ADSR1 = data;
|
||||
voice[v].AdjustEnvelope();
|
||||
break;
|
||||
case 0x06:case 0x16:case 0x26:case 0x36:
|
||||
case 0x46:case 0x56:case 0x66:case 0x76:
|
||||
voice[v].ADSR2 = data;
|
||||
//sustain_level = 0-7, 7 is a special case handled by ATTACK envx mode
|
||||
voice[v].env_sustain = (voice[v].ADSR_sus_level() + 1) << 8;
|
||||
voice[v].AdjustEnvelope();
|
||||
break;
|
||||
case 0x07:case 0x17:case 0x27:case 0x37:
|
||||
case 0x47:case 0x57:case 0x67:case 0x77:
|
||||
voice[v].GAIN = data;
|
||||
voice[v].AdjustEnvelope();
|
||||
break;
|
||||
case 0x08:case 0x18:case 0x28:case 0x38:
|
||||
case 0x48:case 0x58:case 0x68:case 0x78:
|
||||
voice[v].ENVX = data;
|
||||
break;
|
||||
case 0x09:case 0x19:case 0x29:case 0x39:
|
||||
case 0x49:case 0x59:case 0x69:case 0x79:
|
||||
voice[v].OUTX = data;
|
||||
break;
|
||||
|
||||
case 0x0f:case 0x1f:case 0x2f:case 0x3f:
|
||||
case 0x4f:case 0x5f:case 0x6f:case 0x7f:
|
||||
status.FIR[v] = data;
|
||||
break;
|
||||
|
||||
case 0x0c:status.MVOLL = data;break;
|
||||
case 0x1c:status.MVOLR = data;break;
|
||||
case 0x2c:status.EVOLL = data;break;
|
||||
case 0x3c:status.EVOLR = data;break;
|
||||
|
||||
case 0x4c:
|
||||
status.KON = data;
|
||||
status.kon = data;
|
||||
status.key_flag = true;
|
||||
break;
|
||||
|
||||
case 0x5c:
|
||||
status.KOFF = data;
|
||||
status.key_flag = true;
|
||||
break;
|
||||
|
||||
case 0x6c:
|
||||
status.FLG = data;
|
||||
status.key_flag = true;
|
||||
status.noise_rate = RateTable[data & 0x1f];
|
||||
break;
|
||||
|
||||
case 0x7c:
|
||||
//read-only register, writes clear all bits of ENDX
|
||||
status.ENDX = 0;
|
||||
break;
|
||||
|
||||
case 0x0d:status.EFB = data;break;
|
||||
case 0x2d:status.PMON = data;break;
|
||||
case 0x3d:status.NON = data;break;
|
||||
case 0x4d:status.EON = data;break;
|
||||
case 0x5d:status.DIR = data;break;
|
||||
case 0x6d:status.ESA = data;break;
|
||||
|
||||
case 0x7d:
|
||||
status.EDL = data;
|
||||
status.echo_size = (data & 0x0f) << 11;
|
||||
break;
|
||||
}
|
||||
|
||||
dspram[addr] = data;
|
||||
}
|
||||
|
||||
void bDSP::power() {
|
||||
int v;
|
||||
spcram = apu->get_spcram_handle();
|
||||
memset(dspram, 0x00, 128);
|
||||
|
||||
for(v=0;v<8;v++) {
|
||||
voice[v].VOLL = 0;
|
||||
voice[v].VOLR = 0;
|
||||
voice[v].PITCH = 0;
|
||||
voice[v].SRCN = 0;
|
||||
voice[v].ADSR1 = 0;
|
||||
voice[v].ADSR2 = 0;
|
||||
voice[v].GAIN = 0;
|
||||
|
||||
status.FIR[v] = 0;
|
||||
}
|
||||
|
||||
status.MVOLL = status.MVOLR = 0;
|
||||
status.EVOLL = status.EVOLR = 0;
|
||||
status.ENDX = 0;
|
||||
status.EFB = 0;
|
||||
status.PMON = 0;
|
||||
status.NON = 0;
|
||||
status.EON = 0;
|
||||
status.DIR = 0;
|
||||
status.ESA = 0;
|
||||
status.EDL = 0;
|
||||
|
||||
status.echo_size = 0;
|
||||
status.echo_target = 0;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void bDSP::reset() {
|
||||
int v;
|
||||
status.KON = 0x00;
|
||||
status.KOFF = 0x00;
|
||||
status.FLG |= 0xe0;
|
||||
|
||||
status.kon = 0x00;
|
||||
status.key_flag = false;
|
||||
|
||||
status.noise_ctr = 0;
|
||||
status.noise_rate = 0;
|
||||
status.noise_sample = 0x4000;
|
||||
|
||||
status.echo_index = 0;
|
||||
status.fir_buffer_index = 0;
|
||||
|
||||
for(v=0;v<8;v++) {
|
||||
voice[v].ENVX = 0;
|
||||
voice[v].OUTX = 0;
|
||||
|
||||
voice[v].pitch_ctr = 0;
|
||||
|
||||
voice[v].brr_index = 0;
|
||||
voice[v].brr_ptr = read_16((status.DIR << 8) + (voice[v].SRCN << 2));
|
||||
voice[v].brr_looped = false;
|
||||
voice[v].brr_data[0] = 0;
|
||||
voice[v].brr_data[1] = 0;
|
||||
voice[v].brr_data[2] = 0;
|
||||
voice[v].brr_data[3] = 0;
|
||||
voice[v].brr_data_index = 0;
|
||||
|
||||
voice[v].envx = 0;
|
||||
voice[v].env_ctr = 0;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_state = SILENCE;
|
||||
voice[v].env_mode = DIRECT;
|
||||
|
||||
status.fir_buffer[0][v] = 0;
|
||||
status.fir_buffer[1][v] = 0;
|
||||
}
|
||||
|
||||
dsp_counter = 0;
|
||||
}
|
||||
|
||||
int32 bDSP::clamp(int32 bits, int32 x) {
|
||||
int32 b = 1 << (bits - 1);
|
||||
if(x > (b - 1)) {
|
||||
return (b - 1);
|
||||
} else if(x < -b) {
|
||||
return -b;
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int32 bDSP::clip(int32 bits, int32 x) {
|
||||
int32 b = 1 << (bits - 1);
|
||||
if(x & b) {
|
||||
return x | ~(b - 1);
|
||||
} else {
|
||||
return x & (b - 1);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 bDSP::run() {
|
||||
int v, d;
|
||||
uint8 pmon;
|
||||
int32 sample;
|
||||
int32 msamplel, msampler;
|
||||
int32 esamplel, esampler;
|
||||
int32 fir_samplel, fir_sampler;
|
||||
pmon = status.PMON & ~status.NON & ~1;
|
||||
|
||||
if(!(dsp_counter++ & 1) && status.key_flag) {
|
||||
for(v=0;v<8;v++) {
|
||||
if(status.soft_reset()) {
|
||||
if(voice[v].env_state != SILENCE) {
|
||||
voice[v].env_state = SILENCE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
} else if(status.KOFF & (1 << v)) {
|
||||
if(voice[v].env_state != SILENCE && voice[v].env_state != RELEASE) {
|
||||
voice[v].env_state = RELEASE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
} else if(status.kon & (1 << v)) {
|
||||
voice[v].brr_ptr = read_16((status.DIR << 8) + (voice[v].SRCN << 2));
|
||||
voice[v].brr_index = -9;
|
||||
voice[v].brr_looped = false;
|
||||
voice[v].brr_data[0] = 0;
|
||||
voice[v].brr_data[1] = 0;
|
||||
voice[v].brr_data[2] = 0;
|
||||
voice[v].brr_data[3] = 0;
|
||||
voice[v].envx = 0;
|
||||
voice[v].env_state = ATTACK;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
}
|
||||
status.ENDX &= ~status.kon;
|
||||
status.kon = 0;
|
||||
status.key_flag = false;
|
||||
}
|
||||
|
||||
//update noise
|
||||
status.noise_ctr += status.noise_rate;
|
||||
if(status.noise_ctr >= 0x7800) {
|
||||
status.noise_ctr -= 0x7800;
|
||||
status.noise_sample = (status.noise_sample >> 1) |
|
||||
(((status.noise_sample << 14) ^ (status.noise_sample << 13)) & 0x4000);
|
||||
}
|
||||
|
||||
msamplel = msampler = 0;
|
||||
esamplel = esampler = 0;
|
||||
|
||||
for(v=0;v<8;v++) {
|
||||
if(voice[v].brr_index < -1) {
|
||||
voice[v].brr_index++;
|
||||
voice[v].OUTX = voice[v].outx = 0;
|
||||
voice[v].ENVX = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(voice[v].brr_index >= 0) {
|
||||
if(pmon & (1 << v)) {
|
||||
voice[v].pitch_ctr += (voice[v].pitch_rate() * (voice[v - 1].outx + 0x8000)) >> 15;
|
||||
} else {
|
||||
voice[v].pitch_ctr += voice[v].pitch_rate();
|
||||
}
|
||||
} else {
|
||||
voice[v].pitch_ctr = 0x3000;
|
||||
voice[v].brr_index = 0;
|
||||
}
|
||||
|
||||
//decode BRR samples
|
||||
while(voice[v].pitch_ctr >= 0) {
|
||||
voice[v].pitch_ctr -= 0x1000;
|
||||
|
||||
voice[v].brr_data_index++;
|
||||
voice[v].brr_data_index &= 3;
|
||||
|
||||
if(voice[v].brr_index == 0) {
|
||||
voice[v].brr_header = read_8(voice[v].brr_ptr);
|
||||
|
||||
if(voice[v].brr_header_flags() & BRR_END) {
|
||||
status.ENDX |= (1 << v);
|
||||
}
|
||||
|
||||
if(voice[v].brr_header_flags() == BRR_END) {
|
||||
voice[v].env_state = SILENCE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
}
|
||||
|
||||
#define S(x) voice[v].brr_data[(voice[v].brr_data_index + (x)) & 3]
|
||||
if(voice[v].env_state != SILENCE) {
|
||||
sample = read_8(voice[v].brr_ptr + 1 + (voice[v].brr_index >> 1));
|
||||
if(voice[v].brr_index & 1) {
|
||||
sample = clip(4, sample);
|
||||
} else {
|
||||
sample = clip(4, sample >> 4);
|
||||
}
|
||||
|
||||
if(voice[v].brr_header_shift() <= 12) {
|
||||
sample = (sample << voice[v].brr_header_shift() >> 1);
|
||||
} else {
|
||||
sample &= ~0x7ff;
|
||||
}
|
||||
|
||||
switch(voice[v].brr_header_filter()) {
|
||||
case 0: //direct
|
||||
break;
|
||||
case 1: //15/16
|
||||
sample += S(-1) + ((-S(-1)) >> 4);
|
||||
break;
|
||||
case 2: //61/32 - 15/16
|
||||
sample += (S(-1) << 1) + ((-((S(-1) << 1) + S(-1))) >> 5)
|
||||
- S(-2) + (S(-2) >> 4);
|
||||
break;
|
||||
case 3: //115/64 - 13/16
|
||||
sample += (S(-1) << 1) + ((-(S(-1) + (S(-1) << 2) + (S(-1) << 3))) >> 6)
|
||||
- S(-2) + (((S(-2) << 1) + S(-2)) >> 4);
|
||||
break;
|
||||
}
|
||||
|
||||
S(0) = sample = clip(15, clamp(16, sample));
|
||||
} else {
|
||||
S(0) = sample = 0;
|
||||
}
|
||||
|
||||
if(++voice[v].brr_index > 15) {
|
||||
voice[v].brr_index = 0;
|
||||
if(voice[v].brr_header_flags() & BRR_END) {
|
||||
voice[v].brr_ptr = read_16((status.DIR << 8) + (voice[v].SRCN << 2) + 2);
|
||||
voice[v].brr_looped = true;
|
||||
} else {
|
||||
voice[v].brr_ptr += 9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//volume envelope adjust
|
||||
voice[v].env_ctr += voice[v].env_rate;
|
||||
|
||||
if(voice[v].env_ctr >= 0x7800) {
|
||||
voice[v].env_ctr -= 0x7800;
|
||||
switch(voice[v].env_mode) {
|
||||
case DIRECT:
|
||||
voice[v].env_rate = 0;
|
||||
break;
|
||||
case LINEAR_DEC:
|
||||
voice[v].envx -= 32;
|
||||
if(voice[v].envx <= 0) {
|
||||
voice[v].envx = 0;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_mode = DIRECT;
|
||||
}
|
||||
break;
|
||||
case LINEAR_INC:
|
||||
voice[v].envx += 32;
|
||||
if(voice[v].envx >= 0x7ff) {
|
||||
voice[v].envx = 0x7ff;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_mode = DIRECT;
|
||||
if(voice[v].ADSR_enabled() && voice[v].env_state == ATTACK) {
|
||||
voice[v].env_state = ((voice[v].env_sustain == 0x800) ? SUSTAIN : DECAY);
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EXP_DEC:
|
||||
//multiply by 255/256ths
|
||||
voice[v].envx -= ((voice[v].envx - 1) >> 8) + 1;
|
||||
if(voice[v].ADSR_enabled() && voice[v].env_state == DECAY && voice[v].envx <= voice[v].env_sustain) {
|
||||
voice[v].env_state = SUSTAIN;
|
||||
voice[v].AdjustEnvelope();
|
||||
} else if(voice[v].envx <= 0) {
|
||||
voice[v].envx = 0;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_mode = DIRECT;
|
||||
}
|
||||
break;
|
||||
case BENT_INC:
|
||||
if(voice[v].envx < 0x600) {
|
||||
voice[v].envx += 32;
|
||||
} else {
|
||||
voice[v].envx += 8;
|
||||
|
||||
if(voice[v].envx >= 0x7ff) {
|
||||
voice[v].envx = 0x7ff;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_mode = DIRECT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FAST_ATTACK:
|
||||
voice[v].envx += 0x400;
|
||||
if(voice[v].envx >= 0x7ff) {
|
||||
voice[v].envx = 0x7ff;
|
||||
|
||||
//attack raises to max. envx, if sustain is also set to max. envx, skip decay phase
|
||||
voice[v].env_state = ((voice[v].env_sustain == 0x800) ? SUSTAIN : DECAY);
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
break;
|
||||
case RELEASE_DEC:
|
||||
voice[v].envx -= 8;
|
||||
if(voice[v].envx <= 0) {
|
||||
voice[v].env_state = SILENCE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
voice[v].ENVX = voice[v].envx >> 4;
|
||||
|
||||
//gaussian interpolation / noise
|
||||
if(status.NON & (1 << v)) {
|
||||
sample = status.noise_sample;
|
||||
} else {
|
||||
d = voice[v].pitch_ctr >> 4; //-256 <= sample <= -1
|
||||
sample = ((GaussTable[ -1-d] * S(-3)) >> 11);
|
||||
sample += ((GaussTable[255-d] * S(-2)) >> 11);
|
||||
sample += ((GaussTable[512+d] * S(-1)) >> 11);
|
||||
sample = clip (15, sample);
|
||||
sample += ((GaussTable[256+d] * S( 0)) >> 11);
|
||||
sample = clamp(15, sample);
|
||||
}
|
||||
#undef S
|
||||
|
||||
//envelope / volume adjust
|
||||
sample = (sample * voice[v].envx) >> 11;
|
||||
voice[v].outx = sample << 1;
|
||||
voice[v].OUTX = sample >> 7;
|
||||
|
||||
if(!status.mute()) {
|
||||
msamplel += ((sample * voice[v].VOLL) >> 7) << 1;
|
||||
msampler += ((sample * voice[v].VOLR) >> 7) << 1;
|
||||
}
|
||||
|
||||
if((status.EON & (1 << v)) && status.echo_write()) {
|
||||
esamplel += ((sample * voice[v].VOLL) >> 7) << 1;
|
||||
esampler += ((sample * voice[v].VOLR) >> 7) << 1;
|
||||
}
|
||||
}
|
||||
|
||||
//echo (FIR) adjust
|
||||
#define F(c,x) status.fir_buffer[c][(status.fir_buffer_index+(x)) & 7]
|
||||
status.fir_buffer_index++;
|
||||
F(0,0) = read_16((status.ESA << 8) + status.echo_index);
|
||||
F(1,0) = read_16((status.ESA << 8) + status.echo_index + 2);
|
||||
|
||||
fir_samplel = (F(0,-0) * status.FIR[7] +
|
||||
F(0,-1) * status.FIR[6] +
|
||||
F(0,-2) * status.FIR[5] +
|
||||
F(0,-3) * status.FIR[4] +
|
||||
F(0,-4) * status.FIR[3] +
|
||||
F(0,-5) * status.FIR[2] +
|
||||
F(0,-6) * status.FIR[1] +
|
||||
F(0,-7) * status.FIR[0]);
|
||||
|
||||
fir_sampler = (F(1,-0) * status.FIR[7] +
|
||||
F(1,-1) * status.FIR[6] +
|
||||
F(1,-2) * status.FIR[5] +
|
||||
F(1,-3) * status.FIR[4] +
|
||||
F(1,-4) * status.FIR[3] +
|
||||
F(1,-5) * status.FIR[2] +
|
||||
F(1,-6) * status.FIR[1] +
|
||||
F(1,-7) * status.FIR[0]);
|
||||
#undef F
|
||||
|
||||
//update echo buffer
|
||||
if(status.echo_write()) {
|
||||
esamplel += (fir_samplel * status.EFB) >> 14;
|
||||
esampler += (fir_sampler * status.EFB) >> 14;
|
||||
|
||||
esamplel = clamp(16, esamplel);
|
||||
esampler = clamp(16, esampler);
|
||||
|
||||
write_16((status.ESA << 8) + status.echo_index, esamplel);
|
||||
write_16((status.ESA << 8) + status.echo_index + 2, esampler);
|
||||
}
|
||||
|
||||
status.echo_index += 4;
|
||||
if(status.echo_index >= status.echo_target) {
|
||||
status.echo_index = 0;
|
||||
status.echo_target = status.echo_size;
|
||||
}
|
||||
|
||||
//main output adjust
|
||||
if(!status.mute()) {
|
||||
msamplel = (msamplel * status.MVOLL) >> 7;
|
||||
msampler = (msampler * status.MVOLR) >> 7;
|
||||
|
||||
msamplel += (fir_samplel * status.EVOLL) >> 14;
|
||||
msampler += (fir_sampler * status.EVOLR) >> 14;
|
||||
|
||||
msamplel = clamp(16, msamplel);
|
||||
msampler = clamp(16, msampler);
|
||||
}
|
||||
|
||||
return (uint32)(((uint16)msamplel) | ((uint16)msampler << 16));
|
||||
}
|
||||
|
||||
bDSP::bDSP() {}
|
||||
bDSP::~bDSP() {}
|
|
@ -0,0 +1,176 @@
|
|||
class bDSP : public DSP {
|
||||
private:
|
||||
uint8 dspram[128];
|
||||
uint8 *spcram;
|
||||
|
||||
uint32 dsp_counter;
|
||||
|
||||
enum {
|
||||
BRR_END = 1,
|
||||
BRR_LOOP = 2
|
||||
};
|
||||
|
||||
uint8 read_8 (uint16 addr);
|
||||
uint16 read_16 (uint16 addr);
|
||||
void write_8 (uint16 addr, uint8 data);
|
||||
void write_16(uint16 addr, uint16 data);
|
||||
|
||||
public:
|
||||
static const uint16 RateTable[32];
|
||||
static const int16 GaussTable[512];
|
||||
|
||||
enum EnvelopeStates {
|
||||
ATTACK,
|
||||
DECAY,
|
||||
SUSTAIN,
|
||||
RELEASE,
|
||||
SILENCE
|
||||
};
|
||||
|
||||
enum EnvelopeModes {
|
||||
DIRECT,
|
||||
LINEAR_DEC,
|
||||
EXP_DEC,
|
||||
LINEAR_INC,
|
||||
BENT_INC,
|
||||
|
||||
FAST_ATTACK,
|
||||
RELEASE_DEC
|
||||
};
|
||||
|
||||
private:
|
||||
struct Status {
|
||||
//$0c,$1c
|
||||
int8 MVOLL, MVOLR;
|
||||
//$2c,$3c
|
||||
int8 EVOLL, EVOLR;
|
||||
//$4c,$5c
|
||||
uint8 KON, KOFF;
|
||||
//$6c
|
||||
uint8 FLG;
|
||||
//$7c
|
||||
uint8 ENDX;
|
||||
//$0d
|
||||
int8 EFB;
|
||||
//$2d,$3d,$4d
|
||||
uint8 PMON, NON, EON;
|
||||
//$5d
|
||||
uint8 DIR;
|
||||
//$6d,$7d
|
||||
uint8 ESA, EDL;
|
||||
|
||||
//$xf
|
||||
int8 FIR[8];
|
||||
|
||||
//internal variables
|
||||
uint8 kon;
|
||||
bool key_flag;
|
||||
|
||||
int16 noise_ctr, noise_rate;
|
||||
uint16 noise_sample;
|
||||
|
||||
uint16 echo_index, echo_size, echo_target;
|
||||
int16 fir_buffer[2][8];
|
||||
uint8 fir_buffer_index;
|
||||
|
||||
//functions
|
||||
bool soft_reset() { return !!(FLG & 0x80); }
|
||||
bool mute() { return !!(FLG & 0x40); }
|
||||
bool echo_write() { return !(FLG & 0x20); }
|
||||
} status;
|
||||
|
||||
struct Voice {
|
||||
//$x0-$x1
|
||||
int8 VOLL, VOLR;
|
||||
//$x2-$x3
|
||||
int16 PITCH;
|
||||
//$x4
|
||||
uint8 SRCN;
|
||||
//$x5-$x7
|
||||
uint8 ADSR1, ADSR2, GAIN;
|
||||
//$x8-$x9
|
||||
uint8 ENVX, OUTX;
|
||||
|
||||
//internal variables
|
||||
int16 pitch_ctr;
|
||||
|
||||
int8 brr_index;
|
||||
uint16 brr_ptr;
|
||||
uint8 brr_header;
|
||||
bool brr_looped;
|
||||
|
||||
int16 brr_data[4];
|
||||
uint8 brr_data_index;
|
||||
|
||||
int16 envx;
|
||||
uint16 env_ctr, env_rate, env_sustain;
|
||||
enum EnvelopeStates env_state;
|
||||
enum EnvelopeModes env_mode;
|
||||
|
||||
int16 outx;
|
||||
|
||||
//functions
|
||||
int16 pitch_rate() { return PITCH & 0x3fff; }
|
||||
|
||||
uint8 brr_header_shift() { return brr_header >> 4; }
|
||||
uint8 brr_header_filter() { return (brr_header >> 2) & 3; }
|
||||
uint8 brr_header_flags() { return brr_header & 3; }
|
||||
|
||||
bool ADSR_enabled() { return !!(ADSR1 & 0x80); }
|
||||
uint8 ADSR_decay() { return (ADSR1 >> 4) & 7; }
|
||||
uint8 ADSR_attack() { return ADSR1 & 15; }
|
||||
uint8 ADSR_sus_level() { return ADSR2 >> 5; }
|
||||
uint8 ADSR_sus_rate() { return ADSR2 & 31; }
|
||||
|
||||
void AdjustEnvelope() {
|
||||
if(env_state == SILENCE) {
|
||||
env_mode = DIRECT;
|
||||
env_rate = 0;
|
||||
envx = 0;
|
||||
} else if(env_state == RELEASE) {
|
||||
env_mode = RELEASE_DEC;
|
||||
env_rate = 0x7800;
|
||||
} else if(ADSR_enabled()) {
|
||||
switch(env_state) {
|
||||
case ATTACK:
|
||||
env_rate = RateTable[(ADSR_attack() << 1) + 1];
|
||||
env_mode = (env_rate == 0x7800) ? FAST_ATTACK : LINEAR_INC;
|
||||
break;
|
||||
case DECAY:
|
||||
env_rate = RateTable[(ADSR_decay() << 1) + 0x10];
|
||||
env_mode = EXP_DEC;
|
||||
break;
|
||||
case SUSTAIN:
|
||||
env_rate = RateTable[ADSR_sus_rate()];
|
||||
env_mode = (env_rate == 0) ? DIRECT : EXP_DEC;
|
||||
break;
|
||||
}
|
||||
} else if(GAIN & 0x80) {
|
||||
switch(GAIN & 0x60) {
|
||||
case 0x00:env_mode = LINEAR_DEC; break;
|
||||
case 0x20:env_mode = EXP_DEC; break;
|
||||
case 0x40:env_mode = LINEAR_INC; break;
|
||||
case 0x60:env_mode = BENT_INC; break;
|
||||
}
|
||||
env_rate = RateTable[GAIN & 0x1f];
|
||||
} else {
|
||||
env_mode = DIRECT;
|
||||
env_rate = 0;
|
||||
envx = (GAIN & 0x7f) << 4;
|
||||
}
|
||||
}
|
||||
} voice[8];
|
||||
|
||||
int32 clamp(int32 bits, int32 x);
|
||||
int32 clip (int32 bits, int32 x);
|
||||
public:
|
||||
uint8 read (uint8 addr);
|
||||
void write(uint8 addr, uint8 data);
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
uint32 run();
|
||||
|
||||
bDSP();
|
||||
~bDSP();
|
||||
};
|
|
@ -0,0 +1,73 @@
|
|||
const uint16 bDSP::RateTable[32] = {
|
||||
0x0000, 0x000F, 0x0014, 0x0018, 0x001E, 0x0028, 0x0030, 0x003C,
|
||||
0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180,
|
||||
0x01E0, 0x0280, 0x0300, 0x03C0, 0x0500, 0x0600, 0x0780, 0x0A00,
|
||||
0x0C00, 0x0F00, 0x1400, 0x1800, 0x1E00, 0x2800, 0x3C00, 0x7800
|
||||
};
|
||||
|
||||
const int16 bDSP::GaussTable[512] = {
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001,
|
||||
0x001, 0x001, 0x001, 0x002, 0x002, 0x002, 0x002, 0x002,
|
||||
0x002, 0x002, 0x003, 0x003, 0x003, 0x003, 0x003, 0x004,
|
||||
0x004, 0x004, 0x004, 0x004, 0x005, 0x005, 0x005, 0x005,
|
||||
0x006, 0x006, 0x006, 0x006, 0x007, 0x007, 0x007, 0x008,
|
||||
0x008, 0x008, 0x009, 0x009, 0x009, 0x00A, 0x00A, 0x00A,
|
||||
0x00B, 0x00B, 0x00B, 0x00C, 0x00C, 0x00D, 0x00D, 0x00E,
|
||||
0x00E, 0x00F, 0x00F, 0x00F, 0x010, 0x010, 0x011, 0x011,
|
||||
0x012, 0x013, 0x013, 0x014, 0x014, 0x015, 0x015, 0x016,
|
||||
0x017, 0x017, 0x018, 0x018, 0x019, 0x01A, 0x01B, 0x01B,
|
||||
0x01C, 0x01D, 0x01D, 0x01E, 0x01F, 0x020, 0x020, 0x021,
|
||||
0x022, 0x023, 0x024, 0x024, 0x025, 0x026, 0x027, 0x028,
|
||||
0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F, 0x030,
|
||||
0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038,
|
||||
0x03A, 0x03B, 0x03C, 0x03D, 0x03E, 0x040, 0x041, 0x042,
|
||||
0x043, 0x045, 0x046, 0x047, 0x049, 0x04A, 0x04C, 0x04D,
|
||||
0x04E, 0x050, 0x051, 0x053, 0x054, 0x056, 0x057, 0x059,
|
||||
0x05A, 0x05C, 0x05E, 0x05F, 0x061, 0x063, 0x064, 0x066,
|
||||
0x068, 0x06A, 0x06B, 0x06D, 0x06F, 0x071, 0x073, 0x075,
|
||||
0x076, 0x078, 0x07A, 0x07C, 0x07E, 0x080, 0x082, 0x084,
|
||||
0x086, 0x089, 0x08B, 0x08D, 0x08F, 0x091, 0x093, 0x096,
|
||||
0x098, 0x09A, 0x09C, 0x09F, 0x0A1, 0x0A3, 0x0A6, 0x0A8,
|
||||
0x0AB, 0x0AD, 0x0AF, 0x0B2, 0x0B4, 0x0B7, 0x0BA, 0x0BC,
|
||||
0x0BF, 0x0C1, 0x0C4, 0x0C7, 0x0C9, 0x0CC, 0x0CF, 0x0D2,
|
||||
0x0D4, 0x0D7, 0x0DA, 0x0DD, 0x0E0, 0x0E3, 0x0E6, 0x0E9,
|
||||
0x0EC, 0x0EF, 0x0F2, 0x0F5, 0x0F8, 0x0FB, 0x0FE, 0x101,
|
||||
0x104, 0x107, 0x10B, 0x10E, 0x111, 0x114, 0x118, 0x11B,
|
||||
0x11E, 0x122, 0x125, 0x129, 0x12C, 0x130, 0x133, 0x137,
|
||||
0x13A, 0x13E, 0x141, 0x145, 0x148, 0x14C, 0x150, 0x153,
|
||||
0x157, 0x15B, 0x15F, 0x162, 0x166, 0x16A, 0x16E, 0x172,
|
||||
0x176, 0x17A, 0x17D, 0x181, 0x185, 0x189, 0x18D, 0x191,
|
||||
0x195, 0x19A, 0x19E, 0x1A2, 0x1A6, 0x1AA, 0x1AE, 0x1B2,
|
||||
0x1B7, 0x1BB, 0x1BF, 0x1C3, 0x1C8, 0x1CC, 0x1D0, 0x1D5,
|
||||
0x1D9, 0x1DD, 0x1E2, 0x1E6, 0x1EB, 0x1EF, 0x1F3, 0x1F8,
|
||||
0x1FC, 0x201, 0x205, 0x20A, 0x20F, 0x213, 0x218, 0x21C,
|
||||
0x221, 0x226, 0x22A, 0x22F, 0x233, 0x238, 0x23D, 0x241,
|
||||
0x246, 0x24B, 0x250, 0x254, 0x259, 0x25E, 0x263, 0x267,
|
||||
0x26C, 0x271, 0x276, 0x27B, 0x280, 0x284, 0x289, 0x28E,
|
||||
0x293, 0x298, 0x29D, 0x2A2, 0x2A6, 0x2AB, 0x2B0, 0x2B5,
|
||||
0x2BA, 0x2BF, 0x2C4, 0x2C9, 0x2CE, 0x2D3, 0x2D8, 0x2DC,
|
||||
0x2E1, 0x2E6, 0x2EB, 0x2F0, 0x2F5, 0x2FA, 0x2FF, 0x304,
|
||||
0x309, 0x30E, 0x313, 0x318, 0x31D, 0x322, 0x326, 0x32B,
|
||||
0x330, 0x335, 0x33A, 0x33F, 0x344, 0x349, 0x34E, 0x353,
|
||||
0x357, 0x35C, 0x361, 0x366, 0x36B, 0x370, 0x374, 0x379,
|
||||
0x37E, 0x383, 0x388, 0x38C, 0x391, 0x396, 0x39B, 0x39F,
|
||||
0x3A4, 0x3A9, 0x3AD, 0x3B2, 0x3B7, 0x3BB, 0x3C0, 0x3C5,
|
||||
0x3C9, 0x3CE, 0x3D2, 0x3D7, 0x3DC, 0x3E0, 0x3E5, 0x3E9,
|
||||
0x3ED, 0x3F2, 0x3F6, 0x3FB, 0x3FF, 0x403, 0x408, 0x40C,
|
||||
0x410, 0x415, 0x419, 0x41D, 0x421, 0x425, 0x42A, 0x42E,
|
||||
0x432, 0x436, 0x43A, 0x43E, 0x442, 0x446, 0x44A, 0x44E,
|
||||
0x452, 0x455, 0x459, 0x45D, 0x461, 0x465, 0x468, 0x46C,
|
||||
0x470, 0x473, 0x477, 0x47A, 0x47E, 0x481, 0x485, 0x488,
|
||||
0x48C, 0x48F, 0x492, 0x496, 0x499, 0x49C, 0x49F, 0x4A2,
|
||||
0x4A6, 0x4A9, 0x4AC, 0x4AF, 0x4B2, 0x4B5, 0x4B7, 0x4BA,
|
||||
0x4BD, 0x4C0, 0x4C3, 0x4C5, 0x4C8, 0x4CB, 0x4CD, 0x4D0,
|
||||
0x4D2, 0x4D5, 0x4D7, 0x4D9, 0x4DC, 0x4DE, 0x4E0, 0x4E3,
|
||||
0x4E5, 0x4E7, 0x4E9, 0x4EB, 0x4ED, 0x4EF, 0x4F1, 0x4F3,
|
||||
0x4F5, 0x4F6, 0x4F8, 0x4FA, 0x4FB, 0x4FD, 0x4FF, 0x500,
|
||||
0x502, 0x503, 0x504, 0x506, 0x507, 0x508, 0x50A, 0x50B,
|
||||
0x50C, 0x50D, 0x50E, 0x50F, 0x510, 0x511, 0x511, 0x512,
|
||||
0x513, 0x514, 0x514, 0x515, 0x516, 0x516, 0x517, 0x517,
|
||||
0x517, 0x518, 0x518, 0x518, 0x518, 0x518, 0x519, 0x519
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
class DSP {
|
||||
public:
|
||||
virtual uint8 read (uint8 addr) = 0;
|
||||
virtual void write(uint8 addr, uint8 data) = 0;
|
||||
|
||||
virtual void power() = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual uint32 run() = 0;
|
||||
};
|
|
@ -1,3 +1,6 @@
|
|||
#define BSNES_VERSION "0.012"
|
||||
#define BSNES_TITLE "bsnes v" BSNES_VERSION
|
||||
|
||||
#include "reader/reader.h"
|
||||
|
||||
#include "memory/memory.h"
|
||||
|
@ -14,6 +17,10 @@ extern CPU *cpu;
|
|||
#include "apu/bapuskip/bapuskip.h"
|
||||
extern APU *apu;
|
||||
|
||||
#include "dsp/dsp.h"
|
||||
#include "dsp/bdsp/bdsp.h"
|
||||
extern DSP *dsp;
|
||||
|
||||
#include "ppu/ppu.h"
|
||||
#include "ppu/bppu/bppu.h"
|
||||
extern PPU *ppu;
|
||||
|
@ -26,10 +33,14 @@ extern SNES *snes;
|
|||
extern SRTC *srtc;
|
||||
extern SDD1 *sdd1;
|
||||
|
||||
#include "config/config.h"
|
||||
|
||||
#ifdef INTERFACE_MAIN
|
||||
#include "config/config.cpp"
|
||||
MemBus *mem_bus;
|
||||
CPU *cpu;
|
||||
APU *apu;
|
||||
DSP *dsp;
|
||||
PPU *ppu;
|
||||
SNES *snes;
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define zerofree(__n) if(__n) { free(__n); __n = 0; }
|
||||
|
||||
typedef unsigned int uint;
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
|
|
@ -1,273 +1,161 @@
|
|||
#include "libbase.h"
|
||||
#include "libconfig.h"
|
||||
|
||||
config_item::config_item() {
|
||||
strcpy(name, "");
|
||||
strcpy(strdef, "");
|
||||
is_string = false;
|
||||
source = 0;
|
||||
strsource = 0;
|
||||
def = 0;
|
||||
type = 0;
|
||||
void Setting::toggle() {
|
||||
data ^= 1;
|
||||
set(data);
|
||||
}
|
||||
|
||||
void config::add(uint32 *variable, char *name, uint32 def, uint32 type) {
|
||||
int n;
|
||||
if(item_count >= 4096)return;
|
||||
n = item_count;
|
||||
|
||||
item[n] = new config_item();
|
||||
strcpy(item[n]->name, name);
|
||||
item[n]->is_string = false;
|
||||
item[n]->def = def;
|
||||
item[n]->source = variable;
|
||||
*item[n]->source = item[n]->def;
|
||||
item[n]->type = type;
|
||||
|
||||
item_count++;
|
||||
uint Setting::get() {
|
||||
return data;
|
||||
}
|
||||
|
||||
void config::add(string *variable, char *name, char *def, uint32 type) {
|
||||
int n;
|
||||
if(item_count >= 4096)return;
|
||||
n = item_count;
|
||||
void Setting::set(uint _data) {
|
||||
printf("%s %d\n", name, _data);
|
||||
data = _data;
|
||||
|
||||
item[n] = new config_item();
|
||||
strcpy(item[n]->name, name);
|
||||
item[n]->is_string = true;
|
||||
strcpy(item[n]->strdef, def);
|
||||
item[n]->strsource = variable;
|
||||
strcpy(*item[n]->strsource, item[n]->strdef);
|
||||
item[n]->type = type;
|
||||
|
||||
item_count++;
|
||||
}
|
||||
|
||||
uint32 config::find(char *name) {
|
||||
for(int i=0;i<item_count;i++) {
|
||||
if(!strcmp(item[i]->name, name)) {
|
||||
return i;
|
||||
}
|
||||
if(type != DEC && type != HEX) {
|
||||
//data is a boolean type
|
||||
data &= 1;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void config::load(char *fn) {
|
||||
Setting::Setting(Config *_parent, char *_name, char *_desc, uint _data, uint _type) {
|
||||
int s;
|
||||
if(_parent) {
|
||||
_parent->add(this);
|
||||
}
|
||||
|
||||
s = strlen(_name);
|
||||
name = (char*)malloc(s + 1);
|
||||
strcpy(name, _name);
|
||||
|
||||
if(_desc) {
|
||||
s = strlen(_desc);
|
||||
desc = (char*)malloc(s + 1);
|
||||
strcpy(desc, _desc);
|
||||
} else {
|
||||
desc = (char*)malloc(1);
|
||||
*desc = 0;
|
||||
}
|
||||
|
||||
data = _data;
|
||||
def = _data;
|
||||
type = _type;
|
||||
}
|
||||
|
||||
void Config::add(Setting *setting) {
|
||||
list[list_count++] = setting;
|
||||
}
|
||||
|
||||
uint Config::string_to_uint(uint type, char *input) {
|
||||
if(!strcmp(input, "true") ||
|
||||
!strcmp(input, "enabled") ||
|
||||
!strcmp(input, "on") ||
|
||||
!strcmp(input, "yes")
|
||||
) {
|
||||
return (uint)true;
|
||||
}
|
||||
|
||||
if(!strcmp(input, "false") ||
|
||||
!strcmp(input, "disabled") ||
|
||||
!strcmp(input, "off") ||
|
||||
!strcmp(input, "no")
|
||||
) {
|
||||
return (uint)false;
|
||||
}
|
||||
|
||||
if(!strbegin(input, "0x")) {
|
||||
return strhex(input + 2);
|
||||
}
|
||||
|
||||
return strdec(input);
|
||||
}
|
||||
|
||||
char *Config::uint_to_string(uint type, uint input) {
|
||||
static char output[512];
|
||||
switch(type) {
|
||||
case Setting::TRUE_FALSE:
|
||||
sprintf(output, "%s", (input & 1)?"true":"false");
|
||||
break;
|
||||
case Setting::ENABLED_DISABLED:
|
||||
sprintf(output, "%s", (input & 1)?"enabled":"disabled");
|
||||
break;
|
||||
case Setting::ON_OFF:
|
||||
sprintf(output, "%s", (input & 1)?"on":"off");
|
||||
break;
|
||||
case Setting::YES_NO:
|
||||
sprintf(output, "%s", (input & 1)?"yes":"no");
|
||||
break;
|
||||
case Setting::DEC:
|
||||
sprintf(output, "%d", input);
|
||||
break;
|
||||
case Setting::HEX:
|
||||
sprintf(output, "0x%x", input);
|
||||
break;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
bool Config::load(char *fn) {
|
||||
FILE *fp;
|
||||
char *buffer;
|
||||
int i, fsize;
|
||||
uint32 l;
|
||||
fp = fopen(fn, "rb");
|
||||
//file doesn't exist yet, do nothing
|
||||
if(!fp)return;
|
||||
if(!fp)return false;
|
||||
|
||||
//load the config file into memory
|
||||
fseek(fp, 0, SEEK_END);
|
||||
fsize = ftell(fp);
|
||||
int fsize = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
//blank file, do nothing
|
||||
if(fsize == 0) {
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
buffer = (char*)malloc(fsize + 1);
|
||||
char *buffer = (char*)malloc(fsize + 1);
|
||||
fread(buffer, 1, fsize, fp);
|
||||
fclose(fp);
|
||||
buffer[fsize] = 0;
|
||||
|
||||
*(buffer + fsize) = 0;
|
||||
strcpy(data, buffer);
|
||||
free(buffer);
|
||||
replace(data, "\r\n", "\n");
|
||||
qreplace(data, "\t", " ");
|
||||
|
||||
//split the file into lines
|
||||
replace(data, "\r\n", "\n");
|
||||
qreplace(data, "\t", "");
|
||||
qreplace(data, " ", "");
|
||||
split(line, "\n", data);
|
||||
|
||||
for(i=0;i<count(line);i++) {
|
||||
qreplace(line[i], " ", "");
|
||||
|
||||
//remove comment, if it exists
|
||||
if(qstrpos(line[i], "#") != null) {
|
||||
strset(line[i], qstrpos(line[i], "#"), 0);
|
||||
}
|
||||
|
||||
//ignore blank lines
|
||||
for(int i=0;i<count(line);i++) {
|
||||
if(strlen(line[i]) == 0)continue;
|
||||
if(*strptr(line[i]) == '#')continue;
|
||||
|
||||
qsplit(part, "=", line[i]);
|
||||
|
||||
l = find(strptr(part[0]));
|
||||
if(l != null) {
|
||||
//if the config item name is valid... update item value
|
||||
if(item[l]->is_string == true) {
|
||||
strunquote(part[1]);
|
||||
strcpy(*item[l]->strsource, part[1]);
|
||||
} else {
|
||||
if(!strcmp(part[1], "true") || !strcmp(part[1], "yes") ||
|
||||
!strcmp(part[1], "on") || !strcmp(part[1], "enabled")) {
|
||||
*item[l]->source = 1;
|
||||
} else if(!strcmp(part[1], "false") || !strcmp(part[1], "no") ||
|
||||
!strcmp(part[1], "off") || !strcmp(part[1], "disabled")) {
|
||||
*item[l]->source = 0;
|
||||
} else if(item[l]->type == HEX) {
|
||||
*item[l]->source = strhex(strptr(part[1]) + 2); //skip 0x prefix
|
||||
} else { /* fall back on DEC */
|
||||
*item[l]->source = strdec(part[1]);
|
||||
}
|
||||
split(part, "=", line[i]);
|
||||
for(int l=0;l<list_count;l++) {
|
||||
if(!strcmp(list[l]->name, part[0])) {
|
||||
list[l]->set(string_to_uint(list[l]->type, strptr(part[1])));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void config::load(substring &fn) { load(strptr(fn)); }
|
||||
|
||||
//create a text string from config item[i] to be output via config->save()
|
||||
void config::set_newline(int i) {
|
||||
char t[16];
|
||||
if(item[i]->is_string == true) {
|
||||
strcpy(newline, item[i]->name);
|
||||
strcat(newline, " = \"");
|
||||
strcat(newline, *item[i]->strsource);
|
||||
strcat(newline, "\"");
|
||||
} else {
|
||||
strcpy(newline, item[i]->name);
|
||||
strcat(newline, " = ");
|
||||
switch(item[i]->type) {
|
||||
case TRUEFALSE:
|
||||
strcat(newline, (*item[i]->source)?"true":"false");
|
||||
break;
|
||||
case YESNO:
|
||||
strcat(newline, (*item[i]->source)?"yes":"no");
|
||||
break;
|
||||
case ONOFF:
|
||||
strcat(newline, (*item[i]->source)?"on":"off");
|
||||
break;
|
||||
case ENABLED:
|
||||
strcat(newline, (*item[i]->source)?"enabled":"disabled");
|
||||
break;
|
||||
case HEX:
|
||||
sprintf(t, "0x%0.2x", *item[i]->source);
|
||||
strcat(newline, t);
|
||||
break;
|
||||
case DEC:
|
||||
default:
|
||||
sprintf(t, "%d", *item[i]->source);
|
||||
strcat(newline, t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Config::load(substring &fn) { return load(strptr(fn)); }
|
||||
|
||||
void config::save(char *fn) {
|
||||
bool Config::save(char *fn) {
|
||||
FILE *fp;
|
||||
int i, fsize;
|
||||
uint32 l;
|
||||
char *buffer;
|
||||
uint8 set[4096];
|
||||
bool blank = false;
|
||||
fp = fopen(fn, "rb");
|
||||
if(!fp) {
|
||||
blank = true;
|
||||
} else {
|
||||
fseek(fp, 0, SEEK_END);
|
||||
fsize = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
if(fsize == 0) {
|
||||
blank = true;
|
||||
} else {
|
||||
buffer = (char*)malloc(fsize + 1);
|
||||
fread(buffer, 1, fsize, fp);
|
||||
buffer[fsize] = 0;
|
||||
|
||||
strcpy(data, buffer);
|
||||
free(buffer);
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
fp = fopen(fn, "wb");
|
||||
//no write access?
|
||||
if(!fp)return;
|
||||
if(!fp)return false;
|
||||
|
||||
//list of config items. if the item is set in the
|
||||
//existing config file, then don't test it to see
|
||||
//if it needs to be written again later on
|
||||
memset(set, 0, item_count);
|
||||
|
||||
if(blank == false) {
|
||||
for(int i=0;i<list_count;i++) {
|
||||
strcpy(data, list[i]->desc);
|
||||
replace(data, "\r\n", "\n");
|
||||
qreplace(data, "\t", " ");
|
||||
|
||||
split(line, "\n", data);
|
||||
split(oldline, "\n", data);
|
||||
|
||||
for(i=0;i<count(line);i++) {
|
||||
qreplace(line[i], " ", "");
|
||||
|
||||
if(qstrpos(line[i], "#") != null) {
|
||||
strset(line[i], qstrpos(line[i], "#"), 0);
|
||||
}
|
||||
|
||||
//this line is empty, restore the old line and continue
|
||||
if(strlen(line[i]) == 0) {
|
||||
strcpy(line[i], oldline[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
qsplit(part, "=", line[i]);
|
||||
|
||||
l = find(strptr(part[0]));
|
||||
if(l == null) {
|
||||
//invalid item name, restore the old line and continue
|
||||
strcpy(line[i], oldline[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
set[l] = 1;
|
||||
set_newline(l);
|
||||
|
||||
//copy the user comment from the old config file, if it exists
|
||||
if(qstrpos(oldline[i], "#") != null) {
|
||||
strcat(newline, " ");
|
||||
strcat(newline, strptr(oldline[i]) + qstrpos(oldline[i], "#"));
|
||||
}
|
||||
|
||||
strcpy(line[i], newline);
|
||||
}
|
||||
|
||||
//write out the old config file + changes first
|
||||
for(i=0;i<count(line);) {
|
||||
fprintf(fp, "%s", strptr(line[i]));
|
||||
|
||||
//write a line feed on all lines but the last.
|
||||
//keeps the file from growing everytime it is saved
|
||||
if(++i < count(line))fprintf(fp, "\r\n");
|
||||
split(line, "\n", data);
|
||||
for(int l=0;l<count(line);l++) {
|
||||
fprintf(fp, "# %s\r\n", strptr(line[l]));
|
||||
}
|
||||
fprintf(fp, "# (default = %s)\r\n", uint_to_string(list[i]->type, list[i]->def));
|
||||
fprintf(fp, "%s = %s\r\n\r\n", list[i]->name, uint_to_string(list[i]->type, list[i]->data));
|
||||
}
|
||||
|
||||
int lines_written;
|
||||
for(i=lines_written=0;i<item_count;i++) {
|
||||
//if the item was written to the file above...
|
||||
if(set[i] == 1)continue;
|
||||
|
||||
set_newline(i);
|
||||
//prevent a newline from appearing at the top of the file
|
||||
//when the config file is created for the first time
|
||||
if(lines_written == 0 && blank == false)fprintf(fp, "\r\n");
|
||||
fprintf(fp, "%s\r\n", strptr(newline));
|
||||
lines_written++;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
void config::save(substring &fn) { save(strptr(fn)); }
|
||||
bool Config::save(substring &fn) { return save(strptr(fn)); }
|
||||
|
||||
config::config() {
|
||||
item_count = 0;
|
||||
}
|
||||
|
||||
config::~config() {
|
||||
for(int i=0;i<item_count;i++) {
|
||||
if(item[i])delete(item[i]);
|
||||
}
|
||||
Config::Config() {
|
||||
list_count = 0;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
libconfig : version 0.03 ~byuu (08/20/05)
|
||||
libconfig : version 0.05 ~byuu (09/13/05)
|
||||
*/
|
||||
|
||||
#ifndef __LIBCONFIG
|
||||
|
@ -7,41 +7,92 @@
|
|||
|
||||
#include "libstring.h"
|
||||
|
||||
class config_item {
|
||||
public:
|
||||
uint32 *source, def, type;
|
||||
string *strsource, strdef;
|
||||
bool is_string;
|
||||
string name;
|
||||
config_item();
|
||||
};
|
||||
class Config;
|
||||
|
||||
//operator= is the /only/ overloaded operator that isn't inherited by derived classes.
|
||||
//similarly, base constructor/destructors with arguments are not inherited.
|
||||
//the inclusion of the overloaded virtual function 'toggle' is to allow toggle to call
|
||||
//the overloaded set() function, if it exists. for some reason, Setting::toggle() calls
|
||||
//Setting::set() no matter what, even if the derived class defines set()...
|
||||
//the below macro is a quick way to take care of all of these issues.
|
||||
//usage example:
|
||||
// class T : public Setting { public: SettingOperators(T); } t;
|
||||
// t = 0; // -> t.set(0);
|
||||
#define SettingOperators(__name) \
|
||||
inline __name &operator=(const bool _data) { set((uint)_data); return *this; } \
|
||||
inline __name &operator=(const uint _data) { set(_data); return *this; } \
|
||||
inline __name &operator=(const uint8 _data) { set(_data); return *this; } \
|
||||
inline __name &operator=(const uint16 _data) { set(_data); return *this; } \
|
||||
inline __name &operator=(const uint32 _data) { set(_data); return *this; } \
|
||||
inline __name &operator=(const int _data) { set(_data); return *this; } \
|
||||
inline __name &operator=(const int8 _data) { set(_data); return *this; } \
|
||||
inline __name &operator=(const int16 _data) { set(_data); return *this; } \
|
||||
inline __name &operator=(const int32 _data) { set(_data); return *this; } \
|
||||
void toggle() { data ^= 1; set(data); } \
|
||||
__name(Config *_parent, char *_name, char *_desc = 0, uint _data = 0, uint _type = Setting::DEC) : \
|
||||
Setting(_parent, _name, _desc, _data, _type) {}
|
||||
|
||||
class Setting {
|
||||
friend class Config;
|
||||
|
||||
protected:
|
||||
uint data, type, def;
|
||||
|
||||
class config {
|
||||
private:
|
||||
uint32 item_count;
|
||||
config_item *item[4096];
|
||||
string data, line, oldline, newline, part;
|
||||
public:
|
||||
enum {
|
||||
TRUEFALSE = 0,
|
||||
YESNO = 1,
|
||||
ONOFF = 2,
|
||||
ENABLED = 3,
|
||||
DEC = 4,
|
||||
HEX = 5,
|
||||
STR = 6
|
||||
TRUE_FALSE,
|
||||
ENABLED_DISABLED,
|
||||
ON_OFF,
|
||||
YES_NO,
|
||||
BOOL,
|
||||
DEC,
|
||||
HEX
|
||||
};
|
||||
void add(uint32 *variable, char *name, uint32 def, uint32 type = DEC);
|
||||
void add(string *variable, char *name, char *def, uint32 type = STR);
|
||||
uint32 find(char *name);
|
||||
void load(char *fn);
|
||||
void load(substring &fn);
|
||||
void save(char *fn);
|
||||
void save(substring &fn);
|
||||
void set_newline(int i);
|
||||
char *name, *desc;
|
||||
virtual void toggle();
|
||||
virtual uint get();
|
||||
virtual void set(uint _data);
|
||||
|
||||
config();
|
||||
~config();
|
||||
Setting(Config *_parent, char *_name, char *_desc = 0, uint _data = 0, uint _type = DEC);
|
||||
|
||||
inline operator bool() { return (bool)get(); }
|
||||
inline operator uint() { return get(); }
|
||||
inline operator uint8() { return get(); }
|
||||
inline operator uint16() { return get(); }
|
||||
inline operator uint32() { return get(); }
|
||||
inline operator int() { return get(); }
|
||||
inline operator int8() { return get(); }
|
||||
inline operator int16() { return get(); }
|
||||
inline operator int32() { return get(); }
|
||||
|
||||
inline Setting &operator=(const bool _data) { set((uint)_data); return *this; }
|
||||
inline Setting &operator=(const uint _data) { set(_data); return *this; }
|
||||
inline Setting &operator=(const uint8 _data) { set(_data); return *this; }
|
||||
inline Setting &operator=(const uint16 _data) { set(_data); return *this; }
|
||||
inline Setting &operator=(const uint32 _data) { set(_data); return *this; }
|
||||
inline Setting &operator=(const int _data) { set(_data); return *this; }
|
||||
inline Setting &operator=(const int8 _data) { set(_data); return *this; }
|
||||
inline Setting &operator=(const int16 _data) { set(_data); return *this; }
|
||||
inline Setting &operator=(const int32 _data) { set(_data); return *this; }
|
||||
};
|
||||
|
||||
class Config {
|
||||
protected:
|
||||
vector<Setting*> list;
|
||||
uint list_count;
|
||||
|
||||
string data, line, part, subpart;
|
||||
|
||||
uint string_to_uint(uint type, char *input);
|
||||
char *uint_to_string(uint type, uint input);
|
||||
|
||||
public:
|
||||
void add(Setting *setting);
|
||||
bool load(char *fn);
|
||||
bool load(substring &fn);
|
||||
bool save(char *fn);
|
||||
bool save(substring &fn);
|
||||
Config();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,7 +6,7 @@ public:
|
|||
uint8 *rom, *sram;
|
||||
uint32 rom_size, sram_size;
|
||||
uint8 read (uint32 addr);
|
||||
void write(uint32 addr, byte value);
|
||||
void write(uint32 addr, uint8 value);
|
||||
void write_protect(bool r);
|
||||
void set_cartinfo(CartInfo *ci);
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ public:
|
|||
uint8 *rom, *sram;
|
||||
uint32 rom_size, sram_size;
|
||||
uint8 read (uint32 addr);
|
||||
void write(uint32 addr, byte value);
|
||||
void write(uint32 addr, uint8 value);
|
||||
void write_protect(bool r);
|
||||
void set_cartinfo(CartInfo *ci);
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ public:
|
|||
uint8 *rom, *sram;
|
||||
uint32 rom_size, sram_size;
|
||||
uint8 read (uint32 addr);
|
||||
void write(uint32 addr, byte value);
|
||||
void write(uint32 addr, uint8 value);
|
||||
void write_protect(bool r);
|
||||
void set_cartinfo(CartInfo *ci);
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ public:
|
|||
uint8 *rom, *sram;
|
||||
uint32 rom_size, sram_size;
|
||||
uint8 read (uint32 addr);
|
||||
void write(uint32 addr, byte value);
|
||||
void write(uint32 addr, uint8 value);
|
||||
void write_protect(bool r);
|
||||
void set_cartinfo(CartInfo *ci);
|
||||
|
||||
|
|
|
@ -171,33 +171,39 @@ void bMemBus::get_cartinfo(CartInfo *ci) {
|
|||
***************************************/
|
||||
|
||||
uint8 bMemBus::read(uint32 addr) {
|
||||
uint32 b, w, r;
|
||||
addr &= 0xffffff;
|
||||
b = (addr >> 16);
|
||||
w = (addr & 0xffff);
|
||||
static uint32 r;
|
||||
switch(addr & 0xc00000) {
|
||||
case 0x400000:
|
||||
if((addr & 0xfe0000) == 0x7e0000) {
|
||||
r = wram[addr & 0x01ffff];
|
||||
break;
|
||||
}
|
||||
//fallthrough
|
||||
case 0xc00000:
|
||||
r = cart->read(addr);
|
||||
break;
|
||||
|
||||
if(b <= 0x3f) {
|
||||
if(w <= 0x1fff) {
|
||||
r = wram[w];
|
||||
} else if(w <= 0x5fff) {
|
||||
r = mmio[w - 0x2000]->read(w);
|
||||
} else {
|
||||
//case 0x000000:
|
||||
//case 0x800000:
|
||||
default:
|
||||
switch(addr & 0x00e000) {
|
||||
case 0x0000:
|
||||
r = wram[addr & 0x1fff];
|
||||
break;
|
||||
case 0x2000:
|
||||
case 0x4000:
|
||||
r = mmio[(addr - 0x2000) & 0x3fff]->read(addr & 0x7fff);
|
||||
break;
|
||||
// case 0x6000:
|
||||
// case 0x8000:
|
||||
// case 0xa000:
|
||||
// case 0xc000:
|
||||
// case 0xe000:
|
||||
default:
|
||||
r = cart->read(addr);
|
||||
break;
|
||||
}
|
||||
} else if(b <= 0x7d) {
|
||||
r = cart->read(addr);
|
||||
} else if(b <= 0x7f) {
|
||||
r = wram[addr & 0x01ffff];
|
||||
} else if(b <= 0xbf) {
|
||||
if(w <= 0x1fff) {
|
||||
r = wram[w];
|
||||
} else if(w <= 0x5fff) {
|
||||
r = mmio[w - 0x2000]->read(w);
|
||||
} else {
|
||||
r = cart->read(addr);
|
||||
}
|
||||
} else {
|
||||
r = cart->read(addr);
|
||||
break;
|
||||
}
|
||||
|
||||
snes->notify(SNES::MEM_READ, addr, r);
|
||||
|
@ -205,33 +211,38 @@ uint32 b, w, r;
|
|||
}
|
||||
|
||||
void bMemBus::write(uint32 addr, uint8 value) {
|
||||
uint32 b, w;
|
||||
addr &= 0xffffff;
|
||||
b = (addr >> 16);
|
||||
w = (addr & 0xffff);
|
||||
switch(addr & 0xc00000) {
|
||||
case 0x400000:
|
||||
if((addr & 0xfe0000) == 0x7e0000) {
|
||||
wram[addr & 0x01ffff] = value;
|
||||
break;
|
||||
}
|
||||
//fallthrough
|
||||
case 0xc00000:
|
||||
cart->write(addr, value);
|
||||
break;
|
||||
|
||||
if(b <= 0x3f) {
|
||||
if(w <= 0x1fff) {
|
||||
wram[w] = value;
|
||||
} else if(w <= 0x5fff) {
|
||||
mmio[w - 0x2000]->write(w, value);
|
||||
} else {
|
||||
//case 0x000000:
|
||||
//case 0x800000:
|
||||
default:
|
||||
switch(addr & 0x00e000) {
|
||||
case 0x0000:
|
||||
wram[addr & 0x1fff] = value;
|
||||
break;
|
||||
case 0x2000:
|
||||
case 0x4000:
|
||||
mmio[(addr - 0x2000) & 0x3fff]->write(addr & 0x7fff, value);
|
||||
break;
|
||||
// case 0x6000:
|
||||
// case 0x8000:
|
||||
// case 0xa000:
|
||||
// case 0xc000:
|
||||
// case 0xe000:
|
||||
default:
|
||||
cart->write(addr, value);
|
||||
break;
|
||||
}
|
||||
} else if(b <= 0x7d) {
|
||||
cart->write(addr, value);
|
||||
} else if(b <= 0x7f) {
|
||||
wram[addr & 0x01ffff] = value;
|
||||
} else if(b <= 0xbf) {
|
||||
if(w <= 0x1fff) {
|
||||
wram[w] = value;
|
||||
} else if(w <= 0x5fff) {
|
||||
mmio[w - 0x2000]->write(w, value);
|
||||
} else {
|
||||
cart->write(addr, value);
|
||||
}
|
||||
} else {
|
||||
cart->write(addr, value);
|
||||
break;
|
||||
}
|
||||
|
||||
snes->notify(SNES::MEM_WRITE, addr, value);
|
||||
|
@ -243,7 +254,7 @@ void bMemBus::power() {
|
|||
}
|
||||
|
||||
void bMemBus::reset() {
|
||||
fastROM = false;
|
||||
set_speed(false);
|
||||
}
|
||||
|
||||
bMemBus::bMemBus() {
|
||||
|
@ -253,5 +264,5 @@ bMemBus::bMemBus() {
|
|||
}
|
||||
|
||||
bMemBus::~bMemBus() {
|
||||
if(wram)free(wram);
|
||||
zerofree(wram);
|
||||
}
|
||||
|
|
|
@ -18,13 +18,13 @@ bool rom_loaded;
|
|||
enum { LOROM = 0x20, HIROM = 0x21, EXLOROM = 0x22, EXHIROM = 0x25 };
|
||||
|
||||
uint8 read (uint32 addr);
|
||||
void write(uint32 addr, byte value);
|
||||
void write(uint32 addr, uint8 value);
|
||||
|
||||
bool load_cart(Reader *rf);
|
||||
bool load_sram(Reader *rf);
|
||||
bool save_sram(Writer *wf);
|
||||
void unload_cart();
|
||||
void get_cartinfo(CartInfo *ci);
|
||||
bool load_cart(Reader *rf);
|
||||
bool load_sram(Reader *rf);
|
||||
bool save_sram(Writer *wf);
|
||||
void unload_cart();
|
||||
void get_cartinfo(CartInfo *ci);
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "../base.h"
|
||||
|
||||
uint16 Memory::read_word(uint32 addr, uint8 wrap) {
|
||||
uint16 Memory::read_word(uint32 addr, uint wrap) {
|
||||
uint16 r;
|
||||
switch(wrap) {
|
||||
case WRAP_NONE:
|
||||
|
@ -19,24 +19,24 @@ uint16 r;
|
|||
return r;
|
||||
}
|
||||
|
||||
void Memory::write_word(uint32 addr, uint16 value, uint8 wrap) {
|
||||
void Memory::write_word(uint32 addr, uint16 data, uint wrap) {
|
||||
switch(wrap) {
|
||||
case WRAP_NONE:
|
||||
write(addr, value);
|
||||
write(addr + 1, value >> 8);
|
||||
write(addr, data);
|
||||
write(addr + 1, data >> 8);
|
||||
return;
|
||||
case WRAP_BANK:
|
||||
write(addr, value);
|
||||
write((addr & 0xff0000) | ((addr + 1) & 0xffff), value >> 8);
|
||||
write(addr, data);
|
||||
write((addr & 0xff0000) | ((addr + 1) & 0xffff), data >> 8);
|
||||
return;
|
||||
case WRAP_PAGE:
|
||||
write(addr, value);
|
||||
write((addr & 0xffff00) | ((addr + 1) & 0xff), value >> 8);
|
||||
write(addr, data);
|
||||
write((addr & 0xffff00) | ((addr + 1) & 0xff), data >> 8);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Memory::read_long(uint32 addr, uint8 wrap) {
|
||||
uint32 Memory::read_long(uint32 addr, uint wrap) {
|
||||
uint32 r;
|
||||
switch(wrap) {
|
||||
case WRAP_NONE:
|
||||
|
@ -58,22 +58,22 @@ uint32 r;
|
|||
return r;
|
||||
}
|
||||
|
||||
void Memory::write_long(uint32 addr, uint32 value, uint8 wrap) {
|
||||
void Memory::write_long(uint32 addr, uint32 data, uint wrap) {
|
||||
switch(wrap) {
|
||||
case WRAP_NONE:
|
||||
write(addr, value);
|
||||
write(addr + 1, value >> 8);
|
||||
write(addr + 2, value >> 16);
|
||||
write(addr, data);
|
||||
write(addr + 1, data >> 8);
|
||||
write(addr + 2, data >> 16);
|
||||
return;
|
||||
case WRAP_BANK:
|
||||
write(addr, value);
|
||||
write((addr & 0xff0000) | ((addr + 1) & 0xffff), value >> 8);
|
||||
write((addr & 0xff0000) | ((addr + 2) & 0xffff), value >> 16);
|
||||
write(addr, data);
|
||||
write((addr & 0xff0000) | ((addr + 1) & 0xffff), data >> 8);
|
||||
write((addr & 0xff0000) | ((addr + 2) & 0xffff), data >> 16);
|
||||
return;
|
||||
case WRAP_PAGE:
|
||||
write(addr, value);
|
||||
write((addr & 0xffff00) | ((addr + 1) & 0xff), value >> 8);
|
||||
write((addr & 0xffff00) | ((addr + 2) & 0xff), value >> 16);
|
||||
write(addr, data);
|
||||
write((addr & 0xffff00) | ((addr + 1) & 0xff), data >> 8);
|
||||
write((addr & 0xffff00) | ((addr + 2) & 0xff), data >> 16);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -82,16 +82,30 @@ MMIO mmio_unmapped;
|
|||
uint8 MMIO::read (uint32 addr) { return cpu->regs.mdr; }
|
||||
void MMIO::write(uint32 addr, uint8 value) {}
|
||||
|
||||
uint8 MemBus::speed(uint32 addr) {
|
||||
uint8 MemBus::calc_speed(uint32 addr, bool fast) {
|
||||
if((addr & 0xc00000) == 0x400000)return 8;
|
||||
if((addr & 0x808000) == 0x808000)return fastROM?6:8;
|
||||
if((addr & 0xc00000) == 0xc00000)return fastROM?6:8;
|
||||
if((addr & 0x808000) == 0x808000)return fast?6:8;
|
||||
if((addr & 0xc00000) == 0xc00000)return fast?6:8;
|
||||
if((addr & 0xe000) == 0x2000)return 6;
|
||||
if((addr & 0xfe00) == 0x4000)return 12;
|
||||
if((addr & 0xe000) == 0x4000)return 6;
|
||||
return 8;
|
||||
}
|
||||
|
||||
uint8 MemBus::speed(uint32 addr) {
|
||||
return speed_table[addr >> 9];
|
||||
}
|
||||
|
||||
void MemBus::set_speed(bool fast) {
|
||||
fastROM = fast;
|
||||
|
||||
if(fastROM) {
|
||||
speed_table = (uint8*)speed_table_fastrom;
|
||||
} else {
|
||||
speed_table = (uint8*)speed_table_slowrom;
|
||||
}
|
||||
}
|
||||
|
||||
void MemBus::flush_mmio_mappers() {
|
||||
for(int i=0;i<0x4000;i++) {
|
||||
mmio[i] = &mmio_unmapped;
|
||||
|
@ -99,7 +113,7 @@ void MemBus::flush_mmio_mappers() {
|
|||
}
|
||||
|
||||
bool MemBus::set_mmio_mapper(uint16 addr, MMIO *mapper) {
|
||||
/* out of range? */
|
||||
//out of range?
|
||||
if(addr < 0x2000 || addr >= 0x6000)return false;
|
||||
|
||||
mmio[(addr - 0x2000) & 0x3fff] = mapper;
|
||||
|
@ -110,6 +124,12 @@ MemBus::MemBus() {
|
|||
int i;
|
||||
fastROM = false;
|
||||
flush_mmio_mappers();
|
||||
|
||||
for(i=0;i<32768;i++) {
|
||||
speed_table_slowrom[i] = calc_speed(i << 9, false);
|
||||
speed_table_fastrom[i] = calc_speed(i << 9, true);
|
||||
}
|
||||
speed_table = (uint8*)speed_table_slowrom;
|
||||
}
|
||||
|
||||
MemBus::~MemBus() {}
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
class Memory {
|
||||
public:
|
||||
enum { WRAP_NONE = 0, WRAP_BANK = 1, WRAP_PAGE = 2 };
|
||||
virtual uint8 read (uint32 addr) = 0;
|
||||
virtual void write(uint32 addr, uint8 value) = 0;
|
||||
virtual uint16 read_word (uint32 addr, uint8 wrap = WRAP_NONE);
|
||||
virtual void write_word(uint32 addr, uint16 value, uint8 wrap = WRAP_NONE);
|
||||
virtual uint32 read_long (uint32 addr, uint8 wrap = WRAP_NONE);
|
||||
virtual void write_long(uint32 addr, uint32 value, uint8 wrap = WRAP_NONE);
|
||||
virtual uint8 read (uint32 addr) = 0;
|
||||
virtual void write (uint32 addr, uint8 data) = 0;
|
||||
virtual uint16 read_word (uint32 addr, uint wrap = WRAP_NONE);
|
||||
virtual void write_word(uint32 addr, uint16 data, uint wrap = WRAP_NONE);
|
||||
virtual uint32 read_long (uint32 addr, uint wrap = WRAP_NONE);
|
||||
virtual void write_long(uint32 addr, uint32 data, uint wrap = WRAP_NONE);
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8 *rom, *sram;
|
||||
uint32 rom_size, sram_size;
|
||||
}CartInfo;
|
||||
uint8 *rom, *sram;
|
||||
uint32 rom_size, sram_size;
|
||||
} CartInfo;
|
||||
|
||||
class Cart : public Memory {
|
||||
public:
|
||||
|
@ -31,15 +31,26 @@ public:
|
|||
Cart *cart;
|
||||
MMIO *mmio[0x4000];
|
||||
bool fastROM;
|
||||
virtual void flush_mmio_mappers();
|
||||
virtual bool set_mmio_mapper(uint16 addr, MMIO *mapper);
|
||||
virtual uint8 speed(uint32 addr);
|
||||
void flush_mmio_mappers();
|
||||
bool set_mmio_mapper(uint16 addr, MMIO *mapper);
|
||||
|
||||
virtual bool load_cart(Reader *rf) = 0;
|
||||
virtual bool load_sram(Reader *rf) = 0;
|
||||
virtual bool save_sram(Writer *wf) = 0;
|
||||
virtual void unload_cart() = 0;
|
||||
virtual void get_cartinfo(CartInfo *ci) = 0;
|
||||
private:
|
||||
//0x1000000 / 512 = 32768
|
||||
//512 = 0x200, smallest block of a different-speed memory range
|
||||
//ex. $4000-$41ff = 512
|
||||
uint8 *speed_table,
|
||||
speed_table_slowrom[32768],
|
||||
speed_table_fastrom[32768];
|
||||
inline uint8 calc_speed(uint32 addr, bool fast);
|
||||
public:
|
||||
uint8 speed(uint32 addr);
|
||||
void set_speed(bool fast);
|
||||
|
||||
virtual bool load_cart(Reader *rf) = 0;
|
||||
virtual bool load_sram(Reader *rf) = 0;
|
||||
virtual bool save_sram(Writer *wf) = 0;
|
||||
virtual void unload_cart() = 0;
|
||||
virtual void get_cartinfo(CartInfo *ci) = 0;
|
||||
|
||||
virtual void power() = 0;
|
||||
virtual void reset() = 0;
|
||||
|
|
|
@ -6,7 +6,7 @@ void bPPU::run() {}
|
|||
|
||||
void bPPU::scanline() {
|
||||
_y = cpu->vcounter();
|
||||
_screen_width = (regs.bg_mode == 5 || regs.bg_mode == 6)?512:256;
|
||||
_screen_width = (regs.bg_mode == 5 || regs.bg_mode == 6) ? 512 : 256;
|
||||
_interlace = cpu->interlace();
|
||||
_interlace_field = cpu->interlace_field();
|
||||
|
||||
|
@ -25,27 +25,23 @@ void bPPU::scanline() {
|
|||
}
|
||||
}
|
||||
|
||||
if(_y == (cpu->overscan()?239:224) && regs.display_disabled == false) {
|
||||
if(_y == (cpu->overscan() ? 239 : 224) && regs.display_disabled == false) {
|
||||
//OAM address reset
|
||||
regs.oam_addr = ((regs.oam_addrh << 8) | regs.oam_addrl) << 1;
|
||||
}
|
||||
}
|
||||
|
||||
void bPPU::render_scanline() {
|
||||
//only allow frameskip setting to ignore actual rendering; not RTO, etc.
|
||||
if(settings.frameskip_pos != 0)return;
|
||||
|
||||
if(_y > 0 && _y < (cpu->overscan()?239:224)) {
|
||||
if(regs.bg_mode == 5 || regs.bg_mode == 6) {
|
||||
output->hires = true;
|
||||
output->line[_y].hires = true;
|
||||
}
|
||||
if(_interlace == true) {
|
||||
output->interlace = true;
|
||||
output->line[_y].interlace = true;
|
||||
}
|
||||
if(_y > 0 && _y < (cpu->overscan() ? 239 : 224)) {
|
||||
render_line();
|
||||
}
|
||||
}
|
||||
|
||||
bool bPPU::render_frame() { return (settings.frameskip_pos == 0); }
|
||||
|
||||
void bPPU::frame() {
|
||||
if(settings.frameskip_changed == true) {
|
||||
settings.frameskip_changed = false;
|
||||
|
@ -58,12 +54,6 @@ void bPPU::frame() {
|
|||
if(settings.frameskip_pos != 0)return;
|
||||
|
||||
snes->notify(SNES::RENDER_FRAME);
|
||||
output->hires = false;
|
||||
output->interlace = false;
|
||||
for(int i=0;i<239;i++) {
|
||||
output->line[i].hires = false;
|
||||
output->line[i].interlace = false;
|
||||
}
|
||||
}
|
||||
|
||||
void bPPU::set_frameskip(int fs) {
|
||||
|
@ -82,7 +72,6 @@ void bPPU::power() {
|
|||
}
|
||||
|
||||
void bPPU::reset() {
|
||||
memset(output->buffer, 0, 512 * 478 * 2);
|
||||
frame();
|
||||
|
||||
memset(sprite_list, 0, sizeof(sprite_list));
|
||||
|
@ -335,9 +324,9 @@ bPPU::bPPU() {
|
|||
|
||||
mmio = new bPPUMMIO(this);
|
||||
|
||||
vram = (uint8*)memalloc(65536, "bPPU::vram");
|
||||
oam = (uint8*)memalloc( 544, "bPPU::oam");
|
||||
cgram = (uint8*)memalloc( 512, "bPPU::cgram");
|
||||
vram = (uint8*)malloc(65536);
|
||||
oam = (uint8*)malloc( 544);
|
||||
cgram = (uint8*)malloc( 512);
|
||||
memset(vram, 0, 65536);
|
||||
memset(oam, 0, 544);
|
||||
memset(cgram, 0, 512);
|
||||
|
@ -346,7 +335,7 @@ bPPU::bPPU() {
|
|||
|
||||
int i, l;
|
||||
uint8 r, g, b;
|
||||
float m;
|
||||
double m;
|
||||
uint16 *ptr;
|
||||
for(l=0;l<16;l++) {
|
||||
mosaic_table[l] = (uint16*)malloc(4096 * 2);
|
||||
|
@ -358,7 +347,7 @@ uint16 *ptr;
|
|||
light_table = (uint16*)malloc(16 * 32768 * 2);
|
||||
ptr = (uint16*)light_table;
|
||||
for(l=0;l<16;l++) {
|
||||
m = (float)l / 15.0;
|
||||
m = (double)l / 15.0;
|
||||
for(i=0;i<32768;i++) {
|
||||
r = (i ) & 31;
|
||||
g = (i >> 5) & 31;
|
||||
|
@ -366,9 +355,9 @@ uint16 *ptr;
|
|||
if(l == 0) { r = g = b = 0; }
|
||||
else if(l == 15);
|
||||
else {
|
||||
r = (uint8)((float)r * m);
|
||||
g = (uint8)((float)g * m);
|
||||
b = (uint8)((float)b * m);
|
||||
r = (uint8)((double)r * m);
|
||||
g = (uint8)((double)g * m);
|
||||
b = (uint8)((double)b * m);
|
||||
}
|
||||
*ptr++ = (r) | (g << 5) | (b << 10);
|
||||
}
|
||||
|
@ -378,30 +367,15 @@ uint16 *ptr;
|
|||
bPPU::~bPPU() {
|
||||
delete(mmio);
|
||||
|
||||
if(vram) {
|
||||
free(vram);
|
||||
vram = 0;
|
||||
}
|
||||
if(oam) {
|
||||
free(oam);
|
||||
oam = 0;
|
||||
}
|
||||
if(cgram) {
|
||||
free(cgram);
|
||||
cgram = 0;
|
||||
}
|
||||
zerofree(vram);
|
||||
zerofree(oam);
|
||||
zerofree(cgram);
|
||||
|
||||
for(int i=0;i<16;i++) {
|
||||
if(mosaic_table[i]) {
|
||||
free(mosaic_table[i]);
|
||||
mosaic_table[i] = 0;
|
||||
}
|
||||
zerofree(mosaic_table[i]);
|
||||
}
|
||||
|
||||
if(light_table) {
|
||||
memfree(light_table);
|
||||
light_table = 0;
|
||||
}
|
||||
zerofree(light_table);
|
||||
}
|
||||
|
||||
bPPUMMIO::bPPUMMIO(bPPU *_ppu) {
|
||||
|
|
|
@ -25,12 +25,12 @@ struct sprite_item {
|
|||
bool vflip, hflip;
|
||||
uint8 palette;
|
||||
uint8 priority;
|
||||
}sprite_list[128];
|
||||
} sprite_list[128];
|
||||
|
||||
struct {
|
||||
int32 frameskip, frameskip_pos;
|
||||
bool frameskip_changed;
|
||||
}settings;
|
||||
} settings;
|
||||
|
||||
struct {
|
||||
//open bus support
|
||||
|
@ -119,6 +119,7 @@ struct {
|
|||
//$2130
|
||||
uint8 color_mask, colorsub_mask;
|
||||
bool addsub_mode;
|
||||
bool direct_color;
|
||||
|
||||
//$2131
|
||||
bool color_mode, color_halve;
|
||||
|
@ -145,7 +146,7 @@ struct {
|
|||
//$213e
|
||||
bool time_over, range_over;
|
||||
uint16 oam_itemcount, oam_tilecount;
|
||||
}regs;
|
||||
} regs;
|
||||
uint8 vram_read (uint16 addr);
|
||||
void vram_write (uint16 addr, uint8 value);
|
||||
uint8 oam_read (uint16 addr);
|
||||
|
@ -225,7 +226,7 @@ struct {
|
|||
|
||||
void latch_counters();
|
||||
|
||||
/* PPU render functions */
|
||||
//PPU render functions
|
||||
|
||||
#include "bppu_render.h"
|
||||
|
||||
|
@ -234,13 +235,17 @@ uint16 *mosaic_table[16];
|
|||
void render_line();
|
||||
|
||||
void update_oam_status();
|
||||
/* Required functions */
|
||||
//required functions
|
||||
void run();
|
||||
void scanline();
|
||||
void render_scanline();
|
||||
void frame();
|
||||
void power();
|
||||
void reset();
|
||||
void set_frameskip(int fs);
|
||||
bool render_frame();
|
||||
|
||||
bool scanline_is_hires() { return (regs.bg_mode == 5 || regs.bg_mode == 6); }
|
||||
|
||||
bPPU();
|
||||
~bPPU();
|
||||
|
|
|
@ -393,6 +393,7 @@ void bPPU::mmio_w2130(uint8 value) {
|
|||
regs.color_mask = (value >> 6) & 3;
|
||||
regs.colorsub_mask = (value >> 4) & 3;
|
||||
regs.addsub_mode = !!(value & 0x02);
|
||||
regs.direct_color = !!(value & 0x01);
|
||||
}
|
||||
|
||||
//CGADDSUB
|
||||
|
@ -538,9 +539,9 @@ uint8 bPPU::mmio_r213d() {
|
|||
//STAT77
|
||||
uint8 bPPU::mmio_r213e() {
|
||||
uint8 r = 0x00;
|
||||
r |= (regs.time_over) ?0x80:0x00;
|
||||
r |= (regs.range_over)?0x40:0x00;
|
||||
r |= 0x01; //PPU1 version number
|
||||
r |= (regs.time_over) ? 0x80 : 0x00;
|
||||
r |= (regs.range_over) ? 0x40 : 0x00;
|
||||
r |= (ppu1_version & 0x0f);
|
||||
regs.ppu1_mdr = r;
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
@ -560,7 +561,7 @@ uint8 r = 0x00;
|
|||
}
|
||||
r |= (regs.ppu2_mdr & 0x20);
|
||||
r |= (region << 4); //0 = NTSC, 1 = PAL
|
||||
r |= 0x03; //PPU2 version number
|
||||
r |= (ppu2_version & 0x0f);
|
||||
regs.ppu2_mdr = r;
|
||||
return regs.ppu2_mdr;
|
||||
}
|
||||
|
|
|
@ -104,32 +104,30 @@ Mode7: ->
|
|||
1, 2, 3, 4, 5
|
||||
OAM0, BG1n, OAM1, OAM2, OAM3
|
||||
|
||||
***
|
||||
This appears to be incorrect, possibly should be...
|
||||
Mode 7 EXTBG: ->
|
||||
1, 2, 3, 4, 5, 6, 7
|
||||
BG2B, OAM0, BG1n, OAM1, BG2A, OAM2, OAM3
|
||||
***
|
||||
Mode 7 (extbg): ->
|
||||
1, 2, 3, 4, 5, 6
|
||||
BG2B, OAM0, OAM1, BG2A, OAM2, OAM3
|
||||
*/
|
||||
inline void bPPU::render_line_mode7() {
|
||||
if(regs.mode7_extbg == false) {
|
||||
render_line_mode7(2, 0, 0); //bg2 priorities are ignored
|
||||
render_line_mode7(BG1, 2, 2);
|
||||
render_line_oam(1, 3, 4, 5);
|
||||
} else {
|
||||
render_line_mode7(0, 1, 4); //bg1 priority is ignored
|
||||
render_line_oam(2, 3, 5, 6);
|
||||
render_line_mode7(BG1, 3, 3);
|
||||
render_line_mode7(BG2, 1, 5);
|
||||
render_line_oam(2, 4, 6, 7);
|
||||
}
|
||||
}
|
||||
|
||||
void bPPU::render_line() {
|
||||
if(regs.display_disabled == true) {
|
||||
memset(output->buffer + (_y << 10), 0, 2048);
|
||||
memset(snes->get_ppu_output_handle(), 0, 1024);
|
||||
return;
|
||||
}
|
||||
|
||||
clear_pixel_cache();
|
||||
build_color_window_tables();
|
||||
|
||||
switch(regs.bg_mode) {
|
||||
case 0:render_line_mode0();break;
|
||||
case 1:render_line_mode1();break;
|
||||
|
@ -140,5 +138,6 @@ void bPPU::render_line() {
|
|||
case 6:render_line_mode6();break;
|
||||
case 7:render_line_mode7();break;
|
||||
}
|
||||
|
||||
render_line_output();
|
||||
}
|
||||
|
|
|
@ -18,15 +18,17 @@ enum { TILE_2BIT = 0, TILE_4BIT = 1, TILE_8BIT = 2 };
|
|||
|
||||
enum { PC_BG1 = 0x80, PC_BG2 = 0x81, PC_BG3 = 0x82, PC_BG4 = 0x83, PC_OAM = 0x84, PC_BACK = 0x00 };
|
||||
struct _pixel {
|
||||
//palette # index for main/subscreen pixels
|
||||
//0 = transparent / use palette color # 0
|
||||
uint8 src_main, src_sub;
|
||||
//bgr555 color data for main/subscreen pixels: 0x0000 = transparent / use palette color # 0
|
||||
//needs to be bgr555 instead of palette index for direct color mode ($2130 bit 0) to work
|
||||
uint16 src_main, src_sub;
|
||||
//indicates source of palette # for main/subscreen (BG1-4, OAM, or back)
|
||||
uint8 bg_main, bg_sub;
|
||||
uint8 bg_main, bg_sub;
|
||||
//true when bg_main == OAM && palette index >= 192, disables color add/sub effects
|
||||
uint8 color_exempt;
|
||||
//priority level of src_n. to set src_n,
|
||||
//the priority of the pixel must be >pri_n
|
||||
uint8 pri_main, pri_sub;
|
||||
}pixel_cache[512];
|
||||
uint8 pri_main, pri_sub;
|
||||
} pixel_cache[512];
|
||||
|
||||
uint8 *bg_tiledata[3];
|
||||
uint8 *bg_tiledata_state[3];
|
||||
|
@ -55,7 +57,7 @@ uint8 oam_itemlist[32];
|
|||
struct oam_tileitem {
|
||||
uint16 x, y, pri, pal, tile;
|
||||
bool hflip;
|
||||
}oam_tilelist[34];
|
||||
} oam_tilelist[34];
|
||||
|
||||
enum { OAM_PRI_NONE = 4 };
|
||||
uint8 oam_line_pal[512], oam_line_pri[512];
|
||||
|
@ -66,15 +68,16 @@ void render_oam_tile(int tile_num);
|
|||
void render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos);
|
||||
|
||||
//bppu_render_mode7.cpp
|
||||
void render_line_mode7(uint8 bg1_pri, uint8 bg2b_pri, uint8 bg2a_pri);
|
||||
void render_line_mode7(uint8 bg, uint8 pri0_pos, uint8 pri1_pos);
|
||||
|
||||
//bppu_render_addsub.cpp
|
||||
inline uint16 addsub_pixels(int cdest_index, int cdest_bg, int csrc_index, int csrc_bg);
|
||||
inline uint16 addsub_pixel(int cdest_index, int cdest_bg);
|
||||
inline uint16 addsub_pixels(uint32 cdest, uint32 csrc);
|
||||
inline uint16 addsub_pixel (uint32 cdest);
|
||||
|
||||
//bppu_render_line.cpp
|
||||
enum { BLENDTYPE_BACK = 0, BLENDTYPE_MAIN = 1, BLENDTYPE_SUB = 2, BLENDTYPE_COMBINE = 3 };
|
||||
|
||||
inline uint16 get_palette(int index);
|
||||
inline uint16 get_palette(uint8 index);
|
||||
inline uint16 get_direct_color(uint8 p, uint8 t);
|
||||
inline uint16 get_pixel(int x);
|
||||
inline void render_line_output();
|
||||
|
|
|
@ -1,15 +1,6 @@
|
|||
inline uint16 bPPU::addsub_pixels(int cdest_index, int cdest_bg, int csrc_index, int csrc_bg) {
|
||||
inline uint16 bPPU::addsub_pixels(uint32 cdest, uint32 csrc) {
|
||||
int r, g, b;
|
||||
uint32 cdest = get_palette(cdest_index);
|
||||
uint32 csrc = get_palette(csrc_index);
|
||||
uint16 res;
|
||||
//oam palettes 0-3 are not affected by color add/sub
|
||||
if(cdest_bg == OAM) {
|
||||
if(cdest_index < 192) {
|
||||
return cdest;
|
||||
}
|
||||
}
|
||||
|
||||
switch(regs.color_mode) {
|
||||
case 0: //COLORMODE_ADD:
|
||||
if(regs.color_halve == true) {
|
||||
|
@ -53,18 +44,10 @@ uint16 res;
|
|||
return 0x0000; //prevent annoying warning message
|
||||
}
|
||||
|
||||
inline uint16 bPPU::addsub_pixel(int cdest_index, int cdest_bg) {
|
||||
inline uint16 bPPU::addsub_pixel(uint32 cdest) {
|
||||
int r, g, b;
|
||||
uint32 cdest = get_palette(cdest_index);
|
||||
uint32 csrc = (regs.color_r) | (regs.color_g << 5) | (regs.color_b << 10);
|
||||
uint16 res;
|
||||
//only oam palettes 4-7 are affected by color add/sub
|
||||
if(cdest_bg == OAM) {
|
||||
if(cdest_index < 192) {
|
||||
return cdest;
|
||||
}
|
||||
}
|
||||
|
||||
switch(regs.color_mode) {
|
||||
case 0: //COLORMODE_ADD:
|
||||
if(regs.color_halve == true && regs.addsub_mode == 0) {
|
||||
|
|
|
@ -3,7 +3,7 @@ void bPPU::render_line_bg(uint8 bg, uint8 color_depth, uint8 pri0_pos, uint8 pri
|
|||
return;
|
||||
}
|
||||
|
||||
int x;
|
||||
int x;
|
||||
int _scaddr = regs.bg_scaddr[bg];
|
||||
int _tdaddr = regs.bg_tdaddr[bg];
|
||||
bool _bg_enabled = regs.bg_enabled[bg];
|
||||
|
@ -25,17 +25,7 @@ uint16 opt_valid_bit; //offset-per-tile valid flag bit
|
|||
//entry point. This allows all 256 palette colors
|
||||
//to be used, instead of just the first 32.
|
||||
//entry = bg * 32, where 32 is from 8 * 4
|
||||
uint8 bgpal_index;
|
||||
if(regs.bg_mode == 0) {
|
||||
switch(bg) {
|
||||
case BG1:bgpal_index = 0;break;
|
||||
case BG2:bgpal_index = 32;break;
|
||||
case BG3:bgpal_index = 64;break;
|
||||
case BG4:bgpal_index = 96;break;
|
||||
}
|
||||
} else {
|
||||
bgpal_index = 0;
|
||||
}
|
||||
uint8 bgpal_index = (regs.bg_mode == 0) ? (bg << 5) : 0;
|
||||
|
||||
uint8 pal_size, tiledata_size;
|
||||
switch(color_depth) {
|
||||
|
@ -114,36 +104,43 @@ int mosaic_x, mosaic_y;
|
|||
} else {
|
||||
mtable = (uint16*)mosaic_table[0];
|
||||
}
|
||||
|
||||
mosaic_x = mtable[bg_x];
|
||||
mosaic_y = mtable[bg_y];
|
||||
|
||||
uint8 tile_x;
|
||||
uint16 t, base_xpos, base_pos, pos;
|
||||
uint16 tile_num;
|
||||
int mirror_x, mirror_y;
|
||||
uint8 pal_index;
|
||||
int mirror_x, mirror_y;
|
||||
uint8 pal_index, pal_num;
|
||||
uint8 *tile_ptr;
|
||||
int xpos, ypos;
|
||||
uint16 map_index, hoffset, voffset, col;
|
||||
|
||||
build_window_tables(bg);
|
||||
uint8 *wt_main = main_windowtable[bg];
|
||||
uint8 *wt_sub = sub_windowtable[bg];
|
||||
build_window_tables(bg);
|
||||
for(screen_x=0;screen_x<_screen_width;screen_x++) {
|
||||
//offset-per-tile mode. horizontal OPT is buggy, so it is disabled
|
||||
//vertical OPT seems to be working OK...
|
||||
|
||||
screen_x = 0;
|
||||
do { //for(screen_x=0;screen_x<_screen_width;screen_x++) {
|
||||
if(regs.bg_mode == 2 || regs.bg_mode == 4 || regs.bg_mode == 6) {
|
||||
if(regs.bg_mode == 6) {
|
||||
//hires adjust
|
||||
tile_x = (mtable[screen_x + (hscroll & 15)] >> 4);
|
||||
} else {
|
||||
tile_x = (mtable[screen_x + (hscroll & 7)] >> 3);
|
||||
}
|
||||
|
||||
hoffset = hscroll;
|
||||
voffset = vscroll;
|
||||
|
||||
//tile 0 is unaffected by OPT mode...
|
||||
if(tile_x != 0) {
|
||||
tile_x = (tile_x - 1) & 31;
|
||||
//multiply by two to index into 16-bit table entries
|
||||
tile_x = ((tile_x - 1) & 31) << 1;
|
||||
|
||||
if(regs.bg_mode == 4) {
|
||||
pos = regs.bg_scaddr[BG3] + (tile_x << 1);
|
||||
pos = regs.bg_scaddr[BG3] + tile_x;
|
||||
t = *((uint16*)vram + (pos >> 1));
|
||||
if(t & opt_valid_bit) {
|
||||
if(!(t & 0x8000)) {
|
||||
|
@ -153,18 +150,19 @@ uint8 *wt_sub = sub_windowtable[bg];
|
|||
}
|
||||
}
|
||||
} else {
|
||||
pos = regs.bg_scaddr[BG3] + (tile_x << 1);
|
||||
pos = regs.bg_scaddr[BG3] + tile_x;
|
||||
t = *((uint16*)vram + (pos >> 1));
|
||||
if(t & opt_valid_bit) {
|
||||
hoffset = ((t & 0x1ff8) | (hscroll & 7)) & screen_width_mask;
|
||||
}
|
||||
pos = regs.bg_scaddr[BG3] + 64 + (tile_x << 1);
|
||||
pos = regs.bg_scaddr[BG3] + 64 + tile_x;
|
||||
t = *((uint16*)vram + (pos >> 1));
|
||||
if(t & opt_valid_bit) {
|
||||
voffset = (t & 0x1fff) & screen_height_mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mosaic_x = mtable[(screen_x + hoffset) & screen_width_mask ];
|
||||
mosaic_y = mtable[(screen_y + voffset) & screen_height_mask];
|
||||
}
|
||||
|
@ -189,30 +187,36 @@ uint8 *wt_sub = sub_windowtable[bg];
|
|||
base_pos = (((mosaic_y >> tile_height) & 31) << 5) + ((mosaic_x >> tile_width) & 31);
|
||||
pos = _scaddr + map_index + (base_pos << 1);
|
||||
t = *((uint16*)vram + (pos >> 1));
|
||||
mirror_y = (t & 0x8000)?1:0;
|
||||
mirror_x = (t & 0x4000)?1:0;
|
||||
mirror_y = !!(t & 0x8000);
|
||||
mirror_x = !!(t & 0x4000);
|
||||
|
||||
int _pri;
|
||||
_pri = (t & 0x2000) ? pri1_pos : pri0_pos;
|
||||
|
||||
tile_num = t & 0x03ff;
|
||||
|
||||
//16x16 horizontal tile mirroring
|
||||
if(tile_width == 4) {
|
||||
if(((mosaic_x & 15) >= 8 && !mirror_x) ||
|
||||
((mosaic_x & 15) < 8 && mirror_x))tile_num++;
|
||||
tile_num &= 0x03ff;
|
||||
}
|
||||
|
||||
//16x16 vertical tile mirroring
|
||||
if(tile_height == 4) {
|
||||
if(((mosaic_y & 15) >= 8 && !mirror_y) ||
|
||||
((mosaic_y & 15) < 8 && mirror_y))tile_num += 16;
|
||||
tile_num &= 0x03ff;
|
||||
}
|
||||
|
||||
tile_num += (_tdaddr >> tiledata_size);
|
||||
|
||||
if(bg_td_state[tile_num] == 1) {
|
||||
render_bg_tile(color_depth, tile_num);
|
||||
}
|
||||
|
||||
pal_index = ((t >> 10) & 7) * pal_size + bgpal_index;
|
||||
pal_num = ((t >> 10) & 7);
|
||||
pal_index = pal_num * pal_size + bgpal_index;
|
||||
|
||||
if(mirror_y) { ypos = (7 - (mosaic_y & 7)); }
|
||||
else { ypos = ( (mosaic_y & 7)); }
|
||||
|
@ -220,23 +224,30 @@ int _pri;
|
|||
//loop while we are rendering from the same tile, as there's no need to do all of the above work
|
||||
//unless we have rendered all of the visible tile, taking mosaic into account.
|
||||
tile_ptr = (uint8*)bg_td + (tile_num << 6) + (ypos << 3);
|
||||
while(1) {
|
||||
do {
|
||||
if(mirror_x) { xpos = (7 - (mosaic_x & 7)); }
|
||||
else { xpos = ( (mosaic_x & 7)); }
|
||||
col = *(tile_ptr + xpos);
|
||||
if(col && main_colorwindowtable[screen_x]) {
|
||||
if(regs.direct_color == true && bg == BG1 && (regs.bg_mode == 3 || regs.bg_mode == 4)) {
|
||||
col = get_direct_color(pal_num, col);
|
||||
} else {
|
||||
col = get_palette(col + pal_index);
|
||||
}
|
||||
|
||||
if(_bg_enabled == true && !wt_main[screen_x]) {
|
||||
if(pixel_cache[screen_x].pri_main < _pri) {
|
||||
pixel_cache[screen_x].pri_main = _pri;
|
||||
pixel_cache[screen_x].bg_main = 0x80 | bg;
|
||||
pixel_cache[screen_x].src_main = col + pal_index;
|
||||
pixel_cache[screen_x].src_main = col;
|
||||
pixel_cache[screen_x].color_exempt = false;
|
||||
}
|
||||
}
|
||||
if(_bgsub_enabled == true && !wt_sub[screen_x]) {
|
||||
if(pixel_cache[screen_x].pri_sub < _pri) {
|
||||
pixel_cache[screen_x].pri_sub = _pri;
|
||||
pixel_cache[screen_x].bg_sub = 0x80 | bg;
|
||||
pixel_cache[screen_x].src_sub = col + pal_index;
|
||||
pixel_cache[screen_x].src_sub = col;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -246,8 +257,7 @@ int _pri;
|
|||
mosaic_x = mtable[bg_x];
|
||||
|
||||
if(base_xpos != ((mosaic_x >> 3) & 31))break;
|
||||
screen_x++;
|
||||
if(screen_x >= _screen_width)break;
|
||||
}
|
||||
}
|
||||
if(++screen_x >= _screen_width)break;
|
||||
} while(1);
|
||||
} while(++screen_x < _screen_width);
|
||||
}
|
||||
|
|
|
@ -1,36 +1,45 @@
|
|||
inline uint16 bPPU::get_palette(int index) {
|
||||
inline uint16 bPPU::get_palette(uint8 index) {
|
||||
return *((uint16*)cgram + index);
|
||||
}
|
||||
|
||||
inline uint16 bPPU::get_direct_color(uint8 p, uint8 t) {
|
||||
//p = 00000bgr
|
||||
//t = BBGGGRRR
|
||||
//r = 0BBb00GGGg0RRRr0
|
||||
return ((t & 7) << 2) | ((p & 1) << 1) |
|
||||
(((t >> 3) & 7) << 7) | (((p >> 1) & 1) << 6) |
|
||||
((t >> 6) << 13) | ((p >> 2) << 12);
|
||||
}
|
||||
|
||||
inline uint16 bPPU::get_pixel(int x) {
|
||||
_pixel *p = &pixel_cache[x];
|
||||
uint16 _r;
|
||||
uint16 _r, src_back = get_palette(0);
|
||||
if(p->bg_main && p->bg_sub) {
|
||||
if(regs.bg_color_enabled[p->bg_main & 0x7f] && sub_colorwindowtable[x]) {
|
||||
if(p->color_exempt == false && regs.bg_color_enabled[p->bg_main & 0x7f] && sub_colorwindowtable[x]) {
|
||||
if(regs.addsub_mode) {
|
||||
_r = addsub_pixels(p->src_main, p->bg_main & 0x7f, p->src_sub, p->bg_sub & 0x7f);
|
||||
_r = addsub_pixels(p->src_main, p->src_sub);
|
||||
} else {
|
||||
_r = addsub_pixel(p->src_main, p->bg_main & 0x7f);
|
||||
_r = addsub_pixel(p->src_main);
|
||||
}
|
||||
} else {
|
||||
_r = get_palette(p->src_main);
|
||||
_r = p->src_main;
|
||||
}
|
||||
} else if(p->bg_main) {
|
||||
if(regs.bg_color_enabled[p->bg_main & 0x7f] && sub_colorwindowtable[x]) {
|
||||
_r = addsub_pixel(p->src_main, p->bg_main & 0x7f);
|
||||
if(p->color_exempt == false && regs.bg_color_enabled[p->bg_main & 0x7f] && sub_colorwindowtable[x]) {
|
||||
_r = addsub_pixel(p->src_main);
|
||||
} else {
|
||||
_r = get_palette(p->src_main);
|
||||
_r = p->src_main;
|
||||
}
|
||||
} else if(p->bg_sub) {
|
||||
if(regs.bg_color_enabled[BACK]) {
|
||||
if(sub_colorwindowtable[x]) {
|
||||
if(regs.addsub_mode) {
|
||||
_r = addsub_pixels(0, BACK, p->src_sub, p->bg_sub & 0x7f);
|
||||
_r = addsub_pixels(src_back, p->src_sub);
|
||||
} else {
|
||||
_r = addsub_pixel(0, BACK);
|
||||
_r = addsub_pixel(src_back);
|
||||
}
|
||||
} else {
|
||||
_r = get_palette(0);
|
||||
_r = src_back;
|
||||
}
|
||||
} else {
|
||||
_r = 0x0000;
|
||||
|
@ -38,9 +47,9 @@ uint16 _r;
|
|||
} else {
|
||||
if(main_colorwindowtable[x]) {
|
||||
if(regs.bg_color_enabled[BACK] && sub_colorwindowtable[x]) {
|
||||
_r = addsub_pixel(0, BACK);
|
||||
_r = addsub_pixel(src_back);
|
||||
} else {
|
||||
_r = get_palette(0);
|
||||
_r = src_back;
|
||||
}
|
||||
} else {
|
||||
_r = 0x0000;
|
||||
|
@ -53,10 +62,7 @@ inline void bPPU::render_line_output() {
|
|||
int x;
|
||||
uint16 _r;
|
||||
uint16 *ptr;
|
||||
ptr = (uint16*)output->buffer + (_y << 10);
|
||||
if(_interlace == true) {
|
||||
ptr += _interlace_field << 9;
|
||||
}
|
||||
ptr = (uint16*)snes->get_ppu_output_handle();
|
||||
|
||||
uint16 *ltable;
|
||||
ltable = (uint16*)light_table + (regs.display_brightness << 15);
|
||||
|
@ -64,8 +70,7 @@ uint16 *ltable;
|
|||
if(_screen_width == 256) {
|
||||
for(x=0;x<256;x++) {
|
||||
_r = get_pixel(x);
|
||||
*ptr = *(ltable + _r);
|
||||
ptr += 2;
|
||||
*ptr++ = *(ltable + _r);
|
||||
}
|
||||
} else {
|
||||
for(x=0;x<512;x++) {
|
||||
|
|
|
@ -1,62 +1,72 @@
|
|||
#define CLIP_10BIT_SIGNED(x) \
|
||||
((x) & ((1 << 10) - 1)) + (((((x) & (1 << 13)) ^ (1 << 13)) - (1 << 13)) >> 3)
|
||||
/*
|
||||
bsnes mode7 renderer
|
||||
|
||||
#define CAST_WORDTOINT(x) \
|
||||
(int32)(((x & 0x8000) ? (x | 0xffff0000) : (x & 0x00007fff)))
|
||||
base algorithm written by anomie
|
||||
bsnes implementation written by byuu
|
||||
|
||||
supports mode 7 + extbg + rotate + zoom + direct color + scrolling + m7sel + windowing + mosaic
|
||||
does not support pseudo-hires
|
||||
interlace support is automatic via main rendering routine
|
||||
*/
|
||||
|
||||
//13-bit sign extend
|
||||
//--s---vvvvvvvvvv -> ssssssvvvvvvvvvv
|
||||
#define CLIP(x) ( ((x) & 0x2000) ? ( (x) | ~0x03ff) : ((x) & 0x03ff) )
|
||||
//#define CLIP(x) ( ((x) & 0x03ff) | (((x) & 0x2000) ? -0x0400 : 0) )
|
||||
|
||||
void bPPU::render_line_mode7(uint8 bg, uint8 pri0_pos, uint8 pri1_pos) {
|
||||
if(regs.bg_enabled[bg] == false && regs.bgsub_enabled[bg] == false)return;
|
||||
|
||||
int32 x, y;
|
||||
int32 a, b, c, d, cx, cy;
|
||||
int32 hofs, vofs;
|
||||
|
||||
void bPPU::render_line_mode7(uint8 bg1_pri, uint8 bg2b_pri, uint8 bg2a_pri) {
|
||||
int32 x;
|
||||
int32 step_m7a, step_m7c, m7a, m7b, m7c, m7d;
|
||||
int32 hoffset, voffset;
|
||||
int32 centerx, centery;
|
||||
int32 xx, yy;
|
||||
int32 px, py;
|
||||
int32 tx, ty, tile, palette;
|
||||
uint8 layer_pos;
|
||||
hoffset = ((int32)regs.m7_hofs << 19) >> 19;
|
||||
voffset = ((int32)regs.m7_vofs << 19) >> 19;
|
||||
a = int32(int16(regs.m7a));
|
||||
b = int32(int16(regs.m7b));
|
||||
c = int32(int16(regs.m7c));
|
||||
d = int32(int16(regs.m7d));
|
||||
|
||||
centerx = ((int32)regs.m7x << 19) >> 19;
|
||||
centery = ((int32)regs.m7y << 19) >> 19;
|
||||
cx = (int32(regs.m7x) << 19) >> 19;
|
||||
cy = (int32(regs.m7y) << 19) >> 19;
|
||||
hofs = (int32(regs.m7_hofs) << 19) >> 19;
|
||||
vofs = (int32(regs.m7_vofs + 1) << 19) >> 19;
|
||||
|
||||
int _pri, _x;
|
||||
bool _bg_enabled = regs.bg_enabled[bg];
|
||||
bool _bgsub_enabled = regs.bgsub_enabled[bg];
|
||||
|
||||
build_window_tables(bg);
|
||||
uint8 *wt_main = main_windowtable[bg];
|
||||
uint8 *wt_sub = sub_windowtable[bg];
|
||||
|
||||
if(regs.mode7_vflip == true) {
|
||||
yy = 255 - _y;
|
||||
y = 255 - _y;
|
||||
} else {
|
||||
yy = _y;
|
||||
}
|
||||
yy += CLIP_10BIT_SIGNED(voffset - centery);
|
||||
|
||||
m7b = CAST_WORDTOINT(regs.m7b) * yy + (centerx << 8);
|
||||
m7d = CAST_WORDTOINT(regs.m7d) * yy + (centery << 8);
|
||||
|
||||
step_m7a = CAST_WORDTOINT(regs.m7a);
|
||||
step_m7c = CAST_WORDTOINT(regs.m7c);
|
||||
|
||||
xx = CLIP_10BIT_SIGNED(hoffset - centerx);
|
||||
|
||||
m7a = CAST_WORDTOINT(regs.m7a) * xx;
|
||||
m7c = CAST_WORDTOINT(regs.m7c) * xx;
|
||||
|
||||
int _pri, _x, _bg;
|
||||
bool _bg_enabled, _bgsub_enabled;
|
||||
if(regs.mode7_extbg == false) {
|
||||
_pri = bg1_pri;
|
||||
_bg = BG1;
|
||||
_bg_enabled = regs.bg_enabled[BG1];
|
||||
_bgsub_enabled = regs.bgsub_enabled[BG1];
|
||||
} else {
|
||||
_bg = BG2;
|
||||
_bg_enabled = regs.bg_enabled[BG2];
|
||||
_bgsub_enabled = regs.bgsub_enabled[BG2];
|
||||
y = _y;
|
||||
}
|
||||
|
||||
uint8 *wt_main = main_windowtable[_bg];
|
||||
uint8 *wt_sub = sub_windowtable[_bg];
|
||||
build_window_tables(_bg);
|
||||
uint16 *mtable_x, *mtable_y;
|
||||
if(bg == BG1) {
|
||||
mtable_x = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? regs.mosaic_size : 0];
|
||||
mtable_y = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? regs.mosaic_size : 0];
|
||||
} else { //bg == BG2
|
||||
//Mode7 EXTBG BG2 uses BG1 mosaic enable to control vertical mosaic,
|
||||
//and BG2 mosaic enable to control horizontal mosaic...
|
||||
mtable_x = (uint16*)mosaic_table[(regs.mosaic_enabled[BG2] == true) ? regs.mosaic_size : 0];
|
||||
mtable_y = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? regs.mosaic_size : 0];
|
||||
}
|
||||
|
||||
int32 psx = ((a * CLIP(hofs - cx)) & ~63) + ((b * CLIP(vofs - cy)) & ~63) + ((b * mtable_y[y]) & ~63) + (cx << 8);
|
||||
int32 psy = ((c * CLIP(hofs - cx)) & ~63) + ((d * CLIP(vofs - cy)) & ~63) + ((d * mtable_y[y]) & ~63) + (cy << 8);
|
||||
for(x=0;x<256;x++) {
|
||||
px = ((m7a + m7b) >> 8);
|
||||
py = ((m7c + m7d) >> 8);
|
||||
px = psx + (a * mtable_x[x]);
|
||||
py = psy + (c * mtable_x[x]);
|
||||
|
||||
//mask floating-point bits (low 8 bits)
|
||||
px >>= 8;
|
||||
py >>= 8;
|
||||
|
||||
switch(regs.mode7_repeat) {
|
||||
case 0: //screen repitition outside of screen area
|
||||
|
@ -68,20 +78,7 @@ uint8 *wt_sub = sub_windowtable[_bg];
|
|||
tile = vram[(ty * 128 + tx) << 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
break;
|
||||
case 2: //character 0 repetition outside of screen area
|
||||
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
|
||||
tx = 0;
|
||||
ty = 0;
|
||||
} else {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
}
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
break;
|
||||
case 3: //palette color 0 outside of screen area
|
||||
case 2: //palette color 0 outside of screen area
|
||||
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
|
||||
palette = 0;
|
||||
} else {
|
||||
|
@ -93,46 +90,61 @@ uint8 *wt_sub = sub_windowtable[_bg];
|
|||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
}
|
||||
break;
|
||||
case 3: //character 0 repetition outside of screen area
|
||||
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
|
||||
tile = 0;
|
||||
} else {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
}
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
break;
|
||||
}
|
||||
|
||||
if(!palette)goto _end_setpixel;
|
||||
|
||||
if(regs.mode7_extbg == false) {
|
||||
//_pri set at top of function, as it is static
|
||||
if(regs.mode7_hflip == true) {
|
||||
_x = 255 - x;
|
||||
} else {
|
||||
_x = x;
|
||||
}
|
||||
if(bg == BG1) {
|
||||
_pri = pri0_pos;
|
||||
} else {
|
||||
_pri = (palette >> 7) ? bg2a_pri : bg2b_pri;
|
||||
_pri = (palette >> 7) ? pri1_pos : pri0_pos;
|
||||
palette &= 0x7f;
|
||||
if(regs.mode7_hflip == true) {
|
||||
_x = 255 - x;
|
||||
} else {
|
||||
_x = x;
|
||||
}
|
||||
}
|
||||
|
||||
if(!palette)continue;
|
||||
|
||||
if(regs.mode7_hflip == true) {
|
||||
_x = 255 - x;
|
||||
} else {
|
||||
_x = x;
|
||||
}
|
||||
|
||||
if(main_colorwindowtable[_x]) {
|
||||
if(_bg_enabled == true && !wt_main[_x]) {
|
||||
uint32 col;
|
||||
if(regs.direct_color == true && bg == BG1) {
|
||||
//direct color mode does not apply to bg2, as it is only 128 colors...
|
||||
col = get_direct_color(0, palette);
|
||||
} else {
|
||||
col = get_palette(palette);
|
||||
}
|
||||
|
||||
if(regs.bg_enabled[bg] == true && !wt_main[_x]) {
|
||||
if(pixel_cache[_x].pri_main < _pri) {
|
||||
pixel_cache[_x].pri_main = _pri;
|
||||
pixel_cache[_x].bg_main = 0x80 | _bg;
|
||||
pixel_cache[_x].src_main = palette;
|
||||
pixel_cache[_x].bg_main = 0x80 | bg;
|
||||
pixel_cache[_x].src_main = col;
|
||||
pixel_cache[_x].color_exempt = false;
|
||||
}
|
||||
}
|
||||
if(_bgsub_enabled == true && !wt_sub[_x]) {
|
||||
if(regs.bgsub_enabled[bg] == true && !wt_sub[_x]) {
|
||||
if(pixel_cache[_x].pri_sub < _pri) {
|
||||
pixel_cache[_x].pri_sub = _pri;
|
||||
pixel_cache[_x].bg_sub = 0x80 | _bg;
|
||||
pixel_cache[_x].src_sub = palette;
|
||||
pixel_cache[_x].bg_sub = 0x80 | bg;
|
||||
pixel_cache[_x].src_sub = col;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_end_setpixel:
|
||||
m7a += step_m7a;
|
||||
m7c += step_m7c;
|
||||
}
|
||||
}
|
||||
|
||||
#undef CLIP
|
||||
|
|
|
@ -256,14 +256,15 @@ int _pri;
|
|||
if(pixel_cache[x].pri_main < _pri) {
|
||||
pixel_cache[x].pri_main = _pri;
|
||||
pixel_cache[x].bg_main = PC_OAM;
|
||||
pixel_cache[x].src_main = oam_line_pal[x];
|
||||
pixel_cache[x].src_main = get_palette(oam_line_pal[x]);
|
||||
pixel_cache[x].color_exempt = (oam_line_pal[x] < 192);
|
||||
}
|
||||
}
|
||||
if(_bgsub_enabled == true && !wt_sub[x]) {
|
||||
if(pixel_cache[x].pri_sub < _pri) {
|
||||
pixel_cache[x].pri_sub = _pri;
|
||||
pixel_cache[x].bg_sub = PC_OAM;
|
||||
pixel_cache[x].src_sub = oam_line_pal[x];
|
||||
pixel_cache[x].src_sub = get_palette(oam_line_pal[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
#define CLIP_10BIT_SIGNED(x) \
|
||||
((x) & ((1 << 10) - 1)) + (((((x) & (1 << 13)) ^ (1 << 13)) - (1 << 13)) >> 3)
|
||||
|
||||
#define CAST_WORDTOINT(x) \
|
||||
(int32)((((x) & 0x8000) ? ((x) | 0xffff0000) : ((x) & 0x00007fff)))
|
||||
|
||||
void bPPU::render_line_mode7(uint8 bg, uint8 pri0_pos, uint8 pri1_pos) {
|
||||
int32 x;
|
||||
int32 step_m7a, step_m7c, m7a, m7b, m7c, m7d;
|
||||
int32 hoffset, voffset;
|
||||
int32 centerx, centery;
|
||||
int32 xx, yy;
|
||||
int32 px, py;
|
||||
int32 tx, ty, tile, palette;
|
||||
uint8 layer_pos;
|
||||
if(regs.bg_enabled[bg] == false && regs.bgsub_enabled[bg] == false)return;
|
||||
|
||||
uint16 *mtable_x, *mtable_y;
|
||||
if(bg == BG1) {
|
||||
mtable_x = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? regs.mosaic_size : 0];
|
||||
mtable_y = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? regs.mosaic_size : 0];
|
||||
} else { //bg == BG2
|
||||
//Mode7 EXTBG BG2 uses BG1 mosaic enable to control vertical mosaic,
|
||||
//and BG2 mosaic enable to control horizontal mosaic...
|
||||
mtable_x = (uint16*)mosaic_table[(regs.mosaic_enabled[BG2] == true) ? regs.mosaic_size : 0];
|
||||
mtable_y = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? regs.mosaic_size : 0];
|
||||
}
|
||||
|
||||
hoffset = ((int32)regs.m7_hofs << 19) >> 19;
|
||||
voffset = ((int32)regs.m7_vofs << 19) >> 19;
|
||||
|
||||
centerx = ((int32)regs.m7x << 19) >> 19;
|
||||
centery = ((int32)regs.m7y << 19) >> 19;
|
||||
|
||||
if(regs.mode7_vflip == true) {
|
||||
yy = 255 - _y;
|
||||
} else {
|
||||
yy = _y;
|
||||
}
|
||||
yy = mtable_y[yy];
|
||||
yy += CLIP_10BIT_SIGNED(voffset - centery);
|
||||
|
||||
m7b = CAST_WORDTOINT(regs.m7b) * yy + (centerx << 8);
|
||||
m7d = CAST_WORDTOINT(regs.m7d) * yy + (centery << 8);
|
||||
|
||||
step_m7a = CAST_WORDTOINT(regs.m7a);
|
||||
step_m7c = CAST_WORDTOINT(regs.m7c);
|
||||
|
||||
xx = CLIP_10BIT_SIGNED(hoffset - centerx);
|
||||
|
||||
m7a = CAST_WORDTOINT(regs.m7a) * xx;
|
||||
m7c = CAST_WORDTOINT(regs.m7c) * xx;
|
||||
|
||||
int _pri, _x;
|
||||
bool _bg_enabled, _bgsub_enabled;
|
||||
_bg_enabled = regs.bg_enabled[bg];
|
||||
_bgsub_enabled = regs.bgsub_enabled[bg];
|
||||
|
||||
build_window_tables(bg);
|
||||
uint8 *wt_main = main_windowtable[bg];
|
||||
uint8 *wt_sub = sub_windowtable[bg];
|
||||
|
||||
for(x=0;x<256;x++) {
|
||||
px = ((m7a + step_m7a * mtable_x[x] + m7b) >> 8);
|
||||
py = ((m7c + step_m7c * mtable_x[x] + m7d) >> 8);
|
||||
|
||||
switch(regs.mode7_repeat) {
|
||||
case 0: //screen repitition outside of screen area
|
||||
case 1: //same as case 0
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
break;
|
||||
case 2: //palette color 0 outside of screen area
|
||||
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
|
||||
palette = 0;
|
||||
} else {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
}
|
||||
break;
|
||||
case 3: //character 0 repetition outside of screen area
|
||||
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
|
||||
tx = 0;
|
||||
ty = 0;
|
||||
} else {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
}
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
break;
|
||||
}
|
||||
|
||||
if(bg == BG1) {
|
||||
_pri = pri0_pos;
|
||||
} else {
|
||||
_pri = (palette >> 7) ? pri1_pos : pri0_pos;
|
||||
palette &= 0x7f;
|
||||
}
|
||||
|
||||
if(!palette)continue;
|
||||
|
||||
if(regs.mode7_hflip == true) {
|
||||
_x = 255 - x;
|
||||
} else {
|
||||
_x = x;
|
||||
}
|
||||
|
||||
if(main_colorwindowtable[_x]) {
|
||||
uint32 col;
|
||||
if(regs.direct_color == true && bg == BG1) {
|
||||
//direct color mode does not apply to bg2 as it is only 128 colors...
|
||||
col = get_direct_color(0, palette);
|
||||
} else {
|
||||
col = get_palette(palette);
|
||||
}
|
||||
|
||||
if(regs.bg_enabled[bg] == true && !wt_main[_x]) {
|
||||
if(pixel_cache[_x].pri_main < _pri) {
|
||||
pixel_cache[_x].pri_main = _pri;
|
||||
pixel_cache[_x].bg_main = 0x80 | bg;
|
||||
pixel_cache[_x].src_main = col;
|
||||
pixel_cache[_x].color_exempt = false;
|
||||
}
|
||||
}
|
||||
if(regs.bgsub_enabled[bg] == true && !wt_sub[_x]) {
|
||||
if(pixel_cache[_x].pri_sub < _pri) {
|
||||
pixel_cache[_x].pri_sub = _pri;
|
||||
pixel_cache[_x].bg_sub = 0x80 | bg;
|
||||
pixel_cache[_x].src_sub = col;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef CLIP_10BIT_SIGNED
|
||||
#undef CAST_WORDTOINT
|
|
@ -1,27 +1,17 @@
|
|||
#include "../base.h"
|
||||
|
||||
PPUOutput::PPUOutput() {
|
||||
buffer = (uint16*)memalloc(512 * 478 * 2, "PPUOutput::buffer");
|
||||
memset(buffer, 0, 512 * 478 * 2);
|
||||
hires = false;
|
||||
interlace = false;
|
||||
for(int i=0;i<239;i++) {
|
||||
line[i].hires = false;
|
||||
line[i].interlace = false;
|
||||
}
|
||||
}
|
||||
|
||||
PPUOutput::~PPUOutput() {
|
||||
if(buffer)memfree(buffer, "PPUOutput::buffer");
|
||||
void PPU::get_scanline_info(scanline_info *info) {
|
||||
info->hires = scanline_is_hires();
|
||||
info->interlace = cpu->interlace();
|
||||
}
|
||||
|
||||
void PPU::set_frameskip(int fs) {}
|
||||
bool PPU::render_frame() { return true; }
|
||||
|
||||
PPU::PPU() {
|
||||
ppu1_version = 1;
|
||||
ppu2_version = 3;
|
||||
mmio = &mmio_unmapped;
|
||||
output = new PPUOutput();
|
||||
}
|
||||
|
||||
PPU::~PPU() {
|
||||
if(output)delete(output);
|
||||
}
|
||||
PPU::~PPU() {}
|
||||
|
|
|
@ -1,19 +1,25 @@
|
|||
class PPUOutput {
|
||||
public:
|
||||
bool hires, interlace;
|
||||
struct {
|
||||
bool hires, interlace;
|
||||
}line[239];
|
||||
uint16 *buffer;
|
||||
PPUOutput();
|
||||
~PPUOutput();
|
||||
};
|
||||
|
||||
class PPU {
|
||||
public:
|
||||
int _y;
|
||||
PPUOutput *output;
|
||||
MMIO *mmio;
|
||||
//PPU1 version number
|
||||
//* 1 is known
|
||||
//* reported by $213e
|
||||
uint8 ppu1_version;
|
||||
|
||||
//PPU2 version number
|
||||
//* 1 and 3 are known
|
||||
//* reported by $213f
|
||||
uint8 ppu2_version;
|
||||
|
||||
int _y;
|
||||
MMIO *mmio;
|
||||
|
||||
struct scanline_info {
|
||||
bool hires;
|
||||
bool interlace;
|
||||
};
|
||||
virtual bool scanline_is_hires() = 0;
|
||||
virtual void get_scanline_info(scanline_info *info);
|
||||
|
||||
virtual uint8 vram_read (uint16 addr) = 0;
|
||||
virtual void vram_write (uint16 addr, uint8 value) = 0;
|
||||
virtual uint8 oam_read (uint16 addr) = 0;
|
||||
|
@ -25,10 +31,12 @@ MMIO *mmio;
|
|||
|
||||
virtual void run() = 0;
|
||||
virtual void scanline() = 0;
|
||||
virtual void render_scanline() = 0;
|
||||
virtual void frame() = 0;
|
||||
virtual void power() = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual void set_frameskip(int fs);
|
||||
virtual bool render_frame();
|
||||
|
||||
PPU();
|
||||
~PPU();
|
||||
|
|
|
@ -6,6 +6,7 @@ OBJS = sdlmain.o \
|
|||
memory.o bmemory.o \
|
||||
cpu.o bcpu.o \
|
||||
apu.o bapu.o bapuskip.o \
|
||||
bdsp.o \
|
||||
ppu.o bppu.o \
|
||||
snes.o \
|
||||
srtc.o sdd1.o
|
||||
|
@ -60,6 +61,12 @@ bapu.o: ../apu/bapu/*
|
|||
bapuskip.o: ../apu/bapuskip/*
|
||||
$(CC) $(CFLAGS) -c ../apu/bapuskip/bapuskip.cpp
|
||||
|
||||
###########
|
||||
### dsp ###
|
||||
###########
|
||||
bdsp.o: ../dsp/bdsp/*
|
||||
$(CC) $(CFLAGS) -c ../dsp/bdsp/bdsp.cpp
|
||||
|
||||
###########
|
||||
### ppu ###
|
||||
###########
|
||||
|
|
|
@ -6,6 +6,7 @@ OBJS = sdlmain.obj \
|
|||
memory.obj bmemory.obj \
|
||||
cpu.obj bcpu.obj \
|
||||
apu.obj bapu.obj bapuskip.obj \
|
||||
bdsp.obj \
|
||||
ppu.obj bppu.obj \
|
||||
snes.obj \
|
||||
srtc.obj sdd1.obj
|
||||
|
@ -61,6 +62,12 @@ bapu.obj: ../apu/bapu/*
|
|||
bapuskip.obj: ../apu/bapuskip/*
|
||||
$(CC) $(CFLAGS) /c ../apu/bapuskip/bapuskip.cpp
|
||||
|
||||
###########
|
||||
### dsp ###
|
||||
###########
|
||||
bdsp.obj: ../dsp/bdsp/*
|
||||
$(CC) $(CFLAGS) /c ../dsp/bdsp/bdsp.cpp
|
||||
|
||||
###########
|
||||
### ppu ###
|
||||
###########
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
void bSNES::set_status(uint32 new_status) { run_status = new_status; }
|
||||
uint32 bSNES::get_status() { return run_status; }
|
||||
|
||||
void bSNES::snes_run() {
|
||||
void bSNES::run() {
|
||||
if(!rom_image->loaded())return;
|
||||
|
||||
switch(run_status) {
|
||||
case RUN:
|
||||
while(update_frame == false) {
|
||||
run();
|
||||
SNES::run();
|
||||
}
|
||||
update_frame = false;
|
||||
render();
|
||||
|
@ -17,7 +17,8 @@ void bSNES::snes_run() {
|
|||
}
|
||||
}
|
||||
|
||||
void bSNES::render_frame() {}
|
||||
void bSNES::video_run() { render(); }
|
||||
void bSNES::sound_run() {}
|
||||
|
||||
/***********************
|
||||
*** Input functions ***
|
||||
|
@ -28,18 +29,18 @@ void bSNES::render_frame() {}
|
|||
//to throw error messages about a bad free call to stdout...
|
||||
void bSNES::poll_input() {
|
||||
uint8 *keystate = SDL_GetKeyState(0);
|
||||
joypad1.up = keystate[cfg.input.joypad1.up];
|
||||
joypad1.down = keystate[cfg.input.joypad1.down];
|
||||
joypad1.left = keystate[cfg.input.joypad1.left];
|
||||
joypad1.right = keystate[cfg.input.joypad1.right];
|
||||
joypad1.select = keystate[cfg.input.joypad1.select];
|
||||
joypad1.start = keystate[cfg.input.joypad1.start];
|
||||
joypad1.y = keystate[cfg.input.joypad1.y];
|
||||
joypad1.b = keystate[cfg.input.joypad1.b];
|
||||
joypad1.x = keystate[cfg.input.joypad1.x];
|
||||
joypad1.a = keystate[cfg.input.joypad1.a];
|
||||
joypad1.l = keystate[cfg.input.joypad1.l];
|
||||
joypad1.r = keystate[cfg.input.joypad1.r];
|
||||
joypad1.up = keystate[(int)config::input.joypad1.up];
|
||||
joypad1.down = keystate[(int)config::input.joypad1.down];
|
||||
joypad1.left = keystate[(int)config::input.joypad1.left];
|
||||
joypad1.right = keystate[(int)config::input.joypad1.right];
|
||||
joypad1.select = keystate[(int)config::input.joypad1.select];
|
||||
joypad1.start = keystate[(int)config::input.joypad1.start];
|
||||
joypad1.y = keystate[(int)config::input.joypad1.y];
|
||||
joypad1.b = keystate[(int)config::input.joypad1.b];
|
||||
joypad1.x = keystate[(int)config::input.joypad1.x];
|
||||
joypad1.a = keystate[(int)config::input.joypad1.a];
|
||||
joypad1.l = keystate[(int)config::input.joypad1.l];
|
||||
joypad1.r = keystate[(int)config::input.joypad1.r];
|
||||
|
||||
//It's impossible to hold both up+down, or left+right down
|
||||
//at the same time on a directional pad; and besides, allowing
|
||||
|
|
|
@ -14,10 +14,12 @@ bJoypad joypad1, joypad2;
|
|||
|
||||
public:
|
||||
enum { STOP = 0, RUN };
|
||||
void run();
|
||||
void video_run();
|
||||
void sound_run();
|
||||
|
||||
void set_status(uint32 new_status);
|
||||
uint32 get_status();
|
||||
void snes_run();
|
||||
void render_frame();
|
||||
|
||||
//input functions
|
||||
void poll_input();
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
apu.enabled = true
|
||||
video.fullscreen = false
|
||||
video.display_width = 256
|
||||
video.display_height = 223
|
||||
video.output_width = 256
|
||||
video.output_height = 223
|
||||
input.joypad1.up = 0x111
|
||||
input.joypad1.down = 0x112
|
||||
input.joypad1.left = 0x114
|
||||
input.joypad1.right = 0x113
|
||||
input.joypad1.a = 0x78
|
||||
input.joypad1.b = 0x7a
|
||||
input.joypad1.x = 0x73
|
||||
input.joypad1.y = 0x61
|
||||
input.joypad1.l = 0x64
|
||||
input.joypad1.r = 0x63
|
||||
input.joypad1.select = 0x12f
|
||||
input.joypad1.start = 0x0d
|
|
@ -1,3 +1,2 @@
|
|||
@nmake /NOLOGO /f Makefile.win32
|
||||
@move bsnes_sdl.exe ../../bsnes_sdl.exe>nul
|
||||
@pause
|
|
@ -1,47 +1,32 @@
|
|||
#define __config_add(name, def, type) add(&name, #name, def, type)
|
||||
namespace config {
|
||||
|
||||
class Config : public config {
|
||||
public:
|
||||
struct Video {
|
||||
static Setting fullscreen;
|
||||
static Setting display_width, display_height;
|
||||
static Setting output_width, output_height;
|
||||
} video;
|
||||
Setting Video::fullscreen(&config_file, "video.fullscreen", "Enable fullscreen mode at startup", false, Setting::TRUE_FALSE);
|
||||
Setting Video::display_width (&config_file, "video.display_width", "Window / Fullscreen width", 320, Setting::DEC);
|
||||
Setting Video::display_height(&config_file, "video.display_height", "Window / Fullscreen height", 240, Setting::DEC);
|
||||
Setting Video::output_width (&config_file, "video.output_width", "SNES video output width", 256, Setting::DEC);
|
||||
Setting Video::output_height (&config_file, "video.output_height", "SNES video output height", 223, Setting::DEC);
|
||||
|
||||
struct {
|
||||
uint32 enabled;
|
||||
}apu;
|
||||
struct Input {
|
||||
struct Joypad {
|
||||
static Setting up, down, left, right, a, b, x, y, l, r, select, start;
|
||||
} joypad1;
|
||||
} input;
|
||||
Setting Input::Joypad::up (&config_file, "input.joypad1.up", "Joypad1 up", SDLK_UP, Setting::HEX);
|
||||
Setting Input::Joypad::down (&config_file, "input.joypad1.down", "Joypad1 down", SDLK_DOWN, Setting::HEX);
|
||||
Setting Input::Joypad::left (&config_file, "input.joypad1.left", "Joypad1 left", SDLK_LEFT, Setting::HEX);
|
||||
Setting Input::Joypad::right (&config_file, "input.joypad1.right", "Joypad1 right", SDLK_RIGHT, Setting::HEX);
|
||||
Setting Input::Joypad::a (&config_file, "input.joypad1.a", "Joypad1 A", SDLK_x, Setting::HEX);
|
||||
Setting Input::Joypad::b (&config_file, "input.joypad1.b", "Joypad1 B", SDLK_z, Setting::HEX);
|
||||
Setting Input::Joypad::x (&config_file, "input.joypad1.x", "Joypad1 X", SDLK_s, Setting::HEX);
|
||||
Setting Input::Joypad::y (&config_file, "input.joypad1.y", "Joypad1 Y", SDLK_a, Setting::HEX);
|
||||
Setting Input::Joypad::l (&config_file, "input.joypad1.l", "Joypad1 L", SDLK_d, Setting::HEX);
|
||||
Setting Input::Joypad::r (&config_file, "input.joypad1.r", "Joypad1 R", SDLK_c, Setting::HEX);
|
||||
Setting Input::Joypad::select(&config_file, "input.joypad1.select", "Joypad1 select", SDLK_RSHIFT, Setting::HEX);
|
||||
Setting Input::Joypad::start (&config_file, "input.joypad1.start", "Joypad1 start", SDLK_RETURN, Setting::HEX);
|
||||
|
||||
struct {
|
||||
uint32 fullscreen;
|
||||
uint32 display_width, display_height;
|
||||
uint32 output_width, output_height;
|
||||
}video;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
uint32 up, down, left, right;
|
||||
uint32 a, b, x, y, l, r;
|
||||
uint32 select, start;
|
||||
}joypad1;
|
||||
}input;
|
||||
|
||||
Config() {
|
||||
__config_add(apu.enabled, true, TRUEFALSE);
|
||||
|
||||
__config_add(video.fullscreen, false, TRUEFALSE);
|
||||
__config_add(video.display_width, 256, DEC);
|
||||
__config_add(video.display_height, 223, DEC);
|
||||
__config_add(video.output_width, 256, DEC);
|
||||
__config_add(video.output_height, 223, DEC);
|
||||
|
||||
__config_add(input.joypad1.up, SDLK_UP, HEX);
|
||||
__config_add(input.joypad1.down, SDLK_DOWN, HEX);
|
||||
__config_add(input.joypad1.left, SDLK_LEFT, HEX);
|
||||
__config_add(input.joypad1.right, SDLK_RIGHT, HEX);
|
||||
__config_add(input.joypad1.a, SDLK_x, HEX);
|
||||
__config_add(input.joypad1.b, SDLK_z, HEX);
|
||||
__config_add(input.joypad1.x, SDLK_s, HEX);
|
||||
__config_add(input.joypad1.y, SDLK_a, HEX);
|
||||
__config_add(input.joypad1.l, SDLK_d, HEX);
|
||||
__config_add(input.joypad1.r, SDLK_c, HEX);
|
||||
__config_add(input.joypad1.select, SDLK_RSHIFT, HEX);
|
||||
__config_add(input.joypad1.start, SDLK_RETURN, HEX);
|
||||
}
|
||||
|
||||
}cfg;
|
||||
};
|
||||
|
|
|
@ -1,87 +1,49 @@
|
|||
uint8 color_curve_table[32];
|
||||
uint32 color_lookup_table[65536];
|
||||
|
||||
void update_color_lookup_table() {
|
||||
int i, r, g, b, c;
|
||||
for(i=0,c=0;i<16;i++) {
|
||||
color_curve_table[i] = c;
|
||||
c = c + i + 1;
|
||||
}
|
||||
for(;i<31;i++) {
|
||||
color_curve_table[i] = c;
|
||||
c += 8;
|
||||
}
|
||||
color_curve_table[i] = 0xff;
|
||||
|
||||
int color_depth = 16;
|
||||
if(color_depth == 15) {
|
||||
for(i=0;i<65536;i++) {
|
||||
r = (i ) & 31;
|
||||
g = (i >> 5) & 31;
|
||||
b = (i >> 10) & 31;
|
||||
r = color_curve_table[r] >> 3;
|
||||
g = color_curve_table[g] >> 3;
|
||||
b = color_curve_table[b] >> 3;
|
||||
color_lookup_table[i] = (r << 10) | (g << 5) | (b);
|
||||
}
|
||||
} else if(color_depth == 16) {
|
||||
for(i=0;i<65536;i++) {
|
||||
r = (i ) & 31;
|
||||
g = (i >> 5) & 31;
|
||||
b = (i >> 10) & 31;
|
||||
r = color_curve_table[r] >> 3;
|
||||
g = color_curve_table[g] >> 2;
|
||||
b = color_curve_table[b] >> 3;
|
||||
color_lookup_table[i] = (r << 11) | (g << 5) | (b);
|
||||
}
|
||||
} else if(color_depth == 32) {
|
||||
for(i=0;i<65536;i++) {
|
||||
r = (i ) & 31;
|
||||
g = (i >> 5) & 31;
|
||||
b = (i >> 10) & 31;
|
||||
r = color_curve_table[r];
|
||||
g = color_curve_table[g];
|
||||
b = color_curve_table[b];
|
||||
color_lookup_table[i] = (r << 16) | (g << 8) | (b);
|
||||
}
|
||||
} else {
|
||||
alert("Error: Unsupported color depth [%d]", color_depth);
|
||||
}
|
||||
}
|
||||
|
||||
void render16() {
|
||||
uint16 *src, *dest;
|
||||
uint16 *dest, *src;
|
||||
uint32 pitch;
|
||||
int x, y;
|
||||
pitch = (backbuffer->pitch >> 1) - 256;
|
||||
src = (uint16*)ppu->output->buffer + (1 << 10);
|
||||
|
||||
SNES::video_info vi;
|
||||
snes->get_video_info(&vi);
|
||||
|
||||
pitch = (backbuffer->pitch >> 1);
|
||||
dest = (uint16*)backbuffer->pixels;
|
||||
for(y=0;y<223;y++) {
|
||||
for(x=0;x<256;x++) {
|
||||
*dest++ = color_lookup_table[*src];
|
||||
src += 2;
|
||||
src = (uint16*)vi.data;
|
||||
|
||||
if(vi.width == 256 && vi.height == 224) {
|
||||
for(y=0;y<224;y++) {
|
||||
memcpy(dest, src, 512);
|
||||
dest += pitch;
|
||||
src += 256;
|
||||
}
|
||||
} else if(vi.width == 512 && vi.height == 224) {
|
||||
for(y=0;y<224;y++) {
|
||||
memcpy(dest, src, 1024);
|
||||
dest += pitch;
|
||||
src += 512;
|
||||
}
|
||||
} else if(vi.width == 256 && vi.height == 448) {
|
||||
for(y=0;y<448;y++) {
|
||||
memcpy(dest, src, 512);
|
||||
dest += pitch;
|
||||
src += 256;
|
||||
}
|
||||
} else if(vi.width == 512 && vi.height == 448) {
|
||||
for(y=0;y<448;y++) {
|
||||
memcpy(dest, src, 1024);
|
||||
dest += pitch;
|
||||
src += 512;
|
||||
}
|
||||
dest += pitch;
|
||||
src += 512;
|
||||
}
|
||||
|
||||
|
||||
screen_info.rs.x = 0;
|
||||
screen_info.rs.y = (vi.height == 224) ? 1 : 2;
|
||||
screen_info.rs.w = vi.width;
|
||||
screen_info.rs.h = (vi.height == 224) ? 223 : 446;
|
||||
}
|
||||
|
||||
void render32() {
|
||||
uint16 *src;
|
||||
uint32 *dest, pitch;
|
||||
int x, y;
|
||||
pitch = (screen->pitch >> 2) - 256;
|
||||
src = (uint16*)ppu->output->buffer + (1 << 10);
|
||||
dest = (uint32*)screen->pixels;
|
||||
for(y=0;y<223;y++) {
|
||||
for(x=0;x<256;x++) {
|
||||
*dest++ = color_lookup_table[*src];
|
||||
src += 2;
|
||||
}
|
||||
dest += pitch;
|
||||
src += 512;
|
||||
}
|
||||
}
|
||||
void render32() {}
|
||||
|
||||
void render() {
|
||||
if(SDL_MUSTLOCK(screen)) {
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
#define INTERFACE_MAIN
|
||||
#define BSNES_VERSION "0.011"
|
||||
#define BSNES_TITLE "bsnes/SDL v" BSNES_VERSION
|
||||
#include "../base.h"
|
||||
#include "sdlmain.h"
|
||||
|
||||
#include "config.cpp"
|
||||
|
||||
#ifdef _WIN32_
|
||||
HWND hwnd;
|
||||
#endif
|
||||
|
||||
#include "config.cpp"
|
||||
#include "bsnes.h"
|
||||
#include "rom.cpp"
|
||||
#include "render.cpp"
|
||||
|
@ -47,24 +46,31 @@ va_list args;
|
|||
void init_snes() {
|
||||
mem_bus = new bMemBus();
|
||||
cpu = new bCPU();
|
||||
if(cfg.apu.enabled) {
|
||||
apu = new bAPU();
|
||||
} else {
|
||||
apu = new bAPUSkip();
|
||||
}
|
||||
apu = new bAPU();
|
||||
dsp = new bDSP();
|
||||
ppu = new bPPU();
|
||||
snes = new bSNES();
|
||||
bsnes = static_cast<bSNES*>(snes);
|
||||
|
||||
snes->init();
|
||||
|
||||
//TODO: add sound support and remove this,
|
||||
//this is used with linux/bsd and mkfifo to
|
||||
//play audio in real-time while sound output
|
||||
//isn't available.
|
||||
snes->log_audio_enable("output.wav");
|
||||
|
||||
snes->set_playback_buffer_size(2000);
|
||||
}
|
||||
|
||||
void term_snes() {
|
||||
if(mem_bus) { delete(mem_bus); mem_bus = 0; }
|
||||
if(cpu) { delete(cpu); cpu = 0; }
|
||||
if(apu) { delete(apu); apu = 0; }
|
||||
if(ppu) { delete(ppu); ppu = 0; }
|
||||
if(snes) { delete(snes); snes = 0; }
|
||||
snes->term();
|
||||
|
||||
if(mem_bus) { delete(static_cast<bMemBus*>(mem_bus)); mem_bus = 0; }
|
||||
if(cpu) { delete(static_cast<bCPU*> (cpu)); cpu = 0; }
|
||||
if(apu) { delete(static_cast<bAPU*> (apu)); apu = 0; }
|
||||
if(ppu) { delete(static_cast<bPPU*> (ppu)); ppu = 0; }
|
||||
if(snes) { delete(static_cast<bSNES*> (snes)); snes = 0; }
|
||||
}
|
||||
|
||||
void center_window() {
|
||||
|
@ -82,22 +88,17 @@ void set_window_info() {
|
|||
//SDL won't draw anything if you blit an image that's larger than
|
||||
//the display mode/window, even if you use the SoftStretch blit and
|
||||
//clip the source + dest rectangles properly...
|
||||
if(cfg.video.display_width < cfg.video.output_width) {
|
||||
cfg.video.display_width = cfg.video.output_width;
|
||||
if((int)config::video.display_width < (int)config::video.output_width) {
|
||||
config::video.display_width = config::video.output_width;
|
||||
}
|
||||
if(cfg.video.display_height < cfg.video.output_height) {
|
||||
cfg.video.display_height = cfg.video.output_height;
|
||||
if((int)config::video.display_height < (int)config::video.output_height) {
|
||||
config::video.display_height = config::video.output_height;
|
||||
}
|
||||
|
||||
screen_info.rd.x = (cfg.video.display_width - cfg.video.output_width ) >> 1;
|
||||
screen_info.rd.y = (cfg.video.display_height - cfg.video.output_height) >> 1;
|
||||
screen_info.rd.w = cfg.video.output_width;
|
||||
screen_info.rd.h = cfg.video.output_height;
|
||||
|
||||
screen_info.rs.x = 0;
|
||||
screen_info.rs.y = 0;
|
||||
screen_info.rs.w = 256;
|
||||
screen_info.rs.h = 223;
|
||||
screen_info.rd.x = ((int)config::video.display_width - (int)config::video.output_width ) >> 1;
|
||||
screen_info.rd.y = ((int)config::video.display_height - (int)config::video.output_height) >> 1;
|
||||
screen_info.rd.w = config::video.output_width;
|
||||
screen_info.rd.h = config::video.output_height;
|
||||
}
|
||||
|
||||
#ifdef _WIN32_
|
||||
|
@ -115,14 +116,13 @@ SDL_Event event;
|
|||
return 0;
|
||||
}
|
||||
|
||||
cfg.load("bsnes_sdl.cfg");
|
||||
config_file.load("bsnes_sdl.cfg");
|
||||
|
||||
rom_image = new ROMImage();
|
||||
init_snes();
|
||||
|
||||
rom_image->select(argv[1]);
|
||||
rom_image->load();
|
||||
snes->power();
|
||||
|
||||
if(rom_image->loaded() == false) {
|
||||
alert("Failed to load image. Usage: bsnes_sdl <filename.smc>");
|
||||
|
@ -132,13 +132,11 @@ SDL_Event event;
|
|||
SDL_Init(SDL_INIT_VIDEO);
|
||||
atexit(SDL_Quit);
|
||||
set_window_info();
|
||||
screen = SDL_SetVideoMode(cfg.video.display_width, cfg.video.display_height, 16,
|
||||
SDL_SWSURFACE | ((cfg.video.fullscreen)?SDL_FULLSCREEN:0));
|
||||
if(!screen) {
|
||||
alert("Failed to initialize SDL");
|
||||
goto _end;
|
||||
}
|
||||
backbuffer = SDL_CreateRGBSurface(SDL_SWSURFACE, 256, 223, 16, 0xf800, 0x07e0, 0x001f, 0x0000);
|
||||
screen = SDL_SetVideoMode(config::video.display_width, config::video.display_height, 16,
|
||||
SDL_SWSURFACE | ((config::video.fullscreen)?SDL_FULLSCREEN:0));
|
||||
if(!screen) { alert("Failed to initialize SDL"); goto _end; }
|
||||
backbuffer = SDL_CreateRGBSurface(SDL_SWSURFACE, 512, 448, 16, 0xf800, 0x07e0, 0x001f, 0x0000);
|
||||
if(!backbuffer) { alert("Failed to initialize SDL"); goto _end; }
|
||||
|
||||
SDL_WM_SetCaption(BSNES_TITLE, 0);
|
||||
#ifdef _WIN32_
|
||||
|
@ -146,18 +144,21 @@ SDL_Event event;
|
|||
#endif
|
||||
center_window();
|
||||
|
||||
update_color_lookup_table();
|
||||
snes->power();
|
||||
bsnes->set_status(bSNES::RUN);
|
||||
|
||||
int cursor_status;
|
||||
while(1) {
|
||||
bsnes->snes_run();
|
||||
bsnes->run();
|
||||
while(SDL_PollEvent(&event)) {
|
||||
switch(event.type) {
|
||||
case SDL_KEYUP:
|
||||
switch(event.key.keysym.sym) {
|
||||
case SDLK_ESCAPE:
|
||||
goto _end;
|
||||
case SDLK_BACKSPACE:
|
||||
snes->capture_screenshot();
|
||||
break;
|
||||
case SDLK_F10: //toggle cursor display
|
||||
cursor_status = (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE)?SDL_DISABLE:SDL_ENABLE;
|
||||
SDL_ShowCursor(cursor_status);
|
||||
|
@ -174,7 +175,7 @@ int cursor_status;
|
|||
}
|
||||
|
||||
_end:
|
||||
cfg.save("bsnes_sdl.cfg");
|
||||
config_file.save("bsnes_sdl.cfg");
|
||||
term_snes();
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -13,5 +13,5 @@
|
|||
SDL_Surface *screen, *backbuffer;
|
||||
|
||||
struct {
|
||||
SDL_Rect rs, rd;
|
||||
}screen_info;
|
||||
SDL_Rect rs, rd;
|
||||
} screen_info;
|
||||
|
|
|
@ -1 +1 @@
|
|||
c:\root\bsnes_g2\bsnes_sdl.exe c:\root\bsnes_testrom\zelda_us.smc
|
||||
bsnes_sdl c:\root\bsnes_testrom\zelda_us.smc
|
|
@ -1,24 +1,48 @@
|
|||
#include "../base.h"
|
||||
|
||||
#include "snes_video.cpp"
|
||||
#include "snes_audio.cpp"
|
||||
#include "snes_input.cpp"
|
||||
|
||||
void SNES::run() {
|
||||
uint32 cycles;
|
||||
uint32 cycles, r;
|
||||
if(apusync.cycles < 0) {
|
||||
cpu->run();
|
||||
apusync.cycles += apusync.apu_multbl[cpu->cycles_executed()];
|
||||
} else {
|
||||
apu->run();
|
||||
apusync.cycles -= apusync.cpu_multbl[apu->cycles_executed()];
|
||||
cycles = apu->cycles_executed();
|
||||
apusync.dsp += cycles;
|
||||
apusync.cycles -= apusync.cpu_multbl[cycles];
|
||||
|
||||
//1024000(SPC700) / 32000(DSP) = 32spc/dsp ticks
|
||||
//24576000(Sound clock crystal) / 32000(DSP) = 768crystal/dsp ticks
|
||||
while(apusync.dsp >= 768) {
|
||||
apusync.dsp -= 768;
|
||||
audio_update(dsp->run());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SNES::init() {
|
||||
srtc = new SRTC();
|
||||
sdd1 = new SDD1();
|
||||
|
||||
srtc->init();
|
||||
sdd1->init();
|
||||
|
||||
video_init();
|
||||
audio_init();
|
||||
}
|
||||
|
||||
void SNES::term() {
|
||||
audio_term();
|
||||
}
|
||||
|
||||
void SNES::power() {
|
||||
cpu->power();
|
||||
apu->power();
|
||||
dsp->power();
|
||||
ppu->power();
|
||||
mem_bus->power();
|
||||
|
||||
|
@ -30,16 +54,19 @@ int i;
|
|||
for(i=0x2100;i<=0x213f;i++)mem_bus->set_mmio_mapper(i, ppu->mmio);
|
||||
for(i=0x2140;i<=0x217f;i++)mem_bus->set_mmio_mapper(i, cpu->mmio);
|
||||
for(i=0x2180;i<=0x2183;i++)mem_bus->set_mmio_mapper(i, cpu->mmio);
|
||||
//S-RTC
|
||||
mem_bus->set_mmio_mapper(0x2800, srtc->mmio);
|
||||
mem_bus->set_mmio_mapper(0x2801, srtc->mmio);
|
||||
//input
|
||||
mem_bus->set_mmio_mapper(0x4000, cpu->mmio); //test -- remove this
|
||||
mem_bus->set_mmio_mapper(0x4016, cpu->mmio);
|
||||
mem_bus->set_mmio_mapper(0x4017, cpu->mmio);
|
||||
for(i=0x4200;i<=0x421f;i++)mem_bus->set_mmio_mapper(i, cpu->mmio);
|
||||
for(i=0x4300;i<=0x437f;i++)mem_bus->set_mmio_mapper(i, cpu->mmio);
|
||||
//S-DD1
|
||||
for(i=0x4800;i<=0x4807;i++)mem_bus->set_mmio_mapper(i, sdd1->mmio);
|
||||
|
||||
srtc->enable();
|
||||
sdd1->enable();
|
||||
|
||||
memset(video.data, 0, 512 * 448 * sizeof(uint32));
|
||||
memset(video.ppu_data, 0, 512 * 480 * sizeof(uint16));
|
||||
video_update();
|
||||
}
|
||||
|
||||
void SNES::reset() {
|
||||
|
@ -47,13 +74,30 @@ void SNES::reset() {
|
|||
|
||||
cpu->reset();
|
||||
apu->reset();
|
||||
dsp->reset();
|
||||
ppu->reset();
|
||||
mem_bus->reset();
|
||||
|
||||
srtc->reset();
|
||||
sdd1->reset();
|
||||
|
||||
memset(video.data, 0, 512 * 448 * sizeof(uint32));
|
||||
memset(video.ppu_data, 0, 512 * 480 * sizeof(uint16));
|
||||
video_update();
|
||||
}
|
||||
|
||||
void SNES::frame() {
|
||||
video_update();
|
||||
}
|
||||
|
||||
void SNES::scanline() {
|
||||
video_scanline();
|
||||
}
|
||||
|
||||
/****************
|
||||
*** PAL/NTSC ***
|
||||
****************/
|
||||
|
||||
void SNES::set_region(uint8 new_region) {
|
||||
if(new_region == NTSC) {
|
||||
snes_region = NTSC;
|
||||
|
@ -68,6 +112,10 @@ void SNES::set_region(uint8 new_region) {
|
|||
|
||||
uint8 SNES::region() { return snes_region; }
|
||||
|
||||
/**************
|
||||
*** Timing ***
|
||||
**************/
|
||||
|
||||
void SNES::update_timing() {
|
||||
apusync.cycles = 0;
|
||||
if(snes_region == NTSC) {
|
||||
|
@ -87,6 +135,7 @@ int i;
|
|||
/***************************
|
||||
*** Debugging functions ***
|
||||
***************************/
|
||||
|
||||
void SNES::notify(uint32 message, uint32 param1, uint32 param2) {}
|
||||
|
||||
void SNES::debugger_enable() {
|
||||
|
@ -102,8 +151,10 @@ bool SNES::debugger_enabled() {
|
|||
}
|
||||
|
||||
SNES::SNES() {
|
||||
is_debugger_enabled = true;
|
||||
is_debugger_enabled = false;
|
||||
|
||||
snes_region = NTSC;
|
||||
update_timing();
|
||||
|
||||
dsp_buffer.data = 0;
|
||||
}
|
||||
|
|
|
@ -6,10 +6,12 @@ uint8 snes_region;
|
|||
|
||||
//APU synchronization
|
||||
struct {
|
||||
int32 cpu_freq, apu_freq;
|
||||
int32 cpu_multbl[1024], apu_multbl[1024];
|
||||
int32 cycles;
|
||||
}apusync;
|
||||
int32 cpu_freq, apu_freq;
|
||||
int32 cpu_multbl[1024], apu_multbl[1024];
|
||||
int32 cycles;
|
||||
|
||||
int32 dsp;
|
||||
} apusync;
|
||||
|
||||
void update_timing();
|
||||
|
||||
|
@ -17,29 +19,22 @@ public:
|
|||
enum { NTSC = 0, PAL = 1 };
|
||||
|
||||
//system functions
|
||||
void run();
|
||||
virtual void render_frame() = 0;
|
||||
virtual void init();
|
||||
virtual void power();
|
||||
virtual void reset();
|
||||
virtual uint8 region();
|
||||
virtual void set_region(uint8 new_region);
|
||||
virtual void run();
|
||||
virtual void init();
|
||||
virtual void term();
|
||||
virtual void power();
|
||||
virtual void reset();
|
||||
|
||||
//input functions
|
||||
enum {
|
||||
DEV_JOYPAD1 = 0,
|
||||
DEV_JOYPAD2 = 1
|
||||
};
|
||||
enum {
|
||||
JOYPAD_B = 0, JOYPAD_Y = 1,
|
||||
JOYPAD_SELECT = 2, JOYPAD_START = 3,
|
||||
JOYPAD_UP = 4, JOYPAD_DOWN = 5,
|
||||
JOYPAD_LEFT = 6, JOYPAD_RIGHT = 7,
|
||||
JOYPAD_A = 8, JOYPAD_X = 9,
|
||||
JOYPAD_L = 10, JOYPAD_R = 11
|
||||
};
|
||||
virtual void poll_input() = 0;
|
||||
virtual bool get_input_status(uint8 device, uint8 button) = 0;
|
||||
virtual void frame();
|
||||
virtual void scanline();
|
||||
|
||||
//PAL/NTSC
|
||||
uint8 region();
|
||||
void set_region(uint8 new_region);
|
||||
|
||||
#include "snes_video.h"
|
||||
#include "snes_audio.h"
|
||||
#include "snes_input.h"
|
||||
|
||||
//debugging functions
|
||||
enum {
|
||||
|
@ -53,10 +48,12 @@ enum {
|
|||
OAM_READ, OAM_WRITE,
|
||||
CGRAM_READ, CGRAM_WRITE,
|
||||
};
|
||||
virtual void notify(uint32 message, uint32 param1 = 0, uint32 param2 = 0);
|
||||
virtual void debugger_enable();
|
||||
virtual void debugger_disable();
|
||||
virtual bool debugger_enabled();
|
||||
|
||||
//message functions
|
||||
virtual void notify(uint32 message, uint32 param1 = 0, uint32 param2 = 0);
|
||||
|
||||
SNES();
|
||||
};
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
void SNES::set_playback_buffer_size(uint32 buffer_size) {
|
||||
if(dsp_buffer.data) {
|
||||
free(dsp_buffer.data);
|
||||
dsp_buffer.data = 0;
|
||||
}
|
||||
|
||||
//* 2 is for left/right channel data
|
||||
dsp_buffer.data = (uint16*)malloc(buffer_size * sizeof(uint16) * 2);
|
||||
memset(dsp_buffer.data, 0, buffer_size * sizeof(uint16) * 2);
|
||||
|
||||
dsp_buffer.size = buffer_size;
|
||||
dsp_buffer.pos = 0;
|
||||
}
|
||||
|
||||
uint32 SNES::get_playback_buffer_pos() {
|
||||
return dsp_buffer.pos;
|
||||
}
|
||||
|
||||
uint16 *SNES::get_playback_buffer() {
|
||||
return dsp_buffer.data;
|
||||
}
|
||||
|
||||
void SNES::audio_update(uint32 data) {
|
||||
if(pcmfp) {
|
||||
fputc(data, pcmfp);
|
||||
fputc(data >> 8, pcmfp);
|
||||
fputc(data >> 16, pcmfp);
|
||||
fputc(data >> 24, pcmfp);
|
||||
}
|
||||
|
||||
if((bool)config::snes.mute == true)data = 0x0000;
|
||||
|
||||
dsp_buffer.data[dsp_buffer.pos++] = (data) & 0xffff;
|
||||
dsp_buffer.data[dsp_buffer.pos++] = (data >> 16) & 0xffff;
|
||||
dsp_buffer.pos %= dsp_buffer.size;
|
||||
|
||||
sound_run();
|
||||
}
|
||||
|
||||
void SNES::log_audio_enable(const char *fn) {
|
||||
char tfn[256];
|
||||
int i;
|
||||
if(pcmfp)log_audio_disable();
|
||||
|
||||
if(!fn) {
|
||||
for(i=0;i<=999;i++) {
|
||||
sprintf(tfn, "audio%0.3d.wav", i);
|
||||
pcmfp = fopen(tfn, "rb");
|
||||
if(!pcmfp)break;
|
||||
fclose(pcmfp);
|
||||
pcmfp = 0;
|
||||
}
|
||||
if(i >= 1000)return;
|
||||
} else {
|
||||
strcpy(tfn, fn);
|
||||
}
|
||||
|
||||
pcmfp = fopen(tfn, "wb");
|
||||
if(!pcmfp)return;
|
||||
|
||||
//header
|
||||
fwrite("RIFF", 1, 4, pcmfp);
|
||||
//file size
|
||||
fputc(0, pcmfp);
|
||||
fputc(0, pcmfp);
|
||||
fputc(0, pcmfp);
|
||||
fputc(0, pcmfp);
|
||||
//format
|
||||
fwrite("WAVE", 1, 4, pcmfp);
|
||||
fwrite("fmt ", 1, 4, pcmfp);
|
||||
//fmt size
|
||||
fputc(0x12, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
//fmt type (PCM)
|
||||
fputc(1, pcmfp);
|
||||
fputc(0, pcmfp);
|
||||
//channels
|
||||
fputc(2, pcmfp);
|
||||
fputc(0, pcmfp);
|
||||
//sample rate (32000hz)
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0x7d, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
//byte rate (32000 * 2 * (16 / 8)
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0xf4, pcmfp);
|
||||
fputc(0x01, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
//block align (bytes per sample) (4)
|
||||
fputc(4, pcmfp);
|
||||
fputc(0, pcmfp);
|
||||
//???
|
||||
fputc(0x10, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
fwrite("fact", 1, 4, pcmfp);
|
||||
fputc(0x04, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
fputc(0x0b, pcmfp);
|
||||
fputc(0xf4, pcmfp);
|
||||
fputc(0x01, pcmfp);
|
||||
fputc(0x00, pcmfp);
|
||||
//data
|
||||
fwrite("data", 1, 4, pcmfp);
|
||||
//data size
|
||||
fputc(0, pcmfp);
|
||||
fputc(0, pcmfp);
|
||||
fputc(0, pcmfp);
|
||||
fputc(0, pcmfp);
|
||||
}
|
||||
|
||||
void SNES::log_audio_disable() {
|
||||
if(pcmfp) {
|
||||
int fsize, t;
|
||||
fseek(pcmfp, 0, SEEK_END);
|
||||
fsize = ftell(pcmfp);
|
||||
fseek(pcmfp, 4, SEEK_SET);
|
||||
t = fsize - 2;
|
||||
fputc(t, pcmfp);
|
||||
fputc(t >> 8, pcmfp);
|
||||
fputc(t >> 16, pcmfp);
|
||||
fputc(t >> 24, pcmfp);
|
||||
fseek(pcmfp, 0x36, SEEK_SET);
|
||||
t = fsize - 0x3a;
|
||||
fputc(t, pcmfp);
|
||||
fputc(t >> 8, pcmfp);
|
||||
fputc(t >> 16, pcmfp);
|
||||
fputc(t >> 24, pcmfp);
|
||||
fclose(pcmfp);
|
||||
pcmfp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SNES::audio_init() {
|
||||
}
|
||||
|
||||
void SNES::audio_term() {
|
||||
log_audio_disable();
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
struct {
|
||||
uint16 *data;
|
||||
uint32 size, pos;
|
||||
} dsp_buffer;
|
||||
|
||||
FILE *pcmfp;
|
||||
|
||||
//buffer_size is in samples
|
||||
void set_playback_buffer_size(uint32 buffer_size);
|
||||
uint32 get_playback_buffer_pos();
|
||||
uint16 *get_playback_buffer();
|
||||
|
||||
//if a filename is not specified, one will be generated
|
||||
//automatically ("audio%0.3d.wav")
|
||||
void log_audio_enable(const char *fn = 0);
|
||||
void log_audio_disable();
|
||||
|
||||
void audio_update(uint32 data);
|
||||
void audio_init();
|
||||
void audio_term();
|
||||
|
||||
virtual void sound_run() = 0;
|
|
@ -0,0 +1,21 @@
|
|||
enum {
|
||||
DEV_JOYPAD1 = 0,
|
||||
DEV_JOYPAD2 = 1
|
||||
};
|
||||
|
||||
enum {
|
||||
JOYPAD_B = 0, JOYPAD_Y = 1,
|
||||
JOYPAD_SELECT = 2, JOYPAD_START = 3,
|
||||
JOYPAD_UP = 4, JOYPAD_DOWN = 5,
|
||||
JOYPAD_LEFT = 6, JOYPAD_RIGHT = 7,
|
||||
JOYPAD_A = 8, JOYPAD_X = 9,
|
||||
JOYPAD_L = 10, JOYPAD_R = 11
|
||||
};
|
||||
|
||||
//The CPU calls poll_input() when the main interface should check the
|
||||
//status of all joypad buttons and cache the results...
|
||||
virtual void poll_input() = 0;
|
||||
|
||||
//...and then the CPU calls get_input_status() whenever it needs one
|
||||
//of the cached button values to be returned for emulation purposes.
|
||||
virtual bool get_input_status(uint8 device, uint8 button) = 0;
|
|
@ -0,0 +1,385 @@
|
|||
#include "snes_video_ex.cpp"
|
||||
|
||||
const uint8 SNES::color_curve_table[32] = {
|
||||
0x00, 0x01, 0x03, 0x06, 0x0a, 0x0f, 0x15, 0x1c,
|
||||
0x24, 0x2d, 0x37, 0x42, 0x4e, 0x5b, 0x69, 0x78,
|
||||
0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0,
|
||||
0xc8, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, 0xff
|
||||
};
|
||||
|
||||
void SNES::update_color_lookup_table() {
|
||||
int i, l, r, g, b;
|
||||
double lr = 0.2126, lg = 0.7152, lb = 0.0722; //luminance
|
||||
switch(video.depth) {
|
||||
case 15: //rgb565
|
||||
for(i=0;i<32768;i++) {
|
||||
r = (i ) & 31;
|
||||
g = (i >> 5) & 31;
|
||||
b = (i >> 10) & 31;
|
||||
|
||||
if((bool)config::snes.video_color_curve == true) {
|
||||
r = color_curve_table[r] >> 3;
|
||||
g = color_curve_table[g] >> 3;
|
||||
b = color_curve_table[b] >> 3;
|
||||
}
|
||||
|
||||
if((int)config::snes.video_color_adjust_mode == VCA_GRAYSCALE) {
|
||||
r = (r << 3) | (r >> 2);
|
||||
g = (g << 3) | (g >> 2);
|
||||
b = (b << 3) | (b >> 2);
|
||||
|
||||
l = int((double)r * lr) + ((double)g * lg) + ((double)b * lb);
|
||||
if(l < 0)l = 0;
|
||||
if(l > 255)l = 255;
|
||||
r = g = b = l;
|
||||
|
||||
r >>= 3;
|
||||
g >>= 3;
|
||||
b >>= 3;
|
||||
} else if((int)config::snes.video_color_adjust_mode == VCA_VGA) {
|
||||
//rgb555->rgb332
|
||||
r >>= 2;
|
||||
g >>= 2;
|
||||
b >>= 3;
|
||||
|
||||
r = (r << 2) | (r >> 1);
|
||||
g = (g << 2) | (g >> 1);
|
||||
b = (b << 3) | (b << 1) | (b >> 1);
|
||||
} else if((int)config::snes.video_color_adjust_mode == VCA_GENESIS) {
|
||||
//rgb555->rgb333
|
||||
r >>= 2;
|
||||
g >>= 2;
|
||||
b >>= 2;
|
||||
|
||||
r = (r << 2) | (r >> 1);
|
||||
g = (g << 2) | (g >> 1);
|
||||
b = (b << 2) | (b >> 1);
|
||||
}
|
||||
|
||||
color_lookup_table[i] = (r << 10) | (g << 5) | (b);
|
||||
}
|
||||
break;
|
||||
case 16: //rgb565
|
||||
for(i=0;i<32768;i++) {
|
||||
r = (i ) & 31;
|
||||
g = (i >> 5) & 31;
|
||||
b = (i >> 10) & 31;
|
||||
|
||||
if((bool)config::snes.video_color_curve == true) {
|
||||
r = color_curve_table[r] >> 3;
|
||||
g = color_curve_table[g] >> 2;
|
||||
b = color_curve_table[b] >> 3;
|
||||
} else {
|
||||
g = (g << 1) | (g >> 4);
|
||||
}
|
||||
|
||||
if((int)config::snes.video_color_adjust_mode == VCA_GRAYSCALE) {
|
||||
r = (r << 3) | (r >> 2);
|
||||
g = (g << 2) | (g >> 4);
|
||||
b = (b << 3) | (b >> 2);
|
||||
|
||||
l = int((double)r * lr) + ((double)g * lg) + ((double)b * lb);
|
||||
if(l < 0)l = 0;
|
||||
if(l > 255)l = 255;
|
||||
r = g = b = l;
|
||||
|
||||
r >>= 3;
|
||||
g >>= 2;
|
||||
b >>= 3;
|
||||
} else if((int)config::snes.video_color_adjust_mode == VCA_VGA) {
|
||||
//rgb565->rgb332
|
||||
r >>= 2;
|
||||
g >>= 3;
|
||||
b >>= 3;
|
||||
|
||||
r = (r << 2) | (r >> 1);
|
||||
g = (g << 3) | (g);
|
||||
b = (b << 3) | (b << 1) | (b >> 1);
|
||||
} else if((int)config::snes.video_color_adjust_mode == VCA_GENESIS) {
|
||||
//rgb565->rgb333
|
||||
r >>= 2;
|
||||
g >>= 3;
|
||||
b >>= 2;
|
||||
|
||||
r = (r << 2) | (r >> 1);
|
||||
g = (g << 3) | (g);
|
||||
b = (b << 2) | (b >> 1);
|
||||
}
|
||||
|
||||
color_lookup_table[i] = (r << 11) | (g << 5) | (b);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
alert("Error: SNES::update_color_lookup_table() -- color depth %d not supported", video.depth);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SNES::set_video_format(uint8 mode, uint8 depth) {
|
||||
//only make changes at the start of a new frame
|
||||
video.format_changed = true;
|
||||
|
||||
video_changed.mode = mode;
|
||||
video_changed.depth = depth;
|
||||
}
|
||||
|
||||
//internal function called at the start of the frame
|
||||
//after SNES::set_video_format() is called
|
||||
void SNES::update_video_format() {
|
||||
video.mode = video_changed.mode;
|
||||
video.depth = video_changed.depth;
|
||||
|
||||
update_color_lookup_table();
|
||||
video.format_changed = false;
|
||||
}
|
||||
|
||||
void SNES::get_video_info(video_info *info) {
|
||||
info->data = video.data;
|
||||
info->mode = video.mode;
|
||||
|
||||
switch(video.mode) {
|
||||
case VM_256x224:
|
||||
info->width = 256;
|
||||
info->height = 224;
|
||||
break;
|
||||
case VM_512x224:
|
||||
info->width = 512;
|
||||
info->height = 224;
|
||||
break;
|
||||
case VM_256x448:
|
||||
info->width = 256;
|
||||
info->height = 448;
|
||||
break;
|
||||
case VM_512x448:
|
||||
info->width = 512;
|
||||
info->height = 448;
|
||||
break;
|
||||
case VM_VARIABLE:
|
||||
if(video.frame_hires == false) {
|
||||
info->width = 256;
|
||||
} else {
|
||||
info->width = 512;
|
||||
}
|
||||
|
||||
if(video.frame_interlace == false) {
|
||||
info->height = 224;
|
||||
} else {
|
||||
info->height = 448;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SNES::video_update_256x224(uint16 *src) {
|
||||
int x, y;
|
||||
uint16 *dest;
|
||||
dest = video.data;
|
||||
|
||||
for(y=0;y<224;y++) {
|
||||
if(video_frame[y].hires == false) {
|
||||
for(x=0;x<256;x++) {
|
||||
*dest++ = color_lookup_table[*src++];
|
||||
}
|
||||
src += 768;
|
||||
} else {
|
||||
for(x=0;x<256;x++) {
|
||||
*dest++ = color_lookup_table[*src];
|
||||
src += 2;
|
||||
}
|
||||
src += 512;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SNES::video_update_512x224(uint16 *src) {
|
||||
int x, y;
|
||||
uint16 *dest;
|
||||
dest = video.data;
|
||||
|
||||
for(y=0;y<224;y++) {
|
||||
if(video_frame[y].hires == false) {
|
||||
for(x=0;x<256;x++) {
|
||||
*dest++ = color_lookup_table[*src];
|
||||
*dest++ = color_lookup_table[*src++];
|
||||
}
|
||||
src += 768;
|
||||
} else {
|
||||
for(x=0;x<512;x++) {
|
||||
*dest++ = color_lookup_table[*src++];
|
||||
}
|
||||
src += 512;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SNES::video_update_256x448(uint16 *src) {
|
||||
int x, y;
|
||||
uint16 *dest;
|
||||
bool field = !cpu->interlace_field();
|
||||
dest = video.data;
|
||||
|
||||
for(y=0;y<224;y++) {
|
||||
if(video_frame[y].interlace == false) {
|
||||
if(video_frame[y].hires == false) {
|
||||
for(x=0;x<512;x++) {
|
||||
*dest++ = color_lookup_table[*(src + (uint8)x)];
|
||||
}
|
||||
src += 1024;
|
||||
} else {
|
||||
for(x=0;x<512;x++) {
|
||||
*dest++ = color_lookup_table[*(src + ((x & 255) << 1))];
|
||||
}
|
||||
src += 1024;
|
||||
}
|
||||
} else {
|
||||
if(field) {
|
||||
dest += 256;
|
||||
src += 512;
|
||||
}
|
||||
|
||||
if(video_frame[y].hires == false) {
|
||||
for(x=0;x<256;x++) {
|
||||
*dest++ = color_lookup_table[*src++];
|
||||
}
|
||||
src += 256;
|
||||
} else {
|
||||
for(x=0;x<256;x++) {
|
||||
*dest++ = color_lookup_table[*src];
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if(!field) {
|
||||
dest += 256;
|
||||
src += 512;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SNES::video_update_512x448(uint16 *src) {
|
||||
int x, y;
|
||||
uint16 *dest;
|
||||
bool field = !cpu->interlace_field();
|
||||
dest = video.data;
|
||||
|
||||
for(y=0;y<224;y++) {
|
||||
if(video_frame[y].interlace == false) {
|
||||
if(video_frame[y].hires == false) {
|
||||
for(x=0;x<512;x++) {
|
||||
*dest++ = color_lookup_table[*(src + (uint8)x)];
|
||||
*dest++ = color_lookup_table[*(src + (uint8)x)];
|
||||
}
|
||||
src += 1024;
|
||||
} else {
|
||||
for(x=0;x<1024;x++) {
|
||||
*dest++ = color_lookup_table[*(src + (x & 511))];
|
||||
}
|
||||
src += 1024;
|
||||
}
|
||||
} else {
|
||||
if(field) {
|
||||
dest += 512;
|
||||
src += 512;
|
||||
}
|
||||
|
||||
if(video_frame[y].hires == false) {
|
||||
for(x=0;x<256;x++) {
|
||||
*dest++ = color_lookup_table[*(src + x)];
|
||||
*dest++ = color_lookup_table[*(src + x)];
|
||||
}
|
||||
src += 512;
|
||||
} else {
|
||||
for(x=0;x<512;x++) {
|
||||
*dest++ = color_lookup_table[*src++];
|
||||
}
|
||||
}
|
||||
|
||||
if(!field) {
|
||||
dest += 512;
|
||||
src += 512;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SNES::video_update() {
|
||||
if(!ppu->render_frame())return;
|
||||
|
||||
if(video.format_changed == true) {
|
||||
update_video_format();
|
||||
}
|
||||
|
||||
uint16 *src = (uint16*)video.ppu_data + ((int(cpu->overscan()) << 3) * 1024);
|
||||
switch(video.mode) {
|
||||
case VM_256x224:video_update_256x224(src);break;
|
||||
case VM_512x224:video_update_512x224(src);break;
|
||||
case VM_256x448:video_update_256x448(src);break;
|
||||
case VM_512x448:video_update_512x448(src);break;
|
||||
case VM_VARIABLE:
|
||||
switch(int(video.frame_hires) | (int(video.frame_interlace) << 1)) {
|
||||
case 0:video_update_256x224(src);break;
|
||||
case 1:video_update_512x224(src);break;
|
||||
case 2:video_update_256x448(src);break;
|
||||
case 3:video_update_512x448(src);break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//SNES::capture_screenshot() was called by emulation interface
|
||||
if(flag_output_screenshot == true) {
|
||||
output_screenshot();
|
||||
flag_output_screenshot = false;
|
||||
}
|
||||
|
||||
video_run();
|
||||
|
||||
video.frame_hires = false;
|
||||
video.frame_interlace = false;
|
||||
}
|
||||
|
||||
void SNES::video_scanline() {
|
||||
int y = cpu->vcounter();
|
||||
int o = int(cpu->overscan()) << 3;
|
||||
if(y <= (0 + o) || y >= (224 + o))return;
|
||||
y -= o;
|
||||
|
||||
PPU::scanline_info si;
|
||||
ppu->get_scanline_info(&si);
|
||||
|
||||
video_frame[y].hires = si.hires;
|
||||
video_frame[y].interlace = si.interlace;
|
||||
|
||||
video.frame_hires |= si.hires;
|
||||
video.frame_interlace |= si.interlace;
|
||||
}
|
||||
|
||||
uint16 *SNES::get_ppu_output_handle() {
|
||||
return (uint16*)(video.ppu_data +
|
||||
(cpu->vcounter() * 1024) +
|
||||
((cpu->interlace() && cpu->interlace_field())?512:0));
|
||||
}
|
||||
|
||||
void SNES::video_init() {
|
||||
int i, c;
|
||||
video.format_changed = false;
|
||||
|
||||
video.data = (uint16*)malloc(512 * 448 * sizeof(uint32));
|
||||
video.ppu_data = (uint16*)malloc(512 * 480 * sizeof(uint16));
|
||||
memset(video.data, 0, 512 * 448 * sizeof(uint32));
|
||||
memset(video.ppu_data, 0, 512 * 480 * sizeof(uint16));
|
||||
|
||||
for(i=0;i<224;i++) {
|
||||
video_frame[i].hires = false;
|
||||
video_frame[i].interlace = false;
|
||||
}
|
||||
|
||||
video.frame_hires = false;
|
||||
video.frame_interlace = false;
|
||||
|
||||
set_video_format(VM_VARIABLE, 16);
|
||||
update_video_format();
|
||||
|
||||
flag_output_screenshot = false;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
enum {
|
||||
VM_256x224, //video data will be scaled to 256x224
|
||||
VM_512x224, //..
|
||||
VM_256x448, //..
|
||||
VM_512x448, //..
|
||||
VM_VARIABLE //video data can be 256x224 - 512x448
|
||||
};
|
||||
|
||||
enum {
|
||||
VMF_NORMAL = 0,
|
||||
VMF_HIRES = 1,
|
||||
VMF_INTERLACE = 2,
|
||||
VMF_HINTERLACE = 3
|
||||
};
|
||||
|
||||
//video color adjustment
|
||||
//via config::snes.video_color_adjust_mode
|
||||
enum {
|
||||
VCA_NORMAL = 0,
|
||||
VCA_GRAYSCALE = 1,
|
||||
VCA_VGA = 2,
|
||||
VCA_GENESIS = 3
|
||||
};
|
||||
|
||||
static const uint8 color_curve_table[32];
|
||||
uint32 color_lookup_table[32768];
|
||||
|
||||
struct {
|
||||
uint16 *data, *ppu_data;
|
||||
uint8 mode;
|
||||
uint8 depth;
|
||||
|
||||
bool frame_hires, frame_interlace;
|
||||
|
||||
bool format_changed;
|
||||
} video, video_changed;
|
||||
|
||||
struct {
|
||||
bool hires, interlace;
|
||||
} video_frame[224];
|
||||
|
||||
struct video_info {
|
||||
uint16 *data;
|
||||
uint8 mode;
|
||||
uint32 width, height;
|
||||
};
|
||||
|
||||
//public functions
|
||||
void capture_screenshot();
|
||||
void update_color_lookup_table();
|
||||
|
||||
virtual void set_video_format(uint8 mode, uint8 depth);
|
||||
virtual void get_video_info(video_info *info);
|
||||
virtual void video_run() = 0;
|
||||
|
||||
//private functions
|
||||
uint16 *get_ppu_output_handle(); //used by PPU only
|
||||
private:
|
||||
//when a screenshot is requested, wait until the frame
|
||||
//has finished rendering, so we can tell the image size
|
||||
bool flag_output_screenshot;
|
||||
uint16 to_rgb555(uint32 color);
|
||||
void output_screenshot();
|
||||
void update_video_format();
|
||||
void video_update_256x224(uint16 *src);
|
||||
void video_update_512x224(uint16 *src);
|
||||
void video_update_256x448(uint16 *src);
|
||||
void video_update_512x448(uint16 *src);
|
||||
void video_update();
|
||||
void video_scanline();
|
||||
void video_init();
|
||||
public:
|
|
@ -0,0 +1,106 @@
|
|||
void SNES::capture_screenshot() {
|
||||
flag_output_screenshot = true;
|
||||
}
|
||||
|
||||
//used to convert pixel data to write to rgb555 format
|
||||
//bitmap image via SNES::output_screenshot() function
|
||||
uint16 SNES::to_rgb555(uint32 color) {
|
||||
if(video.depth == 15) {
|
||||
//rgb555
|
||||
return color & 0x7fff;
|
||||
}
|
||||
|
||||
if(video.depth == 16) {
|
||||
//rgb565->rgb555
|
||||
return ((color >> 1) & 0x7fe0) | (color & 0x001f);
|
||||
}
|
||||
|
||||
if(video.depth == 24 || video.depth == 32) {
|
||||
//rgb888->rgb555
|
||||
return ((color >> 9) & 0x7c00) | ((color >> 6) & 0x03e0) | ((color >> 3) & 0x001f);
|
||||
}
|
||||
|
||||
//unsupported color depth
|
||||
return color;
|
||||
}
|
||||
|
||||
void SNES::output_screenshot() {
|
||||
FILE *fp;
|
||||
char fn[256];
|
||||
int i;
|
||||
//get a file name that doesn't exit...
|
||||
for(i=0;i<=999;i++) {
|
||||
sprintf(fn, "image%0.3d.bmp", i);
|
||||
fp = fopen(fn, "rb");
|
||||
if(!fp)break;
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
}
|
||||
if(i >= 1000)return;
|
||||
|
||||
fp = fopen(fn, "wb");
|
||||
if(!fp)return;
|
||||
|
||||
video_info vi;
|
||||
get_video_info(&vi);
|
||||
int width, height;
|
||||
width = vi.width;
|
||||
height = (vi.height == 224) ? 223 : 446;
|
||||
int32 fsize;
|
||||
fsize = 0x36 + (width * height * sizeof(uint16));
|
||||
|
||||
//header
|
||||
fputc('B', fp);
|
||||
fputc('M', fp);
|
||||
//file size
|
||||
fputc(fsize, fp);
|
||||
fputc(fsize >> 8, fp);
|
||||
fputc(fsize >> 16, fp);
|
||||
fputc(fsize >> 24, fp);
|
||||
//???
|
||||
fputc(0, fp);
|
||||
fputc(0, fp);
|
||||
fputc(0, fp);
|
||||
fputc(0, fp);
|
||||
//start of data
|
||||
fputc(0x36, fp);
|
||||
fputc(0x00, fp);
|
||||
fputc(0x00, fp);
|
||||
fputc(0x00, fp);
|
||||
//remaining header size
|
||||
fputc(0x28, fp);
|
||||
fputc(0x00, fp);
|
||||
fputc(0x00, fp);
|
||||
fputc(0x00, fp);
|
||||
//width
|
||||
fputc(width, fp);
|
||||
fputc(width >> 8, fp);
|
||||
fputc(width >> 16, fp);
|
||||
fputc(width >> 24, fp);
|
||||
//height
|
||||
fputc(height, fp);
|
||||
fputc(height >> 8, fp);
|
||||
fputc(height >> 16, fp);
|
||||
fputc(height >> 24, fp);
|
||||
//format
|
||||
fputc(0x01, fp);
|
||||
fputc(0x00, fp);
|
||||
//bpp
|
||||
fputc(16, fp);
|
||||
fputc( 0, fp);
|
||||
//???
|
||||
for(i=0;i<24;i++) { fputc(0, fp); }
|
||||
|
||||
int x, y;
|
||||
uint16 c;
|
||||
for(y=height;y>=1;y--) {
|
||||
for(x=0;x<width;x++) {
|
||||
c = to_rgb555(video.data[y * width + x]);
|
||||
fputc(c, fp);
|
||||
fputc(c >> 8, fp);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
}
|
|
@ -6,10 +6,11 @@ OBJS = winmain.obj \
|
|||
memory.obj bmemory.obj \
|
||||
cpu.obj bcpu.obj \
|
||||
apu.obj bapu.obj bapuskip.obj \
|
||||
bdsp.obj \
|
||||
ppu.obj bppu.obj \
|
||||
snes.obj \
|
||||
srtc.obj sdd1.obj
|
||||
LIBS = kernel32.lib user32.lib gdi32.lib comdlg32.lib ddraw.lib dxguid.lib
|
||||
LIBS = kernel32.lib user32.lib gdi32.lib comdlg32.lib ddraw.lib dsound.lib dxguid.lib
|
||||
|
||||
all: $(OBJS)
|
||||
rc /r /fobsnes.res bsnes.rc
|
||||
|
@ -21,7 +22,7 @@ clean:
|
|||
######################
|
||||
### win32-specific ###
|
||||
######################
|
||||
winmain.obj: *.cpp *.h
|
||||
winmain.obj: *.cpp *.h ../config/*
|
||||
$(CC) $(CFLAGS) /c winmain.cpp
|
||||
|
||||
#################
|
||||
|
@ -62,6 +63,12 @@ bapu.obj: ../apu/bapu/*
|
|||
bapuskip.obj: ../apu/bapuskip/*
|
||||
$(CC) $(CFLAGS) /c ../apu/bapuskip/bapuskip.cpp
|
||||
|
||||
###########
|
||||
### dsp ###
|
||||
###########
|
||||
bdsp.obj: ../dsp/bdsp/*
|
||||
$(CC) $(CFLAGS) /c ../dsp/bdsp/bdsp.cpp
|
||||
|
||||
###########
|
||||
### ppu ###
|
||||
###########
|
||||
|
|
|
@ -43,31 +43,31 @@ uint32 bSNES::get_status() {
|
|||
return run_status;
|
||||
}
|
||||
|
||||
void bSNES::snes_run() {
|
||||
void bSNES::run() {
|
||||
if(!rom_image->loaded())return;
|
||||
|
||||
switch(run_status) {
|
||||
case RUN:
|
||||
while(update_frame == false) {
|
||||
run();
|
||||
SNES::run();
|
||||
}
|
||||
update_frame = false;
|
||||
return;
|
||||
case STOP:
|
||||
break;
|
||||
case RUNONCE:
|
||||
run();
|
||||
SNES::run();
|
||||
set_status(STOP);
|
||||
break;
|
||||
case RUNTOSIGNAL:
|
||||
run();
|
||||
SNES::run();
|
||||
if(w_bp->hit() == true) {
|
||||
set_status(STOP);
|
||||
disassemble_bp_op();
|
||||
}
|
||||
break;
|
||||
case RUNTOFRAME:
|
||||
run();
|
||||
SNES::run();
|
||||
if(update_frame == true) {
|
||||
update_frame = false;
|
||||
set_status(STOP);
|
||||
|
@ -79,7 +79,7 @@ void bSNES::snes_run() {
|
|||
}
|
||||
return;
|
||||
case RUNTOCPUSTEP:
|
||||
run();
|
||||
SNES::run();
|
||||
if(status.cpu_ran == true) {
|
||||
set_status(STOP);
|
||||
} else if(w_bp->hit() == true) {
|
||||
|
@ -88,7 +88,7 @@ void bSNES::snes_run() {
|
|||
}
|
||||
break;
|
||||
case RUNTOCPUPROCEED:
|
||||
run();
|
||||
SNES::run();
|
||||
if(cpu->in_opcode() == false && status.cpu_stop_pos == cpu->regs.pc.d) {
|
||||
set_status(STOP);
|
||||
disassemble_cpu_op();
|
||||
|
@ -98,14 +98,14 @@ void bSNES::snes_run() {
|
|||
}
|
||||
break;
|
||||
case RUNTOCPUTRACE:
|
||||
run();
|
||||
SNES::run();
|
||||
if(status.cpu_trace_pos >= status.cpu_trace_stop) {
|
||||
set_status(STOP);
|
||||
disassemble_cpu_op();
|
||||
}
|
||||
break;
|
||||
case RUNTOAPUSTEP:
|
||||
run();
|
||||
SNES::run();
|
||||
if(status.apu_ran == true || w_bp->hit() == true) {
|
||||
set_status(STOP);
|
||||
}
|
||||
|
@ -113,28 +113,32 @@ void bSNES::snes_run() {
|
|||
}
|
||||
}
|
||||
|
||||
void bSNES::render_frame() {
|
||||
void bSNES::video_run() {
|
||||
dd_renderer->update();
|
||||
}
|
||||
|
||||
void bSNES::sound_run() {
|
||||
ds_sound->run();
|
||||
}
|
||||
|
||||
/***********************
|
||||
*** Input functions ***
|
||||
***********************/
|
||||
void bSNES::poll_input() {
|
||||
//only capture input when main window has focus
|
||||
if(GetForegroundWindow() == w_main->hwnd) {
|
||||
joypad1.up = KeyDown(cfg.input.joypad1.up);
|
||||
joypad1.down = KeyDown(cfg.input.joypad1.down);
|
||||
joypad1.left = KeyDown(cfg.input.joypad1.left);
|
||||
joypad1.right = KeyDown(cfg.input.joypad1.right);
|
||||
joypad1.select = KeyDown(cfg.input.joypad1.select);
|
||||
joypad1.start = KeyDown(cfg.input.joypad1.start);
|
||||
joypad1.y = KeyDown(cfg.input.joypad1.y);
|
||||
joypad1.b = KeyDown(cfg.input.joypad1.b);
|
||||
joypad1.x = KeyDown(cfg.input.joypad1.x);
|
||||
joypad1.a = KeyDown(cfg.input.joypad1.a);
|
||||
joypad1.l = KeyDown(cfg.input.joypad1.l);
|
||||
joypad1.r = KeyDown(cfg.input.joypad1.r);
|
||||
joypad1.up = KeyDown(config::input.joypad1.up);
|
||||
joypad1.down = KeyDown(config::input.joypad1.down);
|
||||
joypad1.left = KeyDown(config::input.joypad1.left);
|
||||
joypad1.right = KeyDown(config::input.joypad1.right);
|
||||
joypad1.select = KeyDown(config::input.joypad1.select);
|
||||
joypad1.start = KeyDown(config::input.joypad1.start);
|
||||
joypad1.y = KeyDown(config::input.joypad1.y);
|
||||
joypad1.b = KeyDown(config::input.joypad1.b);
|
||||
joypad1.x = KeyDown(config::input.joypad1.x);
|
||||
joypad1.a = KeyDown(config::input.joypad1.a);
|
||||
joypad1.l = KeyDown(config::input.joypad1.l);
|
||||
joypad1.r = KeyDown(config::input.joypad1.r);
|
||||
} else {
|
||||
joypad1.up = joypad1.down = joypad1.left = joypad1.right =
|
||||
joypad1.select = joypad1.start =
|
||||
|
@ -272,7 +276,6 @@ void bSNES::notify(uint32 message, uint32 param1, uint32 param2) {
|
|||
switch(message) {
|
||||
case RENDER_FRAME:
|
||||
update_frame = true;
|
||||
render_frame();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,10 +35,12 @@ enum {
|
|||
RUNTOAPUSTEP
|
||||
};
|
||||
enum { DRAM = 0, SPCRAM = 1, VRAM = 2, OAM = 3, CGRAM = 4 };
|
||||
void run();
|
||||
void video_run();
|
||||
void sound_run();
|
||||
|
||||
void set_status(uint32 new_status);
|
||||
uint32 get_status();
|
||||
void snes_run();
|
||||
void render_frame();
|
||||
|
||||
//input functions
|
||||
void poll_input();
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,52 +1,40 @@
|
|||
#define __config_add(name, def, type) add(&name, #name, def, type)
|
||||
namespace config {
|
||||
|
||||
class Config : public config {
|
||||
public:
|
||||
struct Video {
|
||||
static Setting mode, use_vram, vblank;
|
||||
} video;
|
||||
Setting Video::mode(&config_file, "video.mode",
|
||||
"Video mode\n"
|
||||
" 0 = 256x224w\n"
|
||||
" 1 = 512x448w\n"
|
||||
" 2 = 960x720w\n"
|
||||
" 3 = 640x480f\n"
|
||||
" 4 = 1024x768f",
|
||||
1, Setting::DEC);
|
||||
Setting Video::use_vram(&config_file, "video.use_vram", "Use Video RAM instead of System RAM", true, Setting::TRUE_FALSE);
|
||||
Setting Video::vblank(&config_file, "video.vblank", "Wait for vertical retrace when updating screen", false, Setting::TRUE_FALSE);
|
||||
|
||||
struct {
|
||||
uint32 enabled;
|
||||
}apu;
|
||||
struct GUI {
|
||||
static Setting show_fps;
|
||||
} gui;
|
||||
Setting GUI::show_fps(&config_file, "gui.show_fps", "Show framerate in window title", true, Setting::TRUE_FALSE);
|
||||
|
||||
struct {
|
||||
uint32 mode;
|
||||
uint32 use_vram;
|
||||
uint32 color_curve;
|
||||
uint32 vblank;
|
||||
}video;
|
||||
struct Input {
|
||||
struct Joypad {
|
||||
static Setting up, down, left, right, a, b, x, y, l, r, select, start;
|
||||
} joypad1;
|
||||
} input;
|
||||
Setting Input::Joypad::up (&config_file, "input.joypad1.up", "Joypad1 up", VK_UP, Setting::HEX);
|
||||
Setting Input::Joypad::down (&config_file, "input.joypad1.down", "Joypad1 down", VK_DOWN, Setting::HEX);
|
||||
Setting Input::Joypad::left (&config_file, "input.joypad1.left", "Joypad1 left", VK_LEFT, Setting::HEX);
|
||||
Setting Input::Joypad::right (&config_file, "input.joypad1.right", "Joypad1 right", VK_RIGHT, Setting::HEX);
|
||||
Setting Input::Joypad::a (&config_file, "input.joypad1.a", "Joypad1 A", 'X', Setting::HEX);
|
||||
Setting Input::Joypad::b (&config_file, "input.joypad1.b", "Joypad1 B", 'Z', Setting::HEX);
|
||||
Setting Input::Joypad::x (&config_file, "input.joypad1.x", "Joypad1 X", 'S', Setting::HEX);
|
||||
Setting Input::Joypad::y (&config_file, "input.joypad1.y", "Joypad1 Y", 'A', Setting::HEX);
|
||||
Setting Input::Joypad::l (&config_file, "input.joypad1.l", "Joypad1 L", 'D', Setting::HEX);
|
||||
Setting Input::Joypad::r (&config_file, "input.joypad1.r", "Joypad1 R", 'C', Setting::HEX);
|
||||
Setting Input::Joypad::select(&config_file, "input.joypad1.select", "Joypad1 select", VK_SHIFT, Setting::HEX);
|
||||
Setting Input::Joypad::start (&config_file, "input.joypad1.start", "Joypad1 start", VK_RETURN, Setting::HEX);
|
||||
|
||||
struct {
|
||||
struct {
|
||||
uint32 up, down, left, right;
|
||||
uint32 a, b, x, y, l, r;
|
||||
uint32 select, start;
|
||||
}joypad1;
|
||||
}input;
|
||||
|
||||
struct {
|
||||
uint32 show_fps;
|
||||
}gui;
|
||||
|
||||
Config() {
|
||||
__config_add(apu.enabled, true, TRUEFALSE);
|
||||
|
||||
__config_add(video.mode, 1, DEC);
|
||||
__config_add(video.use_vram, true, TRUEFALSE);
|
||||
__config_add(video.color_curve, true, ENABLED);
|
||||
__config_add(video.vblank, false, TRUEFALSE);
|
||||
|
||||
__config_add(input.joypad1.up, VK_UP, HEX);
|
||||
__config_add(input.joypad1.down, VK_DOWN, HEX);
|
||||
__config_add(input.joypad1.left, VK_LEFT, HEX);
|
||||
__config_add(input.joypad1.right, VK_RIGHT, HEX);
|
||||
__config_add(input.joypad1.a, 'X', HEX);
|
||||
__config_add(input.joypad1.b, 'Z', HEX);
|
||||
__config_add(input.joypad1.x, 'S', HEX);
|
||||
__config_add(input.joypad1.y, 'A', HEX);
|
||||
__config_add(input.joypad1.l, 'D', HEX);
|
||||
__config_add(input.joypad1.r, 'C', HEX);
|
||||
__config_add(input.joypad1.select, VK_SHIFT, HEX);
|
||||
__config_add(input.joypad1.start, VK_RETURN, HEX);
|
||||
|
||||
__config_add(gui.show_fps, true, TRUEFALSE);
|
||||
}
|
||||
}cfg;
|
||||
};
|
||||
|
|
|
@ -4,68 +4,6 @@ DDRenderer::DDRenderer() {
|
|||
lpdds = 0;
|
||||
lpddsb = 0;
|
||||
lpddc = 0;
|
||||
|
||||
int i, c;
|
||||
for(i=0,c=0;i<16;i++) {
|
||||
color_curve_table[i] = c;
|
||||
c = c + i + 1;
|
||||
}
|
||||
for(;i<31;i++) {
|
||||
color_curve_table[i] = c;
|
||||
c += 8;
|
||||
}
|
||||
color_curve_table[i] = 0xff;
|
||||
}
|
||||
|
||||
void DDRenderer::update_color_lookup_table() {
|
||||
int i, r, g, b;
|
||||
lpddsb->GetSurfaceDesc(&ddsd);
|
||||
color_depth = ddsd.ddpfPixelFormat.dwRGBBitCount;
|
||||
if(color_depth == 15) {
|
||||
for(i=0;i<32768;i++) {
|
||||
r = (i ) & 31;
|
||||
g = (i >> 5) & 31;
|
||||
b = (i >> 10) & 31;
|
||||
if(cfg.video.color_curve) {
|
||||
r = color_curve_table[r] >> 3;
|
||||
g = color_curve_table[g] >> 3;
|
||||
b = color_curve_table[b] >> 3;
|
||||
}
|
||||
color_lookup_table[i] = (r << 10) | (g << 5) | (b);
|
||||
}
|
||||
} else if(color_depth == 16) {
|
||||
for(i=0;i<32768;i++) {
|
||||
r = (i ) & 31;
|
||||
g = (i >> 5) & 31;
|
||||
b = (i >> 10) & 31;
|
||||
if(cfg.video.color_curve) {
|
||||
r = color_curve_table[r] >> 3;
|
||||
g = color_curve_table[g] >> 2;
|
||||
b = color_curve_table[b] >> 3;
|
||||
} else {
|
||||
g = (g << 1) | (g >> 4);
|
||||
}
|
||||
color_lookup_table[i] = (r << 11) | (g << 5) | (b);
|
||||
}
|
||||
} else if(color_depth == 32) {
|
||||
for(i=0;i<32768;i++) {
|
||||
r = (i ) & 31;
|
||||
g = (i >> 5) & 31;
|
||||
b = (i >> 10) & 31;
|
||||
if(cfg.video.color_curve) {
|
||||
r = color_curve_table[r];
|
||||
g = color_curve_table[g];
|
||||
b = color_curve_table[b];
|
||||
} else {
|
||||
r = (r << 3) | (r >> 2);
|
||||
g = (g << 3) | (g >> 2);
|
||||
b = (b << 3) | (b >> 2);
|
||||
}
|
||||
color_lookup_table[i] = (r << 16) | (g << 8) | (b);
|
||||
}
|
||||
} else {
|
||||
alert("Error: Unsupported color depth [%d]", color_depth);
|
||||
}
|
||||
}
|
||||
|
||||
void DDRenderer::set_window(HWND hwnd_handle) { hwnd = hwnd_handle; }
|
||||
|
@ -76,25 +14,24 @@ void DDRenderer::set_window(HWND hwnd_handle) { hwnd = hwnd_handle; }
|
|||
handles conversion from 16bpp->32bpp in hardware. This only works
|
||||
when both the source and dest buffers are in VRAM, though.
|
||||
|
||||
The SNES resolution is 256x224. The top scanline is never drawn, so
|
||||
256x223 is used. Hires mode doubles the screen width, and hires+interlace
|
||||
double the screen height, making the resolution 512x446.
|
||||
The SNES resolution is 256x224. Hires mode doubles the screen width, and
|
||||
hires+interlace double the screen height, making the resolution 512x448.
|
||||
There is one more problem, however. On some video cards, when blitting
|
||||
from video memory from 256x223->512x446, a bilinear filter is applied by
|
||||
from video memory from 256x224->512x448, a bilinear filter is applied by
|
||||
the video card, and sometimes this filter tries to read past the source
|
||||
video memory to get interpolation data. This results in a line of garble
|
||||
on the right and bottom edges of the screen. Therefore, an additional
|
||||
4 pixels in each direction is added to the backbuffer.
|
||||
The backbuffer is thusly 512+4 * 476+4
|
||||
The backbuffer is thusly 512+4 * 480+4
|
||||
*/
|
||||
void DDRenderer::create_backbuffer() {
|
||||
int color_depth;
|
||||
int depth;
|
||||
lpdds->GetSurfaceDesc(&ddsd);
|
||||
color_depth = ddsd.ddpfPixelFormat.dwRGBBitCount;
|
||||
if(color_depth == 15 || color_depth == 16) {
|
||||
depth = ddsd.ddpfPixelFormat.dwRGBBitCount;
|
||||
if(depth == 15 || depth == 16) {
|
||||
goto try_native_backbuffer;
|
||||
} else {
|
||||
if(cfg.video.use_vram == false) {
|
||||
if((int)config::video.use_vram == false) {
|
||||
goto try_native_backbuffer;
|
||||
}
|
||||
}
|
||||
|
@ -103,14 +40,14 @@ int color_depth;
|
|||
ddsd.dwSize = sizeof(DDSURFACEDESC);
|
||||
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
||||
if(cfg.video.use_vram) {
|
||||
if(config::video.use_vram) {
|
||||
ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
|
||||
} else {
|
||||
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
|
||||
}
|
||||
|
||||
ddsd.dwWidth = 512 + 4;
|
||||
ddsd.dwHeight = 476 + 4;
|
||||
ddsd.dwHeight = 480 + 4;
|
||||
|
||||
ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
|
||||
ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
|
||||
|
@ -126,14 +63,14 @@ try_native_backbuffer:
|
|||
ddsd.dwSize = sizeof(DDSURFACEDESC);
|
||||
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
||||
if(cfg.video.use_vram) {
|
||||
if(config::video.use_vram) {
|
||||
ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
|
||||
} else {
|
||||
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
|
||||
}
|
||||
|
||||
ddsd.dwWidth = 512 + 4;
|
||||
ddsd.dwHeight = 476 + 4;
|
||||
ddsd.dwHeight = 480 + 4;
|
||||
|
||||
lpdd->CreateSurface(&ddsd, &lpddsb, 0);
|
||||
|
||||
|
@ -147,6 +84,9 @@ DDBLTFX fx;
|
|||
fx.dwSize = sizeof(DDBLTFX);
|
||||
fx.dwFillColor = 0x00000000;
|
||||
lpddsb->Blt(0, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &fx);
|
||||
|
||||
lpddsb->GetSurfaceDesc(&ddsd);
|
||||
color_depth = ddsd.ddpfPixelFormat.dwRGBBitCount;
|
||||
}
|
||||
|
||||
void DDRenderer::to_windowed() {
|
||||
|
@ -166,7 +106,6 @@ void DDRenderer::to_windowed() {
|
|||
lpdds->SetClipper(lpddc);
|
||||
|
||||
create_backbuffer();
|
||||
update_color_lookup_table();
|
||||
redraw();
|
||||
}
|
||||
|
||||
|
@ -195,14 +134,13 @@ void DDRenderer::to_fullscreen(int _width, int _height) {
|
|||
lpdds->SetClipper(lpddc);
|
||||
|
||||
create_backbuffer();
|
||||
update_color_lookup_table();
|
||||
redraw();
|
||||
}
|
||||
|
||||
void DDRenderer::set_source_window() {
|
||||
SetRect(&lpddrc, 0, 0,
|
||||
(ppu->output->hires == false)?256:512,
|
||||
(ppu->output->interlace == false)?223:446);
|
||||
//skip first scanline
|
||||
int i = (vi.height == 224) ? 1 : 2;
|
||||
SetRect(&lpddrc, 0, i, vi.width, vi.height);
|
||||
}
|
||||
|
||||
void DDRenderer::redraw() {
|
||||
|
@ -226,7 +164,7 @@ int rx, ry;
|
|||
break;
|
||||
}
|
||||
}
|
||||
if(cfg.video.vblank) {
|
||||
if(config::video.vblank) {
|
||||
lpdd->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, 0);
|
||||
}
|
||||
hr = lpdds->Blt(&rd, lpddsb, &lpddrc, DDBLT_WAIT, 0);
|
||||
|
@ -235,7 +173,7 @@ int rx, ry;
|
|||
lpddsb->Restore();
|
||||
}
|
||||
|
||||
if(cfg.gui.show_fps == false || bsnes->get_status() == bSNES::STOP)return;
|
||||
if((int)config::gui.show_fps == false || bsnes->get_status() == bSNES::STOP)return;
|
||||
uint32 fps;
|
||||
char s[256], t[256];
|
||||
fps_timer->tick();
|
||||
|
@ -262,24 +200,22 @@ HRESULT hr;
|
|||
if(hr != DD_OK)return;
|
||||
|
||||
set_source_window();
|
||||
if(ppu->output->hires == false) {
|
||||
if(ppu->output->interlace == false) {
|
||||
update16_256x224();
|
||||
} else {
|
||||
update16_256x448();
|
||||
}
|
||||
} else {
|
||||
if(ppu->output->interlace == false) {
|
||||
update16_512x224();
|
||||
} else {
|
||||
update16_512x448();
|
||||
}
|
||||
|
||||
if (vi.width == 256 && vi.height == 224) {
|
||||
update16_256x224();
|
||||
} else if(vi.width == 512 && vi.height == 224) {
|
||||
update16_512x224();
|
||||
} else if(vi.width == 256 && vi.height == 448) {
|
||||
update16_256x448();
|
||||
} else if(vi.width == 512 && vi.height == 448) {
|
||||
update16_512x448();
|
||||
}
|
||||
|
||||
lpddsb->Unlock(0);
|
||||
}
|
||||
|
||||
#include "dd_renderer32.cpp"
|
||||
//#include "dd_renderer32.cpp"
|
||||
/*
|
||||
void DDRenderer::update32() {
|
||||
HRESULT hr;
|
||||
hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0);
|
||||
|
@ -302,17 +238,21 @@ HRESULT hr;
|
|||
|
||||
lpddsb->Unlock(0);
|
||||
}
|
||||
*/
|
||||
|
||||
void DDRenderer::update() {
|
||||
snes->get_video_info(&vi);
|
||||
|
||||
switch(color_depth) {
|
||||
case 15:
|
||||
case 16:
|
||||
update16();
|
||||
break;
|
||||
case 32:
|
||||
update32();
|
||||
//update32();
|
||||
break;
|
||||
}
|
||||
|
||||
redraw();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <ddraw.h>
|
||||
|
||||
class DDRenderer {
|
||||
public:
|
||||
LPDIRECTDRAW lpdd;
|
||||
|
@ -9,11 +10,10 @@ DDSURFACEDESC ddsd;
|
|||
DDSCAPS ddscaps;
|
||||
RECT lpddrc;
|
||||
HWND hwnd;
|
||||
bool fullscreen;
|
||||
int width, height; //used for fullscreen mode clipping only
|
||||
uint8 color_depth;
|
||||
uint8 color_curve_table[32];
|
||||
uint32 color_lookup_table[32768];
|
||||
bool fullscreen;
|
||||
int width, height; //used for fullscreen mode clipping only
|
||||
uint8 color_depth;
|
||||
SNES::video_info vi; //initialized each frame at start of update()
|
||||
void set_window(HWND hwnd_handle);
|
||||
void create_backbuffer();
|
||||
void to_windowed();
|
||||
|
@ -21,18 +21,17 @@ uint32 color_lookup_table[32768];
|
|||
void set_source_window();
|
||||
void redraw();
|
||||
inline void update16_256x224();
|
||||
inline void update16_256x448();
|
||||
inline void update16_512x224();
|
||||
inline void update16_256x448();
|
||||
inline void update16_512x448();
|
||||
void update16();
|
||||
inline void update32_256x224();
|
||||
inline void update32_256x448();
|
||||
inline void update32_512x224();
|
||||
inline void update32_512x448();
|
||||
void update32();
|
||||
//inline void update32_256x224();
|
||||
//inline void update32_512x224();
|
||||
//inline void update32_256x448();
|
||||
//inline void update32_512x448();
|
||||
//void update32();
|
||||
void update();
|
||||
void destroy();
|
||||
void update_color_lookup_table();
|
||||
|
||||
DDRenderer();
|
||||
};
|
||||
|
|
|
@ -1,123 +1,79 @@
|
|||
inline void DDRenderer::update16_256x224() {
|
||||
uint16 *src;
|
||||
uint16 *dest;
|
||||
uint16 *src, *dest;
|
||||
uint32 pitch;
|
||||
int x, y;
|
||||
src = (uint16*)ppu->output->buffer + (1 << 10);
|
||||
dest = (uint16*)ddsd.lpSurface;
|
||||
pitch = (ddsd.lPitch >> 1) - 256;
|
||||
dest = (uint16*)ddsd.lpSurface;
|
||||
src = (uint16*)vi.data;
|
||||
|
||||
int overscan_adjust = 0;
|
||||
if(cpu->overscan() == true) {
|
||||
src += 7 << 10;
|
||||
overscan_adjust = 7;
|
||||
#ifdef USE_X86_ASM
|
||||
pitch = (ddsd.lPitch) - 512;
|
||||
__asm {
|
||||
mov edi,dest
|
||||
mov esi,src
|
||||
mov edx,224
|
||||
ly:
|
||||
mov ecx,32
|
||||
lx:
|
||||
movsd
|
||||
movsd
|
||||
movsd
|
||||
movsd
|
||||
loopnz lx
|
||||
add edi,pitch
|
||||
dec edx
|
||||
jnz ly
|
||||
}
|
||||
#else
|
||||
pitch = (ddsd.lPitch >> 1);
|
||||
for(y=0;y<224;y++) {
|
||||
memcpy(dest, src, 512);
|
||||
dest += pitch;
|
||||
src += 256;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
for(y=1+overscan_adjust;y<224+overscan_adjust;y++) {
|
||||
x = 256;
|
||||
while(x--) {
|
||||
*dest++ = color_lookup_table[*src];
|
||||
src += 2;
|
||||
}
|
||||
inline void DDRenderer::update16_512x224() {
|
||||
uint16 *src, *dest;
|
||||
uint32 pitch;
|
||||
int x, y;
|
||||
pitch = (ddsd.lPitch >> 1);
|
||||
dest = (uint16*)ddsd.lpSurface;
|
||||
src = (uint16*)vi.data;
|
||||
|
||||
for(y=0;y<224;y++) {
|
||||
memcpy(dest, src, 1024);
|
||||
dest += pitch;
|
||||
src += 512;
|
||||
}
|
||||
}
|
||||
|
||||
inline void DDRenderer::update16_256x448() {
|
||||
uint16 *src;
|
||||
uint16 *dest;
|
||||
uint16 *src, *dest;
|
||||
uint32 pitch;
|
||||
int x, y;
|
||||
src = (uint16*)ppu->output->buffer + (1 << 10);
|
||||
pitch = (ddsd.lPitch >> 1);
|
||||
dest = (uint16*)ddsd.lpSurface;
|
||||
pitch = (ddsd.lPitch >> 1) - 256;
|
||||
src = (uint16*)vi.data;
|
||||
|
||||
int overscan_adjust = 0;
|
||||
if(cpu->overscan() == true) {
|
||||
src += 7 << 10;
|
||||
overscan_adjust = 14;
|
||||
}
|
||||
|
||||
for(y=2+overscan_adjust;y<448+overscan_adjust;y++) {
|
||||
x = 256;
|
||||
while(x--) {
|
||||
*dest++ = color_lookup_table[*src];
|
||||
src += 2;
|
||||
}
|
||||
for(y=0;y<448;y++) {
|
||||
memcpy(dest, src, 512);
|
||||
dest += pitch;
|
||||
if(ppu->output->line[y >> 1].interlace == false) {
|
||||
src += (y & 1)?512:-512;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void DDRenderer::update16_512x224() {
|
||||
uint16 *src;
|
||||
uint16 *dest;
|
||||
uint32 pitch;
|
||||
int x, y;
|
||||
src = (uint16*)ppu->output->buffer + (1 << 10);
|
||||
dest = (uint16*)ddsd.lpSurface;
|
||||
pitch = (ddsd.lPitch >> 1) - 512;
|
||||
|
||||
int overscan_adjust = 0;
|
||||
if(cpu->overscan() == true) {
|
||||
src += 7 << 10;
|
||||
overscan_adjust = 7;
|
||||
}
|
||||
|
||||
for(y=1+overscan_adjust;y<224+overscan_adjust;y++) {
|
||||
if(ppu->output->line[y].hires == true) {
|
||||
x = 512;
|
||||
while(x--) {
|
||||
*dest++ = color_lookup_table[*src++];
|
||||
}
|
||||
} else {
|
||||
x = 256;
|
||||
while(x--) {
|
||||
*dest++ = color_lookup_table[*src];
|
||||
*dest++ = color_lookup_table[*src];
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
dest += pitch;
|
||||
src += 512;
|
||||
src += 256;
|
||||
}
|
||||
}
|
||||
|
||||
inline void DDRenderer::update16_512x448() {
|
||||
uint16 *src;
|
||||
uint16 *dest;
|
||||
uint16 *src, *dest;
|
||||
uint32 pitch;
|
||||
int x, y;
|
||||
src = (uint16*)ppu->output->buffer + (1 << 10);
|
||||
pitch = (ddsd.lPitch >> 1);
|
||||
dest = (uint16*)ddsd.lpSurface;
|
||||
pitch = (ddsd.lPitch >> 1) - 512;
|
||||
src = (uint16*)vi.data;
|
||||
|
||||
int overscan_adjust = 0;
|
||||
if(cpu->overscan() == true) {
|
||||
src += 7 << 10;
|
||||
overscan_adjust = 14;
|
||||
}
|
||||
|
||||
for(y=2+overscan_adjust;y<448+overscan_adjust;y++) {
|
||||
if(ppu->output->line[y >> 1].hires == true) {
|
||||
x = 512;
|
||||
while(x--) {
|
||||
*dest++ = color_lookup_table[*src++];
|
||||
}
|
||||
} else {
|
||||
x = 256;
|
||||
while(x--) {
|
||||
*dest++ = color_lookup_table[*src];
|
||||
*dest++ = color_lookup_table[*src];
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
for(y=0;y<448;y++) {
|
||||
memcpy(dest, src, 1024);
|
||||
dest += pitch;
|
||||
if(ppu->output->line[y >> 1].interlace == false) {
|
||||
src += (y & 1)?512:-512;
|
||||
}
|
||||
src += 512;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
DSSound::DSSound() {
|
||||
data.buffer = 0;
|
||||
data.lpos = data.lsample = data.lbuffer = 0;
|
||||
}
|
||||
|
||||
void DSSound::run() {
|
||||
if(snes->get_playback_buffer_pos() != 0)return;
|
||||
|
||||
uint32 pos, status;
|
||||
|
||||
//dsb_b[0]->SetFrequency(22050);
|
||||
|
||||
//do {
|
||||
// dsb_b[0]->GetStatus(&status);
|
||||
//} while(status & DSBSTATUS_PLAYING);
|
||||
|
||||
dsb_b[0]->Lock(0, DSP_BUFFER_SIZE * 4, &dslb, &dslbs, 0, 0, 0);
|
||||
memcpy(dslb, snes->get_playback_buffer(), DSP_BUFFER_SIZE * 4);
|
||||
dsb_b[0]->Unlock(dslb, dslbs, 0, 0);
|
||||
|
||||
dsb_b[0]->SetCurrentPosition(0);
|
||||
|
||||
//has the buffer stopped (possibly due to running too fast)?
|
||||
dsb_b[0]->GetStatus(&status);
|
||||
if(!(status & DSBSTATUS_PLAYING)) {
|
||||
dsb_b[0]->Play(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void DSSound::init() {
|
||||
DirectSoundCreate(0, &ds, 0);
|
||||
ds->SetCooperativeLevel(w_main->hwnd, DSSCL_PRIORITY);
|
||||
|
||||
memset(&dsbd, 0, sizeof(dsbd));
|
||||
dsbd.dwSize = sizeof(dsbd);
|
||||
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
|
||||
dsbd.dwBufferBytes = 0;
|
||||
dsbd.lpwfxFormat = 0;
|
||||
ds->CreateSoundBuffer(&dsbd, &dsb_p, 0);
|
||||
|
||||
memset(&wfx, 0, sizeof(wfx));
|
||||
wfx.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx.nChannels = 2;
|
||||
wfx.nSamplesPerSec = 32000;
|
||||
wfx.wBitsPerSample = 16;
|
||||
wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
|
||||
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
|
||||
dsb_p->SetFormat(&wfx);
|
||||
|
||||
sample_size = (16 / 8) * 2;
|
||||
buffer_size = DSP_BUFFER_SIZE * sample_size;
|
||||
buffer_pos = 0;
|
||||
|
||||
dsb_b = new LPDIRECTSOUNDBUFFER[1];
|
||||
memset(&dsbd, 0, sizeof(dsbd));
|
||||
dsbd.dwSize = sizeof(dsbd);
|
||||
dsbd.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_GLOBALFOCUS;
|
||||
dsbd.dwBufferBytes = buffer_size;
|
||||
dsbd.guid3DAlgorithm = GUID_NULL;
|
||||
dsbd.lpwfxFormat = &wfx;
|
||||
ds->CreateSoundBuffer(&dsbd, &dsb_b[0], 0);
|
||||
ds->CreateSoundBuffer(&dsbd, &dsb_b[1], 0);
|
||||
dsb_b[0]->SetFrequency(32000);
|
||||
dsb_b[1]->SetFrequency(32000);
|
||||
|
||||
dsb_b[0]->Lock(0, buffer_size, &dslb, &dslbs, 0, 0, 0);
|
||||
memset(dslb, 0, buffer_size);
|
||||
dsb_b[0]->Unlock(dslb, dslbs, 0, 0);
|
||||
|
||||
dsb_b[1]->Lock(0, buffer_size, &dslb, &dslbs, 0, 0, 0);
|
||||
memset(dslb, 0, buffer_size);
|
||||
dsb_b[1]->Unlock(dslb, dslbs, 0, 0);
|
||||
|
||||
dsb_b[0]->Play(0, 0, 0);
|
||||
|
||||
buffer_pos = 0;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue