mirror of
https://github.com/ares-emulator/ares.git
synced 2026-11-08 17:03:47 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7dec0b2a3c | ||
|
|
f288280ceb | ||
|
|
c6c5f4669c | ||
|
|
397b9c4505 | ||
|
|
7e2cfb6d40 |
No files matched your search
@@ -1,57 +1,139 @@
|
||||
#[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 = false
|
||||
|
||||
# Regulate speed to 60hz (NTSC) / 50hz (PAL)
|
||||
# (default = true)
|
||||
system.regulate_speed = 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 = true
|
||||
|
||||
# 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
|
||||
|
||||
# Joypad2 up
|
||||
# (default = 0x54)
|
||||
input.joypad2.up = 0x54
|
||||
|
||||
# Joypad2 down
|
||||
# (default = 0x47)
|
||||
input.joypad2.down = 0x47
|
||||
|
||||
# Joypad2 left
|
||||
# (default = 0x46)
|
||||
input.joypad2.left = 0x46
|
||||
|
||||
# Joypad2 right
|
||||
# (default = 0x48)
|
||||
input.joypad2.right = 0x48
|
||||
|
||||
# Joypad2 A
|
||||
# (default = 0x4b)
|
||||
input.joypad2.a = 0x4b
|
||||
|
||||
# Joypad2 B
|
||||
# (default = 0x4a)
|
||||
input.joypad2.b = 0x4a
|
||||
|
||||
# Joypad2 X
|
||||
# (default = 0x49)
|
||||
input.joypad2.x = 0x49
|
||||
|
||||
# Joypad2 Y
|
||||
# (default = 0x55)
|
||||
input.joypad2.y = 0x55
|
||||
|
||||
# Joypad2 L
|
||||
# (default = 0x4f)
|
||||
input.joypad2.l = 0x4f
|
||||
|
||||
# Joypad2 R
|
||||
# (default = 0x4c)
|
||||
input.joypad2.r = 0x4c
|
||||
|
||||
# Joypad2 select
|
||||
# (default = 0x5b)
|
||||
input.joypad2.select = 0x5b
|
||||
|
||||
# Joypad2 start
|
||||
# (default = 0x5d)
|
||||
input.joypad2.start = 0x5d
|
||||
|
||||
+6
-1
@@ -17,5 +17,10 @@ emulators.
|
||||
The Simple DirectMedia Layer library source code is available from:
|
||||
http://www.libsdl.org/
|
||||
|
||||
This library is distributed under the terms of the GNU LGPL license:
|
||||
This library is distributed under the terms of the GNU LGPL:
|
||||
http://www.gnu.org/copyleft/lesser.html
|
||||
|
||||
Licensing Exemptions:
|
||||
---------------------
|
||||
Richard Bannister has asked for and received my permission to distribute
|
||||
a binary-only port of bsnes on the Mac OS X platform.
|
||||
@@ -1,2 +1,3 @@
|
||||
#include "../base.h"
|
||||
#include "iplrom.h"
|
||||
#include "dapu.cpp"
|
||||
+4
-2
@@ -1,10 +1,9 @@
|
||||
#define _APU_IPLROM
|
||||
#include "iplrom.h"
|
||||
#include "apuregs.h"
|
||||
|
||||
class APU {
|
||||
public:
|
||||
APURegs regs;
|
||||
static const uint8 iplrom[64];
|
||||
enum {
|
||||
FLAG_N = 0x80, FLAG_V = 0x40,
|
||||
FLAG_P = 0x20, FLAG_B = 0x10,
|
||||
@@ -18,11 +17,14 @@ APURegs regs;
|
||||
virtual uint8 port_read (uint8 port) = 0;
|
||||
virtual void port_write(uint8 port, uint8 value) = 0;
|
||||
|
||||
virtual uint8 *get_spcram_handle() = 0;
|
||||
virtual void run() = 0;
|
||||
virtual uint32 cycles_executed() = 0;
|
||||
virtual void power() = 0;
|
||||
virtual void reset() = 0;
|
||||
|
||||
//debugging functions
|
||||
virtual bool in_opcode();
|
||||
void disassemble_opcode(char *output);
|
||||
inline uint16 __relb(int8 offset, int op_len);
|
||||
};
|
||||
+7
-6
@@ -13,7 +13,7 @@ private:
|
||||
inline bool operator ^= (bool i) { if(i)_b ^= B; return (_b & B); }
|
||||
};
|
||||
public:
|
||||
union {
|
||||
union {
|
||||
uint8 _b;
|
||||
bit<0x80> n;
|
||||
bit<0x40> v;
|
||||
@@ -23,7 +23,7 @@ public:
|
||||
bit<0x04> i;
|
||||
bit<0x02> z;
|
||||
bit<0x01> c;
|
||||
};
|
||||
};
|
||||
|
||||
APURegFlags() { _b = 0; }
|
||||
inline operator uint8() { return _b; }
|
||||
@@ -38,10 +38,11 @@ public:
|
||||
uint16 pc;
|
||||
union {
|
||||
uint16 ya;
|
||||
//not endian-safe
|
||||
struct {
|
||||
uint8 a, y;
|
||||
};
|
||||
#ifdef ARCH_LSB
|
||||
struct { uint8 a, y; };
|
||||
#else
|
||||
struct { uint8 y, a; };
|
||||
#endif
|
||||
};
|
||||
uint8 x, sp;
|
||||
APURegFlags p;
|
||||
|
||||
+23
-11
@@ -24,13 +24,13 @@ uint8 r;
|
||||
break;
|
||||
case 0xf3: //DSPDATA
|
||||
//0x80-0xff is a read-only mirror of 0x00-0x7f
|
||||
r = dsp_regs[status.dsp_addr & 0x7f];
|
||||
r = r_dsp->read(status.dsp_addr & 0x7f);
|
||||
break;
|
||||
case 0xf4: //CPUIO0
|
||||
case 0xf5: //CPUIO1
|
||||
case 0xf6: //CPUIO2
|
||||
case 0xf7: //CPUIO3
|
||||
r = cpu->port_read(addr & 3);
|
||||
r = r_cpu->port_read(addr & 3);
|
||||
break;
|
||||
case 0xf8: //???
|
||||
case 0xf9: //??? -- Mapped to SPCRAM
|
||||
@@ -63,7 +63,10 @@ uint8 r;
|
||||
r = spcram[addr];
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::SPCRAM_READ, addr, r);
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -78,12 +81,12 @@ void bAPU::spcram_write(uint16 addr, uint8 value) {
|
||||
//one-time clearing of APU port read registers,
|
||||
//emulated by simulating CPU writes of 0x00
|
||||
if(value & 0x20) {
|
||||
cpu->port_write(2, 0x00);
|
||||
cpu->port_write(3, 0x00);
|
||||
r_cpu->port_write(2, 0x00);
|
||||
r_cpu->port_write(3, 0x00);
|
||||
}
|
||||
if(value & 0x10) {
|
||||
cpu->port_write(0, 0x00);
|
||||
cpu->port_write(1, 0x00);
|
||||
r_cpu->port_write(0, 0x00);
|
||||
r_cpu->port_write(1, 0x00);
|
||||
}
|
||||
|
||||
//0->1 transistion resets timers
|
||||
@@ -111,7 +114,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;
|
||||
r_dsp->write(status.dsp_addr & 0x7f, value);
|
||||
}
|
||||
break;
|
||||
case 0xf4: //CPUIO0
|
||||
@@ -143,7 +146,10 @@ void bAPU::spcram_write(uint16 addr, uint8 value) {
|
||||
//even if the iplrom is enabled.
|
||||
spcram[addr] = value;
|
||||
}
|
||||
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::SPCRAM_WRITE, addr, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8 bAPU::port_read(uint8 port) {
|
||||
@@ -209,6 +215,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();
|
||||
}
|
||||
@@ -226,7 +240,8 @@ void bAPU::reset() {
|
||||
regs.sp = 0xef;
|
||||
regs.p = 0x02;
|
||||
|
||||
status.cycle_pos = 0;
|
||||
status.cycle_pos = 0;
|
||||
status.cycles_executed = 0;
|
||||
|
||||
//$f1
|
||||
status.iplrom_enabled = true;
|
||||
@@ -246,15 +261,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
|
||||
|
||||
+3
-1
@@ -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();
|
||||
@@ -53,6 +54,7 @@ enum {
|
||||
inline void stack_write(uint8 value);
|
||||
|
||||
inline void exec_cycle();
|
||||
inline bool in_opcode();
|
||||
inline void init_op_table();
|
||||
|
||||
inline uint8 op_adc (uint8 x, uint8 y);
|
||||
|
||||
@@ -1,18 +1,27 @@
|
||||
void bAPU::exec_cycle() {
|
||||
uint8 op;
|
||||
if(status.cycle_pos == 0) {
|
||||
op = spcram_read(regs.pc);
|
||||
snes->notify(SNES::APU_EXEC_OPCODE_BEGIN);
|
||||
status.opcode = op_read();
|
||||
status.cycle_pos = 1;
|
||||
add_cycles(1);
|
||||
} else {
|
||||
if(status.cycle_pos) {
|
||||
(this->*optbl[status.opcode])();
|
||||
add_cycles(1);
|
||||
if(status.cycle_pos == 0) {
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::APU_EXEC_OPCODE_END);
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//on first cycle?
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::APU_EXEC_OPCODE_BEGIN);
|
||||
#endif
|
||||
status.opcode = op_read();
|
||||
status.cycle_pos = 1;
|
||||
add_cycles(1);
|
||||
}
|
||||
|
||||
//only return true when we are on an opcode edge
|
||||
bool bAPU::in_opcode() {
|
||||
return (status.cycle_pos != 0);
|
||||
}
|
||||
|
||||
void bAPU::init_op_table() {
|
||||
|
||||
@@ -510,7 +510,7 @@ void bAPU::op_cbne_dp() {
|
||||
rd = op_read();
|
||||
break;
|
||||
case 3:
|
||||
sp = op_read(OPMODE_DP, dp + 0);
|
||||
sp = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 4:
|
||||
if(regs.a == sp)status.cycle_pos = 0;
|
||||
@@ -533,14 +533,16 @@ void bAPU::op_cbne_dpx() {
|
||||
rd = op_read();
|
||||
break;
|
||||
case 3:
|
||||
sp = op_read(OPMODE_DP, dp + regs.x);
|
||||
break;
|
||||
case 4:
|
||||
if(regs.a == sp)status.cycle_pos = 0;
|
||||
sp = op_read(OPMODE_DP, dp + regs.x);
|
||||
break;
|
||||
case 5:
|
||||
if(regs.a == sp)status.cycle_pos = 0;
|
||||
break;
|
||||
case 6:
|
||||
break;
|
||||
case 7:
|
||||
regs.pc += (int8)rd;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
||||
@@ -107,16 +107,16 @@ int i, l;
|
||||
replace(t, "$5", op_list[i].arg[5]);
|
||||
replace(t, "$6", op_list[i].arg[6]);
|
||||
replace(t, "$7", op_list[i].arg[7]);
|
||||
fprintf(fp, "%s\r\n\r\n", *t);
|
||||
fprintf(fp, "%s\r\n\r\n", strptr(t));
|
||||
|
||||
strcpy(t, output_header);
|
||||
replace(t, "$$", op_list[i].name);
|
||||
fprintf(fph, "%s", *t);
|
||||
fprintf(fph, "%s", strptr(t));
|
||||
|
||||
strcpy(t, output_table);
|
||||
replace(t, "$$", op_list[i].name);
|
||||
replace(t, "$0", op_list[i].arg[0]);
|
||||
fprintf(fpt, "%s", *t);
|
||||
fprintf(fpt, "%s", strptr(t));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
+12
-3
@@ -37,16 +37,25 @@ bbc7(0xf3, 0x80, ==) {
|
||||
6:regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
cbne_dp(0x2e, 0),
|
||||
cbne_dpx(0xde, regs.x) {
|
||||
cbne_dp(0x2e) {
|
||||
1:dp = op_read();
|
||||
2:rd = op_read();
|
||||
3:sp = op_read(OPMODE_DP, dp + $1);
|
||||
3:sp = op_read(OPMODE_DP, dp);
|
||||
4:if(regs.a == sp)end;
|
||||
5:
|
||||
6:regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
cbne_dpx(0xde) {
|
||||
1:dp = op_read();
|
||||
2:rd = op_read();
|
||||
3:
|
||||
4:sp = op_read(OPMODE_DP, dp + regs.x);
|
||||
5:if(regs.a == sp)end;
|
||||
6:
|
||||
7:regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
dbnz_dp(0x6e) {
|
||||
1:dp = op_read();
|
||||
2:rd = op_read();
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
#include "../../base.h"
|
||||
|
||||
uint8 bAPUSkip::spcram_read (uint16 addr) { return 0xff; }
|
||||
void bAPUSkip::spcram_write(uint16 addr, uint8 value) {}
|
||||
|
||||
/*
|
||||
This routine is very serious. It will eat holes through
|
||||
the ROM to skip APU test conditions. Or in other words,
|
||||
it will disable and/or force branches when neccesary.
|
||||
|
||||
It can very easily break or corrupt a game and prevent it
|
||||
from being playable until the ROM is reloaded (ROM writes
|
||||
are only performed in memory, of course).
|
||||
|
||||
However, this kind of brute force approach is required to
|
||||
get many games playable without proper SPC700 emulation.
|
||||
*/
|
||||
uint8 bAPUSkip::port_read(uint8 port) {
|
||||
port &= 3;
|
||||
_apu_port *p = &apu_port[port];
|
||||
int i, x, y, z, t;
|
||||
uint32 addr;
|
||||
|
||||
addr = cpu->regs.pc.d;
|
||||
p->read_addr[p->read_pos & 31] = addr;
|
||||
|
||||
//- lda $214x
|
||||
// cmp $214x
|
||||
// bne -
|
||||
// cmp ???
|
||||
// beq/bne -
|
||||
__test1:
|
||||
//look for an lda/cmp read pattern
|
||||
if(addr == p->read_addr[(p->read_pos - 1) & 31])goto __test2;
|
||||
if(addr != p->read_addr[(p->read_pos - 2) & 31])goto __test2;
|
||||
if(addr == p->read_addr[(p->read_pos - 3) & 31])goto __test2;
|
||||
if(addr != p->read_addr[(p->read_pos - 4) & 31])goto __test2;
|
||||
if(p->read_addr[(p->read_pos - 1) & 31] != p->read_addr[(p->read_pos - 3) & 31])goto __test2;
|
||||
//try and find compare opcode
|
||||
for(i=0;i<24;i++) {
|
||||
x = mem_bus->read(addr + i);
|
||||
if(x == OP_CMP_CONST || x == OP_CPX_CONST || x == OP_CPY_CONST)break;
|
||||
if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) break;
|
||||
if(x == OP_CMP_LONG)break;
|
||||
}
|
||||
if(i == 24)goto __test2;
|
||||
//seek to next opcode
|
||||
if(x == OP_CMP_CONST) {
|
||||
i += (cpu->regs.p.m)?2:3;
|
||||
} else if(x == OP_CPX_CONST || x == OP_CPY_CONST) {
|
||||
i += (cpu->regs.p.x)?2:3;
|
||||
} else if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) {
|
||||
i += 3;
|
||||
} else { //(x == OP_CMP_LONG) {
|
||||
i += 4;
|
||||
}
|
||||
x = mem_bus->read(addr + i);
|
||||
if(x == OP_BNE) {
|
||||
mem_bus->cart->write_protect(false);
|
||||
mem_bus->write(addr + i, OP_NOP);
|
||||
mem_bus->write(addr + i + 1, OP_NOP);
|
||||
mem_bus->cart->write_protect(true);
|
||||
} else if(x == OP_BEQ) {
|
||||
mem_bus->cart->write_protect(false);
|
||||
mem_bus->write(addr + i, OP_BRA);
|
||||
mem_bus->cart->write_protect(true);
|
||||
} else goto __test2;
|
||||
goto __pass;
|
||||
|
||||
//- lda $214x
|
||||
// cmp ???
|
||||
// beq/bne -
|
||||
__test2:
|
||||
//look for a repeated read pattern
|
||||
if(addr != p->read_addr[(p->read_pos - 1) & 31])goto __test3;
|
||||
if(addr != p->read_addr[(p->read_pos - 2) & 31])goto __test3;
|
||||
if(addr != p->read_addr[(p->read_pos - 3) & 31])goto __test3;
|
||||
if(addr != p->read_addr[(p->read_pos - 4) & 31])goto __test3;
|
||||
if(addr != p->read_addr[(p->read_pos - 5) & 31])goto __test3;
|
||||
if(addr != p->read_addr[(p->read_pos - 6) & 31])goto __test3;
|
||||
if(addr != p->read_addr[(p->read_pos - 7) & 31])goto __test3;
|
||||
if(addr != p->read_addr[(p->read_pos - 8) & 31])goto __test3;
|
||||
//try and find compare opcode
|
||||
for(i=0;i<24;i++) {
|
||||
x = mem_bus->read(addr + i);
|
||||
if(x == OP_CMP_CONST || x == OP_CPX_CONST || x == OP_CPY_CONST)break;
|
||||
if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) break;
|
||||
if(x == OP_CMP_LONG)break;
|
||||
}
|
||||
if(i == 24)goto __test3;
|
||||
//seek to next opcode
|
||||
if(x == OP_CMP_CONST) {
|
||||
i += (cpu->regs.p.m)?2:3;
|
||||
} else if(x == OP_CPX_CONST || x == OP_CPY_CONST) {
|
||||
i += (cpu->regs.p.x)?2:3;
|
||||
} else if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) {
|
||||
i += 3;
|
||||
} else if(x == OP_CMP_LONG) {
|
||||
i += 4;
|
||||
}
|
||||
x = mem_bus->read(addr + i);
|
||||
if(x == OP_BNE) {
|
||||
mem_bus->cart->write_protect(false);
|
||||
mem_bus->write(addr + i, OP_NOP);
|
||||
mem_bus->write(addr + i + 1, OP_NOP);
|
||||
mem_bus->cart->write_protect(true);
|
||||
} else if(x == OP_BEQ) {
|
||||
mem_bus->cart->write_protect(false);
|
||||
mem_bus->write(addr + i, OP_BRA);
|
||||
mem_bus->cart->write_protect(true);
|
||||
} else goto __test3;
|
||||
goto __pass;
|
||||
|
||||
//fallback
|
||||
__test3:
|
||||
if(p->pos < 4) {
|
||||
if(!(port & 1)) {
|
||||
p->value = cpu->regs.a.l;
|
||||
} else {
|
||||
p->value = cpu->regs.a.h;
|
||||
}
|
||||
} else if(p->pos < 8) {
|
||||
if(!(port & 1)) {
|
||||
p->value = cpu->regs.x.l;
|
||||
} else {
|
||||
p->value = cpu->regs.x.h;
|
||||
}
|
||||
} else if(p->pos < 12) {
|
||||
if(!(port & 1)) {
|
||||
p->value = cpu->regs.y.l;
|
||||
} else {
|
||||
p->value = cpu->regs.y.h;
|
||||
}
|
||||
} else if(p->pos < 16) {
|
||||
p->value = rand();
|
||||
}
|
||||
if(++p->pos == 16)p->pos = 0;
|
||||
|
||||
__pass:
|
||||
p->read_pos++;
|
||||
p->read_pos &= 31;
|
||||
return p->value;
|
||||
}
|
||||
|
||||
void bAPUSkip::port_write(uint8 port, uint8 value) {
|
||||
port &= 3;
|
||||
apu_port[port].value = value;
|
||||
}
|
||||
|
||||
void bAPUSkip::run() {
|
||||
snes->notify(SNES::APU_EXEC_OPCODE_BEGIN);
|
||||
snes->notify(SNES::APU_EXEC_OPCODE_END);
|
||||
}
|
||||
|
||||
void bAPUSkip::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void bAPUSkip::reset() {
|
||||
regs.a = 0x00;
|
||||
regs.x = 0x00;
|
||||
regs.y = 0x00;
|
||||
regs.sp = 0x00;
|
||||
regs.p = 0x02;
|
||||
regs.pc = 0xffc0;
|
||||
|
||||
memset(&apu_port[0], 0, sizeof(_apu_port));
|
||||
memset(&apu_port[1], 0, sizeof(_apu_port));
|
||||
memset(&apu_port[2], 0, sizeof(_apu_port));
|
||||
memset(&apu_port[3], 0, sizeof(_apu_port));
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
class bAPUSkip : public APU {
|
||||
public:
|
||||
|
||||
struct _apu_port {
|
||||
uint8 value;
|
||||
uint8 step, pos;
|
||||
uint32 read_addr[32], read_pos;
|
||||
}apu_port[4];
|
||||
|
||||
enum {
|
||||
OP_CMP_CONST = 0xc9,
|
||||
OP_CPX_CONST = 0xe0,
|
||||
OP_CPY_CONST = 0xc0,
|
||||
OP_CMP_ADDR = 0xcd,
|
||||
OP_CPX_ADDR = 0xec,
|
||||
OP_CPY_ADDR = 0xcc,
|
||||
OP_CMP_LONG = 0xcf,
|
||||
OP_BNE = 0xd0,
|
||||
OP_BEQ = 0xf0,
|
||||
OP_BRA = 0x80,
|
||||
OP_NOP = 0xea
|
||||
};
|
||||
|
||||
uint8 spcram_read (uint16 addr);
|
||||
void spcram_write(uint16 addr, uint8 value);
|
||||
uint8 port_read (uint8 port);
|
||||
void port_write (uint8 port, uint8 value);
|
||||
|
||||
void run();
|
||||
uint32 cycles_executed() { return 12 * 24; }
|
||||
void power();
|
||||
void reset();
|
||||
};
|
||||
+12
-1
@@ -1,12 +1,23 @@
|
||||
//virtual function, see src/cpu/dcpu.cpp
|
||||
//for explanation of this function
|
||||
bool APU::in_opcode() { return false; }
|
||||
|
||||
uint16 APU::__relb(int8 offset, int op_len) {
|
||||
uint16 pc = regs.pc + op_len;
|
||||
return pc + offset;
|
||||
}
|
||||
|
||||
void APU::disassemble_opcode(char *output) {
|
||||
char *s = output, t[512];
|
||||
char *s, t[512];
|
||||
uint8 op, op0, op1;
|
||||
uint16 opw, opdp0, opdp1;
|
||||
s = output;
|
||||
|
||||
if(in_opcode() == true) {
|
||||
strcpy(s, "..???? <APU within opcode>");
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(s, "..%0.4x ", regs.pc);
|
||||
|
||||
op = spcram_read(regs.pc);
|
||||
|
||||
+1
-8
@@ -3,12 +3,8 @@
|
||||
//allow writing to the IPLROM, all writes are
|
||||
//instead mapped to the extended SPC700 RAM region,
|
||||
//accessible when $f1 bit 7 is clear.
|
||||
//If you use this buffer directly, make sure not
|
||||
//to write to it, as this will break other APU
|
||||
//implementations that attempt to use this buffer.
|
||||
|
||||
#ifdef _APU_IPLROM
|
||||
const uint8 spc700_iplrom[64] = {
|
||||
const uint8 APU::iplrom[64] = {
|
||||
/*ffc0*/ 0xcd, 0xef, //mov x,#$ef
|
||||
/*ffc2*/ 0xbd, //mov sp,x
|
||||
/*ffc3*/ 0xe8, 0x00, //mov a,#$00
|
||||
@@ -43,6 +39,3 @@ const uint8 spc700_iplrom[64] = {
|
||||
/*fffb*/ 0x1f, 0x00, 0x00, //jmp ($0000+x)
|
||||
/*fffe*/ 0xc0, 0xff //---reset vector location ($ffc0)
|
||||
};
|
||||
#else
|
||||
extern const uint8 spc700_iplrom[64];
|
||||
#endif
|
||||
+33
-5
@@ -1,11 +1,39 @@
|
||||
//#define DEBUGGER
|
||||
//#define POLYMORPHISM
|
||||
|
||||
//this should be declared in the port-specific makefiles
|
||||
//#define ARCH_LSB
|
||||
//#define ARCH_MSB
|
||||
|
||||
#ifndef ARCH_LSB
|
||||
#ifndef ARCH_MSB
|
||||
#define ARCH_LSB
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include "lib/libbase.h"
|
||||
#include "lib/libvector.h"
|
||||
#include "lib/libstring.h"
|
||||
#include "lib/libconfig.h"
|
||||
|
||||
//structs
|
||||
typedef struct {
|
||||
uint8 *data;
|
||||
uint32 size;
|
||||
}lfile;
|
||||
inline uint16 read16(uint8 *addr, uint pos) {
|
||||
#ifdef ARCH_LSB
|
||||
return *((uint16*)(addr + pos));
|
||||
#else
|
||||
return (addr[pos]) | (addr[pos + 1] << 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define _WIN32_
|
||||
#undef _UNIX_
|
||||
#elif defined(__GNUC__)
|
||||
#define _UNIX_
|
||||
#undef _WIN32_
|
||||
#else
|
||||
#error "unknown architecture"
|
||||
#endif
|
||||
|
||||
//platform-specific global functions
|
||||
void *memalloc(uint32 size, char *name = 0, ...);
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
#include "../../base.h"
|
||||
#include "sdd1emu.cpp"
|
||||
|
||||
void SDD1::init() {
|
||||
}
|
||||
|
||||
void SDD1::enable() {
|
||||
for(int i=0x4800;i<=0x4807;i++) {
|
||||
r_mem->set_mmio_mapper(i, mmio);
|
||||
}
|
||||
}
|
||||
|
||||
void SDD1::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void SDD1::reset() {
|
||||
sdd1.index[0] = 0x000000;
|
||||
sdd1.index[1] = 0x100000;
|
||||
sdd1.index[2] = 0x200000;
|
||||
sdd1.index[3] = 0x300000;
|
||||
|
||||
for(int i=0;i<8;i++) {
|
||||
sdd1.active[i] = false;
|
||||
}
|
||||
|
||||
sdd1.dma_active = false;
|
||||
}
|
||||
|
||||
uint32 SDD1::offset(uint32 addr) {
|
||||
uint8 b = (addr >> 16) & 0xff;
|
||||
if(b <= 0xbf)return 0;
|
||||
|
||||
b -= 0xc0; //b = 0x00-0x3f
|
||||
b >>= 4; //b = 0-3
|
||||
b &= 3; //bitmask
|
||||
|
||||
return sdd1.index[b] + (addr & 0x0fffff);
|
||||
}
|
||||
|
||||
uint8 SDD1::mmio_read(uint16 addr) {
|
||||
switch(addr) {
|
||||
//>>20 == 0x100000 == 1mb
|
||||
case 0x4804:return (sdd1.index[0] >> 20) & 7;
|
||||
case 0x4805:return (sdd1.index[1] >> 20) & 7;
|
||||
case 0x4806:return (sdd1.index[2] >> 20) & 7;
|
||||
case 0x4807:return (sdd1.index[3] >> 20) & 7;
|
||||
}
|
||||
|
||||
return r_cpu->regs.mdr;
|
||||
}
|
||||
|
||||
void SDD1::mmio_write(uint16 addr, uint8 data) {
|
||||
int i;
|
||||
switch(addr) {
|
||||
case 0x4801:
|
||||
for(i=0;i<8;i++) {
|
||||
sdd1.active[i] = !!(data & (1 << i));
|
||||
}
|
||||
break;
|
||||
//<<20 == 0x100000 == 1mb
|
||||
case 0x4804:sdd1.index[0] = (data & 7) << 20;break;
|
||||
case 0x4805:sdd1.index[1] = (data & 7) << 20;break;
|
||||
case 0x4806:sdd1.index[2] = (data & 7) << 20;break;
|
||||
case 0x4807:sdd1.index[3] = (data & 7) << 20;break;
|
||||
}
|
||||
}
|
||||
|
||||
void SDD1::dma_begin(uint8 channel, uint32 addr, uint16 length) {
|
||||
if(sdd1.active[channel] == true) {
|
||||
sdd1.active[channel] = false;
|
||||
sdd1.dma_active = true;
|
||||
sdd1.buffer_index = 0;
|
||||
sdd1.buffer_size = length;
|
||||
sdd1emu.decompress(addr, (length) ? length : 65536, sdd1.buffer);
|
||||
}
|
||||
}
|
||||
|
||||
bool SDD1::dma_active() {
|
||||
return sdd1.dma_active;
|
||||
}
|
||||
|
||||
uint8 SDD1::dma_read() {
|
||||
if(--sdd1.buffer_size == 0) {
|
||||
sdd1.dma_active = false;
|
||||
}
|
||||
|
||||
//sdd1.buffer[] is 65536 bytes, and sdd1.buffer_index
|
||||
//is of type uint16, so no buffer overflow is possible
|
||||
return sdd1.buffer[sdd1.buffer_index++];
|
||||
}
|
||||
|
||||
SDD1::SDD1() {
|
||||
mmio = new SDD1MMIO();
|
||||
}
|
||||
|
||||
uint8 SDD1MMIO::read(uint32 addr) {
|
||||
return sdd1->mmio_read(addr);
|
||||
}
|
||||
|
||||
void SDD1MMIO::write(uint32 addr, uint8 value) {
|
||||
sdd1->mmio_write(addr, value);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#include "sdd1emu.h"
|
||||
|
||||
class SDD1MMIO : public MMIO {
|
||||
public:
|
||||
inline uint8 read (uint32 addr);
|
||||
inline void write(uint32 addr, uint8 value);
|
||||
};
|
||||
|
||||
class SDD1 {
|
||||
public:
|
||||
SDD1emu sdd1emu;
|
||||
SDD1MMIO *mmio;
|
||||
|
||||
struct {
|
||||
uint32 index[4]; //memory mapping registers
|
||||
uint8 buffer[65536]; //pointer to decompressed S-DD1 data,
|
||||
//max. DMA length is 65536
|
||||
uint16 buffer_index; //DMA read index into S-DD1 decompression buffer
|
||||
uint16 buffer_size;
|
||||
bool active[8]; //true when DMA channel should pass through S-DD1
|
||||
bool dma_active;
|
||||
}sdd1;
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
uint32 offset(uint32 addr);
|
||||
|
||||
void dma_begin(uint8 channel, uint32 addr, uint16 length);
|
||||
bool dma_active();
|
||||
uint8 dma_read();
|
||||
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
SDD1();
|
||||
};
|
||||
@@ -0,0 +1,447 @@
|
||||
/************************************************************************
|
||||
|
||||
S-DD1'algorithm emulation code
|
||||
------------------------------
|
||||
|
||||
Author: Andreas Naive
|
||||
Date: August 2003
|
||||
Last update: October 2004
|
||||
|
||||
This code is Public Domain. There is no copyright holded by the author.
|
||||
Said this, the author wish to explicitly emphasize his inalienable moral rights
|
||||
over this piece of intelectual work and the previous research that made it
|
||||
possible, as recognized by most of the copyright laws around the world.
|
||||
|
||||
This code is provided 'as-is', with no warranty, expressed or implied.
|
||||
No responsability is assumed by the author in connection with it.
|
||||
|
||||
The author is greatly indebted with The Dumper, without whose help and
|
||||
patience providing him with real S-DD1 data the research would have never been
|
||||
possible. He also wish to note that in the very beggining of his research,
|
||||
Neviksti had done some steps in the right direction. By last, the author is
|
||||
indirectly indebted to all the people that worked and contributed in the
|
||||
S-DD1 issue in the past.
|
||||
|
||||
An algorithm's documentation is available as a separate document.
|
||||
The implementation is obvious when the algorithm is
|
||||
understood.
|
||||
|
||||
************************************************************************/
|
||||
|
||||
#define SDD1_read(__addr) (r_mem->read(__addr))
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_IM::prepareDecomp(uint32 in_buf) {
|
||||
|
||||
byte_ptr=in_buf;
|
||||
bit_count=4;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
||||
uint8 SDD1_IM::getCodeword(uint8 code_len) {
|
||||
|
||||
uint8 codeword;
|
||||
uint8 comp_count;
|
||||
|
||||
codeword = (SDD1_read(byte_ptr))<<bit_count;
|
||||
|
||||
++bit_count;
|
||||
|
||||
if (codeword & 0x80) {
|
||||
codeword |= SDD1_read(byte_ptr+1)>>(9-bit_count);
|
||||
bit_count+=code_len;
|
||||
}
|
||||
|
||||
if (bit_count & 0x08) {
|
||||
byte_ptr++;
|
||||
bit_count&=0x07;
|
||||
}
|
||||
|
||||
return codeword;
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1_GCD::SDD1_GCD(SDD1_IM *associatedIM) :
|
||||
IM(associatedIM)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_GCD::getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind) {
|
||||
|
||||
const uint8 run_count[] = {
|
||||
0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00,
|
||||
0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00,
|
||||
0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01,
|
||||
0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00,
|
||||
0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03,
|
||||
0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01,
|
||||
0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02,
|
||||
0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00,
|
||||
0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07,
|
||||
0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03,
|
||||
0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05,
|
||||
0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01,
|
||||
0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06,
|
||||
0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02,
|
||||
0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04,
|
||||
0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00,
|
||||
0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f,
|
||||
0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07,
|
||||
0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b,
|
||||
0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03,
|
||||
0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d,
|
||||
0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05,
|
||||
0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09,
|
||||
0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01,
|
||||
0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e,
|
||||
0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06,
|
||||
0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a,
|
||||
0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02,
|
||||
0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c,
|
||||
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04,
|
||||
0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
|
||||
0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00,
|
||||
};
|
||||
|
||||
uint8 codeword=IM->getCodeword(code_num);
|
||||
|
||||
if (codeword & 0x80) {
|
||||
*LPSind=1;
|
||||
*MPScount=run_count[codeword>>(code_num^0x07)];
|
||||
}
|
||||
else {
|
||||
*MPScount=(1<<code_num);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
SDD1_BG::SDD1_BG(SDD1_GCD *associatedGCD, uint8 code) :
|
||||
GCD(associatedGCD), code_num(code)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_BG::prepareDecomp(void) {
|
||||
|
||||
MPScount=0;
|
||||
LPSind=0;
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
|
||||
|
||||
uint8 SDD1_BG::getBit(bool8 *endOfRun) {
|
||||
|
||||
uint8 bit;
|
||||
|
||||
if (!(MPScount || LPSind)) GCD->getRunCount(code_num, &MPScount, &LPSind);
|
||||
|
||||
if (MPScount) {
|
||||
bit=0;
|
||||
MPScount--;
|
||||
}
|
||||
else {
|
||||
bit=1;
|
||||
LPSind=0;
|
||||
}
|
||||
|
||||
if (MPScount || LPSind) (*endOfRun)=0;
|
||||
else (*endOfRun)=1;
|
||||
|
||||
return bit;
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1_PEM::SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
|
||||
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
|
||||
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
|
||||
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7) {
|
||||
|
||||
BG[0]=associatedBG0;
|
||||
BG[1]=associatedBG1;
|
||||
BG[2]=associatedBG2;
|
||||
BG[3]=associatedBG3;
|
||||
BG[4]=associatedBG4;
|
||||
BG[5]=associatedBG5;
|
||||
BG[6]=associatedBG6;
|
||||
BG[7]=associatedBG7;
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
const SDD1_PEM::state SDD1_PEM::evolution_table[]={
|
||||
{ 0,25,25},
|
||||
{ 0, 2, 1},
|
||||
{ 0, 3, 1},
|
||||
{ 0, 4, 2},
|
||||
{ 0, 5, 3},
|
||||
{ 1, 6, 4},
|
||||
{ 1, 7, 5},
|
||||
{ 1, 8, 6},
|
||||
{ 1, 9, 7},
|
||||
{ 2,10, 8},
|
||||
{ 2,11, 9},
|
||||
{ 2,12,10},
|
||||
{ 2,13,11},
|
||||
{ 3,14,12},
|
||||
{ 3,15,13},
|
||||
{ 3,16,14},
|
||||
{ 3,17,15},
|
||||
{ 4,18,16},
|
||||
{ 4,19,17},
|
||||
{ 5,20,18},
|
||||
{ 5,21,19},
|
||||
{ 6,22,20},
|
||||
{ 6,23,21},
|
||||
{ 7,24,22},
|
||||
{ 7,24,23},
|
||||
{ 0,26, 1},
|
||||
{ 1,27, 2},
|
||||
{ 2,28, 4},
|
||||
{ 3,29, 8},
|
||||
{ 4,30,12},
|
||||
{ 5,31,16},
|
||||
{ 6,32,18},
|
||||
{ 7,24,22}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_PEM::prepareDecomp(void) {
|
||||
|
||||
for (uint8 i=0; i<32; i++) {
|
||||
contextInfo[i].status=0;
|
||||
contextInfo[i].MPS=0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
uint8 SDD1_PEM::getBit(uint8 context) {
|
||||
|
||||
bool8 endOfRun;
|
||||
uint8 bit;
|
||||
|
||||
SDD1_ContextInfo *pContInfo=&contextInfo[context];
|
||||
uint8 currStatus = pContInfo->status;
|
||||
const state *pState=&SDD1_PEM::evolution_table[currStatus];
|
||||
uint8 currentMPS=pContInfo->MPS;
|
||||
|
||||
bit=(BG[pState->code_num])->getBit(&endOfRun);
|
||||
|
||||
if (endOfRun)
|
||||
if (bit) {
|
||||
if (!(currStatus & 0xfe)) (pContInfo->MPS)^=0x01;
|
||||
(pContInfo->status)=pState->nextIfLPS;
|
||||
}
|
||||
else
|
||||
(pContInfo->status)=pState->nextIfMPS;
|
||||
|
||||
return bit^currentMPS;
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1_CM::SDD1_CM(SDD1_PEM *associatedPEM) :
|
||||
PEM(associatedPEM)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_CM::prepareDecomp(uint32 first_byte) {
|
||||
|
||||
bitplanesInfo = SDD1_read(first_byte) & 0xc0;
|
||||
contextBitsInfo = SDD1_read(first_byte) & 0x30;
|
||||
bit_number=0;
|
||||
for (int i=0; i<8; i++) prevBitplaneBits[i]=0;
|
||||
switch (bitplanesInfo) {
|
||||
case 0x00:
|
||||
currBitplane = 1;
|
||||
break;
|
||||
case 0x40:
|
||||
currBitplane = 7;
|
||||
break;
|
||||
case 0x80:
|
||||
currBitplane = 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
uint8 SDD1_CM::getBit(void) {
|
||||
|
||||
uint8 currContext;
|
||||
uint16 *context_bits;
|
||||
|
||||
switch (bitplanesInfo) {
|
||||
case 0x00:
|
||||
currBitplane ^= 0x01;
|
||||
break;
|
||||
case 0x40:
|
||||
currBitplane ^= 0x01;
|
||||
if (!(bit_number & 0x7f)) currBitplane = ((currBitplane+2) & 0x07);
|
||||
break;
|
||||
case 0x80:
|
||||
currBitplane ^= 0x01;
|
||||
if (!(bit_number & 0x7f)) currBitplane ^= 0x02;
|
||||
break;
|
||||
case 0xc0:
|
||||
currBitplane = bit_number & 0x07;
|
||||
}
|
||||
|
||||
context_bits = &prevBitplaneBits[currBitplane];
|
||||
|
||||
currContext=(currBitplane & 0x01)<<4;
|
||||
switch (contextBitsInfo) {
|
||||
case 0x00:
|
||||
currContext|=((*context_bits & 0x01c0)>>5)|(*context_bits & 0x0001);
|
||||
break;
|
||||
case 0x10:
|
||||
currContext|=((*context_bits & 0x0180)>>5)|(*context_bits & 0x0001);
|
||||
break;
|
||||
case 0x20:
|
||||
currContext|=((*context_bits & 0x00c0)>>5)|(*context_bits & 0x0001);
|
||||
break;
|
||||
case 0x30:
|
||||
currContext|=((*context_bits & 0x0180)>>5)|(*context_bits & 0x0003);
|
||||
}
|
||||
|
||||
uint8 bit=PEM->getBit(currContext);
|
||||
|
||||
*context_bits <<= 1;
|
||||
*context_bits |= bit;
|
||||
|
||||
bit_number++;
|
||||
|
||||
return bit;
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1_OL::SDD1_OL(SDD1_CM *associatedCM) :
|
||||
CM(associatedCM)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_OL::prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf) {
|
||||
|
||||
bitplanesInfo = SDD1_read(first_byte) & 0xc0;
|
||||
length=out_len;
|
||||
buffer=out_buf;
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1_OL::launch(void) {
|
||||
|
||||
uint8 i;
|
||||
uint8 register1, register2;
|
||||
|
||||
switch (bitplanesInfo) {
|
||||
case 0x00:
|
||||
case 0x40:
|
||||
case 0x80:
|
||||
i=1;
|
||||
do { //if length==0, we output 2^16 bytes
|
||||
if (!i) {
|
||||
*(buffer++)=register2;
|
||||
i=~i;
|
||||
}
|
||||
else {
|
||||
for (register1=register2=0, i=0x80; i; i>>=1) {
|
||||
if (CM->getBit()) register1 |= i;
|
||||
if (CM->getBit()) register2 |= i;
|
||||
}
|
||||
*(buffer++)=register1;
|
||||
}
|
||||
} while (--length);
|
||||
break;
|
||||
case 0xc0:
|
||||
do {
|
||||
for (register1=0, i=0x01; i; i<<=1) {
|
||||
if (CM->getBit()) register1 |= i;
|
||||
}
|
||||
*(buffer++)=register1;
|
||||
} while (--length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SDD1emu::decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf) {
|
||||
|
||||
IM.prepareDecomp(in_buf);
|
||||
BG0.prepareDecomp();
|
||||
BG1.prepareDecomp();
|
||||
BG2.prepareDecomp();
|
||||
BG3.prepareDecomp();
|
||||
BG4.prepareDecomp();
|
||||
BG5.prepareDecomp();
|
||||
BG6.prepareDecomp();
|
||||
BG7.prepareDecomp();
|
||||
PEM.prepareDecomp();
|
||||
CM.prepareDecomp(in_buf);
|
||||
OL.prepareDecomp(in_buf, out_len, out_buf);
|
||||
|
||||
OL.launch();
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
SDD1emu::SDD1emu() :
|
||||
GCD(&IM),
|
||||
BG0(&GCD, 0), BG1(&GCD, 1), BG2(&GCD, 2), BG3(&GCD, 3),
|
||||
BG4(&GCD, 4), BG5(&GCD, 5), BG6(&GCD, 6), BG7(&GCD, 7),
|
||||
PEM(&BG0, &BG1, &BG2, &BG3, &BG4, &BG5, &BG6, &BG7),
|
||||
CM(&PEM),
|
||||
OL(&CM)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,161 @@
|
||||
/************************************************************************
|
||||
|
||||
S-DD1'algorithm emulation code
|
||||
------------------------------
|
||||
|
||||
Author: Andreas Naive
|
||||
Date: August 2003
|
||||
Last update: October 2004
|
||||
|
||||
This code is Public Domain. There is no copyright holded by the author.
|
||||
Said this, the author wish to explicitly emphasize his inalienable moral rights
|
||||
over this piece of intelectual work and the previous research that made it
|
||||
possible, as recognized by most of the copyright laws around the world.
|
||||
|
||||
This code is provided 'as-is', with no warranty, expressed or implied.
|
||||
No responsability is assumed by the author in connection with it.
|
||||
|
||||
The author is greatly indebted with The Dumper, without whose help and
|
||||
patience providing him with real S-DD1 data the research would have never been
|
||||
possible. He also wish to note that in the very beggining of his research,
|
||||
Neviksti had done some steps in the right direction. By last, the author is
|
||||
indirectly indebted to all the people that worked and contributed in the
|
||||
S-DD1 issue in the past.
|
||||
|
||||
An algorithm's documentation is available as a separate document.
|
||||
The implementation is obvious when the algorithm is
|
||||
understood.
|
||||
|
||||
************************************************************************/
|
||||
|
||||
|
||||
class SDD1_IM { //Input Manager
|
||||
|
||||
public:
|
||||
SDD1_IM(void) {}
|
||||
void prepareDecomp(uint32 in_buf);
|
||||
uint8 getCodeword(const uint8 code_len);
|
||||
|
||||
private:
|
||||
uint32 byte_ptr;
|
||||
uint8 bit_count;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_GCD { //Golomb-Code Decoder
|
||||
|
||||
public:
|
||||
SDD1_GCD(SDD1_IM *associatedIM);
|
||||
void getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind);
|
||||
|
||||
private:
|
||||
SDD1_IM *const IM;
|
||||
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_BG { // Bits Generator
|
||||
|
||||
public:
|
||||
SDD1_BG(SDD1_GCD *associatedGCD, uint8 code);
|
||||
void prepareDecomp(void);
|
||||
uint8 getBit(bool8 *endOfRun);
|
||||
|
||||
private:
|
||||
const uint8 code_num;
|
||||
uint8 MPScount;
|
||||
bool8 LPSind;
|
||||
SDD1_GCD *const GCD;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_PEM { //Probability Estimation Module
|
||||
|
||||
public:
|
||||
SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
|
||||
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
|
||||
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
|
||||
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7);
|
||||
void prepareDecomp(void);
|
||||
uint8 getBit(uint8 context);
|
||||
|
||||
private:
|
||||
struct state {
|
||||
uint8 code_num;
|
||||
uint8 nextIfMPS;
|
||||
uint8 nextIfLPS;
|
||||
};
|
||||
static const state evolution_table[];
|
||||
struct SDD1_ContextInfo {
|
||||
uint8 status;
|
||||
uint8 MPS;
|
||||
} contextInfo[32];
|
||||
SDD1_BG * BG[8];
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_CM { //Context Model
|
||||
|
||||
public:
|
||||
SDD1_CM(SDD1_PEM *associatedPEM);
|
||||
void prepareDecomp(uint32 first_byte);
|
||||
uint8 getBit(void);
|
||||
|
||||
private:
|
||||
uint8 bitplanesInfo;
|
||||
uint8 contextBitsInfo;
|
||||
uint8 bit_number;
|
||||
uint8 currBitplane;
|
||||
uint16 prevBitplaneBits[8];
|
||||
SDD1_PEM *const PEM;
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_OL { //Output Logic
|
||||
|
||||
public:
|
||||
SDD1_OL(SDD1_CM *associatedCM);
|
||||
void prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf);
|
||||
void launch(void);
|
||||
|
||||
private:
|
||||
uint8 bitplanesInfo;
|
||||
uint16 length;
|
||||
uint8 *buffer;
|
||||
SDD1_CM *const CM;
|
||||
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1emu {
|
||||
|
||||
public:
|
||||
SDD1emu(void);
|
||||
void decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf);
|
||||
|
||||
private:
|
||||
SDD1_IM IM;
|
||||
SDD1_GCD GCD;
|
||||
SDD1_BG BG0; SDD1_BG BG1; SDD1_BG BG2; SDD1_BG BG3;
|
||||
SDD1_BG BG4; SDD1_BG BG5; SDD1_BG BG6; SDD1_BG BG7;
|
||||
SDD1_PEM PEM;
|
||||
SDD1_CM CM;
|
||||
SDD1_OL OL;
|
||||
|
||||
};
|
||||
@@ -50,7 +50,9 @@
|
||||
whenever the RTC is set.
|
||||
*/
|
||||
|
||||
void bCPU::srtc_set_time() {
|
||||
#include "../../base.h"
|
||||
|
||||
void SRTC::set_time() {
|
||||
time_t rawtime;
|
||||
tm *t;
|
||||
::time(&rawtime);
|
||||
@@ -72,12 +74,20 @@ tm *t;
|
||||
srtc.data[12] = t->tm_wday;
|
||||
}
|
||||
|
||||
void bCPU::srtc_power() {
|
||||
void SRTC::init() {
|
||||
}
|
||||
|
||||
void SRTC::enable() {
|
||||
r_mem->set_mmio_mapper(0x2800, mmio);
|
||||
r_mem->set_mmio_mapper(0x2801, mmio);
|
||||
}
|
||||
|
||||
void SRTC::power() {
|
||||
memset(&srtc, 0, sizeof(srtc));
|
||||
reset();
|
||||
}
|
||||
|
||||
void bCPU::srtc_reset() {
|
||||
void SRTC::reset() {
|
||||
srtc.index = -1;
|
||||
srtc.mode = SRTC_READ;
|
||||
}
|
||||
@@ -87,7 +97,7 @@ void bCPU::srtc_reset() {
|
||||
//as reads will refresh the data array with the current system
|
||||
//time. The write method is only here for the sake of faux
|
||||
//emulation of the real hardware.
|
||||
void bCPU::srtc_write(uint8 data) {
|
||||
void SRTC::write(uint8 data) {
|
||||
data &= 0x0f; //only the low four bits are used
|
||||
|
||||
if(data >= 0x0d) {
|
||||
@@ -140,10 +150,10 @@ void bCPU::srtc_write(uint8 data) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8 bCPU::srtc_read() {
|
||||
uint8 SRTC::read() {
|
||||
if(srtc.mode == SRTC_READ) {
|
||||
if(srtc.index < 0) {
|
||||
srtc_set_time();
|
||||
set_time();
|
||||
srtc.index++;
|
||||
return 0x0f; //send start message
|
||||
} else if(srtc.index > MAX_SRTC_INDEX) {
|
||||
@@ -156,3 +166,21 @@ uint8 bCPU::srtc_read() {
|
||||
return 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
SRTC::SRTC() {
|
||||
mmio = new SRTCMMIO();
|
||||
}
|
||||
|
||||
uint8 SRTCMMIO::read(uint32 addr) {
|
||||
switch(addr) {
|
||||
case 0x2800:return srtc->read();
|
||||
}
|
||||
|
||||
return r_cpu->regs.mdr;
|
||||
}
|
||||
|
||||
void SRTCMMIO::write(uint32 addr, uint8 value) {
|
||||
switch(addr) {
|
||||
case 0x2801:srtc->write(value);break;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
void srtc_set_time();
|
||||
void srtc_power();
|
||||
void srtc_reset();
|
||||
void srtc_write(uint8 data);
|
||||
uint8 srtc_read();
|
||||
class SRTCMMIO : public MMIO {
|
||||
public:
|
||||
inline uint8 read (uint32 addr);
|
||||
inline void write(uint32 addr, uint8 value);
|
||||
};
|
||||
|
||||
#define MAX_SRTC_INDEX 0x0c
|
||||
class SRTC {
|
||||
public:
|
||||
enum { MAX_SRTC_INDEX = 0x0c };
|
||||
|
||||
enum {
|
||||
SRTC_READ = 0,
|
||||
@@ -18,9 +20,7 @@ enum {
|
||||
SRTC_COMMAND_CLEAR = 4
|
||||
};
|
||||
|
||||
#define DAYTICKS (60*60*24)
|
||||
#define HOURTICKS (60*60)
|
||||
#define MINUTETICKS (60)
|
||||
SRTCMMIO *mmio;
|
||||
|
||||
/******************************
|
||||
[srtc.data structure]
|
||||
@@ -38,11 +38,20 @@ Index Description Range
|
||||
9 Year ones 0-9
|
||||
10 Year tens 0-9
|
||||
11 Year hundreds 9-11 (9=19xx, 10=20xx, 11=21xx)
|
||||
12 Day of week 0-6 (0=Sunday, ...)
|
||||
12 Day of week 0-6 (0=Sunday, ...)
|
||||
******************************/
|
||||
|
||||
struct {
|
||||
int8 index;
|
||||
uint8 mode;
|
||||
uint8 data[MAX_SRTC_INDEX + 1];
|
||||
}srtc;
|
||||
int8 index;
|
||||
uint8 mode;
|
||||
uint8 data[MAX_SRTC_INDEX + 1];
|
||||
} srtc;
|
||||
void set_time();
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
void write(uint8 data);
|
||||
uint8 read();
|
||||
|
||||
SRTC();
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
};
|
||||
+82
-184
@@ -1,7 +1,5 @@
|
||||
#include "../../base.h"
|
||||
|
||||
#include "srtc.cpp"
|
||||
|
||||
#include "bcpu_opfn.cpp"
|
||||
#include "bcpu_op_read.cpp"
|
||||
#include "bcpu_op_rmw.cpp"
|
||||
@@ -15,172 +13,70 @@
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
bool bCPU::hdma_test() {
|
||||
if(status.hdma_triggered == false) {
|
||||
if(vcounter() < (overscan()?239:224) && hcounter() >= 278) {
|
||||
status.hdma_triggered = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bCPU::nmi_test() {
|
||||
if(vcounter() >= ((overscan()?239:224) + 1) && status.nmi_triggered == false) {
|
||||
if((vcounter() == ((overscan()?239:224) + 1) && hcycles() >= 12) || (vcounter() > ((overscan()?239:224) + 1))) {
|
||||
status.nmi_triggered = true;
|
||||
status.nmi_pin = 0;
|
||||
if(status.nmi_enabled == true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bCPU::irq_test() {
|
||||
int vpos, hpos;
|
||||
if(regs.p.i)return false; //no interrupt can occur with I flag set
|
||||
if(status.irq_pin == 0)return false; //same as above
|
||||
if(status.virq_enabled == false && status.hirq_enabled == false)return false;
|
||||
|
||||
//calculate V/H positions required for IRQ to trigger
|
||||
vpos = status.virq_pos;
|
||||
hpos = (status.hirq_enabled) ? status.hirq_pos : 0;
|
||||
|
||||
//positions that can never be latched
|
||||
if(vpos == 261 && hpos == 339 && interlace() == false)return false;
|
||||
if(vpos == 262 && interlace() == false)return false;
|
||||
if(vpos == 262 && hpos == 339)return false;
|
||||
if(vpos > 262)return false;
|
||||
if(hpos > 339)return false;
|
||||
|
||||
if(hpos == 0) {
|
||||
hpos = 24;
|
||||
} else {
|
||||
hpos <<= 2;
|
||||
hpos += 24; //30 - status.cycle_count;
|
||||
//it should be OK to use the current line cycles/frame lines,
|
||||
//as the IRQ will only trigger on the correct scanline anyway...
|
||||
if(hpos >= time.line_cycles) {
|
||||
hpos -= time.line_cycles;
|
||||
vpos++;
|
||||
if(vpos >= time.frame_lines) {
|
||||
vpos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(status.virq_enabled == true && vcounter() != vpos)return false;
|
||||
|
||||
if(hcycles() >= hpos && status.irq_pin == 1) {
|
||||
//dprintf("* vpos=%3d,hpos=%4d; v=%3d,h=%4d; lc=%d,virq=%3d,hirq=%3d",
|
||||
// vpos, hpos, vcounter(), hcycles(), status.cycle_count, status.virq_pos, status.hirq_pos);
|
||||
status.irq_triggered = true;
|
||||
status.irq_pin = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
uint8 bCPU::pio_status() { return status.pio; }
|
||||
|
||||
void bCPU::run() {
|
||||
switch(status.cpu_state) {
|
||||
case CPUSTATE_DMA:
|
||||
dma_run();
|
||||
break;
|
||||
case CPUSTATE_RUN:
|
||||
case CPUSTATE_WAI:
|
||||
if(nmi_test() == true) {
|
||||
irq(0xffea);
|
||||
break;
|
||||
}
|
||||
if(irq_test() == true) {
|
||||
irq(0xffee);
|
||||
break;
|
||||
}
|
||||
exec_opcode();
|
||||
break;
|
||||
case CPUSTATE_STP:
|
||||
exec_opcode();
|
||||
break;
|
||||
if(run_state.hdma) {
|
||||
exec_hdma();
|
||||
return;
|
||||
}
|
||||
|
||||
if(run_state.dma) {
|
||||
exec_dma();
|
||||
return;
|
||||
}
|
||||
|
||||
if(status.cycle_pos == 0) {
|
||||
//interrupts only trigger on opcode edges
|
||||
if(!run_state.irq && !run_state.stp) {
|
||||
if(time.nmi_pending == true) {
|
||||
time.nmi_pending = false;
|
||||
aa.w = 0xffea;
|
||||
run_state.irq = true;
|
||||
} else if(time.irq_pending == true) {
|
||||
time.irq_pending = false;
|
||||
aa.w = 0xffee;
|
||||
run_state.irq = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exec_cycle();
|
||||
}
|
||||
|
||||
void bCPU::scanline() {
|
||||
status.hdma_triggered = false;
|
||||
time.hdma_triggered = false;
|
||||
|
||||
if(vcounter() == 225 && status.auto_joypad_poll == true) {
|
||||
snes->poll_input();
|
||||
snes->poll_input(SNES::DEV_JOYPAD1);
|
||||
snes->poll_input(SNES::DEV_JOYPAD2);
|
||||
//When the SNES auto-polls the joypads, it writes 1, then 0 to
|
||||
//$4016, then reads from each 16 times to get the joypad state
|
||||
//information. As a result, the joypad read positions are set
|
||||
//to 16 after such a poll. Position 16 is the controller
|
||||
//connected status bit.
|
||||
status.joypad1_read_pos = 16;
|
||||
}
|
||||
|
||||
if(status.virq_enabled == false) {
|
||||
status.irq_pin = 1;
|
||||
status.joypad2_read_pos = 16;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::frame() {
|
||||
hdma_initialize();
|
||||
time.nmi_read = 1;
|
||||
time.nmi_line = 1;
|
||||
time.nmi_transition = 0;
|
||||
|
||||
status.nmi_triggered = false;
|
||||
status.nmi_pin = 1;
|
||||
status.r4210_read = false;
|
||||
|
||||
status.irq_triggered = false;
|
||||
status.irq_pin = 1;
|
||||
if(cpu_version == 2) {
|
||||
time.hdmainit_trigger_pos = 12 + dma_counter();
|
||||
} else {
|
||||
time.hdmainit_trigger_pos = 12 + 8 - dma_counter();
|
||||
}
|
||||
time.hdmainit_triggered = false;
|
||||
}
|
||||
|
||||
void bCPU::power() {
|
||||
srtc_power();
|
||||
region = snes->region();
|
||||
|
||||
regs.a = regs.x = regs.y = 0x0000;
|
||||
regs.s = 0x01ff;
|
||||
@@ -188,12 +84,8 @@ void bCPU::power() {
|
||||
}
|
||||
|
||||
void bCPU::reset() {
|
||||
srtc_reset();
|
||||
|
||||
frame();
|
||||
|
||||
//reset vector location
|
||||
regs.pc = mem_bus->read(0xfffc) | (mem_bus->read(0xfffd) << 8);
|
||||
regs.pc = r_mem->read(0xfffc) | (r_mem->read(0xfffd) << 8);
|
||||
|
||||
//registers are not fully reset by SNES
|
||||
regs.x.h = 0x00;
|
||||
@@ -203,26 +95,33 @@ void bCPU::reset() {
|
||||
regs.db = 0x00;
|
||||
regs.p = 0x34;
|
||||
regs.e = 1;
|
||||
regs.mdr = 0x00;
|
||||
|
||||
time_reset();
|
||||
mmio_reset();
|
||||
dma_reset();
|
||||
|
||||
status.cpu_state = CPUSTATE_RUN;
|
||||
run_state.hdma = false;
|
||||
run_state.dma = false;
|
||||
run_state.irq = false;
|
||||
run_state.wai = false;
|
||||
run_state.stp = false;
|
||||
|
||||
status.hdma_triggered = false;
|
||||
|
||||
status.nmi_triggered = false;
|
||||
status.nmi_pin = 1;
|
||||
status.r4210_read = false;
|
||||
|
||||
status.irq_triggered = false;
|
||||
status.irq_pin = 1;
|
||||
status.cycle_pos = 0;
|
||||
status.cycle_count = 0;
|
||||
status.cycles_executed = 0;
|
||||
|
||||
apu_port[0] = 0x00;
|
||||
apu_port[1] = 0x00;
|
||||
apu_port[2] = 0x00;
|
||||
apu_port[3] = 0x00;
|
||||
|
||||
frame();
|
||||
|
||||
//initial latch values for $213c/$213d
|
||||
//[x]0035 : [y]0000 (53.0 -> 212) [lda $2137]
|
||||
//[x]0038 : [y]0000 (56.5 -> 226) [nop : lda $2137]
|
||||
add_cycles(186);
|
||||
}
|
||||
|
||||
uint8 bCPU::port_read(uint8 port) {
|
||||
@@ -235,50 +134,52 @@ void bCPU::port_write(uint8 port, uint8 value) {
|
||||
|
||||
void bCPU::cpu_c2() {
|
||||
if(regs.d.l != 0x00) {
|
||||
status.cycle_count = 6;
|
||||
cycle_edge();
|
||||
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;
|
||||
cycle_edge();
|
||||
add_cycles(6);
|
||||
cpu_io();
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::cpu_c6(uint16 addr) {
|
||||
if(regs.e && (regs.pc.w & 0xff00) != (addr & 0xff00)) {
|
||||
status.cycle_count = 6;
|
||||
cycle_edge();
|
||||
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.d0 FastROM enable bit.
|
||||
*/
|
||||
|
||||
void bCPU::cpu_io() {
|
||||
status.cycle_count = 6;
|
||||
cycle_edge();
|
||||
pre_exec_cycle();
|
||||
add_cycles(6);
|
||||
cycle_edge();
|
||||
}
|
||||
|
||||
uint8 bCPU::mem_read(uint32 addr) {
|
||||
uint8 r;
|
||||
status.cycle_count = mem_bus->speed(addr);
|
||||
status.cycle_count = r_mem->speed(addr);
|
||||
pre_exec_cycle();
|
||||
add_cycles(status.cycle_count - 4);
|
||||
regs.mdr = r_mem->read(addr);
|
||||
add_cycles(4);
|
||||
cycle_edge();
|
||||
add_cycles(2);
|
||||
r = mem_bus->read(addr);
|
||||
add_cycles(status.cycle_count - 2);
|
||||
return r;
|
||||
return regs.mdr;
|
||||
}
|
||||
|
||||
void bCPU::mem_write(uint32 addr, uint8 value) {
|
||||
status.cycle_count = mem_bus->speed(addr);
|
||||
status.cycle_count = r_mem->speed(addr);
|
||||
pre_exec_cycle();
|
||||
add_cycles(status.cycle_count);
|
||||
r_mem->write(addr, value);
|
||||
cycle_edge();
|
||||
add_cycles(6);
|
||||
mem_bus->write(addr, value);
|
||||
add_cycles(status.cycle_count - 6);
|
||||
}
|
||||
|
||||
uint32 bCPU::op_addr(uint8 mode, uint32 addr) {
|
||||
@@ -290,12 +191,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;
|
||||
@@ -345,9 +245,7 @@ void bCPU::stack_write(uint8 value) {
|
||||
}
|
||||
|
||||
bCPU::bCPU() {
|
||||
time_init();
|
||||
mmio = new bCPUMMIO(this);
|
||||
|
||||
init_op_tables();
|
||||
}
|
||||
|
||||
|
||||
+95
-61
@@ -10,11 +10,12 @@ 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;
|
||||
|
||||
public:
|
||||
#include "srtc.h"
|
||||
#include "bcpu_timing.h"
|
||||
|
||||
uint8 apu_port[4];
|
||||
@@ -31,41 +32,49 @@ CPUReg24 aa, rd;
|
||||
uint8 dp, sp;
|
||||
|
||||
enum {
|
||||
CPUSTATE_RUN = 0,
|
||||
CPUSTATE_WAI,
|
||||
CPUSTATE_STP,
|
||||
CPUSTATE_DMA
|
||||
};
|
||||
|
||||
enum {
|
||||
DMASTATE_STOP = 0,
|
||||
DMASTATE_INIT,
|
||||
DMASTATE_DMASYNC,
|
||||
DMASTATE_DMASYNC2,
|
||||
DMASTATE_DMASYNC3,
|
||||
DMASTATE_RUN,
|
||||
DMASTATE_CPUSYNC
|
||||
DMASTATE_CPUSYNC,
|
||||
|
||||
HDMASTATE_IDMASYNC,
|
||||
HDMASTATE_IDMASYNC2,
|
||||
HDMASTATE_IDMASYNC3,
|
||||
HDMASTATE_ICPUSYNC,
|
||||
|
||||
HDMASTATE_DMASYNC,
|
||||
HDMASTATE_DMASYNC2,
|
||||
HDMASTATE_DMASYNC3,
|
||||
HDMASTATE_RUN,
|
||||
HDMASTATE_CPUSYNC
|
||||
};
|
||||
|
||||
struct {
|
||||
uint8 cpu_state, cycle_count;
|
||||
bool hdma;
|
||||
bool dma;
|
||||
bool irq;
|
||||
bool stp;
|
||||
bool wai;
|
||||
} run_state;
|
||||
|
||||
uint8 dma_state;
|
||||
uint32 dma_cycle_count;
|
||||
bool hdma_triggered;
|
||||
struct {
|
||||
uint8 cycle_pos, cycle_count;
|
||||
uint8 opcode;
|
||||
uint32 cycles_executed;
|
||||
|
||||
bool nmi_triggered;
|
||||
bool nmi_pin;
|
||||
bool r4210_read;
|
||||
uint8 dma_state, hdma_state;
|
||||
uint32 dma_cycle_count, hdma_cycle_count;
|
||||
|
||||
bool irq_triggered;
|
||||
bool irq_pin;
|
||||
//$4207-$420a
|
||||
uint16 virq_trigger, hirq_trigger;
|
||||
|
||||
//$2181-$2183
|
||||
uint32 wram_addr;
|
||||
|
||||
//$4016
|
||||
uint8 joypad1_strobe_value;
|
||||
uint8 joypad1_read_pos;
|
||||
//$4016-$4017
|
||||
uint8 joypad1_strobe_value, joypad2_strobe_value;
|
||||
uint8 joypad1_read_pos, joypad2_read_pos;
|
||||
|
||||
//$4200
|
||||
bool nmi_enabled;
|
||||
@@ -88,13 +97,21 @@ struct {
|
||||
//$4214-$4216
|
||||
uint16 r4214;
|
||||
uint16 r4216;
|
||||
}status;
|
||||
} status;
|
||||
|
||||
//$43x0.d7
|
||||
enum {
|
||||
DMA_CPUTOMMIO = 0,
|
||||
DMA_MMIOTOCPU = 1
|
||||
};
|
||||
|
||||
struct {
|
||||
uint32 read_index; //set to 0 at beginning of DMA/HDMA
|
||||
|
||||
//$420b
|
||||
bool active;
|
||||
//$420c
|
||||
bool hdma_active;
|
||||
bool hdma_enabled;
|
||||
//$43x0
|
||||
uint8 dmap;
|
||||
bool direction;
|
||||
@@ -104,59 +121,69 @@ struct {
|
||||
uint8 xfermode;
|
||||
//$43x1
|
||||
uint8 destaddr;
|
||||
//$43x2-$43x4
|
||||
uint32 srcaddr;
|
||||
//$43x2-$43x3
|
||||
uint16 srcaddr;
|
||||
//$43x4
|
||||
uint8 srcbank;
|
||||
//$43x5-$43x6
|
||||
uint16 xfersize;
|
||||
union {
|
||||
uint16 xfersize;
|
||||
uint16 hdma_iaddr;
|
||||
};
|
||||
//$43x7
|
||||
uint8 hdma_indirect_bank;
|
||||
uint8 hdma_ibank;
|
||||
//$43x8-$43x9
|
||||
uint32 hdma_taddr;
|
||||
uint16 hdma_addr;
|
||||
//$43xa
|
||||
uint8 hdma_line_counter;
|
||||
//$43xb/$43xf
|
||||
uint8 hdma_unknown;
|
||||
|
||||
//hdma-specific
|
||||
bool hdma_first_line;
|
||||
bool hdma_repeat;
|
||||
uint32 hdma_itaddr;
|
||||
bool hdma_completed;
|
||||
}channel[8];
|
||||
bool hdma_active;
|
||||
bool hdma_do_transfer;
|
||||
} channel[8];
|
||||
|
||||
inline bool hdma_test();
|
||||
inline bool nmi_test();
|
||||
inline bool irq_test();
|
||||
inline void irq(uint16 addr);
|
||||
inline bool hdma_test();
|
||||
inline bool nmi_test();
|
||||
inline bool irq_test();
|
||||
|
||||
inline uint8 pio_status();
|
||||
inline void run();
|
||||
inline void scanline();
|
||||
inline void frame();
|
||||
inline void power();
|
||||
inline void reset();
|
||||
inline uint8 pio_status();
|
||||
inline void run();
|
||||
inline uint32 cycles_executed();
|
||||
inline void scanline();
|
||||
inline void frame();
|
||||
inline void power();
|
||||
inline void reset();
|
||||
|
||||
inline void irq_run();
|
||||
|
||||
//dma commands
|
||||
inline void dma_add_cycles(uint32 cycles);
|
||||
inline void hdma_add_cycles(uint32 cycles);
|
||||
inline void dma_run();
|
||||
inline void hdma_run();
|
||||
inline void hdma_initialize();
|
||||
inline uint16 dma_cputommio(uint8 i, uint8 index);
|
||||
inline uint16 dma_mmiotocpu(uint8 i, uint8 index);
|
||||
inline void dma_xfer_type0(uint8 i);
|
||||
inline void dma_xfer_type1(uint8 i);
|
||||
inline void dma_xfer_type2(uint8 i);
|
||||
inline void dma_xfer_type3(uint8 i);
|
||||
inline void dma_xfer_type4(uint8 i);
|
||||
inline void dma_xfer_type5(uint8 i);
|
||||
inline void hdma_write(uint8 i, uint8 l, uint8 x);
|
||||
inline void hdma_update(uint8 i);
|
||||
inline uint8 hdma_enabled_channels();
|
||||
inline uint8 hdma_active_channels();
|
||||
inline void hdmainit_activate();
|
||||
inline void hdma_activate();
|
||||
inline void dma_cputommio(uint8 i, uint8 index);
|
||||
inline void dma_mmiotocpu(uint8 i, uint8 index);
|
||||
inline void dma_write(uint8 i, uint8 index);
|
||||
inline uint32 dma_addr(uint8 i);
|
||||
inline uint32 hdma_addr(uint8 i);
|
||||
inline uint32 hdma_iaddr(uint8 i);
|
||||
inline uint16 hdma_mmio(uint8 i);
|
||||
inline uint8 hdma_read(uint8 i);
|
||||
inline void hdma_write(uint8 i, uint8 x);
|
||||
inline void dma_reset();
|
||||
|
||||
//mmio commands
|
||||
void mmio_reset();
|
||||
uint8 mmio_r2180();
|
||||
uint8 mmio_r21c2();
|
||||
uint8 mmio_r21c3();
|
||||
uint8 mmio_r4016();
|
||||
uint8 mmio_r4017();
|
||||
uint8 mmio_r4210();
|
||||
uint8 mmio_r4211();
|
||||
uint8 mmio_r4212();
|
||||
@@ -167,6 +194,8 @@ struct {
|
||||
uint8 mmio_r4217();
|
||||
uint8 mmio_r4218();
|
||||
uint8 mmio_r4219();
|
||||
uint8 mmio_r421a();
|
||||
uint8 mmio_r421b();
|
||||
uint8 mmio_r43x0(uint8 i);
|
||||
uint8 mmio_r43x1(uint8 i);
|
||||
uint8 mmio_r43x2(uint8 i);
|
||||
@@ -184,6 +213,7 @@ struct {
|
||||
void mmio_w2182(uint8 value);
|
||||
void mmio_w2183(uint8 value);
|
||||
void mmio_w4016(uint8 value);
|
||||
void mmio_w4017(uint8 value);
|
||||
void mmio_w4200(uint8 value);
|
||||
void mmio_w4201(uint8 value);
|
||||
void mmio_w4202(uint8 value);
|
||||
@@ -212,8 +242,12 @@ struct {
|
||||
void mmio_w43xb(uint8 value, uint8 i);
|
||||
|
||||
enum { CYCLE_OPREAD = 0, CYCLE_READ, CYCLE_WRITE, CYCLE_IO };
|
||||
inline void exec_opcode();
|
||||
inline void cycle_edge();
|
||||
inline void pre_exec_cycle();
|
||||
inline void exec_hdma();
|
||||
inline void exec_dma();
|
||||
inline void exec_cycle();
|
||||
inline void last_cycle();
|
||||
inline bool in_opcode();
|
||||
|
||||
//cpu extra-cycle conditions
|
||||
inline void cpu_c2();
|
||||
|
||||
+191
-182
@@ -1,92 +1,53 @@
|
||||
uint16 bCPU::dma_cputommio(uint8 i, uint8 index) {
|
||||
uint8 x;
|
||||
x = mem_bus->read(channel[i].srcaddr);
|
||||
mem_bus->write(0x2100 | ((channel[i].destaddr + index) & 0xff), x);
|
||||
void bCPU::dma_add_cycles(uint32 cycles) {
|
||||
status.dma_cycle_count += cycles;
|
||||
}
|
||||
|
||||
void bCPU::hdma_add_cycles(uint32 cycles) {
|
||||
if(run_state.dma) {
|
||||
status.dma_cycle_count += cycles;
|
||||
}
|
||||
status.hdma_cycle_count += cycles;
|
||||
}
|
||||
|
||||
uint32 bCPU::dma_addr(uint8 i) {
|
||||
uint32 r;
|
||||
r = (channel[i].srcbank << 16) | (channel[i].srcaddr);
|
||||
|
||||
if(channel[i].fixedxfer == false) {
|
||||
channel[i].srcaddr = (channel[i].srcaddr & 0xff0000) + ((channel[i].srcaddr + channel[i].incmode) & 0xffff);
|
||||
channel[i].srcaddr += channel[i].incmode;
|
||||
}
|
||||
add_cycles(8);
|
||||
return --channel[i].xfersize;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
uint16 bCPU::dma_mmiotocpu(uint8 i, uint8 index) {
|
||||
void bCPU::dma_cputommio(uint8 i, uint8 index) {
|
||||
uint8 x;
|
||||
x = mem_bus->read(0x2100 | ((channel[i].destaddr + index) & 0xff));
|
||||
mem_bus->write(channel[i].srcaddr, x);
|
||||
if(channel[i].fixedxfer == false) {
|
||||
channel[i].srcaddr = (channel[i].srcaddr & 0xff0000) + ((channel[i].srcaddr + channel[i].incmode) & 0xffff);
|
||||
if(sdd1->dma_active() == true) {
|
||||
x = sdd1->dma_read();
|
||||
} else {
|
||||
x = r_mem->read(dma_addr(i));
|
||||
}
|
||||
|
||||
r_mem->write(0x2100 | ((channel[i].destaddr + index) & 0xff), x);
|
||||
|
||||
add_cycles(8);
|
||||
return --channel[i].xfersize;
|
||||
channel[i].xfersize--;
|
||||
}
|
||||
|
||||
void bCPU::dma_xfer_type0(uint8 i) {
|
||||
if(channel[i].direction == 0) {
|
||||
if(dma_cputommio(i, 0) == 0)return;
|
||||
} else {
|
||||
if(dma_mmiotocpu(i, 0) == 0)return;
|
||||
}
|
||||
void bCPU::dma_mmiotocpu(uint8 i, uint8 index) {
|
||||
uint8 x;
|
||||
x = r_mem->read(0x2100 | ((channel[i].destaddr + index) & 0xff));
|
||||
r_mem->write(dma_addr(i), x);
|
||||
|
||||
add_cycles(8);
|
||||
channel[i].xfersize--;
|
||||
}
|
||||
|
||||
void bCPU::dma_xfer_type1(uint8 i) {
|
||||
void bCPU::dma_write(uint8 i, uint8 index) {
|
||||
if(channel[i].direction == 0) {
|
||||
if(dma_cputommio(i, 0) == 0)return;
|
||||
if(dma_cputommio(i, 1) == 0)return;
|
||||
dma_cputommio(i, index);
|
||||
} else {
|
||||
if(dma_mmiotocpu(i, 0) == 0)return;
|
||||
if(dma_mmiotocpu(i, 1) == 0)return;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::dma_xfer_type2(uint8 i) {
|
||||
if(channel[i].direction == 0) {
|
||||
if(dma_cputommio(i, 0) == 0)return;
|
||||
if(dma_cputommio(i, 0) == 0)return;
|
||||
} else {
|
||||
if(dma_mmiotocpu(i, 0) == 0)return;
|
||||
if(dma_mmiotocpu(i, 0) == 0)return;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::dma_xfer_type3(uint8 i) {
|
||||
if(channel[i].direction == 0) {
|
||||
if(dma_cputommio(i, 0) == 0)return;
|
||||
if(dma_cputommio(i, 0) == 0)return;
|
||||
if(dma_cputommio(i, 1) == 0)return;
|
||||
if(dma_cputommio(i, 1) == 0)return;
|
||||
} else {
|
||||
if(dma_mmiotocpu(i, 0) == 0)return;
|
||||
if(dma_mmiotocpu(i, 0) == 0)return;
|
||||
if(dma_mmiotocpu(i, 1) == 0)return;
|
||||
if(dma_mmiotocpu(i, 1) == 0)return;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::dma_xfer_type4(uint8 i) {
|
||||
if(channel[i].direction == 0) {
|
||||
if(dma_cputommio(i, 0) == 0)return;
|
||||
if(dma_cputommio(i, 1) == 0)return;
|
||||
if(dma_cputommio(i, 2) == 0)return;
|
||||
if(dma_cputommio(i, 3) == 0)return;
|
||||
} else {
|
||||
if(dma_mmiotocpu(i, 0) == 0)return;
|
||||
if(dma_mmiotocpu(i, 1) == 0)return;
|
||||
if(dma_mmiotocpu(i, 2) == 0)return;
|
||||
if(dma_mmiotocpu(i, 3) == 0)return;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::dma_xfer_type5(uint8 i) {
|
||||
if(channel[i].direction == 0) {
|
||||
if(dma_cputommio(i, 0) == 0)return;
|
||||
if(dma_cputommio(i, 1) == 0)return;
|
||||
if(dma_cputommio(i, 0) == 0)return;
|
||||
if(dma_cputommio(i, 1) == 0)return;
|
||||
} else {
|
||||
if(dma_mmiotocpu(i, 0) == 0)return;
|
||||
if(dma_mmiotocpu(i, 1) == 0)return;
|
||||
if(dma_mmiotocpu(i, 0) == 0)return;
|
||||
if(dma_mmiotocpu(i, 1) == 0)return;
|
||||
dma_mmiotocpu(i, index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,17 +56,26 @@ int i;
|
||||
for(i=0;i<8;i++) {
|
||||
if(channel[i].active == false)continue;
|
||||
|
||||
switch(channel[i].xfermode) {
|
||||
case 0:dma_xfer_type0(i);break;
|
||||
case 1:dma_xfer_type1(i);break;
|
||||
case 2:dma_xfer_type2(i);break;
|
||||
case 3:dma_xfer_type3(i);break;
|
||||
case 4:dma_xfer_type4(i);break;
|
||||
case 5:dma_xfer_type5(i);break;
|
||||
case 6:dma_xfer_type2(i);break;
|
||||
case 7:dma_xfer_type3(i);break;
|
||||
//first byte transferred?
|
||||
if(channel[i].read_index == 0) {
|
||||
sdd1->dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr),
|
||||
channel[i].xfersize);
|
||||
}
|
||||
|
||||
switch(channel[i].xfermode) {
|
||||
case 0:dma_write(i, 0); break; //0
|
||||
case 1:dma_write(i, channel[i].read_index & 1); break; //0,1
|
||||
case 2:dma_write(i, 0); break; //0,0
|
||||
case 3:dma_write(i, (channel[i].read_index >> 1) & 1);break; //0,0,1,1
|
||||
case 4:dma_write(i, channel[i].read_index & 3); break; //0,1,2,3
|
||||
case 5:dma_write(i, channel[i].read_index & 1); break; //0,1,0,1
|
||||
case 6:dma_write(i, 0); break; //0,0 [2]
|
||||
case 7:dma_write(i, (channel[i].read_index >> 1) & 1);break; //0,0,1,1 [3]
|
||||
}
|
||||
|
||||
channel[i].read_index++;
|
||||
dma_add_cycles(8);
|
||||
|
||||
if(channel[i].xfersize == 0) {
|
||||
channel[i].active = false;
|
||||
}
|
||||
@@ -116,126 +86,165 @@ int i;
|
||||
status.dma_state = DMASTATE_CPUSYNC;
|
||||
}
|
||||
|
||||
void bCPU::hdma_write(uint8 i, uint8 l, uint8 x) {
|
||||
uint32 bCPU::hdma_addr(uint8 i) {
|
||||
return (channel[i].srcbank << 16) | (channel[i].hdma_addr++);
|
||||
}
|
||||
|
||||
uint32 bCPU::hdma_iaddr(uint8 i) {
|
||||
return (channel[i].hdma_ibank << 16) | (channel[i].hdma_iaddr++);
|
||||
}
|
||||
|
||||
uint16 bCPU::hdma_mmio(uint8 i) {
|
||||
uint8 l = channel[i].read_index;
|
||||
uint16 index;
|
||||
switch(channel[i].xfermode) {
|
||||
case 0:mem_bus->write(0x2100 | ((channel[i].destaddr) & 0xff), x);break;
|
||||
case 1:mem_bus->write(0x2100 | ((channel[i].destaddr + l) & 0xff), x);break;
|
||||
case 2:mem_bus->write(0x2100 | ((channel[i].destaddr) & 0xff), x);break;
|
||||
case 3:mem_bus->write(0x2100 | ((channel[i].destaddr + (l >> 1)) & 0xff), x);break;
|
||||
case 4:mem_bus->write(0x2100 | ((channel[i].destaddr + l) & 0xff), x);break;
|
||||
case 5:mem_bus->write(0x2100 | ((channel[i].destaddr + (l & 1)) & 0xff), x);break;
|
||||
case 6:mem_bus->write(0x2100 | ((channel[i].destaddr) & 0xff), x);break;
|
||||
case 7:mem_bus->write(0x2100 | ((channel[i].destaddr + (l >> 1)) & 0xff), x);break;
|
||||
case 0:index = 0; break; //0
|
||||
case 1:index = l & 1; break; //0,1
|
||||
case 2:index = 0; break; //0,0
|
||||
case 3:index = (l >> 1) & 1;break; //0,0,1,1
|
||||
case 4:index = l & 3; break; //0,1,2,3
|
||||
case 5:index = l & 1; break; //0,1,0,1
|
||||
case 6:index = 0; break; //0,0 [2]
|
||||
case 7:index = (l >> 1) & 1;break; //0,0,1,1 [3]
|
||||
}
|
||||
|
||||
return (0x2100 | ((channel[i].destaddr + index) & 0xff));
|
||||
}
|
||||
|
||||
uint8 bCPU::hdma_read(uint8 i) {
|
||||
if(channel[i].direction == DMA_MMIOTOCPU) {
|
||||
return r_mem->read(hdma_mmio(i));
|
||||
} else if(!channel[i].hdma_indirect) {
|
||||
return r_mem->read(hdma_addr(i));
|
||||
} else {
|
||||
return r_mem->read(hdma_iaddr(i));
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::hdma_write(uint8 i, uint8 x) {
|
||||
if(channel[i].direction == DMA_CPUTOMMIO) {
|
||||
r_mem->write(hdma_mmio(i), x);
|
||||
} else if(!channel[i].hdma_indirect) {
|
||||
r_mem->write(hdma_addr(i), x);
|
||||
} else {
|
||||
r_mem->write(hdma_iaddr(i), x);
|
||||
}
|
||||
|
||||
add_cycles(8);
|
||||
hdma_add_cycles(8);
|
||||
}
|
||||
|
||||
void bCPU::hdma_update(uint8 i) {
|
||||
channel[i].hdma_line_counter = r_mem->read(hdma_addr(i));
|
||||
add_cycles(8);
|
||||
hdma_add_cycles(8);
|
||||
|
||||
if(channel[i].hdma_indirect) {
|
||||
channel[i].hdma_iaddr = r_mem->read(hdma_addr(i)) << 8;
|
||||
add_cycles(8);
|
||||
hdma_add_cycles(8);
|
||||
}
|
||||
|
||||
if(channel[i].hdma_line_counter == 0) {
|
||||
channel[i].hdma_active = false;
|
||||
channel[i].hdma_do_transfer = false;
|
||||
return;
|
||||
}
|
||||
|
||||
channel[i].hdma_do_transfer = true;
|
||||
|
||||
if(channel[i].hdma_indirect) {
|
||||
channel[i].hdma_iaddr >>= 8;
|
||||
channel[i].hdma_iaddr |= r_mem->read(hdma_addr(i)) << 8;
|
||||
add_cycles(8);
|
||||
hdma_add_cycles(8);
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::hdma_run() {
|
||||
int l, xferlen;
|
||||
uint8 x, active_channels = 0;
|
||||
static uint8 hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
|
||||
for(int i=0;i<8;i++) {
|
||||
if(channel[i].hdma_completed == true)continue;
|
||||
// add_cycles(8);
|
||||
active_channels++;
|
||||
if(channel[i].hdma_line_counter == 0) {
|
||||
channel[i].hdma_line_counter = mem_bus->read(channel[i].hdma_taddr++);
|
||||
if(channel[i].hdma_line_counter == 0) {
|
||||
channel[i].hdma_completed = true;
|
||||
continue;
|
||||
}
|
||||
if(!channel[i].hdma_enabled || !channel[i].hdma_active)continue;
|
||||
|
||||
if(channel[i].hdma_line_counter > 0x80) {
|
||||
channel[i].hdma_repeat = true;
|
||||
channel[i].hdma_line_counter -= 0x80;
|
||||
} else {
|
||||
channel[i].hdma_repeat = false;
|
||||
}
|
||||
|
||||
channel[i].hdma_first_line = true;
|
||||
if(channel[i].hdma_indirect == false) {
|
||||
channel[i].hdma_itaddr = channel[i].hdma_taddr;
|
||||
} else {
|
||||
channel[i].hdma_itaddr = mem_bus->read(channel[i].hdma_taddr++);
|
||||
channel[i].hdma_itaddr |= mem_bus->read(channel[i].hdma_taddr++) << 8;
|
||||
channel[i].hdma_itaddr |= channel[i].hdma_indirect_bank << 16;
|
||||
// add_cycles(16);
|
||||
if(channel[i].hdma_do_transfer) {
|
||||
int xferlen = hdma_xferlen[channel[i].xfermode];
|
||||
for(channel[i].read_index=0;channel[i].read_index<xferlen;channel[i].read_index++) {
|
||||
hdma_write(i, hdma_read(i));
|
||||
}
|
||||
}
|
||||
|
||||
channel[i].hdma_line_counter--;
|
||||
if(channel[i].hdma_first_line == false && channel[i].hdma_repeat == false)continue;
|
||||
channel[i].hdma_first_line = false;
|
||||
|
||||
if(channel[i].hdma_indirect == false) {
|
||||
channel[i].hdma_itaddr = channel[i].hdma_taddr;
|
||||
channel[i].hdma_do_transfer = !!(channel[i].hdma_line_counter & 0x80);
|
||||
if((channel[i].hdma_line_counter & 0x7f) == 0) {
|
||||
hdma_update(i);
|
||||
}
|
||||
|
||||
switch(channel[i].xfermode) {
|
||||
case 0: xferlen = 1;break;
|
||||
case 1:case 2:case 6: xferlen = 2;break;
|
||||
case 3:case 4:case 5:case 7:xferlen = 4;break;
|
||||
}
|
||||
|
||||
for(l=0;l<xferlen;l++) {
|
||||
x = mem_bus->read(channel[i].hdma_itaddr++);
|
||||
if(channel[i].hdma_indirect == false) {
|
||||
channel[i].hdma_taddr++;
|
||||
}
|
||||
hdma_write(i, l, x);
|
||||
// add_cycles(8);
|
||||
}
|
||||
}
|
||||
|
||||
if(active_channels != 0) {
|
||||
// add_cycles(18);
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::hdma_initialize() {
|
||||
uint8 active_channels = 0;
|
||||
uint8 bCPU::hdma_enabled_channels() {
|
||||
int r = 0;
|
||||
for(int i=0;i<8;i++) {
|
||||
if(channel[i].hdma_active == false) {
|
||||
channel[i].hdma_completed = true;
|
||||
continue;
|
||||
}
|
||||
active_channels++;
|
||||
channel[i].hdma_first_line = true;
|
||||
channel[i].hdma_repeat = false;
|
||||
channel[i].hdma_taddr = channel[i].srcaddr;
|
||||
channel[i].hdma_line_counter = 0x00;
|
||||
channel[i].hdma_completed = false;
|
||||
if(channel[i].hdma_indirect == false) {
|
||||
add_cycles(8);
|
||||
} else {
|
||||
add_cycles(24);
|
||||
}
|
||||
if(channel[i].hdma_enabled)r++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
uint8 bCPU::hdma_active_channels() {
|
||||
int r = 0;
|
||||
for(int i=0;i<8;i++) {
|
||||
if(channel[i].hdma_enabled && channel[i].hdma_active)r++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* hdmainit_activate()
|
||||
* hdma_activate()
|
||||
*
|
||||
* Functions are called by CPU timing routine
|
||||
* when an HDMA event (init or run) occurs.
|
||||
*/
|
||||
|
||||
void bCPU::hdmainit_activate() {
|
||||
for(int i=0;i<8;i++) {
|
||||
channel[i].hdma_active = false;
|
||||
channel[i].hdma_do_transfer = false;
|
||||
}
|
||||
|
||||
if(active_channels != 0) {
|
||||
add_cycles(18);
|
||||
if(hdma_enabled_channels() != 0) {
|
||||
status.hdma_state = HDMASTATE_IDMASYNC;
|
||||
run_state.hdma = true;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::hdma_activate() {
|
||||
if(hdma_active_channels() != 0) {
|
||||
status.hdma_state = HDMASTATE_DMASYNC;
|
||||
run_state.hdma = true;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::dma_reset() {
|
||||
for(int i=0;i<8;i++) {
|
||||
channel[i].active = false;
|
||||
channel[i].hdma_active = false;
|
||||
channel[i].dmap = 0x00;
|
||||
channel[i].direction = 0;
|
||||
channel[i].hdma_indirect = false;
|
||||
channel[i].incmode = 1;
|
||||
channel[i].fixedxfer = false;
|
||||
channel[i].xfermode = 0;
|
||||
channel[i].destaddr = 0;
|
||||
channel[i].srcaddr = 0;
|
||||
channel[i].xfersize = 0;
|
||||
channel[i].hdma_indirect_bank = 0;
|
||||
channel[i].hdma_taddr = 0x000000;
|
||||
channel[i].hdma_line_counter = 0x00;
|
||||
channel[i].hdma_unknown = 0x00;
|
||||
channel[i].read_index = 0;
|
||||
channel[i].active = false;
|
||||
channel[i].hdma_enabled = false;
|
||||
channel[i].dmap = 0x00;
|
||||
channel[i].direction = 0;
|
||||
channel[i].hdma_indirect = false;
|
||||
channel[i].incmode = 1;
|
||||
channel[i].fixedxfer = false;
|
||||
channel[i].xfermode = 0;
|
||||
channel[i].destaddr = 0;
|
||||
channel[i].srcaddr = 0;
|
||||
channel[i].xfersize = 0x0000;
|
||||
//xfersize and hdma_iaddr are of union { uint16 };
|
||||
//channel[i].hdma_iaddr = 0x0000;
|
||||
channel[i].hdma_ibank = 0;
|
||||
channel[i].hdma_addr = 0x0000;
|
||||
channel[i].hdma_line_counter = 0x00;
|
||||
channel[i].hdma_unknown = 0x00;
|
||||
|
||||
channel[i].hdma_first_line = false;
|
||||
channel[i].hdma_repeat = false;
|
||||
channel[i].hdma_itaddr = 0x000000;
|
||||
channel[i].hdma_completed = true;
|
||||
channel[i].hdma_active = false;
|
||||
channel[i].hdma_do_transfer = false;
|
||||
}
|
||||
}
|
||||
+160
-26
@@ -1,40 +1,174 @@
|
||||
inline void bCPU::cycle_edge() {
|
||||
int c, n, z;
|
||||
if(status.dma_state != DMASTATE_STOP) {
|
||||
switch(status.dma_state) {
|
||||
case DMASTATE_INIT:
|
||||
status.dma_state = DMASTATE_DMASYNC;
|
||||
void bCPU::last_cycle() {
|
||||
time.nmi_pending = nmi_test();
|
||||
time.irq_pending = irq_test();
|
||||
}
|
||||
|
||||
void bCPU::pre_exec_cycle() {
|
||||
if(!run_state.dma && !run_state.hdma)return;
|
||||
|
||||
int c, z;
|
||||
if(run_state.hdma) {
|
||||
switch(status.hdma_state) {
|
||||
case HDMASTATE_ICPUSYNC:
|
||||
case HDMASTATE_CPUSYNC:
|
||||
c = status.cycle_count;
|
||||
z = c - (status.hdma_cycle_count % c);
|
||||
if(!z)z = c;
|
||||
add_cycles(z);
|
||||
run_state.hdma = false;
|
||||
break;
|
||||
case DMASTATE_DMASYNC:
|
||||
n = 8 - dma_counter() + 8;
|
||||
add_cycles(n);
|
||||
status.dma_cycle_count = n;
|
||||
for(z=0;z<8;z++) {
|
||||
if(channel[z].active == false)continue;
|
||||
add_cycles(8);
|
||||
status.dma_cycle_count += 8;
|
||||
status.dma_cycle_count += channel[z].xfersize << 3;
|
||||
}
|
||||
status.cpu_state = CPUSTATE_DMA;
|
||||
status.dma_state = DMASTATE_RUN;
|
||||
while(status.dma_state == DMASTATE_RUN) {
|
||||
dma_run();
|
||||
}
|
||||
status.cpu_state = CPUSTATE_RUN;
|
||||
}
|
||||
}
|
||||
|
||||
if(run_state.dma) {
|
||||
switch(status.dma_state) {
|
||||
case DMASTATE_CPUSYNC:
|
||||
c = status.cycle_count;
|
||||
z = c - (status.dma_cycle_count % c);
|
||||
if(!z)z = c;
|
||||
add_cycles(z);
|
||||
status.dma_state = DMASTATE_STOP;
|
||||
run_state.dma = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::exec_opcode() {
|
||||
void bCPU::exec_hdma() {
|
||||
int n;
|
||||
static int z;
|
||||
switch(status.hdma_state) {
|
||||
case HDMASTATE_IDMASYNC:
|
||||
status.hdma_cycle_count = 0;
|
||||
z = 0;
|
||||
if(!run_state.dma) {
|
||||
exec_cycle();
|
||||
status.hdma_state = HDMASTATE_IDMASYNC2;
|
||||
} else {
|
||||
status.hdma_state = HDMASTATE_IDMASYNC3;
|
||||
}
|
||||
break;
|
||||
case HDMASTATE_IDMASYNC2:
|
||||
n = 8 - dma_counter() + 8;
|
||||
add_cycles(n);
|
||||
status.hdma_cycle_count += n;
|
||||
status.hdma_state = HDMASTATE_IDMASYNC3;
|
||||
break;
|
||||
case HDMASTATE_IDMASYNC3:
|
||||
channel[z].hdma_active = channel[z].hdma_enabled;
|
||||
if(channel[z].hdma_enabled) {
|
||||
channel[z].hdma_addr = channel[z].srcaddr;
|
||||
hdma_update(z); //updates status.hdma_cycle_count
|
||||
}
|
||||
if(++z < 8)break;
|
||||
if(!run_state.dma) {
|
||||
status.hdma_state = HDMASTATE_ICPUSYNC;
|
||||
} else {
|
||||
run_state.hdma = false;
|
||||
}
|
||||
break;
|
||||
case HDMASTATE_ICPUSYNC:
|
||||
exec_cycle();
|
||||
break;
|
||||
|
||||
case HDMASTATE_DMASYNC:
|
||||
status.hdma_cycle_count = 0;
|
||||
z = 0;
|
||||
if(!run_state.dma) {
|
||||
exec_cycle();
|
||||
status.hdma_state = HDMASTATE_DMASYNC2;
|
||||
} else {
|
||||
status.hdma_state = HDMASTATE_DMASYNC3;
|
||||
}
|
||||
break;
|
||||
case HDMASTATE_DMASYNC2:
|
||||
n = 8 - dma_counter() + 8;
|
||||
add_cycles(n);
|
||||
status.hdma_cycle_count += n;
|
||||
status.hdma_state = HDMASTATE_DMASYNC3;
|
||||
break;
|
||||
case HDMASTATE_DMASYNC3:
|
||||
if(channel[z].hdma_active) {
|
||||
add_cycles(8);
|
||||
status.hdma_cycle_count += 8;
|
||||
}
|
||||
if(++z < 8)break;
|
||||
status.hdma_state = HDMASTATE_RUN;
|
||||
break;
|
||||
case HDMASTATE_RUN:
|
||||
hdma_run(); //updates status.hdma_cycle_count
|
||||
if(!run_state.dma) {
|
||||
status.hdma_state = HDMASTATE_CPUSYNC;
|
||||
} else {
|
||||
run_state.hdma = false;
|
||||
}
|
||||
break;
|
||||
case HDMASTATE_CPUSYNC:
|
||||
exec_cycle();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::exec_dma() {
|
||||
int n;
|
||||
static int z;
|
||||
switch(status.dma_state) {
|
||||
case DMASTATE_DMASYNC:
|
||||
exec_cycle();
|
||||
status.dma_state = DMASTATE_DMASYNC2;
|
||||
break;
|
||||
case DMASTATE_DMASYNC2:
|
||||
n = 8 - dma_counter() + 8;
|
||||
add_cycles(n);
|
||||
status.dma_cycle_count = n;
|
||||
z = 0;
|
||||
status.dma_state = DMASTATE_DMASYNC3;
|
||||
break;
|
||||
case DMASTATE_DMASYNC3:
|
||||
if(channel[z].active == true) {
|
||||
add_cycles(8);
|
||||
status.dma_cycle_count += 8;
|
||||
}
|
||||
if(++z < 8)break;
|
||||
status.dma_state = DMASTATE_RUN;
|
||||
break;
|
||||
case DMASTATE_RUN:
|
||||
dma_run(); //updates status.dma_cycle_count
|
||||
cycle_edge();
|
||||
break;
|
||||
case DMASTATE_CPUSYNC:
|
||||
exec_cycle();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::exec_cycle() {
|
||||
//irq active? run one bus cycle of the irq event and return
|
||||
if(run_state.irq) {
|
||||
irq_run();
|
||||
return;
|
||||
}
|
||||
|
||||
if(status.cycle_pos) {
|
||||
(this->*optbl[status.opcode])();
|
||||
#ifdef DEBUGGER
|
||||
if(status.cycle_pos == 0) {
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_END);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
//on first cycle?
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_BEGIN);
|
||||
(this->*optbl[op_read()])();
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_END);
|
||||
#endif
|
||||
status.opcode = op_read();
|
||||
status.cycle_pos = 1;
|
||||
}
|
||||
|
||||
//only return true when we are on an opcode edge
|
||||
bool bCPU::in_opcode() {
|
||||
return (status.cycle_pos != 0);
|
||||
}
|
||||
|
||||
void bCPU::init_op_tables() {
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
[IRQ cycles]
|
||||
[0] pbr,pc ; opcode
|
||||
[1] pbr,pc ; io
|
||||
[2] 0,s ; pbr
|
||||
[3] 0,s-1 ; pch
|
||||
[4] 0,s-2 ; pcl
|
||||
[5] 0,s-3 ; p
|
||||
[6] 0,va ; aavl
|
||||
[7] 0,va+1 ; aavh
|
||||
*/
|
||||
void bCPU::irq_run() {
|
||||
//WDC documentation is incorrect, first cycle
|
||||
//is a memory read fetch from PBR:PC
|
||||
switch(status.cycle_pos++) {
|
||||
case 0: add_cycles(r_mem->speed(regs.pc.d)); break;
|
||||
case 1: add_cycles(6); break;
|
||||
case 2: stack_write(regs.pc.b); break;
|
||||
case 3: stack_write(regs.pc.h); break;
|
||||
case 4: stack_write(regs.pc.l); break;
|
||||
case 5: stack_write(regs.p); break;
|
||||
case 6: rd.l = op_read(OPMODE_ADDR, aa.w); break;
|
||||
case 7: rd.h = op_read(OPMODE_ADDR, aa.w + 1);
|
||||
regs.pc.b = 0x00;
|
||||
regs.pc.w = rd.w;
|
||||
regs.p.i = 1;
|
||||
regs.p.d = 0;
|
||||
#ifdef DEBUGGER
|
||||
//let debugger know the new IRQ opcode address
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_END);
|
||||
#endif
|
||||
status.cycle_pos = 0;
|
||||
run_state.irq = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool bCPU::nmi_test() {
|
||||
if(time.nmi_transition == 0)return false;
|
||||
time.nmi_transition = 0;
|
||||
|
||||
run_state.wai = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bCPU::irq_test() {
|
||||
if(time.irq_transition == 1)goto _true;
|
||||
|
||||
if(time.irq_read == 0) {
|
||||
if(time.irq_line == 1 && (irq_trigger_pos_match(0) || irq_trigger_pos_match(2))) {
|
||||
return false;
|
||||
}
|
||||
goto _true;
|
||||
}
|
||||
|
||||
if(time.irq_line == 0) {
|
||||
time.irq_line = 1;
|
||||
goto _true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
_true:
|
||||
time.irq_transition = 0;
|
||||
|
||||
run_state.wai = false;
|
||||
if(regs.p.i)return false;
|
||||
return true;
|
||||
}
|
||||
+178
-96
@@ -2,9 +2,11 @@ void bCPU::mmio_reset() {
|
||||
//$2181-$2183
|
||||
status.wram_addr = 0x000000;
|
||||
|
||||
//$4016
|
||||
//$4016-$4017
|
||||
status.joypad1_strobe_value = 0x00;
|
||||
status.joypad2_strobe_value = 0x00;
|
||||
status.joypad1_read_pos = 0;
|
||||
status.joypad2_read_pos = 0;
|
||||
|
||||
//$4200
|
||||
status.nmi_enabled = false;
|
||||
@@ -35,35 +37,28 @@ void bCPU::mmio_reset() {
|
||||
//WMDATA
|
||||
uint8 bCPU::mmio_r2180() {
|
||||
uint8 r;
|
||||
r = mem_bus->read(0x7e0000 | status.wram_addr);
|
||||
r = r_mem->read(0x7e0000 | status.wram_addr);
|
||||
status.wram_addr++;
|
||||
status.wram_addr &= 0x01ffff;
|
||||
return r;
|
||||
}
|
||||
|
||||
//???
|
||||
uint8 bCPU::mmio_r21c2() {
|
||||
return 0x20;
|
||||
}
|
||||
|
||||
//???
|
||||
uint8 bCPU::mmio_r21c3() {
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
/*
|
||||
The joypad contains a small bit shifter that has 16 bits.
|
||||
Reading from 4016 reads one bit from this buffer, then moves
|
||||
the buffer left one, and adds a '1' to the rightmost bit.
|
||||
Writing a one to $4016 will fill the buffer with the current
|
||||
joypad button states, and lock the bit shifter at position
|
||||
zero. All reads will be the first buffer state, or 'B'.
|
||||
A zero must be written back to $4016 to unlock the buffer,
|
||||
so that reads will increment the bit shifting position.
|
||||
*/
|
||||
//JOYSER0
|
||||
//7-2 = MDR
|
||||
//1-0 = Joypad serial data
|
||||
/* The joypad contains a small bit shifter that has 16 bits.
|
||||
* Reading from 4016 reads one bit from this buffer, then moves
|
||||
* the buffer left one, and adds a '1' to the rightmost bit.
|
||||
* Writing a one to $4016 will fill the buffer with the current
|
||||
* joypad button states, and lock the bit shifter at position
|
||||
* zero. All reads will be the first buffer state, or 'B'.
|
||||
* A zero must be written back to $4016 to unlock the buffer,
|
||||
* so that reads will increment the bit shifting position.
|
||||
*/
|
||||
uint8 bCPU::mmio_r4016() {
|
||||
uint8 r = 0x00;
|
||||
uint8 r;
|
||||
r = regs.mdr & 0xfc;
|
||||
|
||||
if(status.joypad1_strobe_value == 1) {
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_B);
|
||||
} else {
|
||||
@@ -85,59 +80,98 @@ uint8 r = 0x00;
|
||||
}
|
||||
if(++status.joypad1_read_pos > 17)status.joypad1_read_pos = 17;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
//JOYSER1
|
||||
//7-5 = MDR
|
||||
//4-2 = Always 1
|
||||
//1-0 = Joypad serial data
|
||||
uint8 bCPU::mmio_r4017() {
|
||||
uint8 r;
|
||||
r = regs.mdr & 0xe0;
|
||||
r |= 0x1c;
|
||||
|
||||
if(status.joypad2_strobe_value == 1) {
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_B);
|
||||
} else {
|
||||
switch(status.joypad2_read_pos) {
|
||||
case 0:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_B); break;
|
||||
case 1:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_Y); break;
|
||||
case 2:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_SELECT);break;
|
||||
case 3:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_START); break;
|
||||
case 4:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_UP); break;
|
||||
case 5:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_DOWN); break;
|
||||
case 6:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_LEFT); break;
|
||||
case 7:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_RIGHT); break;
|
||||
case 8:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_A); break;
|
||||
case 9:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_X); break;
|
||||
case 10:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_L); break;
|
||||
case 11:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_R); break;
|
||||
case 16:r |= 1;break; //joypad connected bit
|
||||
default:r |= 1;break; //after 16th read, all subsequent reads return 1
|
||||
}
|
||||
if(++status.joypad2_read_pos > 17)status.joypad2_read_pos = 17;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
//RDNMI
|
||||
//7 = NMI acknowledge
|
||||
//6-4 = MDR
|
||||
//3-0 = CPU (5a22) version
|
||||
uint8 bCPU::mmio_r4210() {
|
||||
uint8 r = 0x00;
|
||||
uint16 v, h, hc, vs;
|
||||
v = vcounter();
|
||||
h = hcounter();
|
||||
hc = hcycles();
|
||||
vs = (overscan()?239:224);
|
||||
uint8 r;
|
||||
r = regs.mdr & 0x70;
|
||||
r |= uint8(!time.nmi_read) << 7;
|
||||
|
||||
if(status.r4210_read == false) {
|
||||
if((v == (vs + 1) && hc >= 2) || v > (vs + 1)) {
|
||||
r |= 0x80;
|
||||
status.r4210_read = true;
|
||||
status.nmi_pin = 1;
|
||||
}
|
||||
if(!nmi_trigger_pos_match(0) && !nmi_trigger_pos_match(2)) {
|
||||
time.nmi_read = 1;
|
||||
}
|
||||
|
||||
r |= 0x40;
|
||||
r |= 0x02; //cpu version number
|
||||
r |= (cpu_version & 0x0f);
|
||||
return r;
|
||||
}
|
||||
|
||||
//TIMEUP
|
||||
//7 = IRQ acknowledge
|
||||
//6-0 = MDR
|
||||
uint8 bCPU::mmio_r4211() {
|
||||
uint8 r = 0x00;
|
||||
r |= 0x40;
|
||||
if(status.irq_triggered == true)r |= 0x80;
|
||||
status.irq_triggered = false;
|
||||
uint8 r;
|
||||
r = regs.mdr & 0x7f;
|
||||
r |= uint8(!time.irq_read) << 7;
|
||||
|
||||
if(!irq_trigger_pos_match(0) && !irq_trigger_pos_match(2)) {
|
||||
time.irq_read = 1;
|
||||
time.irq_line = 1;
|
||||
time.irq_transition = 0;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
//HVBJOY
|
||||
//7 = in vblank
|
||||
//6 = in hblank
|
||||
//5-1 = MDR
|
||||
//0 = joypad ready
|
||||
uint8 bCPU::mmio_r4212() {
|
||||
uint8 r;
|
||||
uint16 v, h, hc, vs;
|
||||
r = 0x00;
|
||||
uint8 r;
|
||||
r = regs.mdr & 0x3e;
|
||||
|
||||
v = vcounter();
|
||||
h = hcounter();
|
||||
hc = hcycles();
|
||||
vs = (overscan()?239:224);
|
||||
uint16 vs = overscan() ? 240 : 225;
|
||||
|
||||
//auto joypad polling
|
||||
if(v >= (vs + 1) && v <= (vs + 3))r |= 0x01;
|
||||
if(time.v >= vs && time.v <= (vs + 2))r |= 0x01;
|
||||
|
||||
//hblank
|
||||
if(hc <= 2 || hc >= 1096)r |= 0x40;
|
||||
if(time.hc <= 2 || time.hc >= 1096)r |= 0x40;
|
||||
|
||||
//vblank
|
||||
if(v >= (vs + 1))r |= 0x80;
|
||||
if(time.v >= vs)r |= 0x80;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -168,7 +202,7 @@ uint8 bCPU::mmio_r4217() {
|
||||
|
||||
//JOY1L
|
||||
uint8 bCPU::mmio_r4218() {
|
||||
uint8 r = 0x00;
|
||||
uint8 r = 0x00;
|
||||
uint16 v = vcounter();
|
||||
if(status.auto_joypad_poll == false)return 0x00; //can't read joypad if auto polling not enabled
|
||||
//if(v >= 225 && v <= 227)return 0x00; //can't read joypad while SNES is polling input
|
||||
@@ -181,7 +215,7 @@ uint16 v = vcounter();
|
||||
|
||||
//JOY1H
|
||||
uint8 bCPU::mmio_r4219() {
|
||||
uint8 r = 0x00;
|
||||
uint8 r = 0x00;
|
||||
uint16 v = vcounter();
|
||||
if(status.auto_joypad_poll == false)return 0x00; //can't read joypad if auto polling not enabled
|
||||
//if(v >= 225 && v <= 227)return 0x00; //can't read joypad while SNES is polling input
|
||||
@@ -196,6 +230,36 @@ uint16 v = vcounter();
|
||||
return r;
|
||||
}
|
||||
|
||||
//JOY2L
|
||||
uint8 bCPU::mmio_r421a() {
|
||||
uint8 r = 0x00;
|
||||
uint16 v = vcounter();
|
||||
if(status.auto_joypad_poll == false)return 0x00; //can't read joypad if auto polling not enabled
|
||||
//if(v >= 225 && v <= 227)return 0x00; //can't read joypad while SNES is polling input
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_A) << 7;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_X) << 6;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_L) << 5;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_R) << 4;
|
||||
return r;
|
||||
}
|
||||
|
||||
//JOY2H
|
||||
uint8 bCPU::mmio_r421b() {
|
||||
uint8 r = 0x00;
|
||||
uint16 v = vcounter();
|
||||
if(status.auto_joypad_poll == false)return 0x00; //can't read joypad if auto polling not enabled
|
||||
//if(v >= 225 && v <= 227)return 0x00; //can't read joypad while SNES is polling input
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_B) << 7;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_Y) << 6;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_SELECT) << 5;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_START) << 4;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_UP) << 3;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_DOWN) << 2;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_LEFT) << 1;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_RIGHT);
|
||||
return r;
|
||||
}
|
||||
|
||||
//DMAPx
|
||||
uint8 bCPU::mmio_r43x0(uint8 i) {
|
||||
return channel[i].dmap;
|
||||
@@ -218,7 +282,7 @@ uint8 bCPU::mmio_r43x3(uint8 i) {
|
||||
|
||||
//A1Bx
|
||||
uint8 bCPU::mmio_r43x4(uint8 i) {
|
||||
return channel[i].srcaddr >> 16;
|
||||
return channel[i].srcbank;
|
||||
}
|
||||
|
||||
//DASxL
|
||||
@@ -233,17 +297,17 @@ uint8 bCPU::mmio_r43x6(uint8 i) {
|
||||
|
||||
//DASBx
|
||||
uint8 bCPU::mmio_r43x7(uint8 i) {
|
||||
return channel[i].hdma_indirect_bank;
|
||||
return channel[i].hdma_ibank;
|
||||
}
|
||||
|
||||
//A2AxL
|
||||
uint8 bCPU::mmio_r43x8(uint8 i) {
|
||||
return channel[i].hdma_taddr;
|
||||
return channel[i].hdma_addr;
|
||||
}
|
||||
|
||||
//A2AxH
|
||||
uint8 bCPU::mmio_r43x9(uint8 i) {
|
||||
return channel[i].hdma_taddr >> 8;
|
||||
return channel[i].hdma_addr >> 8;
|
||||
}
|
||||
|
||||
//NTRLx
|
||||
@@ -257,12 +321,10 @@ 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);
|
||||
return r_apu->port_read(addr & 3);
|
||||
}
|
||||
|
||||
//HDMA
|
||||
@@ -281,19 +343,17 @@ uint8 i;
|
||||
case 0x9:return cpu->mmio_r43x9(i);
|
||||
case 0xa:return cpu->mmio_r43xa(i);
|
||||
case 0xb:return cpu->mmio_r43xb(i);
|
||||
case 0xc:return 0x43; //unmapped
|
||||
case 0xd:return 0x43; //unmapped
|
||||
case 0xe:return 0x43; //unmapped
|
||||
case 0xc:return cpu->regs.mdr; //unmapped
|
||||
case 0xd:return cpu->regs.mdr; //unmapped
|
||||
case 0xe:return cpu->regs.mdr; //unmapped
|
||||
case 0xf:return cpu->mmio_r43xb(i); //mirror of 43xb
|
||||
}
|
||||
}
|
||||
|
||||
switch(addr) {
|
||||
case 0x2180:return cpu->mmio_r2180(); //WMDATA
|
||||
case 0x21c2:return cpu->mmio_r21c2(); //???
|
||||
case 0x21c3:return cpu->mmio_r21c3(); //???
|
||||
case 0x2800:return cpu->srtc_read();
|
||||
case 0x4016:return cpu->mmio_r4016(); //JOYSER0
|
||||
case 0x4017:return cpu->mmio_r4017(); //JOYSER1
|
||||
case 0x4210:return cpu->mmio_r4210(); //RDNMI
|
||||
case 0x4211:return cpu->mmio_r4211(); //TIMEUP
|
||||
case 0x4212:return cpu->mmio_r4212(); //HVBJOY
|
||||
@@ -304,14 +364,17 @@ uint8 i;
|
||||
case 0x4217:return cpu->mmio_r4217(); //RDMPYH
|
||||
case 0x4218:return cpu->mmio_r4218(); //JOY1L
|
||||
case 0x4219:return cpu->mmio_r4219(); //JOY1H
|
||||
case 0x421a:case 0x421b:case 0x421c:case 0x421d:case 0x421e:case 0x421f:return 0x00;
|
||||
case 0x421a:return cpu->mmio_r421a(); //JOY2L
|
||||
case 0x421b:return cpu->mmio_r421b(); //JOY2H
|
||||
case 0x421c:case 0x421d:case 0x421e:case 0x421f:return 0x00;
|
||||
}
|
||||
return 0x00;
|
||||
|
||||
return cpu->regs.mdr;
|
||||
}
|
||||
|
||||
//WMDATA
|
||||
void bCPU::mmio_w2180(uint8 value) {
|
||||
mem_bus->write(0x7e0000 | status.wram_addr, value);
|
||||
r_mem->write(0x7e0000 | status.wram_addr, value);
|
||||
status.wram_addr++;
|
||||
status.wram_addr &= 0x01ffff;
|
||||
}
|
||||
@@ -336,13 +399,22 @@ void bCPU::mmio_w2183(uint8 value) {
|
||||
|
||||
//JOYSER0
|
||||
void bCPU::mmio_w4016(uint8 value) {
|
||||
status.joypad1_strobe_value = (value & 1);
|
||||
status.joypad1_strobe_value = !!(value & 1);
|
||||
if(value == 1) {
|
||||
snes->poll_input();
|
||||
snes->poll_input(SNES::DEV_JOYPAD1);
|
||||
status.joypad1_read_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//JOYSER1
|
||||
void bCPU::mmio_w4017(uint8 value) {
|
||||
status.joypad2_strobe_value = !!(value & 1);
|
||||
if(value == 1) {
|
||||
snes->poll_input(SNES::DEV_JOYPAD2);
|
||||
status.joypad2_read_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//NMITIMEN
|
||||
void bCPU::mmio_w4200(uint8 value) {
|
||||
status.nmi_enabled = !!(value & 0x80);
|
||||
@@ -350,19 +422,26 @@ void bCPU::mmio_w4200(uint8 value) {
|
||||
status.hirq_enabled = !!(value & 0x10);
|
||||
status.auto_joypad_poll = !!(value & 0x01);
|
||||
|
||||
if(status.nmi_enabled == false) {
|
||||
status.nmi_pin = 0;
|
||||
if(time.nmi_read == 0) {
|
||||
if(time.nmi_line == 1 && !status.nmi_enabled == 0) {
|
||||
time.nmi_transition = 1;
|
||||
}
|
||||
time.nmi_line = !status.nmi_enabled;
|
||||
}
|
||||
|
||||
if(status.virq_enabled == false && status.hirq_enabled == false) {
|
||||
status.irq_pin = 0;
|
||||
time.irq_line = 1;
|
||||
time.irq_read = 1;
|
||||
time.irq_transition = 0;
|
||||
}
|
||||
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//WRIO
|
||||
void bCPU::mmio_w4201(uint8 value) {
|
||||
if((status.pio & 0x80) && !(value & 0x80)) {
|
||||
ppu->latch_counters();
|
||||
r_ppu->latch_counters();
|
||||
}
|
||||
status.pio = value;
|
||||
}
|
||||
@@ -390,44 +469,48 @@ void bCPU::mmio_w4205(uint8 value) {
|
||||
//WRDIVB
|
||||
void bCPU::mmio_w4206(uint8 value) {
|
||||
status.div_b = value;
|
||||
status.r4214 = (status.div_b)?status.div_a / status.div_b : 0xffff;
|
||||
status.r4216 = (status.div_b)?status.div_a % status.div_b : status.div_a;
|
||||
status.r4214 = (status.div_b) ? status.div_a / status.div_b : 0xffff;
|
||||
status.r4216 = (status.div_b) ? status.div_a % status.div_b : status.div_a;
|
||||
}
|
||||
|
||||
//HTIMEL
|
||||
void bCPU::mmio_w4207(uint8 value) {
|
||||
status.hirq_pos = (status.hirq_pos & 0xff00) | value;
|
||||
if(status.irq_triggered == false)status.irq_pin = 1;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//HTIMEH
|
||||
void bCPU::mmio_w4208(uint8 value) {
|
||||
status.hirq_pos = (status.hirq_pos & 0x00ff) | (value << 8);
|
||||
if(status.irq_triggered == false)status.irq_pin = 1;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//VTIMEL
|
||||
void bCPU::mmio_w4209(uint8 value) {
|
||||
status.virq_pos = (status.virq_pos & 0xff00) | value;
|
||||
if(status.irq_triggered == false)status.irq_pin = 1;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//VTIMEH
|
||||
void bCPU::mmio_w420a(uint8 value) {
|
||||
status.virq_pos = (status.virq_pos & 0x00ff) | (value << 8);
|
||||
if(status.irq_triggered == false)status.irq_pin = 1;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//DMAEN
|
||||
void bCPU::mmio_w420b(uint8 value) {
|
||||
int len;
|
||||
if(value != 0x00) {
|
||||
status.dma_state = DMASTATE_INIT;
|
||||
run_state.dma = true;
|
||||
status.dma_state = DMASTATE_DMASYNC;
|
||||
}
|
||||
|
||||
for(int i=0;i<8;i++) {
|
||||
if(value & (1 << i)) {
|
||||
channel[i].active = true;
|
||||
channel[i].hdma_active = false;
|
||||
channel[i].active = true;
|
||||
channel[i].hdma_enabled = false;
|
||||
channel[i].hdma_active = false;
|
||||
channel[i].read_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -435,13 +518,14 @@ void bCPU::mmio_w420b(uint8 value) {
|
||||
//HDMAEN
|
||||
void bCPU::mmio_w420c(uint8 value) {
|
||||
for(int i=0;i<8;i++) {
|
||||
channel[i].hdma_active = !!(value & (1 << i));
|
||||
channel[i].hdma_enabled = !!(value & (1 << i));
|
||||
channel[i].hdma_active = !!(value & (1 << i));
|
||||
}
|
||||
}
|
||||
|
||||
//MEMSEL
|
||||
void bCPU::mmio_w420d(uint8 value) {
|
||||
mem_bus->fastROM = value & 1;
|
||||
r_mem->set_speed(value & 1);
|
||||
}
|
||||
|
||||
//DMAPx
|
||||
@@ -461,17 +545,17 @@ void bCPU::mmio_w43x1(uint8 value, uint8 i) {
|
||||
|
||||
//A1TxL
|
||||
void bCPU::mmio_w43x2(uint8 value, uint8 i) {
|
||||
channel[i].srcaddr = (channel[i].srcaddr & 0xffff00) | value;
|
||||
channel[i].srcaddr = (channel[i].srcaddr & 0xff00) | value;
|
||||
}
|
||||
|
||||
//A1TxH
|
||||
void bCPU::mmio_w43x3(uint8 value, uint8 i) {
|
||||
channel[i].srcaddr = (channel[i].srcaddr & 0xff00ff) | (value << 8);
|
||||
channel[i].srcaddr = (channel[i].srcaddr & 0x00ff) | (value << 8);
|
||||
}
|
||||
|
||||
//A1Bx
|
||||
void bCPU::mmio_w43x4(uint8 value, uint8 i) {
|
||||
channel[i].srcaddr = (channel[i].srcaddr & 0x00ffff) | (value << 16);
|
||||
channel[i].srcbank = value;
|
||||
}
|
||||
|
||||
//DASxL
|
||||
@@ -486,17 +570,17 @@ void bCPU::mmio_w43x6(uint8 value, uint8 i) {
|
||||
|
||||
//DASBx
|
||||
void bCPU::mmio_w43x7(uint8 value, uint8 i) {
|
||||
channel[i].hdma_indirect_bank = value;
|
||||
channel[i].hdma_ibank = value;
|
||||
}
|
||||
|
||||
//A2AxL
|
||||
void bCPU::mmio_w43x8(uint8 value, uint8 i) {
|
||||
channel[i].hdma_taddr = (channel[i].hdma_taddr & 0xffff00) | value;
|
||||
channel[i].hdma_addr = (channel[i].hdma_addr & 0xff00) | value;
|
||||
}
|
||||
|
||||
//A2AxH
|
||||
void bCPU::mmio_w43x9(uint8 value, uint8 i) {
|
||||
channel[i].hdma_taddr = (channel[i].hdma_taddr & 0xff00ff) | (value << 8);
|
||||
channel[i].hdma_addr = (channel[i].hdma_addr & 0x00ff) | (value << 8);
|
||||
}
|
||||
|
||||
//NTRLx
|
||||
@@ -511,8 +595,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);
|
||||
@@ -547,8 +629,8 @@ uint8 i;
|
||||
case 0x2181:cpu->mmio_w2181(value);return; //WMADDL
|
||||
case 0x2182:cpu->mmio_w2182(value);return; //WMADDM
|
||||
case 0x2183:cpu->mmio_w2183(value);return; //WMADDH
|
||||
case 0x2801:cpu->srtc_write(value);return;
|
||||
case 0x4016:cpu->mmio_w4016(value);return; //JOYSER0
|
||||
case 0x4017:cpu->mmio_w4017(value);return; //JOYSER1
|
||||
case 0x4200:cpu->mmio_w4200(value);return; //NMITIMEN
|
||||
case 0x4201:cpu->mmio_w4201(value);return; //WRIO
|
||||
case 0x4202:cpu->mmio_w4202(value);return; //WRMPYA
|
||||
|
||||
@@ -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();
|
||||
|
||||
+700
-393
File diff suppressed because it is too large.
Load diff
+411
-239
@@ -1,310 +1,482 @@
|
||||
void bCPU::op_bra() {
|
||||
l1:
|
||||
rd.l = op_read();
|
||||
if(1) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
l2:
|
||||
cpu_c6(aa.w);
|
||||
l3:
|
||||
cpu_io();
|
||||
}
|
||||
|
||||
void bCPU::op_bcc() {
|
||||
l1:
|
||||
rd.l = op_read();
|
||||
if(!regs.p.c) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
return;
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
if(!!regs.p.c)last_cycle();
|
||||
rd.l = op_read();
|
||||
if(!regs.p.c) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
status.cycle_pos = 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
l2:
|
||||
cpu_c6(aa.w);
|
||||
l3:
|
||||
cpu_io();
|
||||
}
|
||||
|
||||
void bCPU::op_bcs() {
|
||||
l1:
|
||||
rd.l = op_read();
|
||||
if(regs.p.c) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
return;
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
if(!regs.p.c)last_cycle();
|
||||
rd.l = op_read();
|
||||
if(regs.p.c) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
status.cycle_pos = 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
l2:
|
||||
cpu_c6(aa.w);
|
||||
l3:
|
||||
cpu_io();
|
||||
}
|
||||
|
||||
void bCPU::op_bne() {
|
||||
l1:
|
||||
rd.l = op_read();
|
||||
if(!regs.p.z) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
return;
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
if(!!regs.p.z)last_cycle();
|
||||
rd.l = op_read();
|
||||
if(!regs.p.z) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
status.cycle_pos = 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
l2:
|
||||
cpu_c6(aa.w);
|
||||
l3:
|
||||
cpu_io();
|
||||
}
|
||||
|
||||
void bCPU::op_beq() {
|
||||
l1:
|
||||
rd.l = op_read();
|
||||
if(regs.p.z) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
return;
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
if(!regs.p.z)last_cycle();
|
||||
rd.l = op_read();
|
||||
if(regs.p.z) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
status.cycle_pos = 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
l2:
|
||||
cpu_c6(aa.w);
|
||||
l3:
|
||||
cpu_io();
|
||||
}
|
||||
|
||||
void bCPU::op_bpl() {
|
||||
l1:
|
||||
rd.l = op_read();
|
||||
if(!regs.p.n) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
return;
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
if(!!regs.p.n)last_cycle();
|
||||
rd.l = op_read();
|
||||
if(!regs.p.n) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
status.cycle_pos = 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
l2:
|
||||
cpu_c6(aa.w);
|
||||
l3:
|
||||
cpu_io();
|
||||
}
|
||||
|
||||
void bCPU::op_bmi() {
|
||||
l1:
|
||||
rd.l = op_read();
|
||||
if(regs.p.n) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
return;
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
if(!regs.p.n)last_cycle();
|
||||
rd.l = op_read();
|
||||
if(regs.p.n) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
status.cycle_pos = 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
l2:
|
||||
cpu_c6(aa.w);
|
||||
l3:
|
||||
cpu_io();
|
||||
}
|
||||
|
||||
void bCPU::op_bvc() {
|
||||
l1:
|
||||
rd.l = op_read();
|
||||
if(!regs.p.v) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
return;
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
if(!!regs.p.v)last_cycle();
|
||||
rd.l = op_read();
|
||||
if(!regs.p.v) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
status.cycle_pos = 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
l2:
|
||||
cpu_c6(aa.w);
|
||||
l3:
|
||||
cpu_io();
|
||||
}
|
||||
|
||||
void bCPU::op_bvs() {
|
||||
l1:
|
||||
rd.l = op_read();
|
||||
if(regs.p.v) {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
if(!regs.p.v)last_cycle();
|
||||
rd.l = op_read();
|
||||
if(regs.p.v) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
status.cycle_pos = 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_bra() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
rd.l = op_read();
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
return;
|
||||
break;
|
||||
case 2:
|
||||
cpu_c6(aa.w);
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
l2:
|
||||
cpu_c6(aa.w);
|
||||
l3:
|
||||
cpu_io();
|
||||
}
|
||||
|
||||
void bCPU::op_brl() {
|
||||
l1:
|
||||
rd.l = op_read();
|
||||
l2:
|
||||
rd.h = op_read();
|
||||
l3:
|
||||
cpu_io();
|
||||
regs.pc.w = regs.pc.d + (int16)rd.w;
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
rd.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
rd.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.pc.w = regs.pc.d + (int16)rd.w;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_jmp_addr() {
|
||||
l1:
|
||||
rd.l = op_read();
|
||||
l2:
|
||||
rd.h = op_read();
|
||||
regs.pc.w = rd.w;
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
rd.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
rd.h = op_read();
|
||||
regs.pc.w = rd.w;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_jmp_long() {
|
||||
l1:
|
||||
rd.l = op_read();
|
||||
l2:
|
||||
rd.h = op_read();
|
||||
l3:
|
||||
rd.b = op_read();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
rd.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
rd.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
last_cycle();
|
||||
rd.b = op_read();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_jmp_iaddr() {
|
||||
l1:
|
||||
aa.l = op_read();
|
||||
l2:
|
||||
aa.h = op_read();
|
||||
l3:
|
||||
rd.l = op_read(OPMODE_ADDR, aa.w);
|
||||
l4:
|
||||
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
rd.l = op_read(OPMODE_ADDR, aa.w);
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_jmp_iaddrx() {
|
||||
l1:
|
||||
aa.l = op_read();
|
||||
l2:
|
||||
aa.h = op_read();
|
||||
l3:
|
||||
cpu_io();
|
||||
l4:
|
||||
rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
|
||||
l5:
|
||||
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
cpu_io();
|
||||
break;
|
||||
case 4:
|
||||
rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_jmp_iladdr() {
|
||||
l1:
|
||||
aa.l = op_read();
|
||||
l2:
|
||||
aa.h = op_read();
|
||||
l3:
|
||||
rd.l = op_read(OPMODE_ADDR, aa.w);
|
||||
l4:
|
||||
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
|
||||
l5:
|
||||
rd.b = op_read(OPMODE_ADDR, aa.w + 2);
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
rd.l = op_read(OPMODE_ADDR, aa.w);
|
||||
break;
|
||||
case 4:
|
||||
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
rd.b = op_read(OPMODE_ADDR, aa.w + 2);
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_jsr_addr() {
|
||||
l1:
|
||||
aa.l = op_read();
|
||||
l2:
|
||||
aa.h = op_read();
|
||||
l3:
|
||||
cpu_io();
|
||||
l4:
|
||||
regs.pc.w--;
|
||||
stack_write(regs.pc.h);
|
||||
l5:
|
||||
stack_write(regs.pc.l);
|
||||
regs.pc.w = aa.w;
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
cpu_io();
|
||||
break;
|
||||
case 4:
|
||||
regs.pc.w--;
|
||||
stack_write(regs.pc.h);
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
stack_write(regs.pc.l);
|
||||
regs.pc.w = aa.w;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_jsr_long() {
|
||||
l1:
|
||||
aa.l = op_read();
|
||||
l2:
|
||||
aa.h = op_read();
|
||||
l3:
|
||||
stack_write(regs.pc.b);
|
||||
l4:
|
||||
cpu_io();
|
||||
l5:
|
||||
aa.b = op_read();
|
||||
l6:
|
||||
regs.pc.w--;
|
||||
stack_write(regs.pc.h);
|
||||
l7:
|
||||
stack_write(regs.pc.l);
|
||||
regs.pc.d = aa.d & 0xffffff;
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
stack_write(regs.pc.b);
|
||||
break;
|
||||
case 4:
|
||||
cpu_io();
|
||||
break;
|
||||
case 5:
|
||||
aa.b = op_read();
|
||||
break;
|
||||
case 6:
|
||||
regs.pc.w--;
|
||||
stack_write(regs.pc.h);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
stack_write(regs.pc.l);
|
||||
regs.pc.d = aa.d & 0xffffff;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_jsr_iaddrx() {
|
||||
l1:
|
||||
aa.l = op_read();
|
||||
l2:
|
||||
stack_write(regs.pc.h);
|
||||
l3:
|
||||
stack_write(regs.pc.l);
|
||||
l4:
|
||||
aa.h = op_read();
|
||||
l5:
|
||||
cpu_io();
|
||||
l6:
|
||||
rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
|
||||
l7:
|
||||
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
stack_write(regs.pc.h);
|
||||
break;
|
||||
case 3:
|
||||
stack_write(regs.pc.l);
|
||||
break;
|
||||
case 4:
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 5:
|
||||
cpu_io();
|
||||
break;
|
||||
case 6:
|
||||
rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_rti() {
|
||||
l1:
|
||||
cpu_io();
|
||||
l2:
|
||||
cpu_io();
|
||||
l3:
|
||||
regs.p = stack_read();
|
||||
if(regs.e)regs.p |= 0x30;
|
||||
if(regs.p.x) {
|
||||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
cpu_io();
|
||||
break;
|
||||
case 2:
|
||||
cpu_io();
|
||||
break;
|
||||
case 3:
|
||||
regs.p = stack_read();
|
||||
if(regs.e)regs.p |= 0x30;
|
||||
if(regs.p.x) {
|
||||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
rd.l = stack_read();
|
||||
break;
|
||||
case 5:
|
||||
rd.h = stack_read();
|
||||
if(regs.e) {
|
||||
regs.pc.w = rd.w;
|
||||
status.cycle_pos = 0;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
last_cycle();
|
||||
rd.b = stack_read();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
l4:
|
||||
rd.l = stack_read();
|
||||
l5:
|
||||
rd.h = stack_read();
|
||||
if(regs.e) {
|
||||
regs.pc.w = rd.w;
|
||||
return;
|
||||
}
|
||||
l6:
|
||||
rd.b = stack_read();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
}
|
||||
|
||||
void bCPU::op_rts() {
|
||||
l1:
|
||||
cpu_io();
|
||||
l2:
|
||||
cpu_io();
|
||||
l3:
|
||||
rd.l = stack_read();
|
||||
l4:
|
||||
rd.h = stack_read();
|
||||
l5:
|
||||
cpu_io();
|
||||
regs.pc.w = rd.w;
|
||||
regs.pc.w++;
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
cpu_io();
|
||||
break;
|
||||
case 2:
|
||||
cpu_io();
|
||||
break;
|
||||
case 3:
|
||||
rd.l = stack_read();
|
||||
break;
|
||||
case 4:
|
||||
rd.h = stack_read();
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
regs.pc.w = rd.w;
|
||||
regs.pc.w++;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_rtl() {
|
||||
l1:
|
||||
cpu_io();
|
||||
l2:
|
||||
cpu_io();
|
||||
l3:
|
||||
rd.l = stack_read();
|
||||
l4:
|
||||
rd.h = stack_read();
|
||||
l5:
|
||||
rd.b = stack_read();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
regs.pc.w++;
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
cpu_io();
|
||||
break;
|
||||
case 2:
|
||||
cpu_io();
|
||||
break;
|
||||
case 3:
|
||||
rd.l = stack_read();
|
||||
break;
|
||||
case 4:
|
||||
rd.h = stack_read();
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
rd.b = stack_read();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
regs.pc.w++;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+2804
-1534
File diff suppressed because it is too large.
Load diff
+986
-616
File diff suppressed because it is too large.
Load diff
+510
-268
@@ -1,340 +1,582 @@
|
||||
void bCPU::op_sta_addr() {
|
||||
l1:
|
||||
aa.l = op_read();
|
||||
l2:
|
||||
aa.h = op_read();
|
||||
l3:
|
||||
op_write(OPMODE_DBR, aa.w, regs.a.w);
|
||||
if(regs.p.m)return;
|
||||
l4:
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.a.w >> 8);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, regs.a.w);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.a.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_stx_addr() {
|
||||
l1:
|
||||
aa.l = op_read();
|
||||
l2:
|
||||
aa.h = op_read();
|
||||
l3:
|
||||
op_write(OPMODE_DBR, aa.w, regs.x.w);
|
||||
if(regs.p.x)return;
|
||||
l4:
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.x.w >> 8);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, regs.x.w);
|
||||
if(regs.p.x)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.x.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sty_addr() {
|
||||
l1:
|
||||
aa.l = op_read();
|
||||
l2:
|
||||
aa.h = op_read();
|
||||
l3:
|
||||
op_write(OPMODE_DBR, aa.w, regs.y.w);
|
||||
if(regs.p.x)return;
|
||||
l4:
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.y.w >> 8);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, regs.y.w);
|
||||
if(regs.p.x)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.y.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_stz_addr() {
|
||||
l1:
|
||||
aa.l = op_read();
|
||||
l2:
|
||||
aa.h = op_read();
|
||||
l3:
|
||||
op_write(OPMODE_DBR, aa.w, 0x0000);
|
||||
if(regs.p.m)return;
|
||||
l4:
|
||||
op_write(OPMODE_DBR, aa.w + 1, 0x0000 >> 8);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, 0x0000);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, 0x0000 >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_addrx() {
|
||||
l1:
|
||||
aa.l = op_read();
|
||||
l2:
|
||||
aa.h = op_read();
|
||||
l3:
|
||||
cpu_c4(aa.w, aa.w + regs.x.w);
|
||||
l4:
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, regs.a.w);
|
||||
if(regs.p.m)return;
|
||||
l5:
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, regs.a.w >> 8);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
cpu_c4(aa.w, aa.w + regs.x.w);
|
||||
break;
|
||||
case 4:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, regs.a.w);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, regs.a.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_stz_addrx() {
|
||||
l1:
|
||||
aa.l = op_read();
|
||||
l2:
|
||||
aa.h = op_read();
|
||||
l3:
|
||||
cpu_c4(aa.w, aa.w + regs.x.w);
|
||||
l4:
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, 0x0000);
|
||||
if(regs.p.m)return;
|
||||
l5:
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, 0x0000 >> 8);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
cpu_c4(aa.w, aa.w + regs.x.w);
|
||||
break;
|
||||
case 4:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, 0x0000);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, 0x0000 >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_addry() {
|
||||
l1:
|
||||
aa.l = op_read();
|
||||
l2:
|
||||
aa.h = op_read();
|
||||
l3:
|
||||
cpu_c4(aa.w, aa.w + regs.y.w);
|
||||
l4:
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)return;
|
||||
l5:
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
cpu_c4(aa.w, aa.w + regs.y.w);
|
||||
break;
|
||||
case 4:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_long() {
|
||||
l1:
|
||||
aa.l = op_read();
|
||||
l2:
|
||||
aa.h = op_read();
|
||||
l3:
|
||||
aa.b = op_read();
|
||||
l4:
|
||||
op_write(OPMODE_LONG, aa.d, regs.a.l);
|
||||
if(regs.p.m)return;
|
||||
l5:
|
||||
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
aa.b = op_read();
|
||||
break;
|
||||
case 4:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_longx() {
|
||||
l1:
|
||||
aa.l = op_read();
|
||||
l2:
|
||||
aa.h = op_read();
|
||||
l3:
|
||||
aa.b = op_read();
|
||||
l4:
|
||||
op_write(OPMODE_LONG, aa.d + regs.x.w, regs.a.l);
|
||||
if(regs.p.m)return;
|
||||
l5:
|
||||
op_write(OPMODE_LONG, aa.d + regs.x.w + 1, regs.a.h);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
aa.b = op_read();
|
||||
break;
|
||||
case 4:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.x.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.x.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_dp() {
|
||||
l1:
|
||||
dp = op_read();
|
||||
l2:
|
||||
cpu_c2();
|
||||
l3:
|
||||
op_write(OPMODE_DP, dp, regs.a.w);
|
||||
if(regs.p.m)return;
|
||||
l4:
|
||||
op_write(OPMODE_DP, dp + 1, regs.a.w >> 8);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DP, dp, regs.a.w);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + 1, regs.a.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_stx_dp() {
|
||||
l1:
|
||||
dp = op_read();
|
||||
l2:
|
||||
cpu_c2();
|
||||
l3:
|
||||
op_write(OPMODE_DP, dp, regs.x.w);
|
||||
if(regs.p.x)return;
|
||||
l4:
|
||||
op_write(OPMODE_DP, dp + 1, regs.x.w >> 8);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DP, dp, regs.x.w);
|
||||
if(regs.p.x)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + 1, regs.x.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sty_dp() {
|
||||
l1:
|
||||
dp = op_read();
|
||||
l2:
|
||||
cpu_c2();
|
||||
l3:
|
||||
op_write(OPMODE_DP, dp, regs.y.w);
|
||||
if(regs.p.x)return;
|
||||
l4:
|
||||
op_write(OPMODE_DP, dp + 1, regs.y.w >> 8);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DP, dp, regs.y.w);
|
||||
if(regs.p.x)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + 1, regs.y.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_stz_dp() {
|
||||
l1:
|
||||
dp = op_read();
|
||||
l2:
|
||||
cpu_c2();
|
||||
l3:
|
||||
op_write(OPMODE_DP, dp, 0x0000);
|
||||
if(regs.p.m)return;
|
||||
l4:
|
||||
op_write(OPMODE_DP, dp + 1, 0x0000 >> 8);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DP, dp, 0x0000);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + 1, 0x0000 >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_dpx() {
|
||||
l1:
|
||||
dp = op_read();
|
||||
l2:
|
||||
cpu_c2();
|
||||
l3:
|
||||
cpu_io();
|
||||
l4:
|
||||
op_write(OPMODE_DP, dp + regs.x.w, regs.a.w);
|
||||
if(regs.p.m)return;
|
||||
l5:
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, regs.a.w >> 8);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
cpu_io();
|
||||
break;
|
||||
case 4:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, regs.a.w);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, regs.a.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sty_dpx() {
|
||||
l1:
|
||||
dp = op_read();
|
||||
l2:
|
||||
cpu_c2();
|
||||
l3:
|
||||
cpu_io();
|
||||
l4:
|
||||
op_write(OPMODE_DP, dp + regs.x.w, regs.y.w);
|
||||
if(regs.p.x)return;
|
||||
l5:
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, regs.y.w >> 8);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
cpu_io();
|
||||
break;
|
||||
case 4:
|
||||
if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, regs.y.w);
|
||||
if(regs.p.x)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, regs.y.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_stz_dpx() {
|
||||
l1:
|
||||
dp = op_read();
|
||||
l2:
|
||||
cpu_c2();
|
||||
l3:
|
||||
cpu_io();
|
||||
l4:
|
||||
op_write(OPMODE_DP, dp + regs.x.w, 0x0000);
|
||||
if(regs.p.m)return;
|
||||
l5:
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, 0x0000 >> 8);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
cpu_io();
|
||||
break;
|
||||
case 4:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, 0x0000);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, 0x0000 >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_stx_dpy() {
|
||||
l1:
|
||||
dp = op_read();
|
||||
l2:
|
||||
cpu_c2();
|
||||
l3:
|
||||
cpu_io();
|
||||
l4:
|
||||
op_write(OPMODE_DP, dp + regs.y.w, regs.x.l);
|
||||
if(regs.p.x)return;
|
||||
l5:
|
||||
op_write(OPMODE_DP, dp + regs.y.w + 1, regs.x.h);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
cpu_io();
|
||||
break;
|
||||
case 4:
|
||||
if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.y.w, regs.x.l);
|
||||
if(regs.p.x)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.y.w + 1, regs.x.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_idp() {
|
||||
l1:
|
||||
dp = op_read();
|
||||
l2:
|
||||
cpu_c2();
|
||||
l3:
|
||||
aa.l = op_read(OPMODE_DP, dp);
|
||||
l4:
|
||||
aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
l5:
|
||||
op_write(OPMODE_DBR, aa.w, regs.a.l);
|
||||
if(regs.p.m)return;
|
||||
l6:
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
aa.l = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 4:
|
||||
aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
break;
|
||||
case 5:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 6:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_ildp() {
|
||||
l1:
|
||||
dp = op_read();
|
||||
l2:
|
||||
cpu_c2();
|
||||
l3:
|
||||
aa.l = op_read(OPMODE_DP, dp);
|
||||
l4:
|
||||
aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
l5:
|
||||
aa.b = op_read(OPMODE_DP, dp + 2);
|
||||
l6:
|
||||
op_write(OPMODE_LONG, aa.d, regs.a.l);
|
||||
if(regs.p.m)return;
|
||||
l7:
|
||||
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
aa.l = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 4:
|
||||
aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
break;
|
||||
case 5:
|
||||
aa.b = op_read(OPMODE_DP, dp + 2);
|
||||
break;
|
||||
case 6:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_idpx() {
|
||||
l1:
|
||||
dp = op_read();
|
||||
l2:
|
||||
cpu_c2();
|
||||
l3:
|
||||
cpu_io();
|
||||
l4:
|
||||
aa.l = op_read(OPMODE_DP, dp + regs.x.w);
|
||||
l5:
|
||||
aa.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
|
||||
l6:
|
||||
op_write(OPMODE_DBR, aa.w, regs.a.l);
|
||||
if(regs.p.m)return;
|
||||
l7:
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
cpu_io();
|
||||
break;
|
||||
case 4:
|
||||
aa.l = op_read(OPMODE_DP, dp + regs.x.w);
|
||||
break;
|
||||
case 5:
|
||||
aa.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
|
||||
break;
|
||||
case 6:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_idpy() {
|
||||
l1:
|
||||
dp = op_read();
|
||||
l2:
|
||||
cpu_c2();
|
||||
l3:
|
||||
aa.l = op_read(OPMODE_DP, dp);
|
||||
l4:
|
||||
aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
l5:
|
||||
cpu_c4(aa.w, aa.w + regs.y.w);
|
||||
l6:
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)return;
|
||||
l7:
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
aa.l = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 4:
|
||||
aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
break;
|
||||
case 5:
|
||||
cpu_c4(aa.w, aa.w + regs.y.w);
|
||||
break;
|
||||
case 6:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_ildpy() {
|
||||
l1:
|
||||
dp = op_read();
|
||||
l2:
|
||||
cpu_c2();
|
||||
l3:
|
||||
aa.l = op_read(OPMODE_DP, dp);
|
||||
l4:
|
||||
aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
l5:
|
||||
aa.b = op_read(OPMODE_DP, dp + 2);
|
||||
l6:
|
||||
op_write(OPMODE_LONG, aa.d + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)return;
|
||||
l7:
|
||||
op_write(OPMODE_LONG, aa.d + regs.y.w + 1, regs.a.h);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
aa.l = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 4:
|
||||
aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
break;
|
||||
case 5:
|
||||
aa.b = op_read(OPMODE_DP, dp + 2);
|
||||
break;
|
||||
case 6:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.y.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_sr() {
|
||||
l1:
|
||||
sp = op_read();
|
||||
l2:
|
||||
cpu_io();
|
||||
l3:
|
||||
op_write(OPMODE_SP, sp, regs.a.l);
|
||||
if(regs.p.m)return;
|
||||
l4:
|
||||
op_write(OPMODE_SP, sp + 1, regs.a.h);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
sp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
cpu_io();
|
||||
break;
|
||||
case 3:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_SP, sp, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
last_cycle();
|
||||
op_write(OPMODE_SP, sp + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_isry() {
|
||||
l1:
|
||||
sp = op_read();
|
||||
l2:
|
||||
cpu_io();
|
||||
l3:
|
||||
aa.l = op_read(OPMODE_SP, sp);
|
||||
l4:
|
||||
aa.h = op_read(OPMODE_SP, sp + 1);
|
||||
l5:
|
||||
cpu_io();
|
||||
l6:
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)return;
|
||||
l7:
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
sp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
cpu_io();
|
||||
break;
|
||||
case 3:
|
||||
aa.l = op_read(OPMODE_SP, sp);
|
||||
break;
|
||||
case 4:
|
||||
aa.h = op_read(OPMODE_SP, sp + 1);
|
||||
break;
|
||||
case 5:
|
||||
cpu_io();
|
||||
break;
|
||||
case 6:
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 7:
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
+283
-66
@@ -1,21 +1,194 @@
|
||||
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; }
|
||||
/* Notes about PAL timing:
|
||||
* As I do not have PAL hardware to run timing tests on, I've
|
||||
* had to guess on a lot of things. Below is how I've arrived
|
||||
* at various calculations:
|
||||
*
|
||||
* NTSC timing crystal: ~21477272hz
|
||||
* PAL timing crystal: ~21281370hz
|
||||
* NTSC ~60fps, PAL ~50fps
|
||||
* NTSC ~262 lines/frame, PAL ~312 lines/frame
|
||||
* NTSC 21477272 / (262 * 60) = ~1366 cycles/line
|
||||
* PAL 21281370 / (312 * 50) = ~1364 cycles/line
|
||||
*
|
||||
* As the cycles/line are very close between the two systems,
|
||||
* I have left the known NTSC anomalies intact for PAL timing.
|
||||
* In reality, some of these may not exist, and some may be
|
||||
* slightly different.
|
||||
*
|
||||
* [known]
|
||||
* - DRAM refresh occurs at about the same time every
|
||||
* scanline on PAL units (per Overload).
|
||||
* [unknown]
|
||||
* - Are dots 323/327 still 2 cycles longer than the
|
||||
* other dots?
|
||||
* - Is scanline 240 on non-interlace odd frames still
|
||||
* 4 cycles short?
|
||||
*/
|
||||
|
||||
void bCPU::set_interlace(bool r) { time.interlace = r; }
|
||||
void bCPU::set_overscan(bool r) { time.overscan = r; }
|
||||
uint16 bCPU::vcounter() { return time.v; }
|
||||
uint16 bCPU::hcounter() { return get_hcounter(); }
|
||||
uint16 bCPU::hcycles() { return time.hc; }
|
||||
|
||||
uint8 bCPU::dma_counter() { return (time.dma_counter + time.hc) & 6; }
|
||||
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; 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]
|
||||
//interlace mode has 525 scanlines: 263 on the even frame,
|
||||
//and 262 on the odd.
|
||||
//non-interlace mode has 524 scanlines: 262 scanlines on
|
||||
//both even and odd frames.
|
||||
//[PAL] <PAL info is unverified on hardware>
|
||||
//interlace mode has 625 scanlines: 313 on the even frame,
|
||||
//and 312 on the odd.
|
||||
//non-interlace mode has 624 scanlines: 312 scanlines on
|
||||
//both even and odd frames.
|
||||
//
|
||||
//cycles per frame:
|
||||
// 263 * 1364 = 358732
|
||||
@@ -28,114 +201,158 @@ void bCPU::inc_vcounter() {
|
||||
time.interlace_field ^= 1;
|
||||
|
||||
if(time.interlace == true && time.interlace_field == 0) {
|
||||
time.frame_lines = 263;
|
||||
time.frame_lines = time.region_scanlines + 1;
|
||||
} else {
|
||||
time.frame_lines = 262;
|
||||
time.frame_lines = time.region_scanlines;
|
||||
}
|
||||
}
|
||||
|
||||
time.hc = 0;
|
||||
time.dma_counter = time.line_cycles & 6;
|
||||
time.dma_counter += time.line_cycles;
|
||||
if(time.v == 240 && time.interlace == false && time.interlace_field == 1) {
|
||||
time.line_cycles = 1360;
|
||||
} else {
|
||||
time.line_cycles = 1364;
|
||||
}
|
||||
time.dram_refreshed = false;
|
||||
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
//all dots are 4 cycles long, except dots 322 and 326. dots 322 and 326
|
||||
//all dots are 4 cycles long, except dots 323 and 327. dots 323 and 327
|
||||
//are 6 cycles long. this holds true for all scanlines except scanline
|
||||
//240 on non-interlace odd frames. the reason for this is because this
|
||||
//scanline is only 1360 cycles long, instead of 1364 like all other
|
||||
//scanlines.
|
||||
//this makes the effective range of hscan_pos 0-339 at all times.
|
||||
//dot 322 range = { 1288, 1290, 1292 }
|
||||
//dot 326 range = { 1306, 1308, 1310 }
|
||||
//dot 323 range = { 1292, 1294, 1296 }
|
||||
//dot 327 range = { 1310, 1312, 1314 }
|
||||
uint16 bCPU::get_hcounter() {
|
||||
if(time.v == 240 && time.interlace == false && time.interlace_field == 1) {
|
||||
return time.hc >> 2;
|
||||
}
|
||||
return (time.hc - ((time.hc > 1288) << 1) - ((time.hc > 1306) << 1)) >> 2;
|
||||
return (time.hc - ((time.hc > 1292) << 1) - ((time.hc > 1310) << 1)) >> 2;
|
||||
}
|
||||
|
||||
void bCPU::apu_sync() {
|
||||
int cycles;
|
||||
while(apusync.cycles >= 0) {
|
||||
apu->run();
|
||||
uint32 bCPU::cycles_executed() {
|
||||
uint32 r = status.cycles_executed;
|
||||
status.cycles_executed = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
cycles = apu->cycles_executed();
|
||||
if(cycles) {
|
||||
apusync.cycles -= apusync.cpu_multbl[cycles];
|
||||
void bCPU::cycle_edge() {
|
||||
if(time.hdmainit_triggered == false) {
|
||||
if(time.hc >= time.hdmainit_trigger_pos || time.v) {
|
||||
time.hdmainit_triggered = true;
|
||||
hdmainit_activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::dram_refresh() {
|
||||
time.dram_refreshed = true;
|
||||
add_cycles(40);
|
||||
if(time.v != 240 || time.interlace != false || time.interlace_field != 1) {
|
||||
//alternate between 534 and 538 every scanline except 240ni1
|
||||
time.dram_refresh_pos ^= 12;
|
||||
if(time.hdma_triggered == false) {
|
||||
if(time.v <= (overscan() ? 239 : 224)) {
|
||||
if(time.hc >= 1106) {
|
||||
time.hdma_triggered = true;
|
||||
hdma_activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::add_cycles(int cycles) {
|
||||
cycles >>= 1;
|
||||
while(cycles--) {
|
||||
apusync.cycles += apusync.apu_freq << 1;
|
||||
apu_sync();
|
||||
time.hc += 2;
|
||||
status.cycles_executed += cycles;
|
||||
|
||||
if(time.hc >= time.line_cycles) {
|
||||
inc_vcounter();
|
||||
if(time.v == 0) {
|
||||
frame();
|
||||
ppu->frame();
|
||||
poll_interrupts(cycles);
|
||||
|
||||
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();
|
||||
r_ppu->frame();
|
||||
snes->frame();
|
||||
}
|
||||
|
||||
scanline();
|
||||
r_ppu->scanline();
|
||||
snes->scanline();
|
||||
time.line_rendered = false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
scanline();
|
||||
ppu->scanline();
|
||||
}
|
||||
|
||||
if(time.dram_refreshed == false && time.hc >= time.dram_refresh_pos) {
|
||||
dram_refresh();
|
||||
}
|
||||
|
||||
if(hdma_test() == true) {
|
||||
hdma_run();
|
||||
}
|
||||
}
|
||||
|
||||
if(time.line_rendered == false) {
|
||||
//rendering should start at H=18 (+256=274), but since the
|
||||
//current PPU emulation renders the entire scanline at once,
|
||||
//PPU register changes mid-scanline do not show up.
|
||||
//therefore, wait a few dots before rendering the scanline
|
||||
if(time.hc + cycles >= (48 * 4)) {
|
||||
time.line_rendered = true;
|
||||
r_ppu->render_scanline();
|
||||
}
|
||||
}
|
||||
|
||||
time.hc += cycles;
|
||||
}
|
||||
|
||||
void bCPU::time_reset() {
|
||||
//initial latch values for $213c/$213d
|
||||
//[x]0035 : [y]0000 (53.0 -> 212) [lda $2137]
|
||||
//[x]0038 : [y]0000 (56.5 -> 226) [nop : lda $2137]
|
||||
time.v = 0;
|
||||
time.hc = 186;
|
||||
time.hc = 0;
|
||||
|
||||
//upon SNES reset, start at scanline 0 non-interlace
|
||||
time.interlace = false;
|
||||
time.interlace_field = false;
|
||||
time.overscan = false;
|
||||
time.line_cycles = 1364;
|
||||
time.frame_lines = 262;
|
||||
|
||||
time.dram_refreshed = false;
|
||||
time.dram_refresh_pos = 538;
|
||||
time.dram_refresh_pos = (cpu_version == 2) ? 538 : 530;
|
||||
|
||||
time.dma_counter = 0;
|
||||
|
||||
apusync.cycles = apusync.cpu_multbl[255];
|
||||
}
|
||||
//set at V=0,H=0
|
||||
time.hdmainit_trigger_pos = 0;
|
||||
time.hdmainit_triggered = true;
|
||||
|
||||
void bCPU::time_init() {
|
||||
apusync.cpu_freq = 21477272 >> 3;
|
||||
apusync.apu_freq = 24576000 >> 3;
|
||||
time.hdma_triggered = false;
|
||||
|
||||
int i;
|
||||
for(i=0;i<1024;i++) {
|
||||
apusync.cpu_multbl[i] = i * apusync.cpu_freq;
|
||||
apusync.apu_multbl[i] = i * apusync.apu_freq;
|
||||
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;
|
||||
break;
|
||||
case PAL:
|
||||
time.region_scanlines = 312;
|
||||
break;
|
||||
}
|
||||
|
||||
time.frame_lines = time.region_scanlines;
|
||||
}
|
||||
+47
-11
@@ -4,11 +4,47 @@ struct {
|
||||
bool interlace, interlace_field, overscan;
|
||||
uint16 line_cycles, frame_lines;
|
||||
|
||||
bool line_rendered;
|
||||
|
||||
bool dram_refreshed;
|
||||
uint16 dram_refresh_pos;
|
||||
|
||||
uint8 dma_counter;
|
||||
}time;
|
||||
|
||||
uint16 hdmainit_trigger_pos;
|
||||
bool hdmainit_triggered;
|
||||
|
||||
bool hdma_triggered;
|
||||
|
||||
uint16 region_scanlines;
|
||||
|
||||
//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();
|
||||
@@ -16,6 +52,15 @@ inline uint16 hcycles();
|
||||
inline bool interlace();
|
||||
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);
|
||||
@@ -24,15 +69,6 @@ inline uint8 dma_counter();
|
||||
|
||||
inline void inc_vcounter();
|
||||
inline uint16 get_hcounter();
|
||||
inline void apu_sync();
|
||||
inline void dram_refresh();
|
||||
inline void cycle_edge();
|
||||
inline void add_cycles(int cycles);
|
||||
inline void time_reset();
|
||||
inline void time_init();
|
||||
|
||||
//APU synchronization
|
||||
struct {
|
||||
int32 cpu_freq, apu_freq;
|
||||
int32 cpu_multbl[1024], apu_multbl[1024];
|
||||
int32 cycles;
|
||||
}apusync;
|
||||
+16
-10
@@ -44,7 +44,7 @@ char t[4096];
|
||||
i++;
|
||||
}
|
||||
|
||||
sprintf(output_op, "void bCPU::op_$$() {\r\n");
|
||||
sprintf(output_op, "void bCPU::op_$$() {\r\n switch(status.cycle_pos++) {\r\n");
|
||||
sprintf(output_header, "void op_$$();\r\n");
|
||||
sprintf(output_table, "optbl[$0] = &bCPU::op_$$;\r\n");
|
||||
|
||||
@@ -53,9 +53,8 @@ char t[4096];
|
||||
|
||||
void update_line(int i, int n) {
|
||||
char t[4096];
|
||||
sprintf(t, "goto l%d;", n + 2);
|
||||
replace(line[i], "end;", "return;");
|
||||
replace(line[i], "skip;", t);
|
||||
replace(line[i], "end;", "status.cycle_pos = 0;");
|
||||
replace(line[i], "skip;", "status.cycle_pos++;");
|
||||
}
|
||||
|
||||
void gen_op() {
|
||||
@@ -67,12 +66,12 @@ char t[4096];
|
||||
n = strdec(line[i]);
|
||||
sprintf(t, "%d:", n);
|
||||
strltrim(line[i], t);
|
||||
sprintf(t, "l%d:\r\n", n);
|
||||
sprintf(t, " case %d:\r\n", n);
|
||||
strcat(output_op, t);
|
||||
|
||||
update_line(i, n);
|
||||
if(strcmp(line[i], "")) {
|
||||
strcat(output_op, " ");
|
||||
strcat(output_op, " ");
|
||||
strcat(output_op, line[i]);
|
||||
strcat(output_op, "\r\n");
|
||||
}
|
||||
@@ -82,13 +81,20 @@ char t[4096];
|
||||
if((strptr(line[i])[1]) == ':' || !strcmp(line[i], "}"))break;
|
||||
|
||||
update_line(i, n);
|
||||
strcat(output_op, " ");
|
||||
strcat(output_op, line[i]);
|
||||
strcat(output_op, "\r\n");
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if(!strcmp(line[i], "}")) {
|
||||
strcat(output_op, " status.cycle_pos = 0;\r\n");
|
||||
}
|
||||
|
||||
strcat(output_op, " break;\r\n");
|
||||
}
|
||||
strcat(output_op, "}");
|
||||
strcat(output_op, " }\r\n}");
|
||||
|
||||
line_num = i + 1;
|
||||
}
|
||||
@@ -107,16 +113,16 @@ int i, l;
|
||||
replace(t, "$5", op_list[i].arg[5]);
|
||||
replace(t, "$6", op_list[i].arg[6]);
|
||||
replace(t, "$7", op_list[i].arg[7]);
|
||||
fprintf(fp, "%s\r\n\r\n", *t);
|
||||
fprintf(fp, "%s\r\n\r\n", strptr(t));
|
||||
|
||||
strcpy(t, output_header);
|
||||
replace(t, "$$", op_list[i].name);
|
||||
fprintf(fph, "%s", *t);
|
||||
fprintf(fph, "%s", strptr(t));
|
||||
|
||||
strcpy(t, output_table);
|
||||
replace(t, "$$", op_list[i].name);
|
||||
replace(t, "$0", op_list[i].arg[0]);
|
||||
fprintf(fpt, "%s", *t);
|
||||
fprintf(fpt, "%s", strptr(t));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
+58
-30
@@ -1,15 +1,17 @@
|
||||
nop(0xea) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
}
|
||||
|
||||
wdm(0x42) {
|
||||
1:cpu_io();
|
||||
regs.pc.w++;
|
||||
1:last_cycle();
|
||||
op_read();
|
||||
}
|
||||
|
||||
xba(0xeb) {
|
||||
1:cpu_io();
|
||||
2:cpu_io();
|
||||
2:last_cycle();
|
||||
cpu_io();
|
||||
regs.a.l ^= regs.a.h;
|
||||
regs.a.h ^= regs.a.l;
|
||||
regs.a.l ^= regs.a.h;
|
||||
@@ -27,7 +29,8 @@ mvp(0x44, --) {
|
||||
5:cpu_io();
|
||||
if(regs.p.x) { regs.x.l$1; regs.y.l$1; }
|
||||
else { regs.x.w$1; regs.y.w$1; }
|
||||
6:cpu_io();
|
||||
6:last_cycle();
|
||||
cpu_io();
|
||||
if(regs.a.w--)regs.pc.w -= 3;
|
||||
}
|
||||
|
||||
@@ -40,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,20 +53,26 @@ cop(0x02, 0xfff4, 0xfff5, 0xffe4, 0xffe5) {
|
||||
|
||||
stp(0xdb) {
|
||||
1:cpu_io();
|
||||
status.cpu_state = CPUSTATE_STP;
|
||||
2:cpu_io();
|
||||
run_state.stp = true;
|
||||
2:last_cycle();
|
||||
cpu_io();
|
||||
regs.pc.w--;
|
||||
}
|
||||
|
||||
wai(0xcb) {
|
||||
1:cpu_io();
|
||||
status.cpu_state = CPUSTATE_WAI;
|
||||
2:cpu_io();
|
||||
regs.pc.w--;
|
||||
run_state.wai = true;
|
||||
2:last_cycle();
|
||||
cpu_io();
|
||||
if(run_state.wai) {
|
||||
//this can be cleared within last_cycle()
|
||||
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;
|
||||
@@ -81,14 +91,16 @@ clv(0xb8, regs.p.v = 0),
|
||||
sec(0x38, regs.p.c = 1),
|
||||
sed(0xf8, regs.p.d = 1),
|
||||
sei(0x78, regs.p.i = 1) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
$1;
|
||||
}
|
||||
|
||||
rep(0xc2, &=~),
|
||||
sep(0xe2, |=) {
|
||||
1:rd.l = op_read();
|
||||
2:cpu_io();
|
||||
2:last_cycle();
|
||||
cpu_io();
|
||||
regs.p $1 rd.l;
|
||||
if(regs.e)regs.p |= 0x30;
|
||||
if(regs.p.x) {
|
||||
@@ -103,7 +115,8 @@ txa(0x8a, regs.p.m, a, x),
|
||||
txy(0x9b, regs.p.x, y, x),
|
||||
tya(0x98, regs.p.m, a, y),
|
||||
tyx(0xbb, regs.p.x, x, y) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
if($1) {
|
||||
regs.$2.l = regs.$3.l;
|
||||
regs.p.n = !!(regs.$2.l & 0x80);
|
||||
@@ -116,27 +129,31 @@ tyx(0xbb, regs.p.x, x, y) {
|
||||
}
|
||||
|
||||
tcd(0x5b) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
regs.d.w = regs.a.w;
|
||||
regs.p.n = !!(regs.d.w & 0x8000);
|
||||
regs.p.z = (regs.d.w == 0);
|
||||
}
|
||||
|
||||
tcs(0x1b) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
regs.s.w = regs.a.w;
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
}
|
||||
|
||||
tdc(0x7b) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
regs.a.w = regs.d.w;
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
|
||||
tsc(0x3b) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
regs.a.w = regs.s.w;
|
||||
if(regs.e) {
|
||||
regs.p.n = !!(regs.a.l & 0x80);
|
||||
@@ -148,7 +165,8 @@ tsc(0x3b) {
|
||||
}
|
||||
|
||||
tsx(0xba) {
|
||||
1:cpu_io();
|
||||
1:last_cycle();
|
||||
cpu_io();
|
||||
if(regs.p.x) {
|
||||
regs.x.l = regs.s.l;
|
||||
regs.p.n = !!(regs.x.l & 0x80);
|
||||
@@ -161,7 +179,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);
|
||||
@@ -180,14 +199,16 @@ phd(0x0b, 0, d) {
|
||||
1:cpu_io();
|
||||
if($1)skip;
|
||||
2:stack_write(regs.$2.h);
|
||||
3:stack_write(regs.$2.l);
|
||||
3:last_cycle();
|
||||
stack_write(regs.$2.l);
|
||||
}
|
||||
|
||||
phb(0x8b, regs.db),
|
||||
phk(0x4b, regs.pc.b),
|
||||
php(0x08, regs.p) {
|
||||
1:cpu_io();
|
||||
2:stack_write($1);
|
||||
2:last_cycle();
|
||||
stack_write($1);
|
||||
}
|
||||
|
||||
pla(0x68, regs.p.m, a),
|
||||
@@ -196,13 +217,15 @@ ply(0x7a, regs.p.x, y),
|
||||
pld(0x2b, 0, d) {
|
||||
1:cpu_io();
|
||||
2:cpu_io();
|
||||
3:regs.$2.l = stack_read();
|
||||
3:if($1)last_cycle();
|
||||
regs.$2.l = stack_read();
|
||||
if($1) {
|
||||
regs.p.n = !!(regs.$2.l & 0x80);
|
||||
regs.p.z = (regs.$2.l == 0);
|
||||
end;
|
||||
}
|
||||
4:regs.$2.h = stack_read();
|
||||
4:last_cycle();
|
||||
regs.$2.h = stack_read();
|
||||
regs.p.n = !!(regs.$2.w & 0x8000);
|
||||
regs.p.z = (regs.$2.w == 0);
|
||||
}
|
||||
@@ -210,7 +233,8 @@ pld(0x2b, 0, d) {
|
||||
plb(0xab) {
|
||||
1:cpu_io();
|
||||
2:cpu_io();
|
||||
3:regs.db = stack_read();
|
||||
3:last_cycle();
|
||||
regs.db = stack_read();
|
||||
regs.p.n = !!(regs.db & 0x80);
|
||||
regs.p.z = (regs.db == 0);
|
||||
}
|
||||
@@ -218,7 +242,8 @@ plb(0xab) {
|
||||
plp(0x28) {
|
||||
1:cpu_io();
|
||||
2:cpu_io();
|
||||
3:regs.p = stack_read();
|
||||
3:last_cycle();
|
||||
regs.p = stack_read();
|
||||
if(regs.e)regs.p |= 0x30;
|
||||
if(regs.p.x) {
|
||||
regs.x.h = 0x00;
|
||||
@@ -230,7 +255,8 @@ pea(0xf4) {
|
||||
1:aa.l = op_read();
|
||||
2:aa.h = op_read();
|
||||
3:stack_write(aa.h);
|
||||
4:stack_write(aa.l);
|
||||
4:last_cycle();
|
||||
stack_write(aa.l);
|
||||
}
|
||||
|
||||
pei(0xd4) {
|
||||
@@ -239,7 +265,8 @@ pei(0xd4) {
|
||||
3:aa.l = op_read(OPMODE_DP, dp);
|
||||
4:aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
5:stack_write(aa.h);
|
||||
6:stack_write(aa.l);
|
||||
6:last_cycle();
|
||||
stack_write(aa.l);
|
||||
}
|
||||
|
||||
per(0x62) {
|
||||
@@ -248,5 +275,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);
|
||||
}
|
||||
+37
-15
@@ -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++;
|
||||
}
|
||||
+68
-34
@@ -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);
|
||||
}
|
||||
+20
-10
@@ -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);
|
||||
}
|
||||
+60
-30
@@ -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 = 1;
|
||||
mmio = &mmio_unmapped;
|
||||
}
|
||||
+32
-22
@@ -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,7 @@ public:
|
||||
virtual bool interlace() = 0;
|
||||
virtual bool interlace_field() = 0;
|
||||
virtual bool overscan() = 0;
|
||||
|
||||
virtual uint16 region_scanlines() = 0;
|
||||
virtual void set_interlace(bool r) = 0;
|
||||
virtual void set_overscan (bool r) = 0;
|
||||
|
||||
@@ -26,33 +32,37 @@ CPURegs regs;
|
||||
};
|
||||
virtual uint8 pio_status() = 0;
|
||||
virtual void run() = 0;
|
||||
virtual uint32 cycles_executed() = 0;
|
||||
virtual void scanline() = 0;
|
||||
virtual void frame() = 0;
|
||||
virtual void power() = 0;
|
||||
virtual void reset() = 0;
|
||||
|
||||
//opcode disassembler
|
||||
enum {
|
||||
OPTYPE_DP = 0, //dp
|
||||
OPTYPE_DPX, //dp,x
|
||||
OPTYPE_DPY, //dp,y
|
||||
OPTYPE_IDP, //(dp)
|
||||
OPTYPE_IDPX, //(dp,x)
|
||||
OPTYPE_IDPY, //(dp),y
|
||||
OPTYPE_ILDP, //[dp]
|
||||
OPTYPE_ILDPY, //[dp],y
|
||||
OPTYPE_ADDR, //addr
|
||||
OPTYPE_ADDRX, //addr,x
|
||||
OPTYPE_ADDRY, //addr,y
|
||||
OPTYPE_IADDRX, //(addr,x)
|
||||
OPTYPE_ILADDR, //[addr]
|
||||
OPTYPE_LONG, //long
|
||||
OPTYPE_LONGX, //long, x
|
||||
OPTYPE_SR, //sr,s
|
||||
OPTYPE_ISRY, //(sr,s),y
|
||||
OPTYPE_ADDR_PC, //pbr:addr
|
||||
OPTYPE_IADDR_PC //pbr:(addr)
|
||||
};
|
||||
enum {
|
||||
OPTYPE_DP = 0, //dp
|
||||
OPTYPE_DPX, //dp,x
|
||||
OPTYPE_DPY, //dp,y
|
||||
OPTYPE_IDP, //(dp)
|
||||
OPTYPE_IDPX, //(dp,x)
|
||||
OPTYPE_IDPY, //(dp),y
|
||||
OPTYPE_ILDP, //[dp]
|
||||
OPTYPE_ILDPY, //[dp],y
|
||||
OPTYPE_ADDR, //addr
|
||||
OPTYPE_ADDRX, //addr,x
|
||||
OPTYPE_ADDRY, //addr,y
|
||||
OPTYPE_IADDRX, //(addr,x)
|
||||
OPTYPE_ILADDR, //[addr]
|
||||
OPTYPE_LONG, //long
|
||||
OPTYPE_LONGX, //long, x
|
||||
OPTYPE_SR, //sr,s
|
||||
OPTYPE_ISRY, //(sr,s),y
|
||||
OPTYPE_ADDR_PC, //pbr:addr
|
||||
OPTYPE_IADDR_PC //pbr:(addr)
|
||||
};
|
||||
//see dcpu.cpp for notes on this function
|
||||
virtual bool in_opcode();
|
||||
|
||||
void disassemble_opcode(char *output);
|
||||
uint32 resolve_offset(uint8 offset_type, uint32 addr);
|
||||
uint8 opcode_length();
|
||||
|
||||
+19
-9
@@ -13,7 +13,7 @@ private:
|
||||
inline bool operator ^= (bool i) { if(i)_b ^= B; return (_b & B); }
|
||||
};
|
||||
public:
|
||||
union {
|
||||
union {
|
||||
uint8 _b;
|
||||
bit<0x80> n;
|
||||
bit<0x40> v;
|
||||
@@ -23,7 +23,7 @@ public:
|
||||
bit<0x04> i;
|
||||
bit<0x02> z;
|
||||
bit<0x01> c;
|
||||
};
|
||||
};
|
||||
|
||||
CPURegFlags() { _b = 0; }
|
||||
inline operator uint8() { return _b; }
|
||||
@@ -35,10 +35,14 @@ public:
|
||||
|
||||
class CPUReg16 {
|
||||
public:
|
||||
union {
|
||||
union {
|
||||
uint16 w;
|
||||
#ifdef ARCH_LSB
|
||||
struct { uint8 l, h; };
|
||||
};
|
||||
#else
|
||||
struct { uint8 h, l; };
|
||||
#endif
|
||||
};
|
||||
|
||||
CPUReg16() { w = 0; }
|
||||
inline operator uint16() { return w; }
|
||||
@@ -56,11 +60,16 @@ public:
|
||||
|
||||
class CPUReg24 {
|
||||
public:
|
||||
union {
|
||||
uint16 w;
|
||||
union {
|
||||
uint32 d;
|
||||
struct { uint8 l, h, b; };
|
||||
};
|
||||
#ifdef ARCH_LSB
|
||||
struct { uint16 w, null_w; };
|
||||
struct { uint8 l, h, b, null_b; };
|
||||
#else
|
||||
struct { uint16 null_w, w; };
|
||||
struct { uint8 null_b, b, h, l; };
|
||||
#endif
|
||||
};
|
||||
|
||||
CPUReg24() { d = 0; }
|
||||
inline operator uint32() { return (d & 0xffffff); }
|
||||
@@ -82,6 +91,7 @@ CPUReg24 pc;
|
||||
CPUReg16 a, x, y, s, d;
|
||||
CPURegFlags p;
|
||||
uint8 db;
|
||||
uint8 mdr; //memory data register (openbus)
|
||||
bool e;
|
||||
CPURegs() { db = 0; e = false; }
|
||||
CPURegs() { db = 0; mdr = 0x00; e = false; }
|
||||
};
|
||||
+40
-14
@@ -1,3 +1,17 @@
|
||||
//this is a virtual function.
|
||||
//in opcode-based CPU emulators, the main emulation routine
|
||||
//will only be able to call the disassemble_opcode() function
|
||||
//on clean opcode edges. but with cycle-based CPU emulators,
|
||||
//the CPU may be in the middle of executing an opcode when the
|
||||
//emulator (e.g. debugger) wants to disassemble an opcode. this
|
||||
//would mean that important registers may not reflect what they
|
||||
//did at the start of the opcode (especially regs.pc), so in
|
||||
//cycle-based emulators, this function should be overridden to
|
||||
//reflect whether or not an opcode has only been partially
|
||||
//executed. if not, the debugger should abort attempts to skip,
|
||||
//disable, or disassemble the current opcode.
|
||||
bool CPU::in_opcode() { return false; }
|
||||
|
||||
uint16 CPU::__relb(int8 offset) {
|
||||
uint32 addr;
|
||||
addr = (regs.pc.d & 0xff0000) | ((regs.pc.d + 2) & 0xffff);
|
||||
@@ -24,23 +38,23 @@ uint32 r = 0;
|
||||
break;
|
||||
case OPTYPE_IDP:
|
||||
addr = (regs.d + (addr & 0xffff)) & 0xffff;
|
||||
r = (regs.db << 16) + mem_bus->read_word(addr);
|
||||
r = (regs.db << 16) + r_mem->read_word(addr);
|
||||
break;
|
||||
case OPTYPE_IDPX:
|
||||
addr = (regs.d + regs.x + (addr & 0xffff)) & 0xffff;
|
||||
r = (regs.db << 16) + mem_bus->read_word(addr);
|
||||
r = (regs.db << 16) + r_mem->read_word(addr);
|
||||
break;
|
||||
case OPTYPE_IDPY:
|
||||
addr = (regs.d + (addr & 0xffff)) & 0xffff;
|
||||
r = (regs.db << 16) + mem_bus->read_word(addr) + regs.y;
|
||||
r = (regs.db << 16) + r_mem->read_word(addr) + regs.y;
|
||||
break;
|
||||
case OPTYPE_ILDP:
|
||||
addr = (regs.d + (addr & 0xffff)) & 0xffff;
|
||||
r = mem_bus->read_long(addr);
|
||||
r = r_mem->read_long(addr);
|
||||
break;
|
||||
case OPTYPE_ILDPY:
|
||||
addr = (regs.d + (addr & 0xffff)) & 0xffff;
|
||||
r = mem_bus->read_long(addr) + regs.y;
|
||||
r = r_mem->read_long(addr) + regs.y;
|
||||
break;
|
||||
case OPTYPE_ADDR:
|
||||
r = (regs.db << 16) + (addr & 0xffff);
|
||||
@@ -74,23 +88,31 @@ uint32 r = 0;
|
||||
break;
|
||||
case OPTYPE_ISRY:
|
||||
addr = (regs.s + (addr & 0xff)) & 0xffff;
|
||||
r = (regs.db << 16) + mem_bus->read_word(addr) + regs.y;
|
||||
r = (regs.db << 16) + r_mem->read_word(addr) + regs.y;
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void CPU::disassemble_opcode(char *output) {
|
||||
char *s = output;
|
||||
char *s;
|
||||
char t[256];
|
||||
uint8 op, op0, op1, op2;
|
||||
sprintf(s, "%0.6x ", regs.pc.d);
|
||||
static CPUReg24 pc;
|
||||
s = output;
|
||||
|
||||
//TODO: This should wrap around the bank byte
|
||||
op = mem_bus->read(regs.pc.d);
|
||||
op0 = mem_bus->read(regs.pc.d + 1);
|
||||
op1 = mem_bus->read(regs.pc.d + 2);
|
||||
op2 = mem_bus->read(regs.pc.d + 3);
|
||||
if(in_opcode() == true) {
|
||||
strcpy(s, "?????? <CPU within opcode>");
|
||||
return;
|
||||
}
|
||||
|
||||
pc.d = regs.pc.d;
|
||||
sprintf(s, "%0.6x ", pc.d);
|
||||
|
||||
op = r_mem->read(pc.d); pc.w++;
|
||||
op0 = r_mem->read(pc.d); pc.w++;
|
||||
op1 = r_mem->read(pc.d); pc.w++;
|
||||
op2 = r_mem->read(pc.d);
|
||||
|
||||
switch(op) {
|
||||
case 0x00:sprintf(t, "brk #$%0.2x ", op0);break;
|
||||
@@ -431,7 +453,11 @@ static uint8 op_len_tbl[256] = {
|
||||
6,2,2,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0xen
|
||||
2,2,2,2, 3,2,2,2, 1,3,1,1, 3,3,3,4 //0xfn
|
||||
};
|
||||
op = mem_bus->read(regs.pc.d);
|
||||
if(in_opcode() == true) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
op = r_mem->read(regs.pc.d);
|
||||
len = op_len_tbl[op];
|
||||
if(len == 5)return (regs.p.m)?2:3;
|
||||
if(len == 6)return (regs.p.x)?2:3;
|
||||
|
||||
@@ -0,0 +1,586 @@
|
||||
#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 = r_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++) {
|
||||
uint8 mask = 1 << v;
|
||||
if(status.soft_reset()) {
|
||||
if(voice[v].env_state != SILENCE) {
|
||||
voice[v].env_state = SILENCE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
} else if(status.KOFF & mask) {
|
||||
if(voice[v].env_state != SILENCE && voice[v].env_state != RELEASE) {
|
||||
voice[v].env_state = RELEASE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
} else if(status.KON & mask) { //status.kon
|
||||
status.KON &= ~mask; //new code
|
||||
status.ENDX &= ~mask; //new code
|
||||
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;
|
||||
};
|
||||
+62
-11
@@ -1,30 +1,81 @@
|
||||
#define BSNES_VERSION "0.014"
|
||||
#define BSNES_TITLE "bsnes v" BSNES_VERSION
|
||||
|
||||
#ifdef POLYMORPHISM
|
||||
#define ref(x) x
|
||||
#else
|
||||
#define ref(x) (&x)
|
||||
#endif
|
||||
#define deref(x) __##x
|
||||
|
||||
#define r_mem ref(deref(mem))
|
||||
#define r_cpu ref(deref(cpu))
|
||||
#define r_apu ref(deref(apu))
|
||||
#define r_dsp ref(deref(dsp))
|
||||
#define r_ppu ref(deref(ppu))
|
||||
|
||||
#include "reader/reader.h"
|
||||
|
||||
#include "memory/memory.h"
|
||||
#include "memory/bmemory/bmemory.h"
|
||||
extern MMIO mmio_unmapped;
|
||||
extern MemBus *mem_bus;
|
||||
|
||||
#include "cpu/cpu.h"
|
||||
#include "cpu/bcpu/bcpu.h"
|
||||
extern CPU *cpu;
|
||||
|
||||
#include "apu/apu.h"
|
||||
#include "apu/bapu/bapu.h"
|
||||
#include "apu/bapuskip/bapuskip.h"
|
||||
extern APU *apu;
|
||||
|
||||
#include "dsp/dsp.h"
|
||||
#include "dsp/bdsp/bdsp.h"
|
||||
|
||||
#include "ppu/ppu.h"
|
||||
#include "ppu/bppu/bppu.h"
|
||||
extern PPU *ppu;
|
||||
|
||||
#include "snes/snes.h"
|
||||
|
||||
#include "chip/srtc/srtc.h"
|
||||
#include "chip/sdd1/sdd1.h"
|
||||
|
||||
extern MMIO mmio_unmapped;
|
||||
#ifdef POLYMORPHISM
|
||||
extern MemBus *deref(mem);
|
||||
extern CPU *deref(cpu);
|
||||
extern APU *deref(apu);
|
||||
extern DSP *deref(dsp);
|
||||
extern PPU *deref(ppu);
|
||||
#else
|
||||
extern bMemBus deref(mem);
|
||||
extern bCPU deref(cpu);
|
||||
extern bAPU deref(apu);
|
||||
extern bDSP deref(dsp);
|
||||
extern bPPU deref(ppu);
|
||||
#endif
|
||||
extern SNES *snes;
|
||||
|
||||
extern SRTC *srtc;
|
||||
extern SDD1 *sdd1;
|
||||
|
||||
#include "config/config.h"
|
||||
|
||||
#ifdef INTERFACE_MAIN
|
||||
MemBus *mem_bus;
|
||||
CPU *cpu;
|
||||
APU *apu;
|
||||
PPU *ppu;
|
||||
SNES *snes;
|
||||
|
||||
#include "config/config.cpp"
|
||||
#ifdef POLYMORPHISM
|
||||
MemBus *deref(mem);
|
||||
CPU *deref(cpu);
|
||||
APU *deref(apu);
|
||||
DSP *deref(dsp);
|
||||
PPU *deref(ppu);
|
||||
#else
|
||||
bMemBus deref(mem);
|
||||
bCPU deref(cpu);
|
||||
bAPU deref(apu);
|
||||
bDSP deref(dsp);
|
||||
bPPU deref(ppu);
|
||||
#endif
|
||||
SNES *snes;
|
||||
|
||||
SRTC *srtc;
|
||||
SDD1 *sdd1;
|
||||
|
||||
#endif
|
||||
+14
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
libbase : version 0.01 ~byuu
|
||||
libbase : version 0.03 ~byuu (08/20/05)
|
||||
*/
|
||||
|
||||
#ifndef __LIBBASE
|
||||
@@ -10,10 +10,23 @@
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define zerofree(__n) if(__n) { free(__n); __n = 0; }
|
||||
|
||||
typedef unsigned int uint;
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short word;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
typedef unsigned char bool8;
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned long uint32;
|
||||
|
||||
+113
-270
@@ -1,317 +1,160 @@
|
||||
#include "libbase.h"
|
||||
#include "libconfig.h"
|
||||
|
||||
//if this function returns true, the option is written
|
||||
//to the configuration file. by always returning true,
|
||||
//every option is always written. disable the first line
|
||||
//to only output options after they have been changed by
|
||||
//the program from their default values first.
|
||||
bool config_item::changed() {
|
||||
return true;
|
||||
void Setting::toggle() {
|
||||
data ^= 1;
|
||||
set(data);
|
||||
}
|
||||
|
||||
if(is_string == true) {
|
||||
if(!strcmp(*strsource, strdef))return false;
|
||||
return true;
|
||||
uint Setting::get() {
|
||||
return data;
|
||||
}
|
||||
|
||||
void Setting::set(uint _data) {
|
||||
data = _data;
|
||||
|
||||
if(type != DEC && type != HEX) {
|
||||
//data is a boolean type
|
||||
data &= 1;
|
||||
}
|
||||
return (*source != def);
|
||||
}
|
||||
|
||||
config_item::config_item() {
|
||||
strcpy(name, "");
|
||||
strcpy(strdef, "");
|
||||
is_string = false;
|
||||
source = 0;
|
||||
strsource = 0;
|
||||
def = 0;
|
||||
type = 0;
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
void config::add(string *variable, char *name, char *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 = 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;
|
||||
}
|
||||
Setting::Setting(Config *_parent, char *_name, char *_desc, uint _data, uint _type) {
|
||||
int s;
|
||||
if(_parent) {
|
||||
_parent->add(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
uint32 config::get(char *name) {
|
||||
int i = find(name);
|
||||
if(i == null)return 0;
|
||||
return *item[i]->source;
|
||||
}
|
||||
s = strlen(_name);
|
||||
name = (char*)malloc(s + 1);
|
||||
strcpy(name, _name);
|
||||
|
||||
string &config::strget(char *name) {
|
||||
int i = find(name);
|
||||
if(i == null) {
|
||||
static string not_found;
|
||||
strcmp(not_found, "");
|
||||
return not_found;
|
||||
if(_desc) {
|
||||
s = strlen(_desc);
|
||||
desc = (char*)malloc(s + 1);
|
||||
strcpy(desc, _desc);
|
||||
} else {
|
||||
desc = (char*)malloc(1);
|
||||
*desc = 0;
|
||||
}
|
||||
return *item[i]->strsource;
|
||||
|
||||
data = _data;
|
||||
def = _data;
|
||||
type = _type;
|
||||
}
|
||||
|
||||
void config::set(char *name, uint32 value) {
|
||||
int i = find(name);
|
||||
if(i == null)return;
|
||||
*item[i]->source = value;
|
||||
void Config::add(Setting *setting) {
|
||||
list[list_count++] = setting;
|
||||
}
|
||||
|
||||
void config::set(char *name, char *value) {
|
||||
int i = find(name);
|
||||
if(i == null)return;
|
||||
strcpy(*item[i]->strsource, value);
|
||||
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);
|
||||
}
|
||||
|
||||
void config::load(char *fn) {
|
||||
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(strqpos(line[i], "#") != null) {
|
||||
strset(line[i], strqpos(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(*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(*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])));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//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(strqpos(line[i], "#") != null) {
|
||||
strset(line[i], strqpos(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(*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(strqpos(oldline[i], "#") != null) {
|
||||
strcat(newline, " ");
|
||||
strcat(newline, *oldline[i] + strqpos(oldline[i], "#"));
|
||||
}
|
||||
|
||||
strcpy(line[i], newline);
|
||||
}
|
||||
|
||||
//write out the old config file + changes first
|
||||
for(i=0;i<count(line);) {
|
||||
fprintf(fp, "%s", *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;
|
||||
//...or if it is still set to the default value,
|
||||
//then don't output it to the file here
|
||||
if(item[i]->changed() == false)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", *newline);
|
||||
lines_written++;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
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;
|
||||
}
|
||||
+81
-34
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
libconfig : version 0.02 ~byuu
|
||||
libconfig : version 0.05 ~byuu (09/13/05)
|
||||
*/
|
||||
|
||||
#ifndef __LIBCONFIG
|
||||
@@ -7,45 +7,92 @@
|
||||
|
||||
#include "libstring.h"
|
||||
|
||||
class config_item {
|
||||
public:
|
||||
uint32 *source, def, type;
|
||||
string *strsource, strdef;
|
||||
bool is_string;
|
||||
string name;
|
||||
bool changed();
|
||||
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);
|
||||
uint32 get(char *name);
|
||||
string &strget(char *name);
|
||||
void set(char *name, uint32 value);
|
||||
void set(char *name, char *value);
|
||||
char *name, *desc;
|
||||
virtual void toggle();
|
||||
virtual uint get();
|
||||
virtual void set(uint _data);
|
||||
|
||||
void load(char *fn);
|
||||
void save(char *fn);
|
||||
void set_newline(int i);
|
||||
Setting(Config *_parent, char *_name, char *_desc = 0, uint _data = 0, uint _type = DEC);
|
||||
|
||||
config();
|
||||
~config();
|
||||
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
|
||||
+126
-78
@@ -1,23 +1,26 @@
|
||||
#include "libbase.h"
|
||||
#include "libstring.h"
|
||||
|
||||
_string::_string() {
|
||||
substring::substring() {
|
||||
size = 16;
|
||||
s = (char*)malloc(size + 1);
|
||||
*s = 0;
|
||||
}
|
||||
|
||||
_string::~_string() {
|
||||
free(s);
|
||||
}
|
||||
|
||||
void string::addto(uint32 num) {
|
||||
while(listcount < (num + 1)) {
|
||||
list[listcount++] = new _string();
|
||||
substring::~substring() {
|
||||
if(s) {
|
||||
free(s);
|
||||
s = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_string &string::str(uint32 num) {
|
||||
void string::addto(uint num) {
|
||||
while(listcount < (num + 1)) {
|
||||
list[listcount++] = new substring();
|
||||
}
|
||||
}
|
||||
|
||||
substring &string::str(uint num) {
|
||||
if(listcount < (num + 1)) { addto(num); }
|
||||
return *list[num];
|
||||
}
|
||||
@@ -31,60 +34,68 @@ string::string() {
|
||||
string::~string() {
|
||||
int i;
|
||||
for(i=listcount-1;i>=0;i--) {
|
||||
delete((_string*)list[i]);
|
||||
delete((substring*)list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 count(string &str) {
|
||||
return str.count;
|
||||
char chrlower(char c) {
|
||||
if(c >= 'A' && c <= 'Z')return c + ('a' - 'A');
|
||||
return c;
|
||||
}
|
||||
|
||||
void strresize(_string &str, uint32 size) {
|
||||
char *t;
|
||||
int sl;
|
||||
if(str.size == size)return;
|
||||
sl = strlen(str.s);
|
||||
t = (char*)malloc(size + 1);
|
||||
strcpy(t, str.s);
|
||||
free(str.s);
|
||||
str.s = t;
|
||||
char chrupper(char c) {
|
||||
if(c >= 'a' && c <= 'z')return c - ('a' - 'A');
|
||||
return c;
|
||||
}
|
||||
|
||||
uint count(string &str) { return str.count; }
|
||||
|
||||
void strresize(substring &str, uint size) {
|
||||
str.s = (char*)realloc(str.s, size + 1);
|
||||
str.s[size] = 0;
|
||||
str.size = size;
|
||||
}
|
||||
|
||||
char *strptr(_string &str) {
|
||||
return str.s;
|
||||
}
|
||||
char *strptr(substring &str) { return str.s; }
|
||||
|
||||
void strcpy(_string &dest, char *src) {
|
||||
uint strlen(substring &str) { return strlen(strptr(str)); }
|
||||
|
||||
int strcmp(substring &dest, const char *src) { return strcmp(strptr(dest), src); }
|
||||
int strcmp(const char *dest, substring &src) { return strcmp(dest, strptr(src)); }
|
||||
int strcmp(substring &dest, substring &src) { return strcmp(strptr(dest), strptr(src)); }
|
||||
|
||||
void strcpy(substring &dest, const char *src) {
|
||||
int srclen = strlen(src);
|
||||
if(srclen > dest.size) { strresize(dest, srclen); }
|
||||
strcpy(dest.s, src);
|
||||
}
|
||||
void strcpy(substring &dest, substring &src) { strcpy(dest, strptr(src)); }
|
||||
|
||||
void strset(_string &dest, uint32 pos, uint8 c) {
|
||||
void strset(substring &dest, uint pos, uint8 c) {
|
||||
char *s;
|
||||
if(pos > dest.size) { strresize(dest, pos); }
|
||||
dest.s[pos] = c;
|
||||
}
|
||||
|
||||
void strcat(_string &dest, char *src) {
|
||||
void strcat(substring &dest, const char *src) {
|
||||
int srclen, destlen;
|
||||
srclen = strlen(src);
|
||||
destlen = strlen(dest.s);
|
||||
if(srclen + destlen > dest.size) { strresize(dest, srclen + destlen); }
|
||||
strcat(dest.s, src);
|
||||
}
|
||||
void strcat(substring &dest, substring &src) { strcat(dest, strptr(src)); }
|
||||
|
||||
void strinsert(_string &dest, char *src, uint32 pos) {
|
||||
_string *s = new _string();
|
||||
strcpy(*s, strptr(dest) + pos);
|
||||
void strinsert(substring &dest, const char *src, uint pos) {
|
||||
static substring s;
|
||||
strcpy(s, strptr(dest) + pos);
|
||||
strset(dest, pos, 0);
|
||||
strcat(dest, src);
|
||||
strcat(dest, *s);
|
||||
delete(s);
|
||||
strcat(dest, s);
|
||||
}
|
||||
void strinsert(substring &dest, substring &src, uint pos) { strinsert(dest, strptr(src), pos); }
|
||||
|
||||
void strremove(_string &dest, uint32 start, uint32 length) {
|
||||
void strremove(substring &dest, uint start, uint length) {
|
||||
int destlen;
|
||||
char *s;
|
||||
int i, sl = strlen(dest.s);
|
||||
@@ -98,36 +109,35 @@ int i, sl = strlen(dest.s);
|
||||
s[i] = 0;
|
||||
}
|
||||
|
||||
bool stricmp(char *dest, char *src) {
|
||||
int i, sl = strlen(dest);
|
||||
if(sl != strlen(src))return false;
|
||||
for(i=0;i<sl;i++) {
|
||||
if(dest[i] >= 'A' && dest[i] <= 'Z') {
|
||||
if(dest[i] != src[i] && dest[i] + 0x20 != src[i])return false;
|
||||
} else if(dest[i] >='a' && dest[i] <= 'z') {
|
||||
if(dest[i] != src[i] && dest[i] - 0x20 != src[i])return false;
|
||||
} else {
|
||||
if(dest[i] != src[i])return false;
|
||||
}
|
||||
int __stricmp(const char *dest, const char *src) {
|
||||
while(*dest && *src) {
|
||||
if(chrlower(*dest) != chrlower(*src))break;
|
||||
dest++;
|
||||
src++;
|
||||
}
|
||||
return true;
|
||||
return (int)chrlower(*dest) - (int)chrlower(*src);
|
||||
}
|
||||
int stricmp(substring &dest, const char *src) { return __stricmp(strptr(dest), src); }
|
||||
int stricmp(const char *dest, substring &src) { return __stricmp(dest, strptr(src)); }
|
||||
int stricmp(substring &dest, substring &src) { return __stricmp(strptr(dest), strptr(src)); }
|
||||
|
||||
void strlower(char *str) {
|
||||
int i, sl = strlen(str);
|
||||
for(i=0;i<sl;i++) {
|
||||
if(str[i] >= 'A' && str[i] <= 'Z')str[i] += 0x20;
|
||||
while(*str) {
|
||||
*str = chrlower(*str);
|
||||
str++;
|
||||
}
|
||||
}
|
||||
void strlower(substring &str) { strlower(strptr(str)); }
|
||||
|
||||
void strupper(char *str) {
|
||||
int i, sl = strlen(str);
|
||||
for(i=0;i<sl;i++) {
|
||||
if(str[i] >= 'a' && str[i] <= 'z')str[i] -= 0x20;
|
||||
while(*str) {
|
||||
*str = chrupper(*str);
|
||||
str++;
|
||||
}
|
||||
}
|
||||
void strupper(substring &str) { strupper(strptr(str)); }
|
||||
|
||||
uint32 strpos(char *str, char *key) {
|
||||
uint strpos(const char *str, const char *key) {
|
||||
int i, ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return null;
|
||||
for(i=0;i<=ssl-ksl;i++) {
|
||||
@@ -135,8 +145,11 @@ int i, ssl = strlen(str), ksl = strlen(key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
uint strpos(substring &str, const char *key) { return strpos(strptr(str), key); }
|
||||
uint strpos(const char *str, substring &key) { return strpos(str, strptr(key)); }
|
||||
uint strpos(substring &str, substring &key) { return strpos(strptr(str), strptr(key)); }
|
||||
|
||||
uint32 strqpos(char *str, char *key) {
|
||||
uint qstrpos(const char *str, const char *key) {
|
||||
int i, z, ssl = strlen(str), ksl = strlen(key);
|
||||
uint8 x;
|
||||
if(ksl > ssl)return null;
|
||||
@@ -155,8 +168,11 @@ uint8 x;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
uint qstrpos(substring &str, const char *key) { return qstrpos(strptr(str), key); }
|
||||
uint qstrpos(const char *str, substring &key) { return qstrpos(str, strptr(key)); }
|
||||
uint qstrpos(substring &str, substring &key) { return qstrpos(strptr(str), strptr(key)); }
|
||||
|
||||
void strtr(char *dest, char *before, char *after) {
|
||||
void strtr(char *dest, const char *before, const char *after) {
|
||||
int i, l, sl = strlen(dest), bsl = strlen(before), asl = strlen(after);
|
||||
if((bsl != asl) || bsl == 0)return;
|
||||
for(i=0;i<sl;i++) {
|
||||
@@ -165,15 +181,17 @@ int i, l, sl = strlen(dest), bsl = strlen(before), asl = strlen(after);
|
||||
}
|
||||
}
|
||||
}
|
||||
void strtr(substring &dest, const char *before, const char *after) { strtr(strptr(dest), before, after); }
|
||||
|
||||
uint32 strbegin(char *str, char *key) {
|
||||
uint strbegin(const char *str, const char *key) {
|
||||
int i, ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return 1;
|
||||
if(!memcmp(str, key, ksl))return 0;
|
||||
return 1;
|
||||
}
|
||||
uint strbegin(substring &str, const char *key) { return strbegin(strptr(str), key); }
|
||||
|
||||
uint32 stribegin(char *str, char *key) {
|
||||
uint stribegin(const char *str, const char *key) {
|
||||
int i, ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return 1;
|
||||
for(i=0;i<ksl;i++) {
|
||||
@@ -187,15 +205,17 @@ int i, ssl = strlen(str), ksl = strlen(key);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
uint stribegin(substring &str, const char *key) { return stribegin(strptr(str), key); }
|
||||
|
||||
uint32 strend(char *str, char *key) {
|
||||
uint strend(const char *str, const char *key) {
|
||||
int i, ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return 1;
|
||||
if(!memcmp(str + ssl - ksl, key, ksl))return 0;
|
||||
return 1;
|
||||
}
|
||||
uint strend(substring &str, const char *key) { return strend(strptr(str), key); }
|
||||
|
||||
uint32 striend(char *str, char *key) {
|
||||
uint striend(const char *str, const char *key) {
|
||||
int i, z, ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return 1;
|
||||
for(i=ssl-ksl, z=0;i<ssl;i++, z++) {
|
||||
@@ -209,8 +229,9 @@ int i, z, ssl = strlen(str), ksl = strlen(key);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
uint striend(substring &str, const char *key) { return striend(strptr(str), key); }
|
||||
|
||||
void strltrim(char *str, char *key) {
|
||||
void strltrim(char *str, const char *key) {
|
||||
int i, ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return;
|
||||
if(!strbegin(str, key)) {
|
||||
@@ -218,8 +239,9 @@ int i, ssl = strlen(str), ksl = strlen(key);
|
||||
str[i] = 0;
|
||||
}
|
||||
}
|
||||
void strltrim(substring &str, const char *key) { strltrim(strptr(str), key); }
|
||||
|
||||
void striltrim(char *str, char *key) {
|
||||
void striltrim(char *str, const char *key) {
|
||||
int i, ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return;
|
||||
if(!stribegin(str, key)) {
|
||||
@@ -227,25 +249,28 @@ int i, ssl = strlen(str), ksl = strlen(key);
|
||||
str[i] = 0;
|
||||
}
|
||||
}
|
||||
void striltrim(substring &str, const char *key) { striltrim(strptr(str), key); }
|
||||
|
||||
void strrtrim(char *str, char *key) {
|
||||
void strrtrim(char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return;
|
||||
if(!strend(str, key)) {
|
||||
str[ssl - ksl] = 0;
|
||||
}
|
||||
}
|
||||
void strrtrim(substring &str, const char *key) { strrtrim(strptr(str), key); }
|
||||
|
||||
void strirtrim(char *str, char *key) {
|
||||
void strirtrim(char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return;
|
||||
if(!striend(str, key)) {
|
||||
str[ssl - ksl] = 0;
|
||||
}
|
||||
}
|
||||
void strirtrim(substring &str, const char *key) { strirtrim(strptr(str), key); }
|
||||
|
||||
/* does not work on type char* because function increases string length */
|
||||
void strquote(_string &str) {
|
||||
//does not work on type char* because function increases string length
|
||||
void strquote(substring &str) {
|
||||
static string t;
|
||||
strcpy(t, "\"");
|
||||
strcat(t, str);
|
||||
@@ -255,15 +280,15 @@ static string t;
|
||||
|
||||
bool strunquote(char *str) {
|
||||
int i, ssl = strlen(str);
|
||||
/* make sure string is long enough to have quotes */
|
||||
//make sure string is long enough to have quotes
|
||||
if(ssl < 2)return false;
|
||||
|
||||
/* make sure string actually has quotes */
|
||||
//make sure string actually has quotes
|
||||
if(str[0] == '\"' && str[ssl - 1] == '\"');
|
||||
else if(str[0] == '\'' && str[ssl - 1] == '\'');
|
||||
else return false;
|
||||
|
||||
/* now remove them */
|
||||
//now remove them
|
||||
for(i=0;i<ssl;i++) {
|
||||
str[i] = str[i + 1];
|
||||
}
|
||||
@@ -271,9 +296,10 @@ int i, ssl = strlen(str);
|
||||
|
||||
return true;
|
||||
}
|
||||
bool strunquote(substring &str) { return strunquote(strptr(str)); }
|
||||
|
||||
uint32 strhex(char *str) {
|
||||
uint32 r = 0, m = 0;
|
||||
uint strhex(const char *str) {
|
||||
uint r = 0, m = 0;
|
||||
int i, ssl = strlen(str);
|
||||
uint8 x;
|
||||
for(i=0;i<ssl;i++) {
|
||||
@@ -292,31 +318,44 @@ uint8 x;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
uint strhex(substring &str) { return strhex(strptr(str)); }
|
||||
|
||||
int strdec(char *str) {
|
||||
uint32 m = 1;
|
||||
int sstrhex(const char *str) {
|
||||
if(str[0] == '-') {
|
||||
return -strhex(str + 1);
|
||||
}
|
||||
return strhex(str);
|
||||
}
|
||||
int sstrhex(substring &str) { return sstrhex(strptr(str)); }
|
||||
|
||||
uint strdec(const char *str) {
|
||||
uint m = 1;
|
||||
int i, r = 0, ssl = strlen(str);
|
||||
uint8 x;
|
||||
for(i=0;i<ssl;i++) {
|
||||
if(str[i] >= '0' && str[i] <= '9');
|
||||
else if(str[i] == '-' && i == 0);
|
||||
else break;
|
||||
}
|
||||
for(--i;i>=0;i--, m*=10) {
|
||||
x = str[i];
|
||||
if(x >= '0' && x <= '9')x -= '0';
|
||||
else if(i == 0 && str[i] == '-') {
|
||||
r *= -1;
|
||||
return r;
|
||||
}
|
||||
else return r;
|
||||
r += x * m;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
uint strdec(substring &str) { return strdec(strptr(str)); }
|
||||
|
||||
uint32 strbin(char *str) {
|
||||
uint32 r = 0, m = 0;
|
||||
int sstrdec(const char *str) {
|
||||
if(str[0] == '-') {
|
||||
return -strdec(str + 1);
|
||||
}
|
||||
return strdec(str);
|
||||
}
|
||||
int sstrdec(substring &str) { return sstrdec(strptr(str)); }
|
||||
|
||||
uint strbin(const char *str) {
|
||||
uint r = 0, m = 0;
|
||||
int i, ssl = strlen(str);
|
||||
uint8 x;
|
||||
for(i=0;i<ssl;i++) {
|
||||
@@ -331,6 +370,15 @@ uint8 x;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
uint strbin(substring &str) { return strbin(strptr(str)); }
|
||||
|
||||
int sstrbin(const char *str) {
|
||||
if(str[0] == '-') {
|
||||
return -strbin(str + 1);
|
||||
}
|
||||
return strbin(str);
|
||||
}
|
||||
int sstrbin(substring &str) { return sstrbin(strptr(str)); }
|
||||
|
||||
#include "libstring_math.cpp"
|
||||
#include "libstring_split.cpp"
|
||||
|
||||
+154
-229
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
libstring : version 0.05 ~byuu
|
||||
libstring : version 0.06a ~byuu (08/22/05)
|
||||
*/
|
||||
|
||||
#ifndef __LIBSTRING
|
||||
@@ -8,247 +8,172 @@
|
||||
#include "libvector.h"
|
||||
|
||||
class string;
|
||||
class _string;
|
||||
class substring;
|
||||
|
||||
uint32 count(string &str);
|
||||
void strresize(_string &str, uint32 size);
|
||||
char* strptr(_string &str);
|
||||
void strcpy(_string &dest, char *src);
|
||||
void strset(_string &dest, uint32 pos, uint8 c);
|
||||
void strcat(_string &dest, char *src);
|
||||
void strinsert(_string &dest, char *src, uint32 pos);
|
||||
void strremove(_string &dest, uint32 start, uint32 length = 0);
|
||||
bool stricmp(char *dest, char *src);
|
||||
void strlower(char *str);
|
||||
void strupper(char *str);
|
||||
uint32 strpos(char *str, char *key);
|
||||
uint32 strqpos(char *str, char *key);
|
||||
void strtr(char *dest, char *before, char *after);
|
||||
uint32 strbegin(char *str, char *key);
|
||||
uint32 stribegin(char *str, char *key);
|
||||
uint32 strend(char *str, char *key);
|
||||
uint32 striend(char *str, char *key);
|
||||
void strltrim(char *str, char *key);
|
||||
void striltrim(char *str, char *key);
|
||||
void strrtrim(char *str, char *key);
|
||||
void strirtrim(char *str, char *key);
|
||||
void strquote(_string &str);
|
||||
bool strunquote(char *str);
|
||||
uint32 strhex(char *str);
|
||||
int strdec(char *str);
|
||||
uint32 strbin(char *str);
|
||||
uint32 strmath(char *in_str);
|
||||
uint32 strmathentity(char *str);
|
||||
void replace (_string &str, char *key, char *token);
|
||||
void qreplace(_string &str, char *key, char *token);
|
||||
void split (string &dest, char *key, char *src);
|
||||
void qsplit(string &dest, char *key, char *src);
|
||||
void sprintf(_string &str, char *s, ...);
|
||||
char chrlower(char c);
|
||||
char chrupper(char c);
|
||||
|
||||
class _string {
|
||||
uint count(string &str);
|
||||
|
||||
void strresize(substring &str, uint size);
|
||||
|
||||
char* strptr(substring &str);
|
||||
|
||||
uint strlen(substring &str);
|
||||
|
||||
int strcmp(substring &dest, const char *src);
|
||||
int strcmp(const char *dest, substring &src);
|
||||
int strcmp(substring &dest, substring &src);
|
||||
|
||||
void strcpy(substring &dest, const char *src);
|
||||
void strcpy(substring &dest, substring &src);
|
||||
|
||||
void strset(substring &dest, uint pos, uint8 c);
|
||||
|
||||
void strcat(substring &dest, const char *src);
|
||||
void strcat(substring &dest, substring &src);
|
||||
|
||||
void strinsert(substring &dest, const char *src, uint pos);
|
||||
void strinsert(substring &dest, substring &src, uint pos);
|
||||
|
||||
void strremove(substring &dest, uint start, uint length = 0);
|
||||
|
||||
//vc6/win32 and gcc/dos only support stricmp, whereas
|
||||
//gcc/unix only supports strcasecmp. this is an attempt
|
||||
//to avoid platform-specific defines...
|
||||
#define stricmp __stricmp
|
||||
int __stricmp(const char *dest, const char *src);
|
||||
int stricmp(substring &dest, const char *src);
|
||||
int stricmp(const char *dest, substring &src);
|
||||
int stricmp(substring &dest, substring &src);
|
||||
|
||||
void strlower(char *str);
|
||||
void strlower(substring &str);
|
||||
|
||||
void strupper(char *str);
|
||||
void strupper(substring &str);
|
||||
|
||||
uint strpos(const char *str, const char *key);
|
||||
uint strpos(substring &str, const char *key);
|
||||
uint strpos(const char *str, substring &key);
|
||||
uint strpos(substring &str, substring &key);
|
||||
|
||||
uint qstrpos(const char *str, const char *key);
|
||||
uint qstrpos(substring &str, const char *key);
|
||||
uint qstrpos(const char *str, substring &key);
|
||||
uint qstrpos(substring &str, substring &key);
|
||||
|
||||
void strtr(char *dest, const char *before, const char *after);
|
||||
void strtr(substring &dest, const char *before, const char *after);
|
||||
|
||||
uint strbegin(const char *str, const char *key);
|
||||
uint strbegin(substring &str, const char *key);
|
||||
|
||||
uint stribegin(const char *str, const char *key);
|
||||
uint stribegin(substring &str, const char *key);
|
||||
|
||||
uint strend(const char *str, const char *key);
|
||||
uint strend(substring &str, const char *key);
|
||||
|
||||
uint striend(const char *str, const char *key);
|
||||
uint striend(substring &str, const char *key);
|
||||
|
||||
void strltrim(char *str, const char *key);
|
||||
void strltrim(substring &str, const char *key);
|
||||
|
||||
void striltrim(char *str, const char *key);
|
||||
void striltrim(substring &str, const char *key);
|
||||
|
||||
void strrtrim(char *str, const char *key);
|
||||
void strrtrim(substring &str, const char *key);
|
||||
|
||||
void strirtrim(char *str, const char *key);
|
||||
void strirtrim(substring &str, const char *key);
|
||||
|
||||
void strquote(substring &str);
|
||||
|
||||
bool strunquote(char *str);
|
||||
bool strunquote(substring &str);
|
||||
|
||||
uint strhex(const char *str);
|
||||
uint strhex(substring &str);
|
||||
|
||||
int sstrhex(const char *str);
|
||||
int sstrhex(substring &str);
|
||||
|
||||
uint strdec(const char *str);
|
||||
uint strdec(substring &str);
|
||||
|
||||
int sstrdec(const char *str);
|
||||
int sstrdec(substring &str);
|
||||
|
||||
uint strbin(const char *str);
|
||||
uint strbin(substring &str);
|
||||
|
||||
int sstrbin(const char *str);
|
||||
int sstrbin(substring &str);
|
||||
|
||||
uint strmath(const char *in_str);
|
||||
uint strmath(substring &in_str);
|
||||
|
||||
bool strmathentity(const char *str);
|
||||
bool strmathentity(substring &str);
|
||||
|
||||
void replace(substring &str, const char *key, const char *token);
|
||||
void replace(substring &str, const char *key, substring &token);
|
||||
|
||||
void qreplace(substring &str, const char *key, const char *token);
|
||||
void qreplace(substring &str, const char *key, substring &token);
|
||||
|
||||
void split(string &dest, const char *key, char *src);
|
||||
void split(string &dest, const char *key, substring &src);
|
||||
|
||||
void qsplit(string &dest, const char *key, char *src);
|
||||
void qsplit(string &dest, const char *key, substring &src);
|
||||
|
||||
void sprintf(substring &str, const char *s, ...);
|
||||
|
||||
class substring {
|
||||
public:
|
||||
char *s;
|
||||
uint32 size;
|
||||
inline char* operator*() { return s; }
|
||||
uint size;
|
||||
//inline char* operator*() { return s; }
|
||||
//inline operator char*() { return s; }
|
||||
|
||||
#ifdef __LIBSTRING_OVERLOADS
|
||||
inline _string& operator=(char *cpy);
|
||||
inline _string& operator=(_string &cpy);
|
||||
inline _string& operator=(string &cpy);
|
||||
|
||||
inline _string& operator+=(char *cat);
|
||||
inline _string& operator+=(_string &cat);
|
||||
inline _string& operator+=(string &cat);
|
||||
|
||||
inline _string& operator-=(char *cut);
|
||||
inline _string& operator-=(_string &cut);
|
||||
inline _string& operator-=(string &cut);
|
||||
|
||||
inline bool operator==(char *cmp);
|
||||
inline bool operator==(_string &cmp);
|
||||
inline bool operator==(string &cmp);
|
||||
|
||||
inline bool operator!=(char *cmp);
|
||||
inline bool operator!=(_string &cmp);
|
||||
inline bool operator!=(string &cmp);
|
||||
#endif
|
||||
|
||||
inline operator char*() { return s; }
|
||||
|
||||
_string();
|
||||
~_string();
|
||||
substring();
|
||||
~substring();
|
||||
};
|
||||
|
||||
/* listcount is the actual size of list[], used for allocation
|
||||
* of substrings.
|
||||
* count is used by split() and count() to return the number of
|
||||
* active/valid substrings. example: if string T contains 16
|
||||
* substrings, and split is called, which sets three substrings,
|
||||
* then count() needs to reflect that only three substrings are
|
||||
* now used, but listcount still needs to reflect the true size
|
||||
* of list[].
|
||||
*/
|
||||
class string {
|
||||
public:
|
||||
vector<_string*> list;
|
||||
uint32 count, listcount;
|
||||
void addto(uint32 num); //creates all needed strings to make list[num] valid
|
||||
_string &str(uint32 num); //gets a _string reference, creating it + new strings if needed
|
||||
vector<substring*> list;
|
||||
uint listcount, count;
|
||||
void addto(uint num); //creates all needed strings to make list[num] valid
|
||||
substring &str(uint num); //gets a substring reference, creating it + new strings if needed
|
||||
|
||||
inline char* operator*() { return strptr(str(0)); }
|
||||
|
||||
#ifdef __LIBSTRING_OVERLOADS
|
||||
inline string& operator=(char *cpy);
|
||||
inline string& operator=(_string &cpy);
|
||||
inline string& operator=(string &cpy);
|
||||
|
||||
inline string& operator+=(char *cat);
|
||||
inline string& operator+=(_string &cat);
|
||||
inline string& operator+=(string &cat);
|
||||
|
||||
inline string& operator-=(char *cut);
|
||||
inline string& operator-=(_string &cut);
|
||||
inline string& operator-=(string &cut);
|
||||
|
||||
inline bool operator==(char *cmp);
|
||||
inline bool operator==(_string &cmp);
|
||||
inline bool operator==(string &cmp);
|
||||
|
||||
inline bool operator!=(char *cmp);
|
||||
inline bool operator!=(_string &cmp);
|
||||
inline bool operator!=(string &cmp);
|
||||
#endif
|
||||
|
||||
inline operator char*() { return str(0).s; }
|
||||
inline operator _string&() { return str(0); }
|
||||
inline _string& operator[](uint32 i) { return str(i); }
|
||||
inline _string& operator[](int i) { return str(i); }
|
||||
//inline char* operator*() { return strptr(str(0)); }
|
||||
//inline operator char*() { return str(0).s; }
|
||||
inline operator substring&() { return str(0); }
|
||||
inline substring& operator[](uint i) { return str(i); }
|
||||
inline substring& operator[](uint8 i) { return str(i); }
|
||||
inline substring& operator[](uint16 i) { return str(i); }
|
||||
inline substring& operator[](uint32 i) { return str(i); }
|
||||
inline substring& operator[](int i) { return str(i); }
|
||||
inline substring& operator[](int8 i) { return str(i); }
|
||||
inline substring& operator[](int16 i) { return str(i); }
|
||||
inline substring& operator[](int32 i) { return str(i); }
|
||||
|
||||
string();
|
||||
~string();
|
||||
};
|
||||
|
||||
#ifdef __LIBSTRING_OVERLOADS
|
||||
inline _string& _string::operator=(char *cpy) {
|
||||
strcpy(*this, cpy);
|
||||
return *this;
|
||||
}
|
||||
inline _string& _string::operator=(_string &cpy) {
|
||||
strcpy(*this, cpy);
|
||||
return *this;
|
||||
}
|
||||
inline _string& _string::operator=(string &cpy) {
|
||||
strcpy(*this, cpy.str(0));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline string& string::operator=(char *cpy) {
|
||||
strcpy(str(0), cpy);
|
||||
return *this;
|
||||
}
|
||||
inline string& string::operator=(_string &cpy) {
|
||||
strcpy(str(0), cpy);
|
||||
return *this;
|
||||
}
|
||||
inline string& string::operator=(string &cpy) {
|
||||
strcpy(str(0), cpy.str(0));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline _string& _string::operator+=(char *cat) {
|
||||
strcat(*this, cat);
|
||||
return *this;
|
||||
}
|
||||
inline _string& _string::operator+=(_string &cat) {
|
||||
strcat(*this, cat);
|
||||
return *this;
|
||||
}
|
||||
inline _string& _string::operator+=(string &cat) {
|
||||
strcat(*this, cat.str(0));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline string& string::operator+=(char *cat) {
|
||||
strcat(str(0), cat);
|
||||
return *this;
|
||||
}
|
||||
inline string& string::operator+=(_string &cat) {
|
||||
strcat(str(0), cat);
|
||||
return *this;
|
||||
}
|
||||
inline string& string::operator+=(string &cat) {
|
||||
strcat(str(0), cat.str(0));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline _string& _string::operator-=(char *cut) {
|
||||
strrtrim(*this, cut);
|
||||
return *this;
|
||||
}
|
||||
inline _string& _string::operator-=(_string &cut) {
|
||||
strrtrim(*this, cut);
|
||||
return *this;
|
||||
}
|
||||
inline _string& _string::operator-=(string &cut) {
|
||||
strrtrim(*this, cut.str(0));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline string& string::operator-=(char *cut) {
|
||||
strrtrim(str(0), cut);
|
||||
return *this;
|
||||
}
|
||||
inline string& string::operator-=(_string &cut) {
|
||||
strrtrim(str(0), cut);
|
||||
return *this;
|
||||
}
|
||||
inline string& string::operator-=(string &cut) {
|
||||
strrtrim(str(0), cut.str(0));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool _string::operator==(char *cmp) {
|
||||
if(!strcmp(*this, cmp))return true;
|
||||
return false;
|
||||
}
|
||||
inline bool _string::operator==(_string &cmp) {
|
||||
if(!strcmp(*this, cmp))return true;
|
||||
return false;
|
||||
}
|
||||
inline bool _string::operator==(string &cmp) {
|
||||
if(!strcmp(*this, cmp.str(0)))return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool string::operator==(char *cmp) {
|
||||
if(!strcmp(str(0), cmp))return true;
|
||||
return false;
|
||||
}
|
||||
inline bool string::operator==(_string &cmp) {
|
||||
if(!strcmp(str(0), cmp))return true;
|
||||
return false;
|
||||
}
|
||||
inline bool string::operator==(string &cmp) {
|
||||
if(!strcmp(str(0), cmp.str(0)))return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool _string::operator!=(char *cmp) {
|
||||
if(!strcmp(*this, cmp))return false;
|
||||
return true;
|
||||
}
|
||||
inline bool _string::operator!=(_string &cmp) {
|
||||
if(!strcmp(*this, cmp))return false;
|
||||
return true;
|
||||
}
|
||||
inline bool _string::operator!=(string &cmp) {
|
||||
if(!strcmp(*this, cmp.str(0)))return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool string::operator!=(char *cmp) {
|
||||
if(!strcmp(str(0), cmp))return false;
|
||||
return true;
|
||||
}
|
||||
inline bool string::operator!=(_string &cmp) {
|
||||
if(!strcmp(str(0), cmp))return false;
|
||||
return true;
|
||||
}
|
||||
inline bool string::operator!=(string &cmp) {
|
||||
if(!strcmp(str(0), cmp.str(0)))return false;
|
||||
return true;
|
||||
}
|
||||
#endif //__LIBSTRING_OVERLOADS
|
||||
|
||||
#endif //__LIBSTRING
|
||||
+13
-11
@@ -43,10 +43,10 @@ strmath(str)
|
||||
str, and returns numerical result
|
||||
example: strmath("5+5")=10
|
||||
***************************************/
|
||||
uint32 p_strmath(char *str) {
|
||||
int i = 0, ssl = strlen(str);
|
||||
uint p_strmath(const char *str) {
|
||||
int i = 0, ssl = strlen(str);
|
||||
uint r, array[128], array_size = 0, z = 0;
|
||||
uint8 x, mode = 0;
|
||||
uint32 r, array[128], array_size = 0, z = 0;
|
||||
uint8 array_gate[128];
|
||||
char *s1;
|
||||
if(!ssl)return 0;
|
||||
@@ -95,11 +95,11 @@ char *s1;
|
||||
return r;
|
||||
}
|
||||
|
||||
uint32 strmath(char *in_str) {
|
||||
uint32 r = 0;
|
||||
uint32 pdepth = 0, cpdepth, maxpdepth = 0;
|
||||
uint32 pstart, pend, spos;
|
||||
int i, sc, sl = strlen(in_str);
|
||||
uint strmath(const char *in_str) {
|
||||
uint r = 0;
|
||||
uint pdepth = 0, cpdepth, maxpdepth = 0;
|
||||
uint pstart, pend, spos;
|
||||
int i, sc, sl = strlen(in_str);
|
||||
char *str = (char*)malloc(sl + 1), *str0;
|
||||
char *pstr;
|
||||
char num[64];
|
||||
@@ -165,13 +165,15 @@ char num[64];
|
||||
free(str);
|
||||
return r;
|
||||
}
|
||||
uint strmath(substring &in_str) { return strmath(strptr(in_str)); }
|
||||
|
||||
uint32 strmathentity(char *str) {
|
||||
bool strmathentity(const char *str) {
|
||||
int i, ssl = strlen(str);
|
||||
for(i=0;i<ssl;i++) {
|
||||
if(str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/' ||
|
||||
str[i] == '%' || str[i] == '&' || str[i] == '|' || str[i] == '^' ||
|
||||
(str[i] == '<' && str[i+1] == '<') || (str[i] == '>' && str[i+1] == '>'))return 1;
|
||||
(str[i] == '<' && str[i+1] == '<') || (str[i] == '>' && str[i+1] == '>'))return true;
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
bool strmathentity(substring &str) { return strmathentity(strptr(str)); }
|
||||
@@ -1,6 +1,6 @@
|
||||
void replace(_string &str, char *key, char *token) {
|
||||
int i, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str);
|
||||
uint32 replace_count = 0, size = ssl;
|
||||
void replace(substring &str, const char *key, const char *token) {
|
||||
int i, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str);
|
||||
uint replace_count = 0, size = ssl;
|
||||
char *data;
|
||||
if(ksl > ssl)return;
|
||||
if(tsl > ksl) { //the new string may be longer than the old string...
|
||||
@@ -27,11 +27,12 @@ char *data;
|
||||
strcpy(str, data);
|
||||
free(data);
|
||||
}
|
||||
void replace(substring &str, const char *key, substring &token) { replace(str, key, strptr(token)); }
|
||||
|
||||
void qreplace(_string &str, char *key, char *token) {
|
||||
int i, l, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str);
|
||||
void qreplace(substring &str, const char *key, const char *token) {
|
||||
int i, l, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str);
|
||||
uint replace_count = 0, size = ssl;
|
||||
uint8 x;
|
||||
uint32 replace_count = 0, size = ssl;
|
||||
char *data;
|
||||
if(ksl > ssl)return;
|
||||
if(tsl > ksl) {
|
||||
@@ -80,3 +81,4 @@ char *data;
|
||||
strcpy(str, data);
|
||||
free(data);
|
||||
}
|
||||
void qreplace(substring &str, const char *key, substring &token) { qreplace(str, key, strptr(token)); }
|
||||
@@ -1,7 +1,7 @@
|
||||
void split(string &dest, char *key, char *src) {
|
||||
int i, ssl = strlen(src), ksl = strlen(key);
|
||||
void split(string &dest, const char *key, char *src) {
|
||||
int i, ssl = strlen(src), ksl = strlen(key);
|
||||
uint lp = 0, split_count = 0;
|
||||
uint8 x;
|
||||
uint32 lp = 0, split_count = 0;
|
||||
for(i=0;i<=ssl-ksl;) {
|
||||
if(!memcmp(src + i, key, ksl)) {
|
||||
x = src[i];
|
||||
@@ -15,11 +15,12 @@ uint32 lp = 0, split_count = 0;
|
||||
strcpy(dest[split_count++], src + lp);
|
||||
dest.count = split_count;
|
||||
}
|
||||
void split(string &dest, const char *key, substring &src) { split(dest, key, strptr(src)); }
|
||||
|
||||
void qsplit(string &dest, char *key, char *src) {
|
||||
int i, z, ssl = strlen(src), ksl = strlen(key);
|
||||
void qsplit(string &dest, const char *key, char *src) {
|
||||
int i, z, ssl = strlen(src), ksl = strlen(key);
|
||||
uint lp = 0, split_count = 0;
|
||||
uint8 x;
|
||||
uint32 lp = 0, split_count = 0;
|
||||
for(i=0;i<=ssl-ksl;) {
|
||||
x = src[i];
|
||||
if(x=='\"' || x=='\'') {
|
||||
@@ -39,3 +40,4 @@ uint32 lp = 0, split_count = 0;
|
||||
strcpy(dest[split_count++], src + lp);
|
||||
dest.count = split_count;
|
||||
}
|
||||
void qsplit(string &dest, const char *key, substring &src) { qsplit(dest, key, strptr(src)); }
|
||||
@@ -1,5 +1,5 @@
|
||||
void numtobin(char *s, uint32 num) {
|
||||
uint32 mask = 0x80000000, len = 0, z = 0;
|
||||
void numtobin(char *s, uint num) {
|
||||
uint mask = 0x80000000, len = 0, z = 0;
|
||||
for(;mask;mask>>=1,len++) { if(num&mask)break; }
|
||||
len = 32 - len;
|
||||
do {
|
||||
@@ -9,7 +9,7 @@ uint32 mask = 0x80000000, len = 0, z = 0;
|
||||
s[z] = 0;
|
||||
}
|
||||
|
||||
void sprintf(_string &str, char *s, ...) {
|
||||
void sprintf(substring &str, const char *s, ...) {
|
||||
va_list args;
|
||||
char t[2], n[256];
|
||||
int i, l, sl, z;
|
||||
@@ -17,7 +17,7 @@ uint8 pad_type, pad_len;
|
||||
uint32 num;
|
||||
char *r;
|
||||
va_start(args, s);
|
||||
strcpy(*str, "");
|
||||
strcpy(str, "");
|
||||
for(i=0;i<strlen(s);i++) {
|
||||
if(s[i] == '%') {
|
||||
i++;
|
||||
|
||||
+23
-18
@@ -1,65 +1,70 @@
|
||||
/*
|
||||
libvector : version 0.01 ~byuu
|
||||
libvector : version 0.03 ~byuu (08/16/05)
|
||||
*/
|
||||
|
||||
#ifndef __LIBVECTOR
|
||||
#define __LIBVECTOR
|
||||
|
||||
template<typename T> class vector {
|
||||
public:
|
||||
private:
|
||||
T *array;
|
||||
int size, sizelimit;
|
||||
//find next array size that is a power of two
|
||||
int findsize(int newsize) {
|
||||
int r = 1;
|
||||
while(r >= 1) {
|
||||
r <<= 1;
|
||||
if(r > sizelimit)return sizelimit;
|
||||
if(r >= newsize)return r;
|
||||
if(r > sizelimit)return sizelimit;
|
||||
if(r >= newsize) return r;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public:
|
||||
void resize(int newsize) {
|
||||
T *newarray;
|
||||
newsize = findsize(newsize);
|
||||
|
||||
if(newsize > sizelimit)newsize = sizelimit;
|
||||
if(newsize == size)return;
|
||||
|
||||
newarray = (T*)malloc(sizeof(T) * newsize);
|
||||
if(newsize >= size) {
|
||||
memcpy(newarray, array, sizeof(T) * size);
|
||||
} else {
|
||||
memcpy(newarray, array, sizeof(T) * newsize);
|
||||
}
|
||||
free(array);
|
||||
array = (T*)realloc(array, sizeof(T) * newsize);
|
||||
|
||||
array = newarray;
|
||||
size = newsize;
|
||||
if(newsize > size) {
|
||||
for(int i=size;i<newsize;i+=sizeof(T)) {
|
||||
array[i] = (T)0;
|
||||
}
|
||||
}
|
||||
|
||||
size = newsize;
|
||||
}
|
||||
|
||||
vector(int newsize, int newsizelimit) {
|
||||
size = newsize;
|
||||
sizelimit = newsizelimit;
|
||||
array = (T*)malloc(sizeof(T) * size);
|
||||
array = (T*)calloc(size, sizeof(T));
|
||||
}
|
||||
|
||||
vector(int newsize) {
|
||||
size = newsize;
|
||||
sizelimit = 1 << 24;
|
||||
array = (T*)malloc(sizeof(T) * size);
|
||||
array = (T*)calloc(size, sizeof(T));
|
||||
}
|
||||
|
||||
vector() {
|
||||
size = 16;
|
||||
sizelimit = 1 << 24;
|
||||
array = (T*)malloc(sizeof(T) * size);
|
||||
array = (T*)calloc(size, sizeof(T));
|
||||
}
|
||||
|
||||
~vector() {
|
||||
if(array)free(array);
|
||||
if(array) {
|
||||
free(array);
|
||||
array = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//operator T() { return array[0]; }
|
||||
|
||||
inline T &operator[](int index) {
|
||||
if(index >= size)resize(index + 1);
|
||||
if(index > sizelimit)return array[size - 1];
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
void bCartExLoROM::write_protect(bool r) { write_protected = r; }
|
||||
|
||||
uint8 bCartExLoROM::read(uint32 addr) {
|
||||
uint32 b, w;
|
||||
addr &= 0xffffff;
|
||||
b = (addr >> 16);
|
||||
w = (addr & 0xffff);
|
||||
|
||||
//SRAM Region A
|
||||
if((b & 0x7f) >= 0x30 && (b & 0x7f) <= 0x3f && (w & 0xe000) == 0x6000) {
|
||||
b &= 0x7f;
|
||||
if(b >= 0x30 && b <= 0x3f) {
|
||||
if(sram_size) {
|
||||
addr = (b - 0x30) * 0x2000 + (w - 0x6000);
|
||||
addr &= (sram_size - 1);
|
||||
return sram[addr];
|
||||
} else {
|
||||
return 0x00; //no SRAM available
|
||||
}
|
||||
} else {
|
||||
return 0x00; //unmapped
|
||||
}
|
||||
}
|
||||
|
||||
//SRAM Region B
|
||||
if(b >= 0x70 && b <= 0x7d) {
|
||||
if(sram_size) {
|
||||
addr = (addr & 0xffffff) - 0x700000;
|
||||
addr &= (sram_size - 1);
|
||||
return sram[addr];
|
||||
} else {
|
||||
return 0x00; //no SRAM available
|
||||
}
|
||||
}
|
||||
|
||||
if(b <= 0x3f) {
|
||||
addr = (b << 15) | (addr & 0x7fff);
|
||||
} else if(b <= 0x7f) {
|
||||
addr &= 0x3fffff;
|
||||
} else if(b <= 0xbf) {
|
||||
b &= 0x7f;
|
||||
addr = (b << 15) | (addr & 0x7fff);
|
||||
} else {
|
||||
addr = sdd1->offset(addr);
|
||||
}
|
||||
|
||||
if(addr < rom_size)return rom[addr];
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void bCartExLoROM::write(uint32 addr, uint8 value) {
|
||||
uint32 b, w;
|
||||
addr &= 0xffffff;
|
||||
b = (addr >> 16);
|
||||
w = (addr & 0xffff);
|
||||
|
||||
//SRAM Region A
|
||||
if((b & 0x7f) >= 0x30 && (b & 0x7f) <= 0x3f && (w & 0xe000) == 0x6000) {
|
||||
b &= 0x7f;
|
||||
if(b >= 0x30 && b <= 0x3f) {
|
||||
if(sram_size) {
|
||||
addr = (b - 0x30) * 0x2000 + (w - 0x6000);
|
||||
addr &= (sram_size - 1);
|
||||
sram[addr] = value;
|
||||
return;
|
||||
} else {
|
||||
return; //no SRAM available
|
||||
}
|
||||
} else {
|
||||
return; //unmapped
|
||||
}
|
||||
}
|
||||
|
||||
//SRAM Region B
|
||||
if(b >= 0x70 && b <= 0x7d) {
|
||||
if(sram_size) {
|
||||
addr = (addr & 0xffffff) - 0x700000;
|
||||
addr &= (sram_size - 1);
|
||||
sram[addr] = value;
|
||||
} else {
|
||||
return; //no SRAM available
|
||||
}
|
||||
}
|
||||
|
||||
if(write_protected == true)return;
|
||||
|
||||
if(b <= 0x3f) {
|
||||
addr = (b << 15) | (addr & 0x7fff);
|
||||
} else if(b <= 0x7f) {
|
||||
addr &= 0x3fffff;
|
||||
} else if(b <= 0xbf) {
|
||||
b &= 0x7f;
|
||||
addr = (b << 15) | (addr & 0x7fff);
|
||||
} else {
|
||||
addr = sdd1->offset(addr);
|
||||
}
|
||||
|
||||
if(addr < rom_size)rom[addr] = value;
|
||||
}
|
||||
|
||||
void bCartExLoROM::set_cartinfo(CartInfo *ci) {
|
||||
rom = ci->rom;
|
||||
sram = ci->sram;
|
||||
rom_size = ci->rom_size;
|
||||
sram_size = ci->sram_size;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
class bCartExLoROM : public Cart {
|
||||
private:
|
||||
bool write_protected;
|
||||
|
||||
public:
|
||||
uint8 *rom, *sram;
|
||||
uint32 rom_size, sram_size;
|
||||
uint8 read (uint32 addr);
|
||||
void write(uint32 addr, uint8 value);
|
||||
void write_protect(bool r);
|
||||
void set_cartinfo(CartInfo *ci);
|
||||
|
||||
bCartExLoROM() : write_protected(true) {}
|
||||
};
|
||||
@@ -33,10 +33,13 @@ uint32 b, w;
|
||||
}
|
||||
}
|
||||
|
||||
addr &= 0x3fffff;
|
||||
if(addr < rom_size)return rom[addr];
|
||||
addr &= ROM_mask;
|
||||
|
||||
return 0x00;
|
||||
if(addr >= P0_size) {
|
||||
addr = P0_size + (addr & (P1_size - 1));
|
||||
}
|
||||
|
||||
return rom[addr];
|
||||
}
|
||||
|
||||
void bCartHiROM::write(uint32 addr, uint8 value) {
|
||||
@@ -74,8 +77,14 @@ uint32 b, w;
|
||||
}
|
||||
|
||||
if(write_protected == true)return;
|
||||
addr &= 0x3fffff;
|
||||
if(addr < rom_size)rom[addr] = value;
|
||||
|
||||
addr &= ROM_mask;
|
||||
|
||||
if(addr >= P0_size) {
|
||||
addr = P0_size + (addr & (P1_size - 1));
|
||||
}
|
||||
|
||||
rom[addr] = value;
|
||||
}
|
||||
|
||||
void bCartHiROM::set_cartinfo(CartInfo *ci) {
|
||||
@@ -83,4 +92,15 @@ void bCartHiROM::set_cartinfo(CartInfo *ci) {
|
||||
sram = ci->sram;
|
||||
rom_size = ci->rom_size;
|
||||
sram_size = ci->sram_size;
|
||||
|
||||
//calculate highest power of 2, which is the size of the first ROM chip
|
||||
P0_size = 0x800000;
|
||||
while(!(rom_size & P0_size))P0_size >>= 1;
|
||||
P1_size = rom_size - P0_size;
|
||||
|
||||
if(rom_size == P0_size) { //cart only contains one ROM chip
|
||||
ROM_mask = (P0_size - 1);
|
||||
} else { //cart contains two ROM chips
|
||||
ROM_mask = (P0_size + P0_size - 1);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
class bCartHiROM : public Cart {
|
||||
private:
|
||||
bool write_protected;
|
||||
bool write_protected;
|
||||
uint32 P0_size, P1_size, ROM_mask;
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -35,17 +35,20 @@ uint32 b, w;
|
||||
|
||||
if(w & 0x8000) {
|
||||
b &= 0x7f;
|
||||
b %= 0x60;
|
||||
addr = (b << 15) | (addr & 0x7fff);
|
||||
} else {
|
||||
b &= 0x7f;
|
||||
b %= 0x60;
|
||||
if(b == 0x00)b = 0x60;
|
||||
if(b == 0x00)b = 0x7f;
|
||||
addr = (((b << 15) | (addr & 0x7fff)) - 0x8000);
|
||||
}
|
||||
if(addr < rom_size)return rom[addr];
|
||||
|
||||
return 0x00;
|
||||
addr &= ROM_mask;
|
||||
|
||||
if(addr >= P0_size) {
|
||||
addr = P0_size + (addr & (P1_size - 1));
|
||||
}
|
||||
|
||||
return rom[addr];
|
||||
}
|
||||
|
||||
void bCartLoROM::write(uint32 addr, uint8 value) {
|
||||
@@ -83,17 +86,23 @@ uint32 b, w;
|
||||
}
|
||||
|
||||
if(write_protected == true)return;
|
||||
|
||||
if(w & 0x8000) {
|
||||
b &= 0x7f;
|
||||
b %= 0x60;
|
||||
addr = (b << 15) | (addr & 0x7fff);
|
||||
} else {
|
||||
b &= 0x7f;
|
||||
b %= 0x60;
|
||||
if(b == 0x00)b = 0x60;
|
||||
if(b == 0x00)b = 0x7f;
|
||||
addr = (((b << 15) | (addr & 0x7fff)) - 0x8000);
|
||||
}
|
||||
if(addr < rom_size)rom[addr] = value;
|
||||
|
||||
addr &= ROM_mask;
|
||||
|
||||
if(addr >= P0_size) {
|
||||
addr = P0_size + (addr & (P1_size - 1));
|
||||
}
|
||||
|
||||
rom[addr] = value;
|
||||
}
|
||||
|
||||
void bCartLoROM::set_cartinfo(CartInfo *ci) {
|
||||
@@ -101,4 +110,15 @@ void bCartLoROM::set_cartinfo(CartInfo *ci) {
|
||||
sram = ci->sram;
|
||||
rom_size = ci->rom_size;
|
||||
sram_size = ci->sram_size;
|
||||
|
||||
//calculate highest power of 2, which is the size of the first ROM chip
|
||||
P0_size = 0x800000;
|
||||
while(!(rom_size & P0_size))P0_size >>= 1;
|
||||
P1_size = rom_size - P0_size;
|
||||
|
||||
if(rom_size == P0_size) { //cart only contains one ROM chip
|
||||
ROM_mask = (P0_size - 1);
|
||||
} else { //cart contains two ROM chips
|
||||
ROM_mask = (P0_size + P0_size - 1);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
class bCartLoROM : public Cart {
|
||||
private:
|
||||
bool write_protected;
|
||||
bool write_protected;
|
||||
uint32 P0_size, P1_size, ROM_mask;
|
||||
|
||||
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);
|
||||
|
||||
|
||||
+103
-56
@@ -1,22 +1,36 @@
|
||||
#include "../../base.h"
|
||||
#include "bcart_lorom.cpp"
|
||||
#include "bcart_hirom.cpp"
|
||||
#include "bcart_exlorom.cpp"
|
||||
#include "bcart_exhirom.cpp"
|
||||
|
||||
bool bMemBus::load_cart(Reader *rf) {
|
||||
uint32 cksum, icksum, index;
|
||||
char cart_title[24];
|
||||
uint8 mapper;
|
||||
uint8 mapper, region;
|
||||
if(rom_loaded == true)return false;
|
||||
|
||||
rf->read(&rom);
|
||||
|
||||
rf->read(&rom_image);
|
||||
rom = rom_image;
|
||||
rom_size = rf->size();
|
||||
|
||||
if(rom_size < 32768)return false;
|
||||
if(rom_size < 32768) {
|
||||
zerofree(rom_image);
|
||||
return false;
|
||||
}
|
||||
|
||||
//check for ROM header (currently unused)
|
||||
if((rom_size & 0x1fff) == 0x0200) {
|
||||
rom_size -= 512;
|
||||
rom += 512;
|
||||
}
|
||||
|
||||
if(rom_size >= 0x410000) {
|
||||
mapper = EXHIROM;
|
||||
if(rom[0x7fd5] == 0x32) {
|
||||
mapper = EXLOROM;
|
||||
} else {
|
||||
mapper = EXHIROM;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -33,10 +47,17 @@ uint8 mapper;
|
||||
mapper = LOROM;
|
||||
}
|
||||
|
||||
if(rom[0x7fd5] == 0x32 && rom[0xffd5] == 0x32) {
|
||||
//SFA2 detected
|
||||
mapper = EXLOROM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
switch(mapper) {
|
||||
case LOROM: index = 0x007fc0;break;
|
||||
case HIROM: index = 0x00ffc0;break;
|
||||
case EXLOROM:index = 0x007fc0;break;
|
||||
case EXHIROM:index = 0x40ffc0;break;
|
||||
}
|
||||
memcpy(cart_title, (char*)rom + index, 21);
|
||||
@@ -53,7 +74,10 @@ end:
|
||||
case 7:sram_size = 128 * 1024;break;
|
||||
}
|
||||
|
||||
region = rom[index + 0x19];
|
||||
|
||||
dprintf("* Image Name : \"%s\"", cart_title);
|
||||
dprintf("* Region : %s", (region <= 1) ? "NTSC" : "PAL");
|
||||
dprintf("* MAD : %0.2x", mapper);
|
||||
dprintf("* SRAM Size : %dkb", sram_size / 1024);
|
||||
dprintf("* Reset:%0.4x NMI:%0.4x IRQ:%0.4x BRK[n]:%0.4x COP[n]:%0.4x BRK[e]:%0.4x COP[e]:%0.4x",
|
||||
@@ -76,12 +100,20 @@ CartInfo ci;
|
||||
switch(mapper) {
|
||||
case LOROM: cart = new bCartLoROM(); break;
|
||||
case HIROM: cart = new bCartHiROM(); break;
|
||||
case EXLOROM:cart = new bCartExLoROM();break;
|
||||
case EXHIROM:cart = new bCartExHiROM();break;
|
||||
default:return false;
|
||||
}
|
||||
|
||||
cart->set_cartinfo(&ci);
|
||||
rom_loaded = true;
|
||||
|
||||
if(region == 0 || region == 1) {
|
||||
snes->set_region(SNES::NTSC);
|
||||
} else {
|
||||
snes->set_region(SNES::PAL);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -108,7 +140,7 @@ bool bMemBus::save_sram(Writer *wf) {
|
||||
void bMemBus::unload_cart() {
|
||||
if(rom_loaded == false)return;
|
||||
|
||||
if(rom) free(rom);
|
||||
if(rom_image)free(rom_image);
|
||||
if(sram)free(sram);
|
||||
delete(cart);
|
||||
|
||||
@@ -139,70 +171,85 @@ 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;
|
||||
}
|
||||
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::MEM_READ, addr, r);
|
||||
#endif
|
||||
return 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;
|
||||
}
|
||||
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::MEM_WRITE, addr, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
void bMemBus::power() {
|
||||
@@ -211,7 +258,7 @@ void bMemBus::power() {
|
||||
}
|
||||
|
||||
void bMemBus::reset() {
|
||||
fastROM = false;
|
||||
set_speed(false);
|
||||
}
|
||||
|
||||
bMemBus::bMemBus() {
|
||||
@@ -221,5 +268,5 @@ bMemBus::bMemBus() {
|
||||
}
|
||||
|
||||
bMemBus::~bMemBus() {
|
||||
if(wram)free(wram);
|
||||
zerofree(wram);
|
||||
}
|
||||
@@ -1,23 +1,30 @@
|
||||
#include "bcart_lorom.h"
|
||||
#include "bcart_hirom.h"
|
||||
#include "bcart_exlorom.h"
|
||||
#include "bcart_exhirom.h"
|
||||
|
||||
class bMemBus : public MemBus {
|
||||
public:
|
||||
uint8 *rom, *sram, *wram;
|
||||
|
||||
//rom_image is the actual image, including header.
|
||||
//rom is the image sans header, which is actually
|
||||
//just a pointer to rom_image (with no header), or
|
||||
//rom_image + 512 (if a header is present).
|
||||
//rom should never be allocated or released directly.
|
||||
uint8 *rom_image, *rom, *sram, *wram;
|
||||
uint32 rom_size, sram_size;
|
||||
|
||||
bool rom_loaded;
|
||||
enum { LOROM = 0x20, HIROM = 0x21, EXHIROM = 0x25 };
|
||||
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();
|
||||
|
||||
+40
-24
@@ -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,40 +58,50 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
MMIO mmio_unmapped;
|
||||
uint8 MMIO::read (uint32 addr) { return 0x00; }
|
||||
uint8 MMIO::read (uint32 addr) { return r_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;
|
||||
}
|
||||
|
||||
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 +109,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 +120,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() {}
|
||||
+30
-17
@@ -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,28 @@ 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:
|
||||
inline uint8 speed(uint32 addr) {
|
||||
return speed_table[addr >> 9];
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
inline uint16 bPPU::addsub_pixels(uint32 cdest, uint32 csrc) {
|
||||
if(!regs.color_mode) {
|
||||
//add
|
||||
cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
|
||||
csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
|
||||
cdest += csrc;
|
||||
|
||||
if(regs.color_halve) {
|
||||
cdest >>= 1;
|
||||
} else {
|
||||
if(cdest & 0x04000000)cdest |= 0x03e00000;
|
||||
if(cdest & 0x00008000)cdest |= 0x00007c00;
|
||||
if(cdest & 0x00000020)cdest |= 0x0000001f;
|
||||
}
|
||||
|
||||
cdest &= 0x03e07c1f;
|
||||
return (cdest >> 16) | cdest;
|
||||
} else {
|
||||
//subtract
|
||||
if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00;
|
||||
else cdest -= (csrc & 0x7c00);
|
||||
if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0;
|
||||
else cdest -= (csrc & 0x03e0);
|
||||
if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f;
|
||||
else cdest -= (csrc & 0x001f);
|
||||
|
||||
return (!regs.color_halve) ? cdest : ((cdest & 0x7bde) >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
inline uint16 bPPU::addsub_pixel(uint32 cdest) {
|
||||
uint32 csrc = regs.color_rgb;
|
||||
if(!regs.color_mode) {
|
||||
//add
|
||||
cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
|
||||
csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
|
||||
cdest += csrc;
|
||||
|
||||
if(regs.color_halve && !regs.addsub_mode) {
|
||||
cdest >>= 1;
|
||||
} else {
|
||||
if(cdest & 0x04000000)cdest |= 0x03e00000;
|
||||
if(cdest & 0x00008000)cdest |= 0x00007c00;
|
||||
if(cdest & 0x00000020)cdest |= 0x0000001f;
|
||||
}
|
||||
|
||||
cdest &= 0x03e07c1f;
|
||||
return (cdest >> 16) | cdest;
|
||||
} else {
|
||||
//subtract
|
||||
if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00;
|
||||
else cdest -= (csrc & 0x7c00);
|
||||
if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0;
|
||||
else cdest -= (csrc & 0x03e0);
|
||||
if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f;
|
||||
else cdest -= (csrc & 0x001f);
|
||||
|
||||
if(regs.color_halve && !regs.addsub_mode) {
|
||||
return (cdest & 0x7bde) >> 1;
|
||||
}
|
||||
|
||||
return cdest;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
inline uint16 bPPU::get_palette(uint8 index) {
|
||||
return read16(cgram, index << 1);
|
||||
}
|
||||
|
||||
inline uint16 bPPU::get_direct_color(uint8 p, uint8 t) {
|
||||
//p = 00000bgr <palette data>
|
||||
//t = BBGGGRRR <tilemap data>
|
||||
//r = 0BBb00GGGg0RRRr0 <return data>
|
||||
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, src_back = get_palette(0);
|
||||
if(p->bg_main && p->bg_sub) {
|
||||
if(!p->color_exempt && regs.color_enabled[p->bg_main & 0x7f] && window_cache[COL].sub[x]) {
|
||||
if(regs.addsub_mode) {
|
||||
r = addsub_pixels(p->src_main, p->src_sub);
|
||||
} else {
|
||||
r = addsub_pixel(p->src_main);
|
||||
}
|
||||
} else {
|
||||
r = p->src_main;
|
||||
}
|
||||
} else if(p->bg_main) {
|
||||
if(!p->color_exempt && regs.color_enabled[p->bg_main & 0x7f] && window_cache[COL].sub[x]) {
|
||||
r = addsub_pixel(p->src_main);
|
||||
} else {
|
||||
r = p->src_main;
|
||||
}
|
||||
} else if(p->bg_sub) {
|
||||
if(regs.color_enabled[BACK]) {
|
||||
if(window_cache[COL].sub[x]) {
|
||||
if(regs.addsub_mode) {
|
||||
r = addsub_pixels(src_back, p->src_sub);
|
||||
} else {
|
||||
r = addsub_pixel(src_back);
|
||||
}
|
||||
} else {
|
||||
r = src_back;
|
||||
}
|
||||
} else {
|
||||
r = src_back; //was 0x0000 -- possibly another condition here?
|
||||
}
|
||||
} else {
|
||||
if(window_cache[COL].main[x]) {
|
||||
if(regs.color_enabled[BACK] && window_cache[COL].sub[x]) {
|
||||
r = addsub_pixel(src_back);
|
||||
} else {
|
||||
r = src_back;
|
||||
}
|
||||
} else {
|
||||
if(regs.color_enabled[BACK] && window_cache[COL].sub[x]) {
|
||||
r = (!regs.color_mode) ? regs.color_rgb : 0x0000;
|
||||
} else {
|
||||
r = 0x0000;
|
||||
}
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
inline void bPPU::render_line_output() {
|
||||
uint16 r, x;
|
||||
uint16 *ptr = (uint16*)output + (line.y * 1024) +
|
||||
((line.interlace && line.interlace_field) ? 512 : 0);
|
||||
uint16 *ltable = (uint16*)light_table + (regs.display_brightness << 15);
|
||||
|
||||
if(line.width == 256) {
|
||||
for(x=0;x<256;x++) {
|
||||
r = get_pixel(x);
|
||||
*ptr++ = *(ltable + r);
|
||||
}
|
||||
} else {
|
||||
for(x=0;x<512;x++) {
|
||||
r = get_pixel(x);
|
||||
*ptr++ = *(ltable + r);
|
||||
}
|
||||
}
|
||||
}
|
||||
+121
-113
@@ -5,18 +5,19 @@
|
||||
void bPPU::run() {}
|
||||
|
||||
void bPPU::scanline() {
|
||||
_y = cpu->vcounter();
|
||||
_screen_width = (regs.bg_mode == 5 || regs.bg_mode == 6)?512:256;
|
||||
_interlace = cpu->interlace();
|
||||
_interlace_field = cpu->interlace_field();
|
||||
line.y = r_cpu->vcounter();
|
||||
line.width = (regs.bg_mode == 5 || regs.bg_mode == 6) ? 512 : 256;
|
||||
line.hires = (regs.bg_mode == 5 || regs.bg_mode == 6);
|
||||
line.interlace = r_cpu->interlace();
|
||||
line.interlace_field = r_cpu->interlace_field();
|
||||
|
||||
if(_y == 0) {
|
||||
if(line.y == 0) {
|
||||
//RTO flag reset
|
||||
regs.time_over = false;
|
||||
regs.range_over = false;
|
||||
}
|
||||
|
||||
if(_y == 1) {
|
||||
if(line.y == 1) {
|
||||
//OAM FirstSprite priority set
|
||||
if(regs.oam_priority == true) {
|
||||
regs.oam_firstsprite = (regs.oam_addr & 0xfe) >> 1;
|
||||
@@ -25,65 +26,46 @@ void bPPU::scanline() {
|
||||
}
|
||||
}
|
||||
|
||||
if(_y == (cpu->overscan()?239:224) && regs.display_disabled == false) {
|
||||
if(line.y == (r_cpu->overscan() ? 239 : 224) && regs.display_disabled == false) {
|
||||
//OAM address reset
|
||||
regs.oam_addr = ((regs.oam_addrh << 8) | regs.oam_addrl) << 1;
|
||||
}
|
||||
}
|
||||
|
||||
//only allow frameskip setting to ignore actual rendering; not RTO, etc.
|
||||
if(settings.frameskip_pos != 0)return;
|
||||
void bPPU::render_scanline() {
|
||||
if(status.render_output == false)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(line.y > 0 && line.y < (r_cpu->overscan() ? 239 : 224)) {
|
||||
render_line();
|
||||
}
|
||||
}
|
||||
|
||||
void bPPU::frame() {
|
||||
if(settings.frameskip_changed == true) {
|
||||
settings.frameskip_changed = false;
|
||||
settings.frameskip_pos = 0;
|
||||
} else {
|
||||
settings.frameskip_pos++;
|
||||
settings.frameskip_pos %= (settings.frameskip + 1);
|
||||
}
|
||||
|
||||
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) {
|
||||
settings.frameskip = fs;
|
||||
settings.frameskip_changed = true;
|
||||
PPU::frame();
|
||||
}
|
||||
|
||||
void bPPU::power() {
|
||||
PPU::power();
|
||||
|
||||
memset(vram, 0, 65536);
|
||||
memset(oam, 0, 544);
|
||||
memset(cgram, 0, 512);
|
||||
|
||||
region = snes->region();
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void bPPU::reset() {
|
||||
memset(output->buffer, 0, 512 * 478 * 2);
|
||||
PPU::reset();
|
||||
frame();
|
||||
|
||||
memset(sprite_list, 0, sizeof(sprite_list));
|
||||
|
||||
//open bus support
|
||||
regs.ppu1_mdr = 0xff;
|
||||
regs.ppu2_mdr = 0xff;
|
||||
|
||||
//$2100
|
||||
regs.display_disabled = 0;
|
||||
regs.display_brightness = 0;
|
||||
@@ -133,6 +115,8 @@ void bPPU::reset() {
|
||||
regs.bg_tdaddr[BG4] = 0x0000;
|
||||
|
||||
//$210d-$2114
|
||||
regs.bg_ofslatch = 0x00;
|
||||
regs.m7_hofs = regs.m7_vofs = 0x0000;
|
||||
regs.bg_hofs[BG1] = regs.bg_vofs[BG1] = 0x0000;
|
||||
regs.bg_hofs[BG2] = regs.bg_vofs[BG2] = 0x0000;
|
||||
regs.bg_hofs[BG3] = regs.bg_vofs[BG3] = 0x0000;
|
||||
@@ -152,6 +136,7 @@ void bPPU::reset() {
|
||||
regs.mode7_hflip = false;
|
||||
|
||||
//$211b-$2120
|
||||
regs.m7_latch = 0x00;
|
||||
regs.m7a = 0x0000;
|
||||
regs.m7b = 0x0000;
|
||||
regs.m7c = 0x0000;
|
||||
@@ -163,30 +148,33 @@ void bPPU::reset() {
|
||||
regs.cgram_addr = 0x0000;
|
||||
|
||||
//$2123-$2125
|
||||
regs.bg_window1_enabled[BG1] = false;
|
||||
regs.bg_window1_enabled[BG2] = false;
|
||||
regs.bg_window1_enabled[BG3] = false;
|
||||
regs.bg_window1_enabled[BG4] = false;
|
||||
regs.bg_window1_enabled[OAM] = false;
|
||||
regs.bg_window1_invert [BG1] = false;
|
||||
regs.bg_window1_invert [BG2] = false;
|
||||
regs.bg_window1_invert [BG3] = false;
|
||||
regs.bg_window1_invert [BG4] = false;
|
||||
regs.bg_window1_invert [OAM] = false;
|
||||
regs.bg_window2_enabled[BG1] = false;
|
||||
regs.bg_window2_enabled[BG2] = false;
|
||||
regs.bg_window2_enabled[BG3] = false;
|
||||
regs.bg_window2_enabled[BG4] = false;
|
||||
regs.bg_window2_enabled[OAM] = false;
|
||||
regs.bg_window2_invert [BG1] = false;
|
||||
regs.bg_window2_invert [BG2] = false;
|
||||
regs.bg_window2_invert [BG3] = false;
|
||||
regs.bg_window2_invert [BG4] = false;
|
||||
regs.bg_window2_invert [OAM] = false;
|
||||
regs.color_window1_enabled = false;
|
||||
regs.color_window1_invert = false;
|
||||
regs.color_window2_enabled = false;
|
||||
regs.color_window2_invert = false;
|
||||
regs.window1_enabled[BG1] = false;
|
||||
regs.window1_enabled[BG2] = false;
|
||||
regs.window1_enabled[BG3] = false;
|
||||
regs.window1_enabled[BG4] = false;
|
||||
regs.window1_enabled[OAM] = false;
|
||||
regs.window1_enabled[COL] = false;
|
||||
|
||||
regs.window1_invert [BG1] = false;
|
||||
regs.window1_invert [BG2] = false;
|
||||
regs.window1_invert [BG3] = false;
|
||||
regs.window1_invert [BG4] = false;
|
||||
regs.window1_invert [OAM] = false;
|
||||
regs.window1_invert [COL] = false;
|
||||
|
||||
regs.window2_enabled[BG1] = false;
|
||||
regs.window2_enabled[BG2] = false;
|
||||
regs.window2_enabled[BG3] = false;
|
||||
regs.window2_enabled[BG4] = false;
|
||||
regs.window2_enabled[OAM] = false;
|
||||
regs.window2_enabled[COL] = false;
|
||||
|
||||
regs.window2_invert [BG1] = false;
|
||||
regs.window2_invert [BG2] = false;
|
||||
regs.window2_invert [BG3] = false;
|
||||
regs.window2_invert [BG4] = false;
|
||||
regs.window2_invert [OAM] = false;
|
||||
regs.window2_invert [COL] = false;
|
||||
|
||||
//$2126-$2129
|
||||
regs.window1_left = 0;
|
||||
@@ -195,12 +183,12 @@ void bPPU::reset() {
|
||||
regs.window2_right = 0;
|
||||
|
||||
//$212a-$212b
|
||||
regs.bg_window_mask[BG1] = 0;
|
||||
regs.bg_window_mask[BG2] = 0;
|
||||
regs.bg_window_mask[BG3] = 0;
|
||||
regs.bg_window_mask[BG4] = 0;
|
||||
regs.bg_window_mask[OAM] = 0;
|
||||
regs.color_window_mask = 0;
|
||||
regs.window_mask[BG1] = 0;
|
||||
regs.window_mask[BG2] = 0;
|
||||
regs.window_mask[BG3] = 0;
|
||||
regs.window_mask[BG4] = 0;
|
||||
regs.window_mask[OAM] = 0;
|
||||
regs.window_mask[COL] = 0;
|
||||
|
||||
//$212c-$212d
|
||||
regs.bg_enabled[BG1] = false;
|
||||
@@ -215,16 +203,16 @@ void bPPU::reset() {
|
||||
regs.bgsub_enabled[OAM] = false;
|
||||
|
||||
//$212e-$212f
|
||||
regs.bg_window_enabled[BG1] = false;
|
||||
regs.bg_window_enabled[BG2] = false;
|
||||
regs.bg_window_enabled[BG3] = false;
|
||||
regs.bg_window_enabled[BG4] = false;
|
||||
regs.bg_window_enabled[OAM] = false;
|
||||
regs.bgsub_window_enabled[BG1] = false;
|
||||
regs.bgsub_window_enabled[BG2] = false;
|
||||
regs.bgsub_window_enabled[BG3] = false;
|
||||
regs.bgsub_window_enabled[BG4] = false;
|
||||
regs.bgsub_window_enabled[OAM] = false;
|
||||
regs.window_enabled[BG1] = false;
|
||||
regs.window_enabled[BG2] = false;
|
||||
regs.window_enabled[BG3] = false;
|
||||
regs.window_enabled[BG4] = false;
|
||||
regs.window_enabled[OAM] = false;
|
||||
regs.sub_window_enabled[BG1] = false;
|
||||
regs.sub_window_enabled[BG2] = false;
|
||||
regs.sub_window_enabled[BG3] = false;
|
||||
regs.sub_window_enabled[BG4] = false;
|
||||
regs.sub_window_enabled[OAM] = false;
|
||||
|
||||
//$2130
|
||||
regs.color_mask = 0;
|
||||
@@ -232,19 +220,20 @@ void bPPU::reset() {
|
||||
regs.addsub_mode = 0;
|
||||
|
||||
//$2131
|
||||
regs.color_mode = 0;
|
||||
regs.color_halve = false;
|
||||
regs.bg_color_enabled[BACK] = false;
|
||||
regs.bg_color_enabled[OAM] = false;
|
||||
regs.bg_color_enabled[BG4] = false;
|
||||
regs.bg_color_enabled[BG3] = false;
|
||||
regs.bg_color_enabled[BG2] = false;
|
||||
regs.bg_color_enabled[BG1] = false;
|
||||
regs.color_mode = 0;
|
||||
regs.color_halve = false;
|
||||
regs.color_enabled[BACK] = false;
|
||||
regs.color_enabled[OAM] = false;
|
||||
regs.color_enabled[BG4] = false;
|
||||
regs.color_enabled[BG3] = false;
|
||||
regs.color_enabled[BG2] = false;
|
||||
regs.color_enabled[BG1] = false;
|
||||
|
||||
//$2132
|
||||
regs.color_r = 0x00;
|
||||
regs.color_g = 0x00;
|
||||
regs.color_b = 0x00;
|
||||
regs.color_r = 0x00;
|
||||
regs.color_g = 0x00;
|
||||
regs.color_b = 0x00;
|
||||
regs.color_rgb = 0x0000;
|
||||
|
||||
//$2133
|
||||
regs.mode7_extbg = false;
|
||||
@@ -267,27 +256,35 @@ void bPPU::reset() {
|
||||
regs.time_over = false;
|
||||
regs.range_over = false;
|
||||
|
||||
line.width = 256; //needed for clear_window_cache()
|
||||
update_sprite_list_sizes();
|
||||
clear_tiledata_cache();
|
||||
clear_window_cache();
|
||||
}
|
||||
|
||||
uint8 bPPU::vram_read(uint16 addr) {
|
||||
uint8 r;
|
||||
r = vram[addr];
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::VRAM_READ, addr, r);
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
void bPPU::vram_write(uint16 addr, uint8 value) {
|
||||
vram[addr] = value;
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::VRAM_WRITE, addr, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8 bPPU::oam_read(uint16 addr) {
|
||||
uint8 r;
|
||||
if(addr >= 0x0200)addr = 0x0200 | (addr & 31);
|
||||
r = oam[addr];
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::OAM_READ, addr, r);
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -295,53 +292,63 @@ void bPPU::oam_write(uint16 addr, uint8 value) {
|
||||
if(addr >= 0x0200)addr = 0x0200 | (addr & 31);
|
||||
oam[addr] = value;
|
||||
update_sprite_list(addr);
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::OAM_WRITE, addr, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8 bPPU::cgram_read(uint16 addr) {
|
||||
uint8 r;
|
||||
r = cgram[addr & 511];
|
||||
addr &= 511;
|
||||
r = cgram[addr];
|
||||
if(addr & 1) {
|
||||
r &= 0x7f;
|
||||
}
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::CGRAM_READ, addr, r);
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
void bPPU::cgram_write(uint16 addr, uint8 value) {
|
||||
cgram[addr & 511] = value;
|
||||
addr &= 511;
|
||||
if(addr & 1) {
|
||||
value &= 0x7f;
|
||||
}
|
||||
cgram[addr] = value;
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::CGRAM_WRITE, addr, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
bPPU::bPPU() {
|
||||
settings.frameskip = 0;
|
||||
settings.frameskip_pos = 0;
|
||||
settings.frameskip_changed = false;
|
||||
|
||||
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);
|
||||
|
||||
init_tiledata_cache();
|
||||
|
||||
int i, l;
|
||||
byte r, g, b;
|
||||
double m;
|
||||
int i, l;
|
||||
uint8 r, g, b;
|
||||
double m;
|
||||
uint16 *ptr;
|
||||
for(l=0;l<16;l++) {
|
||||
mosaic_table[l] = (uint16*)memalloc(4096 * 2, "bPPU::mosaic_table[%2d]", l);
|
||||
mosaic_table[l] = (uint16*)malloc(4096 * 2);
|
||||
for(i=0;i<4096;i++) {
|
||||
mosaic_table[l][i] = (i / (l + 1)) * (l + 1);
|
||||
}
|
||||
}
|
||||
|
||||
light_table = (uint16*)memalloc(16 * 65536 * 2, "bPPU::light_table");
|
||||
ptr = (word*)light_table;
|
||||
light_table = (uint16*)malloc(16 * 32768 * 2);
|
||||
ptr = (uint16*)light_table;
|
||||
for(l=0;l<16;l++) {
|
||||
m = (double)l / 15.0;
|
||||
for(i=0;i<65536;i++) {
|
||||
for(i=0;i<32768;i++) {
|
||||
r = (i ) & 31;
|
||||
g = (i >> 5) & 31;
|
||||
b = (i >> 10) & 31;
|
||||
@@ -360,14 +367,15 @@ uint16 *ptr;
|
||||
bPPU::~bPPU() {
|
||||
delete(mmio);
|
||||
|
||||
if(vram) memfree(vram, "bPPU::vram");
|
||||
if(oam) memfree(oam, "bPPU::oam");
|
||||
if(cgram)memfree(cgram, "bPPU::cgram");
|
||||
zerofree(vram);
|
||||
zerofree(oam);
|
||||
zerofree(cgram);
|
||||
|
||||
for(int i=0;i<16;i++) {
|
||||
if(mosaic_table[i])memfree(mosaic_table[i], "bPPU::mosaic_table[%2d]", i);
|
||||
zerofree(mosaic_table[i]);
|
||||
}
|
||||
if(light_table)memfree(light_table, "bPPU::light_table");
|
||||
|
||||
zerofree(light_table);
|
||||
}
|
||||
|
||||
bPPUMMIO::bPPUMMIO(bPPU *_ppu) {
|
||||
|
||||
+35
-21
@@ -11,9 +11,19 @@ bPPU *ppu;
|
||||
class bPPU : public PPU {
|
||||
public:
|
||||
uint8 *vram, *oam, *cgram;
|
||||
uint8 region;
|
||||
|
||||
enum { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5 };
|
||||
enum { SC_32x32 = 0, SC_32x64 = 1, SC_64x32 = 2, SC_64x64 = 3 };
|
||||
enum { NTSC = 0, PAL = 1 };
|
||||
enum { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5, COL = 5 };
|
||||
enum { SC_32x32 = 0, SC_64x32 = 1, SC_32x64 = 2, SC_64x64 = 3 };
|
||||
|
||||
struct {
|
||||
uint32 y;
|
||||
uint32 width;
|
||||
bool hires;
|
||||
bool interlace;
|
||||
bool interlace_field;
|
||||
} line;
|
||||
|
||||
struct sprite_item {
|
||||
uint8 width, height;
|
||||
@@ -23,14 +33,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;
|
||||
//open bus support
|
||||
uint8 ppu1_mdr, ppu2_mdr;
|
||||
|
||||
struct {
|
||||
//$2100
|
||||
bool display_disabled;
|
||||
uint8 display_brightness;
|
||||
@@ -64,6 +72,8 @@ struct {
|
||||
uint16 bg_tdaddr[4];
|
||||
|
||||
//$210d-$2114
|
||||
uint8 bg_ofslatch;
|
||||
uint16 m7_hofs, m7_vofs;
|
||||
uint16 bg_hofs[4];
|
||||
uint16 bg_vofs[4];
|
||||
|
||||
@@ -81,43 +91,43 @@ struct {
|
||||
bool mode7_hflip;
|
||||
|
||||
//$211b-$2120
|
||||
uint8 m7_latch;
|
||||
uint16 m7a, m7b, m7c, m7d, m7x, m7y;
|
||||
|
||||
//$2121
|
||||
uint16 cgram_addr;
|
||||
|
||||
//$2123-$2125
|
||||
bool bg_window1_enabled[5];
|
||||
bool bg_window1_invert [5];
|
||||
bool bg_window2_enabled[5];
|
||||
bool bg_window2_invert [5];
|
||||
bool color_window1_enabled, color_window1_invert;
|
||||
bool color_window2_enabled, color_window2_invert;
|
||||
bool window1_enabled[6];
|
||||
bool window1_invert [6];
|
||||
bool window2_enabled[6];
|
||||
bool window2_invert [6];
|
||||
|
||||
//$2126-$2129
|
||||
uint8 window1_left, window1_right;
|
||||
uint8 window2_left, window2_right;
|
||||
|
||||
//$212a-$212b
|
||||
uint8 bg_window_mask[5];
|
||||
uint8 color_window_mask;
|
||||
uint8 window_mask[6];
|
||||
|
||||
//$212c-$212d
|
||||
bool bg_enabled[5], bgsub_enabled[5];
|
||||
|
||||
//$212e-$212f
|
||||
bool bg_window_enabled[5], bgsub_window_enabled[5];
|
||||
bool window_enabled[5], sub_window_enabled[5];
|
||||
|
||||
//$2130
|
||||
uint8 color_mask, colorsub_mask;
|
||||
bool addsub_mode;
|
||||
bool direct_color;
|
||||
|
||||
//$2131
|
||||
bool color_mode, color_halve;
|
||||
bool bg_color_enabled[6];
|
||||
bool color_enabled[6];
|
||||
|
||||
//$2132
|
||||
uint8 color_r, color_g, color_b;
|
||||
uint16 color_rgb;
|
||||
|
||||
//$2133
|
||||
bool mode7_extbg;
|
||||
@@ -137,7 +147,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);
|
||||
@@ -149,6 +159,8 @@ struct {
|
||||
void update_sprite_list(uint16 addr);
|
||||
void update_sprite_list_sizes();
|
||||
uint16 get_vram_address();
|
||||
bool vram_can_read();
|
||||
bool vram_can_write(uint8 &value);
|
||||
|
||||
void mmio_w2100(uint8 value); //INIDISP
|
||||
void mmio_w2101(uint8 value); //OBSEL
|
||||
@@ -217,7 +229,7 @@ struct {
|
||||
|
||||
void latch_counters();
|
||||
|
||||
/* PPU render functions */
|
||||
//PPU render functions
|
||||
|
||||
#include "bppu_render.h"
|
||||
|
||||
@@ -226,13 +238,15 @@ 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 scanline_is_hires() { return (regs.bg_mode == 5 || regs.bg_mode == 6); }
|
||||
|
||||
bPPU();
|
||||
~bPPU();
|
||||
|
||||
+324
-120
@@ -1,6 +1,6 @@
|
||||
void bPPU::latch_counters() {
|
||||
regs.hcounter = cpu->hcounter();
|
||||
regs.vcounter = cpu->vcounter();
|
||||
regs.hcounter = r_cpu->hcounter();
|
||||
regs.vcounter = r_cpu->vcounter();
|
||||
regs.counters_latched = true;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,55 @@ uint16 addr;
|
||||
return (addr << 1);
|
||||
}
|
||||
|
||||
bool bPPU::vram_can_read() {
|
||||
if(regs.display_disabled == true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16 v = r_cpu->vcounter();
|
||||
uint16 hc = r_cpu->hcycles();
|
||||
uint16 ls;
|
||||
if(r_cpu->interlace() && !r_cpu->interlace_field()) {
|
||||
ls = r_cpu->region_scanlines();
|
||||
} else {
|
||||
ls = r_cpu->region_scanlines() - 1;
|
||||
}
|
||||
|
||||
if(v == ls && hc == 1362)return false;
|
||||
|
||||
if(v < (r_cpu->overscan() ? 239 : 224))return false;
|
||||
|
||||
if(v == (r_cpu->overscan() ? 239 : 224)) {
|
||||
if(hc == 1362)return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bPPU::vram_can_write(uint8 &value) {
|
||||
if(regs.display_disabled == true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16 v = r_cpu->vcounter();
|
||||
uint16 hc = r_cpu->hcycles();
|
||||
if(v == 0) {
|
||||
if(hc <= 4)return true;
|
||||
if(hc == 6) { value = r_cpu->regs.mdr; return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
if(v < (r_cpu->overscan() ? 240 : 225))return false;
|
||||
|
||||
if(v == (r_cpu->overscan() ? 240 : 225)) {
|
||||
if(hc <= 4)return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//INIDISP
|
||||
void bPPU::mmio_w2100(uint8 value) {
|
||||
regs.display_disabled = !!(value & 0x80);
|
||||
@@ -68,6 +117,13 @@ void bPPU::mmio_w2105(uint8 value) {
|
||||
regs.bg_tilesize[BG1] = !!(value & 0x10);
|
||||
regs.bg3_priority = !!(value & 0x08);
|
||||
regs.bg_mode = (value & 7);
|
||||
|
||||
window_cache[BG1].main_dirty = window_cache[BG1].sub_dirty = true;
|
||||
window_cache[BG2].main_dirty = window_cache[BG2].sub_dirty = true;
|
||||
window_cache[BG3].main_dirty = window_cache[BG3].sub_dirty = true;
|
||||
window_cache[BG4].main_dirty = window_cache[BG4].sub_dirty = true;
|
||||
window_cache[OAM].main_dirty = window_cache[OAM].sub_dirty = true;
|
||||
window_cache[COL].main_dirty = window_cache[COL].sub_dirty = true;
|
||||
}
|
||||
|
||||
//MOSAIC
|
||||
@@ -117,42 +173,56 @@ void bPPU::mmio_w210c(uint8 value) {
|
||||
|
||||
//BG1HOFS
|
||||
void bPPU::mmio_w210d(uint8 value) {
|
||||
regs.bg_hofs[BG1] = (value << 8) | (regs.bg_hofs[BG1] >> 8);
|
||||
regs.m7_hofs = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
|
||||
regs.bg_hofs[BG1] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_hofs[BG1] >> 8) & 7);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//BG1VOFS
|
||||
void bPPU::mmio_w210e(uint8 value) {
|
||||
regs.bg_vofs[BG1] = (value << 8) | (regs.bg_vofs[BG1] >> 8);
|
||||
regs.m7_vofs = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
|
||||
regs.bg_vofs[BG1] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_vofs[BG1] >> 8) & 7);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//BG2HOFS
|
||||
void bPPU::mmio_w210f(uint8 value) {
|
||||
regs.bg_hofs[BG2] = (value << 8) | (regs.bg_hofs[BG2] >> 8);
|
||||
regs.bg_hofs[BG2] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_hofs[BG2] >> 8) & 7);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//BG2VOFS
|
||||
void bPPU::mmio_w2110(uint8 value) {
|
||||
regs.bg_vofs[BG2] = (value << 8) | (regs.bg_vofs[BG2] >> 8);
|
||||
regs.bg_vofs[BG2] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_vofs[BG2] >> 8) & 7);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//BG3HOFS
|
||||
void bPPU::mmio_w2111(uint8 value) {
|
||||
regs.bg_hofs[BG3] = (value << 8) | (regs.bg_hofs[BG3] >> 8);
|
||||
regs.bg_hofs[BG3] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_hofs[BG3] >> 8) & 7);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//BG3VOFS
|
||||
void bPPU::mmio_w2112(uint8 value) {
|
||||
regs.bg_vofs[BG3] = (value << 8) | (regs.bg_vofs[BG3] >> 8);
|
||||
regs.bg_vofs[BG3] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_vofs[BG3] >> 8) & 7);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//BG4HOFS
|
||||
void bPPU::mmio_w2113(uint8 value) {
|
||||
regs.bg_hofs[BG4] = (value << 8) | (regs.bg_hofs[BG4] >> 8);
|
||||
regs.bg_hofs[BG4] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_hofs[BG4] >> 8) & 7);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//BG4VOFS
|
||||
void bPPU::mmio_w2114(uint8 value) {
|
||||
regs.bg_vofs[BG4] = (value << 8) | (regs.bg_vofs[BG4] >> 8);
|
||||
regs.bg_vofs[BG4] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_vofs[BG4] >> 8) & 7);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//VMAIN
|
||||
@@ -171,77 +241,97 @@ void bPPU::mmio_w2115(uint8 value) {
|
||||
void bPPU::mmio_w2116(uint8 value) {
|
||||
regs.vram_addr = (regs.vram_addr & 0xff00) | value;
|
||||
uint16 addr = get_vram_address();
|
||||
regs.vram_readbuffer = vram_read(addr);
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
if(vram_can_read()) {
|
||||
regs.vram_readbuffer = vram_read(addr);
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
} else {
|
||||
regs.vram_readbuffer = 0x0000;
|
||||
}
|
||||
}
|
||||
|
||||
//VMADDH
|
||||
void bPPU::mmio_w2117(uint8 value) {
|
||||
regs.vram_addr = (value << 8) | (regs.vram_addr & 0x00ff);
|
||||
uint16 addr = get_vram_address();
|
||||
regs.vram_readbuffer = vram_read(addr);
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
if(vram_can_read()) {
|
||||
regs.vram_readbuffer = vram_read(addr);
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
} else {
|
||||
regs.vram_readbuffer = 0x0000;
|
||||
}
|
||||
}
|
||||
|
||||
//VMDATAL
|
||||
void bPPU::mmio_w2118(uint8 value) {
|
||||
uint16 addr = get_vram_address();
|
||||
vram_write(addr, value);
|
||||
if(vram_can_write(value)) {
|
||||
vram_write(addr, value);
|
||||
bg_tiledata_state[TILE_2BIT][(addr >> 4)] = 1;
|
||||
bg_tiledata_state[TILE_4BIT][(addr >> 5)] = 1;
|
||||
bg_tiledata_state[TILE_8BIT][(addr >> 6)] = 1;
|
||||
}
|
||||
|
||||
if(regs.vram_incmode == 0) {
|
||||
regs.vram_addr += regs.vram_incsize;
|
||||
}
|
||||
bg_tiledata_state[TILE_2BIT][(addr >> 4)] = 1;
|
||||
bg_tiledata_state[TILE_4BIT][(addr >> 5)] = 1;
|
||||
bg_tiledata_state[TILE_8BIT][(addr >> 6)] = 1;
|
||||
}
|
||||
|
||||
//VMDATAH
|
||||
void bPPU::mmio_w2119(uint8 value) {
|
||||
uint16 addr = get_vram_address() + 1;
|
||||
vram_write(addr, value);
|
||||
if(vram_can_write(value)) {
|
||||
vram_write(addr, value);
|
||||
bg_tiledata_state[TILE_2BIT][(addr >> 4)] = 1;
|
||||
bg_tiledata_state[TILE_4BIT][(addr >> 5)] = 1;
|
||||
bg_tiledata_state[TILE_8BIT][(addr >> 6)] = 1;
|
||||
}
|
||||
|
||||
if(regs.vram_incmode == 1) {
|
||||
regs.vram_addr += regs.vram_incsize;
|
||||
}
|
||||
bg_tiledata_state[TILE_2BIT][(addr >> 4)] = 1;
|
||||
bg_tiledata_state[TILE_4BIT][(addr >> 5)] = 1;
|
||||
bg_tiledata_state[TILE_8BIT][(addr >> 6)] = 1;
|
||||
}
|
||||
|
||||
//M7SEL
|
||||
void bPPU::mmio_w211a(uint8 value) {
|
||||
regs.mode7_repeat = (value >> 6) & 3;
|
||||
regs.mode7_vflip = !!(value & 0x02);
|
||||
regs.mode7_hflip = !!(value & 0x01);
|
||||
regs.mode7_vflip = !!(value & 0x02);
|
||||
regs.mode7_hflip = !!(value & 0x01);
|
||||
}
|
||||
|
||||
//M7A
|
||||
void bPPU::mmio_w211b(uint8 value) {
|
||||
regs.m7a = (value << 8) | (regs.m7a >> 8);
|
||||
regs.m7a = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
}
|
||||
|
||||
//M7B
|
||||
void bPPU::mmio_w211c(uint8 value) {
|
||||
regs.m7b = (value << 8) | (regs.m7b >> 8);
|
||||
regs.m7b = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
}
|
||||
|
||||
//M7C
|
||||
void bPPU::mmio_w211d(uint8 value) {
|
||||
regs.m7c = (value << 8) | (regs.m7c >> 8);
|
||||
regs.m7c = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
}
|
||||
|
||||
//M7D
|
||||
void bPPU::mmio_w211e(uint8 value) {
|
||||
regs.m7d = (value << 8) | (regs.m7d >> 8);
|
||||
regs.m7d = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
}
|
||||
|
||||
//M7X
|
||||
void bPPU::mmio_w211f(uint8 value) {
|
||||
regs.m7x = (value << 8) | (regs.m7x >> 8);
|
||||
regs.m7x = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
}
|
||||
|
||||
//M7Y
|
||||
void bPPU::mmio_w2120(uint8 value) {
|
||||
regs.m7y = (value << 8) | (regs.m7y >> 8);
|
||||
regs.m7y = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
}
|
||||
|
||||
//CGADD
|
||||
@@ -250,7 +340,13 @@ void bPPU::mmio_w2121(uint8 value) {
|
||||
}
|
||||
|
||||
//CGDATA
|
||||
//note: CGRAM palette data format is 15-bits
|
||||
//(0,bbbbb,ggggg,rrrrr). Highest bit is ignored,
|
||||
//as evidenced by $213b CGRAM data reads.
|
||||
void bPPU::mmio_w2122(uint8 value) {
|
||||
if(regs.cgram_addr & 1) {
|
||||
value &= 0x7f;
|
||||
}
|
||||
cgram_write(regs.cgram_addr, value);
|
||||
regs.cgram_addr++;
|
||||
regs.cgram_addr &= 0x01ff;
|
||||
@@ -258,72 +354,117 @@ void bPPU::mmio_w2122(uint8 value) {
|
||||
|
||||
//W12SEL
|
||||
void bPPU::mmio_w2123(uint8 value) {
|
||||
regs.bg_window2_enabled[BG2] = !!(value & 0x80);
|
||||
regs.bg_window2_invert [BG2] = !!(value & 0x40);
|
||||
regs.bg_window1_enabled[BG2] = !!(value & 0x20);
|
||||
regs.bg_window1_invert [BG2] = !!(value & 0x10);
|
||||
regs.bg_window2_enabled[BG1] = !!(value & 0x08);
|
||||
regs.bg_window2_invert [BG1] = !!(value & 0x04);
|
||||
regs.bg_window1_enabled[BG1] = !!(value & 0x02);
|
||||
regs.bg_window1_invert [BG1] = !!(value & 0x01);
|
||||
regs.window2_enabled[BG2] = !!(value & 0x80);
|
||||
regs.window2_invert [BG2] = !!(value & 0x40);
|
||||
regs.window1_enabled[BG2] = !!(value & 0x20);
|
||||
regs.window1_invert [BG2] = !!(value & 0x10);
|
||||
regs.window2_enabled[BG1] = !!(value & 0x08);
|
||||
regs.window2_invert [BG1] = !!(value & 0x04);
|
||||
regs.window1_enabled[BG1] = !!(value & 0x02);
|
||||
regs.window1_invert [BG1] = !!(value & 0x01);
|
||||
|
||||
window_cache[BG1].main_dirty = window_cache[BG1].sub_dirty = true;
|
||||
window_cache[BG2].main_dirty = window_cache[BG2].sub_dirty = true;
|
||||
}
|
||||
|
||||
//W34SEL
|
||||
void bPPU::mmio_w2124(uint8 value) {
|
||||
regs.bg_window2_enabled[BG4] = !!(value & 0x80);
|
||||
regs.bg_window2_invert [BG4] = !!(value & 0x40);
|
||||
regs.bg_window1_enabled[BG4] = !!(value & 0x20);
|
||||
regs.bg_window1_invert [BG4] = !!(value & 0x10);
|
||||
regs.bg_window2_enabled[BG3] = !!(value & 0x08);
|
||||
regs.bg_window2_invert [BG3] = !!(value & 0x04);
|
||||
regs.bg_window1_enabled[BG3] = !!(value & 0x02);
|
||||
regs.bg_window1_invert [BG3] = !!(value & 0x01);
|
||||
regs.window2_enabled[BG4] = !!(value & 0x80);
|
||||
regs.window2_invert [BG4] = !!(value & 0x40);
|
||||
regs.window1_enabled[BG4] = !!(value & 0x20);
|
||||
regs.window1_invert [BG4] = !!(value & 0x10);
|
||||
regs.window2_enabled[BG3] = !!(value & 0x08);
|
||||
regs.window2_invert [BG3] = !!(value & 0x04);
|
||||
regs.window1_enabled[BG3] = !!(value & 0x02);
|
||||
regs.window1_invert [BG3] = !!(value & 0x01);
|
||||
|
||||
window_cache[BG3].main_dirty = window_cache[BG3].sub_dirty = true;
|
||||
window_cache[BG4].main_dirty = window_cache[BG4].sub_dirty = true;
|
||||
}
|
||||
|
||||
//WOBJSEL
|
||||
void bPPU::mmio_w2125(uint8 value) {
|
||||
regs.color_window2_enabled = !!(value & 0x80);
|
||||
regs.color_window2_invert = !!(value & 0x40);
|
||||
regs.color_window1_enabled = !!(value & 0x20);
|
||||
regs.color_window1_invert = !!(value & 0x10);
|
||||
regs.bg_window2_enabled[OAM] = !!(value & 0x08);
|
||||
regs.bg_window2_invert [OAM] = !!(value & 0x04);
|
||||
regs.bg_window1_enabled[OAM] = !!(value & 0x02);
|
||||
regs.bg_window1_invert [OAM] = !!(value & 0x01);
|
||||
regs.window2_enabled[COL] = !!(value & 0x80);
|
||||
regs.window2_invert [COL] = !!(value & 0x40);
|
||||
regs.window1_enabled[COL] = !!(value & 0x20);
|
||||
regs.window1_invert [COL] = !!(value & 0x10);
|
||||
regs.window2_enabled[OAM] = !!(value & 0x08);
|
||||
regs.window2_invert [OAM] = !!(value & 0x04);
|
||||
regs.window1_enabled[OAM] = !!(value & 0x02);
|
||||
regs.window1_invert [OAM] = !!(value & 0x01);
|
||||
|
||||
window_cache[OAM].main_dirty = window_cache[OAM].sub_dirty = true;
|
||||
window_cache[COL].main_dirty = window_cache[COL].sub_dirty = true;
|
||||
}
|
||||
|
||||
//WH0
|
||||
void bPPU::mmio_w2126(uint8 value) {
|
||||
regs.window1_left = value;
|
||||
|
||||
window_cache[BG1].main_dirty = window_cache[BG1].sub_dirty = true;
|
||||
window_cache[BG2].main_dirty = window_cache[BG2].sub_dirty = true;
|
||||
window_cache[BG3].main_dirty = window_cache[BG3].sub_dirty = true;
|
||||
window_cache[BG4].main_dirty = window_cache[BG4].sub_dirty = true;
|
||||
window_cache[OAM].main_dirty = window_cache[OAM].sub_dirty = true;
|
||||
window_cache[COL].main_dirty = window_cache[COL].sub_dirty = true;
|
||||
}
|
||||
|
||||
//WH1
|
||||
void bPPU::mmio_w2127(uint8 value) {
|
||||
regs.window1_right = value;
|
||||
|
||||
window_cache[BG1].main_dirty = window_cache[BG1].sub_dirty = true;
|
||||
window_cache[BG2].main_dirty = window_cache[BG2].sub_dirty = true;
|
||||
window_cache[BG3].main_dirty = window_cache[BG3].sub_dirty = true;
|
||||
window_cache[BG4].main_dirty = window_cache[BG4].sub_dirty = true;
|
||||
window_cache[OAM].main_dirty = window_cache[OAM].sub_dirty = true;
|
||||
window_cache[COL].main_dirty = window_cache[COL].sub_dirty = true;
|
||||
}
|
||||
|
||||
//WH2
|
||||
void bPPU::mmio_w2128(uint8 value) {
|
||||
regs.window2_left = value;
|
||||
|
||||
window_cache[BG1].main_dirty = window_cache[BG1].sub_dirty = true;
|
||||
window_cache[BG2].main_dirty = window_cache[BG2].sub_dirty = true;
|
||||
window_cache[BG3].main_dirty = window_cache[BG3].sub_dirty = true;
|
||||
window_cache[BG4].main_dirty = window_cache[BG4].sub_dirty = true;
|
||||
window_cache[OAM].main_dirty = window_cache[OAM].sub_dirty = true;
|
||||
window_cache[COL].main_dirty = window_cache[COL].sub_dirty = true;
|
||||
}
|
||||
|
||||
//WH3
|
||||
void bPPU::mmio_w2129(uint8 value) {
|
||||
regs.window2_right = value;
|
||||
|
||||
window_cache[BG1].main_dirty = window_cache[BG1].sub_dirty = true;
|
||||
window_cache[BG2].main_dirty = window_cache[BG2].sub_dirty = true;
|
||||
window_cache[BG3].main_dirty = window_cache[BG3].sub_dirty = true;
|
||||
window_cache[BG4].main_dirty = window_cache[BG4].sub_dirty = true;
|
||||
window_cache[OAM].main_dirty = window_cache[OAM].sub_dirty = true;
|
||||
window_cache[COL].main_dirty = window_cache[COL].sub_dirty = true;
|
||||
}
|
||||
|
||||
//WBGLOG
|
||||
void bPPU::mmio_w212a(uint8 value) {
|
||||
regs.bg_window_mask[BG4] = (value >> 6) & 3;
|
||||
regs.bg_window_mask[BG3] = (value >> 4) & 3;
|
||||
regs.bg_window_mask[BG2] = (value >> 2) & 3;
|
||||
regs.bg_window_mask[BG1] = (value ) & 3;
|
||||
regs.window_mask[BG4] = (value >> 6) & 3;
|
||||
regs.window_mask[BG3] = (value >> 4) & 3;
|
||||
regs.window_mask[BG2] = (value >> 2) & 3;
|
||||
regs.window_mask[BG1] = (value ) & 3;
|
||||
|
||||
window_cache[BG1].main_dirty = window_cache[BG1].sub_dirty = true;
|
||||
window_cache[BG2].main_dirty = window_cache[BG2].sub_dirty = true;
|
||||
window_cache[BG3].main_dirty = window_cache[BG3].sub_dirty = true;
|
||||
window_cache[BG4].main_dirty = window_cache[BG4].sub_dirty = true;
|
||||
}
|
||||
|
||||
//WOBJLOG
|
||||
void bPPU::mmio_w212b(uint8 value) {
|
||||
regs.color_window_mask = (value >> 2) & 3;
|
||||
regs.bg_window_mask[OAM] = (value ) & 3;
|
||||
regs.window_mask[COL] = (value >> 2) & 3;
|
||||
regs.window_mask[OAM] = (value ) & 3;
|
||||
|
||||
window_cache[OAM].main_dirty = window_cache[OAM].sub_dirty = true;
|
||||
window_cache[COL].main_dirty = window_cache[COL].sub_dirty = true;
|
||||
}
|
||||
|
||||
//TM
|
||||
@@ -346,20 +487,32 @@ void bPPU::mmio_w212d(uint8 value) {
|
||||
|
||||
//TMW
|
||||
void bPPU::mmio_w212e(uint8 value) {
|
||||
regs.bg_window_enabled[OAM] = !!(value & 0x10);
|
||||
regs.bg_window_enabled[BG4] = !!(value & 0x08);
|
||||
regs.bg_window_enabled[BG3] = !!(value & 0x04);
|
||||
regs.bg_window_enabled[BG2] = !!(value & 0x02);
|
||||
regs.bg_window_enabled[BG1] = !!(value & 0x01);
|
||||
regs.window_enabled[OAM] = !!(value & 0x10);
|
||||
regs.window_enabled[BG4] = !!(value & 0x08);
|
||||
regs.window_enabled[BG3] = !!(value & 0x04);
|
||||
regs.window_enabled[BG2] = !!(value & 0x02);
|
||||
regs.window_enabled[BG1] = !!(value & 0x01);
|
||||
|
||||
window_cache[BG1].main_dirty = window_cache[BG1].sub_dirty = true;
|
||||
window_cache[BG2].main_dirty = window_cache[BG2].sub_dirty = true;
|
||||
window_cache[BG3].main_dirty = window_cache[BG3].sub_dirty = true;
|
||||
window_cache[BG4].main_dirty = window_cache[BG4].sub_dirty = true;
|
||||
window_cache[OAM].main_dirty = window_cache[OAM].sub_dirty = true;
|
||||
}
|
||||
|
||||
//TSW
|
||||
void bPPU::mmio_w212f(uint8 value) {
|
||||
regs.bgsub_window_enabled[OAM] = !!(value & 0x10);
|
||||
regs.bgsub_window_enabled[BG4] = !!(value & 0x08);
|
||||
regs.bgsub_window_enabled[BG3] = !!(value & 0x04);
|
||||
regs.bgsub_window_enabled[BG2] = !!(value & 0x02);
|
||||
regs.bgsub_window_enabled[BG1] = !!(value & 0x01);
|
||||
regs.sub_window_enabled[OAM] = !!(value & 0x10);
|
||||
regs.sub_window_enabled[BG4] = !!(value & 0x08);
|
||||
regs.sub_window_enabled[BG3] = !!(value & 0x04);
|
||||
regs.sub_window_enabled[BG2] = !!(value & 0x02);
|
||||
regs.sub_window_enabled[BG1] = !!(value & 0x01);
|
||||
|
||||
window_cache[BG1].main_dirty = window_cache[BG1].sub_dirty = true;
|
||||
window_cache[BG2].main_dirty = window_cache[BG2].sub_dirty = true;
|
||||
window_cache[BG3].main_dirty = window_cache[BG3].sub_dirty = true;
|
||||
window_cache[BG4].main_dirty = window_cache[BG4].sub_dirty = true;
|
||||
window_cache[OAM].main_dirty = window_cache[OAM].sub_dirty = true;
|
||||
}
|
||||
|
||||
//CGWSEL
|
||||
@@ -367,18 +520,21 @@ 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);
|
||||
|
||||
window_cache[COL].main_dirty = window_cache[COL].sub_dirty = true;
|
||||
}
|
||||
|
||||
//CGADDSUB
|
||||
void bPPU::mmio_w2131(uint8 value) {
|
||||
regs.color_mode = !!(value & 0x80);
|
||||
regs.color_halve = !!(value & 0x40);
|
||||
regs.bg_color_enabled[BACK] = !!(value & 0x20);
|
||||
regs.bg_color_enabled[OAM] = !!(value & 0x10);
|
||||
regs.bg_color_enabled[BG4] = !!(value & 0x08);
|
||||
regs.bg_color_enabled[BG3] = !!(value & 0x04);
|
||||
regs.bg_color_enabled[BG2] = !!(value & 0x02);
|
||||
regs.bg_color_enabled[BG1] = !!(value & 0x01);
|
||||
regs.color_mode = !!(value & 0x80);
|
||||
regs.color_halve = !!(value & 0x40);
|
||||
regs.color_enabled[BACK] = !!(value & 0x20);
|
||||
regs.color_enabled[OAM] = !!(value & 0x10);
|
||||
regs.color_enabled[BG4] = !!(value & 0x08);
|
||||
regs.color_enabled[BG3] = !!(value & 0x04);
|
||||
regs.color_enabled[BG2] = !!(value & 0x02);
|
||||
regs.color_enabled[BG1] = !!(value & 0x01);
|
||||
}
|
||||
|
||||
//COLDATA
|
||||
@@ -386,6 +542,8 @@ void bPPU::mmio_w2132(uint8 value) {
|
||||
if(value & 0x80)regs.color_b = value & 0x1f;
|
||||
if(value & 0x40)regs.color_g = value & 0x1f;
|
||||
if(value & 0x20)regs.color_r = value & 0x1f;
|
||||
|
||||
regs.color_rgb = (regs.color_r) | (regs.color_g << 5) | (regs.color_b << 10);
|
||||
}
|
||||
|
||||
//SETINI
|
||||
@@ -396,109 +554,135 @@ void bPPU::mmio_w2133(uint8 value) {
|
||||
regs.oam_halve = !!(value & 0x02);
|
||||
regs.interlace = !!(value & 0x01);
|
||||
|
||||
cpu->set_overscan(regs.overscan);
|
||||
cpu->set_interlace(regs.interlace);
|
||||
r_cpu->set_overscan(regs.overscan);
|
||||
r_cpu->set_interlace(regs.interlace);
|
||||
}
|
||||
|
||||
//MPYL
|
||||
uint8 bPPU::mmio_r2134() {
|
||||
uint32 r;
|
||||
r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
|
||||
return (r);
|
||||
regs.ppu1_mdr = r;
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
//MPYM
|
||||
uint8 bPPU::mmio_r2135() {
|
||||
uint32 r;
|
||||
r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
|
||||
return (r >> 8);
|
||||
regs.ppu1_mdr = r >> 8;
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
//MPYH
|
||||
uint8 bPPU::mmio_r2136() {
|
||||
uint32 r;
|
||||
r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
|
||||
return (r >> 16);
|
||||
regs.ppu1_mdr = r >> 16;
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
//SLHV
|
||||
uint8 bPPU::mmio_r2137() {
|
||||
if(cpu->pio_status() & 0x80) {
|
||||
if(r_cpu->pio_status() & 0x80) {
|
||||
latch_counters();
|
||||
}
|
||||
return 0x00;
|
||||
return r_cpu->regs.mdr;
|
||||
}
|
||||
|
||||
//OAMDATAREAD
|
||||
uint8 bPPU::mmio_r2138() {
|
||||
uint8 r;
|
||||
r = oam_read(regs.oam_addr);
|
||||
regs.ppu1_mdr = oam_read(regs.oam_addr);
|
||||
if(!(regs.oam_addr & 1)) {
|
||||
regs.oam_latchdata = r;
|
||||
regs.oam_latchdata = regs.ppu1_mdr;
|
||||
}
|
||||
regs.oam_addr++;
|
||||
regs.oam_addr &= 0x03ff;
|
||||
return r;
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
//VMDATALREAD
|
||||
uint8 bPPU::mmio_r2139() {
|
||||
uint16 addr = get_vram_address();
|
||||
uint8 r = regs.vram_readbuffer;
|
||||
regs.ppu1_mdr = regs.vram_readbuffer;
|
||||
if(regs.vram_incmode == 0) {
|
||||
addr &= 0xfffe;
|
||||
regs.vram_readbuffer = vram_read(addr);
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
if(vram_can_read()) {
|
||||
regs.vram_readbuffer = vram_read(addr);
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
} else {
|
||||
regs.vram_readbuffer = 0x0000;
|
||||
}
|
||||
regs.vram_addr += regs.vram_incsize;
|
||||
}
|
||||
return r;
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
//VMDATAHREAD
|
||||
uint8 bPPU::mmio_r213a() {
|
||||
uint16 addr = get_vram_address() + 1;
|
||||
uint8 r = regs.vram_readbuffer >> 8;
|
||||
regs.ppu1_mdr = regs.vram_readbuffer >> 8;
|
||||
if(regs.vram_incmode == 1) {
|
||||
addr &= 0xfffe;
|
||||
regs.vram_readbuffer = vram_read(addr);
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
if(vram_can_read()) {
|
||||
regs.vram_readbuffer = vram_read(addr);
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
} else {
|
||||
regs.vram_readbuffer = 0x0000;
|
||||
}
|
||||
regs.vram_addr += regs.vram_incsize;
|
||||
}
|
||||
return r;
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
//CGDATAREAD
|
||||
//note: CGRAM palette data is 15-bits (0,bbbbb,ggggg,rrrrr)
|
||||
//therefore, the high byte read from each color does not
|
||||
//update bit 7 of the PPU2 MDR.
|
||||
uint8 bPPU::mmio_r213b() {
|
||||
uint8 r;
|
||||
r = cgram_read(regs.cgram_addr);
|
||||
if(!(regs.cgram_addr & 1)) {
|
||||
regs.ppu2_mdr = cgram_read(regs.cgram_addr) & 0xff;
|
||||
} else {
|
||||
regs.ppu2_mdr &= 0x80;
|
||||
regs.ppu2_mdr |= cgram_read(regs.cgram_addr) & 0x7f;
|
||||
}
|
||||
regs.cgram_addr++;
|
||||
regs.cgram_addr &= 0x01ff;
|
||||
return r;
|
||||
return regs.ppu2_mdr;
|
||||
}
|
||||
|
||||
//OPHCT
|
||||
uint8 bPPU::mmio_r213c() {
|
||||
uint16 r = regs.hcounter;
|
||||
if(regs.latch_hcounter)r >>= 8;
|
||||
if(!regs.latch_hcounter) {
|
||||
regs.ppu2_mdr = regs.hcounter & 0xff;
|
||||
} else {
|
||||
regs.ppu2_mdr &= 0xfe;
|
||||
regs.ppu2_mdr |= (regs.hcounter >> 8) & 1;
|
||||
}
|
||||
regs.latch_hcounter ^= 1;
|
||||
return r;
|
||||
return regs.ppu2_mdr;
|
||||
}
|
||||
|
||||
//OPVCT
|
||||
uint8 bPPU::mmio_r213d() {
|
||||
uint16 r = regs.vcounter;
|
||||
if(regs.latch_vcounter)r >>= 8;
|
||||
if(!regs.latch_vcounter) {
|
||||
regs.ppu2_mdr = regs.vcounter & 0xff;
|
||||
} else {
|
||||
regs.ppu2_mdr &= 0xfe;
|
||||
regs.ppu2_mdr |= (regs.vcounter >> 8) & 1;
|
||||
}
|
||||
regs.latch_vcounter ^= 1;
|
||||
return r;
|
||||
return regs.ppu2_mdr;
|
||||
}
|
||||
|
||||
//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
|
||||
return r;
|
||||
r |= (regs.time_over) ? 0x80 : 0x00;
|
||||
r |= (regs.range_over) ? 0x40 : 0x00;
|
||||
r |= (ppu1_version & 0x0f);
|
||||
regs.ppu1_mdr = r;
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
//STAT78
|
||||
@@ -507,21 +691,41 @@ uint8 r = 0x00;
|
||||
regs.latch_hcounter = 0;
|
||||
regs.latch_vcounter = 0;
|
||||
|
||||
r |= cpu->interlace_field() << 7;
|
||||
if(!(cpu->pio_status() & 0x80)) {
|
||||
r |= 1 << 6;
|
||||
r |= r_cpu->interlace_field() << 7;
|
||||
if(!(r_cpu->pio_status() & 0x80)) {
|
||||
r |= 0x40;
|
||||
} else if(regs.counters_latched == true) {
|
||||
r |= 1 << 6;
|
||||
r |= 0x40;
|
||||
regs.counters_latched = false;
|
||||
}
|
||||
r |= (1 << 5);
|
||||
r |= 0x03; //PPU2 version number
|
||||
return r;
|
||||
r |= (regs.ppu2_mdr & 0x20);
|
||||
r |= (region << 4); //0 = NTSC, 1 = PAL
|
||||
r |= (ppu2_version & 0x0f);
|
||||
regs.ppu2_mdr = r;
|
||||
return regs.ppu2_mdr;
|
||||
}
|
||||
|
||||
uint8 bPPUMMIO::read(uint32 addr) {
|
||||
//cpu->sync();
|
||||
switch(addr) {
|
||||
case 0x2104:
|
||||
case 0x2105:
|
||||
case 0x2106:
|
||||
case 0x2108:
|
||||
case 0x2109:
|
||||
case 0x210a:
|
||||
case 0x2114:
|
||||
case 0x2115:
|
||||
case 0x2116:
|
||||
case 0x2118:
|
||||
case 0x2119:
|
||||
case 0x211a:
|
||||
case 0x2124:
|
||||
case 0x2125:
|
||||
case 0x2126:
|
||||
case 0x2128:
|
||||
case 0x2129:
|
||||
case 0x212a:
|
||||
return ppu->regs.ppu1_mdr;
|
||||
case 0x2134:return ppu->mmio_r2134(); //MPYL
|
||||
case 0x2135:return ppu->mmio_r2135(); //MPYM
|
||||
case 0x2136:return ppu->mmio_r2136(); //MPYH
|
||||
@@ -535,11 +739,11 @@ uint8 bPPUMMIO::read(uint32 addr) {
|
||||
case 0x213e:return ppu->mmio_r213e(); //STAT77
|
||||
case 0x213f:return ppu->mmio_r213f(); //STAT78
|
||||
}
|
||||
return 0x00;
|
||||
|
||||
return r_cpu->regs.mdr;
|
||||
}
|
||||
|
||||
void bPPUMMIO::write(uint32 addr, uint8 value) {
|
||||
//cpu->sync();
|
||||
switch(addr) {
|
||||
case 0x2100:ppu->mmio_w2100(value);return; //INIDISP
|
||||
case 0x2101:ppu->mmio_w2101(value);return; //OBSEL
|
||||
|
||||
@@ -20,28 +20,25 @@ inline void bPPU::render_line_mode0() {
|
||||
}
|
||||
|
||||
/*
|
||||
Mode 1 (pri=0): ->
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
|
||||
BG3B, OAM0, BG3A, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3
|
||||
|
||||
Mode 1 (pri=1): ->
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
|
||||
BG3B, OAM0, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3, BG3A
|
||||
|
||||
Mode 1 (pri=0): ->
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
|
||||
BG3B, OAM0, BG3A, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3
|
||||
*/
|
||||
inline void bPPU::render_line_mode1() {
|
||||
switch(regs.bg3_priority) {
|
||||
case 0:
|
||||
render_line_bg(BG1, COLORDEPTH_16, 6, 9);
|
||||
render_line_bg(BG2, COLORDEPTH_16, 5, 8);
|
||||
render_line_bg(BG3, COLORDEPTH_4, 1, 3);
|
||||
render_line_oam(2, 4, 7, 10);
|
||||
break;
|
||||
case 1:
|
||||
if(regs.bg3_priority) {
|
||||
render_line_bg(BG1, COLORDEPTH_16, 5, 8);
|
||||
render_line_bg(BG2, COLORDEPTH_16, 4, 7);
|
||||
render_line_bg(BG3, COLORDEPTH_4, 1, 10);
|
||||
render_line_oam(2, 3, 6, 9);
|
||||
break;
|
||||
} else {
|
||||
render_line_bg(BG1, COLORDEPTH_16, 6, 9);
|
||||
render_line_bg(BG2, COLORDEPTH_16, 5, 8);
|
||||
render_line_bg(BG3, COLORDEPTH_4, 1, 3);
|
||||
render_line_oam(2, 4, 7, 10);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,32 +101,31 @@ 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(output + (line.y * 1024), 0, 1024);
|
||||
return;
|
||||
}
|
||||
|
||||
clear_pixel_cache();
|
||||
build_color_window_tables();
|
||||
build_window_tables(COL);
|
||||
update_bg_info();
|
||||
|
||||
switch(regs.bg_mode) {
|
||||
case 0:render_line_mode0();break;
|
||||
case 1:render_line_mode1();break;
|
||||
@@ -140,5 +136,6 @@ void bPPU::render_line() {
|
||||
case 6:render_line_mode6();break;
|
||||
case 7:render_line_mode7();break;
|
||||
}
|
||||
|
||||
render_line_output();
|
||||
}
|
||||
+32
-24
@@ -1,8 +1,4 @@
|
||||
//bppu_render.cpp
|
||||
int _screen_width;
|
||||
bool _interlace;
|
||||
int _interlace_field;
|
||||
|
||||
inline void render_line_mode0();
|
||||
inline void render_line_mode1();
|
||||
inline void render_line_mode2();
|
||||
@@ -18,34 +14,44 @@ 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];
|
||||
|
||||
void render_bg_tile(uint8 color_depth, uint16 tile_num);
|
||||
inline void clear_pixel_cache();
|
||||
void init_tiledata_cache();
|
||||
void clear_tiledata_cache();
|
||||
inline void init_tiledata_cache();
|
||||
inline void clear_tiledata_cache();
|
||||
|
||||
//bppu_render_windows.cpp
|
||||
uint8 main_windowtable[5][512], sub_windowtable[5][512],
|
||||
main_colorwindowtable[512], sub_colorwindowtable[512];
|
||||
struct _window {
|
||||
bool main_dirty, sub_dirty;
|
||||
uint8 main[512], sub[512];
|
||||
} window_cache[6];
|
||||
|
||||
void build_window_table(uint8 bg, uint8 *wtbl, bool mainscreen);
|
||||
void build_window_table(uint8 bg, bool mainscreen);
|
||||
void build_window_tables(uint8 bg);
|
||||
void build_color_window_table(uint8 *wtbl, uint8 mask);
|
||||
void build_color_window_tables();
|
||||
inline void clear_window_cache();
|
||||
|
||||
//bppu_render_bg.cpp
|
||||
struct {
|
||||
uint16 tw, th; //tile width, height
|
||||
uint16 mx, my; //screen mask x, y
|
||||
} bg_info[4];
|
||||
|
||||
inline void update_bg_info();
|
||||
inline uint16 bg_get_tile(uint8 bg, uint16 x, uint16 y);
|
||||
void render_line_bg(uint8 bg, uint8 color_depth, uint8 pri0_pos, uint8 pri1_pos);
|
||||
|
||||
//bppu_render_oam.cpp
|
||||
@@ -55,26 +61,28 @@ 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];
|
||||
uint8 oam_line_pal[256], oam_line_pri[256];
|
||||
|
||||
bool is_sprite_on_scanline();
|
||||
void load_oam_tiles();
|
||||
void render_oam_tile(int tile_num);
|
||||
void render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos);
|
||||
void render_line_oam_lores(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos);
|
||||
void render_line_oam_hires(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 x);
|
||||
|
||||
//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_pixel(int x);
|
||||
inline uint16 get_palette(uint8 index);
|
||||
inline uint16 get_direct_color(uint8 p, uint8 t);
|
||||
inline uint16 get_pixel(uint32 x);
|
||||
inline void render_line_output();
|
||||
@@ -1,109 +1,39 @@
|
||||
inline uint16 bPPU::addsub_pixels(int cdest_index, int cdest_bg, int csrc_index, int csrc_bg) {
|
||||
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;
|
||||
inline uint16 bPPU::addsub_pixels(uint32 x) {
|
||||
uint32 cdest = pixel_cache[x].src_main,
|
||||
csrc = pixel_cache[x].src_sub;
|
||||
bool halve = false;
|
||||
if(regs.color_halve && window_cache[COL].main[x]) {
|
||||
if(regs.addsub_mode && pixel_cache[x].bg_sub == BACK);
|
||||
else {
|
||||
halve = true;
|
||||
}
|
||||
}
|
||||
|
||||
switch(regs.color_mode) {
|
||||
case 0: //COLORMODE_ADD:
|
||||
if(regs.color_halve == true) {
|
||||
cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
|
||||
csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
|
||||
cdest += csrc;
|
||||
cdest >>= 1;
|
||||
cdest &= 0x03e07c1f;
|
||||
return (cdest >> 16) | cdest;
|
||||
} else {
|
||||
cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
|
||||
csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
|
||||
cdest += csrc;
|
||||
if(!regs.color_mode) {
|
||||
//add
|
||||
cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
|
||||
csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
|
||||
cdest += csrc;
|
||||
|
||||
if(!halve) {
|
||||
if(cdest & 0x04000000)cdest |= 0x03e00000;
|
||||
if(cdest & 0x00008000)cdest |= 0x00007c00;
|
||||
if(cdest & 0x00000020)cdest |= 0x0000001f;
|
||||
cdest &= 0x03e07c1f;
|
||||
return (cdest >> 16) | cdest;
|
||||
}
|
||||
break;
|
||||
case 1: //COLORMODE_SUB:
|
||||
if(regs.color_halve == true) {
|
||||
if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00;
|
||||
else cdest -= (csrc & 0x7c00);
|
||||
if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0;
|
||||
else cdest -= (csrc & 0x03e0);
|
||||
if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f;
|
||||
else cdest -= (csrc & 0x001f);
|
||||
return (cdest & 0x7bde) >> 1;
|
||||
} else {
|
||||
if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00;
|
||||
else cdest -= (csrc & 0x7c00);
|
||||
if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0;
|
||||
else cdest -= (csrc & 0x03e0);
|
||||
if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f;
|
||||
else cdest -= (csrc & 0x001f);
|
||||
return cdest;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0x0000; //prevent annoying warning message
|
||||
}
|
||||
|
||||
inline uint16 bPPU::addsub_pixel(int cdest_index, int cdest_bg) {
|
||||
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) {
|
||||
cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
|
||||
csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
|
||||
cdest += csrc;
|
||||
cdest >>= 1;
|
||||
cdest &= 0x03e07c1f;
|
||||
return (cdest >> 16) | cdest;
|
||||
} else {
|
||||
cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
|
||||
csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
|
||||
cdest += csrc;
|
||||
if(cdest & 0x04000000)cdest |= 0x03e00000;
|
||||
if(cdest & 0x00008000)cdest |= 0x00007c00;
|
||||
if(cdest & 0x00000020)cdest |= 0x0000001f;
|
||||
cdest &= 0x03e07c1f;
|
||||
return (cdest >> 16) | cdest;
|
||||
}
|
||||
break;
|
||||
case 1: //COLORMODE_SUB:
|
||||
if(regs.color_halve == true && regs.addsub_mode == 0) {
|
||||
if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00;
|
||||
else cdest -= (csrc & 0x7c00);
|
||||
if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0;
|
||||
else cdest -= (csrc & 0x03e0);
|
||||
if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f;
|
||||
else cdest -= (csrc & 0x001f);
|
||||
return (cdest & 0x7bde) >> 1;
|
||||
} else {
|
||||
if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00;
|
||||
else cdest -= (csrc & 0x7c00);
|
||||
if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0;
|
||||
else cdest -= (csrc & 0x03e0);
|
||||
if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f;
|
||||
else cdest -= (csrc & 0x001f);
|
||||
return cdest;
|
||||
}
|
||||
break;
|
||||
|
||||
cdest &= 0x03e07c1f;
|
||||
return (cdest >> 16) | cdest;
|
||||
} else {
|
||||
//subtract
|
||||
if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00;
|
||||
else cdest -= (csrc & 0x7c00);
|
||||
if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0;
|
||||
else cdest -= (csrc & 0x03e0);
|
||||
if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f;
|
||||
else cdest -= (csrc & 0x001f);
|
||||
|
||||
return (!halve) ? cdest : ((cdest & 0x7bde) >> 1);
|
||||
}
|
||||
return 0x0000; //prevent annoying warning message
|
||||
}
|
||||
+156
-199
@@ -1,234 +1,191 @@
|
||||
//called once at the start of every rendered scanline
|
||||
void bPPU::update_bg_info() {
|
||||
for(int bg=0;bg<4;bg++) {
|
||||
bg_info[bg].th = (regs.bg_tilesize[bg]) ? 4 : 3;
|
||||
bg_info[bg].tw = (line.hires) ? 4 : bg_info[bg].th;
|
||||
bg_info[bg].mx = (bg_info[bg].th == 4) ? (line.width << 1) : line.width;
|
||||
bg_info[bg].my = bg_info[bg].mx;
|
||||
if(regs.bg_scsize[bg] & 0x01)bg_info[bg].mx <<= 1;
|
||||
if(regs.bg_scsize[bg] & 0x02)bg_info[bg].my <<= 1;
|
||||
bg_info[bg].mx--;
|
||||
bg_info[bg].my--;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 bPPU::bg_get_tile(uint8 bg, uint16 x, uint16 y) {
|
||||
uint16 map_index, pos;
|
||||
x &= bg_info[bg].mx;
|
||||
y &= bg_info[bg].my;
|
||||
|
||||
//32 = SC width, height; tilemap data is stored as uint16
|
||||
//width(32) * height(32) * sizeof(uint16) = 2048
|
||||
switch(regs.bg_scsize[bg]) {
|
||||
case SC_32x32:map_index = 0; break;
|
||||
case SC_64x32:map_index = ((x >> bg_info[bg].th) / 32) * 2048; break;
|
||||
case SC_32x64:map_index = ((y >> bg_info[bg].th) / 32) * 2048; break;
|
||||
case SC_64x64:map_index = ((x >> bg_info[bg].th) / 32) * 2048 +
|
||||
((y >> bg_info[bg].th) / 32) * 4096; break;
|
||||
}
|
||||
|
||||
pos = ((((y >> bg_info[bg].th) & 31) * 32) + ((x >> bg_info[bg].tw) & 31)) << 1;
|
||||
return read16(vram, regs.bg_scaddr[bg] + map_index + pos);
|
||||
}
|
||||
|
||||
void bPPU::render_line_bg(uint8 bg, uint8 color_depth, uint8 pri0_pos, uint8 pri1_pos) {
|
||||
if(regs.bg_enabled[bg] == false && regs.bgsub_enabled[bg] == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
int x;
|
||||
int _scaddr = regs.bg_scaddr[bg];
|
||||
int _tdaddr = regs.bg_tdaddr[bg];
|
||||
bool _bg_enabled = regs.bg_enabled[bg];
|
||||
bool _bgsub_enabled = regs.bgsub_enabled[bg];
|
||||
bool bg_enabled = regs.bg_enabled[bg];
|
||||
bool bgsub_enabled = regs.bgsub_enabled[bg];
|
||||
|
||||
uint16 opt_valid_bit; //offset-per-tile valid flag bit
|
||||
if(bg == BG1) {
|
||||
opt_valid_bit = 0x2000;
|
||||
} else if(bg == BG2) {
|
||||
opt_valid_bit = 0x4000;
|
||||
} else {
|
||||
opt_valid_bit = 0x0000;
|
||||
uint16 opt_valid_bit = (bg == BG1) ? 0x2000 : ((bg == BG2) ? 0x4000 : 0x0000);
|
||||
uint8 bgpal_index = (regs.bg_mode == 0) ? (bg << 5) : 0;
|
||||
|
||||
uint8 pal_size = (color_depth == 2) ? 256 : ((color_depth == 1) ? 16 : 4);
|
||||
uint16 tile_mask = (color_depth == 2) ? 0x03ff : ((color_depth == 1) ? 0x07ff : 0x0fff);
|
||||
//4 + color_depth = >>(4-6) -- / {16, 32, 64 } bytes/tile
|
||||
//index is a tile number count to add to base tile number
|
||||
uint tiledata_index = regs.bg_tdaddr[bg] >> (4 + color_depth);
|
||||
|
||||
uint8 *bg_td = (uint8*)bg_tiledata[color_depth];
|
||||
uint8 *bg_td_state = (uint8*)bg_tiledata_state[color_depth];
|
||||
|
||||
uint8 tile_width = bg_info[bg].tw;
|
||||
uint8 tile_height = bg_info[bg].th;
|
||||
uint16 mask_x = bg_info[bg].mx; //screen width mask
|
||||
uint16 mask_y = bg_info[bg].my; //screen height mask
|
||||
|
||||
uint x = 0;
|
||||
uint y = line.y;
|
||||
if(line.interlace && line.hires) {
|
||||
y = (y << 1) + line.interlace_field;
|
||||
}
|
||||
|
||||
uint8 pal_size, tiledata_size;
|
||||
switch(color_depth) {
|
||||
case COLORDEPTH_4:
|
||||
pal_size = 4;
|
||||
tiledata_size = 4; //<<4=*16
|
||||
break;
|
||||
case COLORDEPTH_16:
|
||||
pal_size = 16;
|
||||
tiledata_size = 5; //<<5=*32
|
||||
break;
|
||||
case COLORDEPTH_256:
|
||||
pal_size = 256;
|
||||
tiledata_size = 6; //<<6=*64
|
||||
break;
|
||||
}
|
||||
uint16 hscroll = (line.hires) ? (regs.bg_hofs[bg] << 1) : regs.bg_hofs[bg];
|
||||
uint16 vscroll = (line.interlace && line.hires) ? (regs.bg_vofs[bg] << 1) : regs.bg_vofs[bg];
|
||||
hscroll &= mask_x;
|
||||
vscroll &= mask_y;
|
||||
|
||||
uint8 *bg_td, *bg_td_state;
|
||||
bg_td = (uint8*)bg_tiledata[color_depth];
|
||||
bg_td_state = (uint8*)bg_tiledata_state[color_depth];
|
||||
uint16 *mtable = (uint16*)mosaic_table[(regs.mosaic_enabled[bg]) ? regs.mosaic_size : 0];
|
||||
uint16 mosaic_x;
|
||||
uint16 mosaic_y;
|
||||
|
||||
uint16 screen_width, screen_height;
|
||||
screen_width = _screen_width;
|
||||
screen_height = _screen_width; //this is correct -- ppu tilemap is a perfect square
|
||||
|
||||
uint8 tile_size, tile_width, tile_height;
|
||||
tile_size = (regs.bg_tilesize[bg])?4:3; //<<4=*16, <<3=*8
|
||||
tile_width = tile_size;
|
||||
tile_height = tile_size;
|
||||
|
||||
int screen_x, screen_y;
|
||||
if(_interlace == true && _screen_width == 512) {
|
||||
screen_y = (_y << 1) + _interlace_field;
|
||||
} else {
|
||||
screen_y = _y;
|
||||
}
|
||||
|
||||
//Modes 5 and 6 seem to force 16-width tiles due to having twice the resolution.
|
||||
//The tile size attribute in $2105 has no effect on tile width.
|
||||
if(_screen_width == 512) {
|
||||
tile_width = 4; //<<4=*16
|
||||
}
|
||||
|
||||
if(tile_size == 4) { //16x16 tile size
|
||||
screen_width <<= 1;
|
||||
screen_height <<= 1;
|
||||
}
|
||||
|
||||
if(regs.bg_scsize[bg] & 0x01)screen_width <<= 1;
|
||||
if(regs.bg_scsize[bg] & 0x02)screen_height <<= 1;
|
||||
|
||||
uint16 screen_width_mask, screen_height_mask;
|
||||
screen_width_mask = screen_width - 1;
|
||||
screen_height_mask = screen_height - 1;
|
||||
|
||||
int bg_x, bg_y;
|
||||
uint16 vscroll, hscroll;
|
||||
if(_screen_width == 512) {
|
||||
hscroll = (regs.bg_hofs[bg] << 1) & screen_width_mask;
|
||||
} else {
|
||||
hscroll = regs.bg_hofs[bg] & screen_width_mask;
|
||||
}
|
||||
bg_x = hscroll;
|
||||
|
||||
if(_screen_width == 512 && _interlace == true) {
|
||||
vscroll = (regs.bg_vofs[bg] << 1) & screen_height_mask;
|
||||
} else {
|
||||
vscroll = regs.bg_vofs[bg] & screen_height_mask;
|
||||
}
|
||||
bg_y = (screen_y + vscroll) & screen_height_mask;
|
||||
|
||||
uint16 *mtable;
|
||||
int mosaic_x, mosaic_y;
|
||||
if(regs.mosaic_enabled[bg] == true) {
|
||||
mtable = (uint16*)mosaic_table[regs.mosaic_size];
|
||||
} 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;
|
||||
uint16 hval, vval;
|
||||
uint16 t, tile_pri, tile_num;
|
||||
uint8 pal_index, pal_num;
|
||||
uint8 *tile_ptr;
|
||||
int xpos, ypos;
|
||||
uint16 map_index, hoffset, voffset, col;
|
||||
uint xpos, ypos;
|
||||
uint16 hoffset, voffset, opt_x, col;
|
||||
bool mirror_x, mirror_y;
|
||||
bool is_opt_mode = (regs.bg_mode == 2 || regs.bg_mode == 4 || regs.bg_mode == 6);
|
||||
|
||||
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...
|
||||
if(regs.bg_mode == 2 || regs.bg_mode == 4 || regs.bg_mode == 6) {
|
||||
if(regs.bg_mode == 6) {
|
||||
tile_x = (mtable[screen_x + (hscroll & 15)] >> 4);
|
||||
} else {
|
||||
tile_x = (mtable[screen_x + (hscroll & 7)] >> 3);
|
||||
}
|
||||
hoffset = hscroll;
|
||||
voffset = vscroll;
|
||||
if(tile_x != 0) {
|
||||
tile_x = (tile_x - 1) & 31;
|
||||
uint8 *wt_main = window_cache[bg].main;
|
||||
uint8 *wt_sub = window_cache[bg].sub;
|
||||
|
||||
int32 prev_x = -1, prev_y = -1;
|
||||
for(x=0;x<line.width;x++) {
|
||||
hoffset = x + hscroll;
|
||||
voffset = y + vscroll;
|
||||
|
||||
if(is_opt_mode) {
|
||||
opt_x = (x + (hscroll & 7));
|
||||
|
||||
//tile 0 is unaffected by OPT mode...
|
||||
if(opt_x >= 8) {
|
||||
hval = bg_get_tile(BG3,
|
||||
(opt_x - 8) + (regs.bg_hofs[BG3] & ~7),
|
||||
regs.bg_vofs[BG3]);
|
||||
|
||||
vval = bg_get_tile(BG3,
|
||||
(opt_x - 8) + (regs.bg_hofs[BG3] & ~7),
|
||||
regs.bg_vofs[BG3] + 8);
|
||||
|
||||
if(regs.bg_mode == 4) {
|
||||
pos = regs.bg_scaddr[BG3] + (tile_x << 1);
|
||||
t = *((uint16*)vram + (pos >> 1));
|
||||
if(t & opt_valid_bit) {
|
||||
if(!(t & 0x8000)) {
|
||||
hoffset = ((t & 0x1ff8) | (hscroll & 7)) & screen_width_mask;
|
||||
if(hval & opt_valid_bit) {
|
||||
if(!(hval & 0x8000)) {
|
||||
hoffset = opt_x + (hval & ~7);
|
||||
} else {
|
||||
voffset = (t & 0x1fff) & screen_height_mask;
|
||||
voffset = y + hval;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pos = regs.bg_scaddr[BG3] + (tile_x << 1);
|
||||
t = *((uint16*)vram + (pos >> 1));
|
||||
if(t & opt_valid_bit) {
|
||||
hoffset = ((t & 0x1ff8) | (hscroll & 7)) & screen_width_mask;
|
||||
if(hval & opt_valid_bit) {
|
||||
hoffset = opt_x + (hval & ~7);
|
||||
}
|
||||
pos = regs.bg_scaddr[BG3] + 64 + (tile_x << 1);
|
||||
t = *((uint16*)vram + (pos >> 1));
|
||||
if(t & opt_valid_bit) {
|
||||
voffset = (t & 0x1fff) & screen_height_mask;
|
||||
if(vval & opt_valid_bit) {
|
||||
voffset = y + vval;
|
||||
}
|
||||
}
|
||||
}
|
||||
mosaic_x = mtable[(screen_x + hoffset) & screen_width_mask ];
|
||||
mosaic_y = mtable[(screen_y + voffset) & screen_height_mask];
|
||||
}
|
||||
|
||||
switch(regs.bg_scsize[bg]) {
|
||||
case 0:
|
||||
map_index = 0;
|
||||
break;
|
||||
case 1:
|
||||
map_index = ((mosaic_x >> tile_size) >> 5) << 11;
|
||||
break;
|
||||
case 2:
|
||||
map_index = ((mosaic_y >> tile_size) >> 5) << 11;
|
||||
break;
|
||||
case 3:
|
||||
map_index = ((mosaic_x >> tile_size) >> 5) << 11 |
|
||||
((mosaic_y >> tile_size) >> 5) << 12;
|
||||
break;
|
||||
}
|
||||
mosaic_x = mtable[hoffset & mask_x];
|
||||
mosaic_y = mtable[voffset & mask_y];
|
||||
|
||||
base_xpos = ((mosaic_x >> 3) & 31);
|
||||
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;
|
||||
if((mosaic_x >> 3) != prev_x || (mosaic_y >> 3) != prev_y) {
|
||||
prev_x = (mosaic_x >> 3);
|
||||
prev_y = (mosaic_y >> 3);
|
||||
|
||||
int _pri;
|
||||
_pri = (t & 0x2000) ? pri1_pos : pri0_pos;
|
||||
t = bg_get_tile(bg, mosaic_x, mosaic_y);
|
||||
|
||||
tile_num = t & 0x03ff;
|
||||
if(tile_width == 4) {
|
||||
if(((mosaic_x & 15) >= 8 && !mirror_x) ||
|
||||
((mosaic_x & 15) < 8 && mirror_x))tile_num++;
|
||||
tile_num &= 0x03ff;
|
||||
}
|
||||
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);
|
||||
mirror_y = !!(t & 0x8000);
|
||||
mirror_x = !!(t & 0x4000);
|
||||
|
||||
if(bg_td_state[tile_num] == 1) {
|
||||
render_bg_tile(color_depth, tile_num);
|
||||
}
|
||||
tile_pri = (t & 0x2000) ? pri1_pos : pri0_pos;
|
||||
tile_num = t;
|
||||
|
||||
pal_index = ((t >> 10) & 7) * pal_size;
|
||||
|
||||
if(mirror_y) { ypos = (7 - (mosaic_y & 7)); }
|
||||
else { ypos = ( (mosaic_y & 7)); }
|
||||
|
||||
//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) {
|
||||
if(mirror_x) { xpos = (7 - (mosaic_x & 7)); }
|
||||
else { xpos = ( (mosaic_x & 7)); }
|
||||
col = *(tile_ptr + xpos);
|
||||
if(col && main_colorwindowtable[screen_x]) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
if(tile_width == 4) { //16x16 horizontal tile mirroring
|
||||
if(!!(mosaic_x & 8) != mirror_x)tile_num++;
|
||||
}
|
||||
|
||||
bg_x++;
|
||||
bg_x &= screen_width_mask;
|
||||
mosaic_x = mtable[bg_x];
|
||||
if(tile_height == 4) { //16x16 vertical tile mirroring
|
||||
if(!!(mosaic_y & 8) != mirror_y)tile_num += 16;
|
||||
}
|
||||
|
||||
if(base_xpos != ((mosaic_x >> 3) & 31))break;
|
||||
screen_x++;
|
||||
if(screen_x >= _screen_width)break;
|
||||
tile_num &= 0x03ff;
|
||||
tile_num += tiledata_index;
|
||||
tile_num &= tile_mask;
|
||||
|
||||
if(bg_td_state[tile_num] == 1) {
|
||||
render_bg_tile(color_depth, tile_num);
|
||||
}
|
||||
|
||||
pal_num = ((t >> 10) & 7);
|
||||
pal_index = (pal_num * pal_size) + bgpal_index;
|
||||
|
||||
ypos = mosaic_y & 7;
|
||||
if(mirror_y)ypos ^= 7; //invert y tile pos
|
||||
|
||||
tile_ptr = (uint8*)bg_td + (tile_num * 64) + (ypos * 8);
|
||||
}
|
||||
|
||||
xpos = mosaic_x & 7;
|
||||
if(mirror_x)xpos ^= 7; //invert x tile pos
|
||||
col = *(tile_ptr + xpos);
|
||||
if(col) {
|
||||
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[x]) {
|
||||
if(pixel_cache[x].pri_main < tile_pri) {
|
||||
pixel_cache[x].pri_main = tile_pri;
|
||||
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(pixel_cache[x].pri_sub < tile_pri) {
|
||||
pixel_cache[x].pri_sub = tile_pri;
|
||||
pixel_cache[x].bg_sub = 0x80 | bg;
|
||||
pixel_cache[x].src_sub = col;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
if(d0 & __m)col += 1; \
|
||||
if(d1 & __m)col += 2; \
|
||||
*dest++ = col
|
||||
|
||||
#define render_bg_tile_line_16(__m) \
|
||||
col = 0; \
|
||||
if(d0 & __m)col += 1; \
|
||||
@@ -10,6 +11,7 @@
|
||||
if(d2 & __m)col += 4; \
|
||||
if(d3 & __m)col += 8; \
|
||||
*dest++ = col
|
||||
|
||||
#define render_bg_tile_line_256(__m) \
|
||||
col = 0; \
|
||||
if(d0 & __m)col += 1; \
|
||||
@@ -96,6 +98,10 @@ uint8 *dest;
|
||||
}
|
||||
}
|
||||
|
||||
#undef render_bg_tile_line_4
|
||||
#undef render_bg_tile_line_16
|
||||
#undef render_bg_tile_line_256
|
||||
|
||||
inline void bPPU::clear_pixel_cache() {
|
||||
memset(pixel_cache, 0, sizeof(pixel_cache));
|
||||
}
|
||||
@@ -112,8 +118,22 @@ void bPPU::init_tiledata_cache() {
|
||||
void bPPU::clear_tiledata_cache() {
|
||||
memset(bg_tiledata[TILE_2BIT], 0, 262144);
|
||||
memset(bg_tiledata[TILE_4BIT], 0, 131072);
|
||||
memset(bg_tiledata[TILE_4BIT], 0, 65536);
|
||||
memset(bg_tiledata[TILE_8BIT], 0, 65536);
|
||||
memset(bg_tiledata_state[TILE_2BIT], 0, 4096);
|
||||
memset(bg_tiledata_state[TILE_4BIT], 0, 2048);
|
||||
memset(bg_tiledata_state[TILE_8BIT], 0, 1024);
|
||||
}
|
||||
|
||||
void bPPU::clear_window_cache() {
|
||||
for(int i=0;i<6;i++) {
|
||||
window_cache[i].main_dirty = true;
|
||||
window_cache[i].sub_dirty = true;
|
||||
}
|
||||
|
||||
build_window_tables(BG1);
|
||||
build_window_tables(BG2);
|
||||
build_window_tables(BG3);
|
||||
build_window_tables(BG4);
|
||||
build_window_tables(OAM);
|
||||
build_window_tables(COL);
|
||||
}
|
||||
@@ -1,76 +1,69 @@
|
||||
inline uint16 bPPU::get_palette(int index) {
|
||||
return *((uint16*)cgram + index);
|
||||
inline uint16 bPPU::get_palette(uint8 index) {
|
||||
return read16(cgram, index << 1);
|
||||
}
|
||||
|
||||
inline uint16 bPPU::get_pixel(int x) {
|
||||
inline uint16 bPPU::get_direct_color(uint8 p, uint8 t) {
|
||||
//p = 00000bgr <palette data>
|
||||
//t = BBGGGRRR <tilemap data>
|
||||
//r = 0BBb00GGGg0RRRr0 <return data>
|
||||
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(uint32 x) {
|
||||
_pixel *p = &pixel_cache[x];
|
||||
uint16 _r;
|
||||
if(p->bg_main && p->bg_sub) {
|
||||
if(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);
|
||||
} else {
|
||||
_r = addsub_pixel(p->src_main, p->bg_main & 0x7f);
|
||||
}
|
||||
} else {
|
||||
_r = get_palette(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);
|
||||
} else {
|
||||
_r = get_palette(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);
|
||||
} else {
|
||||
_r = addsub_pixel(0, BACK);
|
||||
}
|
||||
} else {
|
||||
_r = get_palette(0);
|
||||
}
|
||||
} else {
|
||||
_r = 0x0000;
|
||||
}
|
||||
if(!p->bg_main) {
|
||||
p->bg_main = BACK;
|
||||
p->src_main = get_palette(0);
|
||||
p->color_exempt = false;
|
||||
} else {
|
||||
if(main_colorwindowtable[x]) {
|
||||
if(regs.bg_color_enabled[BACK] && sub_colorwindowtable[x]) {
|
||||
_r = addsub_pixel(0, BACK);
|
||||
} else {
|
||||
_r = get_palette(0);
|
||||
}
|
||||
} else {
|
||||
_r = 0x0000;
|
||||
}
|
||||
p->bg_main &= 0x7f;
|
||||
}
|
||||
return _r;
|
||||
|
||||
if(!p->bg_sub) {
|
||||
p->bg_sub = BACK;
|
||||
p->src_sub = regs.color_rgb;
|
||||
} else {
|
||||
p->bg_sub &= 0x7f;
|
||||
}
|
||||
|
||||
if(!regs.addsub_mode) {
|
||||
p->bg_sub = BACK;
|
||||
p->src_sub = regs.color_rgb;
|
||||
}
|
||||
|
||||
if(!window_cache[COL].main[x]) {
|
||||
if(!window_cache[COL].sub[x]) {
|
||||
return 0x0000;
|
||||
}
|
||||
//p->bg_main remains the same, even when the main color window
|
||||
//masks out the color. this is needed for regs.color_enabled[p->bg_main]
|
||||
//test below. illusion of gaia relies on this behavior for its load menu.
|
||||
p->src_main = 0x0000;
|
||||
}
|
||||
|
||||
if(!p->color_exempt && regs.color_enabled[p->bg_main] && window_cache[COL].sub[x]) {
|
||||
return addsub_pixels(x);
|
||||
}
|
||||
return p->src_main;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
uint16 r, x;
|
||||
uint16 *ptr = (uint16*)output + (line.y * 1024) +
|
||||
((line.interlace && line.interlace_field) ? 512 : 0);
|
||||
uint16 *ltable = (uint16*)light_table + (regs.display_brightness << 15);
|
||||
|
||||
uint16 *ltable;
|
||||
ltable = (uint16*)light_table + (regs.display_brightness << 16);
|
||||
|
||||
if(_screen_width == 256) {
|
||||
if(line.width == 256) {
|
||||
for(x=0;x<256;x++) {
|
||||
_r = get_pixel(x);
|
||||
*ptr = *(ltable + _r);
|
||||
ptr += 2;
|
||||
r = get_pixel(x);
|
||||
*ptr++ = *(ltable + r);
|
||||
}
|
||||
} else {
|
||||
for(x=0;x<512;x++) {
|
||||
_r = get_pixel(x);
|
||||
*ptr++ = *(ltable + _r);
|
||||
r = get_pixel(x);
|
||||
*ptr++ = *(ltable + r);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +1,73 @@
|
||||
#define CLIP_10BIT_SIGNED(x) \
|
||||
((x) & ((1 << 10) - 1)) + (((((x) & (1 << 13)) ^ (1 << 13)) - (1 << 13)) >> 3)
|
||||
/*
|
||||
bsnes mode7 renderer
|
||||
|
||||
#define CAST_WORDTOINT(x) \
|
||||
(int)(((x & 0x8000)?(x | 0xffff0000):(x & 0x00007fff)))
|
||||
base algorithm written by anomie
|
||||
bsnes implementation written by byuu
|
||||
|
||||
void bPPU::render_line_mode7(uint8 bg1_pri, uint8 bg2b_pri, uint8 bg2a_pri) {
|
||||
int x;
|
||||
int step_m7a, step_m7c, m7a, m7b, m7c, m7d;
|
||||
int hoffset, voffset;
|
||||
int centerx, centery;
|
||||
int xx, yy;
|
||||
int px, py;
|
||||
int tx, ty, tile, palette;
|
||||
uint8 layer_pos;
|
||||
hoffset = (CAST_WORDTOINT(regs.bg_hofs[BG1]) << 7) >> 7;
|
||||
voffset = (CAST_WORDTOINT(regs.bg_vofs[BG1]) << 7) >> 7;
|
||||
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
|
||||
*/
|
||||
|
||||
centerx = (CAST_WORDTOINT(regs.m7x) << 7) >> 7;
|
||||
centery = (CAST_WORDTOINT(regs.m7y) << 7) >> 7;
|
||||
//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;
|
||||
|
||||
int32 px, py;
|
||||
int32 tx, ty, tile, palette;
|
||||
a = int32(int16(regs.m7a));
|
||||
b = int32(int16(regs.m7b));
|
||||
c = int32(int16(regs.m7c));
|
||||
d = int32(int16(regs.m7d));
|
||||
|
||||
cx = (int32(regs.m7x) << 19) >> 19;
|
||||
cy = (int32(regs.m7y) << 19) >> 19;
|
||||
hofs = (int32(regs.m7_hofs) << 19) >> 19;
|
||||
//+1 breaks FF5 title screen mirror alignment...
|
||||
vofs = (int32(regs.m7_vofs + 0) << 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 = window_cache[bg].main;
|
||||
uint8 *wt_sub = window_cache[bg].sub;
|
||||
|
||||
if(regs.mode7_vflip == true) {
|
||||
yy = 223 - _y;
|
||||
y = 255 - line.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 = line.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 +79,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 +91,59 @@ 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(main_colorwindowtable[_x]) {
|
||||
if(_bg_enabled == 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;
|
||||
}
|
||||
}
|
||||
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 = 0x80 | _bg;
|
||||
pixel_cache[_x].src_sub = palette;
|
||||
}
|
||||
}
|
||||
if(!palette)continue;
|
||||
|
||||
if(regs.mode7_hflip == true) {
|
||||
_x = 255 - x;
|
||||
} else {
|
||||
_x = x;
|
||||
}
|
||||
|
||||
_end_setpixel:
|
||||
m7a += step_m7a;
|
||||
m7c += step_m7c;
|
||||
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
|
||||
@@ -63,10 +63,10 @@ uint16 width, height;
|
||||
addr &= 0x001f;
|
||||
z = oam[0x0200 + addr];
|
||||
i = addr << 2;
|
||||
sprite_list[i ].x = ((z & 0x01)?0x0100:0x0000) + (sprite_list[i ].x & 0xff);
|
||||
sprite_list[i + 1].x = ((z & 0x04)?0x0100:0x0000) + (sprite_list[i + 1].x & 0xff);
|
||||
sprite_list[i + 2].x = ((z & 0x10)?0x0100:0x0000) + (sprite_list[i + 2].x & 0xff);
|
||||
sprite_list[i + 3].x = ((z & 0x40)?0x0100:0x0000) + (sprite_list[i + 3].x & 0xff);
|
||||
sprite_list[i ].x = ((z & 0x01) ? 256 : 0) + (sprite_list[i ].x & 255);
|
||||
sprite_list[i + 1].x = ((z & 0x04) ? 256 : 0) + (sprite_list[i + 1].x & 255);
|
||||
sprite_list[i + 2].x = ((z & 0x10) ? 256 : 0) + (sprite_list[i + 2].x & 255);
|
||||
sprite_list[i + 3].x = ((z & 0x40) ? 256 : 0) + (sprite_list[i + 3].x & 255);
|
||||
get_sprite_size(i, !!(z & 0x02));
|
||||
get_sprite_size(i + 1, !!(z & 0x08));
|
||||
get_sprite_size(i + 2, !!(z & 0x20));
|
||||
@@ -90,18 +90,18 @@ uint16 addr = 0x0200;
|
||||
bool bPPU::is_sprite_on_scanline() {
|
||||
//if sprite is entirely offscreen and doesn't wrap around to the left side of the screen,
|
||||
//then it is not counted. 256 is correct, and not 255 -- as one might first expect
|
||||
if(spr->x > 256 && (spr->x + spr->width) < 512 && _screen_width != 512)return false;
|
||||
if(spr->x > 256 && (spr->x + spr->width) < 512)return false;
|
||||
|
||||
if(regs.oam_halve == false) {
|
||||
if(_y >= spr->y && _y < (spr->y + spr->height)) {
|
||||
if(line.y >= spr->y && line.y < (spr->y + spr->height)) {
|
||||
return true;
|
||||
} else if((spr->y + spr->height) >= 256 && _y < ((spr->y + spr->height) & 255)) {
|
||||
} else if((spr->y + spr->height) >= 256 && line.y < ((spr->y + spr->height) & 255)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if(_y >= spr->y && _y < (spr->y + (spr->height >> 1))) {
|
||||
if(line.y >= spr->y && line.y < (spr->y + (spr->height >> 1))) {
|
||||
return true;
|
||||
} else if((spr->y + (spr->height >> 1)) >= 256 && _y < ((spr->y + (spr->height >> 1)) & 255)) {
|
||||
} else if((spr->y + (spr->height >> 1)) >= 256 && line.y < ((spr->y + (spr->height >> 1)) & 255)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -110,62 +110,53 @@ bool bPPU::is_sprite_on_scanline() {
|
||||
}
|
||||
|
||||
void bPPU::load_oam_tiles() {
|
||||
uint16 tile_width;
|
||||
tile_width = spr->width >> 3;
|
||||
uint16 tile_width = spr->width >> 3;
|
||||
int x = spr->x;
|
||||
int y = (spr->vflip) ? ((spr->height - 1) - (line.y - spr->y)) : (line.y - spr->y);
|
||||
|
||||
int x, y, chr, nameselect_index;
|
||||
x = spr->x;
|
||||
if(_screen_width == 512)x <<= 1;
|
||||
x &= 511;
|
||||
|
||||
if(spr->vflip) {
|
||||
y = ((spr->height - 1) - (_y - spr->y));
|
||||
} else {
|
||||
y = (_y - spr->y);
|
||||
}
|
||||
//todo: double-check code below. seems that interlace_field
|
||||
//should be added to hires 512x448 sprites as well, and not
|
||||
//just when oam_halve is enabled...
|
||||
if(regs.oam_halve == true) {
|
||||
y <<= 1;
|
||||
if(_interlace == true && _screen_width == 512) {
|
||||
y += _interlace_field;
|
||||
if(line.interlace && line.width == 512) {
|
||||
y += line.interlace_field;
|
||||
}
|
||||
}
|
||||
|
||||
x &= 511;
|
||||
y &= 255;
|
||||
|
||||
chr = spr->character;
|
||||
uint16 tdaddr = regs.oam_tdaddr;
|
||||
uint16 chrx = (spr->character ) & 15;
|
||||
uint16 chry = (spr->character >> 4) & 15;
|
||||
if(spr->use_nameselect == true) {
|
||||
chr += 256;
|
||||
nameselect_index = regs.oam_nameselect << 13;
|
||||
} else {
|
||||
nameselect_index = 0x0000;
|
||||
tdaddr += (256 * 32) + (regs.oam_nameselect << 13);
|
||||
}
|
||||
chr += (y >> 3) << 4;
|
||||
chry += (y >> 3);
|
||||
chry &= 15;
|
||||
chry <<= 4;
|
||||
|
||||
int i, n, mx, pos, z;
|
||||
int i, n, sx, mx, pos;
|
||||
for(i=0;i<tile_width;i++) {
|
||||
z = x;
|
||||
z += (i << ((_screen_width == 512)?4:3));
|
||||
z &= 511;
|
||||
sx = x;
|
||||
sx += i << 3;
|
||||
sx &= 511;
|
||||
|
||||
//ignore sprites that are offscreen
|
||||
//sprites at 256 are still counted, even though they aren't visible onscreen
|
||||
if(z >= 257 && (z + 7) < 512 && _screen_width != 512)continue;
|
||||
if(sx >= 257 && (sx + 7) < 512)continue;
|
||||
|
||||
if(regs.oam_tilecount++ > 34)break;
|
||||
n = regs.oam_tilecount - 1;
|
||||
oam_tilelist[n].x = z;
|
||||
oam_tilelist[n].x = sx;
|
||||
oam_tilelist[n].y = y;
|
||||
oam_tilelist[n].pri = spr->priority;
|
||||
oam_tilelist[n].pal = (spr->palette << 4) + 128;
|
||||
oam_tilelist[n].hflip = spr->hflip;
|
||||
|
||||
if(oam_tilelist[n].hflip) {
|
||||
mx = (tile_width - 1) - i;
|
||||
} else {
|
||||
mx = i;
|
||||
}
|
||||
pos = regs.oam_tdaddr + ((chr + mx) << 5) + ((y & 7) << 1) + nameselect_index;
|
||||
mx = (oam_tilelist[n].hflip) ? ((tile_width - 1) - i) : i;
|
||||
pos = tdaddr + ((chry + ((chrx + mx) & 15)) << 5);
|
||||
oam_tilelist[n].tile = (pos >> 5) & 0x07ff;
|
||||
}
|
||||
}
|
||||
@@ -182,38 +173,26 @@ oam_tileitem *t = &oam_tilelist[tile_num];
|
||||
|
||||
int x, sx, col;
|
||||
sx = t->x;
|
||||
//tile_ptr = tiledata + (tile * (8_width * 8_height)) + ((y & 7_height_mask) * 8_width);
|
||||
tile_ptr = (uint8*)oam_td + (t->tile << 6) + ((t->y & 7) << 3);
|
||||
for(x=0;x<8;x++) {
|
||||
sx &= 511;
|
||||
if(sx < _screen_width) {
|
||||
col = *(tile_ptr + ((t->hflip)?7-x:x));
|
||||
if(sx < 256) {
|
||||
col = *(tile_ptr + ((t->hflip) ? (7 - x) : x));
|
||||
if(col) {
|
||||
col += t->pal;
|
||||
oam_line_pal[sx] = col;
|
||||
oam_line_pri[sx] = t->pri;
|
||||
if(_screen_width == 512) {
|
||||
oam_line_pal[sx + 1] = col;
|
||||
oam_line_pri[sx + 1] = t->pri;
|
||||
}
|
||||
}
|
||||
}
|
||||
sx += (_screen_width == 512)?2:1;
|
||||
sx++;
|
||||
}
|
||||
}
|
||||
|
||||
void bPPU::render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) {
|
||||
int s, x;
|
||||
bool _bg_enabled = regs.bg_enabled[OAM];
|
||||
bool _bgsub_enabled = regs.bgsub_enabled[OAM];
|
||||
|
||||
uint8 *wt_main = main_windowtable[OAM];
|
||||
uint8 *wt_sub = sub_windowtable[OAM];
|
||||
build_window_tables(OAM);
|
||||
|
||||
int s;
|
||||
regs.oam_itemcount = 0;
|
||||
regs.oam_tilecount = 0;
|
||||
memset(oam_line_pri, OAM_PRI_NONE, 512);
|
||||
memset(oam_line_pri, OAM_PRI_NONE, 256);
|
||||
|
||||
memset(oam_itemlist, 0xff, 32);
|
||||
for(s=0;s<128;s++) {
|
||||
@@ -239,32 +218,105 @@ uint8 *wt_sub = sub_windowtable[OAM];
|
||||
regs.time_over |= (regs.oam_tilecount > 34);
|
||||
regs.range_over |= (regs.oam_itemcount > 32);
|
||||
|
||||
if(_bg_enabled == false && _bgsub_enabled == false)return;
|
||||
int _pri;
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
if(regs.bg_enabled[OAM] == false && regs.bgsub_enabled[OAM] == false)return;
|
||||
|
||||
if(line.width == 256) {
|
||||
render_line_oam_lores(pri0_pos, pri1_pos, pri2_pos, pri3_pos);
|
||||
} else {
|
||||
render_line_oam_hires(pri0_pos, pri1_pos, pri2_pos, pri3_pos);
|
||||
}
|
||||
}
|
||||
|
||||
void bPPU::render_line_oam_lores(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) {
|
||||
bool bg_enabled = regs.bg_enabled[OAM];
|
||||
bool bgsub_enabled = regs.bgsub_enabled[OAM];
|
||||
|
||||
build_window_tables(OAM);
|
||||
uint8 *wt_main = window_cache[OAM].main;
|
||||
uint8 *wt_sub = window_cache[OAM].sub;
|
||||
|
||||
int pri;
|
||||
for(int x=0;x<256;x++) {
|
||||
if(oam_line_pri[x] == OAM_PRI_NONE)continue;
|
||||
|
||||
switch(oam_line_pri[x]) {
|
||||
case 0:_pri = pri0_pos;break;
|
||||
case 1:_pri = pri1_pos;break;
|
||||
case 2:_pri = pri2_pos;break;
|
||||
case 3:_pri = pri3_pos;break;
|
||||
case 0:pri = pri0_pos;break;
|
||||
case 1:pri = pri1_pos;break;
|
||||
case 2:pri = pri2_pos;break;
|
||||
case 3:pri = pri3_pos;break;
|
||||
}
|
||||
|
||||
if(main_colorwindowtable[x]) {
|
||||
if(_bg_enabled == true && !wt_main[x]) {
|
||||
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];
|
||||
}
|
||||
if(bg_enabled == true && !wt_main[x]) {
|
||||
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 = 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];
|
||||
}
|
||||
}
|
||||
|
||||
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 = get_palette(oam_line_pal[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bPPU::render_line_oam_hires(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) {
|
||||
bool bg_enabled = regs.bg_enabled[OAM];
|
||||
bool bgsub_enabled = regs.bgsub_enabled[OAM];
|
||||
|
||||
build_window_tables(OAM);
|
||||
uint8 *wt_main = window_cache[OAM].main;
|
||||
uint8 *wt_sub = window_cache[OAM].sub;
|
||||
|
||||
int pri, sx;
|
||||
for(int x=0;x<256;x++) {
|
||||
if(oam_line_pri[x] == OAM_PRI_NONE)continue;
|
||||
|
||||
switch(oam_line_pri[x]) {
|
||||
case 0:pri = pri0_pos;break;
|
||||
case 1:pri = pri1_pos;break;
|
||||
case 2:pri = pri2_pos;break;
|
||||
case 3:pri = pri3_pos;break;
|
||||
}
|
||||
|
||||
sx = x << 1;
|
||||
if(bg_enabled == true && !wt_main[sx]) {
|
||||
if(pixel_cache[sx].pri_main < pri) {
|
||||
pixel_cache[sx].pri_main = pri;
|
||||
pixel_cache[sx].bg_main = PC_OAM;
|
||||
pixel_cache[sx].src_main = get_palette(oam_line_pal[x]);
|
||||
pixel_cache[sx].color_exempt = (oam_line_pal[x] < 192);
|
||||
}
|
||||
}
|
||||
|
||||
if(bgsub_enabled == true && !wt_sub[sx]) {
|
||||
if(pixel_cache[sx].pri_sub < pri) {
|
||||
pixel_cache[sx].pri_sub = pri;
|
||||
pixel_cache[sx].bg_sub = PC_OAM;
|
||||
pixel_cache[sx].src_sub = get_palette(oam_line_pal[x]);
|
||||
}
|
||||
}
|
||||
|
||||
sx++;
|
||||
if(bg_enabled == true && !wt_main[sx]) {
|
||||
if(pixel_cache[sx].pri_main < pri) {
|
||||
pixel_cache[sx].pri_main = pri;
|
||||
pixel_cache[sx].bg_main = PC_OAM;
|
||||
pixel_cache[sx].src_main = get_palette(oam_line_pal[x]);
|
||||
pixel_cache[sx].color_exempt = (oam_line_pal[x] < 192);
|
||||
}
|
||||
}
|
||||
|
||||
if(bgsub_enabled == true && !wt_sub[sx]) {
|
||||
if(pixel_cache[sx].pri_sub < pri) {
|
||||
pixel_cache[sx].pri_sub = pri;
|
||||
pixel_cache[sx].bg_sub = PC_OAM;
|
||||
pixel_cache[sx].src_sub = get_palette(oam_line_pal[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,50 @@
|
||||
void bPPU::build_window_table(uint8 bg, uint8 *wtbl, bool mainscreen) {
|
||||
if(mainscreen == true && regs.bg_window_enabled[bg] == false) {
|
||||
memset(wtbl, 0, _screen_width);
|
||||
return;
|
||||
void bPPU::build_window_table(uint8 bg, bool mainscreen) {
|
||||
uint8 set = true, clr = false;
|
||||
uint8 *wtbl;
|
||||
if(mainscreen == true) {
|
||||
wtbl = (uint8*)window_cache[bg].main;
|
||||
} else {
|
||||
wtbl = (uint8*)window_cache[bg].sub;
|
||||
}
|
||||
if(mainscreen == false && regs.bgsub_window_enabled[bg] == false) {
|
||||
memset(wtbl, 0, _screen_width);
|
||||
return;
|
||||
|
||||
if(bg != COL) {
|
||||
if(mainscreen == true && regs.window_enabled[bg] == false) {
|
||||
memset(wtbl, 0, line.width);
|
||||
return;
|
||||
}
|
||||
if(mainscreen == false && regs.sub_window_enabled[bg] == false) {
|
||||
memset(wtbl, 0, line.width);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
uint8 mask;
|
||||
if(mainscreen == true) {
|
||||
mask = regs.color_mask;
|
||||
} else {
|
||||
mask = regs.colorsub_mask;
|
||||
}
|
||||
|
||||
if(mask == 0) {
|
||||
//always
|
||||
memset(wtbl, 1, line.width);
|
||||
return;
|
||||
}
|
||||
|
||||
if(mask == 3) {
|
||||
//never
|
||||
memset(wtbl, 0, line.width);
|
||||
return;
|
||||
}
|
||||
|
||||
if(mask == 1) {
|
||||
//inside window only
|
||||
set = 1;
|
||||
clr = 0;
|
||||
} else { //mask == 2
|
||||
//outside window only
|
||||
set = 0;
|
||||
clr = 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 window1_left, window1_right, window2_left, window2_right;
|
||||
@@ -17,61 +56,61 @@ bool r;
|
||||
window2_left = regs.window2_left;
|
||||
window2_right = regs.window2_right;
|
||||
|
||||
if(_screen_width == 512) {
|
||||
if(line.width == 512) {
|
||||
window1_left <<= 1;
|
||||
window1_right <<= 1;
|
||||
window2_left <<= 1;
|
||||
window2_right <<= 1;
|
||||
}
|
||||
|
||||
if(regs.bg_window1_enabled[bg] == false && regs.bg_window2_enabled[bg] == false) {
|
||||
memset(wtbl, 0, _screen_width);
|
||||
} else if(regs.bg_window1_enabled[bg] == true && regs.bg_window2_enabled[bg] == false) {
|
||||
if(regs.bg_window1_invert[bg] == false) {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
wtbl[x] = (x >= window1_left && x <= window1_right)?true:false;
|
||||
if(regs.window1_enabled[bg] == false && regs.window2_enabled[bg] == false) {
|
||||
memset(wtbl, clr, line.width);
|
||||
} else if(regs.window1_enabled[bg] == true && regs.window2_enabled[bg] == false) {
|
||||
if(regs.window1_invert[bg] == false) {
|
||||
for(x=0;x<line.width;x++) {
|
||||
wtbl[x] = (x >= window1_left && x <= window1_right) ? set : clr;
|
||||
}
|
||||
} else {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
wtbl[x] = (x < window1_left || x > window1_right)?true:false;
|
||||
for(x=0;x<line.width;x++) {
|
||||
wtbl[x] = (x < window1_left || x > window1_right) ? set : clr;
|
||||
}
|
||||
}
|
||||
} else if(regs.bg_window1_enabled[bg] == false && regs.bg_window2_enabled[bg] == true) {
|
||||
if(regs.bg_window2_invert[bg] == false) {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
wtbl[x] = (x >= window2_left && x <= window2_right)?true:false;
|
||||
} else if(regs.window1_enabled[bg] == false && regs.window2_enabled[bg] == true) {
|
||||
if(regs.window2_invert[bg] == false) {
|
||||
for(x=0;x<line.width;x++) {
|
||||
wtbl[x] = (x >= window2_left && x <= window2_right) ? set : clr;
|
||||
}
|
||||
} else {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
wtbl[x] = (x < window2_left || x > window2_right)?true:false;
|
||||
for(x=0;x<line.width;x++) {
|
||||
wtbl[x] = (x < window2_left || x > window2_right) ? set : clr;
|
||||
}
|
||||
}
|
||||
} else { //if(regs.bg_window1_enabled[bg] == true && regs.bg_window2_enabled[bg] == true) {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
if(regs.bg_window1_invert[bg] == false) {
|
||||
} else { //if(regs.window1_enabled[bg] == true && regs.window2_enabled[bg] == true) {
|
||||
for(x=0;x<line.width;x++) {
|
||||
if(regs.window1_invert[bg] == false) {
|
||||
w1_mask = (x >= window1_left && x <= window1_right);
|
||||
} else {
|
||||
w1_mask = (x < window1_left || x > window1_right);
|
||||
}
|
||||
|
||||
if(regs.bg_window2_invert[bg] == false) {
|
||||
if(regs.window2_invert[bg] == false) {
|
||||
w2_mask = (x >= window2_left && x <= window2_right);
|
||||
} else {
|
||||
w2_mask = (x < window2_left || x > window2_right);
|
||||
}
|
||||
|
||||
switch(regs.bg_window_mask[bg]) {
|
||||
switch(regs.window_mask[bg]) {
|
||||
case 0: //WINDOWMASK_OR:
|
||||
wtbl[x] = ((w1_mask | w2_mask) == 1)?true:false;
|
||||
wtbl[x] = ((w1_mask | w2_mask) == 1) ? set : clr;
|
||||
break;
|
||||
case 1: //WINDOWMASK_AND:
|
||||
wtbl[x] = ((w1_mask & w2_mask) == 1)?true:false;
|
||||
wtbl[x] = ((w1_mask & w2_mask) == 1) ? set : clr;
|
||||
break;
|
||||
case 2: //WINDOWMASK_XOR:
|
||||
wtbl[x] = ((w1_mask ^ w2_mask) == 1)?true:false;
|
||||
wtbl[x] = ((w1_mask ^ w2_mask) == 1) ? set : clr;
|
||||
break;
|
||||
case 3: //WINDOWMASK_XNOR:
|
||||
wtbl[x] = ((w1_mask ^ w2_mask) == 0)?true:false;
|
||||
wtbl[x] = ((w1_mask ^ w2_mask) == 0) ? set : clr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -79,105 +118,13 @@ bool r;
|
||||
}
|
||||
|
||||
void bPPU::build_window_tables(uint8 bg) {
|
||||
build_window_table(bg, main_windowtable[bg], true);
|
||||
build_window_table(bg, sub_windowtable[bg], false);
|
||||
}
|
||||
|
||||
void bPPU::build_color_window_table(uint8 *wtbl, uint8 mask) {
|
||||
if(mask == 0) {
|
||||
//always
|
||||
memset(wtbl, 1, _screen_width);
|
||||
return;
|
||||
if(window_cache[bg].main_dirty == true) {
|
||||
window_cache[bg].main_dirty = false;
|
||||
build_window_table(bg, true);
|
||||
}
|
||||
|
||||
if(mask == 3) {
|
||||
//never
|
||||
memset(wtbl, 0, _screen_width);
|
||||
return;
|
||||
}
|
||||
|
||||
int _true, _false;
|
||||
if(mask == 1) {
|
||||
//inside window only
|
||||
_true = 1;
|
||||
_false = 0;
|
||||
} else { //mask == 2
|
||||
//outside window only
|
||||
_true = 0;
|
||||
_false = 1;
|
||||
}
|
||||
|
||||
uint16 window1_left, window1_right, window2_left, window2_right;
|
||||
int w1_mask, w2_mask; //1 = masked, 0 = not masked
|
||||
int x;
|
||||
bool r;
|
||||
window1_left = regs.window1_left;
|
||||
window1_right = regs.window1_right;
|
||||
window2_left = regs.window2_left;
|
||||
window2_right = regs.window2_right;
|
||||
|
||||
if(_screen_width == 512) {
|
||||
window1_left <<= 1;
|
||||
window1_right <<= 1;
|
||||
window2_left <<= 1;
|
||||
window2_right <<= 1;
|
||||
}
|
||||
|
||||
if(regs.color_window1_enabled == false && regs.color_window2_enabled == false) {
|
||||
memset(wtbl, _false, _screen_width);
|
||||
} else if(regs.color_window1_enabled == true && regs.color_window2_enabled == false) {
|
||||
if(regs.color_window1_invert == false) {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
wtbl[x] = (x >= window1_left && x <= window1_right)?_true:_false;
|
||||
}
|
||||
} else {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
wtbl[x] = (x < window1_left || x > window1_right)?_true:_false;
|
||||
}
|
||||
}
|
||||
} else if(regs.color_window1_enabled == false && regs.color_window2_enabled == true) {
|
||||
if(regs.color_window2_invert == false) {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
wtbl[x] = (x >= window2_left && x <= window2_right)?_true:_false;
|
||||
}
|
||||
} else {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
wtbl[x] = (x < window2_left || x > window2_right)?_true:_false;
|
||||
}
|
||||
}
|
||||
} else { //if(regs.color_window1_enabled == true && regs.color_window2_enabled == true) {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
if(regs.color_window1_invert == false) {
|
||||
w1_mask = (x >= window1_left && x <= window1_right);
|
||||
} else {
|
||||
w1_mask = (x < window1_left || x > window1_right);
|
||||
}
|
||||
|
||||
if(regs.color_window2_invert == false) {
|
||||
w2_mask = (x >= window2_left && x <= window2_right);
|
||||
} else {
|
||||
w2_mask = (x < window2_left || x > window2_right);
|
||||
}
|
||||
|
||||
switch(regs.color_window_mask) {
|
||||
case 0: //WINDOWMASK_OR:
|
||||
wtbl[x] = ((w1_mask | w2_mask) == 1)?_true:_false;
|
||||
break;
|
||||
case 1: //WINDOWMASK_AND:
|
||||
wtbl[x] = ((w1_mask & w2_mask) == 1)?_true:_false;
|
||||
break;
|
||||
case 2: //WINDOWMASK_XOR:
|
||||
wtbl[x] = ((w1_mask ^ w2_mask) == 1)?_true:_false;
|
||||
break;
|
||||
case 3: //WINDOWMASK_XNOR:
|
||||
wtbl[x] = ((w1_mask ^ w2_mask) == 0)?_true:_false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(window_cache[bg].sub_dirty == true) {
|
||||
window_cache[bg].sub_dirty = false;
|
||||
build_window_table(bg, false);
|
||||
}
|
||||
}
|
||||
|
||||
void bPPU::build_color_window_tables() {
|
||||
build_color_window_table(main_colorwindowtable, regs.color_mask);
|
||||
build_color_window_table(sub_colorwindowtable, regs.colorsub_mask);
|
||||
}
|
||||
@@ -1,230 +0,0 @@
|
||||
void bPPU::set_sprite_attributes(uint8 sprite_num) {
|
||||
uint32 t;
|
||||
uint8 size, b;
|
||||
uint16 x;
|
||||
t = *((uint32*)oam + sprite_num);
|
||||
b = oam[512 + (sprite_num >> 2)];
|
||||
|
||||
switch(sprite_num & 3) {
|
||||
case 0: size = !!(b & 0x02); x = (b & 0x01)?0x100:0; break;
|
||||
case 1: size = !!(b & 0x08); x = (b & 0x04)?0x100:0; break;
|
||||
case 2: size = !!(b & 0x20); x = (b & 0x10)?0x100:0; break;
|
||||
case 3: size = !!(b & 0x80); x = (b & 0x40)?0x100:0; break;
|
||||
}
|
||||
|
||||
current_sprite.num = sprite_num;
|
||||
current_sprite.priority = (t >> 28) & 3;
|
||||
current_sprite.x = x | (t & 0xff);
|
||||
current_sprite.y = ((t >> 8) + 1) & 0xff;
|
||||
current_sprite.v_flip = !!(t & 0x80000000);
|
||||
current_sprite.h_flip = !!(t & 0x40000000);
|
||||
current_sprite.palette = (t >> 25) & 7;
|
||||
current_sprite.character = (t >> 16) & 0x01ff;
|
||||
|
||||
//size: 0 = small, 1 = large
|
||||
switch(regs.oam_basesize) {
|
||||
case 0:
|
||||
if(!size) { current_sprite.width = 8; current_sprite.height = 8; }
|
||||
else { current_sprite.width = 16; current_sprite.height = 16; }
|
||||
break;
|
||||
case 1:
|
||||
if(!size) { current_sprite.width = 8; current_sprite.height = 8; }
|
||||
else { current_sprite.width = 32; current_sprite.height = 32; }
|
||||
break;
|
||||
case 2:
|
||||
if(!size) { current_sprite.width = 8; current_sprite.height = 8; }
|
||||
else { current_sprite.width = 64; current_sprite.height = 64; }
|
||||
break;
|
||||
case 3:
|
||||
if(!size) { current_sprite.width = 16; current_sprite.height = 16; }
|
||||
else { current_sprite.width = 32; current_sprite.height = 32; }
|
||||
break;
|
||||
case 4:
|
||||
if(!size) { current_sprite.width = 16; current_sprite.height = 16; }
|
||||
else { current_sprite.width = 64; current_sprite.height = 64; }
|
||||
break;
|
||||
case 5:
|
||||
if(!size) { current_sprite.width = 32; current_sprite.height = 32; }
|
||||
else { current_sprite.width = 64; current_sprite.height = 64; }
|
||||
break;
|
||||
case 6:
|
||||
if(!size) { current_sprite.width = 16; current_sprite.height = 32; }
|
||||
else { current_sprite.width = 32; current_sprite.height = 64; }
|
||||
break;
|
||||
case 7:
|
||||
if(!size) { current_sprite.width = 16; current_sprite.height = 32; }
|
||||
else { current_sprite.width = 32; current_sprite.height = 32; }
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bPPU::render_oam_sprite() {
|
||||
uint16 pos, col, chr, tiledata_inc;
|
||||
uint8 d0, d1, d2, d3, pal_index;
|
||||
int x, y, z, x1, mx, mask, p;
|
||||
int tile_width;
|
||||
//uint8 item_inc, tile_inc;
|
||||
tile_width = current_sprite.width >> 3; //e.x. 16x16 sprite = 2x2 tiles
|
||||
|
||||
regs.oam_itemcount++;
|
||||
//add all visible tiles to regs.oam_tilecount
|
||||
if(current_sprite.x > 256) {
|
||||
//if sprite clips on left edge of the screen
|
||||
regs.oam_tilecount += ((current_sprite.x + current_sprite.width + 7) & 511) >> 3;
|
||||
} else if(current_sprite.x + current_sprite.width >= 257) {
|
||||
//if sprite clips on right edge of screen
|
||||
regs.oam_tilecount += (257 - current_sprite.x + 7) >> 3;
|
||||
} else {
|
||||
//if entire sprite is visible
|
||||
regs.oam_tilecount += current_sprite.width >> 3;
|
||||
}
|
||||
|
||||
//if(_y == 0xa0)dprintf("* oam_itemcount=%d, oam_tilecount=%d", regs.oam_itemcount, regs.oam_tilecount);
|
||||
|
||||
if(regs.bg_enabled[OAM] == false && regs.bgsub_enabled[OAM] == false)return;
|
||||
if(regs.oam_tilecount > 34)return;
|
||||
if(regs.oam_itemcount > 32)return;
|
||||
|
||||
if(_interlace == true && _screen_width == 512) {
|
||||
y = (_y << 1) + _interlace_field;
|
||||
} else {
|
||||
y = _y;
|
||||
}
|
||||
|
||||
x = current_sprite.x;
|
||||
if(_screen_width == 512) {
|
||||
x <<= 1;
|
||||
}
|
||||
|
||||
if(current_sprite.v_flip) {
|
||||
y = ((current_sprite.height - 1) - (_y - current_sprite.y));
|
||||
} else {
|
||||
y = (_y - current_sprite.y);
|
||||
}
|
||||
if(regs.oam_halve == true) {
|
||||
y <<= 1;
|
||||
if(_interlace == true && _screen_width == 512) {
|
||||
y += _interlace_field;
|
||||
}
|
||||
}
|
||||
y &= 255;
|
||||
|
||||
chr = current_sprite.character;
|
||||
tiledata_inc = (chr & 0x100)?(regs.oam_nameselect << 13):0;
|
||||
chr += (y >> 3) << 4;
|
||||
pal_index = (current_sprite.palette << 4);
|
||||
for(x1=0;x1<tile_width;x1++) {
|
||||
if(current_sprite.h_flip)mx = (tile_width - 1) - x1;
|
||||
else mx = x1;
|
||||
pos = regs.oam_tdaddr + ((chr + mx) << 5) + ((y & 7) << 1) + tiledata_inc;
|
||||
d0 = vram[pos ];
|
||||
d1 = vram[pos + 1];
|
||||
d2 = vram[pos + 16];
|
||||
d3 = vram[pos + 17];
|
||||
for(z=0;z<8;z++) {
|
||||
if(current_sprite.h_flip) {
|
||||
mask = 0x01 << z;
|
||||
} else {
|
||||
mask = 0x80 >> z;
|
||||
}
|
||||
x &= 511;
|
||||
if(x < _screen_width) {
|
||||
col = 0;
|
||||
if(d0 & mask)col += 1;
|
||||
if(d1 & mask)col += 2;
|
||||
if(d2 & mask)col += 4;
|
||||
if(d3 & mask)col += 8;
|
||||
if(col) {
|
||||
col += pal_index;
|
||||
col += 128;
|
||||
if(oam_line_pri[x] == OAM_PRI_NONE) {
|
||||
oam_line_pal[x] = col;
|
||||
oam_line_pri[x] = current_sprite.priority;
|
||||
}
|
||||
if(_screen_width == 512) {
|
||||
if(oam_line_pri[x + 1] == OAM_PRI_NONE) {
|
||||
oam_line_pal[x + 1] = col;
|
||||
oam_line_pri[x + 1] = current_sprite.priority;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
x += (_screen_width == 512)?2:1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bPPU::render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) {
|
||||
int s, x;
|
||||
bool _bg_enabled = regs.bg_enabled[OAM];
|
||||
bool _bgsub_enabled = regs.bgsub_enabled[OAM];
|
||||
|
||||
uint8 *wt_main = main_windowtable[OAM];
|
||||
uint8 *wt_sub = sub_windowtable[OAM];
|
||||
build_window_tables(OAM);
|
||||
|
||||
regs.oam_itemcount = 0;
|
||||
regs.oam_tilecount = 0;
|
||||
memset(oam_line_pri, OAM_PRI_NONE, 512);
|
||||
for(s=0;s<128;s++) {
|
||||
set_sprite_attributes((s + regs.oam_firstsprite) & 127);
|
||||
|
||||
//if sprite is entirely offscreen and doesn't wrap around to the left side of the screen,
|
||||
//then it is not counted. 256 is correct, and not 255 -- as one might first expect
|
||||
if(current_sprite.x > 256 && ((current_sprite.x + current_sprite.width) & 511) > 256)continue;
|
||||
|
||||
//if(_y == 0xa0)
|
||||
//dprintf("* y: %d, fs: %d, sprite: %d, width: %d, height: %d, x: %d, y: %d",
|
||||
// _y, regs.oam_firstsprite, (s + regs.oam_firstsprite) & 127,
|
||||
// current_sprite.width, current_sprite.height, current_sprite.x, current_sprite.y);
|
||||
|
||||
if(regs.oam_halve == false) {
|
||||
if(_y >= current_sprite.y && _y < (current_sprite.y + current_sprite.height)) {
|
||||
render_oam_sprite();
|
||||
} else if((current_sprite.y + current_sprite.height) >= 256 && _y < ((current_sprite.y + current_sprite.height) & 255)) {
|
||||
render_oam_sprite();
|
||||
}
|
||||
} else {
|
||||
if(_y >= current_sprite.y && _y < (current_sprite.y + (current_sprite.height >> 1))) {
|
||||
render_oam_sprite();
|
||||
} else if((current_sprite.y + (current_sprite.height >> 1)) >= 256 && _y < ((current_sprite.y + (current_sprite.height >> 1)) & 255)) {
|
||||
render_oam_sprite();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
regs.time_over |= (regs.oam_tilecount > 34);
|
||||
regs.range_over |= (regs.oam_itemcount > 32);
|
||||
//dprintf("* line: %d, t = %d, r = %d, tc = %d, ic = %d", _y,
|
||||
//regs.time_over, regs.range_over, regs.oam_tilecount, regs.oam_itemcount);
|
||||
|
||||
if(_bg_enabled == false && _bgsub_enabled == false)return;
|
||||
int _pri;
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
if(oam_line_pri[x] == OAM_PRI_NONE)continue;
|
||||
|
||||
switch(oam_line_pri[x]) {
|
||||
case 0:_pri = pri0_pos;break;
|
||||
case 1:_pri = pri1_pos;break;
|
||||
case 2:_pri = pri2_pos;break;
|
||||
case 3:_pri = pri3_pos;break;
|
||||
}
|
||||
|
||||
if(main_colorwindowtable[x]) {
|
||||
if(_bg_enabled == true && !wt_main[x]) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+38
-14
@@ -1,27 +1,51 @@
|
||||
#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;
|
||||
void PPU::get_scanline_info(scanline_info *info) {
|
||||
info->hires = scanline_is_hires();
|
||||
info->interlace = r_cpu->interlace();
|
||||
}
|
||||
|
||||
void PPU::enable_renderer(bool r) { status.render_output = r; }
|
||||
bool PPU::renderer_enabled() { return status.render_output; }
|
||||
|
||||
void PPU::frame() {
|
||||
status.frame_executed = true;
|
||||
|
||||
static int32 fr = 0, fe = 0;
|
||||
static time_t prev, curr;
|
||||
fe++;
|
||||
if(status.render_output)fr++;
|
||||
|
||||
time(&curr);
|
||||
if(curr != prev) {
|
||||
status.frames_updated = true;
|
||||
status.frames_rendered = fr;
|
||||
status.frames_executed = fe;
|
||||
fr = fe = 0;
|
||||
}
|
||||
prev = curr;
|
||||
}
|
||||
|
||||
PPUOutput::~PPUOutput() {
|
||||
if(buffer)memfree(buffer, "PPUOutput::buffer");
|
||||
}
|
||||
void PPU::power() {}
|
||||
|
||||
void PPU::set_frameskip(int fs) {}
|
||||
void PPU::reset() {
|
||||
memset(output, 0, 512 * 480 * sizeof(uint16));
|
||||
}
|
||||
|
||||
PPU::PPU() {
|
||||
output = (uint16*)malloc(512 * 480 * sizeof(uint16));
|
||||
memset(output, 0, 512 * 480 * sizeof(uint16));
|
||||
|
||||
status.render_output = true;
|
||||
status.frames_updated = false;
|
||||
status.frames_rendered = 0;
|
||||
status.frames_executed = 0;
|
||||
|
||||
ppu1_version = 1;
|
||||
ppu2_version = 1;
|
||||
mmio = &mmio_unmapped;
|
||||
output = new PPUOutput();
|
||||
}
|
||||
|
||||
PPU::~PPU() {
|
||||
if(output)delete(output);
|
||||
zerofree(output);
|
||||
}
|
||||
+38
-18
@@ -1,19 +1,37 @@
|
||||
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;
|
||||
uint16 *output;
|
||||
|
||||
//this struct should be read-only to
|
||||
//functions outside of this class
|
||||
struct {
|
||||
bool render_output;
|
||||
|
||||
bool frame_executed;
|
||||
bool frames_updated;
|
||||
uint32 frames_rendered;
|
||||
uint32 frames_executed;
|
||||
} status;
|
||||
|
||||
//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;
|
||||
|
||||
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 +43,12 @@ MMIO *mmio;
|
||||
|
||||
virtual void run() = 0;
|
||||
virtual void scanline() = 0;
|
||||
virtual void frame() = 0;
|
||||
virtual void power() = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual void set_frameskip(int fs);
|
||||
virtual void render_scanline() = 0;
|
||||
virtual void frame();
|
||||
virtual void power();
|
||||
virtual void reset();
|
||||
virtual void enable_renderer(bool r);
|
||||
virtual bool renderer_enabled();
|
||||
|
||||
PPU();
|
||||
~PPU();
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
uint32 FileReader::size() {
|
||||
return fsize;
|
||||
}
|
||||
|
||||
//This function will allocate memory even if open() fails.
|
||||
//This is needed so that when SRAM files do not exist, the
|
||||
//memory for the SRAM data will be allocated still.
|
||||
//The memory is flushed to 0x00 when no file is opened.
|
||||
void FileReader::read(uint8 **buffer, uint32 length) {
|
||||
uint8 *data;
|
||||
if(length == 0) {
|
||||
//read the entire file into RAM
|
||||
data = (uint8*)memalloc(fsize);
|
||||
memset(data, 0, fsize);
|
||||
if(fp)fread(data, 1, fsize, fp);
|
||||
} else if(length > fsize) {
|
||||
//read the entire file into RAM, pad the rest with 0x00s
|
||||
data = (uint8*)memalloc(length);
|
||||
memset(data, 0, length);
|
||||
if(fp)fread(data, 1, fsize, fp);
|
||||
} else { //fsize >= length
|
||||
//read only what was requested
|
||||
data = (uint8*)memalloc(length);
|
||||
memset(data, 0, length);
|
||||
if(fp)fread(data, 1, length, fp);
|
||||
}
|
||||
*buffer = data;
|
||||
}
|
||||
|
||||
bool FileReader::open(char *fn) {
|
||||
fp = fopen(fn, "rb");
|
||||
if(!fp)return false;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
fsize = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
//empty file?
|
||||
if(fsize == 0) {
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileReader::close() {
|
||||
if(fp) {
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void FileWriter::write(uint8 *buffer, uint32 length) {
|
||||
if(!fp)return;
|
||||
|
||||
fwrite(buffer, 1, length, fp);
|
||||
}
|
||||
|
||||
bool FileWriter::open(char *fn) {
|
||||
fp = fopen(fn, "wb");
|
||||
if(!fp)return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileWriter::close() {
|
||||
if(fp) {
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
class FileReader : public Reader {
|
||||
private:
|
||||
FILE *fp;
|
||||
uint32 fsize;
|
||||
|
||||
public:
|
||||
uint32 size();
|
||||
void read(uint8 **buffer, uint32 length = 0);
|
||||
bool open(char *fn);
|
||||
void close();
|
||||
|
||||
FileReader() { fp = 0; fsize = 0; }
|
||||
~FileReader() { if(fp)fclose(fp); }
|
||||
};
|
||||
|
||||
class FileWriter : public Writer {
|
||||
private:
|
||||
FILE *fp;
|
||||
|
||||
public:
|
||||
void write(uint8 *buffer, uint32 length);
|
||||
bool open(char *fn);
|
||||
void close();
|
||||
|
||||
FileWriter() { fp = 0; }
|
||||
~FileWriter() { if(fp)fclose(fp); }
|
||||
};
|
||||
+1
-78
@@ -1,79 +1,2 @@
|
||||
#include "../base.h"
|
||||
|
||||
uint32 FileReader::size() {
|
||||
return fsize;
|
||||
}
|
||||
|
||||
/*
|
||||
This function will allocate memory even if open() fails.
|
||||
This is needed so that when SRAM files do not exist, the
|
||||
memory for the SRAM data will be allocated still.
|
||||
|
||||
The memory is flushed to 0x00 when no file is opened.
|
||||
*/
|
||||
void FileReader::read(uint8 **buffer, uint32 length) {
|
||||
uint8 *data;
|
||||
if(length == 0) {
|
||||
/* read the entire file into RAM */
|
||||
data = (uint8*)memalloc(fsize);
|
||||
memset(data, 0, fsize);
|
||||
if(fp)fread(data, 1, fsize, fp);
|
||||
} else if(length > fsize) {
|
||||
/* read the entire file into RAM, pad the rest with 0x00s */
|
||||
data = (uint8*)memalloc(length);
|
||||
memset(data, 0, length);
|
||||
if(fp)fread(data, 1, fsize, fp);
|
||||
} else { //fsize >= length
|
||||
/* read as much of the file as possible, truncate the rest */
|
||||
data = (uint8*)memalloc(length);
|
||||
memset(data, 0, length);
|
||||
if(fp)fread(data, 1, length, fp);
|
||||
}
|
||||
*buffer = data;
|
||||
}
|
||||
|
||||
bool FileReader::open(uint8 type, char *fn) {
|
||||
fp = fopen(fn, "rb");
|
||||
if(!fp)return false;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
fsize = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
if(type == TYPE_ROM) {
|
||||
/* remove header if it exists */
|
||||
if((fsize & 0xfff) == 0x200) {
|
||||
fsize -= 0x200;
|
||||
fseek(fp, 0x200, SEEK_SET);
|
||||
}
|
||||
}
|
||||
|
||||
/* empty file? */
|
||||
if(fsize == 0) {
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileReader::close() {
|
||||
if(fp)fclose(fp);
|
||||
}
|
||||
|
||||
void FileWriter::write(uint8 *buffer, uint32 length) {
|
||||
if(!fp)return;
|
||||
|
||||
fwrite(buffer, 1, length, fp);
|
||||
}
|
||||
|
||||
bool FileWriter::open(char *fn) {
|
||||
fp = fopen(fn, "wb");
|
||||
if(!fp)return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileWriter::close() {
|
||||
if(fp)fclose(fp);
|
||||
}
|
||||
#include "filereader.cpp"
|
||||
+1
-31
@@ -4,39 +4,9 @@ public:
|
||||
virtual void read(uint8 **buffer, uint32 length = 0) = 0;
|
||||
};
|
||||
|
||||
class FileReader : public Reader {
|
||||
private:
|
||||
FILE *fp;
|
||||
uint32 fsize;
|
||||
|
||||
public:
|
||||
enum {
|
||||
TYPE_ROM = 0,
|
||||
TYPE_SRAM = 1
|
||||
};
|
||||
uint32 size();
|
||||
void read(uint8 **buffer, uint32 length = 0);
|
||||
bool open(uint8 type, char *fn);
|
||||
void close();
|
||||
|
||||
FileReader() { fp = 0; fsize = 0; }
|
||||
~FileReader() { if(fp)fclose(fp); }
|
||||
};
|
||||
|
||||
class Writer {
|
||||
public:
|
||||
virtual void write(uint8 *buffer, uint32 length) = 0;
|
||||
};
|
||||
|
||||
class FileWriter : public Writer {
|
||||
private:
|
||||
FILE *fp;
|
||||
|
||||
public:
|
||||
void write(uint8 *buffer, uint32 length);
|
||||
bool open(char *fn);
|
||||
void close();
|
||||
|
||||
FileWriter() { fp = 0; }
|
||||
~FileWriter() { if(fp)fclose(fp); }
|
||||
};
|
||||
#include "filereader.h"
|
||||
+23
-6
@@ -1,13 +1,15 @@
|
||||
CC = c++
|
||||
CFLAGS = -O2
|
||||
CFLAGS = -O3 -fomit-frame-pointer -ffast-math
|
||||
OBJS = sdlmain.o \
|
||||
libstring.o libconfig.o \
|
||||
reader.o \
|
||||
memory.o bmemory.o \
|
||||
cpu.o bcpu.o \
|
||||
apu.o bapu.o bapuskip.o \
|
||||
apu.o bapu.o \
|
||||
bdsp.o \
|
||||
ppu.o bppu.o \
|
||||
snes.o
|
||||
snes.o \
|
||||
srtc.o sdd1.o
|
||||
|
||||
all: $(OBJS)
|
||||
$(CC) $(CFLAGS) $(OBJS) `sdl11-config --cflags --libs` -o bsnes_sdl
|
||||
@@ -56,8 +58,11 @@ apu.o: ../apu/*
|
||||
bapu.o: ../apu/bapu/*
|
||||
$(CC) $(CFLAGS) -c ../apu/bapu/bapu.cpp
|
||||
|
||||
bapuskip.o: ../apu/bapuskip/*
|
||||
$(CC) $(CFLAGS) -c ../apu/bapuskip/bapuskip.cpp
|
||||
###########
|
||||
### dsp ###
|
||||
###########
|
||||
bdsp.o: ../dsp/bdsp/*
|
||||
$(CC) $(CFLAGS) -c ../dsp/bdsp/bdsp.cpp
|
||||
|
||||
###########
|
||||
### ppu ###
|
||||
@@ -71,7 +76,7 @@ bppu.o: ../ppu/bppu/*
|
||||
##############
|
||||
### reader ###
|
||||
##############
|
||||
reader.o: ../reader/reader.cpp ../reader/reader.h
|
||||
reader.o: ../reader/*.cpp ../reader/*.h
|
||||
$(CC) $(CFLAGS) -c ../reader/reader.cpp
|
||||
|
||||
############
|
||||
@@ -79,3 +84,15 @@ reader.o: ../reader/reader.cpp ../reader/reader.h
|
||||
############
|
||||
snes.o: ../snes/*.cpp ../snes/*.h
|
||||
$(CC) $(CFLAGS) -c ../snes/snes.cpp
|
||||
|
||||
############
|
||||
### srtc ###
|
||||
############
|
||||
srtc.o: ../chip/srtc/*.cpp ../chip/srtc/*.h
|
||||
$(CC) $(CFLAGS) -c ../chip/srtc/srtc.cpp
|
||||
|
||||
############
|
||||
### sdd1 ###
|
||||
############
|
||||
sdd1.o: ../chip/sdd1/*.cpp ../chip/sdd1/*.h
|
||||
$(CC) $(CFLAGS) -c ../chip/sdd1/sdd1.cpp
|
||||
Loaded 100 of 142 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user