mirror of
https://github.com/ares-emulator/ares.git
synced 2026-11-10 01:11:44 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49c39e0e4d | ||
|
|
7dec0b2a3c | ||
|
|
f288280ceb | ||
|
|
c6c5f4669c |
No files matched your search
@@ -13,75 +13,190 @@ snes.video_color_curve = true
|
||||
snes.video_color_adjust_mode = 0
|
||||
|
||||
# Mutes SNES audio output when enabled
|
||||
# (default = true)
|
||||
snes.mute = true
|
||||
# (default = false)
|
||||
snes.mute = false
|
||||
|
||||
# Video mode
|
||||
# 0 = 256x224w
|
||||
# 1 = 512x448w
|
||||
# 2 = 960x720w
|
||||
# 3 = 640x480f
|
||||
# 4 = 1024x768f
|
||||
# (default = 1)
|
||||
video.mode = 1
|
||||
# Regulate speed to 60hz (NTSC) / 50hz (PAL)
|
||||
# (default = true)
|
||||
system.regulate_speed = true
|
||||
|
||||
# Slowest speed setting (in hz)
|
||||
# (default = 16000)
|
||||
system.speed_slowest = 16000
|
||||
|
||||
# Slow speed setting
|
||||
# (default = 24000)
|
||||
system.speed_slow = 24000
|
||||
|
||||
# Normal speed setting
|
||||
# (default = 32000)
|
||||
system.speed_normal = 32000
|
||||
|
||||
# Fast speed setting
|
||||
# (default = 48000)
|
||||
system.speed_fast = 48000
|
||||
|
||||
# Fastest speed setting
|
||||
# (default = 64000)
|
||||
system.speed_fastest = 64000
|
||||
|
||||
# Video mode at startup
|
||||
# (default = 2)
|
||||
video.mode = 2
|
||||
|
||||
# Video mode 0 (windowed)
|
||||
# (default = "256x223")
|
||||
video.mode_0 = "256x223"
|
||||
|
||||
# Video mode 1 (windowed)
|
||||
# (default = "512x446")
|
||||
video.mode_1 = "512x446"
|
||||
|
||||
# Video mode 2 (windowed)
|
||||
# (default = "640x480")
|
||||
video.mode_2 = "640x480"
|
||||
|
||||
# Video mode 3 (windowed)
|
||||
# (default = "960x720")
|
||||
video.mode_3 = "960x720"
|
||||
|
||||
# Video mode 4 (windowed)
|
||||
# (default = "1152x864")
|
||||
video.mode_4 = "1152x864"
|
||||
|
||||
# Video mode 5 (fullscreen)
|
||||
# (default = "640x480@60:640x480")
|
||||
video.mode_5 = "640x480@60:640x480"
|
||||
|
||||
# Video mode 6 (fullscreen)
|
||||
# (default = "800x600@60:800x600")
|
||||
video.mode_6 = "800x600@60:800x600"
|
||||
|
||||
# Video mode 7 (fullscreen)
|
||||
# (default = "1024x768@60:1024x768")
|
||||
video.mode_7 = "1024x768@60:1024x768"
|
||||
|
||||
# Video mode 8 (fullscreen)
|
||||
# (default = "1280x960@60:1280x960")
|
||||
video.mode_8 = "1280x960@60:1280x960"
|
||||
|
||||
# Video mode 9 (fullscreen)
|
||||
# (default = "1600x1200@60:1600x1200")
|
||||
video.mode_9 = "1600x1200@60:1600x1200"
|
||||
|
||||
# Use Video RAM instead of System RAM
|
||||
# (default = true)
|
||||
video.use_vram = true
|
||||
|
||||
# Wait for vertical retrace when updating screen
|
||||
# Use triple buffering
|
||||
# (default = false)
|
||||
video.vblank = false
|
||||
video.triple_buffering = false
|
||||
|
||||
# Show framerate in window title
|
||||
# (default = true)
|
||||
gui.show_fps = false
|
||||
gui.show_fps = true
|
||||
|
||||
# Allow "impossible" key combinations for joypad 1 (not recommended)
|
||||
# (default = false)
|
||||
input.joypad1.allow_invalid_input = false
|
||||
|
||||
# Joypad1 up
|
||||
# (default = 0x26)
|
||||
input.joypad1.up = 0x26
|
||||
# (default = 0x80c8)
|
||||
input.joypad1.up = 0x80c8
|
||||
|
||||
# Joypad1 down
|
||||
# (default = 0x28)
|
||||
input.joypad1.down = 0x28
|
||||
# (default = 0x81d0)
|
||||
input.joypad1.down = 0x81d0
|
||||
|
||||
# Joypad1 left
|
||||
# (default = 0x25)
|
||||
input.joypad1.left = 0x25
|
||||
# (default = 0x82cb)
|
||||
input.joypad1.left = 0x82cb
|
||||
|
||||
# Joypad1 right
|
||||
# (default = 0x27)
|
||||
input.joypad1.right = 0x27
|
||||
# (default = 0x83cd)
|
||||
input.joypad1.right = 0x83cd
|
||||
|
||||
# Joypad1 A
|
||||
# (default = 0x58)
|
||||
input.joypad1.a = 0x58
|
||||
# (default = 0x42d)
|
||||
input.joypad1.a = 0x42d
|
||||
|
||||
# Joypad1 B
|
||||
# (default = 0x5a)
|
||||
input.joypad1.b = 0x5a
|
||||
# (default = 0x32c)
|
||||
input.joypad1.b = 0x32c
|
||||
|
||||
# Joypad1 X
|
||||
# (default = 0x53)
|
||||
input.joypad1.x = 0x53
|
||||
# (default = 0x11f)
|
||||
input.joypad1.x = 0x11f
|
||||
|
||||
# Joypad1 Y
|
||||
# (default = 0x41)
|
||||
input.joypad1.y = 0x41
|
||||
# (default = 0x1e)
|
||||
input.joypad1.y = 0x1e
|
||||
|
||||
# Joypad1 L
|
||||
# (default = 0x44)
|
||||
input.joypad1.l = 0x44
|
||||
# (default = 0x620)
|
||||
input.joypad1.l = 0x620
|
||||
|
||||
# Joypad1 R
|
||||
# (default = 0x43)
|
||||
input.joypad1.r = 0x43
|
||||
# (default = 0x72e)
|
||||
input.joypad1.r = 0x72e
|
||||
|
||||
# Joypad1 select
|
||||
# (default = 0x10)
|
||||
input.joypad1.select = 0x10
|
||||
# (default = 0x836)
|
||||
input.joypad1.select = 0x836
|
||||
|
||||
# Joypad1 start
|
||||
# (default = 0xd)
|
||||
input.joypad1.start = 0xd
|
||||
# (default = 0x91c)
|
||||
input.joypad1.start = 0x91c
|
||||
|
||||
# Allow "impossible" key combinations for joypad 2 (not recommended)
|
||||
# (default = false)
|
||||
input.joypad2.allow_invalid_input = false
|
||||
|
||||
# Joypad2 up
|
||||
# (default = 0xff14)
|
||||
input.joypad2.up = 0xff14
|
||||
|
||||
# Joypad2 down
|
||||
# (default = 0xff22)
|
||||
input.joypad2.down = 0xff22
|
||||
|
||||
# Joypad2 left
|
||||
# (default = 0xff21)
|
||||
input.joypad2.left = 0xff21
|
||||
|
||||
# Joypad2 right
|
||||
# (default = 0xff23)
|
||||
input.joypad2.right = 0xff23
|
||||
|
||||
# Joypad2 A
|
||||
# (default = 0xff25)
|
||||
input.joypad2.a = 0xff25
|
||||
|
||||
# Joypad2 B
|
||||
# (default = 0xff24)
|
||||
input.joypad2.b = 0xff24
|
||||
|
||||
# Joypad2 X
|
||||
# (default = 0xff17)
|
||||
input.joypad2.x = 0xff17
|
||||
|
||||
# Joypad2 Y
|
||||
# (default = 0xff16)
|
||||
input.joypad2.y = 0xff16
|
||||
|
||||
# Joypad2 L
|
||||
# (default = 0xff18)
|
||||
input.joypad2.l = 0xff18
|
||||
|
||||
# Joypad2 R
|
||||
# (default = 0xff26)
|
||||
input.joypad2.r = 0xff26
|
||||
|
||||
# Joypad2 select
|
||||
# (default = 0xff1a)
|
||||
input.joypad2.select = 0xff1a
|
||||
|
||||
# Joypad2 start
|
||||
# (default = 0xff1b)
|
||||
input.joypad2.start = 0xff1b
|
||||
|
||||
@@ -19,3 +19,8 @@ http://www.libsdl.org/
|
||||
|
||||
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.
|
||||
@@ -27,4 +27,7 @@ static const uint8 iplrom[64];
|
||||
virtual bool in_opcode();
|
||||
void disassemble_opcode(char *output);
|
||||
inline uint16 __relb(int8 offset, int op_len);
|
||||
|
||||
APU() {}
|
||||
virtual ~APU() {}
|
||||
};
|
||||
+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;
|
||||
|
||||
+13
-7
@@ -24,13 +24,13 @@ uint8 r;
|
||||
break;
|
||||
case 0xf3: //DSPDATA
|
||||
//0x80-0xff is a read-only mirror of 0x00-0x7f
|
||||
r = dsp->read(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->write(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) {
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
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
|
||||
|
||||
@@ -9,12 +9,11 @@ int16 r = x + y + regs.p.c;
|
||||
}
|
||||
|
||||
uint16 bAPU::op_addw(uint16 x, uint16 y) {
|
||||
int32 r = x + y;
|
||||
regs.p.n = !!(r & 0x8000);
|
||||
regs.p.v = !!(~(x ^ y) & (y ^ (uint16)r) & 0x8000);
|
||||
regs.p.h = !!((x ^ y ^ (uint16)r) & 0x10);
|
||||
int16 r;
|
||||
regs.p.c = 0;
|
||||
r = op_adc(x, y);
|
||||
r |= op_adc(x >> 8, y >> 8) << 8;
|
||||
regs.p.z = ((uint16)r == 0);
|
||||
regs.p.c = (r > 0xffff);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -66,12 +65,11 @@ int16 r = x - y - !regs.p.c;
|
||||
}
|
||||
|
||||
uint16 bAPU::op_subw(uint16 x, uint16 y) {
|
||||
int32 r = x - y;
|
||||
regs.p.n = !!(r & 0x8000);
|
||||
regs.p.v = !!((x ^ y) & (x ^ (uint16)r) & 0x8000);
|
||||
regs.p.h = !((x ^ y ^ (uint16)r) & 0x10);
|
||||
int16 r;
|
||||
regs.p.c = 1;
|
||||
r = op_sbc(x, y);
|
||||
r |= op_sbc(x >> 8, y >> 8) << 8;
|
||||
regs.p.z = ((uint16)r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+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,37 +0,0 @@
|
||||
class bAPUSkip : public APU {
|
||||
private:
|
||||
uint8 spcram[65536];
|
||||
|
||||
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);
|
||||
|
||||
uint8 *get_spcram_handle() { return spcram; }
|
||||
void run();
|
||||
uint32 cycles_executed() { return 12 * 24; }
|
||||
void power();
|
||||
void reset();
|
||||
};
|
||||
+31
@@ -1,9 +1,40 @@
|
||||
//debugging extensions (~10% speed hit)
|
||||
//#define DEBUGGER
|
||||
|
||||
//snes core polymorphism (allow mem/cpu/apu/ppu overriding,
|
||||
//~10% speed hit)
|
||||
//#define POLYMORPHISM
|
||||
|
||||
//enable GZ, ZIP format support
|
||||
#define GZIP_SUPPORT
|
||||
|
||||
//enable JMA support
|
||||
#define JMA_SUPPORT
|
||||
|
||||
//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"
|
||||
|
||||
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_
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
#include "../base.h"
|
||||
|
||||
void Cartridge::read_header() {
|
||||
cart.srtc = false;
|
||||
cart.sdd1 = false;
|
||||
cart.c4 = false;
|
||||
|
||||
if(cart.header_index == 0x7fc0 && cart.rom_size >= 0x401000) {
|
||||
cart.mapper = EXLOROM;
|
||||
} else if(cart.header_index == 0x7fc0 && rom[cart.header_index + MAPPER] == 0x32) {
|
||||
cart.mapper = EXLOROM;
|
||||
} else if(cart.header_index == 0x7fc0) {
|
||||
cart.mapper = LOROM;
|
||||
} else if(cart.header_index == 0xffc0) {
|
||||
cart.mapper = HIROM;
|
||||
} else { //cart.header_index == 0x40ffc0
|
||||
cart.mapper = EXHIROM;
|
||||
}
|
||||
|
||||
uint8 mapper = rom[cart.header_index + MAPPER];
|
||||
uint8 rom_type = rom[cart.header_index + ROM_TYPE];
|
||||
if(mapper == 0x35 && rom_type == 0x55) {
|
||||
cart.srtc = true;
|
||||
}
|
||||
|
||||
if(mapper == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
|
||||
cart.sdd1 = true;
|
||||
}
|
||||
|
||||
if(mapper == 0x20 && rom_type == 0xf3) {
|
||||
cart.c4 = true;
|
||||
}
|
||||
|
||||
if(rom[cart.header_index + SRAM_SIZE] & 7) {
|
||||
cart.sram_size = 1024 << (rom[cart.header_index + SRAM_SIZE] & 7);
|
||||
} else {
|
||||
cart.sram_size = 0;
|
||||
}
|
||||
|
||||
cart.region = (rom[cart.header_index + REGION] < 2) ? NTSC : PAL;
|
||||
|
||||
memcpy(&cart.name, &rom[cart.header_index + CART_NAME], 21);
|
||||
cart.name[21] = 0;
|
||||
|
||||
for(int i=0;i<22;i++) {
|
||||
if(cart.name[i] & 0x80) {
|
||||
cart.name[i] = '?';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::find_header() {
|
||||
int32 score_lo = 0,
|
||||
score_hi = 0,
|
||||
score_ex = 0;
|
||||
|
||||
if(rom_size < 0x010000) {
|
||||
//cart too small to be anything else
|
||||
cart.header_index = 0x007fc0;
|
||||
return;
|
||||
}
|
||||
|
||||
if((rom[0x7fc0 + MAPPER] & ~0x10) == 0x20)score_lo++;
|
||||
if((rom[0xffc0 + MAPPER] & ~0x10) == 0x21)score_hi++;
|
||||
|
||||
if(rom[0x7fc0 + ROM_TYPE] < 0x08)score_lo++;
|
||||
if(rom[0xffc0 + ROM_TYPE] < 0x08)score_hi++;
|
||||
|
||||
if(rom[0x7fc0 + ROM_SIZE] < 0x10)score_lo++;
|
||||
if(rom[0xffc0 + ROM_SIZE] < 0x10)score_hi++;
|
||||
|
||||
if(rom[0x7fc0 + SRAM_SIZE] < 0x08)score_lo++;
|
||||
if(rom[0xffc0 + SRAM_SIZE] < 0x08)score_hi++;
|
||||
|
||||
if(rom[0x7fc0 + REGION] < 14)score_lo++;
|
||||
if(rom[0xffc0 + REGION] < 14)score_hi++;
|
||||
|
||||
if(rom[0x7fc0 + LICENSE] < 3)score_lo++;
|
||||
if(rom[0xffc0 + LICENSE] < 3)score_hi++;
|
||||
|
||||
uint16 cksum, icksum;
|
||||
cksum = rom[0x7fc0 + CKSUM] | (rom[0x7fc0 + CKSUM + 1] << 8);
|
||||
icksum = rom[0x7fc0 + ICKSUM] | (rom[0x7fc0 + ICKSUM + 1] << 8);
|
||||
if((cksum + icksum) == 0xffff)score_lo += 8;
|
||||
cksum = rom[0xffc0 + CKSUM] | (rom[0xffc0 + CKSUM + 1] << 8);
|
||||
icksum = rom[0xffc0 + ICKSUM] | (rom[0xffc0 + ICKSUM + 1] << 8);
|
||||
if((cksum + icksum) == 0xffff)score_hi += 8;
|
||||
|
||||
if(rom_size < 0x401000) {
|
||||
score_ex = 0;
|
||||
} else {
|
||||
if(rom[0x7fc0 + MAPPER] == 0x32)score_lo++;
|
||||
else score_ex += 16;
|
||||
}
|
||||
|
||||
if(score_lo >= score_hi && score_lo >= score_ex) {
|
||||
cart.header_index = 0x007fc0;
|
||||
} else if(score_hi >= score_ex) {
|
||||
cart.header_index = 0x00ffc0;
|
||||
} else {
|
||||
cart.header_index = 0x40ffc0;
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::load_sram() {
|
||||
if(cart.sram_size == 0) {
|
||||
sram = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
FileReader ff;
|
||||
if(!ff.open(sram_fn)) {
|
||||
sram = (uint8*)malloc(cart.sram_size);
|
||||
memset(sram, 0, cart.sram_size);
|
||||
return;
|
||||
}
|
||||
|
||||
sram = ff.read(cart.sram_size);
|
||||
ff.close();
|
||||
}
|
||||
|
||||
void Cartridge::save_sram() {
|
||||
if(cart.sram_size == 0)return;
|
||||
|
||||
FileWriter ff;
|
||||
if(!ff.open(sram_fn))return;
|
||||
|
||||
ff.write(sram, cart.sram_size);
|
||||
ff.close();
|
||||
}
|
||||
|
||||
void Cartridge::load_rom(Reader *rf) {
|
||||
base_rom = rf->read();
|
||||
rom_size = rf->size();
|
||||
|
||||
if((rom_size & 0x7fff) == 0x0200) {
|
||||
rom = base_rom + 512;
|
||||
rom_size -= 512;
|
||||
} else {
|
||||
rom = base_rom;
|
||||
}
|
||||
|
||||
cart.rom_size = rom_size;
|
||||
}
|
||||
|
||||
bool Cartridge::load(const char *fn) {
|
||||
if(cart_loaded == true)return false;
|
||||
if(strlen(fn) < 3)return false;
|
||||
|
||||
dprintf("* Loading \"%s\"...", fn);
|
||||
|
||||
strcpy(rom_fn, fn);
|
||||
|
||||
switch(Reader::detect(rom_fn)) {
|
||||
case Reader::RF_NORMAL: {
|
||||
FileReader ff;
|
||||
if(!ff.open(rom_fn)) {
|
||||
alert("Error loading image file (%s)!", rom_fn);
|
||||
return false;
|
||||
}
|
||||
load_rom(static_cast<Reader*>(&ff));
|
||||
ff.close();
|
||||
break;
|
||||
}
|
||||
#ifdef GZIP_SUPPORT
|
||||
case Reader::RF_GZ: {
|
||||
GZReader gf;
|
||||
if(!gf.open(rom_fn)) {
|
||||
alert("Error loading image file (%s)!", rom_fn);
|
||||
return false;
|
||||
}
|
||||
load_rom(static_cast<Reader*>(&gf));
|
||||
gf.close();
|
||||
break;
|
||||
}
|
||||
case Reader::RF_ZIP: {
|
||||
ZipReader zf(rom_fn);
|
||||
load_rom(static_cast<Reader*>(&zf));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef JMA_SUPPORT
|
||||
case Reader::RF_JMA: {
|
||||
try {
|
||||
JMAReader jf(rom_fn);
|
||||
load_rom(static_cast<Reader*>(&jf));
|
||||
} catch(JMA::jma_errors jma_error) {
|
||||
alert("Error loading image file (%s)!", rom_fn);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int i;
|
||||
strcpy(sram_fn, fn);
|
||||
for(i=strlen(fn)-1;i>=0;i--) {
|
||||
if(fn[i] == '.')break;
|
||||
}
|
||||
if(i != 0)sram_fn[i] = 0;
|
||||
strcat(sram_fn, ".srm");
|
||||
|
||||
find_header();
|
||||
read_header();
|
||||
load_sram();
|
||||
cart_loaded = true;
|
||||
r_mem->load_cart();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Cartridge::unload() {
|
||||
if(cart_loaded == false)return false;
|
||||
|
||||
r_mem->unload_cart();
|
||||
|
||||
if(base_rom) {
|
||||
zerofree(base_rom);
|
||||
}
|
||||
|
||||
if(sram) {
|
||||
save_sram();
|
||||
zerofree(sram);
|
||||
}
|
||||
|
||||
cart_loaded = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Cartridge::Cartridge() {
|
||||
cart_loaded = false;
|
||||
|
||||
base_rom = 0;
|
||||
rom = 0;
|
||||
sram = 0;
|
||||
rom_size = 0;
|
||||
}
|
||||
|
||||
Cartridge::~Cartridge() {
|
||||
if(cart_loaded == true) {
|
||||
unload();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
class Cartridge {
|
||||
public:
|
||||
bool cart_loaded;
|
||||
char rom_fn[4096], sram_fn[4096];
|
||||
|
||||
uint8 *base_rom, *rom, *sram;
|
||||
uint32 rom_size;
|
||||
|
||||
enum {
|
||||
//header fields
|
||||
CART_NAME = 0x00,
|
||||
MAPPER = 0x15,
|
||||
ROM_TYPE = 0x16,
|
||||
ROM_SIZE = 0x17,
|
||||
SRAM_SIZE = 0x18,
|
||||
REGION = 0x19,
|
||||
LICENSE = 0x1a,
|
||||
VERSION = 0x1b,
|
||||
ICKSUM = 0x1c,
|
||||
CKSUM = 0x1e,
|
||||
|
||||
//regions
|
||||
NTSC = 0,
|
||||
PAL = 1,
|
||||
|
||||
//memory mappers
|
||||
LOROM = 0x20,
|
||||
HIROM = 0x21,
|
||||
EXLOROM = 0x22,
|
||||
EXHIROM = 0x25,
|
||||
};
|
||||
|
||||
struct {
|
||||
uint32 header_index;
|
||||
|
||||
char name[32];
|
||||
uint32 rom_size;
|
||||
uint32 sram_size;
|
||||
bool region;
|
||||
|
||||
uint32 mapper;
|
||||
bool srtc;
|
||||
bool sdd1;
|
||||
bool c4;
|
||||
} cart;
|
||||
|
||||
void load_rom(Reader *rf);
|
||||
void load_sram();
|
||||
void save_sram();
|
||||
void find_header();
|
||||
void read_header();
|
||||
bool load(const char *fn);
|
||||
bool unload();
|
||||
|
||||
Cartridge();
|
||||
~Cartridge();
|
||||
};
|
||||
|
||||
extern Cartridge cartridge;
|
||||
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
C4 emulation
|
||||
|
||||
Used in Rockman X2/X3 (Megaman X2/X3)
|
||||
Portions (c) anomie, Overload, zsKnight, Nach, byuu
|
||||
*/
|
||||
|
||||
#include "../../base.h"
|
||||
|
||||
#include "c4data.cpp"
|
||||
#include "c4fn.cpp"
|
||||
#include "c4oam.cpp"
|
||||
#include "c4ops.cpp"
|
||||
|
||||
void C4::init() {}
|
||||
void C4::enable() {}
|
||||
|
||||
uint32 C4::ldr(uint8 r) {
|
||||
uint16 addr = 0x0080 + (r * 3);
|
||||
return (reg[addr]) | (reg[addr + 1] << 8) | (reg[addr + 2] << 16);
|
||||
}
|
||||
|
||||
void C4::str(uint8 r, uint32 data) {
|
||||
uint16 addr = 0x0080 + (r * 3);
|
||||
reg[addr ] = (data);
|
||||
reg[addr + 1] = (data >> 8);
|
||||
reg[addr + 2] = (data >> 16);
|
||||
}
|
||||
|
||||
void C4::mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh) {
|
||||
int64 rx = x & 0xffffff;
|
||||
int64 ry = y & 0xffffff;
|
||||
if(rx & 0x800000)rx |= ~0x7fffff;
|
||||
if(ry & 0x800000)ry |= ~0x7fffff;
|
||||
|
||||
rx *= ry;
|
||||
|
||||
rl = (rx) & 0xffffff;
|
||||
rh = (rx >> 24) & 0xffffff;
|
||||
}
|
||||
|
||||
uint32 C4::sin(uint32 rx) {
|
||||
r0 = rx & 0x1ff;
|
||||
if(r0 & 0x100)r0 ^= 0x1ff;
|
||||
if(r0 & 0x080)r0 ^= 0x0ff;
|
||||
if(rx & 0x100) {
|
||||
return sin_table[r0 + 0x80];
|
||||
} else {
|
||||
return sin_table[r0];
|
||||
}
|
||||
}
|
||||
|
||||
uint32 C4::cos(uint32 rx) {
|
||||
return sin(rx + 0x080);
|
||||
}
|
||||
|
||||
void C4::immediate_reg(uint32 start) {
|
||||
r0 = ldr(0);
|
||||
for(uint32 i=start;i<48;i++) {
|
||||
if((r0 & 0x0fff) < 0x0c00) {
|
||||
ram[r0 & 0x0fff] = immediate_data[i];
|
||||
}
|
||||
r0++;
|
||||
}
|
||||
str(0, r0);
|
||||
}
|
||||
|
||||
void C4::transfer_data() {
|
||||
uint32 src;
|
||||
uint16 dest, count;
|
||||
src = (reg[0x40]) | (reg[0x41] << 8) | (reg[0x42] << 16);
|
||||
count = (reg[0x43]) | (reg[0x44] << 8);
|
||||
dest = (reg[0x45]) | (reg[0x46] << 8);
|
||||
|
||||
for(uint32 i=0;i<count;i++) {
|
||||
write(dest++, r_mem->read(src++));
|
||||
}
|
||||
}
|
||||
|
||||
void C4::write(uint16 addr, uint8 data) {
|
||||
addr &= 0x1fff;
|
||||
|
||||
if(addr < 0x0c00) {
|
||||
//ram
|
||||
ram[addr] = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr < 0x1f00) {
|
||||
//unmapped
|
||||
return;
|
||||
}
|
||||
|
||||
//command register
|
||||
reg[addr & 0xff] = data;
|
||||
|
||||
if(addr == 0x1f47) {
|
||||
//memory transfer
|
||||
transfer_data();
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0x1f4f) {
|
||||
//c4 command
|
||||
if(reg[0x4d] == 0x0e && !(data & 0xc3)) {
|
||||
//c4 test command
|
||||
reg[0x80] = data >> 2;
|
||||
return;
|
||||
}
|
||||
|
||||
switch(data) {
|
||||
case 0x00:op00();break;
|
||||
case 0x01:op01();break;
|
||||
case 0x05:op05();break;
|
||||
case 0x0d:op0d();break;
|
||||
case 0x10:op10();break;
|
||||
case 0x13:op13();break;
|
||||
case 0x15:op15();break;
|
||||
case 0x1f:op1f();break;
|
||||
case 0x22:op22();break;
|
||||
case 0x25:op25();break;
|
||||
case 0x2d:op2d();break;
|
||||
case 0x40:op40();break;
|
||||
case 0x54:op54();break;
|
||||
case 0x5c:op5c();break;
|
||||
case 0x5e:op5e();break;
|
||||
case 0x60:op60();break;
|
||||
case 0x62:op62();break;
|
||||
case 0x64:op64();break;
|
||||
case 0x66:op66();break;
|
||||
case 0x68:op68();break;
|
||||
case 0x6a:op6a();break;
|
||||
case 0x6c:op6c();break;
|
||||
case 0x6e:op6e();break;
|
||||
case 0x70:op70();break;
|
||||
case 0x72:op72();break;
|
||||
case 0x74:op74();break;
|
||||
case 0x76:op76();break;
|
||||
case 0x78:op78();break;
|
||||
case 0x7a:op7a();break;
|
||||
case 0x7c:op7c();break;
|
||||
case 0x89:op89();break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void C4::writeb(uint16 addr, uint8 data) {
|
||||
write(addr, data);
|
||||
}
|
||||
|
||||
void C4::writew(uint16 addr, uint16 data) {
|
||||
write(addr, data);
|
||||
write(addr + 1, data >> 8);
|
||||
}
|
||||
|
||||
void C4::writel(uint16 addr, uint32 data) {
|
||||
write(addr, data);
|
||||
write(addr + 1, data >> 8);
|
||||
write(addr + 2, data >> 16);
|
||||
}
|
||||
|
||||
uint8 C4::read(uint16 addr) {
|
||||
addr &= 0x1fff;
|
||||
|
||||
if(addr < 0x0c00) {
|
||||
return ram[addr];
|
||||
}
|
||||
|
||||
if(addr >= 0x1f00) {
|
||||
return reg[addr & 0xff];
|
||||
}
|
||||
|
||||
return r_cpu->regs.mdr;
|
||||
}
|
||||
|
||||
uint8 C4::readb(uint16 addr) {
|
||||
return read(addr);
|
||||
}
|
||||
|
||||
uint16 C4::readw(uint16 addr) {
|
||||
return read(addr) | (read(addr + 1) << 8);
|
||||
}
|
||||
|
||||
uint32 C4::readl(uint16 addr) {
|
||||
return read(addr) | (read(addr + 1) << 8) + (read(addr + 2) << 16);
|
||||
}
|
||||
|
||||
void C4::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void C4::reset() {
|
||||
memset(ram, 0, 0x0c00);
|
||||
memset(reg, 0, 0x0100);
|
||||
}
|
||||
|
||||
C4::C4() {}
|
||||
@@ -0,0 +1,94 @@
|
||||
class C4 {
|
||||
private:
|
||||
uint8 ram[0x0c00];
|
||||
uint8 reg[0x0100];
|
||||
uint32 r0, r1, r2, r3, r4, r5, r6, r7,
|
||||
r8, r9, r10, r11, r12, r13, r14, r15;
|
||||
|
||||
static const uint8 immediate_data[48];
|
||||
static const uint16 wave_data[40];
|
||||
static const uint32 sin_table[256];
|
||||
|
||||
static const int16 SinTable[512];
|
||||
static const int16 CosTable[512];
|
||||
|
||||
int16 C4WFXVal, C4WFYVal, C4WFZVal, C4WFX2Val, C4WFY2Val, C4WFDist, C4WFScale;
|
||||
int16 C41FXVal, C41FYVal, C41FAngleRes, C41FDist, C41FDistVal;
|
||||
|
||||
double tanval;
|
||||
double c4x,c4y,c4z, c4x2,c4y2,c4z2;
|
||||
|
||||
void C4TransfWireFrame();
|
||||
void C4TransfWireFrame2();
|
||||
void C4CalcWireFrame();
|
||||
void C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color);
|
||||
void C4DrawWireFrame();
|
||||
void C4DoScaleRotate(int row_padding);
|
||||
|
||||
public:
|
||||
uint32 ldr(uint8 r);
|
||||
void str(uint8 r, uint32 data);
|
||||
void mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh);
|
||||
uint32 sin(uint32 rx);
|
||||
uint32 cos(uint32 rx);
|
||||
|
||||
void transfer_data();
|
||||
void immediate_reg(uint32 num);
|
||||
|
||||
void op00_00();
|
||||
void op00_03();
|
||||
void op00_05();
|
||||
void op00_07();
|
||||
void op00_08();
|
||||
void op00_0b();
|
||||
void op00_0c();
|
||||
|
||||
void op00();
|
||||
void op01();
|
||||
void op05();
|
||||
void op0d();
|
||||
void op10();
|
||||
void op13();
|
||||
void op15();
|
||||
void op1f();
|
||||
void op22();
|
||||
void op25();
|
||||
void op2d();
|
||||
void op40();
|
||||
void op54();
|
||||
void op5c();
|
||||
void op5e();
|
||||
void op60();
|
||||
void op62();
|
||||
void op64();
|
||||
void op66();
|
||||
void op68();
|
||||
void op6a();
|
||||
void op6c();
|
||||
void op6e();
|
||||
void op70();
|
||||
void op72();
|
||||
void op74();
|
||||
void op76();
|
||||
void op78();
|
||||
void op7a();
|
||||
void op7c();
|
||||
void op89();
|
||||
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
void write (uint16 addr, uint8 data);
|
||||
void writeb(uint16 addr, uint8 data);
|
||||
void writew(uint16 addr, uint16 data);
|
||||
void writel(uint16 addr, uint32 data);
|
||||
|
||||
uint8 read (uint16 addr);
|
||||
uint8 readb(uint16 addr);
|
||||
uint16 readw(uint16 addr);
|
||||
uint32 readl(uint16 addr);
|
||||
|
||||
C4();
|
||||
};
|
||||
@@ -0,0 +1,183 @@
|
||||
const uint8 C4::immediate_data[48] = {
|
||||
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f,
|
||||
0x00, 0x80, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff,
|
||||
0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00
|
||||
};
|
||||
|
||||
const uint16 C4::wave_data[40] = {
|
||||
0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
|
||||
0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020a, 0x020c, 0x020e,
|
||||
0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e,
|
||||
0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060a, 0x060c, 0x060e,
|
||||
0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080a, 0x080c, 0x080e
|
||||
};
|
||||
|
||||
const uint32 C4::sin_table[256] = {
|
||||
0x000000, 0x000324, 0x000648, 0x00096c, 0x000c8f, 0x000fb2, 0x0012d5, 0x0015f6,
|
||||
0x001917, 0x001c37, 0x001f56, 0x002273, 0x002590, 0x0028aa, 0x002bc4, 0x002edb,
|
||||
0x0031f1, 0x003505, 0x003817, 0x003b26, 0x003e33, 0x00413e, 0x004447, 0x00474d,
|
||||
0x004a50, 0x004d50, 0x00504d, 0x005347, 0x00563e, 0x005931, 0x005c22, 0x005f0e,
|
||||
0x0061f7, 0x0064dc, 0x0067bd, 0x006a9b, 0x006d74, 0x007049, 0x007319, 0x0075e5,
|
||||
0x0078ad, 0x007b70, 0x007e2e, 0x0080e7, 0x00839c, 0x00864b, 0x0088f5, 0x008b9a,
|
||||
0x008e39, 0x0090d3, 0x009368, 0x0095f6, 0x00987f, 0x009b02, 0x009d7f, 0x009ff6,
|
||||
0x00a267, 0x00a4d2, 0x00a736, 0x00a994, 0x00abeb, 0x00ae3b, 0x00b085, 0x00b2c8,
|
||||
0x00b504, 0x00b73a, 0x00b968, 0x00bb8f, 0x00bdae, 0x00bfc7, 0x00c1d8, 0x00c3e2,
|
||||
0x00c5e4, 0x00c7de, 0x00c9d1, 0x00cbbb, 0x00cd9f, 0x00cf7a, 0x00d14d, 0x00d318,
|
||||
0x00d4db, 0x00d695, 0x00d848, 0x00d9f2, 0x00db94, 0x00dd2d, 0x00debe, 0x00e046,
|
||||
0x00e1c5, 0x00e33c, 0x00e4aa, 0x00e60f, 0x00e76b, 0x00e8bf, 0x00ea09, 0x00eb4b,
|
||||
0x00ec83, 0x00edb2, 0x00eed8, 0x00eff5, 0x00f109, 0x00f213, 0x00f314, 0x00f40b,
|
||||
0x00f4fa, 0x00f5de, 0x00f6ba, 0x00f78b, 0x00f853, 0x00f912, 0x00f9c7, 0x00fa73,
|
||||
0x00fb14, 0x00fbac, 0x00fc3b, 0x00fcbf, 0x00fd3a, 0x00fdab, 0x00fe13, 0x00fe70,
|
||||
0x00fec4, 0x00ff0e, 0x00ff4e, 0x00ff84, 0x00ffb1, 0x00ffd3, 0x00ffec, 0x00fffb,
|
||||
0x000000, 0xfffcdb, 0xfff9b7, 0xfff693, 0xfff370, 0xfff04d, 0xffed2a, 0xffea09,
|
||||
0xffe6e8, 0xffe3c8, 0xffe0a9, 0xffdd8c, 0xffda6f, 0xffd755, 0xffd43b, 0xffd124,
|
||||
0xffce0e, 0xffcafa, 0xffc7e8, 0xffc4d9, 0xffc1cc, 0xffbec1, 0xffbbb8, 0xffb8b2,
|
||||
0xffb5af, 0xffb2af, 0xffafb2, 0xffacb8, 0xffa9c1, 0xffa6ce, 0xffa3dd, 0xffa0f1,
|
||||
0xff9e08, 0xff9b23, 0xff9842, 0xff9564, 0xff928b, 0xff8fb6, 0xff8ce6, 0xff8a1a,
|
||||
0xff8752, 0xff848f, 0xff81d1, 0xff7f18, 0xff7c63, 0xff79b4, 0xff770a, 0xff7465,
|
||||
0xff71c6, 0xff6f2c, 0xff6c97, 0xff6a09, 0xff6780, 0xff64fd, 0xff6280, 0xff6009,
|
||||
0xff5d98, 0xff5b2d, 0xff58c9, 0xff566b, 0xff5414, 0xff51c4, 0xff4f7a, 0xff4d37,
|
||||
0xff4afb, 0xff48c5, 0xff4697, 0xff4470, 0xff4251, 0xff4038, 0xff3e27, 0xff3c1e,
|
||||
0xff3a1b, 0xff3821, 0xff362e, 0xff3444, 0xff3260, 0xff3085, 0xff2eb2, 0xff2ce7,
|
||||
0xff2b24, 0xff296a, 0xff27b7, 0xff260d, 0xff246b, 0xff22d2, 0xff2141, 0xff1fb9,
|
||||
0xff1e3a, 0xff1cc3, 0xff1b55, 0xff19f0, 0xff1894, 0xff1740, 0xff15f6, 0xff14b4,
|
||||
0xff137c, 0xff124d, 0xff1127, 0xff100a, 0xff0ef6, 0xff0dec, 0xff0ceb, 0xff0bf4,
|
||||
0xff0b05, 0xff0a21, 0xff0945, 0xff0874, 0xff07ac, 0xff06ed, 0xff0638, 0xff058d,
|
||||
0xff04eb, 0xff0453, 0xff03c4, 0xff0340, 0xff02c5, 0xff0254, 0xff01ec, 0xff018f,
|
||||
0xff013b, 0xff00f1, 0xff00b1, 0xff007b, 0xff004e, 0xff002c, 0xff0013, 0xff0004
|
||||
};
|
||||
|
||||
const int16 C4::SinTable[512] = {
|
||||
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
|
||||
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
|
||||
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
|
||||
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
|
||||
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
|
||||
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
|
||||
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
|
||||
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
|
||||
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
|
||||
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
|
||||
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
|
||||
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
|
||||
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
|
||||
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
|
||||
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
|
||||
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765,
|
||||
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
|
||||
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
|
||||
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
|
||||
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
|
||||
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
|
||||
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
|
||||
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
|
||||
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
|
||||
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
|
||||
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
|
||||
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
|
||||
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
|
||||
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
|
||||
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
|
||||
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
|
||||
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
|
||||
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
|
||||
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
|
||||
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
|
||||
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
|
||||
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
|
||||
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
|
||||
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
|
||||
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
|
||||
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
|
||||
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
|
||||
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
|
||||
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
|
||||
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
|
||||
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
|
||||
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
|
||||
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
|
||||
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
|
||||
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
|
||||
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
|
||||
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
|
||||
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
|
||||
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
|
||||
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
|
||||
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
|
||||
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
|
||||
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
|
||||
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
|
||||
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
|
||||
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
|
||||
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
|
||||
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
|
||||
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402
|
||||
};
|
||||
|
||||
const int16 C4::CosTable[512] = {
|
||||
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
|
||||
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
|
||||
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
|
||||
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
|
||||
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
|
||||
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
|
||||
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
|
||||
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
|
||||
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
|
||||
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
|
||||
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
|
||||
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
|
||||
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
|
||||
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
|
||||
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
|
||||
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
|
||||
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
|
||||
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
|
||||
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
|
||||
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
|
||||
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
|
||||
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
|
||||
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
|
||||
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
|
||||
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
|
||||
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
|
||||
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
|
||||
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
|
||||
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
|
||||
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
|
||||
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
|
||||
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
|
||||
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
|
||||
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
|
||||
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
|
||||
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
|
||||
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
|
||||
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
|
||||
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
|
||||
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
|
||||
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
|
||||
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
|
||||
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
|
||||
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
|
||||
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
|
||||
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
|
||||
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
|
||||
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402,
|
||||
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
|
||||
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
|
||||
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
|
||||
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
|
||||
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
|
||||
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
|
||||
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
|
||||
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
|
||||
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
|
||||
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
|
||||
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
|
||||
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
|
||||
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
|
||||
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
|
||||
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
|
||||
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765
|
||||
};
|
||||
@@ -0,0 +1,242 @@
|
||||
#include <math.h>
|
||||
#define Tan(a) (CosTable[a] ? ((((int32)SinTable[a]) << 16) / CosTable[a]) : 0x80000000)
|
||||
#define sar(b, n) ((b) >> (n))
|
||||
#ifdef PI
|
||||
#undef PI
|
||||
#endif
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
|
||||
//Wireframe Helpers
|
||||
void C4::C4TransfWireFrame() {
|
||||
c4x = (double)C4WFXVal;
|
||||
c4y = (double)C4WFYVal;
|
||||
c4z = (double)C4WFZVal - 0x95;
|
||||
|
||||
//Rotate X
|
||||
tanval = -(double)C4WFX2Val * PI * 2 / 128;
|
||||
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
|
||||
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
|
||||
|
||||
//Rotate Y
|
||||
tanval = -(double)C4WFY2Val * PI * 2 / 128;
|
||||
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
|
||||
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
|
||||
|
||||
//Rotate Z
|
||||
tanval = -(double)C4WFDist * PI * 2 / 128;
|
||||
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
|
||||
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
|
||||
|
||||
//Scale
|
||||
C4WFXVal = (int16)(c4x * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
|
||||
C4WFYVal = (int16)(c4y * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
|
||||
}
|
||||
|
||||
void C4::C4CalcWireFrame() {
|
||||
C4WFXVal = C4WFX2Val - C4WFXVal;
|
||||
C4WFYVal = C4WFY2Val - C4WFYVal;
|
||||
|
||||
if(abs(C4WFXVal) > abs(C4WFYVal)) {
|
||||
C4WFDist = abs(C4WFXVal) + 1;
|
||||
C4WFYVal = (256 * (long)C4WFYVal) / abs(C4WFXVal);
|
||||
C4WFXVal = (C4WFXVal < 0) ? -256 : 256;
|
||||
} else if(C4WFYVal != 0) {
|
||||
C4WFDist = abs(C4WFYVal) + 1;
|
||||
C4WFXVal = (256 * (long)C4WFXVal) / abs(C4WFYVal);
|
||||
C4WFYVal = (C4WFYVal < 0) ? -256 : 256;
|
||||
} else {
|
||||
C4WFDist = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void C4::C4TransfWireFrame2() {
|
||||
c4x = (double)C4WFXVal;
|
||||
c4y = (double)C4WFYVal;
|
||||
c4z = (double)C4WFZVal;
|
||||
|
||||
//Rotate X
|
||||
tanval = -(double)C4WFX2Val * PI * 2 / 128;
|
||||
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
|
||||
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
|
||||
|
||||
//Rotate Y
|
||||
tanval = -(double)C4WFY2Val * PI * 2 / 128;
|
||||
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
|
||||
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
|
||||
|
||||
//Rotate Z
|
||||
tanval = -(double)C4WFDist * PI * 2 / 128;
|
||||
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
|
||||
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
|
||||
|
||||
//Scale
|
||||
C4WFXVal = (int16)(c4x * C4WFScale / 0x100);
|
||||
C4WFYVal = (int16)(c4y * C4WFScale / 0x100);
|
||||
}
|
||||
|
||||
void C4::C4DrawWireFrame() {
|
||||
uint32 line = readl(0x1f80);
|
||||
uint32 point1, point2;
|
||||
int16 X1, Y1, Z1;
|
||||
int16 X2, Y2, Z2;
|
||||
uint8 Color;
|
||||
for(int32 i = ram[0x0295]; i > 0; i--, line += 5) {
|
||||
if(r_mem->read(line) == 0xff && r_mem->read(line + 1) == 0xff) {
|
||||
int32 tmp = line - 5;
|
||||
while(r_mem->read(tmp + 2) == 0xff && r_mem->read(tmp + 3) == 0xff && (tmp + 2) >= 0) { tmp -= 5; }
|
||||
point1 = (read(0x1f82) << 16) | (r_mem->read(tmp + 2) << 8) | r_mem->read(tmp + 3);
|
||||
} else {
|
||||
point1 = (read(0x1f82) << 16) | (r_mem->read(line) << 8) | r_mem->read(line + 1);
|
||||
}
|
||||
point2 = (read(0x1f82) << 16) | (r_mem->read(line + 2) << 8) | r_mem->read(line + 3);
|
||||
|
||||
X1=(r_mem->read(point1 + 0) << 8) | r_mem->read(point1 + 1);
|
||||
Y1=(r_mem->read(point1 + 2) << 8) | r_mem->read(point1 + 3);
|
||||
Z1=(r_mem->read(point1 + 4) << 8) | r_mem->read(point1 + 5);
|
||||
X2=(r_mem->read(point2 + 0) << 8) | r_mem->read(point2 + 1);
|
||||
Y2=(r_mem->read(point2 + 2) << 8) | r_mem->read(point2 + 3);
|
||||
Z2=(r_mem->read(point2 + 4) << 8) | r_mem->read(point2 + 5);
|
||||
Color = r_mem->read(line + 4);
|
||||
C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color);
|
||||
}
|
||||
}
|
||||
|
||||
void C4::C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color) {
|
||||
//Transform coordinates
|
||||
C4WFXVal = (int16)X1;
|
||||
C4WFYVal = (int16)Y1;
|
||||
C4WFZVal = Z1;
|
||||
C4WFScale = read(0x1f90);
|
||||
C4WFX2Val = read(0x1f86);
|
||||
C4WFY2Val = read(0x1f87);
|
||||
C4WFDist = read(0x1f88);
|
||||
C4TransfWireFrame2();
|
||||
X1 = (C4WFXVal + 48) << 8;
|
||||
Y1 = (C4WFYVal + 48) << 8;
|
||||
|
||||
C4WFXVal = (int16)X2;
|
||||
C4WFYVal = (int16)Y2;
|
||||
C4WFZVal = Z2;
|
||||
C4TransfWireFrame2();
|
||||
X2 = (C4WFXVal + 48) << 8;
|
||||
Y2 = (C4WFYVal + 48) << 8;
|
||||
|
||||
//Get line info
|
||||
C4WFXVal = (int16)(X1 >> 8);
|
||||
C4WFYVal = (int16)(Y1 >> 8);
|
||||
C4WFX2Val = (int16)(X2 >> 8);
|
||||
C4WFY2Val = (int16)(Y2 >> 8);
|
||||
C4CalcWireFrame();
|
||||
X2 = (int16)C4WFXVal;
|
||||
Y2 = (int16)C4WFYVal;
|
||||
|
||||
//Render line
|
||||
for(int32 i = C4WFDist ? C4WFDist : 1; i > 0; i--) {
|
||||
if(X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000) {
|
||||
uint16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2;
|
||||
uint8 bit = 0x80 >> ((X1 >> 8) & 7);
|
||||
ram[addr + 0x300] &= ~bit;
|
||||
ram[addr + 0x301] &= ~bit;
|
||||
if(Color & 1) { ram[addr + 0x300] |= bit; }
|
||||
if(Color & 2) { ram[addr + 0x301] |= bit; }
|
||||
}
|
||||
X1 += X2;
|
||||
Y1 += Y2;
|
||||
}
|
||||
}
|
||||
|
||||
void C4::C4DoScaleRotate(int row_padding) {
|
||||
int16 A, B, C, D;
|
||||
|
||||
//Calculate matrix
|
||||
int32 XScale = readw(0x1f8f);
|
||||
int32 YScale = readw(0x1f92);
|
||||
if(XScale & 0x8000)XScale = 0x7fff;
|
||||
if(YScale & 0x8000)YScale = 0x7fff;
|
||||
|
||||
if(readw(0x1f80) == 0) { //no rotation
|
||||
A = (int16)XScale;
|
||||
B = 0;
|
||||
C = 0;
|
||||
D = (int16)YScale;
|
||||
} else if(readw(0x1f80) == 128) { //90 degree rotation
|
||||
A = 0;
|
||||
B = (int16)(-YScale);
|
||||
C = (int16)XScale;
|
||||
D = 0;
|
||||
} else if(readw(0x1f80) == 256) { //180 degree rotation
|
||||
A = (int16)(-XScale);
|
||||
B = 0;
|
||||
C = 0;
|
||||
D = (int16)(-YScale);
|
||||
} else if(readw(0x1f80) == 384) { //270 degree rotation
|
||||
A = 0;
|
||||
B = (int16)YScale;
|
||||
C = (int16)(-XScale);
|
||||
D = 0;
|
||||
} else {
|
||||
A = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * XScale, 15);
|
||||
B = (int16)(-sar(SinTable[readw(0x1f80) & 0x1ff] * YScale, 15));
|
||||
C = (int16) sar(SinTable[readw(0x1f80) & 0x1ff] * XScale, 15);
|
||||
D = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * YScale, 15);
|
||||
}
|
||||
|
||||
//Calculate Pixel Resolution
|
||||
uint8 w = read(0x1f89) & ~7;
|
||||
uint8 h = read(0x1f8c) & ~7;
|
||||
|
||||
//Clear the output RAM
|
||||
memset(ram, 0, (w + row_padding / 4) * h / 2);
|
||||
|
||||
int32 Cx = (int16)readw(0x1f83);
|
||||
int32 Cy = (int16)readw(0x1f86);
|
||||
|
||||
//Calculate start position (i.e. (Ox, Oy) = (0, 0))
|
||||
//The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in
|
||||
//the function. We do Cx*A etc normally because the matrix parameters
|
||||
//already have the fractional parts.
|
||||
int32 LineX = (Cx << 12) - Cx * A - Cx * B;
|
||||
int32 LineY = (Cy << 12) - Cy * C - Cy * D;
|
||||
|
||||
//Start loop
|
||||
uint32 X, Y;
|
||||
uint8 byte;
|
||||
int32 outidx = 0;
|
||||
uint8 bit = 0x80;
|
||||
for(int32 y = 0; y < h; y++) {
|
||||
X = LineX;
|
||||
Y = LineY;
|
||||
for(int32 x = 0; x < w; x++) {
|
||||
if((X >> 12) >= w || (Y >> 12) >= h) {
|
||||
byte = 0;
|
||||
} else {
|
||||
uint32 addr = (Y >> 12) * w + (X >> 12);
|
||||
byte = read(0x600 + (addr >> 1));
|
||||
if(addr & 1) { byte >>= 4; }
|
||||
}
|
||||
|
||||
//De-bitplanify
|
||||
if(byte & 1) { ram[outidx ] |= bit; }
|
||||
if(byte & 2) { ram[outidx + 1] |= bit; }
|
||||
if(byte & 4) { ram[outidx + 16] |= bit; }
|
||||
if(byte & 8) { ram[outidx + 17] |= bit; }
|
||||
|
||||
bit >>= 1;
|
||||
if(!bit) {
|
||||
bit = 0x80;
|
||||
outidx += 32;
|
||||
}
|
||||
|
||||
X += A; //Add 1 to output x => add an A and a C
|
||||
Y += C;
|
||||
}
|
||||
outidx += 2 + row_padding;
|
||||
if(outidx & 0x10) {
|
||||
outidx &= ~0x10;
|
||||
} else {
|
||||
outidx -= w * 4 + row_padding;
|
||||
}
|
||||
LineX += B; //Add 1 to output y => add a B and a D
|
||||
LineY += D;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
//Build OAM
|
||||
void C4::op00_00() {
|
||||
uint32 oamptr = ram[0x626] << 2;
|
||||
for(int32 i=0x1fd;i>oamptr && i>=0;i-=4) {
|
||||
//clear oam-to-be
|
||||
if(i >= 0)ram[i] = 0xe0;
|
||||
}
|
||||
|
||||
uint16 globalx, globaly;
|
||||
uint32 oamptr2;
|
||||
int16 sprx, spry;
|
||||
uint8 sprname, sprattr;
|
||||
uint8 sprcount;
|
||||
globalx = readw(0x621);
|
||||
globaly = readw(0x623);
|
||||
oamptr2 = 0x200 + (ram[0x626] >> 2);
|
||||
|
||||
if(!ram[0x620])return;
|
||||
|
||||
sprcount = 128 - ram[0x626];
|
||||
uint8 offset = (ram[0x626] & 3) * 2;
|
||||
for(int pri=0x30;pri>=0;pri-=0x10) {
|
||||
uint32 srcptr = 0x220;
|
||||
for(int i=ram[0x620];i>0 && sprcount>0;i--, srcptr+=16) {
|
||||
if((ram[srcptr + 4] & 0x30) != pri)continue;
|
||||
sprx = readw(srcptr) - globalx;
|
||||
spry = readw(srcptr + 2) - globaly;
|
||||
sprname = ram[srcptr + 5];
|
||||
sprattr = ram[srcptr + 4] | ram[srcptr + 6];
|
||||
|
||||
uint32 spraddr = readl(srcptr + 7);
|
||||
if(r_mem->read(spraddr)) {
|
||||
int16 x, y;
|
||||
for(int sprcnt=r_mem->read(spraddr++);sprcnt>0 && sprcount>0;sprcnt--, spraddr+=4) {
|
||||
x = (int8)r_mem->read(spraddr + 1);
|
||||
if(sprattr & 0x40) {
|
||||
x = -x - ((r_mem->read(spraddr) & 0x20) ? 16 : 8);
|
||||
}
|
||||
x += sprx;
|
||||
if(x >= -16 && x <= 272) {
|
||||
y = (int8)r_mem->read(spraddr + 2);
|
||||
if(sprattr & 0x80) {
|
||||
y = -y - ((r_mem->read(spraddr) & 0x20) ? 16 : 8);
|
||||
}
|
||||
y += spry;
|
||||
if(y >= -16 && y <= 224) {
|
||||
ram[oamptr ] = (uint8)x;
|
||||
ram[oamptr + 1] = (uint8)y;
|
||||
ram[oamptr + 2] = sprname + r_mem->read(spraddr + 3);
|
||||
ram[oamptr + 3] = sprattr ^ (r_mem->read(spraddr) & 0xc0);
|
||||
ram[oamptr2] &= ~(3 << offset);
|
||||
if(x & 0x100)ram[oamptr2] |= 1 << offset;
|
||||
if(r_mem->read(spraddr) & 0x20)ram[oamptr2] |= 2 << offset;
|
||||
oamptr += 4;
|
||||
sprcount--;
|
||||
offset = (offset + 2) & 6;
|
||||
if(!offset)oamptr2++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(sprcount > 0) {
|
||||
ram[oamptr ] = (uint8)sprx;
|
||||
ram[oamptr + 1] = (uint8)spry;
|
||||
ram[oamptr + 2] = sprname;
|
||||
ram[oamptr + 3] = sprattr;
|
||||
ram[oamptr2] &= ~(3 << offset);
|
||||
if(sprx & 0x100)ram[oamptr2] |= 3 << offset;
|
||||
else ram[oamptr2] |= 2 << offset;
|
||||
oamptr += 4;
|
||||
sprcount--;
|
||||
offset = (offset + 2) & 6;
|
||||
if(!offset)oamptr2++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Scale and Rotate
|
||||
void C4::op00_03() {
|
||||
C4DoScaleRotate(0);
|
||||
}
|
||||
|
||||
//Transform Lines
|
||||
void C4::op00_05() {
|
||||
C4WFX2Val = read(0x1f83);
|
||||
C4WFY2Val = read(0x1f86);
|
||||
C4WFDist = read(0x1f89);
|
||||
C4WFScale = read(0x1f8c);
|
||||
|
||||
//Transform Vertices
|
||||
uint32 ptr = 0;
|
||||
for(int32 i = readw(0x1f80); i > 0; i--, ptr += 0x10) {
|
||||
C4WFXVal = readw(ptr + 1);
|
||||
C4WFYVal = readw(ptr + 5);
|
||||
C4WFZVal = readw(ptr + 9);
|
||||
C4TransfWireFrame();
|
||||
|
||||
//Displace
|
||||
writew(ptr + 1, C4WFXVal + 0x80);
|
||||
writew(ptr + 5, C4WFYVal + 0x50);
|
||||
}
|
||||
|
||||
writew(0x600, 23);
|
||||
writew(0x602, 0x60);
|
||||
writew(0x605, 0x40);
|
||||
writew(0x600 + 8, 23);
|
||||
writew(0x602 + 8, 0x60);
|
||||
writew(0x605 + 8, 0x40);
|
||||
|
||||
ptr = 0xb02;
|
||||
uint32 ptr2 = 0;
|
||||
for(int32 i = readw(0xb00); i > 0; i--, ptr += 2, ptr2 += 8) {
|
||||
C4WFXVal = readw((read(ptr + 0) << 4) + 1);
|
||||
C4WFYVal = readw((read(ptr + 0) << 4) + 5);
|
||||
C4WFX2Val = readw((read(ptr + 1) << 4) + 1);
|
||||
C4WFY2Val = readw((read(ptr + 1) << 4) + 5);
|
||||
C4CalcWireFrame();
|
||||
writew(ptr2 + 0x600, C4WFDist ? C4WFDist : 1);
|
||||
writew(ptr2 + 0x602, C4WFXVal);
|
||||
writew(ptr2 + 0x605, C4WFYVal);
|
||||
}
|
||||
}
|
||||
|
||||
//Scale and Rotate
|
||||
void C4::op00_07() {
|
||||
C4DoScaleRotate(64);
|
||||
}
|
||||
|
||||
//Draw Wireframe
|
||||
void C4::op00_08() {
|
||||
C4DrawWireFrame();
|
||||
}
|
||||
|
||||
//Disintegrate
|
||||
void C4::op00_0b() {
|
||||
uint8 width, height;
|
||||
uint32 startx, starty;
|
||||
uint32 srcptr;
|
||||
uint32 x, y;
|
||||
int32 scalex, scaley;
|
||||
int32 cx, cy;
|
||||
int32 i, j;
|
||||
width = read(0x1f89);
|
||||
height = read(0x1f8c);
|
||||
cx = readw(0x1f80);
|
||||
cy = readw(0x1f83);
|
||||
|
||||
scalex = (int16)readw(0x1f86);
|
||||
scaley = (int16)readw(0x1f8f);
|
||||
startx = -cx * scalex + (cx << 8);
|
||||
starty = -cy * scaley + (cy << 8);
|
||||
srcptr = 0x600;
|
||||
|
||||
for(i = 0; i < (width * height) >> 1; i++) {
|
||||
write(i, 0);
|
||||
}
|
||||
|
||||
for(y = starty, i = 0;i < height; i++, y += scaley) {
|
||||
for(x = startx, j = 0;j < width; j++, x += scalex) {
|
||||
if((x >> 8) < width && (y >> 8) < height && (y >> 8) * width + (x >> 8) < 0x2000) {
|
||||
uint8 pixel = (j & 1) ? (ram[srcptr] >> 4) : (ram[srcptr]);
|
||||
int32 index = (y >> 11) * width * 4 + (x >> 11) * 32 + ((y >> 8) & 7) * 2;
|
||||
uint8 mask = 0x80 >> ((x >> 8) & 7);
|
||||
if(pixel & 1)ram[index ] |= mask;
|
||||
if(pixel & 2)ram[index + 1] |= mask;
|
||||
if(pixel & 4)ram[index + 16] |= mask;
|
||||
if(pixel & 8)ram[index + 17] |= mask;
|
||||
}
|
||||
if(j & 1)srcptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Bitplane Wave
|
||||
void C4::op00_0c() {
|
||||
uint32 destptr = 0;
|
||||
uint32 waveptr = read(0x1f83);
|
||||
uint16 mask1 = 0xc0c0;
|
||||
uint16 mask2 = 0x3f3f;
|
||||
|
||||
int32 i, j;
|
||||
int16 height, temp;
|
||||
for(j = 0; j < 0x10; j++) {
|
||||
do {
|
||||
height = -((int8)ram[waveptr + 0xb00]) - 16;
|
||||
for(i = 0; i < 40; i++) {
|
||||
temp = readw(destptr + wave_data[i]) & mask2;
|
||||
if(height >= 0) {
|
||||
if(height < 8) {
|
||||
temp |= mask1 & readw(0xa00 + height * 2);
|
||||
} else {
|
||||
temp |= mask1 & 0xff00;
|
||||
}
|
||||
}
|
||||
writew(destptr + wave_data[i], temp);
|
||||
height++;
|
||||
}
|
||||
waveptr = (waveptr + 1) & 0x7f;
|
||||
mask1 = (mask1 >> 2) | (mask1 << 6);
|
||||
mask2 = (mask2 >> 2) | (mask2 << 6);
|
||||
} while(mask1 != 0xc0c0);
|
||||
destptr += 16;
|
||||
|
||||
do {
|
||||
height = -((int8)ram[waveptr + 0xb00]) - 16;
|
||||
for(i = 0; i < 40; i++) {
|
||||
temp = readw(destptr + wave_data[i]) & mask2;
|
||||
if(height >= 0) {
|
||||
if(height < 8) {
|
||||
temp |= mask1 & readw(0xa10 + height * 2);
|
||||
} else {
|
||||
temp |= mask1 & 0xff00;
|
||||
}
|
||||
writew(destptr + wave_data[i], temp);
|
||||
height++;
|
||||
}
|
||||
waveptr = (waveptr + 1) & 0x7f;
|
||||
mask1 = (mask1 >> 2) | (mask1 << 6);
|
||||
mask2 = (mask2 >> 2) | (mask2 << 6);
|
||||
}
|
||||
} while(mask1 != 0xc0c0);
|
||||
destptr += 16;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
//Sprite Functions
|
||||
void C4::op00() {
|
||||
switch(reg[0x4d]) {
|
||||
case 0x00:op00_00();break;
|
||||
case 0x03:op00_03();break;
|
||||
case 0x05:op00_05();break;
|
||||
case 0x07:op00_07();break;
|
||||
case 0x08:op00_08();break;
|
||||
case 0x0b:op00_0b();break;
|
||||
case 0x0c:op00_0c();break;
|
||||
}
|
||||
}
|
||||
|
||||
//Draw Wireframe
|
||||
void C4::op01() {
|
||||
memset(ram + 0x300, 0, 2304);
|
||||
C4DrawWireFrame();
|
||||
}
|
||||
|
||||
//Propulsion
|
||||
void C4::op05() {
|
||||
int32 temp = 0x10000;
|
||||
if(readw(0x1f83)) {
|
||||
temp = sar((temp / readw(0x1f83)) * readw(0x1f81), 8);
|
||||
}
|
||||
writew(0x1f80, temp);
|
||||
}
|
||||
|
||||
//Set Vector length
|
||||
void C4::op0d() {
|
||||
C41FXVal = readw(0x1f80);
|
||||
C41FYVal = readw(0x1f83);
|
||||
C41FDistVal = readw(0x1f86);
|
||||
tanval = sqrt(((double)C41FYVal) * ((double)C41FYVal) + ((double)C41FXVal) * ((double)C41FXVal));
|
||||
tanval = (double)C41FDistVal / tanval;
|
||||
C41FYVal = (int16)(((double)C41FYVal * tanval) * 0.99);
|
||||
C41FXVal = (int16)(((double)C41FXVal * tanval) * 0.98);
|
||||
writew(0x1f89, C41FXVal);
|
||||
writew(0x1f8c, C41FYVal);
|
||||
}
|
||||
|
||||
//Triangle
|
||||
void C4::op10() {
|
||||
r0 = ldr(0);
|
||||
r1 = ldr(1);
|
||||
|
||||
r4 = r0 & 0x1ff;
|
||||
if(r1 & 0x8000)r1 |= ~0x7fff;
|
||||
|
||||
mul(cos(r4), r1, r5, r2);
|
||||
r5 = (r5 >> 16) & 0xff;
|
||||
r2 = (r2 << 8) + r5;
|
||||
|
||||
mul(sin(r4), r1, r5, r3);
|
||||
r5 = (r5 >> 16) & 0xff;
|
||||
r3 = (r3 << 8) + r5;
|
||||
|
||||
str(0, r0);
|
||||
str(1, r1);
|
||||
str(2, r2);
|
||||
str(3, r3);
|
||||
str(4, r4);
|
||||
str(5, r5);
|
||||
}
|
||||
|
||||
//Triangle
|
||||
void C4::op13() {
|
||||
r0 = ldr(0);
|
||||
r1 = ldr(1);
|
||||
|
||||
r4 = r0 & 0x1ff;
|
||||
|
||||
mul(cos(r4), r1, r5, r2);
|
||||
r5 = (r5 >> 8) & 0xffff;
|
||||
r2 = (r2 << 16) + r5;
|
||||
|
||||
mul(sin(r4), r1, r5, r3);
|
||||
r5 = (r5 >> 8) & 0xffff;
|
||||
r3 = (r3 << 16) + r5;
|
||||
|
||||
str(0, r0);
|
||||
str(1, r1);
|
||||
str(2, r2);
|
||||
str(3, r3);
|
||||
str(4, r4);
|
||||
str(5, r5);
|
||||
}
|
||||
|
||||
//Pythagorean
|
||||
void C4::op15() {
|
||||
C41FXVal = readw(0x1f80);
|
||||
C41FYVal = readw(0x1f83);
|
||||
C41FDist = (int16)sqrt((double)C41FXVal * (double)C41FXVal + (double)C41FYVal * (double)C41FYVal);
|
||||
writew(0x1f80, C41FDist);
|
||||
}
|
||||
|
||||
//Calculate distance
|
||||
void C4::op1f() {
|
||||
C41FXVal = readw(0x1f80);
|
||||
C41FYVal = readw(0x1f83);
|
||||
if(!C41FXVal) {
|
||||
C41FAngleRes = (C41FYVal > 0) ? 0x080 : 0x180;
|
||||
} else {
|
||||
tanval = ((double)C41FYVal) / ((double)C41FXVal);
|
||||
C41FAngleRes = (short)(atan(tanval) / (PI * 2) * 512);
|
||||
C41FAngleRes = C41FAngleRes;
|
||||
if(C41FXVal < 0) {
|
||||
C41FAngleRes += 0x100;
|
||||
}
|
||||
C41FAngleRes &= 0x1ff;
|
||||
}
|
||||
writew(0x1f86, C41FAngleRes);
|
||||
}
|
||||
|
||||
//Trapezoid
|
||||
void C4::op22() {
|
||||
int16 angle1 = readw(0x1f8c) & 0x1ff;
|
||||
int16 angle2 = readw(0x1f8f) & 0x1ff;
|
||||
int32 tan1 = Tan(angle1);
|
||||
int32 tan2 = Tan(angle2);
|
||||
int16 y = readw(0x1f83) - readw(0x1f89);
|
||||
int16 left, right;
|
||||
for(int32 j = 0; j < 225; j++, y++) {
|
||||
if(y >= 0) {
|
||||
left = sar((int32)tan1 * y, 16) - readw(0x1f80) + readw(0x1f86);
|
||||
right = sar((int32)tan2 * y, 16) - readw(0x1f80) + readw(0x1f86) + readw(0x1f93);
|
||||
|
||||
if(left < 0 && right < 0) {
|
||||
left = 1;
|
||||
right = 0;
|
||||
} else if(left < 0) {
|
||||
left = 0;
|
||||
} else if(right < 0) {
|
||||
right = 0;
|
||||
}
|
||||
|
||||
if(left > 255 && right > 255) {
|
||||
left = 255;
|
||||
right = 254;
|
||||
} else if(left > 255) {
|
||||
left = 255;
|
||||
} else if(right > 255) {
|
||||
right = 255;
|
||||
}
|
||||
} else {
|
||||
left = 1;
|
||||
right = 0;
|
||||
}
|
||||
ram[j + 0x800] = (uint8)left;
|
||||
ram[j + 0x900] = (uint8)right;
|
||||
}
|
||||
}
|
||||
|
||||
//Multiply
|
||||
void C4::op25() {
|
||||
r0 = ldr(0);
|
||||
r1 = ldr(1);
|
||||
mul(r0, r1, r0, r1);
|
||||
str(0, r0);
|
||||
str(1, r1);
|
||||
}
|
||||
|
||||
//Transform Coords
|
||||
void C4::op2d() {
|
||||
C4WFXVal = readw(0x1f81);
|
||||
C4WFYVal = readw(0x1f84);
|
||||
C4WFZVal = readw(0x1f87);
|
||||
C4WFX2Val = read (0x1f89);
|
||||
C4WFY2Val = read (0x1f8a);
|
||||
C4WFDist = read (0x1f8b);
|
||||
C4WFScale = readw(0x1f90);
|
||||
C4TransfWireFrame2();
|
||||
writew(0x1f80, C4WFXVal);
|
||||
writew(0x1f83, C4WFYVal);
|
||||
}
|
||||
|
||||
//Sum
|
||||
void C4::op40() {
|
||||
r0 = 0;
|
||||
for(uint32 i=0;i<0x800;i++) {
|
||||
r0 += ram[i];
|
||||
}
|
||||
str(0, r0);
|
||||
}
|
||||
|
||||
//Square
|
||||
void C4::op54() {
|
||||
r0 = ldr(0);
|
||||
mul(r0, r0, r1, r2);
|
||||
str(1, r1);
|
||||
str(2, r2);
|
||||
}
|
||||
|
||||
//Immediate Register
|
||||
void C4::op5c() {
|
||||
str(0, 0x000000);
|
||||
immediate_reg(0);
|
||||
}
|
||||
|
||||
//Immediate Register (Multiple)
|
||||
void C4::op5e() { immediate_reg( 0); }
|
||||
void C4::op60() { immediate_reg( 3); }
|
||||
void C4::op62() { immediate_reg( 6); }
|
||||
void C4::op64() { immediate_reg( 9); }
|
||||
void C4::op66() { immediate_reg(12); }
|
||||
void C4::op68() { immediate_reg(15); }
|
||||
void C4::op6a() { immediate_reg(18); }
|
||||
void C4::op6c() { immediate_reg(21); }
|
||||
void C4::op6e() { immediate_reg(24); }
|
||||
void C4::op70() { immediate_reg(27); }
|
||||
void C4::op72() { immediate_reg(30); }
|
||||
void C4::op74() { immediate_reg(33); }
|
||||
void C4::op76() { immediate_reg(36); }
|
||||
void C4::op78() { immediate_reg(39); }
|
||||
void C4::op7a() { immediate_reg(42); }
|
||||
void C4::op7c() { immediate_reg(45); }
|
||||
|
||||
//Immediate ROM
|
||||
void C4::op89() {
|
||||
str(0, 0x054336);
|
||||
str(1, 0xffffff);
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
#include "../../base.h"
|
||||
#include "sdd1emu.cpp"
|
||||
|
||||
void SDD1::init() {
|
||||
}
|
||||
void SDD1::init() {}
|
||||
|
||||
void SDD1::enable() {
|
||||
for(int i=0x4800;i<=0x4807;i++) {
|
||||
mem_bus->set_mmio_mapper(i, mmio);
|
||||
r_mem->set_mmio_mapper(i, mmio);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +46,7 @@ uint8 SDD1::mmio_read(uint16 addr) {
|
||||
case 0x4807:return (sdd1.index[3] >> 20) & 7;
|
||||
}
|
||||
|
||||
return cpu->regs.mdr;
|
||||
return r_cpu->regs.mdr;
|
||||
}
|
||||
|
||||
void SDD1::mmio_write(uint16 addr, uint8 data) {
|
||||
|
||||
@@ -28,7 +28,7 @@ understood.
|
||||
|
||||
************************************************************************/
|
||||
|
||||
#define SDD1_read(__addr) (mem_bus->read(__addr))
|
||||
#define SDD1_read(__addr) (r_mem->read(__addr))
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -74,12 +74,11 @@ tm *t;
|
||||
srtc.data[12] = t->tm_wday;
|
||||
}
|
||||
|
||||
void SRTC::init() {
|
||||
}
|
||||
void SRTC::init() {}
|
||||
|
||||
void SRTC::enable() {
|
||||
mem_bus->set_mmio_mapper(0x2800, mmio);
|
||||
mem_bus->set_mmio_mapper(0x2801, mmio);
|
||||
r_mem->set_mmio_mapper(0x2800, mmio);
|
||||
r_mem->set_mmio_mapper(0x2801, mmio);
|
||||
}
|
||||
|
||||
void SRTC::power() {
|
||||
@@ -176,7 +175,7 @@ uint8 SRTCMMIO::read(uint32 addr) {
|
||||
case 0x2800:return srtc->read();
|
||||
}
|
||||
|
||||
return cpu->regs.mdr;
|
||||
return r_cpu->regs.mdr;
|
||||
}
|
||||
|
||||
void SRTCMMIO::write(uint32 addr, uint8 value) {
|
||||
|
||||
+19
-3
@@ -21,8 +21,24 @@ void SNES::VideoColorAdjust::set(uint32 _data) {
|
||||
::snes->update_color_lookup_table();
|
||||
}
|
||||
|
||||
Setting SNES::mute(&config_file, "snes.mute",
|
||||
"Mutes SNES audio output when enabled",
|
||||
true, Setting::TRUE_FALSE);
|
||||
Setting SNES::mute(&config_file, "snes.mute", "Mutes SNES audio output when enabled",
|
||||
false, Setting::TRUE_FALSE);
|
||||
|
||||
//do not save these settings to config_file
|
||||
Setting CPU::hdma_enable(0, "cpu.hdma_enable", "Enable HDMA effects", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::opt_enable(0, "ppu.opt_enable", "Enable offset-per-tile effects", true, Setting::TRUE_FALSE);
|
||||
|
||||
Setting PPU::bg1_pri0_enable(0, "ppu.bg1_pri0_enable", "Enable BG1 Priority 0", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::bg1_pri1_enable(0, "ppu.bg1_pri1_enable", "Enable BG1 Priority 1", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::bg2_pri0_enable(0, "ppu.bg2_pri0_enable", "Enable BG2 Priority 0", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::bg2_pri1_enable(0, "ppu.bg2_pri1_enable", "Enable BG2 Priority 1", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::bg3_pri0_enable(0, "ppu.bg3_pri0_enable", "Enable BG3 Priority 0", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::bg3_pri1_enable(0, "ppu.bg3_pri1_enable", "Enable BG3 Priority 1", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::bg4_pri0_enable(0, "ppu.bg4_pri0_enable", "Enable BG4 Priority 0", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::bg4_pri1_enable(0, "ppu.bg4_pri1_enable", "Enable BG4 Priority 1", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::oam_pri0_enable(0, "ppu.oam_pri0_enable", "Enable OAM Priority 0", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::oam_pri1_enable(0, "ppu.oam_pri1_enable", "Enable OAM Priority 1", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::oam_pri2_enable(0, "ppu.oam_pri2_enable", "Enable OAM Priority 2", true, Setting::TRUE_FALSE);
|
||||
Setting PPU::oam_pri3_enable(0, "ppu.oam_pri3_enable", "Enable OAM Priority 3", true, Setting::TRUE_FALSE);
|
||||
|
||||
};
|
||||
@@ -12,4 +12,19 @@ extern struct SNES {
|
||||
static Setting mute;
|
||||
} snes;
|
||||
|
||||
extern struct CPU {
|
||||
static Setting hdma_enable;
|
||||
} cpu;
|
||||
|
||||
extern struct PPU {
|
||||
static Setting opt_enable;
|
||||
|
||||
static Setting bg1_pri0_enable, bg1_pri1_enable;
|
||||
static Setting bg2_pri0_enable, bg2_pri1_enable;
|
||||
static Setting bg3_pri0_enable, bg3_pri1_enable;
|
||||
static Setting bg4_pri0_enable, bg4_pri1_enable;
|
||||
static Setting oam_pri0_enable, oam_pri1_enable;
|
||||
static Setting oam_pri2_enable, oam_pri3_enable;
|
||||
} ppu;
|
||||
|
||||
};
|
||||
+57
-44
@@ -18,54 +18,61 @@
|
||||
uint8 bCPU::pio_status() { return status.pio; }
|
||||
|
||||
void bCPU::run() {
|
||||
switch(status.cpu_state) {
|
||||
case CPUSTATE_DMA:
|
||||
dma_run();
|
||||
break;
|
||||
case CPUSTATE_WAI:
|
||||
case CPUSTATE_RUN:
|
||||
if(status.cycle_pos == 0) {
|
||||
//interrupts only trigger on opcode edges
|
||||
if(time.nmi_pending == true) {
|
||||
time.nmi_pending = false;
|
||||
irq(0xffea);
|
||||
break;
|
||||
}
|
||||
if(time.irq_pending == true) {
|
||||
time.irq_pending = false;
|
||||
irq(0xffee);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//fallthrough
|
||||
case CPUSTATE_STP:
|
||||
exec_cycle();
|
||||
break;
|
||||
if(run_state.hdma) {
|
||||
exec_hdma();
|
||||
return;
|
||||
}
|
||||
|
||||
cycle_edge();
|
||||
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;
|
||||
status.joypad2_read_pos = 16;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::frame() {
|
||||
hdma_initialize();
|
||||
|
||||
time.nmi_read = 1;
|
||||
time.nmi_line = 1;
|
||||
time.nmi_transition = 0;
|
||||
|
||||
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() {
|
||||
@@ -78,7 +85,7 @@ void bCPU::power() {
|
||||
|
||||
void bCPU::reset() {
|
||||
//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;
|
||||
@@ -94,21 +101,27 @@ void bCPU::reset() {
|
||||
mmio_reset();
|
||||
dma_reset();
|
||||
|
||||
status.cpu_state = CPUSTATE_RUN;
|
||||
status.dma_state = DMASTATE_STOP;
|
||||
run_state.hdma = false;
|
||||
run_state.dma = false;
|
||||
run_state.irq = false;
|
||||
run_state.wai = false;
|
||||
run_state.stp = false;
|
||||
|
||||
status.cycle_pos = 0;
|
||||
status.cycle_count = 0;
|
||||
status.cycles_executed = 0;
|
||||
|
||||
status.hdma_triggered = false;
|
||||
|
||||
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) {
|
||||
@@ -141,32 +154,32 @@ void bCPU::cpu_c6(uint16 addr) {
|
||||
* cpu_io is an I/O cycle, and always 6 clock cycles long.
|
||||
* mem_read / mem_write indicate memory access bus cycle,
|
||||
* they are either 6, 8, or 12 bus cycles long, depending
|
||||
* both on location and the $420d.1 FastROM enable bit.
|
||||
* both on location and the $420d.d0 FastROM enable bit.
|
||||
*/
|
||||
|
||||
void bCPU::cpu_io() {
|
||||
if(status.is_last_cycle)last_cycle_exec();
|
||||
|
||||
status.cycle_count = 6;
|
||||
pre_exec_cycle();
|
||||
add_cycles(6);
|
||||
cycle_edge();
|
||||
}
|
||||
|
||||
uint8 bCPU::mem_read(uint32 addr) {
|
||||
if(status.is_last_cycle)last_cycle_exec();
|
||||
|
||||
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 = mem_bus->read(addr);
|
||||
regs.mdr = r_mem->read(addr);
|
||||
add_cycles(4);
|
||||
cycle_edge();
|
||||
return regs.mdr;
|
||||
}
|
||||
|
||||
void bCPU::mem_write(uint32 addr, uint8 value) {
|
||||
if(status.is_last_cycle)last_cycle_exec();
|
||||
|
||||
status.cycle_count = mem_bus->speed(addr);
|
||||
status.cycle_count = r_mem->speed(addr);
|
||||
pre_exec_cycle();
|
||||
add_cycles(status.cycle_count);
|
||||
mem_bus->write(addr, value);
|
||||
r_mem->write(addr, value);
|
||||
cycle_edge();
|
||||
}
|
||||
|
||||
uint32 bCPU::op_addr(uint8 mode, uint32 addr) {
|
||||
|
||||
+55
-29
@@ -32,32 +32,39 @@ CPUReg24 aa, rd;
|
||||
uint8 dp, sp;
|
||||
|
||||
enum {
|
||||
CPUSTATE_RUN = 0,
|
||||
CPUSTATE_WAI,
|
||||
CPUSTATE_STP,
|
||||
CPUSTATE_DMA
|
||||
};
|
||||
|
||||
enum {
|
||||
DMASTATE_STOP = 0,
|
||||
DMASTATE_DMASYNC,
|
||||
DMASTATE_DMASYNC2,
|
||||
DMASTATE_DMASYNC3,
|
||||
DMASTATE_RUN,
|
||||
DMASTATE_CPUSYNC,
|
||||
DMASTATE_CPUSYNC2
|
||||
|
||||
HDMASTATE_IDMASYNC,
|
||||
HDMASTATE_IDMASYNC2,
|
||||
HDMASTATE_IDMASYNC3,
|
||||
HDMASTATE_ICPUSYNC,
|
||||
|
||||
HDMASTATE_DMASYNC,
|
||||
HDMASTATE_DMASYNC2,
|
||||
HDMASTATE_DMASYNC3,
|
||||
HDMASTATE_RUN,
|
||||
HDMASTATE_CPUSYNC
|
||||
};
|
||||
|
||||
struct {
|
||||
uint8 cpu_state, cycle_pos, cycle_count;
|
||||
bool hdma;
|
||||
bool dma;
|
||||
bool irq;
|
||||
bool stp;
|
||||
bool wai;
|
||||
} run_state;
|
||||
|
||||
struct {
|
||||
uint8 cycle_pos, cycle_count;
|
||||
uint8 opcode;
|
||||
uint32 cycles_executed;
|
||||
|
||||
//set by last_cycle(), cleared by last_cycle_exec()
|
||||
bool is_last_cycle;
|
||||
|
||||
uint8 dma_state;
|
||||
uint32 dma_cycle_count;
|
||||
bool hdma_triggered;
|
||||
uint8 dma_state, hdma_state;
|
||||
uint32 dma_cycle_count, hdma_cycle_count;
|
||||
|
||||
//$4207-$420a
|
||||
uint16 virq_trigger, hirq_trigger;
|
||||
@@ -65,9 +72,9 @@ struct {
|
||||
//$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;
|
||||
@@ -92,6 +99,12 @@ struct {
|
||||
uint16 r4216;
|
||||
} status;
|
||||
|
||||
//$43x0.d7
|
||||
enum {
|
||||
DMA_CPUTOMMIO = 0,
|
||||
DMA_MMIOTOCPU = 1
|
||||
};
|
||||
|
||||
struct {
|
||||
uint32 read_index; //set to 0 at beginning of DMA/HDMA
|
||||
|
||||
@@ -113,7 +126,10 @@ struct {
|
||||
//$43x4
|
||||
uint8 srcbank;
|
||||
//$43x5-$43x6
|
||||
uint16 xfersize;
|
||||
union {
|
||||
uint16 xfersize;
|
||||
uint16 hdma_iaddr;
|
||||
};
|
||||
//$43x7
|
||||
uint8 hdma_ibank;
|
||||
//$43x8-$43x9
|
||||
@@ -124,15 +140,11 @@ struct {
|
||||
uint8 hdma_unknown;
|
||||
|
||||
//hdma-specific
|
||||
bool hdma_first_line;
|
||||
bool hdma_repeat;
|
||||
uint16 hdma_iaddr;
|
||||
bool hdma_active;
|
||||
bool hdma_do_transfer;
|
||||
} channel[8];
|
||||
|
||||
inline bool hdma_test();
|
||||
|
||||
inline void irq(uint16 addr);
|
||||
inline bool nmi_test();
|
||||
inline bool irq_test();
|
||||
|
||||
@@ -144,17 +156,27 @@ struct {
|
||||
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 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 void hdma_write(uint8 i, uint8 l, uint8 x);
|
||||
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
|
||||
@@ -172,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);
|
||||
@@ -189,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);
|
||||
@@ -217,10 +242,11 @@ struct {
|
||||
void mmio_w43xb(uint8 value, uint8 i);
|
||||
|
||||
enum { CYCLE_OPREAD = 0, CYCLE_READ, CYCLE_WRITE, CYCLE_IO };
|
||||
inline void pre_exec_cycle();
|
||||
inline void exec_hdma();
|
||||
inline void exec_dma();
|
||||
inline void exec_cycle();
|
||||
inline void last_cycle();
|
||||
inline void last_cycle_exec();
|
||||
inline void cycle_edge();
|
||||
inline bool in_opcode();
|
||||
|
||||
//cpu extra-cycle conditions
|
||||
|
||||
+129
-94
@@ -1,7 +1,22 @@
|
||||
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].srcaddr;
|
||||
r |= (channel[i].srcbank << 16);
|
||||
r = (channel[i].srcbank << 16) | (channel[i].srcaddr);
|
||||
|
||||
if(channel[i].fixedxfer == false) {
|
||||
channel[i].srcaddr += channel[i].incmode;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -10,14 +25,10 @@ uint8 x;
|
||||
if(sdd1->dma_active() == true) {
|
||||
x = sdd1->dma_read();
|
||||
} else {
|
||||
x = mem_bus->read(dma_addr(i));
|
||||
x = r_mem->read(dma_addr(i));
|
||||
}
|
||||
|
||||
mem_bus->write(0x2100 | ((channel[i].destaddr + index) & 0xff), x);
|
||||
|
||||
if(channel[i].fixedxfer == false) {
|
||||
channel[i].srcaddr += channel[i].incmode;
|
||||
}
|
||||
r_mem->write(0x2100 | ((channel[i].destaddr + index) & 0xff), x);
|
||||
|
||||
add_cycles(8);
|
||||
channel[i].xfersize--;
|
||||
@@ -25,12 +36,8 @@ uint8 x;
|
||||
|
||||
void bCPU::dma_mmiotocpu(uint8 i, uint8 index) {
|
||||
uint8 x;
|
||||
x = mem_bus->read(0x2100 | ((channel[i].destaddr + index) & 0xff));
|
||||
mem_bus->write(dma_addr(i), x);
|
||||
|
||||
if(channel[i].fixedxfer == false) {
|
||||
channel[i].srcaddr += channel[i].incmode;
|
||||
}
|
||||
x = r_mem->read(0x2100 | ((channel[i].destaddr + index) & 0xff));
|
||||
r_mem->write(dma_addr(i), x);
|
||||
|
||||
add_cycles(8);
|
||||
channel[i].xfersize--;
|
||||
@@ -51,7 +58,8 @@ int i;
|
||||
|
||||
//first byte transferred?
|
||||
if(channel[i].read_index == 0) {
|
||||
sdd1->dma_begin(i, dma_addr(i), channel[i].xfersize);
|
||||
sdd1->dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr),
|
||||
channel[i].xfersize);
|
||||
}
|
||||
|
||||
switch(channel[i].xfermode) {
|
||||
@@ -66,6 +74,7 @@ int i;
|
||||
}
|
||||
|
||||
channel[i].read_index++;
|
||||
dma_add_cycles(8);
|
||||
|
||||
if(channel[i].xfersize == 0) {
|
||||
channel[i].active = false;
|
||||
@@ -78,22 +87,15 @@ int i;
|
||||
}
|
||||
|
||||
uint32 bCPU::hdma_addr(uint8 i) {
|
||||
uint32 r;
|
||||
r = channel[i].hdma_addr;
|
||||
r |= (channel[i].srcbank << 16);
|
||||
channel[i].hdma_addr++;
|
||||
return r;
|
||||
return (channel[i].srcbank << 16) | (channel[i].hdma_addr++);
|
||||
}
|
||||
|
||||
uint32 bCPU::hdma_iaddr(uint8 i) {
|
||||
uint32 r;
|
||||
r = channel[i].hdma_iaddr;
|
||||
r |= (channel[i].hdma_ibank << 16);
|
||||
channel[i].hdma_iaddr++;
|
||||
return r;
|
||||
return (channel[i].hdma_ibank << 16) | (channel[i].hdma_iaddr++);
|
||||
}
|
||||
|
||||
void bCPU::hdma_write(uint8 i, uint8 l, uint8 x) {
|
||||
uint16 bCPU::hdma_mmio(uint8 i) {
|
||||
uint8 l = channel[i].read_index;
|
||||
uint16 index;
|
||||
switch(channel[i].xfermode) {
|
||||
case 0:index = 0; break; //0
|
||||
@@ -106,90 +108,123 @@ uint16 index;
|
||||
case 7:index = (l >> 1) & 1;break; //0,0,1,1 [3]
|
||||
}
|
||||
|
||||
index = 0x2100 | ((channel[i].destaddr + index) & 0xff);
|
||||
mem_bus->write(index, x);
|
||||
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) {
|
||||
uint32 addr;
|
||||
if(channel[i].direction == DMA_CPUTOMMIO) {
|
||||
addr = hdma_mmio(i);
|
||||
} else if(!channel[i].hdma_indirect) {
|
||||
addr = hdma_addr(i);
|
||||
} else {
|
||||
addr = hdma_iaddr(i);
|
||||
}
|
||||
|
||||
if((bool)config::cpu.hdma_enable == true) {
|
||||
r_mem->write(addr, 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_active == false)continue;
|
||||
if(!channel[i].hdma_enabled || !channel[i].hdma_active)continue;
|
||||
|
||||
add_cycles(8);
|
||||
active_channels++;
|
||||
|
||||
if(channel[i].hdma_line_counter == 0) {
|
||||
channel[i].hdma_line_counter = mem_bus->read(hdma_addr(i));
|
||||
|
||||
if(channel[i].hdma_line_counter == 0) {
|
||||
channel[i].hdma_active = false;
|
||||
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 == true) {
|
||||
channel[i].hdma_iaddr = mem_bus->read(hdma_addr(i));
|
||||
channel[i].hdma_iaddr |= mem_bus->read(hdma_addr(i)) << 8;
|
||||
add_cycles(16);
|
||||
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;
|
||||
|
||||
xferlen = hdma_xferlen[channel[i].xfermode];
|
||||
for(l=0;l<xferlen;l++) {
|
||||
if(channel[i].hdma_indirect == false) {
|
||||
x = mem_bus->read(hdma_addr(i));
|
||||
} else {
|
||||
x = mem_bus->read(hdma_iaddr(i));
|
||||
}
|
||||
|
||||
hdma_write(i, l, x);
|
||||
add_cycles(8);
|
||||
channel[i].hdma_do_transfer = !!(channel[i].hdma_line_counter & 0x80);
|
||||
if((channel[i].hdma_line_counter & 0x7f) == 0) {
|
||||
hdma_update(i);
|
||||
}
|
||||
}
|
||||
|
||||
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++) {
|
||||
//does this happen when $420c channel bit is clear?
|
||||
channel[i].hdma_addr = channel[i].srcaddr;
|
||||
channel[i].hdma_line_counter = 0x00;
|
||||
if(channel[i].hdma_enabled)r++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
if(channel[i].hdma_enabled == false) {
|
||||
channel[i].hdma_active = false;
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
channel[i].hdma_active = true;
|
||||
active_channels++;
|
||||
/* hdmainit_activate()
|
||||
* hdma_activate()
|
||||
*
|
||||
* Functions are called by CPU timing routine
|
||||
* when an HDMA event (init or run) occurs.
|
||||
*/
|
||||
|
||||
if(channel[i].hdma_indirect == false) {
|
||||
add_cycles(8);
|
||||
} else {
|
||||
add_cycles(24);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,15 +241,15 @@ void bCPU::dma_reset() {
|
||||
channel[i].xfermode = 0;
|
||||
channel[i].destaddr = 0;
|
||||
channel[i].srcaddr = 0;
|
||||
channel[i].xfersize = 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_active = false;
|
||||
channel[i].hdma_first_line = false;
|
||||
channel[i].hdma_repeat = false;
|
||||
channel[i].hdma_iaddr = 0x0000;
|
||||
channel[i].hdma_do_transfer = false;
|
||||
}
|
||||
}
|
||||
+145
-40
@@ -1,64 +1,169 @@
|
||||
void bCPU::last_cycle() {
|
||||
status.is_last_cycle = true;
|
||||
}
|
||||
|
||||
void bCPU::last_cycle_exec() {
|
||||
status.is_last_cycle = false;
|
||||
|
||||
time.nmi_pending = nmi_test();
|
||||
time.irq_pending = irq_test();
|
||||
}
|
||||
|
||||
void bCPU::cycle_edge() {
|
||||
int c, n, z;
|
||||
if(status.dma_state != DMASTATE_STOP) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if(run_state.dma) {
|
||||
switch(status.dma_state) {
|
||||
case DMASTATE_DMASYNC:
|
||||
status.dma_state = DMASTATE_DMASYNC2;
|
||||
break;
|
||||
case DMASTATE_DMASYNC2:
|
||||
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.cpu_state = CPUSTATE_DMA;
|
||||
status.dma_state = DMASTATE_RUN;
|
||||
break;
|
||||
case DMASTATE_RUN:
|
||||
status.dma_cycle_count += 8;
|
||||
break;
|
||||
case DMASTATE_CPUSYNC:
|
||||
status.cpu_state = CPUSTATE_RUN;
|
||||
status.dma_state = DMASTATE_CPUSYNC2;
|
||||
break;
|
||||
case DMASTATE_CPUSYNC2:
|
||||
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_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() {
|
||||
//on first cycle?
|
||||
if(status.cycle_pos == 0) {
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_BEGIN);
|
||||
status.opcode = op_read();
|
||||
status.cycle_pos = 1;
|
||||
//irq active? run one bus cycle of the irq event and return
|
||||
if(run_state.irq) {
|
||||
irq_run();
|
||||
return;
|
||||
}
|
||||
|
||||
(this->*optbl[status.opcode])();
|
||||
if(status.cycle_pos == 0) {
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_END);
|
||||
if(status.cycle_pos) {
|
||||
(this->*optbl[status.opcode])();
|
||||
#ifdef DEBUGGER
|
||||
if(status.cycle_pos == 0) {
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_END);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
//on first cycle?
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_BEGIN);
|
||||
#endif
|
||||
status.opcode = op_read();
|
||||
status.cycle_pos = 1;
|
||||
}
|
||||
|
||||
//only return true when we are on an opcode edge
|
||||
|
||||
+32
-33
@@ -1,43 +1,45 @@
|
||||
/*
|
||||
[IRQ cycles]
|
||||
[1] pbr,pc ; opcode
|
||||
[2] pbr,pc ; io
|
||||
[3] 0,s ; pbr
|
||||
[4] 0,s-1 ; pch
|
||||
[5] 0,s-2 ; pcl
|
||||
[6] 0,s-3 ; p
|
||||
[7] 0,va ; aavl
|
||||
[8] 0,va+1 ; aavh
|
||||
[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(uint16 addr) {
|
||||
void bCPU::irq_run() {
|
||||
//WDC documentation is incorrect, first cycle
|
||||
//is a memory read fetch from PBR:PC
|
||||
add_cycles(mem_bus->speed(regs.pc.d));
|
||||
add_cycles(6);
|
||||
stack_write(regs.pc.b);
|
||||
stack_write(regs.pc.h);
|
||||
stack_write(regs.pc.l);
|
||||
stack_write(regs.p);
|
||||
rd.l = op_read(OPMODE_ADDR, addr);
|
||||
rd.h = op_read(OPMODE_ADDR, addr + 1);
|
||||
|
||||
regs.pc.b = 0x00;
|
||||
regs.pc.w = rd.w;
|
||||
regs.p.i = 1;
|
||||
regs.p.d = 0;
|
||||
|
||||
//let debugger know the new IRQ opcode address
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_END);
|
||||
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;
|
||||
|
||||
if(status.cpu_state == CPUSTATE_WAI) {
|
||||
status.cpu_state = CPUSTATE_RUN;
|
||||
}
|
||||
|
||||
run_state.wai = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -61,10 +63,7 @@ bool bCPU::irq_test() {
|
||||
_true:
|
||||
time.irq_transition = 0;
|
||||
|
||||
if(status.cpu_state == CPUSTATE_WAI) {
|
||||
status.cpu_state = CPUSTATE_RUN;
|
||||
}
|
||||
|
||||
run_state.wai = false;
|
||||
if(regs.p.i)return false;
|
||||
return true;
|
||||
}
|
||||
+76
-12
@@ -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,7 +37,7 @@ 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;
|
||||
@@ -91,6 +93,28 @@ 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;
|
||||
}
|
||||
|
||||
@@ -206,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;
|
||||
@@ -270,7 +324,7 @@ uint8 bCPUMMIO::read(uint32 addr) {
|
||||
uint i;
|
||||
//APU
|
||||
if(addr >= 0x2140 && addr <= 0x217f) {
|
||||
return apu->port_read(addr & 3);
|
||||
return r_apu->port_read(addr & 3);
|
||||
}
|
||||
|
||||
//HDMA
|
||||
@@ -310,9 +364,9 @@ uint 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 0x4000:dprintf("* 4000 read at %3d,%4d <%d>", cpu->time.v, cpu->time.hc, cpu->status.cycle_count);break;
|
||||
case 0x4200:dprintf("* 4200 read at %3d,%4d", cpu->time.v, cpu->time.hc);break;
|
||||
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 cpu->regs.mdr;
|
||||
@@ -320,7 +374,7 @@ case 0x4200:dprintf("* 4200 read at %3d,%4d", cpu->time.v, cpu->time.hc);break;
|
||||
|
||||
//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;
|
||||
}
|
||||
@@ -345,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);
|
||||
@@ -378,7 +441,7 @@ void bCPU::mmio_w4200(uint8 value) {
|
||||
//WRIO
|
||||
void bCPU::mmio_w4201(uint8 value) {
|
||||
if((status.pio & 0x80) && !(value & 0x80)) {
|
||||
ppu->latch_counters();
|
||||
r_ppu->latch_counters();
|
||||
}
|
||||
status.pio = value;
|
||||
}
|
||||
@@ -438,6 +501,7 @@ void bCPU::mmio_w420a(uint8 value) {
|
||||
void bCPU::mmio_w420b(uint8 value) {
|
||||
int len;
|
||||
if(value != 0x00) {
|
||||
run_state.dma = true;
|
||||
status.dma_state = DMASTATE_DMASYNC;
|
||||
}
|
||||
|
||||
@@ -461,7 +525,7 @@ void bCPU::mmio_w420c(uint8 value) {
|
||||
|
||||
//MEMSEL
|
||||
void bCPU::mmio_w420d(uint8 value) {
|
||||
mem_bus->set_speed(value & 1);
|
||||
r_mem->set_speed(value & 1);
|
||||
}
|
||||
|
||||
//DMAPx
|
||||
@@ -566,6 +630,7 @@ uint8 i;
|
||||
case 0x2182:cpu->mmio_w2182(value);return; //WMADDM
|
||||
case 0x2183:cpu->mmio_w2183(value);return; //WMADDH
|
||||
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
|
||||
@@ -580,7 +645,6 @@ uint8 i;
|
||||
case 0x420b:cpu->mmio_w420b(value);return; //DMAEN
|
||||
case 0x420c:cpu->mmio_w420c(value);return; //HDMAEN
|
||||
case 0x420d:cpu->mmio_w420d(value);return; //MEMSEL
|
||||
case 0x4000:dprintf("* 4000 write at %3d,%4d", cpu->time.v, cpu->time.hc);break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ void bCPU::op_stp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
cpu_io();
|
||||
status.cpu_state = CPUSTATE_STP;
|
||||
run_state.stp = true;
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
@@ -179,12 +179,13 @@ void bCPU::op_wai() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
cpu_io();
|
||||
status.cpu_state = CPUSTATE_WAI;
|
||||
run_state.wai = true;
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(status.cpu_state == CPUSTATE_WAI) {
|
||||
if(run_state.wai) {
|
||||
//this can be cleared within last_cycle()
|
||||
regs.pc.w--;
|
||||
}
|
||||
status.cycle_pos = 0;
|
||||
|
||||
+107
-25
@@ -1,31 +1,75 @@
|
||||
//op_read
|
||||
inline void bCPU::op_adc_b() {
|
||||
int32 r = regs.a.l + rd.l + regs.p.c;
|
||||
//bcd
|
||||
if(regs.p.d) {
|
||||
if(((r ) & 15) > 9)r += 6;
|
||||
if(((r >> 4) & 15) > 9)r += 6 << 4;
|
||||
uint8 n0 = (regs.a.l ) & 15;
|
||||
uint8 n1 = (regs.a.l >> 4) & 15;
|
||||
n0 += ((rd.l) & 15) + regs.p.c;
|
||||
if(n0 > 9) {
|
||||
n0 -= 10;
|
||||
n0 &= 15;
|
||||
n1++;
|
||||
}
|
||||
n1 += ((rd.l >> 4) & 15);
|
||||
if(n1 > 9) {
|
||||
n1 -= 10;
|
||||
n1 &= 15;
|
||||
regs.p.c = 1;
|
||||
} else {
|
||||
regs.p.c = 0;
|
||||
}
|
||||
r = (n1 << 4) | (n0);
|
||||
} else {
|
||||
r = regs.a.l + rd.l + regs.p.c;
|
||||
regs.p.c = (r > 0xff);
|
||||
}
|
||||
regs.p.n = !!(r & 0x80);
|
||||
regs.p.v = !!(~(regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80);
|
||||
regs.p.z = ((uint8)r == 0);
|
||||
regs.p.c = (r > 0xff);
|
||||
regs.a.l = r;
|
||||
}
|
||||
|
||||
inline void bCPU::op_adc_w() {
|
||||
int32 r = regs.a.w + rd.w + regs.p.c;
|
||||
//bcd
|
||||
int32 r;
|
||||
if(regs.p.d) {
|
||||
if(((r ) & 15) > 9)r += 6;
|
||||
if(((r >> 4) & 15) > 9)r += 6 << 4;
|
||||
if(((r >> 8) & 15) > 9)r += 6 << 8;
|
||||
if(((r >> 12) & 15) > 9)r += 6 << 12;
|
||||
uint8 n0 = (regs.a.w ) & 15;
|
||||
uint8 n1 = (regs.a.w >> 4) & 15;
|
||||
uint8 n2 = (regs.a.w >> 8) & 15;
|
||||
uint8 n3 = (regs.a.w >> 12) & 15;
|
||||
n0 += ((rd.w) & 15) + regs.p.c;
|
||||
if(n0 > 9) {
|
||||
n0 -= 10;
|
||||
n0 &= 15;
|
||||
n1++;
|
||||
}
|
||||
n1 += ((rd.w >> 4) & 15);
|
||||
if(n1 > 9) {
|
||||
n1 -= 10;
|
||||
n1 &= 15;
|
||||
n2++;
|
||||
}
|
||||
n2 += ((rd.w >> 8) & 15);
|
||||
if(n2 > 9) {
|
||||
n2 -= 10;
|
||||
n2 &= 15;
|
||||
n3++;
|
||||
}
|
||||
n3 += ((rd.w >> 12) & 15);
|
||||
if(n3 > 9) {
|
||||
n3 -= 10;
|
||||
n3 &= 15;
|
||||
regs.p.c = 1;
|
||||
} else {
|
||||
regs.p.c = 0;
|
||||
}
|
||||
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | (n0);
|
||||
} else {
|
||||
r = regs.a.w + rd.w + regs.p.c;
|
||||
regs.p.c = (r > 0xffff);
|
||||
}
|
||||
regs.p.n = !!(r & 0x8000);
|
||||
regs.p.v = !!(~(regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000);
|
||||
regs.p.z = ((uint16)r == 0);
|
||||
regs.p.c = (r > 0xffff);
|
||||
regs.a.w = r;
|
||||
}
|
||||
|
||||
@@ -156,32 +200,70 @@ inline void bCPU::op_ora_w() {
|
||||
}
|
||||
|
||||
inline void bCPU::op_sbc_b() {
|
||||
int32 r = regs.a.l - rd.l - !regs.p.c;
|
||||
//bcd
|
||||
int32 r;
|
||||
if(regs.p.d) {
|
||||
if(((r ) & 15) > 9)r -= 6;
|
||||
if(((r >> 4) & 15) > 9)r -= 6 << 4;
|
||||
uint8 n0 = (regs.a.l ) & 15;
|
||||
uint8 n1 = (regs.a.l >> 4) & 15;
|
||||
n0 -= ((rd.l ) & 15) + !regs.p.c;
|
||||
n1 -= ((rd.l >> 4) & 15);
|
||||
if(n0 > 9) {
|
||||
n0 += 10;
|
||||
n1--;
|
||||
}
|
||||
if(n1 > 9) {
|
||||
n1 += 10;
|
||||
regs.p.c = 0;
|
||||
} else {
|
||||
regs.p.c = 1;
|
||||
}
|
||||
r = (n1 << 4) | (n0);
|
||||
} else {
|
||||
r = regs.a.l - rd.l - !regs.p.c;
|
||||
regs.p.c = (r >= 0);
|
||||
}
|
||||
regs.p.n = !!(r & 0x80);
|
||||
regs.p.v = !!((regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80);
|
||||
regs.p.z = ((byte)r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
regs.p.z = ((uint8)r == 0);
|
||||
regs.a.l = r;
|
||||
}
|
||||
|
||||
inline void bCPU::op_sbc_w() {
|
||||
int32 r = regs.a.w - rd.w - !regs.p.c;
|
||||
//bcd
|
||||
int32 r;
|
||||
if(regs.p.d) {
|
||||
if(((r ) & 15) > 9)r -= 6;
|
||||
if(((r >> 4) & 15) > 9)r -= 6 << 4;
|
||||
if(((r >> 8) & 15) > 9)r -= 6 << 8;
|
||||
if(((r >> 12) & 15) > 9)r -= 6 << 12;
|
||||
uint8 n0 = (regs.a.w ) & 15;
|
||||
uint8 n1 = (regs.a.w >> 4) & 15;
|
||||
uint8 n2 = (regs.a.w >> 8) & 15;
|
||||
uint8 n3 = (regs.a.w >> 12) & 15;
|
||||
n0 -= ((rd.w ) & 15) + !regs.p.c;
|
||||
n1 -= ((rd.w >> 4) & 15);
|
||||
n2 -= ((rd.w >> 8) & 15);
|
||||
n3 -= ((rd.w >> 12) & 15);
|
||||
if(n0 > 9) {
|
||||
n0 += 10;
|
||||
n1--;
|
||||
}
|
||||
if(n1 > 9) {
|
||||
n1 += 10;
|
||||
n2--;
|
||||
}
|
||||
if(n2 > 9) {
|
||||
n2 += 10;
|
||||
n3--;
|
||||
}
|
||||
if(n3 > 9) {
|
||||
n3 += 10;
|
||||
regs.p.c = 0;
|
||||
} else {
|
||||
regs.p.c = 1;
|
||||
}
|
||||
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | (n0);
|
||||
} else {
|
||||
r = regs.a.w - rd.w - !regs.p.c;
|
||||
regs.p.c = (r >= 0);
|
||||
}
|
||||
regs.p.n = !!(r & 0x8000);
|
||||
regs.p.v = !!((regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000);
|
||||
regs.p.z = ((word)r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
regs.p.z = ((uint16)r == 0);
|
||||
regs.a.w = r;
|
||||
}
|
||||
|
||||
|
||||
@@ -207,7 +207,7 @@ void bCPU::inc_vcounter() {
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -239,6 +239,24 @@ uint32 r = status.cycles_executed;
|
||||
return r;
|
||||
}
|
||||
|
||||
void bCPU::cycle_edge() {
|
||||
if(time.hdmainit_triggered == false) {
|
||||
if(time.hc >= time.hdmainit_trigger_pos || time.v) {
|
||||
time.hdmainit_triggered = true;
|
||||
hdmainit_activate();
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
status.cycles_executed += cycles;
|
||||
|
||||
@@ -253,30 +271,16 @@ void bCPU::add_cycles(int cycles) {
|
||||
|
||||
if(time.v == 0) {
|
||||
frame();
|
||||
ppu->frame();
|
||||
r_ppu->frame();
|
||||
snes->frame();
|
||||
}
|
||||
|
||||
scanline();
|
||||
ppu->scanline();
|
||||
// ppu->render_scanline();
|
||||
r_ppu->scanline();
|
||||
snes->scanline();
|
||||
time.line_rendered = false;
|
||||
}
|
||||
|
||||
if(time.line_rendered == false) {
|
||||
//rendering should start at H=22, but due to inaccurate
|
||||
//timing, and due to using a scanline-based renderer, use
|
||||
//a higher value to allow more games to run properly...
|
||||
//H=48 fixes off-by-one HDMA effects with FF6's battles
|
||||
if(time.hc + cycles >= (48 * 4)) {
|
||||
cycles = (time.hc + cycles) - (48 * 4);
|
||||
time.hc = (48 * 4);
|
||||
time.line_rendered = true;
|
||||
ppu->render_scanline();
|
||||
}
|
||||
}
|
||||
|
||||
if(time.dram_refreshed == false) {
|
||||
if(time.hc + cycles >= time.dram_refresh_pos) {
|
||||
time.dram_refreshed = true;
|
||||
@@ -296,15 +300,14 @@ void bCPU::add_cycles(int cycles) {
|
||||
}
|
||||
}
|
||||
|
||||
if(status.hdma_triggered == false) {
|
||||
//vcounter range verified on hardware
|
||||
if(time.v <= (overscan() ? 239 : 224)) {
|
||||
if(time.hc + cycles >= 1112) { //278 * 4 = 1112
|
||||
cycles = (time.hc + cycles) - 1112;
|
||||
time.hc = 1112;
|
||||
status.hdma_triggered = true;
|
||||
hdma_run();
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,11 +315,8 @@ void bCPU::add_cycles(int 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;
|
||||
@@ -329,6 +329,12 @@ void bCPU::time_reset() {
|
||||
|
||||
time.dma_counter = 0;
|
||||
|
||||
//set at V=0,H=0
|
||||
time.hdmainit_trigger_pos = 0;
|
||||
time.hdmainit_triggered = true;
|
||||
|
||||
time.hdma_triggered = false;
|
||||
|
||||
time.nmi_pending = false;
|
||||
time.irq_pending = false;
|
||||
time.nmi_line = time.nmi_read = 1;
|
||||
|
||||
@@ -11,6 +11,11 @@ struct {
|
||||
|
||||
uint8 dma_counter;
|
||||
|
||||
uint16 hdmainit_trigger_pos;
|
||||
bool hdmainit_triggered;
|
||||
|
||||
bool hdma_triggered;
|
||||
|
||||
uint16 region_scanlines;
|
||||
|
||||
//nmi_pending, irq_pending are used by last_cycle()
|
||||
@@ -64,5 +69,6 @@ inline uint8 dma_counter();
|
||||
|
||||
inline void inc_vcounter();
|
||||
inline uint16 get_hcounter();
|
||||
inline void cycle_edge();
|
||||
inline void add_cycles(int cycles);
|
||||
inline void time_reset();
|
||||
@@ -53,7 +53,7 @@ cop(0x02, 0xfff4, 0xfff5, 0xffe4, 0xffe5) {
|
||||
|
||||
stp(0xdb) {
|
||||
1:cpu_io();
|
||||
status.cpu_state = CPUSTATE_STP;
|
||||
run_state.stp = true;
|
||||
2:last_cycle();
|
||||
cpu_io();
|
||||
regs.pc.w--;
|
||||
@@ -61,10 +61,11 @@ stp(0xdb) {
|
||||
|
||||
wai(0xcb) {
|
||||
1:cpu_io();
|
||||
status.cpu_state = CPUSTATE_WAI;
|
||||
run_state.wai = true;
|
||||
2:last_cycle();
|
||||
cpu_io();
|
||||
if(status.cpu_state == CPUSTATE_WAI) {
|
||||
if(run_state.wai) {
|
||||
//this can be cleared within last_cycle()
|
||||
regs.pc.w--;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,6 +2,6 @@
|
||||
#include "dcpu.cpp"
|
||||
|
||||
CPU::CPU() {
|
||||
cpu_version = 2;
|
||||
cpu_version = 1;
|
||||
mmio = &mmio_unmapped;
|
||||
}
|
||||
@@ -15,6 +15,7 @@ uint8 cpu_version;
|
||||
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;
|
||||
|
||||
@@ -69,4 +70,5 @@ enum {
|
||||
uint16 __relw(int16 offset);
|
||||
|
||||
CPU();
|
||||
virtual ~CPU() {}
|
||||
};
|
||||
+17
-8
@@ -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); }
|
||||
|
||||
+11
-11
@@ -38,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);
|
||||
@@ -88,7 +88,7 @@ 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;
|
||||
@@ -109,10 +109,10 @@ static CPUReg24 pc;
|
||||
pc.d = regs.pc.d;
|
||||
sprintf(s, "%0.6x ", pc.d);
|
||||
|
||||
op = mem_bus->read(pc.d); pc.w++;
|
||||
op0 = mem_bus->read(pc.d); pc.w++;
|
||||
op1 = mem_bus->read(pc.d); pc.w++;
|
||||
op2 = mem_bus->read(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;
|
||||
@@ -457,7 +457,7 @@ static uint8 op_len_tbl[256] = {
|
||||
return 0;
|
||||
}
|
||||
|
||||
op = mem_bus->read(regs.pc.d);
|
||||
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;
|
||||
|
||||
+56
-34
@@ -1,10 +1,22 @@
|
||||
#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::readb(uint16 addr) {
|
||||
return spcram[addr];
|
||||
}
|
||||
|
||||
void bDSP::writeb(uint16 addr, uint8 data) {
|
||||
spcram[addr] = data;
|
||||
}
|
||||
|
||||
uint16 bDSP::readw(uint16 addr) {
|
||||
return (readb(addr)) | (readb(addr + 1) << 8);
|
||||
}
|
||||
|
||||
void bDSP::writew(uint16 addr, uint16 data) {
|
||||
writeb(addr, data);
|
||||
writeb(addr + 1, data >> 8);
|
||||
}
|
||||
|
||||
uint8 bDSP::read(uint8 addr) {
|
||||
int i, v, n;
|
||||
@@ -98,12 +110,14 @@ int i, v, n;
|
||||
break;
|
||||
case 0x04:case 0x14:case 0x24:case 0x34:
|
||||
case 0x44:case 0x54:case 0x64:case 0x74:
|
||||
//voice[v].SRCN = data;
|
||||
voice[v].SRCN = data;
|
||||
break;
|
||||
//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
|
||||
//anomie's code breaks MK2 sound completely...
|
||||
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].SRCN = data;
|
||||
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2) + ((voice[v].brr_looped) ? 2 : 0));
|
||||
voice[v].brr_index = 0;
|
||||
}
|
||||
break;
|
||||
@@ -144,18 +158,18 @@ int i, v, n;
|
||||
case 0x3c:status.EVOLR = data;break;
|
||||
|
||||
case 0x4c:
|
||||
status.KON = data;
|
||||
status.kon = data;
|
||||
status.KON = data;
|
||||
status.kon = data;
|
||||
status.key_flag = true;
|
||||
break;
|
||||
|
||||
case 0x5c:
|
||||
status.KOFF = data;
|
||||
status.KOFF = data;
|
||||
status.key_flag = true;
|
||||
break;
|
||||
|
||||
case 0x6c:
|
||||
status.FLG = data;
|
||||
status.FLG = data;
|
||||
status.key_flag = true;
|
||||
status.noise_rate = RateTable[data & 0x1f];
|
||||
break;
|
||||
@@ -165,15 +179,15 @@ int i, v, n;
|
||||
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 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.EDL = data;
|
||||
status.echo_size = (data & 0x0f) << 11;
|
||||
break;
|
||||
}
|
||||
@@ -183,7 +197,7 @@ int i, v, n;
|
||||
|
||||
void bDSP::power() {
|
||||
int v;
|
||||
spcram = apu->get_spcram_handle();
|
||||
spcram = r_apu->get_spcram_handle();
|
||||
memset(dspram, 0x00, 128);
|
||||
|
||||
for(v=0;v<8;v++) {
|
||||
@@ -238,7 +252,7 @@ int v;
|
||||
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_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2));
|
||||
voice[v].brr_looped = false;
|
||||
voice[v].brr_data[0] = 0;
|
||||
voice[v].brr_data[1] = 0;
|
||||
@@ -288,20 +302,27 @@ int32 esamplel, esampler;
|
||||
int32 fir_samplel, fir_sampler;
|
||||
pmon = status.PMON & ~status.NON & ~1;
|
||||
|
||||
if(!(dsp_counter++ & 1) && status.key_flag) {
|
||||
//if(!(dsp_counter++ & 1) && status.key_flag) {
|
||||
//TRAC believes KON/KOFF is polled every sample. further testing is needed
|
||||
if(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 & (1 << v)) {
|
||||
} 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 & (1 << v)) {
|
||||
voice[v].brr_ptr = read_16((status.DIR << 8) + (voice[v].SRCN << 2));
|
||||
} else if(status.kon & mask) {
|
||||
//new KON code
|
||||
status.ENDX &= ~mask;
|
||||
status.kon &= ~mask;
|
||||
|
||||
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2));
|
||||
voice[v].brr_index = -9;
|
||||
voice[v].brr_looped = false;
|
||||
voice[v].brr_data[0] = 0;
|
||||
@@ -313,8 +334,9 @@ int32 fir_samplel, fir_sampler;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
}
|
||||
status.ENDX &= ~status.kon;
|
||||
status.kon = 0;
|
||||
//old KON code, breaks sound effects in DL / SFA2
|
||||
// status.ENDX &= ~status.kon;
|
||||
// status.kon = 0;
|
||||
status.key_flag = false;
|
||||
}
|
||||
|
||||
@@ -356,7 +378,7 @@ int32 fir_samplel, fir_sampler;
|
||||
voice[v].brr_data_index &= 3;
|
||||
|
||||
if(voice[v].brr_index == 0) {
|
||||
voice[v].brr_header = read_8(voice[v].brr_ptr);
|
||||
voice[v].brr_header = readb(voice[v].brr_ptr);
|
||||
|
||||
if(voice[v].brr_header_flags() & BRR_END) {
|
||||
status.ENDX |= (1 << v);
|
||||
@@ -370,7 +392,7 @@ int32 fir_samplel, fir_sampler;
|
||||
|
||||
#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));
|
||||
sample = readb(voice[v].brr_ptr + 1 + (voice[v].brr_index >> 1));
|
||||
if(voice[v].brr_index & 1) {
|
||||
sample = clip(4, sample);
|
||||
} else {
|
||||
@@ -407,7 +429,7 @@ int32 fir_samplel, fir_sampler;
|
||||
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_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2) + 2);
|
||||
voice[v].brr_looped = true;
|
||||
} else {
|
||||
voice[v].brr_ptr += 9;
|
||||
@@ -493,7 +515,7 @@ int32 fir_samplel, fir_sampler;
|
||||
|
||||
//gaussian interpolation / noise
|
||||
if(status.NON & (1 << v)) {
|
||||
sample = status.noise_sample;
|
||||
sample = clip(15, status.noise_sample);
|
||||
} else {
|
||||
d = voice[v].pitch_ctr >> 4; //-256 <= sample <= -1
|
||||
sample = ((GaussTable[ -1-d] * S(-3)) >> 11);
|
||||
@@ -524,8 +546,8 @@ int32 fir_samplel, fir_sampler;
|
||||
//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);
|
||||
F(0,0) = readw((status.ESA << 8) + status.echo_index);
|
||||
F(1,0) = readw((status.ESA << 8) + status.echo_index + 2);
|
||||
|
||||
fir_samplel = (F(0,-0) * status.FIR[7] +
|
||||
F(0,-1) * status.FIR[6] +
|
||||
@@ -554,8 +576,8 @@ int32 fir_samplel, fir_sampler;
|
||||
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);
|
||||
writew((status.ESA << 8) + status.echo_index, esamplel);
|
||||
writew((status.ESA << 8) + status.echo_index + 2, esampler);
|
||||
}
|
||||
|
||||
status.echo_index += 4;
|
||||
|
||||
+4
-4
@@ -10,10 +10,10 @@ enum {
|
||||
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);
|
||||
uint8 readb (uint16 addr);
|
||||
uint16 readw (uint16 addr);
|
||||
void writeb(uint16 addr, uint8 data);
|
||||
void writew(uint16 addr, uint16 data);
|
||||
|
||||
public:
|
||||
static const uint16 RateTable[32];
|
||||
|
||||
@@ -6,4 +6,7 @@ public:
|
||||
virtual void power() = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual uint32 run() = 0;
|
||||
|
||||
DSP() {}
|
||||
virtual ~DSP() {}
|
||||
};
|
||||
+54
-17
@@ -1,49 +1,86 @@
|
||||
#define BSNES_VERSION "0.012"
|
||||
#define BSNES_VERSION "0.015"
|
||||
#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 "cart/cart.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"
|
||||
extern DSP *dsp;
|
||||
|
||||
#include "ppu/ppu.h"
|
||||
#include "ppu/bppu/bppu.h"
|
||||
extern PPU *ppu;
|
||||
|
||||
#include "snes/snes.h"
|
||||
extern SNES *snes;
|
||||
|
||||
#include "chip/srtc/srtc.h"
|
||||
#include "chip/sdd1/sdd1.h"
|
||||
#include "chip/c4/c4.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;
|
||||
extern C4 *c4;
|
||||
|
||||
#include "config/config.h"
|
||||
|
||||
#ifdef INTERFACE_MAIN
|
||||
Cartridge cartridge;
|
||||
|
||||
#include "config/config.cpp"
|
||||
MemBus *mem_bus;
|
||||
CPU *cpu;
|
||||
APU *apu;
|
||||
DSP *dsp;
|
||||
PPU *ppu;
|
||||
SNES *snes;
|
||||
#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;
|
||||
C4 *c4;
|
||||
|
||||
SRTC *srtc;
|
||||
SDD1 *sdd1;
|
||||
#endif
|
||||
+14
-11
@@ -20,20 +20,23 @@
|
||||
|
||||
#define zerofree(__n) if(__n) { free(__n); __n = 0; }
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned int uint;
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short word;
|
||||
typedef unsigned long ulong;
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short word;
|
||||
typedef unsigned long ulong;
|
||||
typedef unsigned long long uquad;
|
||||
|
||||
typedef unsigned char bool8;
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned long uint32;
|
||||
typedef unsigned char bool8;
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned long uint32;
|
||||
typedef unsigned long long uint64;
|
||||
|
||||
typedef signed char int8;
|
||||
typedef signed short int16;
|
||||
typedef signed long int32;
|
||||
typedef signed char int8;
|
||||
typedef signed short int16;
|
||||
typedef signed long int32;
|
||||
typedef signed long long int64;
|
||||
|
||||
#ifdef null
|
||||
#undef null
|
||||
|
||||
+65
-23
@@ -11,7 +11,6 @@ uint Setting::get() {
|
||||
}
|
||||
|
||||
void Setting::set(uint _data) {
|
||||
printf("%s %d\n", name, _data);
|
||||
data = _data;
|
||||
|
||||
if(type != DEC && type != HEX) {
|
||||
@@ -20,6 +19,15 @@ printf("%s %d\n", name, _data);
|
||||
}
|
||||
}
|
||||
|
||||
char *Setting::sget() {
|
||||
return strptr(char_data);
|
||||
}
|
||||
|
||||
void Setting::sset(const char *_data) {
|
||||
strcpy(char_data, _data);
|
||||
strunquote(char_data);
|
||||
}
|
||||
|
||||
Setting::Setting(Config *_parent, char *_name, char *_desc, uint _data, uint _type) {
|
||||
int s;
|
||||
if(_parent) {
|
||||
@@ -44,28 +52,53 @@ int s;
|
||||
type = _type;
|
||||
}
|
||||
|
||||
Setting::Setting(Config *_parent, char *_name, char *_desc, char *_data) {
|
||||
int s;
|
||||
if(_parent) {
|
||||
_parent->add(this);
|
||||
}
|
||||
|
||||
s = strlen(_name);
|
||||
name = (char*)malloc(s + 1);
|
||||
strcpy(name, _name);
|
||||
|
||||
if(_desc) {
|
||||
s = strlen(_desc);
|
||||
desc = (char*)malloc(s + 1);
|
||||
strcpy(desc, _desc);
|
||||
} else {
|
||||
desc = (char*)malloc(1);
|
||||
*desc = 0;
|
||||
}
|
||||
|
||||
strcpy(char_data, _data);
|
||||
strcpy(char_def, _data);
|
||||
|
||||
type = STR;
|
||||
}
|
||||
|
||||
void Config::add(Setting *setting) {
|
||||
list[list_count++] = setting;
|
||||
}
|
||||
|
||||
uint Config::string_to_uint(uint type, char *input) {
|
||||
if(!strcmp(input, "true") ||
|
||||
!strcmp(input, "enabled") ||
|
||||
!strcmp(input, "on") ||
|
||||
!strcmp(input, "yes")
|
||||
if(strmatch(input, "true") ||
|
||||
strmatch(input, "enabled") ||
|
||||
strmatch(input, "on") ||
|
||||
strmatch(input, "yes")
|
||||
) {
|
||||
return (uint)true;
|
||||
}
|
||||
|
||||
if(!strcmp(input, "false") ||
|
||||
!strcmp(input, "disabled") ||
|
||||
!strcmp(input, "off") ||
|
||||
!strcmp(input, "no")
|
||||
if(strmatch(input, "false") ||
|
||||
strmatch(input, "disabled") ||
|
||||
strmatch(input, "off") ||
|
||||
strmatch(input, "no")
|
||||
) {
|
||||
return (uint)false;
|
||||
}
|
||||
|
||||
if(!strbegin(input, "0x")) {
|
||||
if(strbegin(input, "0x")) {
|
||||
return strhex(input + 2);
|
||||
}
|
||||
|
||||
@@ -76,16 +109,16 @@ 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");
|
||||
sprintf(output, "%s", (input & 1) ? "true" : "false");
|
||||
break;
|
||||
case Setting::ENABLED_DISABLED:
|
||||
sprintf(output, "%s", (input & 1)?"enabled":"disabled");
|
||||
sprintf(output, "%s", (input & 1) ? "enabled" : "disabled");
|
||||
break;
|
||||
case Setting::ON_OFF:
|
||||
sprintf(output, "%s", (input & 1)?"on":"off");
|
||||
sprintf(output, "%s", (input & 1) ? "on" : "off");
|
||||
break;
|
||||
case Setting::YES_NO:
|
||||
sprintf(output, "%s", (input & 1)?"yes":"no");
|
||||
sprintf(output, "%s", (input & 1) ? "yes" : "no");
|
||||
break;
|
||||
case Setting::DEC:
|
||||
sprintf(output, "%d", input);
|
||||
@@ -120,14 +153,18 @@ char *buffer = (char*)malloc(fsize + 1);
|
||||
qreplace(data, " ", "");
|
||||
split(line, "\n", data);
|
||||
|
||||
for(int i=0;i<count(line);i++) {
|
||||
for(int i = 0; i < count(line); i++) {
|
||||
if(strlen(line[i]) == 0)continue;
|
||||
if(*strptr(line[i]) == '#')continue;
|
||||
|
||||
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])));
|
||||
qsplit(part, "=", line[i]);
|
||||
for(int l = 0; l < list_count; l++) {
|
||||
if(strmatch(list[l]->name, part[0])) {
|
||||
if(list[l]->type != Setting::STR) {
|
||||
list[l]->set(string_to_uint(list[l]->type, strptr(part[1])));
|
||||
} else {
|
||||
list[l]->sset(strptr(part[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,15 +178,20 @@ FILE *fp;
|
||||
fp = fopen(fn, "wb");
|
||||
if(!fp)return false;
|
||||
|
||||
for(int i=0;i<list_count;i++) {
|
||||
for(int i = 0; i < list_count; i++) {
|
||||
strcpy(data, list[i]->desc);
|
||||
replace(data, "\r\n", "\n");
|
||||
split(line, "\n", data);
|
||||
for(int l=0;l<count(line);l++) {
|
||||
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));
|
||||
if(list[i]->type != Setting::STR) {
|
||||
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));
|
||||
} else {
|
||||
fprintf(fp, "# (default = \"%s\")\r\n", strptr(list[i]->char_def));
|
||||
fprintf(fp, "%s = \"%s\"\r\n\r\n", list[i]->name, strptr(list[i]->char_data));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
+18
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
libconfig : version 0.05 ~byuu (09/13/05)
|
||||
libconfig : version 0.05 ~byuu (10/30/05)
|
||||
*/
|
||||
|
||||
#ifndef __LIBCONFIG
|
||||
@@ -28,6 +28,8 @@ class Config;
|
||||
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; } \
|
||||
inline __name &operator=(const float _data) { set((uint)_data); return *this; } \
|
||||
inline __name &operator=(const double _data) { set((uint)_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) {}
|
||||
@@ -46,14 +48,20 @@ enum {
|
||||
YES_NO,
|
||||
BOOL,
|
||||
DEC,
|
||||
HEX
|
||||
HEX,
|
||||
STR
|
||||
};
|
||||
char *name, *desc;
|
||||
virtual void toggle();
|
||||
virtual uint get();
|
||||
virtual void set(uint _data);
|
||||
substring char_data, char_def;
|
||||
virtual void toggle();
|
||||
virtual uint get();
|
||||
virtual void set(uint _data);
|
||||
|
||||
Setting(Config *_parent, char *_name, char *_desc = 0, uint _data = 0, uint _type = DEC);
|
||||
virtual char *sget();
|
||||
virtual void sset(const char *_data);
|
||||
|
||||
Setting(Config *_parent, char *_name, char *_desc, uint _data, uint _type);
|
||||
Setting(Config *_parent, char *_name, char *_desc, char *_data);
|
||||
|
||||
inline operator bool() { return (bool)get(); }
|
||||
inline operator uint() { return get(); }
|
||||
@@ -64,6 +72,8 @@ char *name, *desc;
|
||||
inline operator int8() { return get(); }
|
||||
inline operator int16() { return get(); }
|
||||
inline operator int32() { return get(); }
|
||||
inline operator float() { return (float) get(); }
|
||||
inline operator double() { return (double)get(); }
|
||||
|
||||
inline Setting &operator=(const bool _data) { set((uint)_data); return *this; }
|
||||
inline Setting &operator=(const uint _data) { set(_data); return *this; }
|
||||
@@ -74,6 +84,8 @@ char *name, *desc;
|
||||
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; }
|
||||
inline Setting &operator=(const float _data) { set((uint)_data); return *this; }
|
||||
inline Setting &operator=(const double _data) { set((uint)_data); return *this; }
|
||||
};
|
||||
|
||||
class Config {
|
||||
|
||||
+65
-53
@@ -64,6 +64,28 @@ 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)); }
|
||||
|
||||
int __stricmp(const char *dest, const char *src) {
|
||||
while(*dest && *src) {
|
||||
if(chrlower(*dest) != chrlower(*src))break;
|
||||
dest++;
|
||||
src++;
|
||||
}
|
||||
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)); }
|
||||
|
||||
bool strmatch(const char *dest, const char *src) { return !strcmp(dest, src); }
|
||||
bool strmatch(substring &dest, const char *src) { return strmatch(strptr(dest), src); }
|
||||
bool strmatch(const char *dest, substring &src) { return strmatch(dest, strptr(src)); }
|
||||
bool strmatch(substring &dest, substring &src) { return strmatch(strptr(dest), strptr(src)); }
|
||||
|
||||
bool strimatch(const char *dest, const char *src) { return !stricmp(dest, src); }
|
||||
bool strimatch(substring &dest, const char *src) { return strimatch(strptr(dest), src); }
|
||||
bool strimatch(const char *dest, substring &src) { return strimatch(dest, strptr(src)); }
|
||||
bool strimatch(substring &dest, substring &src) { return strimatch(strptr(dest), strptr(src)); }
|
||||
|
||||
void strcpy(substring &dest, const char *src) {
|
||||
int srclen = strlen(src);
|
||||
if(srclen > dest.size) { strresize(dest, srclen); }
|
||||
@@ -109,18 +131,6 @@ int i, sl = strlen(dest.s);
|
||||
s[i] = 0;
|
||||
}
|
||||
|
||||
int __stricmp(const char *dest, const char *src) {
|
||||
while(*dest && *src) {
|
||||
if(chrlower(*dest) != chrlower(*src))break;
|
||||
dest++;
|
||||
src++;
|
||||
}
|
||||
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) {
|
||||
while(*str) {
|
||||
*str = chrlower(*str);
|
||||
@@ -137,40 +147,44 @@ void strupper(char *str) {
|
||||
}
|
||||
void strupper(substring &str) { strupper(strptr(str)); }
|
||||
|
||||
uint strpos(const char *str, const char *key) {
|
||||
bool strpos(const char *str, const char *key, uint &pos) {
|
||||
int i, ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return null;
|
||||
for(i=0;i<=ssl-ksl;i++) {
|
||||
if(!memcmp(str+i, key, ksl))return i;
|
||||
if(ksl > ssl)return false;
|
||||
for(i = 0; i <= ssl - ksl; i++) {
|
||||
if(!memcmp(str + i, key, ksl)) {
|
||||
pos = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
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)); }
|
||||
bool strpos(substring &str, const char *key, uint &pos) { return strpos(strptr(str), key, pos); }
|
||||
bool strpos(const char *str, substring &key, uint &pos) { return strpos(str, strptr(key), pos); }
|
||||
bool strpos(substring &str, substring &key, uint &pos) { return strpos(strptr(str), strptr(key), pos); }
|
||||
|
||||
uint qstrpos(const char *str, const char *key) {
|
||||
bool qstrpos(const char *str, const char *key, uint &pos) {
|
||||
int i, z, ssl = strlen(str), ksl = strlen(key);
|
||||
uint8 x;
|
||||
if(ksl > ssl)return null;
|
||||
for(i=0;i<=ssl-ksl;) {
|
||||
if(ksl > ssl)return false;
|
||||
for(i = 0; i <= ssl - ksl;) {
|
||||
x = str[i];
|
||||
if(x == '\"' || x == '\'') {
|
||||
z = i++;
|
||||
while(str[i] != x && i < ssl)i++;
|
||||
if(i >= ssl)i = z;
|
||||
}
|
||||
if(!memcmp(str+i, key, ksl)) {
|
||||
return i;
|
||||
if(!memcmp(str + i, key, ksl)) {
|
||||
pos = i;
|
||||
return true;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
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)); }
|
||||
bool qstrpos(substring &str, const char *key, uint &pos) { return qstrpos(strptr(str), key, pos); }
|
||||
bool qstrpos(const char *str, substring &key, uint &pos) { return qstrpos(str, strptr(key), pos); }
|
||||
bool qstrpos(substring &str, substring &key, uint &pos) { return qstrpos(strptr(str), strptr(key), pos); }
|
||||
|
||||
void strtr(char *dest, const char *before, const char *after) {
|
||||
int i, l, sl = strlen(dest), bsl = strlen(before), asl = strlen(after);
|
||||
@@ -183,53 +197,51 @@ 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); }
|
||||
|
||||
uint strbegin(const char *str, const char *key) {
|
||||
bool 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;
|
||||
if(ksl > ssl)return false;
|
||||
return (!memcmp(str, key, ksl));
|
||||
}
|
||||
uint strbegin(substring &str, const char *key) { return strbegin(strptr(str), key); }
|
||||
bool strbegin(substring &str, const char *key) { return strbegin(strptr(str), key); }
|
||||
|
||||
uint stribegin(const char *str, const char *key) {
|
||||
bool stribegin(const char *str, const char *key) {
|
||||
int i, ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return 1;
|
||||
if(ksl > ssl)return false;
|
||||
for(i=0;i<ksl;i++) {
|
||||
if(str[i] >= 'A' && str[i] <= 'Z') {
|
||||
if(str[i] != key[i] && str[i]+0x20 != key[i])return 1;
|
||||
if(str[i] != key[i] && str[i]+0x20 != key[i])return false;
|
||||
} else if(str[i] >= 'a' && str[i] <= 'z') {
|
||||
if(str[i] != key[i] && str[i]-0x20 != key[i])return 1;
|
||||
if(str[i] != key[i] && str[i]-0x20 != key[i])return false;
|
||||
} else {
|
||||
if(str[i] != key[i])return 1;
|
||||
if(str[i] != key[i])return false;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
uint stribegin(substring &str, const char *key) { return stribegin(strptr(str), key); }
|
||||
bool stribegin(substring &str, const char *key) { return stribegin(strptr(str), key); }
|
||||
|
||||
uint strend(const char *str, const char *key) {
|
||||
bool 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;
|
||||
if(ksl > ssl)return false;
|
||||
return (!memcmp(str + ssl - ksl, key, ksl));
|
||||
}
|
||||
uint strend(substring &str, const char *key) { return strend(strptr(str), key); }
|
||||
bool strend(substring &str, const char *key) { return strend(strptr(str), key); }
|
||||
|
||||
uint striend(const char *str, const char *key) {
|
||||
bool striend(const char *str, const char *key) {
|
||||
int i, z, ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return 1;
|
||||
if(ksl > ssl)return false;
|
||||
for(i=ssl-ksl, z=0;i<ssl;i++, z++) {
|
||||
if(str[i] >= 'A' && str[i] <= 'Z') {
|
||||
if(str[i] != key[z] && str[i]+0x20 != key[z])return 1;
|
||||
if(str[i] != key[z] && str[i]+0x20 != key[z])return false;
|
||||
} else if(str[i] >= 'a' && str[i] <= 'z') {
|
||||
if(str[i] != key[z] && str[i]-0x20 != key[z])return 1;
|
||||
if(str[i] != key[z] && str[i]-0x20 != key[z])return false;
|
||||
} else {
|
||||
if(str[i] != key[z])return 1;
|
||||
if(str[i] != key[z])return false;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
uint striend(substring &str, const char *key) { return striend(strptr(str), key); }
|
||||
bool striend(substring &str, const char *key) { return striend(strptr(str), key); }
|
||||
|
||||
void strltrim(char *str, const char *key) {
|
||||
int i, ssl = strlen(str), ksl = strlen(key);
|
||||
|
||||
+36
-26
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
libstring : version 0.06a ~byuu (08/22/05)
|
||||
libstring : version 0.07 ~byuu (11/30/05)
|
||||
*/
|
||||
|
||||
#ifndef __LIBSTRING
|
||||
@@ -25,6 +25,25 @@ int strcmp(substring &dest, const char *src);
|
||||
int strcmp(const char *dest, substring &src);
|
||||
int strcmp(substring &dest, substring &src);
|
||||
|
||||
//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);
|
||||
|
||||
bool strmatch(const char *dest, const char *src);
|
||||
bool strmatch(substring &dest, const char *src);
|
||||
bool strmatch(const char *dest, substring &src);
|
||||
bool strmatch(substring &dest, substring &src);
|
||||
|
||||
bool strimatch(const char *dest, const char *src);
|
||||
bool strimatch(substring &dest, const char *src);
|
||||
bool strimatch(const char *dest, substring &src);
|
||||
bool strimatch(substring &dest, substring &src);
|
||||
|
||||
void strcpy(substring &dest, const char *src);
|
||||
void strcpy(substring &dest, substring &src);
|
||||
|
||||
@@ -38,45 +57,36 @@ 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);
|
||||
bool strpos(const char *str, const char *key, uint &pos);
|
||||
bool strpos(substring &str, const char *key, uint &pos);
|
||||
bool strpos(const char *str, substring &key, uint &pos);
|
||||
bool strpos(substring &str, substring &key, uint &pos);
|
||||
|
||||
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);
|
||||
bool qstrpos(const char *str, const char *key, uint &pos);
|
||||
bool qstrpos(substring &str, const char *key, uint &pos);
|
||||
bool qstrpos(const char *str, substring &key, uint &pos);
|
||||
bool qstrpos(substring &str, substring &key, uint &pos);
|
||||
|
||||
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);
|
||||
bool strbegin(const char *str, const char *key);
|
||||
bool strbegin(substring &str, const char *key);
|
||||
|
||||
uint stribegin(const char *str, const char *key);
|
||||
uint stribegin(substring &str, const char *key);
|
||||
bool stribegin(const char *str, const char *key);
|
||||
bool stribegin(substring &str, const char *key);
|
||||
|
||||
uint strend(const char *str, const char *key);
|
||||
uint strend(substring &str, const char *key);
|
||||
bool strend(const char *str, const char *key);
|
||||
bool strend(substring &str, const char *key);
|
||||
|
||||
uint striend(const char *str, const char *key);
|
||||
uint striend(substring &str, const char *key);
|
||||
bool striend(const char *str, const char *key);
|
||||
bool striend(substring &str, const char *key);
|
||||
|
||||
void strltrim(char *str, const char *key);
|
||||
void strltrim(substring &str, const char *key);
|
||||
|
||||
@@ -6,6 +6,12 @@ uint32 b, w;
|
||||
b = (addr >> 16);
|
||||
w = (addr & 0xffff);
|
||||
|
||||
if(cartridge.cart.c4) {
|
||||
if(!(b & 0x40) && w >= 0x6000 && w <= 0x7fff) {
|
||||
return c4->read(w);
|
||||
}
|
||||
}
|
||||
|
||||
//SRAM Region A
|
||||
if((b & 0x7f) >= 0x30 && (b & 0x7f) <= 0x3f && (w & 0xe000) == 0x6000) {
|
||||
b &= 0x7f;
|
||||
@@ -57,6 +63,13 @@ uint32 b, w;
|
||||
b = (addr >> 16);
|
||||
w = (addr & 0xffff);
|
||||
|
||||
if(cartridge.cart.c4) {
|
||||
if(!(b & 0x40) && w >= 0x6000 && w <= 0x7fff) {
|
||||
c4->write(w, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//SRAM Region A
|
||||
if((b & 0x7f) >= 0x30 && (b & 0x7f) <= 0x3f && (w & 0xe000) == 0x6000) {
|
||||
b &= 0x7f;
|
||||
|
||||
+29
-116
@@ -4,82 +4,15 @@
|
||||
#include "bcart_exlorom.cpp"
|
||||
#include "bcart_exhirom.cpp"
|
||||
|
||||
bool bMemBus::load_cart(Reader *rf) {
|
||||
uint32 cksum, icksum, index;
|
||||
char cart_title[24];
|
||||
uint8 mapper, region;
|
||||
if(rom_loaded == true)return false;
|
||||
void bMemBus::load_cart() {
|
||||
if(rom_loaded == true)return;
|
||||
|
||||
rf->read(&rom_image);
|
||||
rom = rom_image;
|
||||
rom_size = rf->size();
|
||||
|
||||
if(rom_size < 32768) {
|
||||
free(rom_image);
|
||||
return false;
|
||||
}
|
||||
|
||||
//check for ROM header (currently unused)
|
||||
if((rom_size & 0x1fff) == 0x0200) {
|
||||
rom_size -= 512;
|
||||
rom += 512;
|
||||
}
|
||||
|
||||
if(rom_size >= 0x410000) {
|
||||
if(rom[0x7fd5] == 0x32) {
|
||||
mapper = EXLOROM;
|
||||
} else {
|
||||
mapper = EXHIROM;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
|
||||
if(rom_size < 65536) {
|
||||
mapper = LOROM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
cksum = rom[0xffdc] | (rom[0xffdd] << 8);
|
||||
icksum = rom[0xffde] | (rom[0xffdf] << 8);
|
||||
if(cksum + icksum == 0xffff) {
|
||||
mapper = HIROM;
|
||||
} else {
|
||||
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);
|
||||
cart_title[21] = 0;
|
||||
|
||||
switch(rom[index + 0x18] & 7) {
|
||||
case 0:sram_size = 0; break;
|
||||
case 1:sram_size = 2 * 1024;break;
|
||||
case 2:sram_size = 4 * 1024;break;
|
||||
case 3:sram_size = 8 * 1024;break;
|
||||
case 4:sram_size = 16 * 1024;break;
|
||||
case 5:sram_size = 32 * 1024;break;
|
||||
case 6:sram_size = 64 * 1024;break;
|
||||
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);
|
||||
uint8 *rom = cartridge.rom;
|
||||
uint16 index = cartridge.cart.header_index;
|
||||
dprintf("* Image Name : \"%s\"", cartridge.cart.name);
|
||||
dprintf("* Region : %s", (cartridge.cart.region == Cartridge::NTSC) ? "NTSC" : "PAL");
|
||||
dprintf("* MAD : %0.2x", cartridge.cart.mapper);
|
||||
dprintf("* SRAM Size : %dkb", cartridge.cart.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",
|
||||
rom[index + 0x3c] | (rom[index + 0x3d] << 8), //Reset
|
||||
rom[index + 0x2a] | (rom[index + 0x2b] << 8), //NMI
|
||||
@@ -92,66 +25,42 @@ end:
|
||||
dprintf("");
|
||||
|
||||
CartInfo ci;
|
||||
ci.rom = rom;
|
||||
ci.sram = sram;
|
||||
ci.rom_size = rom_size;
|
||||
ci.sram_size = sram_size;
|
||||
ci.rom = cartridge.rom;
|
||||
ci.sram = cartridge.sram;
|
||||
ci.rom_size = cartridge.cart.rom_size;
|
||||
ci.sram_size = cartridge.cart.sram_size;
|
||||
|
||||
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;
|
||||
switch(cartridge.cart.mapper) {
|
||||
case Cartridge::LOROM: cart = new bCartLoROM(); break;
|
||||
case Cartridge::HIROM: cart = new bCartHiROM(); break;
|
||||
case Cartridge::EXLOROM:cart = new bCartExLoROM();break;
|
||||
case Cartridge::EXHIROM:cart = new bCartExHiROM();break;
|
||||
default:return;
|
||||
}
|
||||
|
||||
cart->set_cartinfo(&ci);
|
||||
rom_loaded = true;
|
||||
|
||||
if(region == 0 || region == 1) {
|
||||
if(cartridge.cart.region == Cartridge::NTSC) {
|
||||
snes->set_region(SNES::NTSC);
|
||||
} else {
|
||||
snes->set_region(SNES::PAL);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bMemBus::load_sram(Reader *rf) {
|
||||
if(rom_loaded == false || sram_size == 0)return false;
|
||||
rf->read(&sram, sram_size);
|
||||
|
||||
CartInfo ci;
|
||||
ci.rom = rom;
|
||||
ci.sram = sram;
|
||||
ci.rom_size = rom_size;
|
||||
ci.sram_size = sram_size;
|
||||
cart->set_cartinfo(&ci);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bMemBus::save_sram(Writer *wf) {
|
||||
if(rom_loaded == false || sram_size == 0)return false;
|
||||
wf->write(sram, sram_size);
|
||||
return true;
|
||||
rom_loaded = true;
|
||||
}
|
||||
|
||||
void bMemBus::unload_cart() {
|
||||
if(rom_loaded == false)return;
|
||||
|
||||
if(rom_image)free(rom_image);
|
||||
if(sram)free(sram);
|
||||
delete(cart);
|
||||
|
||||
rom_loaded = false;
|
||||
}
|
||||
|
||||
void bMemBus::get_cartinfo(CartInfo *ci) {
|
||||
ci->rom = rom;
|
||||
ci->sram = sram;
|
||||
ci->rom_size = rom_size;
|
||||
ci->sram_size = sram_size;
|
||||
ci->rom = cartridge.rom;
|
||||
ci->sram = cartridge.sram;
|
||||
ci->rom_size = cartridge.cart.rom_size;
|
||||
ci->sram_size = cartridge.cart.sram_size;
|
||||
}
|
||||
|
||||
/***********************
|
||||
@@ -171,7 +80,7 @@ void bMemBus::get_cartinfo(CartInfo *ci) {
|
||||
***************************************/
|
||||
|
||||
uint8 bMemBus::read(uint32 addr) {
|
||||
static uint32 r;
|
||||
uint8 r;
|
||||
switch(addr & 0xc00000) {
|
||||
case 0x400000:
|
||||
if((addr & 0xfe0000) == 0x7e0000) {
|
||||
@@ -206,7 +115,9 @@ static uint32 r;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::MEM_READ, addr, r);
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -245,7 +156,9 @@ void bMemBus::write(uint32 addr, uint8 value) {
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::MEM_WRITE, addr, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
void bMemBus::power() {
|
||||
|
||||
@@ -11,8 +11,7 @@ public:
|
||||
//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;
|
||||
uint8 *wram;
|
||||
|
||||
bool rom_loaded;
|
||||
enum { LOROM = 0x20, HIROM = 0x21, EXLOROM = 0x22, EXHIROM = 0x25 };
|
||||
@@ -20,10 +19,9 @@ enum { LOROM = 0x20, HIROM = 0x21, EXLOROM = 0x22, EXHIROM = 0x25 };
|
||||
uint8 read (uint32 addr);
|
||||
void write(uint32 addr, uint8 value);
|
||||
|
||||
bool load_cart(Reader *rf);
|
||||
bool load_sram(Reader *rf);
|
||||
bool save_sram(Writer *wf);
|
||||
void load_cart();
|
||||
void unload_cart();
|
||||
bool cart_loaded() { return rom_loaded; }
|
||||
void get_cartinfo(CartInfo *ci);
|
||||
|
||||
void power();
|
||||
|
||||
@@ -79,7 +79,7 @@ void Memory::write_long(uint32 addr, uint32 data, uint wrap) {
|
||||
}
|
||||
|
||||
MMIO mmio_unmapped;
|
||||
uint8 MMIO::read (uint32 addr) { return cpu->regs.mdr; }
|
||||
uint8 MMIO::read (uint32 addr) { return r_cpu->regs.mdr; }
|
||||
void MMIO::write(uint32 addr, uint8 value) {}
|
||||
|
||||
uint8 MemBus::calc_speed(uint32 addr, bool fast) {
|
||||
@@ -92,10 +92,6 @@ uint8 MemBus::calc_speed(uint32 addr, bool fast) {
|
||||
return 8;
|
||||
}
|
||||
|
||||
uint8 MemBus::speed(uint32 addr) {
|
||||
return speed_table[addr >> 9];
|
||||
}
|
||||
|
||||
void MemBus::set_speed(bool fast) {
|
||||
fastROM = fast;
|
||||
|
||||
@@ -131,5 +127,3 @@ int i;
|
||||
}
|
||||
speed_table = (uint8*)speed_table_slowrom;
|
||||
}
|
||||
|
||||
MemBus::~MemBus() {}
|
||||
+7
-6
@@ -43,18 +43,19 @@ uint8 *speed_table,
|
||||
speed_table_fastrom[32768];
|
||||
inline uint8 calc_speed(uint32 addr, bool fast);
|
||||
public:
|
||||
uint8 speed(uint32 addr);
|
||||
void set_speed(bool fast);
|
||||
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 load_cart() = 0;
|
||||
virtual void unload_cart() = 0;
|
||||
virtual bool cart_loaded() = 0;
|
||||
virtual void get_cartinfo(CartInfo *ci) = 0;
|
||||
|
||||
virtual void power() = 0;
|
||||
virtual void reset() = 0;
|
||||
|
||||
MemBus();
|
||||
~MemBus();
|
||||
virtual ~MemBus() {}
|
||||
};
|
||||
+123
-93
@@ -5,18 +5,40 @@
|
||||
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.hires) ? 512 : 256;
|
||||
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) {
|
||||
int32 bg;
|
||||
if(line.y == 1) {
|
||||
//mosaic reset
|
||||
for(bg=BG1;bg<=BG4;bg++) {
|
||||
regs.bg_y[bg] = 1;
|
||||
}
|
||||
|
||||
regs.mosaic_countdown = regs.mosaic_size + 1;
|
||||
regs.mosaic_countdown--;
|
||||
} else {
|
||||
for(bg=BG1;bg<=BG4;bg++) {
|
||||
if(!regs.mosaic_enabled[bg] || !regs.mosaic_countdown) {
|
||||
regs.bg_y[bg] = line.y;
|
||||
}
|
||||
}
|
||||
|
||||
if(!regs.mosaic_countdown) {
|
||||
regs.mosaic_countdown = regs.mosaic_size + 1;
|
||||
}
|
||||
regs.mosaic_countdown--;
|
||||
}
|
||||
|
||||
if(line.y == 1) {
|
||||
//OAM FirstSprite priority set
|
||||
if(regs.oam_priority == true) {
|
||||
regs.oam_firstsprite = (regs.oam_addr & 0xfe) >> 1;
|
||||
@@ -25,43 +47,27 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
void bPPU::render_scanline() {
|
||||
//only allow frameskip setting to ignore actual rendering; not RTO, etc.
|
||||
if(settings.frameskip_pos != 0)return;
|
||||
if(status.render_output == false)return;
|
||||
|
||||
if(_y > 0 && _y < (cpu->overscan() ? 239 : 224)) {
|
||||
if(line.y > 0 && line.y < (r_cpu->overscan() ? 239 : 224)) {
|
||||
render_line();
|
||||
}
|
||||
}
|
||||
|
||||
bool bPPU::render_frame() { return (settings.frameskip_pos == 0); }
|
||||
|
||||
void bPPU::frame() {
|
||||
if(settings.frameskip_changed == true) {
|
||||
settings.frameskip_changed = false;
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -72,6 +78,7 @@ void bPPU::power() {
|
||||
}
|
||||
|
||||
void bPPU::reset() {
|
||||
PPU::reset();
|
||||
frame();
|
||||
|
||||
memset(sprite_list, 0, sizeof(sprite_list));
|
||||
@@ -80,6 +87,12 @@ void bPPU::reset() {
|
||||
regs.ppu1_mdr = 0xff;
|
||||
regs.ppu2_mdr = 0xff;
|
||||
|
||||
//bg line counters
|
||||
regs.bg_y[0] = 0;
|
||||
regs.bg_y[1] = 0;
|
||||
regs.bg_y[2] = 0;
|
||||
regs.bg_y[3] = 0;
|
||||
|
||||
//$2100
|
||||
regs.display_disabled = 0;
|
||||
regs.display_brightness = 0;
|
||||
@@ -104,13 +117,15 @@ void bPPU::reset() {
|
||||
regs.bg_tilesize[BG4] = 0;
|
||||
regs.bg3_priority = 0;
|
||||
regs.bg_mode = 0;
|
||||
regs.hires = false;
|
||||
|
||||
//$2106
|
||||
regs.mosaic_size = 0;
|
||||
regs.mosaic_enabled[BG1] = false;
|
||||
regs.mosaic_enabled[BG2] = false;
|
||||
regs.mosaic_enabled[BG3] = false;
|
||||
regs.mosaic_enabled[BG4] = false;
|
||||
regs.mosaic_size = 0;
|
||||
regs.mosaic_enabled[BG1] = false;
|
||||
regs.mosaic_enabled[BG2] = false;
|
||||
regs.mosaic_enabled[BG3] = false;
|
||||
regs.mosaic_enabled[BG4] = false;
|
||||
regs.mosaic_countdown = 0;
|
||||
|
||||
//$2107-$210a
|
||||
regs.bg_scaddr[BG1] = 0x0000;
|
||||
@@ -162,30 +177,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;
|
||||
@@ -194,12 +212,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;
|
||||
@@ -214,16 +232,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;
|
||||
@@ -231,26 +249,28 @@ 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;
|
||||
regs.overscan = false;
|
||||
regs.scanlines = 224;
|
||||
regs.oam_halve = false;
|
||||
regs.interlace = false;
|
||||
regs.mode7_extbg = false;
|
||||
regs.pseudo_hires = false;
|
||||
regs.overscan = false;
|
||||
regs.scanlines = 224;
|
||||
regs.oam_halve = false;
|
||||
regs.interlace = false;
|
||||
|
||||
//$2137
|
||||
regs.hcounter = 0;
|
||||
@@ -266,27 +286,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;
|
||||
}
|
||||
|
||||
@@ -294,7 +322,9 @@ 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) {
|
||||
@@ -304,7 +334,9 @@ uint8 r;
|
||||
if(addr & 1) {
|
||||
r &= 0x7f;
|
||||
}
|
||||
#ifdef DEBUGGER
|
||||
snes->notify(SNES::CGRAM_READ, addr, r);
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -314,14 +346,12 @@ void bPPU::cgram_write(uint16 addr, uint8 value) {
|
||||
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*)malloc(65536);
|
||||
|
||||
+26
-20
@@ -14,8 +14,15 @@ uint8 *vram, *oam, *cgram;
|
||||
uint8 region;
|
||||
|
||||
enum { NTSC = 0, PAL = 1 };
|
||||
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 { 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 interlace;
|
||||
bool interlace_field;
|
||||
} line;
|
||||
|
||||
struct sprite_item {
|
||||
uint8 width, height;
|
||||
@@ -27,15 +34,13 @@ struct sprite_item {
|
||||
uint8 priority;
|
||||
} sprite_list[128];
|
||||
|
||||
struct {
|
||||
int32 frameskip, frameskip_pos;
|
||||
bool frameskip_changed;
|
||||
} settings;
|
||||
|
||||
struct {
|
||||
//open bus support
|
||||
uint8 ppu1_mdr, ppu2_mdr;
|
||||
|
||||
//bg line counters
|
||||
uint16 bg_y[4];
|
||||
|
||||
//$2100
|
||||
bool display_disabled;
|
||||
uint8 display_brightness;
|
||||
@@ -56,10 +61,12 @@ struct {
|
||||
bool bg_tilesize[4];
|
||||
bool bg3_priority;
|
||||
uint8 bg_mode;
|
||||
bool hires;
|
||||
|
||||
//$2106
|
||||
uint8 mosaic_size;
|
||||
bool mosaic_enabled[4];
|
||||
uint16 mosaic_countdown;
|
||||
|
||||
//$2107-$210a
|
||||
uint16 bg_scaddr[4];
|
||||
@@ -95,26 +102,23 @@ struct {
|
||||
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;
|
||||
@@ -123,13 +127,15 @@ struct {
|
||||
|
||||
//$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;
|
||||
bool pseudo_hires;
|
||||
bool overscan;
|
||||
uint16 scanlines;
|
||||
bool oam_halve;
|
||||
@@ -158,6 +164,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
|
||||
@@ -242,10 +250,8 @@ uint16 *mosaic_table[16];
|
||||
void frame();
|
||||
void power();
|
||||
void reset();
|
||||
void set_frameskip(int fs);
|
||||
bool render_frame();
|
||||
|
||||
bool scanline_is_hires() { return (regs.bg_mode == 5 || regs.bg_mode == 6); }
|
||||
bool scanline_is_hires() { return (regs.hires); }
|
||||
|
||||
bPPU();
|
||||
~bPPU();
|
||||
|
||||
+219
-78
@@ -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,14 @@ void bPPU::mmio_w2105(uint8 value) {
|
||||
regs.bg_tilesize[BG1] = !!(value & 0x10);
|
||||
regs.bg3_priority = !!(value & 0x08);
|
||||
regs.bg_mode = (value & 7);
|
||||
regs.hires = (regs.bg_mode == 5 || regs.bg_mode == 6);
|
||||
|
||||
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
|
||||
@@ -185,40 +242,54 @@ 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
|
||||
@@ -284,72 +355,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
|
||||
@@ -372,20 +488,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
|
||||
@@ -394,18 +522,20 @@ void bPPU::mmio_w2130(uint8 value) {
|
||||
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
|
||||
@@ -413,18 +543,21 @@ 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
|
||||
void bPPU::mmio_w2133(uint8 value) {
|
||||
regs.mode7_extbg = !!(value & 0x40);
|
||||
regs.overscan = !!(value & 0x04);
|
||||
regs.scanlines = (value & 0x04)?239:224;
|
||||
regs.oam_halve = !!(value & 0x02);
|
||||
regs.interlace = !!(value & 0x01);
|
||||
regs.mode7_extbg = !!(value & 0x40);
|
||||
regs.pseudo_hires = !!(value & 0x08);
|
||||
regs.overscan = !!(value & 0x04);
|
||||
regs.scanlines = (value & 0x04)?239:224;
|
||||
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
|
||||
@@ -453,10 +586,10 @@ uint32 r;
|
||||
|
||||
//SLHV
|
||||
uint8 bPPU::mmio_r2137() {
|
||||
if(cpu->pio_status() & 0x80) {
|
||||
if(r_cpu->pio_status() & 0x80) {
|
||||
latch_counters();
|
||||
}
|
||||
return cpu->regs.mdr;
|
||||
return r_cpu->regs.mdr;
|
||||
}
|
||||
|
||||
//OAMDATAREAD
|
||||
@@ -476,8 +609,12 @@ uint16 addr = get_vram_address();
|
||||
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 regs.ppu1_mdr;
|
||||
@@ -489,8 +626,12 @@ uint16 addr = get_vram_address() + 1;
|
||||
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 regs.ppu1_mdr;
|
||||
@@ -552,8 +693,8 @@ uint8 r = 0x00;
|
||||
regs.latch_hcounter = 0;
|
||||
regs.latch_vcounter = 0;
|
||||
|
||||
r |= cpu->interlace_field() << 7;
|
||||
if(!(cpu->pio_status() & 0x80)) {
|
||||
r |= r_cpu->interlace_field() << 7;
|
||||
if(!(r_cpu->pio_status() & 0x80)) {
|
||||
r |= 0x40;
|
||||
} else if(regs.counters_latched == true) {
|
||||
r |= 0x40;
|
||||
@@ -601,7 +742,7 @@ uint8 bPPUMMIO::read(uint32 addr) {
|
||||
case 0x213f:return ppu->mmio_r213f(); //STAT78
|
||||
}
|
||||
|
||||
return cpu->regs.mdr;
|
||||
return r_cpu->regs.mdr;
|
||||
}
|
||||
|
||||
void bPPUMMIO::write(uint32 addr, uint8 value) {
|
||||
|
||||
@@ -6,6 +6,40 @@
|
||||
#include "bppu_render_addsub.cpp"
|
||||
#include "bppu_render_line.cpp"
|
||||
|
||||
bool bPPU::render_enabled(uint8 bg, uint8 pri) {
|
||||
switch(bg) {
|
||||
case BG1:
|
||||
switch(pri) {
|
||||
case 0: return config::ppu.bg1_pri0_enable;
|
||||
case 1: return config::ppu.bg1_pri1_enable;
|
||||
} break;
|
||||
case BG2:
|
||||
switch(pri) {
|
||||
case 0: return config::ppu.bg2_pri0_enable;
|
||||
case 1: return config::ppu.bg2_pri1_enable;
|
||||
} break;
|
||||
case BG3:
|
||||
switch(pri) {
|
||||
case 0: return config::ppu.bg3_pri0_enable;
|
||||
case 1: return config::ppu.bg3_pri1_enable;
|
||||
} break;
|
||||
case BG4:
|
||||
switch(pri) {
|
||||
case 0: return config::ppu.bg4_pri0_enable;
|
||||
case 1: return config::ppu.bg4_pri1_enable;
|
||||
} break;
|
||||
case OAM:
|
||||
switch(pri) {
|
||||
case 0: return config::ppu.oam_pri0_enable;
|
||||
case 1: return config::ppu.oam_pri1_enable;
|
||||
case 2: return config::ppu.oam_pri2_enable;
|
||||
case 3: return config::ppu.oam_pri3_enable;
|
||||
} break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Mode 0: ->
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
|
||||
@@ -20,28 +54,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,12 +152,13 @@ inline void bPPU::render_line_mode7() {
|
||||
|
||||
void bPPU::render_line() {
|
||||
if(regs.display_disabled == true) {
|
||||
memset(snes->get_ppu_output_handle(), 0, 1024);
|
||||
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;
|
||||
|
||||
+26
-19
@@ -1,8 +1,5 @@
|
||||
//bppu_render.cpp
|
||||
int _screen_width;
|
||||
bool _interlace;
|
||||
int _interlace_field;
|
||||
|
||||
inline bool render_enabled(uint8 bg, uint8 pri);
|
||||
inline void render_line_mode0();
|
||||
inline void render_line_mode1();
|
||||
inline void render_line_mode2();
|
||||
@@ -16,38 +13,45 @@ inline void render_line_mode7();
|
||||
enum { COLORDEPTH_4 = 0, COLORDEPTH_16 = 1, COLORDEPTH_256 = 2 };
|
||||
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 {
|
||||
//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;
|
||||
//true when bg_main == OAM && palette index >= 192, disables color add/sub effects
|
||||
uint8 color_exempt;
|
||||
//color_exemption -- true when bg == OAM && palette index >= 192, disables color add/sub effects
|
||||
uint8 ce_main, ce_sub;
|
||||
//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];
|
||||
} pixel_cache[256];
|
||||
|
||||
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[256], sub[256];
|
||||
} 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
|
||||
@@ -60,24 +64,27 @@ struct oam_tileitem {
|
||||
} 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);
|
||||
|
||||
//bppu_render_mode7.cpp
|
||||
void render_line_mode7(uint8 bg, uint8 pri0_pos, uint8 pri1_pos);
|
||||
|
||||
//bppu_render_addsub.cpp
|
||||
inline uint16 addsub_pixels(uint32 cdest, uint32 csrc);
|
||||
inline uint16 addsub_pixel (uint32 cdest);
|
||||
inline uint16 addsub_pixels(uint32 x, uint32 cdest, uint32 csrc, bool halve);
|
||||
|
||||
//bppu_render_line.cpp
|
||||
enum { BLENDTYPE_BACK = 0, BLENDTYPE_MAIN = 1, BLENDTYPE_SUB = 2, BLENDTYPE_COMBINE = 3 };
|
||||
|
||||
inline uint16 get_palette(uint8 index);
|
||||
inline uint16 get_direct_color(uint8 p, uint8 t);
|
||||
inline uint16 get_pixel(int x);
|
||||
inline uint16 get_pixel_normal(uint32 x);
|
||||
inline uint16 get_pixel_swap(uint32 x);
|
||||
inline uint16 get_pixel_lores(uint32 x);
|
||||
inline uint16 get_pixel_hires(uint32 x);
|
||||
inline void render_line_output();
|
||||
@@ -1,92 +1,29 @@
|
||||
inline uint16 bPPU::addsub_pixels(uint32 cdest, uint32 csrc) {
|
||||
int r, g, b;
|
||||
uint16 res;
|
||||
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(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_pixels(uint32 x, uint32 cdest, uint32 csrc, bool halve) {
|
||||
if(!regs.color_mode) {
|
||||
//add
|
||||
cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
|
||||
csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
|
||||
cdest += csrc;
|
||||
|
||||
inline uint16 bPPU::addsub_pixel(uint32 cdest) {
|
||||
int r, g, b;
|
||||
uint32 csrc = (regs.color_r) | (regs.color_g << 5) | (regs.color_b << 10);
|
||||
uint16 res;
|
||||
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(!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 && 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;
|
||||
cdest >>= 1;
|
||||
}
|
||||
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
|
||||
}
|
||||
+162
-219
@@ -1,263 +1,206 @@
|
||||
//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 = (regs.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 pos;
|
||||
x &= bg_info[bg].mx;
|
||||
y &= bg_info[bg].my;
|
||||
|
||||
x >>= bg_info[bg].tw;
|
||||
y >>= bg_info[bg].th;
|
||||
|
||||
pos = (regs.bg_scsize[bg] & 2) ? ((y & 0x20) << ((regs.bg_scsize[bg] & 1) ? 6 : 5)) : 0;
|
||||
pos += (regs.bg_scsize[bg] & 1) ? ((x & 0x20) << 5) : 0;
|
||||
pos += ((y & 31) << 5) + (x & 31);
|
||||
return read16(vram, regs.bg_scaddr[bg] + (pos << 1));
|
||||
}
|
||||
|
||||
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];
|
||||
//are layers disabled by user?
|
||||
if(render_enabled(bg, 0) == false)pri0_pos = 0;
|
||||
if(render_enabled(bg, 1) == false)pri1_pos = 0;
|
||||
//nothing to render?
|
||||
if(!pri0_pos && !pri1_pos)return;
|
||||
|
||||
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;
|
||||
bool bg_enabled = regs.bg_enabled[bg];
|
||||
bool bgsub_enabled = regs.bgsub_enabled[bg];
|
||||
|
||||
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 = regs.bg_y[bg];
|
||||
if(line.interlace && regs.hires) {
|
||||
y = (y << 1) + line.interlace_field;
|
||||
}
|
||||
|
||||
//Mode 0 uses a special palette-indexing mode.
|
||||
//Since there are 8 selectable palettes per tile,
|
||||
//and there are 4 colors per palette on all four
|
||||
//BGs for Mode 0, each BG has a unique palette
|
||||
//entry point. This allows all 256 palette colors
|
||||
//to be used, instead of just the first 32.
|
||||
//entry = bg * 32, where 32 is from 8 * 4
|
||||
uint8 bgpal_index = (regs.bg_mode == 0) ? (bg << 5) : 0;
|
||||
uint16 hscroll = (regs.hires) ? (regs.bg_hofs[bg] << 1) : regs.bg_hofs[bg];
|
||||
uint16 vscroll = (line.interlace && regs.hires) ? (regs.bg_vofs[bg] << 1) : regs.bg_vofs[bg];
|
||||
hscroll &= mask_x;
|
||||
vscroll &= mask_y;
|
||||
|
||||
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 *mtable = (uint16*)mosaic_table[(regs.mosaic_enabled[bg]) ? regs.mosaic_size : 0];
|
||||
uint16 mosaic_x;
|
||||
uint16 mosaic_y;
|
||||
|
||||
uint8 *bg_td, *bg_td_state;
|
||||
bg_td = (uint8*)bg_tiledata[color_depth];
|
||||
bg_td_state = (uint8*)bg_tiledata_state[color_depth];
|
||||
|
||||
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;
|
||||
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 = (config::ppu.opt_enable) && (regs.bg_mode == 2 || regs.bg_mode == 4 || regs.bg_mode == 6);
|
||||
|
||||
build_window_tables(bg);
|
||||
uint8 *wt_main = main_windowtable[bg];
|
||||
uint8 *wt_sub = sub_windowtable[bg];
|
||||
uint8 *wt_main = window_cache[bg].main;
|
||||
uint8 *wt_sub = window_cache[bg].sub;
|
||||
|
||||
screen_x = 0;
|
||||
do { //for(screen_x=0;screen_x<_screen_width;screen_x++) {
|
||||
if(regs.bg_mode == 2 || regs.bg_mode == 4 || regs.bg_mode == 6) {
|
||||
if(regs.bg_mode == 6) {
|
||||
//hires adjust
|
||||
tile_x = (mtable[screen_x + (hscroll & 15)] >> 4);
|
||||
} else {
|
||||
tile_x = (mtable[screen_x + (hscroll & 7)] >> 3);
|
||||
}
|
||||
int32 prev_x = -1, prev_y = -1;
|
||||
for(x = 0; x < line.width; x++) {
|
||||
hoffset = x + hscroll;
|
||||
voffset = y + vscroll;
|
||||
|
||||
hoffset = hscroll;
|
||||
voffset = vscroll;
|
||||
if(is_opt_mode) {
|
||||
opt_x = (x + (hscroll & 7));
|
||||
|
||||
//tile 0 is unaffected by OPT mode...
|
||||
if(tile_x != 0) {
|
||||
//multiply by two to index into 16-bit table entries
|
||||
tile_x = ((tile_x - 1) & 31) << 1;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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 = 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);
|
||||
mirror_x = !!(t & 0x4000);
|
||||
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;
|
||||
mirror_y = !!(t & 0x8000);
|
||||
mirror_x = !!(t & 0x4000);
|
||||
|
||||
tile_pri = (t & 0x2000) ? pri1_pos : pri0_pos;
|
||||
tile_num = t;
|
||||
|
||||
if(tile_width == 4) { //16x16 horizontal tile mirroring
|
||||
if(!!(mosaic_x & 8) != mirror_x)tile_num++;
|
||||
}
|
||||
|
||||
if(tile_height == 4) { //16x16 vertical tile mirroring
|
||||
if(!!(mosaic_y & 8) != mirror_y)tile_num += 16;
|
||||
}
|
||||
|
||||
//16x16 horizontal tile mirroring
|
||||
if(tile_width == 4) {
|
||||
if(((mosaic_x & 15) >= 8 && !mirror_x) ||
|
||||
((mosaic_x & 15) < 8 && mirror_x))tile_num++;
|
||||
tile_num &= 0x03ff;
|
||||
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);
|
||||
}
|
||||
|
||||
//16x16 vertical tile mirroring
|
||||
if(tile_height == 4) {
|
||||
if(((mosaic_y & 15) >= 8 && !mirror_y) ||
|
||||
((mosaic_y & 15) < 8 && mirror_y))tile_num += 16;
|
||||
tile_num &= 0x03ff;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
tile_num += (_tdaddr >> tiledata_size);
|
||||
#define setpixel_main(x) \
|
||||
if(pixel_cache[x].pri_main < tile_pri) { \
|
||||
pixel_cache[x].pri_main = tile_pri; \
|
||||
pixel_cache[x].bg_main = bg; \
|
||||
pixel_cache[x].src_main = col; \
|
||||
pixel_cache[x].ce_main = false; \
|
||||
}
|
||||
#define setpixel_sub(x) \
|
||||
if(pixel_cache[x].pri_sub < tile_pri) { \
|
||||
pixel_cache[x].pri_sub = tile_pri; \
|
||||
pixel_cache[x].bg_sub = bg; \
|
||||
pixel_cache[x].src_sub = col; \
|
||||
pixel_cache[x].ce_sub = false; \
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
do {
|
||||
if(mirror_x) { xpos = (7 - (mosaic_x & 7)); }
|
||||
else { xpos = ( (mosaic_x & 7)); }
|
||||
col = *(tile_ptr + xpos);
|
||||
if(col && main_colorwindowtable[screen_x]) {
|
||||
if(regs.direct_color == true && bg == BG1 && (regs.bg_mode == 3 || regs.bg_mode == 4)) {
|
||||
col = get_direct_color(pal_num, col);
|
||||
if(!regs.hires) {
|
||||
if(bg_enabled == true && !wt_main[x]) { setpixel_main(x); }
|
||||
if(bgsub_enabled == true && !wt_sub[x]) { setpixel_sub(x); }
|
||||
} else {
|
||||
int hx = x >> 1;
|
||||
if(x & 1) {
|
||||
if(bg_enabled == true && !wt_main[hx]) { setpixel_main(hx); }
|
||||
} else {
|
||||
col = get_palette(col + pal_index);
|
||||
}
|
||||
|
||||
if(_bg_enabled == true && !wt_main[screen_x]) {
|
||||
if(pixel_cache[screen_x].pri_main < _pri) {
|
||||
pixel_cache[screen_x].pri_main = _pri;
|
||||
pixel_cache[screen_x].bg_main = 0x80 | bg;
|
||||
pixel_cache[screen_x].src_main = col;
|
||||
pixel_cache[screen_x].color_exempt = false;
|
||||
}
|
||||
}
|
||||
if(_bgsub_enabled == true && !wt_sub[screen_x]) {
|
||||
if(pixel_cache[screen_x].pri_sub < _pri) {
|
||||
pixel_cache[screen_x].pri_sub = _pri;
|
||||
pixel_cache[screen_x].bg_sub = 0x80 | bg;
|
||||
pixel_cache[screen_x].src_sub = col;
|
||||
}
|
||||
if(bgsub_enabled == true && !wt_sub[hx]) { setpixel_sub(hx); }
|
||||
}
|
||||
}
|
||||
|
||||
bg_x++;
|
||||
bg_x &= screen_width_mask;
|
||||
mosaic_x = mtable[bg_x];
|
||||
|
||||
if(base_xpos != ((mosaic_x >> 3) & 31))break;
|
||||
if(++screen_x >= _screen_width)break;
|
||||
} while(1);
|
||||
} while(++screen_x < _screen_width);
|
||||
#undef setpixel_main
|
||||
#undef setpixel_sub
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,8 +98,24 @@ 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));
|
||||
uint16 main = get_palette(0);
|
||||
uint16 sub = (regs.pseudo_hires || regs.hires) ? main : regs.color_rgb;
|
||||
uint32 i = 255;
|
||||
do {
|
||||
pixel_cache[i].src_main = main;
|
||||
pixel_cache[i].src_sub = sub;
|
||||
pixel_cache[i].bg_main = BACK;
|
||||
pixel_cache[i].bg_sub = BACK;
|
||||
pixel_cache[i].ce_main = false;
|
||||
pixel_cache[i].ce_sub = false;
|
||||
pixel_cache[i].pri_main = 0;
|
||||
pixel_cache[i].pri_sub = 0;
|
||||
} while(i--);
|
||||
}
|
||||
|
||||
void bPPU::init_tiledata_cache() {
|
||||
@@ -112,8 +130,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,81 +1,119 @@
|
||||
inline uint16 bPPU::get_palette(uint8 index) {
|
||||
return *((uint16*)cgram + index);
|
||||
return read16(cgram, index << 1);
|
||||
}
|
||||
|
||||
inline uint16 bPPU::get_direct_color(uint8 p, uint8 t) {
|
||||
//p = 00000bgr
|
||||
//t = BBGGGRRR
|
||||
//r = 0BBb00GGGg0RRRr0
|
||||
//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);
|
||||
(((t >> 3) & 7) << 7) | (((p >> 1) & 1) << 6) |
|
||||
((t >> 6) << 13) | ((p >> 2) << 12);
|
||||
}
|
||||
|
||||
inline uint16 bPPU::get_pixel(int x) {
|
||||
inline uint16 bPPU::get_pixel_normal(uint32 x) {
|
||||
_pixel *p = &pixel_cache[x];
|
||||
uint16 _r, src_back = get_palette(0);
|
||||
if(p->bg_main && p->bg_sub) {
|
||||
if(p->color_exempt == false && regs.bg_color_enabled[p->bg_main & 0x7f] && sub_colorwindowtable[x]) {
|
||||
if(regs.addsub_mode) {
|
||||
_r = addsub_pixels(p->src_main, p->src_sub);
|
||||
} else {
|
||||
_r = addsub_pixel(p->src_main);
|
||||
}
|
||||
} else {
|
||||
_r = p->src_main;
|
||||
}
|
||||
} else if(p->bg_main) {
|
||||
if(p->color_exempt == false && regs.bg_color_enabled[p->bg_main & 0x7f] && sub_colorwindowtable[x]) {
|
||||
_r = addsub_pixel(p->src_main);
|
||||
} else {
|
||||
_r = p->src_main;
|
||||
}
|
||||
} else if(p->bg_sub) {
|
||||
if(regs.bg_color_enabled[BACK]) {
|
||||
if(sub_colorwindowtable[x]) {
|
||||
if(regs.addsub_mode) {
|
||||
_r = addsub_pixels(src_back, p->src_sub);
|
||||
} else {
|
||||
_r = addsub_pixel(src_back);
|
||||
}
|
||||
} else {
|
||||
_r = src_back;
|
||||
}
|
||||
} else {
|
||||
_r = 0x0000;
|
||||
}
|
||||
uint16 src_main, src_sub;
|
||||
uint8 bg_sub;
|
||||
src_main = p->src_main;
|
||||
|
||||
if(!regs.addsub_mode) {
|
||||
bg_sub = BACK;
|
||||
src_sub = regs.color_rgb;
|
||||
} else {
|
||||
if(main_colorwindowtable[x]) {
|
||||
if(regs.bg_color_enabled[BACK] && sub_colorwindowtable[x]) {
|
||||
_r = addsub_pixel(src_back);
|
||||
} else {
|
||||
_r = src_back;
|
||||
bg_sub = p->bg_sub;
|
||||
src_sub = p->src_sub;
|
||||
}
|
||||
|
||||
if(!window_cache[COL].main[x]) {
|
||||
if(!window_cache[COL].sub[x]) {
|
||||
return 0x0000;
|
||||
}
|
||||
src_main = 0x0000;
|
||||
}
|
||||
|
||||
if(!p->ce_main && regs.color_enabled[p->bg_main] && window_cache[COL].sub[x]) {
|
||||
bool halve = false;
|
||||
if(regs.color_halve && window_cache[COL].main[x]) {
|
||||
if(regs.addsub_mode && bg_sub == BACK);
|
||||
else {
|
||||
halve = true;
|
||||
}
|
||||
}
|
||||
return addsub_pixels(x, src_main, src_sub, halve);
|
||||
}
|
||||
|
||||
return src_main;
|
||||
}
|
||||
|
||||
inline uint16 bPPU::get_pixel_swap(uint32 x) {
|
||||
_pixel *p = &pixel_cache[x];
|
||||
uint16 src_main, src_sub;
|
||||
uint8 bg_sub;
|
||||
src_main = p->src_sub;
|
||||
|
||||
if(!regs.addsub_mode) {
|
||||
bg_sub = BACK;
|
||||
src_sub = regs.color_rgb;
|
||||
} else {
|
||||
bg_sub = p->bg_main;
|
||||
src_sub = p->src_main;
|
||||
}
|
||||
|
||||
if(!window_cache[COL].main[x]) {
|
||||
if(!window_cache[COL].sub[x]) {
|
||||
return 0x0000;
|
||||
}
|
||||
src_main = 0x0000;
|
||||
}
|
||||
|
||||
if(!p->ce_sub && regs.color_enabled[p->bg_sub] && window_cache[COL].sub[x]) {
|
||||
bool halve = false;
|
||||
if(regs.color_halve && window_cache[COL].main[x]) {
|
||||
if(regs.addsub_mode && bg_sub == BACK);
|
||||
else {
|
||||
halve = true;
|
||||
}
|
||||
} else {
|
||||
_r = 0x0000;
|
||||
}
|
||||
return addsub_pixels(x, src_main, src_sub, halve);
|
||||
}
|
||||
|
||||
return src_main;
|
||||
}
|
||||
|
||||
inline uint16 bPPU::get_pixel_lores(uint32 x) {
|
||||
return get_pixel_normal(x);
|
||||
}
|
||||
|
||||
inline uint16 bPPU::get_pixel_hires(uint32 x) {
|
||||
if(x & 1) {
|
||||
return get_pixel_normal(x >> 1);
|
||||
} else {
|
||||
return get_pixel_swap(x >> 1);
|
||||
}
|
||||
return _r;
|
||||
}
|
||||
|
||||
inline void bPPU::render_line_output() {
|
||||
int x;
|
||||
uint16 _r;
|
||||
uint16 *ptr;
|
||||
ptr = (uint16*)snes->get_ppu_output_handle();
|
||||
uint32 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 << 15);
|
||||
|
||||
if(_screen_width == 256) {
|
||||
if(!regs.pseudo_hires && !regs.hires) {
|
||||
for(x=0;x<256;x++) {
|
||||
_r = get_pixel(x);
|
||||
*ptr++ = *(ltable + _r);
|
||||
r = get_pixel_lores(x);
|
||||
*ptr++ = *(ltable + r);
|
||||
}
|
||||
} else {
|
||||
for(x=0;x<512;x++) {
|
||||
_r = get_pixel(x);
|
||||
*ptr++ = *(ltable + _r);
|
||||
r = get_pixel_hires(x);
|
||||
*ptr++ = *(ltable + r);
|
||||
}
|
||||
if(regs.pseudo_hires && !regs.hires) {
|
||||
ptr -= 512;
|
||||
for(x=0;x<256;x++) {
|
||||
*(ptr + x) = ((ptr[x << 1] & 0x7bde) >> 1) + ((ptr[(x << 1) + 1] & 0x7bde) >> 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,12 @@
|
||||
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;
|
||||
|
||||
//are layers disabled by user?
|
||||
if(render_enabled(bg, 0) == false)pri0_pos = 0;
|
||||
if(render_enabled(bg, 1) == false)pri1_pos = 0;
|
||||
//nothing to render?
|
||||
if(!pri0_pos && !pri1_pos);
|
||||
|
||||
int32 x, y;
|
||||
int32 a, b, c, d, cx, cy;
|
||||
int32 hofs, vofs;
|
||||
@@ -31,20 +37,21 @@ int32 tx, ty, tile, palette;
|
||||
cx = (int32(regs.m7x) << 19) >> 19;
|
||||
cy = (int32(regs.m7y) << 19) >> 19;
|
||||
hofs = (int32(regs.m7_hofs) << 19) >> 19;
|
||||
vofs = (int32(regs.m7_vofs + 1) << 19) >> 19;
|
||||
//+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 = main_windowtable[bg];
|
||||
uint8 *wt_sub = sub_windowtable[bg];
|
||||
uint8 *wt_main = window_cache[bg].main;
|
||||
uint8 *wt_sub = window_cache[bg].sub;
|
||||
|
||||
if(regs.mode7_vflip == true) {
|
||||
y = 255 - _y;
|
||||
y = 255 - line.y;
|
||||
} else {
|
||||
y = _y;
|
||||
y = line.y;
|
||||
}
|
||||
|
||||
uint16 *mtable_x, *mtable_y;
|
||||
@@ -119,29 +126,28 @@ int32 psy = ((c * CLIP(hofs - cx)) & ~63) + ((d * CLIP(vofs - cy)) & ~63) + ((d
|
||||
_x = x;
|
||||
}
|
||||
|
||||
if(main_colorwindowtable[_x]) {
|
||||
uint32 col;
|
||||
if(regs.direct_color == true && bg == BG1) {
|
||||
//direct color mode does not apply to bg2, as it is only 128 colors...
|
||||
col = get_direct_color(0, palette);
|
||||
} else {
|
||||
col = get_palette(palette);
|
||||
}
|
||||
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.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 = bg;
|
||||
pixel_cache[_x].src_main = col;
|
||||
pixel_cache[_x].ce_main = 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;
|
||||
}
|
||||
}
|
||||
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 = bg;
|
||||
pixel_cache[_x].src_sub = col;
|
||||
pixel_cache[_x].ce_sub = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,34 +218,57 @@ 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;
|
||||
|
||||
//are layers disabled by user?
|
||||
if(render_enabled(OAM, 0) == false)pri0_pos = 0;
|
||||
if(render_enabled(OAM, 1) == false)pri1_pos = 0;
|
||||
if(render_enabled(OAM, 2) == false)pri2_pos = 0;
|
||||
if(render_enabled(OAM, 3) == false)pri3_pos = 0;
|
||||
//nothing to render?
|
||||
if(!pri0_pos && !pri1_pos && !pri2_pos && !pri3_pos)return;
|
||||
|
||||
render_line_oam_lores(pri0_pos, pri1_pos, pri2_pos, pri3_pos);
|
||||
}
|
||||
|
||||
#define setpixel_main(x) \
|
||||
if(pixel_cache[x].pri_main < pri) { \
|
||||
pixel_cache[x].pri_main = pri; \
|
||||
pixel_cache[x].bg_main = OAM; \
|
||||
pixel_cache[x].src_main = get_palette(oam_line_pal[x]); \
|
||||
pixel_cache[x].ce_main = (oam_line_pal[x] < 192); \
|
||||
}
|
||||
#define setpixel_sub(x) \
|
||||
if(pixel_cache[x].pri_sub < pri) { \
|
||||
pixel_cache[x].pri_sub = pri; \
|
||||
pixel_cache[x].bg_sub = OAM; \
|
||||
pixel_cache[x].src_sub = get_palette(oam_line_pal[x]); \
|
||||
pixel_cache[x].ce_sub = (oam_line_pal[x] < 192); \
|
||||
}
|
||||
|
||||
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 = 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 = get_palette(oam_line_pal[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(bg_enabled == true && !wt_main[x]) { setpixel_main(x); }
|
||||
if(bgsub_enabled == true && !wt_sub[x]) { setpixel_sub(x); }
|
||||
}
|
||||
}
|
||||
|
||||
#undef setpixel_main
|
||||
#undef setpixel_sub
|
||||
@@ -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, 256);
|
||||
return;
|
||||
}
|
||||
if(mainscreen == false && regs.sub_window_enabled[bg] == false) {
|
||||
memset(wtbl, 0, 256);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
uint8 mask;
|
||||
if(mainscreen == true) {
|
||||
mask = regs.color_mask;
|
||||
} else {
|
||||
mask = regs.colorsub_mask;
|
||||
}
|
||||
|
||||
if(mask == 0) {
|
||||
//always
|
||||
memset(wtbl, 1, 256);
|
||||
return;
|
||||
}
|
||||
|
||||
if(mask == 3) {
|
||||
//never
|
||||
memset(wtbl, 0, 256);
|
||||
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,54 @@ bool r;
|
||||
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.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, 256);
|
||||
} else if(regs.window1_enabled[bg] == true && regs.window2_enabled[bg] == false) {
|
||||
if(regs.window1_invert[bg] == false) {
|
||||
for(x = 0; x < 256; 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 < 256; 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 < 256; 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 < 256; 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 < 256; 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 +111,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,148 +0,0 @@
|
||||
#define CLIP_10BIT_SIGNED(x) \
|
||||
((x) & ((1 << 10) - 1)) + (((((x) & (1 << 13)) ^ (1 << 13)) - (1 << 13)) >> 3)
|
||||
|
||||
#define CAST_WORDTOINT(x) \
|
||||
(int32)((((x) & 0x8000) ? ((x) | 0xffff0000) : ((x) & 0x00007fff)))
|
||||
|
||||
void bPPU::render_line_mode7(uint8 bg, uint8 pri0_pos, uint8 pri1_pos) {
|
||||
int32 x;
|
||||
int32 step_m7a, step_m7c, m7a, m7b, m7c, m7d;
|
||||
int32 hoffset, voffset;
|
||||
int32 centerx, centery;
|
||||
int32 xx, yy;
|
||||
int32 px, py;
|
||||
int32 tx, ty, tile, palette;
|
||||
uint8 layer_pos;
|
||||
if(regs.bg_enabled[bg] == false && regs.bgsub_enabled[bg] == false)return;
|
||||
|
||||
uint16 *mtable_x, *mtable_y;
|
||||
if(bg == BG1) {
|
||||
mtable_x = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? regs.mosaic_size : 0];
|
||||
mtable_y = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? regs.mosaic_size : 0];
|
||||
} else { //bg == BG2
|
||||
//Mode7 EXTBG BG2 uses BG1 mosaic enable to control vertical mosaic,
|
||||
//and BG2 mosaic enable to control horizontal mosaic...
|
||||
mtable_x = (uint16*)mosaic_table[(regs.mosaic_enabled[BG2] == true) ? regs.mosaic_size : 0];
|
||||
mtable_y = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? regs.mosaic_size : 0];
|
||||
}
|
||||
|
||||
hoffset = ((int32)regs.m7_hofs << 19) >> 19;
|
||||
voffset = ((int32)regs.m7_vofs << 19) >> 19;
|
||||
|
||||
centerx = ((int32)regs.m7x << 19) >> 19;
|
||||
centery = ((int32)regs.m7y << 19) >> 19;
|
||||
|
||||
if(regs.mode7_vflip == true) {
|
||||
yy = 255 - _y;
|
||||
} else {
|
||||
yy = _y;
|
||||
}
|
||||
yy = mtable_y[yy];
|
||||
yy += CLIP_10BIT_SIGNED(voffset - centery);
|
||||
|
||||
m7b = CAST_WORDTOINT(regs.m7b) * yy + (centerx << 8);
|
||||
m7d = CAST_WORDTOINT(regs.m7d) * yy + (centery << 8);
|
||||
|
||||
step_m7a = CAST_WORDTOINT(regs.m7a);
|
||||
step_m7c = CAST_WORDTOINT(regs.m7c);
|
||||
|
||||
xx = CLIP_10BIT_SIGNED(hoffset - centerx);
|
||||
|
||||
m7a = CAST_WORDTOINT(regs.m7a) * xx;
|
||||
m7c = CAST_WORDTOINT(regs.m7c) * xx;
|
||||
|
||||
int _pri, _x;
|
||||
bool _bg_enabled, _bgsub_enabled;
|
||||
_bg_enabled = regs.bg_enabled[bg];
|
||||
_bgsub_enabled = regs.bgsub_enabled[bg];
|
||||
|
||||
build_window_tables(bg);
|
||||
uint8 *wt_main = main_windowtable[bg];
|
||||
uint8 *wt_sub = sub_windowtable[bg];
|
||||
|
||||
for(x=0;x<256;x++) {
|
||||
px = ((m7a + step_m7a * mtable_x[x] + m7b) >> 8);
|
||||
py = ((m7c + step_m7c * mtable_x[x] + m7d) >> 8);
|
||||
|
||||
switch(regs.mode7_repeat) {
|
||||
case 0: //screen repitition outside of screen area
|
||||
case 1: //same as case 0
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
break;
|
||||
case 2: //palette color 0 outside of screen area
|
||||
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
|
||||
palette = 0;
|
||||
} else {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
}
|
||||
break;
|
||||
case 3: //character 0 repetition outside of screen area
|
||||
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
|
||||
tx = 0;
|
||||
ty = 0;
|
||||
} else {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
}
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
break;
|
||||
}
|
||||
|
||||
if(bg == BG1) {
|
||||
_pri = pri0_pos;
|
||||
} else {
|
||||
_pri = (palette >> 7) ? pri1_pos : pri0_pos;
|
||||
palette &= 0x7f;
|
||||
}
|
||||
|
||||
if(!palette)continue;
|
||||
|
||||
if(regs.mode7_hflip == true) {
|
||||
_x = 255 - x;
|
||||
} else {
|
||||
_x = x;
|
||||
}
|
||||
|
||||
if(main_colorwindowtable[_x]) {
|
||||
uint32 col;
|
||||
if(regs.direct_color == true && bg == BG1) {
|
||||
//direct color mode does not apply to bg2 as it is only 128 colors...
|
||||
col = get_direct_color(0, palette);
|
||||
} else {
|
||||
col = get_palette(palette);
|
||||
}
|
||||
|
||||
if(regs.bg_enabled[bg] == true && !wt_main[_x]) {
|
||||
if(pixel_cache[_x].pri_main < _pri) {
|
||||
pixel_cache[_x].pri_main = _pri;
|
||||
pixel_cache[_x].bg_main = 0x80 | bg;
|
||||
pixel_cache[_x].src_main = col;
|
||||
pixel_cache[_x].color_exempt = false;
|
||||
}
|
||||
}
|
||||
if(regs.bgsub_enabled[bg] == true && !wt_sub[_x]) {
|
||||
if(pixel_cache[_x].pri_sub < _pri) {
|
||||
pixel_cache[_x].pri_sub = _pri;
|
||||
pixel_cache[_x].bg_sub = 0x80 | bg;
|
||||
pixel_cache[_x].src_sub = col;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef CLIP_10BIT_SIGNED
|
||||
#undef CAST_WORDTOINT
|
||||
+39
-5
@@ -2,16 +2,50 @@
|
||||
|
||||
void PPU::get_scanline_info(scanline_info *info) {
|
||||
info->hires = scanline_is_hires();
|
||||
info->interlace = cpu->interlace();
|
||||
info->interlace = r_cpu->interlace();
|
||||
}
|
||||
|
||||
void PPU::set_frameskip(int fs) {}
|
||||
bool PPU::render_frame() { return true; }
|
||||
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;
|
||||
}
|
||||
|
||||
void PPU::power() {}
|
||||
|
||||
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 = 3;
|
||||
ppu2_version = 1;
|
||||
mmio = &mmio_unmapped;
|
||||
}
|
||||
|
||||
PPU::~PPU() {}
|
||||
PPU::~PPU() {
|
||||
zerofree(output);
|
||||
}
|
||||
+19
-7
@@ -1,5 +1,18 @@
|
||||
class PPU {
|
||||
public:
|
||||
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
|
||||
@@ -10,7 +23,6 @@ uint8 ppu1_version;
|
||||
//* reported by $213f
|
||||
uint8 ppu2_version;
|
||||
|
||||
int _y;
|
||||
MMIO *mmio;
|
||||
|
||||
struct scanline_info {
|
||||
@@ -32,12 +44,12 @@ struct scanline_info {
|
||||
virtual void run() = 0;
|
||||
virtual void scanline() = 0;
|
||||
virtual void render_scanline() = 0;
|
||||
virtual void frame() = 0;
|
||||
virtual void power() = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual void set_frameskip(int fs);
|
||||
virtual bool render_frame();
|
||||
virtual void frame();
|
||||
virtual void power();
|
||||
virtual void reset();
|
||||
virtual void enable_renderer(bool r);
|
||||
virtual bool renderer_enabled();
|
||||
|
||||
PPU();
|
||||
~PPU();
|
||||
virtual ~PPU();
|
||||
};
|
||||
@@ -6,7 +6,7 @@ uint32 FileReader::size() {
|
||||
//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 *FileReader::read(uint32 length) {
|
||||
uint8 *data;
|
||||
if(length == 0) {
|
||||
//read the entire file into RAM
|
||||
@@ -24,7 +24,7 @@ uint8 *data;
|
||||
memset(data, 0, length);
|
||||
if(fp)fread(data, 1, length, fp);
|
||||
}
|
||||
*buffer = data;
|
||||
return data;
|
||||
}
|
||||
|
||||
bool FileReader::open(char *fn) {
|
||||
|
||||
@@ -5,7 +5,7 @@ uint32 fsize;
|
||||
|
||||
public:
|
||||
uint32 size();
|
||||
void read(uint8 **buffer, uint32 length = 0);
|
||||
uint8 *read(uint32 length = 0);
|
||||
bool open(char *fn);
|
||||
void close();
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
uint32 GZReader::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.
|
||||
uint8 *GZReader::read(uint32 length) {
|
||||
uint8 *data;
|
||||
if(length == 0) {
|
||||
//read the entire file into RAM
|
||||
data = (uint8*)memalloc(fsize);
|
||||
memset(data, 0, fsize);
|
||||
if(gp)gzread(gp, data, fsize);
|
||||
} else if(length > fsize) {
|
||||
//read the entire file into RAM, pad the rest with 0x00s
|
||||
data = (uint8*)memalloc(length);
|
||||
memset(data, 0, length);
|
||||
if(gp)gzread(gp, data, fsize);
|
||||
} else { //fsize >= length
|
||||
//read only what was requested
|
||||
data = (uint8*)memalloc(length);
|
||||
memset(data, 0, length);
|
||||
if(gp)gzread(gp, data, length);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
bool GZReader::open(char *fn) {
|
||||
FILE *fp;
|
||||
fp = fopen(fn, "rb");
|
||||
if(!fp)return false;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
fsize = ftell(fp);
|
||||
|
||||
if(fsize < 4) {
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 gzsize;
|
||||
fseek(fp, -4, SEEK_END); //jump to 4 bytes before end
|
||||
gzsize = fgetc(fp);
|
||||
gzsize |= fgetc(fp) << 8;
|
||||
gzsize |= fgetc(fp) << 16;
|
||||
gzsize |= fgetc(fp) << 24;
|
||||
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
|
||||
gp = gzopen(fn, "rb");
|
||||
if(!gp)return false;
|
||||
|
||||
if(!gzdirect(gp)) {
|
||||
fsize = gzsize;
|
||||
}
|
||||
|
||||
//empty file?
|
||||
if(fsize == 0) {
|
||||
gzclose(gp);
|
||||
gp = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GZReader::close() {
|
||||
if(gp) {
|
||||
gzclose(gp);
|
||||
gp = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "zlib/zlib.h"
|
||||
|
||||
class GZReader : public Reader {
|
||||
private:
|
||||
gzFile gp;
|
||||
uint32 fsize;
|
||||
|
||||
public:
|
||||
uint32 size();
|
||||
uint8 *read(uint32 length = 0);
|
||||
bool open(char *fn);
|
||||
void close();
|
||||
|
||||
GZReader() { gp = 0; fsize = 0; }
|
||||
~GZReader() { if(gp)gzclose(gp); }
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
Copyright (C) 2005 NSRT Team ( http://nsrt.edgeemu.com )
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __7Z_H
|
||||
#define __7Z_H
|
||||
|
||||
#include "iiostrm.h"
|
||||
|
||||
bool decompress_lzma_7z(ISequentialInStream& in, unsigned in_size, ISequentialOutStream& out, unsigned out_size) throw ();
|
||||
bool decompress_lzma_7z(const unsigned char* in_data, unsigned in_size, unsigned char* out_data, unsigned out_size) throw ();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright (C) 2005 NSRT Team ( http://nsrt.edgeemu.com )
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "7z.h"
|
||||
|
||||
#include "lzmadec.h"
|
||||
|
||||
bool decompress_lzma_7z(ISequentialInStream& in, unsigned in_size, ISequentialOutStream& out, unsigned out_size) throw ()
|
||||
{
|
||||
try
|
||||
{
|
||||
NCompress::NLZMA::CDecoder cc;
|
||||
|
||||
UINT64 in_size_l = in_size;
|
||||
UINT64 out_size_l = out_size;
|
||||
|
||||
if (cc.ReadCoderProperties(&in) != S_OK) { return(false); }
|
||||
if (cc.Code(&in, &out, &in_size_l, &out_size_l) != S_OK) { return(false); }
|
||||
if (out.size_get() != out_size || out.overflow_get()) { return(false); }
|
||||
|
||||
return(true);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool decompress_lzma_7z(const unsigned char* in_data, unsigned int in_size, unsigned char* out_data, unsigned int out_size) throw ()
|
||||
{
|
||||
ISequentialInStream_Array in(reinterpret_cast<const char*>(in_data), in_size);
|
||||
ISequentialOutStream_Array out(reinterpret_cast<char*>(out_data), out_size);
|
||||
|
||||
return(decompress_lzma_7z(in, in_size, out, out_size));
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
#ifndef __COMPRESSION_BITCODER_H
|
||||
#define __COMPRESSION_BITCODER_H
|
||||
|
||||
#include "rngcoder.h"
|
||||
|
||||
namespace NCompression {
|
||||
namespace NArithmetic {
|
||||
|
||||
const int kNumBitModelTotalBits = 11;
|
||||
const UINT32 kBitModelTotal = (1 << kNumBitModelTotalBits);
|
||||
|
||||
const int kNumMoveReducingBits = 2;
|
||||
|
||||
/////////////////////////////
|
||||
// CBitModel
|
||||
|
||||
template <int aNumMoveBits>
|
||||
class CBitModel
|
||||
{
|
||||
public:
|
||||
UINT32 m_Probability;
|
||||
void UpdateModel(UINT32 aSymbol)
|
||||
{
|
||||
/*
|
||||
m_Probability -= (m_Probability + ((aSymbol - 1) & ((1 << aNumMoveBits) - 1))) >> aNumMoveBits;
|
||||
m_Probability += (1 - aSymbol) << (kNumBitModelTotalBits - aNumMoveBits);
|
||||
*/
|
||||
if (aSymbol == 0)
|
||||
m_Probability += (kBitModelTotal - m_Probability) >> aNumMoveBits;
|
||||
else
|
||||
m_Probability -= (m_Probability) >> aNumMoveBits;
|
||||
}
|
||||
public:
|
||||
void Init() { m_Probability = kBitModelTotal / 2; }
|
||||
};
|
||||
|
||||
template <int aNumMoveBits>
|
||||
class CBitDecoder: public CBitModel<aNumMoveBits>
|
||||
{
|
||||
public:
|
||||
UINT32 Decode(CRangeDecoder *aRangeDecoder)
|
||||
{
|
||||
UINT32 aNewBound = (aRangeDecoder->m_Range >> kNumBitModelTotalBits) * CBitModel<aNumMoveBits>::m_Probability;
|
||||
if (aRangeDecoder->m_Code < aNewBound)
|
||||
{
|
||||
aRangeDecoder->m_Range = aNewBound;
|
||||
CBitModel<aNumMoveBits>::m_Probability += (kBitModelTotal - CBitModel<aNumMoveBits>::m_Probability) >> aNumMoveBits;
|
||||
if (aRangeDecoder->m_Range < kTopValue)
|
||||
{
|
||||
aRangeDecoder->m_Code = (aRangeDecoder->m_Code << 8) | aRangeDecoder->m_Stream.ReadByte();
|
||||
aRangeDecoder->m_Range <<= 8;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
aRangeDecoder->m_Range -= aNewBound;
|
||||
aRangeDecoder->m_Code -= aNewBound;
|
||||
CBitModel<aNumMoveBits>::m_Probability -= (CBitModel<aNumMoveBits>::m_Probability) >> aNumMoveBits;
|
||||
if (aRangeDecoder->m_Range < kTopValue)
|
||||
{
|
||||
aRangeDecoder->m_Code = (aRangeDecoder->m_Code << 8) | aRangeDecoder->m_Stream.ReadByte();
|
||||
aRangeDecoder->m_Range <<= 8;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org )
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __ARICONST_H
|
||||
#define __ARICONST_H
|
||||
|
||||
#include "aribitcd.h"
|
||||
|
||||
|
||||
typedef NCompression::NArithmetic::CRangeDecoder CMyRangeDecoder;
|
||||
template <int aNumMoveBits> class CMyBitDecoder:
|
||||
public NCompression::NArithmetic::CBitDecoder<aNumMoveBits> {};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef __COMPRESSION_ARIPRICE_H
|
||||
#define __COMPRESSION_ARIPRICE_H
|
||||
|
||||
namespace NCompression {
|
||||
namespace NArithmetic {
|
||||
|
||||
const UINT32 kNumBitPriceShiftBits = 6;
|
||||
const UINT32 kBitPrice = 1 << kNumBitPriceShiftBits;
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org )
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __BITTREECODER_H
|
||||
#define __BITTREECODER_H
|
||||
|
||||
#include "aribitcd.h"
|
||||
#include "rcdefs.h"
|
||||
|
||||
|
||||
//////////////////////////
|
||||
// CBitTreeDecoder
|
||||
|
||||
template <int aNumMoveBits, UINT32 m_NumBitLevels>
|
||||
class CBitTreeDecoder
|
||||
{
|
||||
CMyBitDecoder<aNumMoveBits> m_Models[1 << m_NumBitLevels];
|
||||
public:
|
||||
void Init()
|
||||
{
|
||||
for(UINT32 i = 1; i < (1 << m_NumBitLevels); i++)
|
||||
m_Models[i].Init();
|
||||
}
|
||||
UINT32 Decode(CMyRangeDecoder *aRangeDecoder)
|
||||
{
|
||||
UINT32 aModelIndex = 1;
|
||||
RC_INIT_VAR
|
||||
for(UINT32 aBitIndex = m_NumBitLevels; aBitIndex > 0; aBitIndex--)
|
||||
{
|
||||
// aModelIndex = (aModelIndex << 1) + m_Models[aModelIndex].Decode(aRangeDecoder);
|
||||
RC_GETBIT(aNumMoveBits, m_Models[aModelIndex].m_Probability, aModelIndex)
|
||||
}
|
||||
RC_FLUSH_VAR
|
||||
return aModelIndex - (1 << m_NumBitLevels);
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
// CReverseBitTreeDecoder
|
||||
|
||||
template <int aNumMoveBits>
|
||||
class CReverseBitTreeDecoder2
|
||||
{
|
||||
CMyBitDecoder<aNumMoveBits> *m_Models;
|
||||
UINT32 m_NumBitLevels;
|
||||
public:
|
||||
CReverseBitTreeDecoder2(): m_Models(0) { }
|
||||
~CReverseBitTreeDecoder2() { delete []m_Models; }
|
||||
bool Create(UINT32 aNumBitLevels)
|
||||
{
|
||||
m_NumBitLevels = aNumBitLevels;
|
||||
m_Models = new CMyBitDecoder<aNumMoveBits>[1 << aNumBitLevels];
|
||||
return (m_Models != 0);
|
||||
}
|
||||
void Init()
|
||||
{
|
||||
UINT32 aNumModels = 1 << m_NumBitLevels;
|
||||
for(UINT32 i = 1; i < aNumModels; i++)
|
||||
m_Models[i].Init();
|
||||
}
|
||||
UINT32 Decode(CMyRangeDecoder *aRangeDecoder)
|
||||
{
|
||||
UINT32 aModelIndex = 1;
|
||||
UINT32 aSymbol = 0;
|
||||
RC_INIT_VAR
|
||||
for(UINT32 aBitIndex = 0; aBitIndex < m_NumBitLevels; aBitIndex++)
|
||||
{
|
||||
// UINT32 aBit = m_Models[aModelIndex].Decode(aRangeDecoder);
|
||||
// aModelIndex <<= 1;
|
||||
// aModelIndex += aBit;
|
||||
// aSymbol |= (aBit << aBitIndex);
|
||||
RC_GETBIT2(aNumMoveBits, m_Models[aModelIndex].m_Probability, aModelIndex, ; , aSymbol |= (1 << aBitIndex))
|
||||
}
|
||||
RC_FLUSH_VAR
|
||||
return aSymbol;
|
||||
};
|
||||
};
|
||||
////////////////////////////
|
||||
// CReverseBitTreeDecoder2
|
||||
|
||||
template <int aNumMoveBits, UINT32 m_NumBitLevels>
|
||||
class CReverseBitTreeDecoder
|
||||
{
|
||||
CMyBitDecoder<aNumMoveBits> m_Models[1 << m_NumBitLevels];
|
||||
public:
|
||||
void Init()
|
||||
{
|
||||
for(UINT32 i = 1; i < (1 << m_NumBitLevels); i++)
|
||||
m_Models[i].Init();
|
||||
}
|
||||
UINT32 Decode(CMyRangeDecoder *aRangeDecoder)
|
||||
{
|
||||
UINT32 aModelIndex = 1;
|
||||
UINT32 aSymbol = 0;
|
||||
RC_INIT_VAR
|
||||
for(UINT32 aBitIndex = 0; aBitIndex < m_NumBitLevels; aBitIndex++)
|
||||
{
|
||||
// UINT32 aBit = m_Models[aModelIndex].Decode(aRangeDecoder);
|
||||
// aModelIndex <<= 1;
|
||||
// aModelIndex += aBit;
|
||||
// aSymbol |= (aBit << aBitIndex);
|
||||
RC_GETBIT2(aNumMoveBits, m_Models[aModelIndex].m_Probability, aModelIndex, ; , aSymbol |= (1 << aBitIndex))
|
||||
}
|
||||
RC_FLUSH_VAR
|
||||
return aSymbol;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
Copyright (C) 2004 NSRT Team ( http://nsrt.edgeemu.com )
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef CRC32_H
|
||||
#define CRC32_H
|
||||
|
||||
namespace CRC32lib
|
||||
{
|
||||
unsigned int CRC32(const unsigned char *, size_t, register unsigned int crc32 = 0xFFFFFFFF);
|
||||
unsigned short SUM_CRC32(const unsigned char *, size_t, unsigned int &crc32);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
Copyright (C) 2005 NSRT Team ( http://nsrt.edgeemu.com )
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org )
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
#include "iiostrm.h"
|
||||
#include "crc32.h"
|
||||
|
||||
HRESULT ISequentialInStream_Array::Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize)
|
||||
{
|
||||
if (aSize > size)
|
||||
{
|
||||
aSize = size;
|
||||
}
|
||||
|
||||
*aProcessedSize = aSize;
|
||||
memcpy(aData, data, aSize);
|
||||
size -= aSize;
|
||||
data += aSize;
|
||||
return(S_OK);
|
||||
}
|
||||
|
||||
HRESULT ISequentialOutStream_Array::Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize)
|
||||
{
|
||||
if (aSize > size)
|
||||
{
|
||||
overflow = true;
|
||||
aSize = size;
|
||||
}
|
||||
|
||||
*aProcessedSize = aSize;
|
||||
memcpy(data, aData, aSize);
|
||||
size -= aSize;
|
||||
data += aSize;
|
||||
total += aSize;
|
||||
return(S_OK);
|
||||
}
|
||||
|
||||
HRESULT ISequentialInStream_String::Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize)
|
||||
{
|
||||
if (aSize > data.size())
|
||||
{
|
||||
aSize = data.size();
|
||||
}
|
||||
|
||||
*aProcessedSize = aSize;
|
||||
memcpy(aData, data.c_str(), aSize);
|
||||
data.erase(0, aSize);
|
||||
return(S_OK);
|
||||
}
|
||||
|
||||
HRESULT ISequentialOutStream_String::Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize)
|
||||
{
|
||||
*aProcessedSize = aSize;
|
||||
data.append((const char *)aData, aSize);
|
||||
total += aSize;
|
||||
return(S_OK);
|
||||
}
|
||||
|
||||
HRESULT ISequentialInStream_Istream::Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize)
|
||||
{
|
||||
data.read((char *)aData, aSize);
|
||||
*aProcessedSize = data.gcount();
|
||||
return(S_OK);
|
||||
}
|
||||
|
||||
HRESULT ISequentialOutStream_Ostream::Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize)
|
||||
{
|
||||
*aProcessedSize = aSize;
|
||||
data.write((char *)aData, aSize);
|
||||
total += aSize;
|
||||
return(S_OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
HRESULT ISequentialInStreamCRC32_Array::Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize)
|
||||
{
|
||||
ISequentialInStream_Array::Read(aData, aSize, aProcessedSize);
|
||||
crc32 = CRC32lib::CRC32((const unsigned char *)aData, *aProcessedSize, ~crc32);
|
||||
return(S_OK);
|
||||
}
|
||||
|
||||
HRESULT ISequentialOutStreamCRC32_Array::Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize)
|
||||
{
|
||||
ISequentialOutStream_Array::Write(aData, aSize, aProcessedSize);
|
||||
crc32 = CRC32lib::CRC32((const unsigned char *)aData, *aProcessedSize, ~crc32);
|
||||
return(S_OK);
|
||||
}
|
||||
|
||||
HRESULT ISequentialInStreamCRC32_String::Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize)
|
||||
{
|
||||
ISequentialInStream_String::Read(aData, aSize, aProcessedSize);
|
||||
crc32 = CRC32lib::CRC32((const unsigned char *)aData, *aProcessedSize, ~crc32);
|
||||
return(S_OK);
|
||||
}
|
||||
|
||||
HRESULT ISequentialOutStreamCRC32_String::Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize)
|
||||
{
|
||||
ISequentialOutStream_String::Write(aData, aSize, aProcessedSize);
|
||||
crc32 = CRC32lib::CRC32((const unsigned char *)aData, *aProcessedSize, ~crc32);
|
||||
return(S_OK);
|
||||
}
|
||||
|
||||
HRESULT ISequentialInStreamCRC32_Istream::Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize)
|
||||
{
|
||||
ISequentialInStream_Istream::Read(aData, aSize, aProcessedSize);
|
||||
crc32 = CRC32lib::CRC32((const unsigned char *)aData, *aProcessedSize, ~crc32);
|
||||
return(S_OK);
|
||||
}
|
||||
|
||||
HRESULT ISequentialOutStreamCRC32_Ostream::Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize)
|
||||
{
|
||||
ISequentialOutStream_Ostream::Write(aData, aSize, aProcessedSize);
|
||||
crc32 = CRC32lib::CRC32((const unsigned char *)aData, *aProcessedSize, ~crc32);
|
||||
return(S_OK);
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
Copyright (C) 2005 NSRT Team ( http://nsrt.edgeemu.com )
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org )
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __IINOUTSTREAMS_H
|
||||
#define __IINOUTSTREAMS_H
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
|
||||
class ISequentialInStream
|
||||
{
|
||||
public:
|
||||
virtual HRESULT Read(void *, UINT32, UINT32 *) = 0;
|
||||
|
||||
virtual ~ISequentialInStream() {}
|
||||
};
|
||||
|
||||
|
||||
class ISequentialInStream_Array : public ISequentialInStream
|
||||
{
|
||||
const char *data;
|
||||
unsigned int size;
|
||||
public:
|
||||
ISequentialInStream_Array(const char *Adata, unsigned Asize) : data(Adata), size(Asize) { }
|
||||
|
||||
HRESULT Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize);
|
||||
|
||||
virtual ~ISequentialInStream_Array() {}
|
||||
};
|
||||
|
||||
class ISequentialInStream_String : public ISequentialInStream
|
||||
{
|
||||
std::string& data;
|
||||
public:
|
||||
ISequentialInStream_String(std::string& Adata) : data(Adata) { }
|
||||
|
||||
HRESULT Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize);
|
||||
|
||||
virtual ~ISequentialInStream_String() {}
|
||||
};
|
||||
|
||||
class ISequentialInStream_Istream : public ISequentialInStream
|
||||
{
|
||||
std::istream& data;
|
||||
public:
|
||||
ISequentialInStream_Istream(std::istream& Adata) : data(Adata) { }
|
||||
|
||||
HRESULT Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize);
|
||||
|
||||
virtual ~ISequentialInStream_Istream() {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class ISequentialOutStream
|
||||
{
|
||||
public:
|
||||
virtual bool overflow_get() const = 0;
|
||||
virtual unsigned int size_get() const = 0;
|
||||
|
||||
virtual HRESULT Write(const void *, UINT32, UINT32 *) = 0;
|
||||
|
||||
virtual ~ISequentialOutStream() {}
|
||||
};
|
||||
|
||||
|
||||
class ISequentialOutStream_Array : public ISequentialOutStream
|
||||
{
|
||||
char *data;
|
||||
unsigned int size;
|
||||
bool overflow;
|
||||
unsigned int total;
|
||||
public:
|
||||
ISequentialOutStream_Array(char *Adata, unsigned Asize) : data(Adata), size(Asize), overflow(false), total(0) { }
|
||||
|
||||
bool overflow_get() const { return(overflow); }
|
||||
unsigned int size_get() const { return(total); }
|
||||
|
||||
HRESULT Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize);
|
||||
|
||||
virtual ~ISequentialOutStream_Array() {}
|
||||
};
|
||||
|
||||
class ISequentialOutStream_String : public ISequentialOutStream
|
||||
{
|
||||
std::string& data;
|
||||
unsigned int total;
|
||||
public:
|
||||
ISequentialOutStream_String(std::string& Adata) : data(Adata), total(0) { }
|
||||
|
||||
bool overflow_get() const { return(false); }
|
||||
unsigned int size_get() const { return(total); }
|
||||
|
||||
HRESULT Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize);
|
||||
|
||||
virtual ~ISequentialOutStream_String() {}
|
||||
};
|
||||
|
||||
|
||||
class ISequentialOutStream_Ostream : public ISequentialOutStream
|
||||
{
|
||||
std::ostream& data;
|
||||
unsigned int total;
|
||||
public:
|
||||
ISequentialOutStream_Ostream(std::ostream& Adata) : data(Adata), total(0) { }
|
||||
|
||||
bool overflow_get() const { return(false); }
|
||||
unsigned int size_get() const { return(total); }
|
||||
|
||||
HRESULT Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize);
|
||||
|
||||
virtual ~ISequentialOutStream_Ostream() {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class ISequentialStreamCRC32
|
||||
{
|
||||
protected:
|
||||
unsigned int crc32;
|
||||
public:
|
||||
ISequentialStreamCRC32() : crc32(0) {}
|
||||
unsigned int crc32_get() const { return(crc32); }
|
||||
|
||||
virtual ~ISequentialStreamCRC32() {}
|
||||
};
|
||||
|
||||
|
||||
class ISequentialInStreamCRC32_Array : public ISequentialInStream_Array, public ISequentialStreamCRC32
|
||||
{
|
||||
public:
|
||||
ISequentialInStreamCRC32_Array(const char *Adata, unsigned Asize) : ISequentialInStream_Array(Adata, Asize) { }
|
||||
|
||||
HRESULT Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize);
|
||||
|
||||
virtual ~ISequentialInStreamCRC32_Array() {}
|
||||
};
|
||||
|
||||
class ISequentialInStreamCRC32_String : public ISequentialInStream_String, public ISequentialStreamCRC32
|
||||
{
|
||||
public:
|
||||
ISequentialInStreamCRC32_String(std::string& Adata) : ISequentialInStream_String(Adata) { }
|
||||
|
||||
HRESULT Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize);
|
||||
|
||||
virtual ~ISequentialInStreamCRC32_String() {}
|
||||
};
|
||||
|
||||
class ISequentialInStreamCRC32_Istream : public ISequentialInStream_Istream, public ISequentialStreamCRC32
|
||||
{
|
||||
public:
|
||||
ISequentialInStreamCRC32_Istream(std::istream& Adata) : ISequentialInStream_Istream(Adata) { }
|
||||
|
||||
HRESULT Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize);
|
||||
|
||||
virtual ~ISequentialInStreamCRC32_Istream() {}
|
||||
};
|
||||
|
||||
|
||||
class ISequentialOutStreamCRC32_Array : public ISequentialOutStream_Array, public ISequentialStreamCRC32
|
||||
{
|
||||
public:
|
||||
ISequentialOutStreamCRC32_Array(char *Adata, unsigned Asize) : ISequentialOutStream_Array(Adata, Asize) { }
|
||||
|
||||
HRESULT Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize);
|
||||
|
||||
virtual ~ISequentialOutStreamCRC32_Array() {}
|
||||
};
|
||||
|
||||
class ISequentialOutStreamCRC32_String : public ISequentialOutStream_String, public ISequentialStreamCRC32
|
||||
{
|
||||
public:
|
||||
ISequentialOutStreamCRC32_String(std::string& Adata) : ISequentialOutStream_String(Adata) { }
|
||||
|
||||
HRESULT Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize);
|
||||
|
||||
virtual ~ISequentialOutStreamCRC32_String() {}
|
||||
};
|
||||
|
||||
|
||||
class ISequentialOutStreamCRC32_Ostream : public ISequentialOutStream_Ostream, public ISequentialStreamCRC32
|
||||
{
|
||||
public:
|
||||
ISequentialOutStreamCRC32_Ostream(std::ostream& Adata) : ISequentialOutStream_Ostream(Adata) { }
|
||||
|
||||
HRESULT Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize);
|
||||
|
||||
virtual ~ISequentialOutStreamCRC32_Ostream() {}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright (C) 2005 NSRT Team ( http://nsrt.edgeemu.com )
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org )
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "inbyte.h"
|
||||
|
||||
namespace NStream{
|
||||
|
||||
CInByte::CInByte(UINT32 aBufferSize):
|
||||
m_BufferBase(0),
|
||||
m_BufferSize(aBufferSize)
|
||||
{
|
||||
m_BufferBase = new BYTE[m_BufferSize];
|
||||
}
|
||||
|
||||
CInByte::~CInByte()
|
||||
{
|
||||
delete []m_BufferBase;
|
||||
}
|
||||
|
||||
void CInByte::Init(ISequentialInStream *aStream)
|
||||
{
|
||||
m_Stream = aStream;
|
||||
m_ProcessedSize = 0;
|
||||
m_Buffer = m_BufferBase;
|
||||
m_BufferLimit = m_Buffer;
|
||||
m_StreamWasExhausted = false;
|
||||
}
|
||||
|
||||
bool CInByte::ReadBlock()
|
||||
{
|
||||
if (m_StreamWasExhausted)
|
||||
return false;
|
||||
m_ProcessedSize += (m_Buffer - m_BufferBase);
|
||||
UINT32 aNumProcessedBytes;
|
||||
HRESULT aResult = m_Stream->Read(m_BufferBase, m_BufferSize, &aNumProcessedBytes);
|
||||
if (aResult != S_OK)
|
||||
throw aResult;
|
||||
m_Buffer = m_BufferBase;
|
||||
m_BufferLimit = m_Buffer + aNumProcessedBytes;
|
||||
m_StreamWasExhausted = (aNumProcessedBytes == 0);
|
||||
return (!m_StreamWasExhausted);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org )
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __STREAM_INBYTE_H
|
||||
#define __STREAM_INBYTE_H
|
||||
|
||||
#include "iiostrm.h"
|
||||
|
||||
namespace NStream {
|
||||
|
||||
class CInByte
|
||||
{
|
||||
UINT64 m_ProcessedSize;
|
||||
BYTE *m_BufferBase;
|
||||
UINT32 m_BufferSize;
|
||||
BYTE *m_Buffer;
|
||||
BYTE *m_BufferLimit;
|
||||
ISequentialInStream* m_Stream;
|
||||
bool m_StreamWasExhausted;
|
||||
|
||||
bool ReadBlock();
|
||||
|
||||
public:
|
||||
CInByte(UINT32 aBufferSize = 0x100000);
|
||||
~CInByte();
|
||||
|
||||
void Init(ISequentialInStream *aStream);
|
||||
|
||||
bool ReadByte(BYTE &aByte)
|
||||
{
|
||||
if(m_Buffer >= m_BufferLimit)
|
||||
if(!ReadBlock())
|
||||
return false;
|
||||
aByte = *m_Buffer++;
|
||||
return true;
|
||||
}
|
||||
BYTE ReadByte()
|
||||
{
|
||||
if(m_Buffer >= m_BufferLimit)
|
||||
if(!ReadBlock())
|
||||
return 0x0;
|
||||
return *m_Buffer++;
|
||||
}
|
||||
void ReadBytes(void *aData, UINT32 aSize, UINT32 &aProcessedSize)
|
||||
{
|
||||
for(aProcessedSize = 0; aProcessedSize < aSize; aProcessedSize++)
|
||||
if (!ReadByte(((BYTE *)aData)[aProcessedSize]))
|
||||
return;
|
||||
}
|
||||
bool ReadBytes(void *aData, UINT32 aSize)
|
||||
{
|
||||
UINT32 aProcessedSize;
|
||||
ReadBytes(aData, aSize, aProcessedSize);
|
||||
return (aProcessedSize == aSize);
|
||||
}
|
||||
UINT64 GetProcessedSize() const { return m_ProcessedSize + (m_Buffer - m_BufferBase); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright (C) 2004 NSRT Team ( http://nsrt.edgeemu.com )
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace CRC32lib
|
||||
{
|
||||
//Don't ask questions, this is the PKZip CRC32 table
|
||||
const unsigned int crc32Table[256] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d };
|
||||
|
||||
|
||||
//CRC32 for char arrays
|
||||
unsigned int CRC32(const unsigned char *array, size_t size, register unsigned int crc32)
|
||||
{
|
||||
const unsigned char *end_p = array+size;
|
||||
for (register const unsigned char *p = array; p < end_p; p++)
|
||||
{
|
||||
crc32 = ((crc32 >> 8) & 0x00FFFFFF) ^ crc32Table[(crc32 ^ *p) & 0xFF];
|
||||
}
|
||||
|
||||
return(~crc32);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,552 @@
|
||||
/*
|
||||
Copyright (C) 2005 NSRT Team ( http://nsrt.edgeemu.com )
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
#include "jma.h"
|
||||
using namespace std;
|
||||
|
||||
#include "portable.h"
|
||||
#include "7z.h"
|
||||
#include "crc32.h"
|
||||
|
||||
namespace JMA
|
||||
{
|
||||
const char jma_magic[] = { 'J', 'M', 'A', 0, 'N' };
|
||||
const unsigned int jma_header_length = 5;
|
||||
const unsigned char jma_version = 1;
|
||||
const unsigned int jma_version_length = 1;
|
||||
const unsigned int jma_total_header_length = jma_header_length + jma_version_length + UINT_SIZE;
|
||||
|
||||
//Convert DOS/zip/JMA integer time to to time_t
|
||||
time_t uint_to_time(unsigned short date, unsigned short time)
|
||||
{
|
||||
tm formatted_time;
|
||||
|
||||
formatted_time.tm_mday = date & 0x1F;
|
||||
formatted_time.tm_mon = ((date >> 5) & 0xF) - 1;
|
||||
formatted_time.tm_year = ((date >> 9) & 0x7f) + 80;
|
||||
formatted_time.tm_sec = (time & 0x1F) * 2;
|
||||
formatted_time.tm_min = (time >> 5) & 0x3F;
|
||||
formatted_time.tm_hour = (time >> 11) & 0x1F;
|
||||
|
||||
return(mktime(&formatted_time));
|
||||
}
|
||||
|
||||
|
||||
//Retreive the file block, what else?
|
||||
void jma_open::retrieve_file_block() throw(jma_errors)
|
||||
{
|
||||
unsigned char uint_buffer[UINT_SIZE];
|
||||
unsigned char ushort_buffer[USHORT_SIZE];
|
||||
|
||||
//File block size is the last UINT in the file
|
||||
stream.seekg(-UINT_SIZE,ios::end);
|
||||
stream.read((char *)uint_buffer, UINT_SIZE);
|
||||
size_t file_block_size = charp_to_uint(uint_buffer);
|
||||
|
||||
//Currently at the end of the file, so that's the file size
|
||||
size_t jma_file_size = stream.tellg();
|
||||
|
||||
//The file block can't be larger than the JMA file without it's header.
|
||||
//This if can probably be improved
|
||||
if (file_block_size >= jma_file_size-jma_total_header_length)
|
||||
{
|
||||
throw(JMA_BAD_FILE);
|
||||
}
|
||||
|
||||
//Seek to before file block so we can read the file block
|
||||
stream.seekg(-((int)file_block_size+UINT_SIZE),ios::end);
|
||||
|
||||
//This is needed if the file block is compressed
|
||||
stringstream decompressed_file_block;
|
||||
//Pointer to where to read file block from (file or decompressed buffer)
|
||||
istream *file_block_stream;
|
||||
|
||||
//Setup file info buffer and byte to read with
|
||||
jma_file_info file_info;
|
||||
char byte;
|
||||
|
||||
stream.get(byte);
|
||||
if (!byte) //If file block is compressed
|
||||
{
|
||||
//Compressed size isn't counting the byte we just read or the UINT for compressed size
|
||||
size_t compressed_size = file_block_size - (1+UINT_SIZE);
|
||||
|
||||
//Read decompressed size / true file block size
|
||||
stream.read((char *)uint_buffer, UINT_SIZE);
|
||||
file_block_size = charp_to_uint(uint_buffer);
|
||||
|
||||
//Setup access methods for decompression
|
||||
ISequentialInStream_Istream compressed_data(stream);
|
||||
ISequentialOutStream_Ostream decompressed_data(decompressed_file_block);
|
||||
|
||||
//Decompress the data
|
||||
if (!decompress_lzma_7z(compressed_data, compressed_size, decompressed_data, file_block_size))
|
||||
{
|
||||
throw(JMA_DECOMPRESS_FAILED);
|
||||
}
|
||||
|
||||
//Go to beginning, setup pointer to buffer
|
||||
decompressed_file_block.seekg(0, ios::beg);
|
||||
file_block_stream = &decompressed_file_block;
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.putback(byte); //Putback byte, byte is part of filename, not compressed indicator
|
||||
file_block_stream = &stream;
|
||||
}
|
||||
|
||||
|
||||
//Minimum file name length is 2 bytes, a char and a null
|
||||
//Minimum comment length is 1 byte, a null
|
||||
//There are currently 2 UINTs and 2 USHORTs per file
|
||||
while (file_block_size >= 2+1+UINT_SIZE*2+USHORT_SIZE*2) //This does allow for a gap, but that's okay
|
||||
{
|
||||
//First stored in the file block is the file name null terminated
|
||||
file_info.name = "";
|
||||
|
||||
file_block_stream->get(byte);
|
||||
while (byte)
|
||||
{
|
||||
file_info.name += byte;
|
||||
file_block_stream->get(byte);
|
||||
}
|
||||
|
||||
//There must be a file name or the file is bad
|
||||
if (!file_info.name.length())
|
||||
{
|
||||
throw(JMA_BAD_FILE);
|
||||
}
|
||||
|
||||
//Same trick as above for the comment
|
||||
file_info.comment = "";
|
||||
|
||||
file_block_stream->get(byte);
|
||||
while (byte)
|
||||
{
|
||||
file_info.comment += byte;
|
||||
file_block_stream->get(byte);
|
||||
}
|
||||
|
||||
//Next is a UINT representing the file's size
|
||||
file_block_stream->read((char *)uint_buffer, UINT_SIZE);
|
||||
file_info.size = charp_to_uint(uint_buffer);
|
||||
|
||||
//Followed by CRC32
|
||||
file_block_stream->read((char *)uint_buffer, UINT_SIZE);
|
||||
file_info.crc32 = charp_to_uint(uint_buffer);
|
||||
|
||||
//Special USHORT representation of file's date
|
||||
file_block_stream->read((char *)ushort_buffer, USHORT_SIZE);
|
||||
file_info.date = charp_to_ushort(ushort_buffer);
|
||||
|
||||
//Special USHORT representation of file's time
|
||||
file_block_stream->read((char *)ushort_buffer, USHORT_SIZE);
|
||||
file_info.time = charp_to_ushort(ushort_buffer);
|
||||
|
||||
file_info.buffer = 0; //Pointing to null till we decompress files
|
||||
|
||||
files.push_back(file_info); //Put file info into our structure
|
||||
|
||||
//Subtract size of the file info we just read
|
||||
file_block_size -= file_info.name.length()+file_info.comment.length()+2+UINT_SIZE*2+USHORT_SIZE*2;
|
||||
}
|
||||
}
|
||||
|
||||
//Constructor for opening JMA files for reading
|
||||
jma_open::jma_open(const char *compressed_file_name) throw (jma_errors)
|
||||
{
|
||||
decompressed_buffer = 0;
|
||||
compressed_buffer = 0;
|
||||
|
||||
stream.open(compressed_file_name, ios::in | ios::binary);
|
||||
if (!stream.is_open())
|
||||
{
|
||||
throw(JMA_NO_OPEN);
|
||||
}
|
||||
|
||||
//Header is "JMA\0N"
|
||||
unsigned char header[jma_header_length];
|
||||
stream.read((char *)header, jma_header_length);
|
||||
if (memcmp(jma_magic, header, jma_header_length))
|
||||
{
|
||||
throw(JMA_BAD_FILE);
|
||||
}
|
||||
|
||||
//Not the cleanest code but logical
|
||||
stream.read((char *)header, 5);
|
||||
if (*header <= jma_version)
|
||||
{
|
||||
chunk_size = charp_to_uint(header+1); //Chunk size is a UINT that follows version #
|
||||
retrieve_file_block();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw(JMA_UNSUPPORTED_VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
//Destructor only has to close the stream if neccesary
|
||||
jma_open::~jma_open()
|
||||
{
|
||||
if (stream.is_open())
|
||||
{
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
|
||||
//Return a vector containing useful info about the files in the JMA
|
||||
vector<jma_public_file_info> jma_open::get_files_info()
|
||||
{
|
||||
vector<jma_public_file_info> file_info_vector;
|
||||
jma_public_file_info file_info;
|
||||
|
||||
for (vector<jma_file_info>::iterator i = files.begin(); i != files.end(); i++)
|
||||
{
|
||||
file_info.name = i->name;
|
||||
file_info.comment = i->comment;
|
||||
file_info.size = i->size;
|
||||
file_info.datetime = uint_to_time(i->date, i->time);
|
||||
file_info.crc32 = i->crc32;
|
||||
file_info_vector.push_back(file_info);
|
||||
}
|
||||
|
||||
return(file_info_vector);
|
||||
}
|
||||
|
||||
//Skip forward a given number of chunks
|
||||
void jma_open::chunk_seek(unsigned int chunk_num) throw(jma_errors)
|
||||
{
|
||||
//Check the stream is open
|
||||
if (!stream.is_open())
|
||||
{
|
||||
throw(JMA_NO_OPEN);
|
||||
}
|
||||
|
||||
//Clear possible errors so the seek will work
|
||||
stream.clear();
|
||||
|
||||
//Move forward over header
|
||||
stream.seekg(jma_total_header_length, ios::beg);
|
||||
|
||||
unsigned char int4_buffer[UINT_SIZE];
|
||||
|
||||
while (chunk_num--)
|
||||
{
|
||||
//Read in size of chunk
|
||||
stream.read((char *)int4_buffer, UINT_SIZE);
|
||||
|
||||
//Skip chunk plus it's CRC32
|
||||
stream.seekg(charp_to_uint(int4_buffer)+UINT_SIZE, ios::cur);
|
||||
}
|
||||
}
|
||||
|
||||
//Return a vector of pointers to each file in the JMA, the buffer to hold all the files
|
||||
//must be initilized outside.
|
||||
vector<unsigned char *> jma_open::get_all_files(unsigned char *buffer) throw(jma_errors)
|
||||
{
|
||||
//If there's no stream we can't read from it, so exit
|
||||
if (!stream.is_open())
|
||||
{
|
||||
throw(JMA_NO_OPEN);
|
||||
}
|
||||
|
||||
//Seek to the first chunk
|
||||
chunk_seek(0);
|
||||
|
||||
//Set the buffer that decompressed data goes to
|
||||
decompressed_buffer = buffer;
|
||||
|
||||
//If the JMA is not solid
|
||||
if (chunk_size)
|
||||
{
|
||||
unsigned char int4_buffer[UINT_SIZE];
|
||||
size_t size = get_total_size(files);
|
||||
|
||||
//For each chunk in the file...
|
||||
for (size_t remaining_size = size; remaining_size; remaining_size -= chunk_size)
|
||||
{
|
||||
//Read the compressed size
|
||||
stream.read((char *)int4_buffer, UINT_SIZE);
|
||||
size_t compressed_size = charp_to_uint(int4_buffer);
|
||||
|
||||
//Allocate memory of the correct size to hold the compressed data in the JMA
|
||||
//Throw error on failure as that is unrecoverable from
|
||||
try
|
||||
{
|
||||
compressed_buffer = new unsigned char[compressed_size];
|
||||
}
|
||||
catch (bad_alloc xa)
|
||||
{
|
||||
throw(JMA_NO_MEM_ALLOC);
|
||||
}
|
||||
|
||||
//Read all the compressed data in
|
||||
stream.read((char *)compressed_buffer, compressed_size);
|
||||
|
||||
//Read the expected CRC of compressed data from the file
|
||||
stream.read((char *)int4_buffer, UINT_SIZE);
|
||||
|
||||
//If it doesn't match, throw error and cleanup memory
|
||||
if (CRC32lib::CRC32(compressed_buffer, compressed_size) != charp_to_uint(int4_buffer))
|
||||
{
|
||||
delete[] compressed_buffer;
|
||||
throw(JMA_BAD_FILE);
|
||||
}
|
||||
|
||||
//Decompress the data, cleanup memory on failure
|
||||
if (!decompress_lzma_7z(compressed_buffer, compressed_size,
|
||||
decompressed_buffer+size-remaining_size,
|
||||
(remaining_size > chunk_size) ? chunk_size : remaining_size))
|
||||
{
|
||||
delete[] compressed_buffer;
|
||||
throw(JMA_DECOMPRESS_FAILED);
|
||||
}
|
||||
delete[] compressed_buffer;
|
||||
|
||||
if (remaining_size <= chunk_size) //If we just decompressed the remainder
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else //Solidly compressed JMA
|
||||
{
|
||||
unsigned char int4_buffer[UINT_SIZE];
|
||||
|
||||
//Read the size of the compressed data
|
||||
stream.read((char *)int4_buffer, UINT_SIZE);
|
||||
size_t compressed_size = charp_to_uint(int4_buffer);
|
||||
|
||||
//Get decompressed size
|
||||
size_t size = get_total_size(files);
|
||||
|
||||
//Setup access methods for decompression
|
||||
ISequentialInStream_Istream compressed_data(stream);
|
||||
ISequentialOutStream_Array decompressed_data(reinterpret_cast<char*>(decompressed_buffer), size);
|
||||
|
||||
//Decompress the data
|
||||
if (!decompress_lzma_7z(compressed_data, compressed_size, decompressed_data, size))
|
||||
{
|
||||
throw(JMA_DECOMPRESS_FAILED);
|
||||
}
|
||||
|
||||
/*
|
||||
//Allocate memory of the right size to hold the compressed data in the JMA
|
||||
try
|
||||
{
|
||||
compressed_buffer = new unsigned char[compressed_size];
|
||||
}
|
||||
catch (bad_alloc xa)
|
||||
{
|
||||
throw(JMA_NO_MEM_ALLOC);
|
||||
}
|
||||
|
||||
//Copy the compressed data into memory
|
||||
stream.read((char *)compressed_buffer, compressed_size);
|
||||
size_t size = get_total_size(files);
|
||||
|
||||
//Read the CRC of the compressed data
|
||||
stream.read((char *)int4_buffer, UINT_SIZE);
|
||||
|
||||
//If it doesn't match, complain
|
||||
if (CRC32lib::CRC32(compressed_buffer, compressed_size) != charp_to_uint(int4_buffer))
|
||||
{
|
||||
delete[] compressed_buffer;
|
||||
throw(JMA_BAD_FILE);
|
||||
}
|
||||
|
||||
//Decompress the data
|
||||
if (!decompress_lzma_7z(compressed_buffer, compressed_size, decompressed_buffer, size))
|
||||
{
|
||||
delete[] compressed_buffer;
|
||||
throw(JMA_DECOMPRESS_FAILED);
|
||||
}
|
||||
delete[] compressed_buffer;
|
||||
*/
|
||||
}
|
||||
|
||||
vector<unsigned char *> file_pointers;
|
||||
size_t size = 0;
|
||||
|
||||
//For each file, add it's pointer to the vector, size is pointer offset in the buffer
|
||||
for (vector<jma_file_info>::iterator i = files.begin(); i != files.end(); i++)
|
||||
{
|
||||
i->buffer = decompressed_buffer+size;
|
||||
file_pointers.push_back(decompressed_buffer+size);
|
||||
size += i->size;
|
||||
}
|
||||
|
||||
//Return the vector of pointers
|
||||
return(file_pointers);
|
||||
}
|
||||
|
||||
//Extracts the file with a given name found in the archive to the given buffer
|
||||
void jma_open::extract_file(string& name, unsigned char *buffer) throw(jma_errors)
|
||||
{
|
||||
if (!stream.is_open())
|
||||
{
|
||||
throw(JMA_NO_OPEN);
|
||||
}
|
||||
|
||||
size_t size_to_skip = 0;
|
||||
size_t our_file_size = 0;
|
||||
|
||||
//Search through the vector of file information
|
||||
for (vector<jma_file_info>::iterator i = files.begin(); i != files.end(); i++)
|
||||
{
|
||||
if (i->name == name)
|
||||
{
|
||||
//Set the variable so we can tell we found it
|
||||
our_file_size = i->size;
|
||||
break;
|
||||
}
|
||||
|
||||
//Keep a running total of size
|
||||
size_to_skip += i->size;
|
||||
}
|
||||
|
||||
if (!our_file_size) //File with the specified name was not found in the archive
|
||||
{
|
||||
throw(JMA_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
//If the JMA only contains one file, we can skip a lot of overhead
|
||||
if (files.size() == 1)
|
||||
{
|
||||
get_all_files(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (chunk_size) //we are using non-solid archive..
|
||||
{
|
||||
unsigned int chunks_to_skip = size_to_skip / chunk_size;
|
||||
|
||||
//skip over requisite number of chunks
|
||||
chunk_seek(chunks_to_skip);
|
||||
|
||||
//Allocate memory for compressed and decompressed data
|
||||
unsigned char *comp_buffer = 0, *decomp_buffer = 0;
|
||||
try
|
||||
{
|
||||
//Compressed data size is <= non compressed size
|
||||
unsigned char *combined_buffer = new unsigned char[chunk_size*2];
|
||||
comp_buffer = combined_buffer;
|
||||
decomp_buffer = combined_buffer+chunk_size;
|
||||
}
|
||||
catch (bad_alloc xa)
|
||||
{
|
||||
throw(JMA_NO_MEM_ALLOC);
|
||||
}
|
||||
|
||||
size_t first_chunk_offset = size_to_skip % chunk_size;
|
||||
unsigned char int4_buffer[UINT_SIZE];
|
||||
for (size_t i = 0; i < our_file_size;)
|
||||
{
|
||||
//Get size
|
||||
stream.read((char *)int4_buffer, UINT_SIZE);
|
||||
size_t compressed_size = charp_to_uint(int4_buffer);
|
||||
|
||||
//Read all the compressed data in
|
||||
stream.read((char *)comp_buffer, compressed_size);
|
||||
|
||||
//Read the CRC of the compressed data
|
||||
stream.read((char *)int4_buffer, UINT_SIZE);
|
||||
|
||||
//If it doesn't match, complain
|
||||
if (CRC32lib::CRC32(comp_buffer, compressed_size) != charp_to_uint(int4_buffer))
|
||||
{
|
||||
delete[] comp_buffer;
|
||||
throw(JMA_BAD_FILE);
|
||||
}
|
||||
|
||||
//Decompress chunk
|
||||
if (!decompress_lzma_7z(comp_buffer, compressed_size, decomp_buffer, chunk_size))
|
||||
{
|
||||
delete[] comp_buffer;
|
||||
throw(JMA_DECOMPRESS_FAILED);
|
||||
}
|
||||
|
||||
size_t copy_amount = our_file_size-i > chunk_size-first_chunk_offset ? chunk_size-first_chunk_offset : our_file_size-i;
|
||||
|
||||
memcpy(buffer+i, decomp_buffer+first_chunk_offset, copy_amount);
|
||||
first_chunk_offset = 0; //Set to zero since this is only for the first iteration
|
||||
i += copy_amount;
|
||||
}
|
||||
delete[] comp_buffer;
|
||||
}
|
||||
else //Solid JMA
|
||||
{
|
||||
unsigned char *decomp_buffer = 0;
|
||||
try
|
||||
{
|
||||
decomp_buffer = new unsigned char[get_total_size(files)];
|
||||
}
|
||||
catch (bad_alloc xa)
|
||||
{
|
||||
throw(JMA_NO_MEM_ALLOC);
|
||||
}
|
||||
|
||||
get_all_files(decomp_buffer);
|
||||
|
||||
memcpy(buffer, decomp_buffer+size_to_skip, our_file_size);
|
||||
|
||||
delete[] decomp_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
bool jma_open::is_solid()
|
||||
{
|
||||
return(chunk_size ? false : true);
|
||||
}
|
||||
|
||||
const char *jma_error_text(jma_errors error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case JMA_NO_CREATE:
|
||||
return("JMA could not be created");
|
||||
|
||||
case JMA_NO_MEM_ALLOC:
|
||||
return("Memory for JMA could be allocated");
|
||||
|
||||
case JMA_NO_OPEN:
|
||||
return("JMA could not be opened");
|
||||
|
||||
case JMA_BAD_FILE:
|
||||
return("Invalid/Corrupt JMA");
|
||||
|
||||
case JMA_UNSUPPORTED_VERSION:
|
||||
return("JMA version not supported");
|
||||
|
||||
case JMA_COMPRESS_FAILED:
|
||||
return("JMA compression failed");
|
||||
|
||||
case JMA_DECOMPRESS_FAILED:
|
||||
return("JMA decompression failed");
|
||||
|
||||
case JMA_FILE_NOT_FOUND:
|
||||
return("File not found in JMA");
|
||||
}
|
||||
return("Unknown error");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright (C) 2005 NSRT Team ( http://nsrt.edgeemu.com )
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef JMA_H
|
||||
#define JMA_H
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <time.h>
|
||||
|
||||
namespace JMA
|
||||
{
|
||||
enum jma_errors { JMA_NO_CREATE, JMA_NO_MEM_ALLOC, JMA_NO_OPEN, JMA_BAD_FILE,
|
||||
JMA_UNSUPPORTED_VERSION, JMA_COMPRESS_FAILED, JMA_DECOMPRESS_FAILED,
|
||||
JMA_FILE_NOT_FOUND };
|
||||
|
||||
struct jma_file_info_base
|
||||
{
|
||||
std::string name;
|
||||
std::string comment;
|
||||
size_t size;
|
||||
unsigned int crc32;
|
||||
};
|
||||
|
||||
struct jma_public_file_info : jma_file_info_base
|
||||
{
|
||||
time_t datetime;
|
||||
};
|
||||
|
||||
struct jma_file_info : jma_file_info_base
|
||||
{
|
||||
unsigned short date;
|
||||
unsigned short time;
|
||||
const unsigned char *buffer;
|
||||
};
|
||||
|
||||
template<class jma_file_type>
|
||||
inline size_t get_total_size(std::vector<jma_file_type>& files)
|
||||
{
|
||||
size_t size = 0;
|
||||
for (typename std::vector<jma_file_type>::iterator i = files.begin(); i != files.end(); i++)
|
||||
{
|
||||
size += i->size; //We do have a problem if this wraps around
|
||||
}
|
||||
|
||||
return(size);
|
||||
}
|
||||
|
||||
class jma_open
|
||||
{
|
||||
public:
|
||||
jma_open(const char *) throw(jma_errors);
|
||||
~jma_open();
|
||||
|
||||
std::vector<jma_public_file_info> get_files_info();
|
||||
std::vector<unsigned char *> get_all_files(unsigned char *) throw(jma_errors);
|
||||
void extract_file(std::string& name, unsigned char *) throw(jma_errors);
|
||||
bool is_solid();
|
||||
|
||||
private:
|
||||
std::ifstream stream;
|
||||
std::vector<jma_file_info> files;
|
||||
size_t chunk_size;
|
||||
unsigned char *decompressed_buffer;
|
||||
unsigned char *compressed_buffer;
|
||||
|
||||
void chunk_seek(unsigned int) throw(jma_errors);
|
||||
void retrieve_file_block() throw(jma_errors);
|
||||
};
|
||||
|
||||
const char *jma_error_text(jma_errors);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright (C) 2005 NSRT Team ( http://nsrt.edgeemu.com )
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org )
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __LENCODER_H
|
||||
#define __LENCODER_H
|
||||
|
||||
#include "btreecd.h"
|
||||
|
||||
namespace NLength {
|
||||
|
||||
const UINT32 kNumPosStatesBitsMax = 4;
|
||||
const int kNumPosStatesMax = (1 << kNumPosStatesBitsMax);
|
||||
|
||||
|
||||
const int kNumPosStatesBitsEncodingMax = 4;
|
||||
const int kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax);
|
||||
|
||||
|
||||
const int kNumMoveBits = 5;
|
||||
|
||||
const int kNumLenBits = 3;
|
||||
const int kNumLowSymbols = 1 << kNumLenBits;
|
||||
const int kNumMidBits = 3;
|
||||
const int kNumMidSymbols = 1 << kNumMidBits;
|
||||
|
||||
const int kNumHighBits = 8;
|
||||
|
||||
const int kNumSymbolsTotal = kNumLowSymbols + kNumMidSymbols + (1 << kNumHighBits);
|
||||
|
||||
const int kNumSpecSymbols = kNumLowSymbols + kNumMidSymbols;
|
||||
|
||||
class CDecoder
|
||||
{
|
||||
CMyBitDecoder<kNumMoveBits> m_Choice;
|
||||
CBitTreeDecoder<kNumMoveBits, kNumLenBits> m_LowCoder[kNumPosStatesMax];
|
||||
CMyBitDecoder<kNumMoveBits> m_Choice2;
|
||||
CBitTreeDecoder<kNumMoveBits, kNumMidBits> m_MidCoder[kNumPosStatesMax];
|
||||
CBitTreeDecoder<kNumMoveBits, kNumHighBits> m_HighCoder;
|
||||
UINT32 m_NumPosStates;
|
||||
public:
|
||||
void Create(UINT32 aNumPosStates)
|
||||
{ m_NumPosStates = aNumPosStates; }
|
||||
void Init()
|
||||
{
|
||||
m_Choice.Init();
|
||||
for (UINT32 aPosState = 0; aPosState < m_NumPosStates; aPosState++)
|
||||
{
|
||||
m_LowCoder[aPosState].Init();
|
||||
m_MidCoder[aPosState].Init();
|
||||
}
|
||||
m_Choice2.Init();
|
||||
m_HighCoder.Init();
|
||||
}
|
||||
UINT32 Decode(CMyRangeDecoder *aRangeDecoder, UINT32 aPosState)
|
||||
{
|
||||
if(m_Choice.Decode(aRangeDecoder) == 0)
|
||||
return m_LowCoder[aPosState].Decode(aRangeDecoder);
|
||||
else
|
||||
{
|
||||
UINT32 aSymbol = kNumLowSymbols;
|
||||
if(m_Choice2.Decode(aRangeDecoder) == 0)
|
||||
aSymbol += m_MidCoder[aPosState].Decode(aRangeDecoder);
|
||||
else
|
||||
{
|
||||
aSymbol += kNumMidSymbols;
|
||||
aSymbol += m_HighCoder.Decode(aRangeDecoder);
|
||||
}
|
||||
return aSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org )
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __LITERALCODER_H
|
||||
#define __LITERALCODER_H
|
||||
|
||||
#include "aribitcd.h"
|
||||
#include "rcdefs.h"
|
||||
|
||||
namespace NLiteral {
|
||||
|
||||
const int kNumMoveBits = 5;
|
||||
|
||||
class CDecoder2
|
||||
{
|
||||
CMyBitDecoder<kNumMoveBits> m_Decoders[3][1 << 8];
|
||||
public:
|
||||
void Init()
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (int j = 1; j < (1 << 8); j++)
|
||||
m_Decoders[i][j].Init();
|
||||
}
|
||||
|
||||
BYTE DecodeNormal(CMyRangeDecoder *aRangeDecoder)
|
||||
{
|
||||
UINT32 aSymbol = 1;
|
||||
RC_INIT_VAR
|
||||
do
|
||||
{
|
||||
// aSymbol = (aSymbol << 1) | m_Decoders[0][aSymbol].Decode(aRangeDecoder);
|
||||
RC_GETBIT(kNumMoveBits, m_Decoders[0][aSymbol].m_Probability, aSymbol)
|
||||
}
|
||||
while (aSymbol < 0x100);
|
||||
RC_FLUSH_VAR
|
||||
return aSymbol;
|
||||
}
|
||||
|
||||
BYTE DecodeWithMatchByte(CMyRangeDecoder *aRangeDecoder, BYTE aMatchByte)
|
||||
{
|
||||
UINT32 aSymbol = 1;
|
||||
RC_INIT_VAR
|
||||
do
|
||||
{
|
||||
UINT32 aMatchBit = (aMatchByte >> 7) & 1;
|
||||
aMatchByte <<= 1;
|
||||
// UINT32 aBit = m_Decoders[1 + aMatchBit][aSymbol].Decode(aRangeDecoder);
|
||||
// aSymbol = (aSymbol << 1) | aBit;
|
||||
UINT32 aBit;
|
||||
RC_GETBIT2(kNumMoveBits, m_Decoders[1 + aMatchBit][aSymbol].m_Probability, aSymbol,
|
||||
aBit = 0, aBit = 1)
|
||||
if (aMatchBit != aBit)
|
||||
{
|
||||
while (aSymbol < 0x100)
|
||||
{
|
||||
// aSymbol = (aSymbol << 1) | m_Decoders[0][aSymbol].Decode(aRangeDecoder);
|
||||
RC_GETBIT(kNumMoveBits, m_Decoders[0][aSymbol].m_Probability, aSymbol)
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (aSymbol < 0x100);
|
||||
RC_FLUSH_VAR
|
||||
return aSymbol;
|
||||
}
|
||||
};
|
||||
|
||||
class CDecoder
|
||||
{
|
||||
CDecoder2 *m_Coders;
|
||||
UINT32 m_NumPrevBits;
|
||||
UINT32 m_NumPosBits;
|
||||
UINT32 m_PosMask;
|
||||
public:
|
||||
CDecoder(): m_Coders(0) {}
|
||||
~CDecoder() { Free(); }
|
||||
void Free()
|
||||
{
|
||||
delete []m_Coders;
|
||||
m_Coders = 0;
|
||||
}
|
||||
void Create(UINT32 aNumPosBits, UINT32 aNumPrevBits)
|
||||
{
|
||||
Free();
|
||||
m_NumPosBits = aNumPosBits;
|
||||
m_PosMask = (1 << aNumPosBits) - 1;
|
||||
m_NumPrevBits = aNumPrevBits;
|
||||
UINT32 aNumStates = 1 << (m_NumPrevBits + m_NumPosBits);
|
||||
m_Coders = new CDecoder2[aNumStates];
|
||||
}
|
||||
void Init()
|
||||
{
|
||||
UINT32 aNumStates = 1 << (m_NumPrevBits + m_NumPosBits);
|
||||
for (UINT32 i = 0; i < aNumStates; i++)
|
||||
m_Coders[i].Init();
|
||||
}
|
||||
UINT32 GetState(UINT32 aPos, BYTE aPrevByte) const
|
||||
{ return ((aPos & m_PosMask) << m_NumPrevBits) + (aPrevByte >> (8 - m_NumPrevBits)); }
|
||||
BYTE DecodeNormal(CMyRangeDecoder *aRangeDecoder, UINT32 aPos, BYTE aPrevByte)
|
||||
{ return m_Coders[GetState(aPos, aPrevByte)].DecodeNormal(aRangeDecoder); }
|
||||
BYTE DecodeWithMatchByte(CMyRangeDecoder *aRangeDecoder, UINT32 aPos, BYTE aPrevByte, BYTE aMatchByte)
|
||||
{ return m_Coders[GetState(aPos, aPrevByte)].DecodeWithMatchByte(aRangeDecoder, aMatchByte); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org )
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "lzma.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLZMA {
|
||||
|
||||
UINT32 kDistStart[kDistTableSizeMax];
|
||||
|
||||
static class CConstInit
|
||||
{
|
||||
public:
|
||||
CConstInit()
|
||||
{
|
||||
UINT32 aStartValue = 0;
|
||||
int i;
|
||||
for (i = 0; i < kDistTableSizeMax; i++)
|
||||
{
|
||||
kDistStart[i] = aStartValue;
|
||||
aStartValue += (1 << kDistDirectBits[i]);
|
||||
}
|
||||
}
|
||||
} g_ConstInit;
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
Copyright (C) 2005 NSRT Team ( http://nsrt.edgeemu.com )
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org )
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "lencoder.h"
|
||||
|
||||
#ifndef __LZMA_H
|
||||
#define __LZMA_H
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLZMA {
|
||||
|
||||
const UINT32 kNumRepDistances = 4;
|
||||
|
||||
const BYTE kNumStates = 12;
|
||||
|
||||
const BYTE kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5};
|
||||
const BYTE kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
|
||||
const BYTE kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
|
||||
const BYTE kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
|
||||
|
||||
class CState
|
||||
{
|
||||
public:
|
||||
BYTE m_Index;
|
||||
void Init()
|
||||
{ m_Index = 0; }
|
||||
void UpdateChar()
|
||||
{ m_Index = kLiteralNextStates[m_Index]; }
|
||||
void UpdateMatch()
|
||||
{ m_Index = kMatchNextStates[m_Index]; }
|
||||
void UpdateRep()
|
||||
{ m_Index = kRepNextStates[m_Index]; }
|
||||
void UpdateShortRep()
|
||||
{ m_Index = kShortRepNextStates[m_Index]; }
|
||||
};
|
||||
|
||||
class CBaseCoder
|
||||
{
|
||||
protected:
|
||||
CState m_State;
|
||||
BYTE m_PreviousByte;
|
||||
bool m_PeviousIsMatch;
|
||||
UINT32 m_RepDistances[kNumRepDistances];
|
||||
void Init()
|
||||
{
|
||||
m_State.Init();
|
||||
m_PreviousByte = 0;
|
||||
m_PeviousIsMatch = false;
|
||||
for(UINT32 i = 0 ; i < kNumRepDistances; i++)
|
||||
m_RepDistances[i] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
const int kNumPosSlotBits = 6;
|
||||
const int kDicLogSizeMax = 28;
|
||||
const int kDistTableSizeMax = kDicLogSizeMax * 2;
|
||||
|
||||
extern UINT32 kDistStart[kDistTableSizeMax];
|
||||
const BYTE kDistDirectBits[kDistTableSizeMax] =
|
||||
{
|
||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
|
||||
10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19,
|
||||
20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26
|
||||
};
|
||||
|
||||
const UINT32 kNumLenToPosStates = 4;
|
||||
inline UINT32 GetLenToPosState(UINT32 aLen)
|
||||
{
|
||||
aLen -= 2;
|
||||
if (aLen < kNumLenToPosStates)
|
||||
return aLen;
|
||||
return kNumLenToPosStates - 1;
|
||||
}
|
||||
|
||||
const int kMatchMinLen = 2;
|
||||
|
||||
const int kMatchMaxLen = kMatchMinLen + NLength::kNumSymbolsTotal - 1;
|
||||
|
||||
const int kNumAlignBits = 4;
|
||||
const int kAlignTableSize = 1 << kNumAlignBits;
|
||||
const UINT32 kAlignMask = (kAlignTableSize - 1);
|
||||
|
||||
const int kStartPosModelIndex = 4;
|
||||
const int kEndPosModelIndex = 14;
|
||||
const int kNumPosModels = kEndPosModelIndex - kStartPosModelIndex;
|
||||
|
||||
const int kNumFullDistances = 1 << (kEndPosModelIndex / 2);
|
||||
|
||||
|
||||
const int kMainChoiceLiteralIndex = 0;
|
||||
const int kMainChoiceMatchIndex = 1;
|
||||
|
||||
const int kMatchChoiceDistanceIndex= 0;
|
||||
const int kMatchChoiceRepetitionIndex = 1;
|
||||
|
||||
const int kNumMoveBitsForMainChoice = 5;
|
||||
const int kNumMoveBitsForPosCoders = 5;
|
||||
|
||||
const int kNumMoveBitsForAlignCoders = 5;
|
||||
|
||||
const int kNumMoveBitsForPosSlotCoder = 5;
|
||||
|
||||
const int kNumLitPosStatesBitsEncodingMax = 4;
|
||||
const int kNumLitContextBitsMax = 8;
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
Copyright (C) 2005 NSRT Team ( http://nsrt.edgeemu.com )
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org )
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
#include "lzmadec.h"
|
||||
|
||||
#define RETURN_E_OUTOFMEMORY_IF_FALSE(x) { if (!(x)) return E_OUTOFMEMORY; }
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLZMA {
|
||||
|
||||
HRESULT CDecoder::SetDictionarySize(UINT32 aDictionarySize)
|
||||
{
|
||||
if (aDictionarySize > (1 << kDicLogSizeMax))
|
||||
return E_INVALIDARG;
|
||||
|
||||
UINT32 aWindowReservSize = MyMax(aDictionarySize, UINT32(1 << 21));
|
||||
|
||||
if (m_DictionarySize != aDictionarySize)
|
||||
{
|
||||
m_OutWindowStream.Create(aDictionarySize, kMatchMaxLen, aWindowReservSize);
|
||||
m_DictionarySize = aDictionarySize;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CDecoder::SetLiteralProperties(
|
||||
UINT32 aLiteralPosStateBits, UINT32 aLiteralContextBits)
|
||||
{
|
||||
if (aLiteralPosStateBits > 8)
|
||||
return E_INVALIDARG;
|
||||
if (aLiteralContextBits > 8)
|
||||
return E_INVALIDARG;
|
||||
m_LiteralDecoder.Create(aLiteralPosStateBits, aLiteralContextBits);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CDecoder::SetPosBitsProperties(UINT32 aNumPosStateBits)
|
||||
{
|
||||
if (aNumPosStateBits > NLength::kNumPosStatesBitsMax)
|
||||
return E_INVALIDARG;
|
||||
UINT32 aNumPosStates = 1 << aNumPosStateBits;
|
||||
m_LenDecoder.Create(aNumPosStates);
|
||||
m_RepMatchLenDecoder.Create(aNumPosStates);
|
||||
m_PosStateMask = aNumPosStates - 1;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
CDecoder::CDecoder():
|
||||
m_DictionarySize((UINT32)-1)
|
||||
{
|
||||
Create();
|
||||
}
|
||||
|
||||
HRESULT CDecoder::Create()
|
||||
{
|
||||
for(int i = 0; i < kNumPosModels; i++)
|
||||
{
|
||||
RETURN_E_OUTOFMEMORY_IF_FALSE(
|
||||
m_PosDecoders[i].Create(kDistDirectBits[kStartPosModelIndex + i]));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CDecoder::Init(ISequentialInStream *anInStream,
|
||||
ISequentialOutStream *anOutStream)
|
||||
{
|
||||
m_RangeDecoder.Init(anInStream);
|
||||
|
||||
m_OutWindowStream.Init(anOutStream);
|
||||
|
||||
int i;
|
||||
for(i = 0; i < kNumStates; i++)
|
||||
{
|
||||
for (UINT32 j = 0; j <= m_PosStateMask; j++)
|
||||
{
|
||||
m_MainChoiceDecoders[i][j].Init();
|
||||
m_MatchRepShortChoiceDecoders[i][j].Init();
|
||||
}
|
||||
m_MatchChoiceDecoders[i].Init();
|
||||
m_MatchRepChoiceDecoders[i].Init();
|
||||
m_MatchRep1ChoiceDecoders[i].Init();
|
||||
m_MatchRep2ChoiceDecoders[i].Init();
|
||||
}
|
||||
|
||||
m_LiteralDecoder.Init();
|
||||
|
||||
// m_RepMatchLenDecoder.Init();
|
||||
|
||||
for (i = 0; (UINT32) i < kNumLenToPosStates; i++)
|
||||
m_PosSlotDecoder[i].Init();
|
||||
|
||||
for(i = 0; i < kNumPosModels; i++)
|
||||
m_PosDecoders[i].Init();
|
||||
|
||||
m_LenDecoder.Init();
|
||||
m_RepMatchLenDecoder.Init();
|
||||
|
||||
m_PosAlignDecoder.Init();
|
||||
return S_OK;
|
||||
|
||||
}
|
||||
|
||||
HRESULT CDecoder::CodeReal(ISequentialInStream *anInStream,
|
||||
ISequentialOutStream *anOutStream,
|
||||
const UINT64 *anInSize, const UINT64 *anOutSize)
|
||||
{
|
||||
if (anOutSize == NULL)
|
||||
return E_INVALIDARG;
|
||||
|
||||
Init(anInStream, anOutStream);
|
||||
|
||||
CState aState;
|
||||
aState.Init();
|
||||
bool aPeviousIsMatch = false;
|
||||
BYTE aPreviousByte = 0;
|
||||
UINT32 aRepDistances[kNumRepDistances];
|
||||
for(UINT32 i = 0 ; i < kNumRepDistances; i++)
|
||||
aRepDistances[i] = 0;
|
||||
|
||||
UINT64 aNowPos64 = 0;
|
||||
UINT64 aSize = *anOutSize;
|
||||
while(aNowPos64 < aSize)
|
||||
{
|
||||
UINT64 aNext = MyMin(aNowPos64 + (1 << 18), aSize);
|
||||
while(aNowPos64 < aNext)
|
||||
{
|
||||
UINT32 aPosState = UINT32(aNowPos64) & m_PosStateMask;
|
||||
if (m_MainChoiceDecoders[aState.m_Index][aPosState].Decode(&m_RangeDecoder) == (UINT32) kMainChoiceLiteralIndex)
|
||||
{
|
||||
// aCounts[0]++;
|
||||
aState.UpdateChar();
|
||||
if(aPeviousIsMatch)
|
||||
{
|
||||
BYTE aMatchByte = m_OutWindowStream.GetOneByte(0 - aRepDistances[0] - 1);
|
||||
aPreviousByte = m_LiteralDecoder.DecodeWithMatchByte(&m_RangeDecoder,
|
||||
UINT32(aNowPos64), aPreviousByte, aMatchByte);
|
||||
aPeviousIsMatch = false;
|
||||
}
|
||||
else
|
||||
aPreviousByte = m_LiteralDecoder.DecodeNormal(&m_RangeDecoder,
|
||||
UINT32(aNowPos64), aPreviousByte);
|
||||
m_OutWindowStream.PutOneByte(aPreviousByte);
|
||||
aNowPos64++;
|
||||
}
|
||||
else
|
||||
{
|
||||
aPeviousIsMatch = true;
|
||||
UINT32 aDistance, aLen;
|
||||
if(m_MatchChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) ==
|
||||
(UINT32) kMatchChoiceRepetitionIndex)
|
||||
{
|
||||
if(m_MatchRepChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) == 0)
|
||||
{
|
||||
if(m_MatchRepShortChoiceDecoders[aState.m_Index][aPosState].Decode(&m_RangeDecoder) == 0)
|
||||
{
|
||||
aState.UpdateShortRep();
|
||||
aPreviousByte = m_OutWindowStream.GetOneByte(0 - aRepDistances[0] - 1);
|
||||
m_OutWindowStream.PutOneByte(aPreviousByte);
|
||||
aNowPos64++;
|
||||
// aCounts[3 + 4]++;
|
||||
continue;
|
||||
}
|
||||
// aCounts[3 + 0]++;
|
||||
aDistance = aRepDistances[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_MatchRep1ChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) == 0)
|
||||
{
|
||||
aDistance = aRepDistances[1];
|
||||
aRepDistances[1] = aRepDistances[0];
|
||||
// aCounts[3 + 1]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_MatchRep2ChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) == 0)
|
||||
{
|
||||
// aCounts[3 + 2]++;
|
||||
aDistance = aRepDistances[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
// aCounts[3 + 3]++;
|
||||
aDistance = aRepDistances[3];
|
||||
aRepDistances[3] = aRepDistances[2];
|
||||
}
|
||||
aRepDistances[2] = aRepDistances[1];
|
||||
aRepDistances[1] = aRepDistances[0];
|
||||
}
|
||||
aRepDistances[0] = aDistance;
|
||||
}
|
||||
aLen = m_RepMatchLenDecoder.Decode(&m_RangeDecoder, aPosState) + kMatchMinLen;
|
||||
// aCounts[aLen]++;
|
||||
aState.UpdateRep();
|
||||
}
|
||||
else
|
||||
{
|
||||
aLen = kMatchMinLen + m_LenDecoder.Decode(&m_RangeDecoder, aPosState);
|
||||
aState.UpdateMatch();
|
||||
UINT32 aPosSlot = m_PosSlotDecoder[GetLenToPosState(aLen)].Decode(&m_RangeDecoder);
|
||||
// aCounts[aPosSlot]++;
|
||||
if (aPosSlot >= (UINT32) kStartPosModelIndex)
|
||||
{
|
||||
aDistance = kDistStart[aPosSlot];
|
||||
if (aPosSlot < (UINT32) kEndPosModelIndex)
|
||||
aDistance += m_PosDecoders[aPosSlot - kStartPosModelIndex].Decode(&m_RangeDecoder);
|
||||
else
|
||||
{
|
||||
aDistance += (m_RangeDecoder.DecodeDirectBits(kDistDirectBits[aPosSlot] -
|
||||
kNumAlignBits) << kNumAlignBits);
|
||||
aDistance += m_PosAlignDecoder.Decode(&m_RangeDecoder);
|
||||
}
|
||||
}
|
||||
else
|
||||
aDistance = aPosSlot;
|
||||
|
||||
|
||||
aRepDistances[3] = aRepDistances[2];
|
||||
aRepDistances[2] = aRepDistances[1];
|
||||
aRepDistances[1] = aRepDistances[0];
|
||||
|
||||
aRepDistances[0] = aDistance;
|
||||
// UpdateStat(aLen, aPosSlot);
|
||||
}
|
||||
if (aDistance >= aNowPos64)
|
||||
throw E_INVALIDDATA;
|
||||
m_OutWindowStream.CopyBackBlock(aDistance, aLen);
|
||||
aNowPos64 += aLen;
|
||||
aPreviousByte = m_OutWindowStream.GetOneByte(0 - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Flush();
|
||||
}
|
||||
|
||||
HRESULT CDecoder::Code(ISequentialInStream *anInStream, ISequentialOutStream *anOutStream, const UINT64 *anInSize, const UINT64 *anOutSize)
|
||||
{
|
||||
try {
|
||||
return CodeReal(anInStream, anOutStream, anInSize, anOutSize);
|
||||
} catch (HRESULT& e) {
|
||||
return e;
|
||||
} catch (...) {
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT CDecoder::ReadCoderProperties(ISequentialInStream *anInStream)
|
||||
{
|
||||
UINT32 aNumPosStateBits;
|
||||
UINT32 aLiteralPosStateBits;
|
||||
UINT32 aLiteralContextBits;
|
||||
UINT32 aDictionarySize;
|
||||
|
||||
UINT32 aProcessesedSize;
|
||||
|
||||
BYTE aByte;
|
||||
RETURN_IF_NOT_S_OK(anInStream->Read(&aByte, sizeof(aByte), &aProcessesedSize));
|
||||
if (aProcessesedSize != sizeof(aByte))
|
||||
return E_INVALIDARG;
|
||||
|
||||
aLiteralContextBits = aByte % 9;
|
||||
BYTE aRemainder = aByte / 9;
|
||||
aLiteralPosStateBits = aRemainder % 5;
|
||||
aNumPosStateBits = aRemainder / 5;
|
||||
|
||||
UINT8 uint_buffer[UINT_SIZE];
|
||||
RETURN_IF_NOT_S_OK(anInStream->Read(uint_buffer, sizeof(aDictionarySize), &aProcessesedSize));
|
||||
aDictionarySize = charp_to_uint(uint_buffer);
|
||||
|
||||
if (aProcessesedSize != sizeof(aDictionarySize))
|
||||
return E_INVALIDARG;
|
||||
|
||||
RETURN_IF_NOT_S_OK(SetDictionarySize(aDictionarySize));
|
||||
RETURN_IF_NOT_S_OK(SetLiteralProperties(aLiteralPosStateBits, aLiteralContextBits));
|
||||
RETURN_IF_NOT_S_OK(SetPosBitsProperties(aNumPosStateBits));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org )
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __LZARITHMETIC_DECODER_H
|
||||
#define __LZARITHMETIC_DECODER_H
|
||||
|
||||
#include "winout.h"
|
||||
#include "lzma.h"
|
||||
#include "lencoder.h"
|
||||
#include "litcoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLZMA {
|
||||
|
||||
typedef CMyBitDecoder<kNumMoveBitsForMainChoice> CMyBitDecoder2;
|
||||
|
||||
class CDecoder
|
||||
{
|
||||
NStream::NWindow::COut m_OutWindowStream;
|
||||
CMyRangeDecoder m_RangeDecoder;
|
||||
|
||||
CMyBitDecoder2 m_MainChoiceDecoders[kNumStates][NLength::kNumPosStatesMax];
|
||||
CMyBitDecoder2 m_MatchChoiceDecoders[kNumStates];
|
||||
CMyBitDecoder2 m_MatchRepChoiceDecoders[kNumStates];
|
||||
CMyBitDecoder2 m_MatchRep1ChoiceDecoders[kNumStates];
|
||||
CMyBitDecoder2 m_MatchRep2ChoiceDecoders[kNumStates];
|
||||
CMyBitDecoder2 m_MatchRepShortChoiceDecoders[kNumStates][NLength::kNumPosStatesMax];
|
||||
|
||||
CBitTreeDecoder<kNumMoveBitsForPosSlotCoder, kNumPosSlotBits> m_PosSlotDecoder[kNumLenToPosStates];
|
||||
|
||||
CReverseBitTreeDecoder2<kNumMoveBitsForPosCoders> m_PosDecoders[kNumPosModels];
|
||||
CReverseBitTreeDecoder<kNumMoveBitsForAlignCoders, kNumAlignBits> m_PosAlignDecoder;
|
||||
// CBitTreeDecoder2<kNumMoveBitsForPosCoders> m_PosDecoders[kNumPosModels];
|
||||
// CBitTreeDecoder<kNumMoveBitsForAlignCoders, kNumAlignBits> m_PosAlignDecoder;
|
||||
|
||||
NLength::CDecoder m_LenDecoder;
|
||||
NLength::CDecoder m_RepMatchLenDecoder;
|
||||
|
||||
NLiteral::CDecoder m_LiteralDecoder;
|
||||
|
||||
UINT32 m_DictionarySize;
|
||||
|
||||
UINT32 m_PosStateMask;
|
||||
|
||||
HRESULT Create();
|
||||
|
||||
HRESULT Init(ISequentialInStream *anInStream, ISequentialOutStream *anOutStream);
|
||||
|
||||
HRESULT Flush() { return m_OutWindowStream.Flush(); }
|
||||
|
||||
HRESULT CodeReal(ISequentialInStream *anInStream, ISequentialOutStream *anOutStream, const UINT64 *anInSize, const UINT64 *anOutSize);
|
||||
|
||||
public:
|
||||
|
||||
CDecoder();
|
||||
|
||||
HRESULT Code(ISequentialInStream *anInStream, ISequentialOutStream *anOutStream, const UINT64 *anInSize, const UINT64 *anOutSize);
|
||||
HRESULT ReadCoderProperties(ISequentialInStream *anInStream);
|
||||
|
||||
HRESULT SetDictionarySize(UINT32 aDictionarySize);
|
||||
HRESULT SetLiteralProperties(UINT32 aLiteralPosStateBits, UINT32 aLiteralContextBits);
|
||||
HRESULT SetPosBitsProperties(UINT32 aNumPosStateBits);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
Copyright (C) 2004 NSRT Team ( http://nsrt.edgeemu.com )
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __PORTABLE_H
|
||||
#define __PORTABLE_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
typedef signed char INT8;
|
||||
typedef unsigned char UINT8;
|
||||
typedef short INT16;
|
||||
typedef unsigned short UINT16;
|
||||
typedef long INT32;
|
||||
typedef unsigned long UINT32;
|
||||
typedef long long INT64;
|
||||
typedef unsigned long long UINT64;
|
||||
|
||||
typedef UINT8 BYTE;
|
||||
typedef UINT16 WORD;
|
||||
typedef UINT32 DWORD;
|
||||
|
||||
typedef unsigned UINT_PTR;
|
||||
|
||||
typedef int BOOL;
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
#define HRESULT int
|
||||
#define S_OK 0
|
||||
#define E_INVALIDARG -1
|
||||
#define E_OUTOFMEMORY -2
|
||||
#define E_FAIL -3
|
||||
#define E_INTERNAL_ERROR -4
|
||||
#define E_INVALIDDATA -5
|
||||
|
||||
template <class T> inline T MyMin(T a, T b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
template <class T> inline T MyMax(T a, T b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
#define RETURN_IF_NOT_S_OK(x) { HRESULT __aResult_ = (x); if(__aResult_ != S_OK) return __aResult_; }
|
||||
|
||||
|
||||
#define UINT_SIZE (4)
|
||||
#define USHORT_SIZE (2)
|
||||
|
||||
//Convert an array of 4 bytes back into an integer
|
||||
inline unsigned int charp_to_uint(const unsigned char buffer[UINT_SIZE])
|
||||
{
|
||||
unsigned int num = (unsigned int)buffer[3];
|
||||
num |= ((unsigned int)buffer[2]) << 8;
|
||||
num |= ((unsigned int)buffer[1]) << 16;
|
||||
num |= ((unsigned int)buffer[0]) << 24;
|
||||
return(num);
|
||||
}
|
||||
|
||||
//Convert an array of 2 bytes back into a short integer
|
||||
inline unsigned short charp_to_ushort(const unsigned char buffer[USHORT_SIZE])
|
||||
{
|
||||
unsigned short num = (unsigned short)buffer[1];
|
||||
num |= ((unsigned short)buffer[0]) << 8;
|
||||
return(num);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org )
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __RCDEFS_H
|
||||
#define __RCDEFS_H
|
||||
|
||||
#include "aribitcd.h"
|
||||
#include "ariconst.h"
|
||||
|
||||
#define RC_INIT_VAR \
|
||||
UINT32 aRange = aRangeDecoder->m_Range; \
|
||||
UINT32 aCode = aRangeDecoder->m_Code;
|
||||
|
||||
#define RC_FLUSH_VAR \
|
||||
aRangeDecoder->m_Range = aRange; \
|
||||
aRangeDecoder->m_Code = aCode;
|
||||
|
||||
#define RC_NORMALIZE \
|
||||
if (aRange < NCompression::NArithmetic::kTopValue) \
|
||||
{ \
|
||||
aCode = (aCode << 8) | aRangeDecoder->m_Stream.ReadByte(); \
|
||||
aRange <<= 8; }
|
||||
|
||||
#define RC_GETBIT2(aNumMoveBits, aProb, aModelIndex, Action0, Action1) \
|
||||
{UINT32 aNewBound = (aRange >> NCompression::NArithmetic::kNumBitModelTotalBits) * aProb; \
|
||||
if (aCode < aNewBound) \
|
||||
{ \
|
||||
Action0; \
|
||||
aRange = aNewBound; \
|
||||
aProb += (NCompression::NArithmetic::kBitModelTotal - aProb) >> aNumMoveBits; \
|
||||
aModelIndex <<= 1; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
Action1; \
|
||||
aRange -= aNewBound; \
|
||||
aCode -= aNewBound; \
|
||||
aProb -= (aProb) >> aNumMoveBits; \
|
||||
aModelIndex = (aModelIndex << 1) + 1; \
|
||||
}} \
|
||||
RC_NORMALIZE
|
||||
|
||||
#define RC_GETBIT(aNumMoveBits, aProb, aModelIndex) RC_GETBIT2(aNumMoveBits, aProb, aModelIndex, ; , ;)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org )
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __COMPRESSION_RANGECODER_H
|
||||
#define __COMPRESSION_RANGECODER_H
|
||||
|
||||
#include "inbyte.h"
|
||||
|
||||
namespace NCompression {
|
||||
namespace NArithmetic {
|
||||
|
||||
const UINT32 kNumTopBits = 24;
|
||||
const UINT32 kTopValue = (1 << kNumTopBits);
|
||||
|
||||
class CRangeDecoder
|
||||
{
|
||||
public:
|
||||
NStream::CInByte m_Stream;
|
||||
UINT32 m_Range;
|
||||
UINT32 m_Code;
|
||||
UINT32 m_Word;
|
||||
void Normalize()
|
||||
{
|
||||
while (m_Range < kTopValue)
|
||||
{
|
||||
m_Code = (m_Code << 8) | m_Stream.ReadByte();
|
||||
m_Range <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void Init(ISequentialInStream *aStream)
|
||||
{
|
||||
m_Stream.Init(aStream);
|
||||
m_Code = 0;
|
||||
m_Range = UINT32(-1);
|
||||
for(int i = 0; i < 5; i++)
|
||||
m_Code = (m_Code << 8) | m_Stream.ReadByte();
|
||||
}
|
||||
|
||||
UINT32 GetThreshold(UINT32 aTotal)
|
||||
{
|
||||
return (m_Code) / ( m_Range /= aTotal);
|
||||
}
|
||||
|
||||
void Decode(UINT32 aStart, UINT32 aSize, UINT32 aTotal)
|
||||
{
|
||||
m_Code -= aStart * m_Range;
|
||||
m_Range *= aSize;
|
||||
Normalize();
|
||||
}
|
||||
|
||||
/*
|
||||
UINT32 DecodeDirectBitsDiv(UINT32 aNumTotalBits)
|
||||
{
|
||||
m_Range >>= aNumTotalBits;
|
||||
UINT32 aThreshold = m_Code / m_Range;
|
||||
m_Code -= aThreshold * m_Range;
|
||||
|
||||
Normalize();
|
||||
return aThreshold;
|
||||
}
|
||||
|
||||
UINT32 DecodeDirectBitsDiv2(UINT32 aNumTotalBits)
|
||||
{
|
||||
if (aNumTotalBits <= kNumBottomBits)
|
||||
return DecodeDirectBitsDiv(aNumTotalBits);
|
||||
UINT32 aResult = DecodeDirectBitsDiv(aNumTotalBits - kNumBottomBits) << kNumBottomBits;
|
||||
return (aResult | DecodeDirectBitsDiv(kNumBottomBits));
|
||||
}
|
||||
*/
|
||||
|
||||
UINT32 DecodeDirectBits(UINT32 aNumTotalBits)
|
||||
{
|
||||
UINT32 aRange = m_Range;
|
||||
UINT32 aCode = m_Code;
|
||||
UINT32 aResult = 0;
|
||||
for (UINT32 i = aNumTotalBits; i > 0; i--)
|
||||
{
|
||||
aRange >>= 1;
|
||||
/*
|
||||
aResult <<= 1;
|
||||
if (aCode >= aRange)
|
||||
{
|
||||
aCode -= aRange;
|
||||
aResult |= 1;
|
||||
}
|
||||
*/
|
||||
UINT32 t = (aCode - aRange) >> 31;
|
||||
aCode -= aRange & (t - 1);
|
||||
// aRange = aRangeTmp + ((aRange & 1) & (1 - t));
|
||||
aResult = (aResult << 1) | (1 - t);
|
||||
|
||||
if (aRange < kTopValue)
|
||||
{
|
||||
aCode = (aCode << 8) | m_Stream.ReadByte();
|
||||
aRange <<= 8;
|
||||
}
|
||||
}
|
||||
m_Range = aRange;
|
||||
m_Code = aCode;
|
||||
return aResult;
|
||||
}
|
||||
|
||||
UINT32 DecodeBit(UINT32 aSize0, UINT32 aNumTotalBits)
|
||||
{
|
||||
UINT32 aNewBound = (m_Range >> aNumTotalBits) * aSize0;
|
||||
UINT32 aSymbol;
|
||||
if (m_Code < aNewBound)
|
||||
{
|
||||
aSymbol = 0;
|
||||
m_Range = aNewBound;
|
||||
}
|
||||
else
|
||||
{
|
||||
aSymbol = 1;
|
||||
m_Code -= aNewBound;
|
||||
m_Range -= aNewBound;
|
||||
}
|
||||
Normalize();
|
||||
return aSymbol;
|
||||
}
|
||||
|
||||
UINT64 GetProcessedSize() {return m_Stream.GetProcessedSize(); }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org )
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "winout.h"
|
||||
|
||||
namespace NStream {
|
||||
namespace NWindow {
|
||||
|
||||
void COut::Create(UINT32 aKeepSizeBefore, UINT32 aKeepSizeAfter, UINT32 aKeepSizeReserv)
|
||||
{
|
||||
m_Pos = 0;
|
||||
m_PosLimit = aKeepSizeReserv + aKeepSizeBefore;
|
||||
m_KeepSizeBefore = aKeepSizeBefore;
|
||||
m_KeepSizeAfter = aKeepSizeAfter;
|
||||
m_KeepSizeReserv = aKeepSizeReserv;
|
||||
m_StreamPos = 0;
|
||||
m_MoveFrom = m_KeepSizeReserv;
|
||||
m_WindowSize = aKeepSizeBefore;
|
||||
UINT32 aBlockSize = m_KeepSizeBefore + m_KeepSizeAfter + m_KeepSizeReserv;
|
||||
delete []m_Buffer;
|
||||
m_Buffer = new BYTE[aBlockSize];
|
||||
}
|
||||
|
||||
COut::~COut()
|
||||
{
|
||||
delete []m_Buffer;
|
||||
}
|
||||
|
||||
void COut::SetWindowSize(UINT32 aWindowSize)
|
||||
{
|
||||
m_WindowSize = aWindowSize;
|
||||
m_MoveFrom = m_KeepSizeReserv + m_KeepSizeBefore - aWindowSize;
|
||||
}
|
||||
|
||||
void COut::Init(ISequentialOutStream *aStream, bool aSolid)
|
||||
{
|
||||
m_Stream = aStream;
|
||||
|
||||
if(aSolid)
|
||||
m_StreamPos = m_Pos;
|
||||
else
|
||||
{
|
||||
m_Pos = 0;
|
||||
m_PosLimit = m_KeepSizeReserv + m_KeepSizeBefore;
|
||||
m_StreamPos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT COut::Flush()
|
||||
{
|
||||
UINT32 aSize = m_Pos - m_StreamPos;
|
||||
if(aSize == 0)
|
||||
return S_OK;
|
||||
UINT32 aProcessedSize;
|
||||
HRESULT aResult = m_Stream->Write(m_Buffer + m_StreamPos, aSize, &aProcessedSize);
|
||||
if (aResult != S_OK)
|
||||
return aResult;
|
||||
if (aSize != aProcessedSize)
|
||||
return E_FAIL;
|
||||
m_StreamPos = m_Pos;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void COut::MoveBlockBackward()
|
||||
{
|
||||
HRESULT aResult = Flush();
|
||||
if (aResult != S_OK)
|
||||
throw aResult;
|
||||
memmove(m_Buffer, m_Buffer + m_MoveFrom, m_WindowSize + m_KeepSizeAfter);
|
||||
m_Pos -= m_MoveFrom;
|
||||
m_StreamPos -= m_MoveFrom;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org )
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __STREAM_WINDOWOUT_H
|
||||
#define __STREAM_WINDOWOUT_H
|
||||
|
||||
#include "iiostrm.h"
|
||||
|
||||
namespace NStream {
|
||||
namespace NWindow {
|
||||
|
||||
// m_KeepSizeBefore: how mach BYTEs must be in buffer before m_Pos;
|
||||
// m_KeepSizeAfter: how mach BYTEs must be in buffer after m_Pos;
|
||||
// m_KeepSizeReserv: how mach BYTEs must be in buffer for Moving Reserv;
|
||||
// must be >= aKeepSizeAfter; // test it
|
||||
|
||||
class COut
|
||||
{
|
||||
BYTE *m_Buffer;
|
||||
UINT32 m_Pos;
|
||||
UINT32 m_PosLimit;
|
||||
UINT32 m_KeepSizeBefore;
|
||||
UINT32 m_KeepSizeAfter;
|
||||
UINT32 m_KeepSizeReserv;
|
||||
UINT32 m_StreamPos;
|
||||
|
||||
UINT32 m_WindowSize;
|
||||
UINT32 m_MoveFrom;
|
||||
|
||||
ISequentialOutStream *m_Stream;
|
||||
|
||||
virtual void MoveBlockBackward();
|
||||
public:
|
||||
COut(): m_Buffer(0), m_Stream(0) {}
|
||||
virtual ~COut();
|
||||
void Create(UINT32 aKeepSizeBefore,
|
||||
UINT32 aKeepSizeAfter, UINT32 aKeepSizeReserv = (1<<17));
|
||||
void SetWindowSize(UINT32 aWindowSize);
|
||||
|
||||
void Init(ISequentialOutStream *aStream, bool aSolid = false);
|
||||
HRESULT Flush();
|
||||
|
||||
UINT32 GetCurPos() const { return m_Pos; }
|
||||
const BYTE *GetPointerToCurrentPos() const { return m_Buffer + m_Pos;};
|
||||
|
||||
void CopyBackBlock(UINT32 aDistance, UINT32 aLen)
|
||||
{
|
||||
if (m_Pos >= m_PosLimit)
|
||||
MoveBlockBackward();
|
||||
BYTE *p = m_Buffer + m_Pos;
|
||||
aDistance++;
|
||||
for(UINT32 i = 0; i < aLen; i++)
|
||||
p[i] = p[i - aDistance];
|
||||
m_Pos += aLen;
|
||||
}
|
||||
|
||||
void PutOneByte(BYTE aByte)
|
||||
{
|
||||
if (m_Pos >= m_PosLimit)
|
||||
MoveBlockBackward();
|
||||
m_Buffer[m_Pos++] = aByte;
|
||||
}
|
||||
|
||||
BYTE GetOneByte(UINT32 anIndex) const
|
||||
{
|
||||
return m_Buffer[m_Pos + anIndex];
|
||||
}
|
||||
|
||||
BYTE *GetBuffer() const { return m_Buffer; }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
//created by Nach
|
||||
|
||||
//#include "jma/jma.h"
|
||||
|
||||
uint32 JMAReader::size() {
|
||||
return fsize;
|
||||
}
|
||||
|
||||
#define MAXROM 0x800000
|
||||
|
||||
uint8 *JMAReader::read(uint32 length)
|
||||
{
|
||||
uint8 *data;
|
||||
if (!fsize) { return 0; }
|
||||
if (length <= fsize)
|
||||
{
|
||||
//read the entire file into RAM
|
||||
data = (uint8*)memalloc(fsize);
|
||||
JMAFile.extract_file(cname, data);
|
||||
}
|
||||
else if (length > fsize)
|
||||
{
|
||||
//read the entire file into RAM, pad the rest with 0x00s
|
||||
data = (uint8*)memalloc(length);
|
||||
memset(data, 0, length);
|
||||
JMAFile.extract_file(cname, data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
JMAReader::JMAReader(char *fn) : JMAFile(fn), fsize(0)
|
||||
{
|
||||
std::vector<JMA::jma_public_file_info> file_info = JMAFile.get_files_info();
|
||||
for (std::vector<JMA::jma_public_file_info>::iterator i = file_info.begin(); i != file_info.end(); i++)
|
||||
{
|
||||
//Check for valid ROM based on size
|
||||
if ((i->size <= MAXROM+512) && (i->size > fsize))
|
||||
{
|
||||
cname = i->name;
|
||||
fsize = i->size;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 206 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user