Update to bsnes v011 release.

- Fixed Mode 0 color palette index problem. Fixes ToP, DQ5, etc.
    - Improved LoROM memory mapper to support 32mbit images. Fixes Tokimeki Memorial, etc.
    - Added full S-DD1 support, SFA2 and Star Ocean are now playable. Special thanks to Andreas Naive
    - Updated BGnxOFS / Mode7 registers with anomie's latest findings
    - Added basic ROM mirroring support. Fixes copy protection issues in MMX, etc.
    - Rewrote string library to work better on gcc/linux
    - Cleaned up S-RTC/S-DD1 emulation to make way for future add-on chip emulation
    - Rewrote DMA code, now runs cycle-by-cycle
    - Rewrote HDMA code, now allows HDMA to be enabled mid-frame, fixes many games
    - Fixed a bug in Mode7 vertical screen flip mode. Fixes FF5 title screen, etc.
    - Greatly improved IRQ triggering. Fixes Der Langrisser, etc.
    - Added full support for open bus. This includes PPU1 and PPU2 open bus support
    - Modified CPU core back to cycle-based system. Slower, but improves debugger
    - Implemented temporary fix for debugger to handle new cycle-based cores
    - Modified CGRAM to ignore highest bit, since it is not used at all by the SNES, and is impossible to read on real hardware. Lowers memory usage by ~1.2mb
    - Added mostly accurate PAL timing support. This should increase compatibility by ~30% or so
    - More stuff I'm forgetting at the moment...
This commit is contained in:
byuu 2005-08-26 20:38:00 +00:00
parent 970dcea0ac
commit 7e2cfb6d40
80 changed files with 7430 additions and 4387 deletions

BIN
bsnes.exe

Binary file not shown.

View File

@ -23,6 +23,8 @@ APURegs regs;
virtual void power() = 0; virtual void power() = 0;
virtual void reset() = 0; virtual void reset() = 0;
//debugging functions
virtual bool in_opcode();
void disassemble_opcode(char *output); void disassemble_opcode(char *output);
inline uint16 __relb(int8 offset, int op_len); inline uint16 __relb(int8 offset, int op_len);
}; };

View File

@ -226,7 +226,8 @@ void bAPU::reset() {
regs.sp = 0xef; regs.sp = 0xef;
regs.p = 0x02; regs.p = 0x02;
status.cycle_pos = 0; status.cycle_pos = 0;
status.cycles_executed = 0;
//$f1 //$f1
status.iplrom_enabled = true; status.iplrom_enabled = true;

View File

@ -53,6 +53,7 @@ enum {
inline void stack_write(uint8 value); inline void stack_write(uint8 value);
inline void exec_cycle(); inline void exec_cycle();
inline bool in_opcode();
inline void init_op_table(); inline void init_op_table();
inline uint8 op_adc (uint8 x, uint8 y); inline uint8 op_adc (uint8 x, uint8 y);

View File

@ -15,6 +15,11 @@ uint8 op;
} }
} }
//only return true when we are on an opcode edge
bool bAPU::in_opcode() {
return (status.cycle_pos != 0);
}
void bAPU::init_op_table() { void bAPU::init_op_table() {
#include "bapu_optable.cpp" #include "bapu_optable.cpp"
} }

View File

@ -107,16 +107,16 @@ int i, l;
replace(t, "$5", op_list[i].arg[5]); replace(t, "$5", op_list[i].arg[5]);
replace(t, "$6", op_list[i].arg[6]); replace(t, "$6", op_list[i].arg[6]);
replace(t, "$7", op_list[i].arg[7]); replace(t, "$7", op_list[i].arg[7]);
fprintf(fp, "%s\r\n\r\n", *t); fprintf(fp, "%s\r\n\r\n", strptr(t));
strcpy(t, output_header); strcpy(t, output_header);
replace(t, "$$", op_list[i].name); replace(t, "$$", op_list[i].name);
fprintf(fph, "%s", *t); fprintf(fph, "%s", strptr(t));
strcpy(t, output_table); strcpy(t, output_table);
replace(t, "$$", op_list[i].name); replace(t, "$$", op_list[i].name);
replace(t, "$0", op_list[i].arg[0]); replace(t, "$0", op_list[i].arg[0]);
fprintf(fpt, "%s", *t); fprintf(fpt, "%s", strptr(t));
} }
} }

Binary file not shown.

View File

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

View File

@ -1,6 +1,16 @@
#include <time.h> #include <time.h>
#include "lib/libbase.h" #include "lib/libbase.h"
#if defined(_WIN32)
#define _WIN32_
#undef _UNIX_
#elif defined(__GNUC__)
#define _UNIX_
#undef _WIN32_
#else
#error "unknown architecture"
#endif
//structs //structs
typedef struct { typedef struct {
uint8 *data; uint8 *data;

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

@ -0,0 +1,94 @@
#include "../../base.h"
#include "sdd1emu.cpp"
void SDD1::power() {
reset();
}
void SDD1::reset() {
sdd1.index[0] = 0x000000;
sdd1.index[1] = 0x100000;
sdd1.index[2] = 0x200000;
sdd1.index[3] = 0x300000;
for(int i=0;i<8;i++) {
sdd1.active[i] = false;
}
sdd1.dma_active = false;
}
uint32 SDD1::offset(uint32 addr) {
uint8 b = (addr >> 16) & 0xff;
if(b <= 0xbf)return 0;
b -= 0xc0; //b = 0x00-0x3f
b >>= 4; //b = 0-3
b &= 3; //bitmask
return sdd1.index[b] + (addr & 0x0fffff);
}
uint8 SDD1::mmio_read(uint16 addr) {
switch(addr) {
//>>20 == 0x100000 == 1mb
case 0x4804:return (sdd1.index[0] >> 20) & 7;
case 0x4805:return (sdd1.index[1] >> 20) & 7;
case 0x4806:return (sdd1.index[2] >> 20) & 7;
case 0x4807:return (sdd1.index[3] >> 20) & 7;
}
return cpu->regs.mdr;
}
void SDD1::mmio_write(uint16 addr, uint8 data) {
int i;
switch(addr) {
case 0x4801:
for(i=0;i<8;i++) {
sdd1.active[i] = !!(data & (1 << i));
}
break;
//<<20 == 0x100000 == 1mb
case 0x4804:sdd1.index[0] = (data & 7) << 20;break;
case 0x4805:sdd1.index[1] = (data & 7) << 20;break;
case 0x4806:sdd1.index[2] = (data & 7) << 20;break;
case 0x4807:sdd1.index[3] = (data & 7) << 20;break;
}
}
void SDD1::dma_begin(uint8 channel, uint32 addr, uint16 length) {
if(sdd1.active[channel] == true) {
sdd1.active[channel] = false;
sdd1.dma_active = true;
sdd1.buffer_index = 0;
sdd1.buffer_size = length;
sdd1emu.decompress(addr, (length) ? length : 65536, sdd1.buffer);
}
}
bool SDD1::dma_active() {
return sdd1.dma_active;
}
uint8 SDD1::dma_read() {
if(--sdd1.buffer_size == 0) {
sdd1.dma_active = false;
}
//sdd1.buffer[] is 65536 bytes, and sdd1.buffer_index
//is of type uint16, so no buffer overflow is possible
return sdd1.buffer[sdd1.buffer_index++];
}
SDD1::SDD1() {
mmio = new SDD1MMIO();
}
uint8 SDD1MMIO::read(uint32 addr) {
return sdd1->mmio_read(addr);
}
void SDD1MMIO::write(uint32 addr, uint8 value) {
sdd1->mmio_write(addr, value);
}

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

@ -0,0 +1,36 @@
#include "sdd1emu.h"
class SDD1MMIO : public MMIO {
public:
inline uint8 read (uint32 addr);
inline void write(uint32 addr, uint8 value);
};
class SDD1 {
public:
SDD1emu sdd1emu;
SDD1MMIO *mmio;
struct {
uint32 index[4]; //memory mapping registers
uint8 buffer[65536]; //pointer to decompressed S-DD1 data,
//max. DMA length is 65536
uint16 buffer_index; //DMA read index into S-DD1 decompression buffer
uint16 buffer_size;
bool active[8]; //true when DMA channel should pass through S-DD1
bool dma_active;
}sdd1;
void init();
void power();
void reset();
uint32 offset(uint32 addr);
void dma_begin(uint8 channel, uint32 addr, uint16 length);
bool dma_active();
uint8 dma_read();
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
SDD1();
};

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

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

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

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

View File

@ -50,7 +50,9 @@
whenever the RTC is set. whenever the RTC is set.
*/ */
void bCPU::srtc_set_time() { #include "../../base.h"
void SRTC::set_time() {
time_t rawtime; time_t rawtime;
tm *t; tm *t;
::time(&rawtime); ::time(&rawtime);
@ -72,12 +74,12 @@ tm *t;
srtc.data[12] = t->tm_wday; srtc.data[12] = t->tm_wday;
} }
void bCPU::srtc_power() { void SRTC::power() {
memset(&srtc, 0, sizeof(srtc)); memset(&srtc, 0, sizeof(srtc));
reset(); reset();
} }
void bCPU::srtc_reset() { void SRTC::reset() {
srtc.index = -1; srtc.index = -1;
srtc.mode = SRTC_READ; srtc.mode = SRTC_READ;
} }
@ -87,7 +89,7 @@ void bCPU::srtc_reset() {
//as reads will refresh the data array with the current system //as reads will refresh the data array with the current system
//time. The write method is only here for the sake of faux //time. The write method is only here for the sake of faux
//emulation of the real hardware. //emulation of the real hardware.
void bCPU::srtc_write(uint8 data) { void SRTC::write(uint8 data) {
data &= 0x0f; //only the low four bits are used data &= 0x0f; //only the low four bits are used
if(data >= 0x0d) { if(data >= 0x0d) {
@ -140,10 +142,10 @@ void bCPU::srtc_write(uint8 data) {
} }
} }
uint8 bCPU::srtc_read() { uint8 SRTC::read() {
if(srtc.mode == SRTC_READ) { if(srtc.mode == SRTC_READ) {
if(srtc.index < 0) { if(srtc.index < 0) {
srtc_set_time(); set_time();
srtc.index++; srtc.index++;
return 0x0f; //send start message return 0x0f; //send start message
} else if(srtc.index > MAX_SRTC_INDEX) { } else if(srtc.index > MAX_SRTC_INDEX) {
@ -156,3 +158,21 @@ uint8 bCPU::srtc_read() {
return 0x00; return 0x00;
} }
} }
SRTC::SRTC() {
mmio = new SRTCMMIO();
}
uint8 SRTCMMIO::read(uint32 addr) {
switch(addr) {
case 0x2800:return srtc->read();
}
return cpu->regs.mdr;
}
void SRTCMMIO::write(uint32 addr, uint8 value) {
switch(addr) {
case 0x2801:srtc->write(value);break;
}
}

View File

@ -1,10 +1,12 @@
void srtc_set_time(); class SRTCMMIO : public MMIO {
void srtc_power(); public:
void srtc_reset(); inline uint8 read (uint32 addr);
void srtc_write(uint8 data); inline void write(uint32 addr, uint8 value);
uint8 srtc_read(); };
#define MAX_SRTC_INDEX 0x0c class SRTC {
public:
enum { MAX_SRTC_INDEX = 0x0c };
enum { enum {
SRTC_READ = 0, SRTC_READ = 0,
@ -18,9 +20,7 @@ enum {
SRTC_COMMAND_CLEAR = 4 SRTC_COMMAND_CLEAR = 4
}; };
#define DAYTICKS (60*60*24) SRTCMMIO *mmio;
#define HOURTICKS (60*60)
#define MINUTETICKS (60)
/****************************** /******************************
[srtc.data structure] [srtc.data structure]
@ -38,11 +38,18 @@ Index Description Range
9 Year ones 0-9 9 Year ones 0-9
10 Year tens 0-9 10 Year tens 0-9
11 Year hundreds 9-11 (9=19xx, 10=20xx, 11=21xx) 11 Year hundreds 9-11 (9=19xx, 10=20xx, 11=21xx)
12 Day of week 0-6 (0=Sunday, ...) 12 Day of week 0-6 (0=Sunday, ...)
******************************/ ******************************/
struct { struct {
int8 index; int8 index;
uint8 mode; uint8 mode;
uint8 data[MAX_SRTC_INDEX + 1]; uint8 data[MAX_SRTC_INDEX + 1];
}srtc; }srtc;
void set_time();
void power();
void reset();
void write(uint8 data);
uint8 read();
SRTC();
};

View File

@ -1,7 +1,5 @@
#include "../../base.h" #include "../../base.h"
#include "srtc.cpp"
#include "bcpu_opfn.cpp" #include "bcpu_opfn.cpp"
#include "bcpu_op_read.cpp" #include "bcpu_op_read.cpp"
#include "bcpu_op_rmw.cpp" #include "bcpu_op_rmw.cpp"
@ -58,9 +56,11 @@ void bCPU::irq(uint16 addr) {
snes->notify(SNES::CPU_EXEC_OPCODE_END); snes->notify(SNES::CPU_EXEC_OPCODE_END);
} }
//vcounter range verified on real hardware,
//HDMA runs on the very first scanline of vblank
bool bCPU::hdma_test() { bool bCPU::hdma_test() {
if(status.hdma_triggered == false) { if(status.hdma_triggered == false) {
if(vcounter() < (overscan()?239:224) && hcounter() >= 278) { if(vcounter() <= (overscan()?239:224) && hcounter() >= 278) {
status.hdma_triggered = true; status.hdma_triggered = true;
return true; return true;
} }
@ -68,41 +68,62 @@ bool bCPU::hdma_test() {
return false; return false;
} }
//NMI range: V==225/240,H>=12 ; V>225/240
bool bCPU::nmi_test() { bool bCPU::nmi_test() {
if(vcounter() >= ((overscan()?239:224) + 1) && status.nmi_triggered == false) { if(status.nmi_exec == true)return false;
if((vcounter() == ((overscan()?239:224) + 1) && hcycles() >= 12) || (vcounter() > ((overscan()?239:224) + 1))) {
status.nmi_triggered = true; //[status.cycle_count index]
status.nmi_pin = 0; // 6->12
if(status.nmi_enabled == true) { // 8->14
return true; int hc = status.cycle_count + 6;
} if(vcounter() == ((overscan()?239:224) + 1) && hcycles() < hc) {
} //dprintf("* miss at %3d,%4d,%3x : %d x=%0.4x", vcounter(), hcycles(), hcounter(), status.cycle_count, regs.x.w);
} }
if(
(vcounter() == ((overscan()?239:224) + 1) && hcycles() >= hc) ||
(vcounter() > ((overscan()?239:224) + 1))
) {
//dprintf("* %3d,%4d,%3x : %d x=%0.4x", vcounter(), hcycles(), hcounter(), status.cycle_count, regs.x.w);
status.nmi_exec = true;
return status.nmi_enabled;
}
return false; return false;
} }
bool bCPU::irq_test() { bool bCPU::irq_test() {
int vpos, hpos; int vpos, hpos;
if(regs.p.i)return false; //no interrupt can occur with I flag set if(regs.p.i)return false; //no interrupt can occur with I flag set
if(status.irq_pin == 0)return false; //same as above if(status.irq_read == true)return false; //same as above
if(status.virq_enabled == false && status.hirq_enabled == false)return false; if(status.virq_enabled == false && status.hirq_enabled == false)return false;
//if irq_exec is true, then an IRQ occurred already.
//IRQs will continue to fire until $4211 is read from, or
//$4200 is written to, where irq_exec is set back to false.
if(status.irq_exec == true) {
return true;
}
//calculate V/H positions required for IRQ to trigger //calculate V/H positions required for IRQ to trigger
vpos = status.virq_pos; vpos = status.virq_pos;
hpos = (status.hirq_enabled) ? status.hirq_pos : 0; hpos = (status.hirq_enabled) ? status.hirq_pos : 0;
//positions that can never be latched //positions that can never be latched
if(vpos == 261 && hpos == 339 && interlace() == false)return false; //region_scanlines() = 262/NTSC, 312/PAL
if(vpos == 262 && interlace() == false)return false; //PAL results are unverified on hardware
if(vpos == 262 && hpos == 339)return false; if(vpos == 240 && hpos == 339 && interlace() == false && interlace_field() == 1)return false;
if(vpos > 262)return false; if(vpos == (region_scanlines() - 1) && hpos == 339 && interlace() == false)return false;
if(vpos == region_scanlines() && interlace() == false)return false;
if(vpos == region_scanlines() && hpos == 339)return false;
if(vpos > region_scanlines())return false;
if(hpos > 339)return false; if(hpos > 339)return false;
if(hpos == 0) { if(hpos == 0) {
hpos = 24; hpos = status.cycle_count + 14;
} else { } else {
hpos <<= 2; hpos <<= 2;
hpos += 24; //30 - status.cycle_count; hpos += status.cycle_count + 18;
//it should be OK to use the current line cycles/frame lines, //it should be OK to use the current line cycles/frame lines,
//as the IRQ will only trigger on the correct scanline anyway... //as the IRQ will only trigger on the correct scanline anyway...
if(hpos >= time.line_cycles) { if(hpos >= time.line_cycles) {
@ -116,11 +137,8 @@ int vpos, hpos;
if(status.virq_enabled == true && vcounter() != vpos)return false; if(status.virq_enabled == true && vcounter() != vpos)return false;
if(hcycles() >= hpos && status.irq_pin == 1) { if(hcycles() >= hpos) {
//dprintf("* vpos=%3d,hpos=%4d; v=%3d,h=%4d; lc=%d,virq=%3d,hirq=%3d", status.irq_exec = true;
// vpos, hpos, vcounter(), hcycles(), status.cycle_count, status.virq_pos, status.hirq_pos);
status.irq_triggered = true;
status.irq_pin = 0;
return true; return true;
} }
@ -134,20 +152,24 @@ void bCPU::run() {
break; break;
case CPUSTATE_RUN: case CPUSTATE_RUN:
case CPUSTATE_WAI: case CPUSTATE_WAI:
if(nmi_test() == true) { if(status.cycle_pos == 0) {
irq(0xffea); //interrupts only trigger on opcode edges
break; if(nmi_test() == true) {
irq(0xffea);
break;
}
if(irq_test() == true) {
irq(0xffee);
break;
}
} }
if(irq_test() == true) { //fallthrough
irq(0xffee);
break;
}
exec_opcode();
break;
case CPUSTATE_STP: case CPUSTATE_STP:
exec_opcode(); exec_cycle();
break; break;
} }
cycle_edge();
} }
void bCPU::scanline() { void bCPU::scanline() {
@ -164,23 +186,21 @@ void bCPU::scanline() {
} }
if(status.virq_enabled == false) { if(status.virq_enabled == false) {
status.irq_pin = 1; status.irq_read = false;
} }
} }
void bCPU::frame() { void bCPU::frame() {
hdma_initialize(); hdma_initialize();
status.nmi_triggered = false; status.nmi_read = false;
status.nmi_pin = 1; status.nmi_exec = false;
status.r4210_read = false;
status.irq_triggered = false; status.irq_read = false;
status.irq_pin = 1;
} }
void bCPU::power() { void bCPU::power() {
srtc_power(); region = snes->region();
regs.a = regs.x = regs.y = 0x0000; regs.a = regs.x = regs.y = 0x0000;
regs.s = 0x01ff; regs.s = 0x01ff;
@ -188,10 +208,6 @@ void bCPU::power() {
} }
void bCPU::reset() { void bCPU::reset() {
srtc_reset();
frame();
//reset vector location //reset vector location
regs.pc = mem_bus->read(0xfffc) | (mem_bus->read(0xfffd) << 8); regs.pc = mem_bus->read(0xfffc) | (mem_bus->read(0xfffd) << 8);
@ -203,26 +219,33 @@ void bCPU::reset() {
regs.db = 0x00; regs.db = 0x00;
regs.p = 0x34; regs.p = 0x34;
regs.e = 1; regs.e = 1;
regs.mdr = 0x00;
time_reset(); time_reset();
mmio_reset(); mmio_reset();
dma_reset(); dma_reset();
status.cpu_state = CPUSTATE_RUN; status.cpu_state = CPUSTATE_RUN;
status.dma_state = DMASTATE_STOP;
status.cycle_pos = 0;
status.cycle_count = 0;
status.cycles_executed = 0;
status.hdma_triggered = false; status.hdma_triggered = false;
status.nmi_triggered = false; status.nmi_read = false;
status.nmi_pin = 1; status.nmi_exec = false;
status.r4210_read = false;
status.irq_triggered = false; status.irq_read = false;
status.irq_pin = 1; status.irq_exec = false;
apu_port[0] = 0x00; apu_port[0] = 0x00;
apu_port[1] = 0x00; apu_port[1] = 0x00;
apu_port[2] = 0x00; apu_port[2] = 0x00;
apu_port[3] = 0x00; apu_port[3] = 0x00;
frame();
} }
uint8 bCPU::port_read(uint8 port) { uint8 bCPU::port_read(uint8 port) {
@ -236,7 +259,6 @@ void bCPU::port_write(uint8 port, uint8 value) {
void bCPU::cpu_c2() { void bCPU::cpu_c2() {
if(regs.d.l != 0x00) { if(regs.d.l != 0x00) {
status.cycle_count = 6; status.cycle_count = 6;
cycle_edge();
add_cycles(6); add_cycles(6);
} }
} }
@ -244,7 +266,6 @@ void bCPU::cpu_c2() {
void bCPU::cpu_c4(uint16 x, uint16 y) { void bCPU::cpu_c4(uint16 x, uint16 y) {
if(!regs.p.x && (x & 0xff00) != (y & 0xff00)) { if(!regs.p.x && (x & 0xff00) != (y & 0xff00)) {
status.cycle_count = 6; status.cycle_count = 6;
cycle_edge();
add_cycles(6); add_cycles(6);
} }
} }
@ -252,30 +273,25 @@ void bCPU::cpu_c4(uint16 x, uint16 y) {
void bCPU::cpu_c6(uint16 addr) { void bCPU::cpu_c6(uint16 addr) {
if(regs.e && (regs.pc.w & 0xff00) != (addr & 0xff00)) { if(regs.e && (regs.pc.w & 0xff00) != (addr & 0xff00)) {
status.cycle_count = 6; status.cycle_count = 6;
cycle_edge();
add_cycles(6); add_cycles(6);
} }
} }
void bCPU::cpu_io() { void bCPU::cpu_io() {
status.cycle_count = 6; status.cycle_count = 6;
cycle_edge();
add_cycles(6); add_cycles(6);
} }
uint8 bCPU::mem_read(uint32 addr) { uint8 bCPU::mem_read(uint32 addr) {
uint8 r;
status.cycle_count = mem_bus->speed(addr); status.cycle_count = mem_bus->speed(addr);
cycle_edge();
add_cycles(2); add_cycles(2);
r = mem_bus->read(addr); regs.mdr = mem_bus->read(addr);
add_cycles(status.cycle_count - 2); add_cycles(status.cycle_count - 2);
return r; return regs.mdr;
} }
void bCPU::mem_write(uint32 addr, uint8 value) { void bCPU::mem_write(uint32 addr, uint8 value) {
status.cycle_count = mem_bus->speed(addr); status.cycle_count = mem_bus->speed(addr);
cycle_edge();
add_cycles(6); add_cycles(6);
mem_bus->write(addr, value); mem_bus->write(addr, value);
add_cycles(status.cycle_count - 6); add_cycles(status.cycle_count - 6);
@ -345,9 +361,7 @@ void bCPU::stack_write(uint8 value) {
} }
bCPU::bCPU() { bCPU::bCPU() {
time_init();
mmio = new bCPUMMIO(this); mmio = new bCPUMMIO(this);
init_op_tables(); init_op_tables();
} }

View File

@ -13,8 +13,10 @@ private:
typedef void (bCPU::*op)(); typedef void (bCPU::*op)();
op optbl[256]; op optbl[256];
enum { NTSC = 0, PAL = 1 };
uint8 region;
public: public:
#include "srtc.h"
#include "bcpu_timing.h" #include "bcpu_timing.h"
uint8 apu_port[4]; uint8 apu_port[4];
@ -39,25 +41,33 @@ enum {
enum { enum {
DMASTATE_STOP = 0, DMASTATE_STOP = 0,
DMASTATE_INIT,
DMASTATE_DMASYNC, DMASTATE_DMASYNC,
DMASTATE_DMASYNC2,
DMASTATE_RUN, DMASTATE_RUN,
DMASTATE_CPUSYNC DMASTATE_CPUSYNC,
DMASTATE_CPUSYNC2
}; };
struct { struct {
uint8 cpu_state, cycle_count; uint8 cpu_state, cycle_pos, cycle_count;
uint8 opcode;
uint32 cycles_executed;
uint8 dma_state; uint8 dma_state;
uint32 dma_cycle_count; uint32 dma_cycle_count;
bool hdma_triggered; bool hdma_triggered;
bool nmi_triggered; //used by $4210 read bit 7
bool nmi_pin; bool nmi_read;
bool r4210_read; //used by NMI test, set when NMI executed this frame
bool nmi_exec;
bool irq_triggered; //IRQ is level-sensitive, so $4211 must be read to
bool irq_pin; //prevent multiple interrupts from occurring
bool irq_read;
//this is used to return $4211 bit 7
bool irq_exec;
//$4207-$420a
uint16 virq_trigger, hirq_trigger; uint16 virq_trigger, hirq_trigger;
//$2181-$2183 //$2181-$2183
@ -91,10 +101,12 @@ struct {
}status; }status;
struct { struct {
uint32 read_index; //set to 0 at beginning of DMA/HDMA
//$420b //$420b
bool active; bool active;
//$420c //$420c
bool hdma_active; bool hdma_enabled;
//$43x0 //$43x0
uint8 dmap; uint8 dmap;
bool direction; bool direction;
@ -104,14 +116,16 @@ struct {
uint8 xfermode; uint8 xfermode;
//$43x1 //$43x1
uint8 destaddr; uint8 destaddr;
//$43x2-$43x4 //$43x2-$43x3
uint32 srcaddr; uint16 srcaddr;
//$43x4
uint8 srcbank;
//$43x5-$43x6 //$43x5-$43x6
uint16 xfersize; uint16 xfersize;
//$43x7 //$43x7
uint8 hdma_indirect_bank; uint8 hdma_ibank;
//$43x8-$43x9 //$43x8-$43x9
uint32 hdma_taddr; uint16 hdma_addr;
//$43xa //$43xa
uint8 hdma_line_counter; uint8 hdma_line_counter;
//$43xb/$43xf //$43xb/$43xf
@ -120,43 +134,41 @@ struct {
//hdma-specific //hdma-specific
bool hdma_first_line; bool hdma_first_line;
bool hdma_repeat; bool hdma_repeat;
uint32 hdma_itaddr; uint16 hdma_iaddr;
bool hdma_completed; bool hdma_active;
}channel[8]; }channel[8];
inline bool hdma_test(); inline bool hdma_test();
inline bool nmi_test(); inline bool nmi_test();
inline bool irq_test(); inline bool irq_test();
inline void irq(uint16 addr); inline void irq(uint16 addr);
inline uint8 pio_status(); inline uint8 pio_status();
inline void run(); inline void run();
inline void scanline(); inline uint32 cycles_executed();
inline void frame(); inline void scanline();
inline void power(); inline void frame();
inline void reset(); inline void power();
inline void reset();
//dma commands //dma commands
inline void dma_run(); inline void dma_run();
inline void hdma_run(); inline void hdma_run();
inline void hdma_initialize(); inline void hdma_initialize();
inline uint16 dma_cputommio(uint8 i, uint8 index); inline void dma_cputommio(uint8 i, uint8 index);
inline uint16 dma_mmiotocpu(uint8 i, uint8 index); inline void dma_mmiotocpu(uint8 i, uint8 index);
inline void dma_xfer_type0(uint8 i); inline void dma_write(uint8 i, uint8 index);
inline void dma_xfer_type1(uint8 i); inline uint32 dma_addr(uint8 i);
inline void dma_xfer_type2(uint8 i); inline uint32 hdma_addr(uint8 i);
inline void dma_xfer_type3(uint8 i); inline uint32 hdma_iaddr(uint8 i);
inline void dma_xfer_type4(uint8 i);
inline void dma_xfer_type5(uint8 i);
inline void hdma_write(uint8 i, uint8 l, uint8 x); inline void hdma_write(uint8 i, uint8 l, uint8 x);
inline void dma_reset(); inline void dma_reset();
//mmio commands //mmio commands
void mmio_reset(); void mmio_reset();
uint8 mmio_r2180(); uint8 mmio_r2180();
uint8 mmio_r21c2();
uint8 mmio_r21c3();
uint8 mmio_r4016(); uint8 mmio_r4016();
uint8 mmio_r4017();
uint8 mmio_r4210(); uint8 mmio_r4210();
uint8 mmio_r4211(); uint8 mmio_r4211();
uint8 mmio_r4212(); uint8 mmio_r4212();
@ -212,8 +224,9 @@ struct {
void mmio_w43xb(uint8 value, uint8 i); void mmio_w43xb(uint8 value, uint8 i);
enum { CYCLE_OPREAD = 0, CYCLE_READ, CYCLE_WRITE, CYCLE_IO }; enum { CYCLE_OPREAD = 0, CYCLE_READ, CYCLE_WRITE, CYCLE_IO };
inline void exec_opcode(); inline void exec_cycle();
inline void cycle_edge(); inline void cycle_edge();
inline bool in_opcode();
//cpu extra-cycle conditions //cpu extra-cycle conditions
inline void cpu_c2(); inline void cpu_c2();

View File

@ -1,92 +1,46 @@
uint16 bCPU::dma_cputommio(uint8 i, uint8 index) { uint32 bCPU::dma_addr(uint8 i) {
uint8 x; uint32 r;
x = mem_bus->read(channel[i].srcaddr); r = channel[i].srcaddr;
mem_bus->write(0x2100 | ((channel[i].destaddr + index) & 0xff), x); r |= (channel[i].srcbank << 16);
if(channel[i].fixedxfer == false) { return r;
channel[i].srcaddr = (channel[i].srcaddr & 0xff0000) + ((channel[i].srcaddr + channel[i].incmode) & 0xffff);
}
add_cycles(8);
return --channel[i].xfersize;
} }
uint16 bCPU::dma_mmiotocpu(uint8 i, uint8 index) { void bCPU::dma_cputommio(uint8 i, uint8 index) {
uint8 x;
if(sdd1->dma_active() == true) {
x = sdd1->dma_read();
} else {
x = mem_bus->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;
}
add_cycles(8);
channel[i].xfersize--;
}
void bCPU::dma_mmiotocpu(uint8 i, uint8 index) {
uint8 x; uint8 x;
x = mem_bus->read(0x2100 | ((channel[i].destaddr + index) & 0xff)); x = mem_bus->read(0x2100 | ((channel[i].destaddr + index) & 0xff));
mem_bus->write(channel[i].srcaddr, x); mem_bus->write(dma_addr(i), x);
if(channel[i].fixedxfer == false) { if(channel[i].fixedxfer == false) {
channel[i].srcaddr = (channel[i].srcaddr & 0xff0000) + ((channel[i].srcaddr + channel[i].incmode) & 0xffff); channel[i].srcaddr += channel[i].incmode;
} }
add_cycles(8); add_cycles(8);
return --channel[i].xfersize; channel[i].xfersize--;
} }
void bCPU::dma_xfer_type0(uint8 i) { void bCPU::dma_write(uint8 i, uint8 index) {
if(channel[i].direction == 0) { if(channel[i].direction == 0) {
if(dma_cputommio(i, 0) == 0)return; dma_cputommio(i, index);
} else { } else {
if(dma_mmiotocpu(i, 0) == 0)return; dma_mmiotocpu(i, index);
}
}
void bCPU::dma_xfer_type1(uint8 i) {
if(channel[i].direction == 0) {
if(dma_cputommio(i, 0) == 0)return;
if(dma_cputommio(i, 1) == 0)return;
} else {
if(dma_mmiotocpu(i, 0) == 0)return;
if(dma_mmiotocpu(i, 1) == 0)return;
}
}
void bCPU::dma_xfer_type2(uint8 i) {
if(channel[i].direction == 0) {
if(dma_cputommio(i, 0) == 0)return;
if(dma_cputommio(i, 0) == 0)return;
} else {
if(dma_mmiotocpu(i, 0) == 0)return;
if(dma_mmiotocpu(i, 0) == 0)return;
}
}
void bCPU::dma_xfer_type3(uint8 i) {
if(channel[i].direction == 0) {
if(dma_cputommio(i, 0) == 0)return;
if(dma_cputommio(i, 0) == 0)return;
if(dma_cputommio(i, 1) == 0)return;
if(dma_cputommio(i, 1) == 0)return;
} else {
if(dma_mmiotocpu(i, 0) == 0)return;
if(dma_mmiotocpu(i, 0) == 0)return;
if(dma_mmiotocpu(i, 1) == 0)return;
if(dma_mmiotocpu(i, 1) == 0)return;
}
}
void bCPU::dma_xfer_type4(uint8 i) {
if(channel[i].direction == 0) {
if(dma_cputommio(i, 0) == 0)return;
if(dma_cputommio(i, 1) == 0)return;
if(dma_cputommio(i, 2) == 0)return;
if(dma_cputommio(i, 3) == 0)return;
} else {
if(dma_mmiotocpu(i, 0) == 0)return;
if(dma_mmiotocpu(i, 1) == 0)return;
if(dma_mmiotocpu(i, 2) == 0)return;
if(dma_mmiotocpu(i, 3) == 0)return;
}
}
void bCPU::dma_xfer_type5(uint8 i) {
if(channel[i].direction == 0) {
if(dma_cputommio(i, 0) == 0)return;
if(dma_cputommio(i, 1) == 0)return;
if(dma_cputommio(i, 0) == 0)return;
if(dma_cputommio(i, 1) == 0)return;
} else {
if(dma_mmiotocpu(i, 0) == 0)return;
if(dma_mmiotocpu(i, 1) == 0)return;
if(dma_mmiotocpu(i, 0) == 0)return;
if(dma_mmiotocpu(i, 1) == 0)return;
} }
} }
@ -95,17 +49,24 @@ int i;
for(i=0;i<8;i++) { for(i=0;i<8;i++) {
if(channel[i].active == false)continue; if(channel[i].active == false)continue;
switch(channel[i].xfermode) { //first byte transferred?
case 0:dma_xfer_type0(i);break; if(channel[i].read_index == 0) {
case 1:dma_xfer_type1(i);break; sdd1->dma_begin(i, dma_addr(i), channel[i].xfersize);
case 2:dma_xfer_type2(i);break;
case 3:dma_xfer_type3(i);break;
case 4:dma_xfer_type4(i);break;
case 5:dma_xfer_type5(i);break;
case 6:dma_xfer_type2(i);break;
case 7:dma_xfer_type3(i);break;
} }
switch(channel[i].xfermode) {
case 0:dma_write(i, 0); break; //0
case 1:dma_write(i, channel[i].read_index & 1); break; //0,1
case 2:dma_write(i, 0); break; //0,0
case 3:dma_write(i, (channel[i].read_index >> 1) & 1);break; //0,0,1,1
case 4:dma_write(i, channel[i].read_index & 3); break; //0,1,2,3
case 5:dma_write(i, channel[i].read_index & 1); break; //0,1,0,1
case 6:dma_write(i, 0); break; //0,0 [2]
case 7:dma_write(i, (channel[i].read_index >> 1) & 1);break; //0,0,1,1 [3]
}
channel[i].read_index++;
if(channel[i].xfersize == 0) { if(channel[i].xfersize == 0) {
channel[i].active = false; channel[i].active = false;
} }
@ -116,30 +77,54 @@ int i;
status.dma_state = DMASTATE_CPUSYNC; status.dma_state = DMASTATE_CPUSYNC;
} }
uint32 bCPU::hdma_addr(uint8 i) {
uint32 r;
r = channel[i].hdma_addr;
r |= (channel[i].srcbank << 16);
channel[i].hdma_addr++;
return r;
}
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;
}
void bCPU::hdma_write(uint8 i, uint8 l, uint8 x) { void bCPU::hdma_write(uint8 i, uint8 l, uint8 x) {
uint16 index;
switch(channel[i].xfermode) { switch(channel[i].xfermode) {
case 0:mem_bus->write(0x2100 | ((channel[i].destaddr) & 0xff), x);break; case 0:index = 0; break; //0
case 1:mem_bus->write(0x2100 | ((channel[i].destaddr + l) & 0xff), x);break; case 1:index = l & 1; break; //0,1
case 2:mem_bus->write(0x2100 | ((channel[i].destaddr) & 0xff), x);break; case 2:index = 0; break; //0,0
case 3:mem_bus->write(0x2100 | ((channel[i].destaddr + (l >> 1)) & 0xff), x);break; case 3:index = (l >> 1) & 1;break; //0,0,1,1
case 4:mem_bus->write(0x2100 | ((channel[i].destaddr + l) & 0xff), x);break; case 4:index = l & 3; break; //0,1,2,3
case 5:mem_bus->write(0x2100 | ((channel[i].destaddr + (l & 1)) & 0xff), x);break; case 5:index = l & 1; break; //0,1,0,1
case 6:mem_bus->write(0x2100 | ((channel[i].destaddr) & 0xff), x);break; case 6:index = 0; break; //0,0 [2]
case 7:mem_bus->write(0x2100 | ((channel[i].destaddr + (l >> 1)) & 0xff), x);break; case 7:index = (l >> 1) & 1;break; //0,0,1,1 [3]
} }
index = 0x2100 | ((channel[i].destaddr + index) & 0xff);
mem_bus->write(index, x);
} }
void bCPU::hdma_run() { void bCPU::hdma_run() {
int l, xferlen; int l, xferlen;
uint8 x, active_channels = 0; uint8 x, active_channels = 0;
static hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
for(int i=0;i<8;i++) { for(int i=0;i<8;i++) {
if(channel[i].hdma_completed == true)continue; if(channel[i].hdma_active == false)continue;
// add_cycles(8);
// add_cycles(8);
active_channels++; active_channels++;
if(channel[i].hdma_line_counter == 0) { if(channel[i].hdma_line_counter == 0) {
channel[i].hdma_line_counter = mem_bus->read(channel[i].hdma_taddr++); channel[i].hdma_line_counter = mem_bus->read(hdma_addr(i));
if(channel[i].hdma_line_counter == 0) { if(channel[i].hdma_line_counter == 0) {
channel[i].hdma_completed = true; channel[i].hdma_active = false;
continue; continue;
} }
@ -151,13 +136,11 @@ uint8 x, active_channels = 0;
} }
channel[i].hdma_first_line = true; channel[i].hdma_first_line = true;
if(channel[i].hdma_indirect == false) {
channel[i].hdma_itaddr = channel[i].hdma_taddr; if(channel[i].hdma_indirect == true) {
} else { channel[i].hdma_iaddr = mem_bus->read(hdma_addr(i));
channel[i].hdma_itaddr = mem_bus->read(channel[i].hdma_taddr++); channel[i].hdma_iaddr |= mem_bus->read(hdma_addr(i)) << 8;
channel[i].hdma_itaddr |= mem_bus->read(channel[i].hdma_taddr++) << 8; // add_cycles(16);
channel[i].hdma_itaddr |= channel[i].hdma_indirect_bank << 16;
// add_cycles(16);
} }
} }
@ -165,44 +148,39 @@ uint8 x, active_channels = 0;
if(channel[i].hdma_first_line == false && channel[i].hdma_repeat == false)continue; if(channel[i].hdma_first_line == false && channel[i].hdma_repeat == false)continue;
channel[i].hdma_first_line = false; channel[i].hdma_first_line = false;
if(channel[i].hdma_indirect == false) { xferlen = hdma_xferlen[channel[i].xfermode];
channel[i].hdma_itaddr = channel[i].hdma_taddr;
}
switch(channel[i].xfermode) {
case 0: xferlen = 1;break;
case 1:case 2:case 6: xferlen = 2;break;
case 3:case 4:case 5:case 7:xferlen = 4;break;
}
for(l=0;l<xferlen;l++) { for(l=0;l<xferlen;l++) {
x = mem_bus->read(channel[i].hdma_itaddr++);
if(channel[i].hdma_indirect == false) { if(channel[i].hdma_indirect == false) {
channel[i].hdma_taddr++; x = mem_bus->read(hdma_addr(i));
} else {
x = mem_bus->read(hdma_iaddr(i));
} }
hdma_write(i, l, x); hdma_write(i, l, x);
// add_cycles(8); // add_cycles(8);
} }
} }
if(active_channels != 0) { if(active_channels != 0) {
// add_cycles(18); // add_cycles(18);
} }
} }
void bCPU::hdma_initialize() { void bCPU::hdma_initialize() {
uint8 active_channels = 0; uint8 active_channels = 0;
for(int i=0;i<8;i++) { for(int i=0;i<8;i++) {
if(channel[i].hdma_active == false) { //does this happen when $420c channel bit is clear?
channel[i].hdma_completed = true; channel[i].hdma_addr = channel[i].srcaddr;
channel[i].hdma_line_counter = 0x00;
if(channel[i].hdma_enabled == false) {
channel[i].hdma_active = false;
continue; continue;
} }
channel[i].hdma_active = true;
active_channels++; active_channels++;
channel[i].hdma_first_line = true;
channel[i].hdma_repeat = false;
channel[i].hdma_taddr = channel[i].srcaddr;
channel[i].hdma_line_counter = 0x00;
channel[i].hdma_completed = false;
if(channel[i].hdma_indirect == false) { if(channel[i].hdma_indirect == false) {
add_cycles(8); add_cycles(8);
} else { } else {
@ -217,25 +195,26 @@ uint8 active_channels = 0;
void bCPU::dma_reset() { void bCPU::dma_reset() {
for(int i=0;i<8;i++) { for(int i=0;i<8;i++) {
channel[i].active = false; channel[i].read_index = 0;
channel[i].hdma_active = false; channel[i].active = false;
channel[i].dmap = 0x00; channel[i].hdma_enabled = false;
channel[i].direction = 0; channel[i].dmap = 0x00;
channel[i].hdma_indirect = false; channel[i].direction = 0;
channel[i].incmode = 1; channel[i].hdma_indirect = false;
channel[i].fixedxfer = false; channel[i].incmode = 1;
channel[i].xfermode = 0; channel[i].fixedxfer = false;
channel[i].destaddr = 0; channel[i].xfermode = 0;
channel[i].srcaddr = 0; channel[i].destaddr = 0;
channel[i].xfersize = 0; channel[i].srcaddr = 0;
channel[i].hdma_indirect_bank = 0; channel[i].xfersize = 0;
channel[i].hdma_taddr = 0x000000; channel[i].hdma_ibank = 0;
channel[i].hdma_line_counter = 0x00; channel[i].hdma_addr = 0x0000;
channel[i].hdma_unknown = 0x00; channel[i].hdma_line_counter = 0x00;
channel[i].hdma_unknown = 0x00;
channel[i].hdma_first_line = false; channel[i].hdma_active = false;
channel[i].hdma_repeat = false; channel[i].hdma_first_line = false;
channel[i].hdma_itaddr = 0x000000; channel[i].hdma_repeat = false;
channel[i].hdma_completed = true; channel[i].hdma_iaddr = 0x0000;
} }
} }

View File

@ -2,10 +2,10 @@ inline void bCPU::cycle_edge() {
int c, n, z; int c, n, z;
if(status.dma_state != DMASTATE_STOP) { if(status.dma_state != DMASTATE_STOP) {
switch(status.dma_state) { switch(status.dma_state) {
case DMASTATE_INIT:
status.dma_state = DMASTATE_DMASYNC;
break;
case DMASTATE_DMASYNC: case DMASTATE_DMASYNC:
status.dma_state = DMASTATE_DMASYNC2;
break;
case DMASTATE_DMASYNC2:
n = 8 - dma_counter() + 8; n = 8 - dma_counter() + 8;
add_cycles(n); add_cycles(n);
status.dma_cycle_count = n; status.dma_cycle_count = n;
@ -13,14 +13,18 @@ int c, n, z;
if(channel[z].active == false)continue; if(channel[z].active == false)continue;
add_cycles(8); add_cycles(8);
status.dma_cycle_count += 8; status.dma_cycle_count += 8;
status.dma_cycle_count += channel[z].xfersize << 3;
} }
status.cpu_state = CPUSTATE_DMA; status.cpu_state = CPUSTATE_DMA;
status.dma_state = DMASTATE_RUN; status.dma_state = DMASTATE_RUN;
while(status.dma_state == DMASTATE_RUN) { break;
dma_run(); case DMASTATE_RUN:
} status.dma_cycle_count += 8;
break;
case DMASTATE_CPUSYNC:
status.cpu_state = CPUSTATE_RUN; status.cpu_state = CPUSTATE_RUN;
status.dma_state = DMASTATE_CPUSYNC2;
break;
case DMASTATE_CPUSYNC2:
c = status.cycle_count; c = status.cycle_count;
z = c - (status.dma_cycle_count % c); z = c - (status.dma_cycle_count % c);
if(!z)z = c; if(!z)z = c;
@ -31,10 +35,22 @@ int c, n, z;
} }
} }
void bCPU::exec_opcode() { void bCPU::exec_cycle() {
snes->notify(SNES::CPU_EXEC_OPCODE_BEGIN); if(status.cycle_pos == 0) {
(this->*optbl[op_read()])(); snes->notify(SNES::CPU_EXEC_OPCODE_BEGIN);
snes->notify(SNES::CPU_EXEC_OPCODE_END); status.opcode = op_read();
status.cycle_pos = 1;
} else {
(this->*optbl[status.opcode])();
if(status.cycle_pos == 0) {
snes->notify(SNES::CPU_EXEC_OPCODE_END);
}
}
}
//only return true when we are on an opcode edge
bool bCPU::in_opcode() {
return (status.cycle_pos != 0);
} }
void bCPU::init_op_tables() { void bCPU::init_op_tables() {

View File

@ -41,16 +41,7 @@ uint8 r;
return r; return r;
} }
//??? //JOYSER0
uint8 bCPU::mmio_r21c2() {
return 0x20;
}
//???
uint8 bCPU::mmio_r21c3() {
return 0x00;
}
/* /*
The joypad contains a small bit shifter that has 16 bits. The joypad contains a small bit shifter that has 16 bits.
Reading from 4016 reads one bit from this buffer, then moves Reading from 4016 reads one bit from this buffer, then moves
@ -61,9 +52,12 @@ uint8 bCPU::mmio_r21c3() {
A zero must be written back to $4016 to unlock the buffer, A zero must be written back to $4016 to unlock the buffer,
so that reads will increment the bit shifting position. so that reads will increment the bit shifting position.
*/ */
//JOYSER0 //7-2 = MDR
//1-0 = Joypad serial data
uint8 bCPU::mmio_r4016() { uint8 bCPU::mmio_r4016() {
uint8 r = 0x00; uint8 r;
r = regs.mdr & 0xfc;
if(status.joypad1_strobe_value == 1) { if(status.joypad1_strobe_value == 1) {
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_B); r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_B);
} else { } else {
@ -85,45 +79,85 @@ uint8 r = 0x00;
} }
if(++status.joypad1_read_pos > 17)status.joypad1_read_pos = 17; if(++status.joypad1_read_pos > 17)status.joypad1_read_pos = 17;
} }
return r;
}
//JOYSER1
//7-5 = MDR
//4-2 = Always 1
//1-0 = Joypad serial data
uint8 bCPU::mmio_r4017() {
uint8 r;
r = regs.mdr & 0xe0;
r |= 0x1c;
return r; return r;
} }
//RDNMI //RDNMI
/* $4210 bit 7 (NMI triggered bit) is set at:
* V=225/240,HC>=2,
* V>225
* The bit is only set once per NMI trigger, so
* subsequent reads return this bit as being clear.
* There is but one exception: if the $4210 read
* occurs at *exactly* V=225/240,HC==2, then $4210
* bit 7 will be set, and the next read will also
* have this bit set.
*/
//7 = NMI acknowledge
//6-4 = MDR
//3-0 = CPU (5a22) version
uint8 bCPU::mmio_r4210() { uint8 bCPU::mmio_r4210() {
uint8 r = 0x00; uint8 r;
uint16 v, h, hc, vs; uint16 v, h, hc, vs;
r = regs.mdr & 0x70;
v = vcounter(); v = vcounter();
h = hcounter(); h = hcounter();
hc = hcycles(); hc = hcycles();
vs = (overscan()?239:224); vs = (overscan()?239:224);
if(status.r4210_read == false) { if(status.nmi_read == false) {
if((v == (vs + 1) && hc >= 2) || v > (vs + 1)) { if(
(v == (vs + 1) && hc >= 2) ||
(v > (vs + 1))
) {
r |= 0x80; r |= 0x80;
status.r4210_read = true;
status.nmi_pin = 1; //test for special case where NMI read not raised
if(v != (vs + 1) || hc != 2) {
status.nmi_read = true;
}
} }
} }
r |= 0x40;
r |= 0x02; //cpu version number r |= 0x02; //cpu version number
return r; return r;
} }
//TIMEUP //TIMEUP
//7 = IRQ acknowledge
//6-0 = MDR
uint8 bCPU::mmio_r4211() { uint8 bCPU::mmio_r4211() {
uint8 r = 0x00; uint8 r;
r |= 0x40; r = regs.mdr & 0x7f;
if(status.irq_triggered == true)r |= 0x80; if(status.irq_exec == true)r |= 0x80;
status.irq_triggered = false; status.irq_exec = false;
status.irq_read = true;
return r; return r;
} }
//HVBJOY //HVBJOY
//7 = in vblank
//6 = in hblank
//5-1 = MDR
//0 = joypad ready
uint8 bCPU::mmio_r4212() { uint8 bCPU::mmio_r4212() {
uint8 r; uint8 r;
uint16 v, h, hc, vs; uint16 v, h, hc, vs;
r = 0x00; r = regs.mdr & 0x3e;
v = vcounter(); v = vcounter();
h = hcounter(); h = hcounter();
@ -168,7 +202,7 @@ uint8 bCPU::mmio_r4217() {
//JOY1L //JOY1L
uint8 bCPU::mmio_r4218() { uint8 bCPU::mmio_r4218() {
uint8 r = 0x00; uint8 r = 0x00;
uint16 v = vcounter(); uint16 v = vcounter();
if(status.auto_joypad_poll == false)return 0x00; //can't read joypad if auto polling not enabled 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 //if(v >= 225 && v <= 227)return 0x00; //can't read joypad while SNES is polling input
@ -181,7 +215,7 @@ uint16 v = vcounter();
//JOY1H //JOY1H
uint8 bCPU::mmio_r4219() { uint8 bCPU::mmio_r4219() {
uint8 r = 0x00; uint8 r = 0x00;
uint16 v = vcounter(); uint16 v = vcounter();
if(status.auto_joypad_poll == false)return 0x00; //can't read joypad if auto polling not enabled 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 //if(v >= 225 && v <= 227)return 0x00; //can't read joypad while SNES is polling input
@ -218,7 +252,7 @@ uint8 bCPU::mmio_r43x3(uint8 i) {
//A1Bx //A1Bx
uint8 bCPU::mmio_r43x4(uint8 i) { uint8 bCPU::mmio_r43x4(uint8 i) {
return channel[i].srcaddr >> 16; return channel[i].srcbank;
} }
//DASxL //DASxL
@ -233,17 +267,17 @@ uint8 bCPU::mmio_r43x6(uint8 i) {
//DASBx //DASBx
uint8 bCPU::mmio_r43x7(uint8 i) { uint8 bCPU::mmio_r43x7(uint8 i) {
return channel[i].hdma_indirect_bank; return channel[i].hdma_ibank;
} }
//A2AxL //A2AxL
uint8 bCPU::mmio_r43x8(uint8 i) { uint8 bCPU::mmio_r43x8(uint8 i) {
return channel[i].hdma_taddr; return channel[i].hdma_addr;
} }
//A2AxH //A2AxH
uint8 bCPU::mmio_r43x9(uint8 i) { uint8 bCPU::mmio_r43x9(uint8 i) {
return channel[i].hdma_taddr >> 8; return channel[i].hdma_addr >> 8;
} }
//NTRLx //NTRLx
@ -281,19 +315,17 @@ uint8 i;
case 0x9:return cpu->mmio_r43x9(i); case 0x9:return cpu->mmio_r43x9(i);
case 0xa:return cpu->mmio_r43xa(i); case 0xa:return cpu->mmio_r43xa(i);
case 0xb:return cpu->mmio_r43xb(i); case 0xb:return cpu->mmio_r43xb(i);
case 0xc:return 0x43; //unmapped case 0xc:return cpu->regs.mdr; //unmapped
case 0xd:return 0x43; //unmapped case 0xd:return cpu->regs.mdr; //unmapped
case 0xe:return 0x43; //unmapped case 0xe:return cpu->regs.mdr; //unmapped
case 0xf:return cpu->mmio_r43xb(i); //mirror of 43xb case 0xf:return cpu->mmio_r43xb(i); //mirror of 43xb
} }
} }
switch(addr) { switch(addr) {
case 0x2180:return cpu->mmio_r2180(); //WMDATA case 0x2180:return cpu->mmio_r2180(); //WMDATA
case 0x21c2:return cpu->mmio_r21c2(); //???
case 0x21c3:return cpu->mmio_r21c3(); //???
case 0x2800:return cpu->srtc_read();
case 0x4016:return cpu->mmio_r4016(); //JOYSER0 case 0x4016:return cpu->mmio_r4016(); //JOYSER0
case 0x4017:return cpu->mmio_r4017(); //JOYSER1
case 0x4210:return cpu->mmio_r4210(); //RDNMI case 0x4210:return cpu->mmio_r4210(); //RDNMI
case 0x4211:return cpu->mmio_r4211(); //TIMEUP case 0x4211:return cpu->mmio_r4211(); //TIMEUP
case 0x4212:return cpu->mmio_r4212(); //HVBJOY case 0x4212:return cpu->mmio_r4212(); //HVBJOY
@ -306,7 +338,8 @@ uint8 i;
case 0x4219:return cpu->mmio_r4219(); //JOY1H case 0x4219:return cpu->mmio_r4219(); //JOY1H
case 0x421a:case 0x421b:case 0x421c:case 0x421d:case 0x421e:case 0x421f:return 0x00; case 0x421a:case 0x421b:case 0x421c:case 0x421d:case 0x421e:case 0x421f:return 0x00;
} }
return 0x00;
return cpu->regs.mdr;
} }
//WMDATA //WMDATA
@ -351,11 +384,12 @@ void bCPU::mmio_w4200(uint8 value) {
status.auto_joypad_poll = !!(value & 0x01); status.auto_joypad_poll = !!(value & 0x01);
if(status.nmi_enabled == false) { if(status.nmi_enabled == false) {
status.nmi_pin = 0; status.nmi_read = false;
} }
if(status.virq_enabled == false && status.hirq_enabled == false) { status.irq_exec = false;
status.irq_pin = 0; if(status.virq_enabled == true || status.hirq_enabled == true) {
status.irq_read = false;
} }
} }
@ -397,37 +431,40 @@ void bCPU::mmio_w4206(uint8 value) {
//HTIMEL //HTIMEL
void bCPU::mmio_w4207(uint8 value) { void bCPU::mmio_w4207(uint8 value) {
status.hirq_pos = (status.hirq_pos & 0xff00) | value; status.hirq_pos = (status.hirq_pos & 0xff00) | value;
if(status.irq_triggered == false)status.irq_pin = 1; status.irq_read = false;
} }
//HTIMEH //HTIMEH
void bCPU::mmio_w4208(uint8 value) { void bCPU::mmio_w4208(uint8 value) {
status.hirq_pos = (status.hirq_pos & 0x00ff) | (value << 8); status.hirq_pos = (status.hirq_pos & 0x00ff) | (value << 8);
if(status.irq_triggered == false)status.irq_pin = 1; status.irq_read = false;
} }
//VTIMEL //VTIMEL
void bCPU::mmio_w4209(uint8 value) { void bCPU::mmio_w4209(uint8 value) {
status.virq_pos = (status.virq_pos & 0xff00) | value; status.virq_pos = (status.virq_pos & 0xff00) | value;
if(status.irq_triggered == false)status.irq_pin = 1; status.irq_read = false;
} }
//VTIMEH //VTIMEH
void bCPU::mmio_w420a(uint8 value) { void bCPU::mmio_w420a(uint8 value) {
status.virq_pos = (status.virq_pos & 0x00ff) | (value << 8); status.virq_pos = (status.virq_pos & 0x00ff) | (value << 8);
if(status.irq_triggered == false)status.irq_pin = 1; status.irq_read = false;
} }
//DMAEN //DMAEN
void bCPU::mmio_w420b(uint8 value) { void bCPU::mmio_w420b(uint8 value) {
int len;
if(value != 0x00) { if(value != 0x00) {
status.dma_state = DMASTATE_INIT; status.dma_state = DMASTATE_DMASYNC;
} }
for(int i=0;i<8;i++) { for(int i=0;i<8;i++) {
if(value & (1 << i)) { if(value & (1 << i)) {
channel[i].active = true; channel[i].active = true;
channel[i].hdma_active = false; channel[i].hdma_enabled = false;
channel[i].hdma_active = false;
channel[i].read_index = 0;
} }
} }
} }
@ -435,7 +472,8 @@ void bCPU::mmio_w420b(uint8 value) {
//HDMAEN //HDMAEN
void bCPU::mmio_w420c(uint8 value) { void bCPU::mmio_w420c(uint8 value) {
for(int i=0;i<8;i++) { for(int i=0;i<8;i++) {
channel[i].hdma_active = !!(value & (1 << i)); channel[i].hdma_enabled = !!(value & (1 << i));
channel[i].hdma_active = !!(value & (1 << i));
} }
} }
@ -461,17 +499,17 @@ void bCPU::mmio_w43x1(uint8 value, uint8 i) {
//A1TxL //A1TxL
void bCPU::mmio_w43x2(uint8 value, uint8 i) { void bCPU::mmio_w43x2(uint8 value, uint8 i) {
channel[i].srcaddr = (channel[i].srcaddr & 0xffff00) | value; channel[i].srcaddr = (channel[i].srcaddr & 0xff00) | value;
} }
//A1TxH //A1TxH
void bCPU::mmio_w43x3(uint8 value, uint8 i) { void bCPU::mmio_w43x3(uint8 value, uint8 i) {
channel[i].srcaddr = (channel[i].srcaddr & 0xff00ff) | (value << 8); channel[i].srcaddr = (channel[i].srcaddr & 0x00ff) | (value << 8);
} }
//A1Bx //A1Bx
void bCPU::mmio_w43x4(uint8 value, uint8 i) { void bCPU::mmio_w43x4(uint8 value, uint8 i) {
channel[i].srcaddr = (channel[i].srcaddr & 0x00ffff) | (value << 16); channel[i].srcbank = value;
} }
//DASxL //DASxL
@ -486,17 +524,17 @@ void bCPU::mmio_w43x6(uint8 value, uint8 i) {
//DASBx //DASBx
void bCPU::mmio_w43x7(uint8 value, uint8 i) { void bCPU::mmio_w43x7(uint8 value, uint8 i) {
channel[i].hdma_indirect_bank = value; channel[i].hdma_ibank = value;
} }
//A2AxL //A2AxL
void bCPU::mmio_w43x8(uint8 value, uint8 i) { void bCPU::mmio_w43x8(uint8 value, uint8 i) {
channel[i].hdma_taddr = (channel[i].hdma_taddr & 0xffff00) | value; channel[i].hdma_addr = (channel[i].hdma_addr & 0xff00) | value;
} }
//A2AxH //A2AxH
void bCPU::mmio_w43x9(uint8 value, uint8 i) { void bCPU::mmio_w43x9(uint8 value, uint8 i) {
channel[i].hdma_taddr = (channel[i].hdma_taddr & 0xff00ff) | (value << 8); channel[i].hdma_addr = (channel[i].hdma_addr & 0x00ff) | (value << 8);
} }
//NTRLx //NTRLx
@ -547,7 +585,6 @@ uint8 i;
case 0x2181:cpu->mmio_w2181(value);return; //WMADDL case 0x2181:cpu->mmio_w2181(value);return; //WMADDL
case 0x2182:cpu->mmio_w2182(value);return; //WMADDM case 0x2182:cpu->mmio_w2182(value);return; //WMADDM
case 0x2183:cpu->mmio_w2183(value);return; //WMADDH case 0x2183:cpu->mmio_w2183(value);return; //WMADDH
case 0x2801:cpu->srtc_write(value);return;
case 0x4016:cpu->mmio_w4016(value);return; //JOYSER0 case 0x4016:cpu->mmio_w4016(value);return; //JOYSER0
case 0x4200:cpu->mmio_w4200(value);return; //NMITIMEN case 0x4200:cpu->mmio_w4200(value);return; //NMITIMEN
case 0x4201:cpu->mmio_w4201(value);return; //WRIO case 0x4201:cpu->mmio_w4201(value);return; //WRIO

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,21 +1,55 @@
uint16 bCPU::vcounter() { return time.v; } /* Notes about PAL timing:
uint16 bCPU::hcounter() { return get_hcounter(); } * As I do not have PAL hardware to run timing tests on, I've
uint16 bCPU::hcycles() { return time.hc; } * had to guess on a lot of things. Below is how I've arrived
bool bCPU::interlace() { return time.interlace; } * at various calculations:
bool bCPU::interlace_field() { return time.interlace_field; } *
bool bCPU::overscan() { return time.overscan; } * NTSC timing crystal: ~21477272hz
* PAL timing crystal: ~21281370hz
* NTSC ~60fps, PAL ~50fps
* NTSC ~262 lines/frame, PAL ~312 lines/frame
* NTSC 21477272 / (262 * 60) = ~1366 cycles/line
* PAL 21281370 / (312 * 50) = ~1364 cycles/line
*
* As the cycles/line are very close between the two systems,
* I have left the known NTSC anomalies intact for PAL timing.
* In reality, some of these may not exist, and some may be
* slightly different.
*
* [known]
* - DRAM refresh occurs at about the same time every
* scanline on PAL units (per Overload).
* [unknown]
* - Are dots 323/327 still 2 cycles longer than the
* other dots?
* - Is scanline 240 on non-interlace odd frames still
* 4 cycles short?
*/
uint16 bCPU::vcounter() { return time.v; }
uint16 bCPU::hcounter() { return get_hcounter(); }
uint16 bCPU::hcycles() { return time.hc; }
bool bCPU::interlace() { return time.interlace; }
bool bCPU::interlace_field() { return time.interlace_field; }
bool bCPU::overscan() { return time.overscan; }
uint16 bCPU::region_scanlines() { return time.region_scanlines; }
void bCPU::set_interlace(bool r) { time.interlace = r; } void bCPU::set_interlace(bool r) { time.interlace = r; }
void bCPU::set_overscan(bool r) { time.overscan = r; } void bCPU::set_overscan(bool r) { time.overscan = r; }
uint8 bCPU::dma_counter() { return (time.dma_counter + time.hc) & 6; } uint8 bCPU::dma_counter() { return (time.dma_counter + time.hc) & 6; }
//all scanlines are 1364 cycles long, except scanline 240 //all scanlines are 1364 cycles long, except scanline 240
//on non-interlace odd-frames, which is 1360 cycles long. //on non-interlace odd-frames, which is 1360 cycles long.
//[NTSC]
//interlace mode has 525 scanlines: 263 on the even frame, //interlace mode has 525 scanlines: 263 on the even frame,
//and 262 on the odd. //and 262 on the odd.
//non-interlace mode has 524 scanlines: 262 scanlines on //non-interlace mode has 524 scanlines: 262 scanlines on
//both even and odd frames. //both even and odd frames.
//[PAL] <PAL info is unverified on hardware>
//interlace mode has 625 scanlines: 313 on the even frame,
//and 312 on the odd.
//non-interlace mode has 624 scanlines: 312 scanlines on
//both even and odd frames.
// //
//cycles per frame: //cycles per frame:
// 263 * 1364 = 358732 // 263 * 1364 = 358732
@ -28,9 +62,9 @@ void bCPU::inc_vcounter() {
time.interlace_field ^= 1; time.interlace_field ^= 1;
if(time.interlace == true && time.interlace_field == 0) { if(time.interlace == true && time.interlace_field == 0) {
time.frame_lines = 263; time.frame_lines = time.region_scanlines + 1;
} else { } else {
time.frame_lines = 262; time.frame_lines = time.region_scanlines;
} }
} }
@ -44,31 +78,19 @@ void bCPU::inc_vcounter() {
time.dram_refreshed = false; time.dram_refreshed = false;
} }
//all dots are 4 cycles long, except dots 322 and 326. dots 322 and 326 //all dots are 4 cycles long, except dots 323 and 327. dots 323 and 327
//are 6 cycles long. this holds true for all scanlines except scanline //are 6 cycles long. this holds true for all scanlines except scanline
//240 on non-interlace odd frames. the reason for this is because this //240 on non-interlace odd frames. the reason for this is because this
//scanline is only 1360 cycles long, instead of 1364 like all other //scanline is only 1360 cycles long, instead of 1364 like all other
//scanlines. //scanlines.
//this makes the effective range of hscan_pos 0-339 at all times. //this makes the effective range of hscan_pos 0-339 at all times.
//dot 322 range = { 1288, 1290, 1292 } //dot 323 range = { 1292, 1294, 1296 }
//dot 326 range = { 1306, 1308, 1310 } //dot 327 range = { 1310, 1312, 1314 }
uint16 bCPU::get_hcounter() { uint16 bCPU::get_hcounter() {
if(time.v == 240 && time.interlace == false && time.interlace_field == 1) { if(time.v == 240 && time.interlace == false && time.interlace_field == 1) {
return time.hc >> 2; return time.hc >> 2;
} }
return (time.hc - ((time.hc > 1288) << 1) - ((time.hc > 1306) << 1)) >> 2; return (time.hc - ((time.hc > 1292) << 1) - ((time.hc > 1310) << 1)) >> 2;
}
void bCPU::apu_sync() {
int cycles;
while(apusync.cycles >= 0) {
apu->run();
cycles = apu->cycles_executed();
if(cycles) {
apusync.cycles -= apusync.cpu_multbl[cycles];
}
}
} }
void bCPU::dram_refresh() { void bCPU::dram_refresh() {
@ -76,15 +98,22 @@ void bCPU::dram_refresh() {
add_cycles(40); add_cycles(40);
if(time.v != 240 || time.interlace != false || time.interlace_field != 1) { if(time.v != 240 || time.interlace != false || time.interlace_field != 1) {
//alternate between 534 and 538 every scanline except 240ni1 //alternate between 534 and 538 every scanline except 240ni1
//in reality, this is probably based on frame cycle length...
time.dram_refresh_pos ^= 12; time.dram_refresh_pos ^= 12;
} }
} }
uint32 bCPU::cycles_executed() {
uint32 r = status.cycles_executed;
status.cycles_executed = 0;
return r;
}
void bCPU::add_cycles(int cycles) { void bCPU::add_cycles(int cycles) {
status.cycles_executed += cycles;
cycles >>= 1; cycles >>= 1;
while(cycles--) { while(cycles--) {
apusync.cycles += apusync.apu_freq << 1;
apu_sync();
time.hc += 2; time.hc += 2;
if(time.hc >= time.line_cycles) { if(time.hc >= time.line_cycles) {
@ -119,23 +148,20 @@ void bCPU::time_reset() {
time.interlace_field = false; time.interlace_field = false;
time.overscan = false; time.overscan = false;
time.line_cycles = 1364; time.line_cycles = 1364;
time.frame_lines = 262;
time.dram_refreshed = false; time.dram_refreshed = false;
time.dram_refresh_pos = 538; time.dram_refresh_pos = 538;
time.dma_counter = 0; time.dma_counter = 0;
apusync.cycles = apusync.cpu_multbl[255]; switch(region) {
} case NTSC:
time.region_scanlines = 262;
void bCPU::time_init() { break;
apusync.cpu_freq = 21477272 >> 3; case PAL:
apusync.apu_freq = 24576000 >> 3; time.region_scanlines = 312;
break;
int i;
for(i=0;i<1024;i++) {
apusync.cpu_multbl[i] = i * apusync.cpu_freq;
apusync.apu_multbl[i] = i * apusync.apu_freq;
} }
time.frame_lines = time.region_scanlines;
} }

View File

@ -8,6 +8,8 @@ struct {
uint16 dram_refresh_pos; uint16 dram_refresh_pos;
uint8 dma_counter; uint8 dma_counter;
uint16 region_scanlines;
}time; }time;
inline uint16 vcounter(); inline uint16 vcounter();
@ -16,6 +18,7 @@ inline uint16 hcycles();
inline bool interlace(); inline bool interlace();
inline bool interlace_field(); inline bool interlace_field();
inline bool overscan(); inline bool overscan();
inline uint16 region_scanlines();
inline void set_interlace(bool r); inline void set_interlace(bool r);
inline void set_overscan (bool r); inline void set_overscan (bool r);
@ -24,15 +27,6 @@ inline uint8 dma_counter();
inline void inc_vcounter(); inline void inc_vcounter();
inline uint16 get_hcounter(); inline uint16 get_hcounter();
inline void apu_sync();
inline void dram_refresh(); inline void dram_refresh();
inline void add_cycles(int cycles); inline void add_cycles(int cycles);
inline void time_reset(); inline void time_reset();
inline void time_init();
//APU synchronization
struct {
int32 cpu_freq, apu_freq;
int32 cpu_multbl[1024], apu_multbl[1024];
int32 cycles;
}apusync;

View File

@ -44,7 +44,7 @@ char t[4096];
i++; i++;
} }
sprintf(output_op, "void bCPU::op_$$() {\r\n"); sprintf(output_op, "void bCPU::op_$$() {\r\n switch(status.cycle_pos++) {\r\n");
sprintf(output_header, "void op_$$();\r\n"); sprintf(output_header, "void op_$$();\r\n");
sprintf(output_table, "optbl[$0] = &bCPU::op_$$;\r\n"); sprintf(output_table, "optbl[$0] = &bCPU::op_$$;\r\n");
@ -54,8 +54,8 @@ char t[4096];
void update_line(int i, int n) { void update_line(int i, int n) {
char t[4096]; char t[4096];
sprintf(t, "goto l%d;", n + 2); sprintf(t, "goto l%d;", n + 2);
replace(line[i], "end;", "return;"); replace(line[i], "end;", "status.cycle_pos = 0;");
replace(line[i], "skip;", t); replace(line[i], "skip;", "status.cycle_pos++;");
} }
void gen_op() { void gen_op() {
@ -67,12 +67,12 @@ char t[4096];
n = strdec(line[i]); n = strdec(line[i]);
sprintf(t, "%d:", n); sprintf(t, "%d:", n);
strltrim(line[i], t); strltrim(line[i], t);
sprintf(t, "l%d:\r\n", n); sprintf(t, " case %d:\r\n", n);
strcat(output_op, t); strcat(output_op, t);
update_line(i, n); update_line(i, n);
if(strcmp(line[i], "")) { if(strcmp(line[i], "")) {
strcat(output_op, " "); strcat(output_op, " ");
strcat(output_op, line[i]); strcat(output_op, line[i]);
strcat(output_op, "\r\n"); strcat(output_op, "\r\n");
} }
@ -82,13 +82,16 @@ char t[4096];
if((strptr(line[i])[1]) == ':' || !strcmp(line[i], "}"))break; if((strptr(line[i])[1]) == ':' || !strcmp(line[i], "}"))break;
update_line(i, n); update_line(i, n);
strcat(output_op, " ");
strcat(output_op, line[i]); strcat(output_op, line[i]);
strcat(output_op, "\r\n"); strcat(output_op, "\r\n");
i++; i++;
} }
if(!strcmp(line[i], "}"))strcat(output_op, " status.cycle_pos = 0;\r\n");
strcat(output_op, " break;\r\n");
} }
strcat(output_op, "}"); strcat(output_op, " }\r\n}");
line_num = i + 1; line_num = i + 1;
} }
@ -107,16 +110,16 @@ int i, l;
replace(t, "$5", op_list[i].arg[5]); replace(t, "$5", op_list[i].arg[5]);
replace(t, "$6", op_list[i].arg[6]); replace(t, "$6", op_list[i].arg[6]);
replace(t, "$7", op_list[i].arg[7]); replace(t, "$7", op_list[i].arg[7]);
fprintf(fp, "%s\r\n\r\n", *t); fprintf(fp, "%s\r\n\r\n", strptr(t));
strcpy(t, output_header); strcpy(t, output_header);
replace(t, "$$", op_list[i].name); replace(t, "$$", op_list[i].name);
fprintf(fph, "%s", *t); fprintf(fph, "%s", strptr(t));
strcpy(t, output_table); strcpy(t, output_table);
replace(t, "$$", op_list[i].name); replace(t, "$$", op_list[i].name);
replace(t, "$0", op_list[i].arg[0]); replace(t, "$0", op_list[i].arg[0]);
fprintf(fpt, "%s", *t); fprintf(fpt, "%s", strptr(t));
} }
} }

Binary file not shown.

View File

@ -3,8 +3,7 @@ nop(0xea) {
} }
wdm(0x42) { wdm(0x42) {
1:cpu_io(); 1:op_read();
regs.pc.w++;
} }
xba(0xeb) { xba(0xeb) {

View File

@ -26,33 +26,37 @@ CPURegs regs;
}; };
virtual uint8 pio_status() = 0; virtual uint8 pio_status() = 0;
virtual void run() = 0; virtual void run() = 0;
virtual uint32 cycles_executed() = 0;
virtual void scanline() = 0; virtual void scanline() = 0;
virtual void frame() = 0; virtual void frame() = 0;
virtual void power() = 0; virtual void power() = 0;
virtual void reset() = 0; virtual void reset() = 0;
//opcode disassembler //opcode disassembler
enum { enum {
OPTYPE_DP = 0, //dp OPTYPE_DP = 0, //dp
OPTYPE_DPX, //dp,x OPTYPE_DPX, //dp,x
OPTYPE_DPY, //dp,y OPTYPE_DPY, //dp,y
OPTYPE_IDP, //(dp) OPTYPE_IDP, //(dp)
OPTYPE_IDPX, //(dp,x) OPTYPE_IDPX, //(dp,x)
OPTYPE_IDPY, //(dp),y OPTYPE_IDPY, //(dp),y
OPTYPE_ILDP, //[dp] OPTYPE_ILDP, //[dp]
OPTYPE_ILDPY, //[dp],y OPTYPE_ILDPY, //[dp],y
OPTYPE_ADDR, //addr OPTYPE_ADDR, //addr
OPTYPE_ADDRX, //addr,x OPTYPE_ADDRX, //addr,x
OPTYPE_ADDRY, //addr,y OPTYPE_ADDRY, //addr,y
OPTYPE_IADDRX, //(addr,x) OPTYPE_IADDRX, //(addr,x)
OPTYPE_ILADDR, //[addr] OPTYPE_ILADDR, //[addr]
OPTYPE_LONG, //long OPTYPE_LONG, //long
OPTYPE_LONGX, //long, x OPTYPE_LONGX, //long, x
OPTYPE_SR, //sr,s OPTYPE_SR, //sr,s
OPTYPE_ISRY, //(sr,s),y OPTYPE_ISRY, //(sr,s),y
OPTYPE_ADDR_PC, //pbr:addr OPTYPE_ADDR_PC, //pbr:addr
OPTYPE_IADDR_PC //pbr:(addr) OPTYPE_IADDR_PC //pbr:(addr)
}; };
//see dcpu.cpp for notes on this function
virtual bool in_opcode();
void disassemble_opcode(char *output); void disassemble_opcode(char *output);
uint32 resolve_offset(uint8 offset_type, uint32 addr); uint32 resolve_offset(uint8 offset_type, uint32 addr);
uint8 opcode_length(); uint8 opcode_length();

View File

@ -82,6 +82,7 @@ CPUReg24 pc;
CPUReg16 a, x, y, s, d; CPUReg16 a, x, y, s, d;
CPURegFlags p; CPURegFlags p;
uint8 db; uint8 db;
uint8 mdr; //memory data register (openbus)
bool e; bool e;
CPURegs() { db = 0; e = false; } CPURegs() { db = 0; mdr = 0x00; e = false; }
}; };

View File

@ -1,3 +1,17 @@
//this is a virtual function.
//in opcode-based CPU emulators, the main emulation routine
//will only be able to call the disassemble_opcode() function
//on clean opcode edges. but with cycle-based CPU emulators,
//the CPU may be in the middle of executing an opcode when the
//emulator (e.g. debugger) wants to disassemble an opcode. this
//would mean that important registers may not reflect what they
//did at the start of the opcode (especially regs.pc), so in
//cycle-based emulators, this function should be overridden to
//reflect whether or not an opcode has only been partially
//executed. if not, the debugger should abort attempts to skip,
//disable, or disassemble the current opcode.
bool CPU::in_opcode() { return false; }
uint16 CPU::__relb(int8 offset) { uint16 CPU::__relb(int8 offset) {
uint32 addr; uint32 addr;
addr = (regs.pc.d & 0xff0000) | ((regs.pc.d + 2) & 0xffff); addr = (regs.pc.d & 0xff0000) | ((regs.pc.d + 2) & 0xffff);
@ -81,16 +95,24 @@ uint32 r = 0;
} }
void CPU::disassemble_opcode(char *output) { void CPU::disassemble_opcode(char *output) {
char *s = output; char *s;
char t[256]; char t[256];
uint8 op, op0, op1, op2; uint8 op, op0, op1, op2;
sprintf(s, "%0.6x ", regs.pc.d); static CPUReg24 pc;
s = output;
//TODO: This should wrap around the bank byte if(in_opcode() == true) {
op = mem_bus->read(regs.pc.d); strcpy(s, "?????? <CPU within opcode>");
op0 = mem_bus->read(regs.pc.d + 1); return;
op1 = mem_bus->read(regs.pc.d + 2); }
op2 = mem_bus->read(regs.pc.d + 3);
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);
switch(op) { switch(op) {
case 0x00:sprintf(t, "brk #$%0.2x ", op0);break; case 0x00:sprintf(t, "brk #$%0.2x ", op0);break;
@ -431,6 +453,10 @@ static uint8 op_len_tbl[256] = {
6,2,2,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0xen 6,2,2,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0xen
2,2,2,2, 3,2,2,2, 1,3,1,1, 3,3,3,4 //0xfn 2,2,2,2, 3,2,2,2, 1,3,1,1, 3,3,3,4 //0xfn
}; };
if(in_opcode() == true) {
return 0;
}
op = mem_bus->read(regs.pc.d); op = mem_bus->read(regs.pc.d);
len = op_len_tbl[op]; len = op_len_tbl[op];
if(len == 5)return (regs.p.m)?2:3; if(len == 5)return (regs.p.m)?2:3;

View File

@ -21,10 +21,18 @@ extern PPU *ppu;
#include "snes/snes.h" #include "snes/snes.h"
extern SNES *snes; extern SNES *snes;
#include "chip/srtc/srtc.h"
#include "chip/sdd1/sdd1.h"
extern SRTC *srtc;
extern SDD1 *sdd1;
#ifdef INTERFACE_MAIN #ifdef INTERFACE_MAIN
MemBus *mem_bus; MemBus *mem_bus;
CPU *cpu; CPU *cpu;
APU *apu; APU *apu;
PPU *ppu; PPU *ppu;
SNES *snes; SNES *snes;
SRTC *srtc;
SDD1 *sdd1;
#endif #endif

View File

@ -1,5 +1,5 @@
/* /*
libbase : version 0.01 ~byuu libbase : version 0.03 ~byuu (08/20/05)
*/ */
#ifndef __LIBBASE #ifndef __LIBBASE
@ -10,10 +10,21 @@
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
typedef unsigned int uint;
typedef unsigned char byte; typedef unsigned char byte;
typedef unsigned short word; typedef unsigned short word;
typedef unsigned long ulong; typedef unsigned long ulong;
typedef unsigned char bool8;
typedef unsigned char uint8; typedef unsigned char uint8;
typedef unsigned short uint16; typedef unsigned short uint16;
typedef unsigned long uint32; typedef unsigned long uint32;

View File

@ -1,21 +1,6 @@
#include "libbase.h" #include "libbase.h"
#include "libconfig.h" #include "libconfig.h"
//if this function returns true, the option is written
//to the configuration file. by always returning true,
//every option is always written. disable the first line
//to only output options after they have been changed by
//the program from their default values first.
bool config_item::changed() {
return true;
if(is_string == true) {
if(!strcmp(*strsource, strdef))return false;
return true;
}
return (*source != def);
}
config_item::config_item() { config_item::config_item() {
strcpy(name, ""); strcpy(name, "");
strcpy(strdef, ""); strcpy(strdef, "");
@ -67,34 +52,6 @@ uint32 config::find(char *name) {
return null; return null;
} }
uint32 config::get(char *name) {
int i = find(name);
if(i == null)return 0;
return *item[i]->source;
}
string &config::strget(char *name) {
int i = find(name);
if(i == null) {
static string not_found;
strcmp(not_found, "");
return not_found;
}
return *item[i]->strsource;
}
void config::set(char *name, uint32 value) {
int i = find(name);
if(i == null)return;
*item[i]->source = value;
}
void config::set(char *name, char *value) {
int i = find(name);
if(i == null)return;
strcpy(*item[i]->strsource, value);
}
void config::load(char *fn) { void config::load(char *fn) {
FILE *fp; FILE *fp;
char *buffer; char *buffer;
@ -130,8 +87,8 @@ uint32 l;
qreplace(line[i], " ", ""); qreplace(line[i], " ", "");
//remove comment, if it exists //remove comment, if it exists
if(strqpos(line[i], "#") != null) { if(qstrpos(line[i], "#") != null) {
strset(line[i], strqpos(line[i], "#"), 0); strset(line[i], qstrpos(line[i], "#"), 0);
} }
//ignore blank lines //ignore blank lines
@ -139,7 +96,7 @@ uint32 l;
qsplit(part, "=", line[i]); qsplit(part, "=", line[i]);
l = find(*part[0]); l = find(strptr(part[0]));
if(l != null) { if(l != null) {
//if the config item name is valid... update item value //if the config item name is valid... update item value
if(item[l]->is_string == true) { if(item[l]->is_string == true) {
@ -153,7 +110,7 @@ uint32 l;
!strcmp(part[1], "off") || !strcmp(part[1], "disabled")) { !strcmp(part[1], "off") || !strcmp(part[1], "disabled")) {
*item[l]->source = 0; *item[l]->source = 0;
} else if(item[l]->type == HEX) { } else if(item[l]->type == HEX) {
*item[l]->source = strhex(*part[1] + 2); //skip 0x prefix *item[l]->source = strhex(strptr(part[1]) + 2); //skip 0x prefix
} else { /* fall back on DEC */ } else { /* fall back on DEC */
*item[l]->source = strdec(part[1]); *item[l]->source = strdec(part[1]);
} }
@ -161,6 +118,7 @@ uint32 l;
} }
} }
} }
void config::load(substring &fn) { load(strptr(fn)); }
//create a text string from config item[i] to be output via config->save() //create a text string from config item[i] to be output via config->save()
void config::set_newline(int i) { void config::set_newline(int i) {
@ -246,8 +204,8 @@ bool blank = false;
for(i=0;i<count(line);i++) { for(i=0;i<count(line);i++) {
qreplace(line[i], " ", ""); qreplace(line[i], " ", "");
if(strqpos(line[i], "#") != null) { if(qstrpos(line[i], "#") != null) {
strset(line[i], strqpos(line[i], "#"), 0); strset(line[i], qstrpos(line[i], "#"), 0);
} }
//this line is empty, restore the old line and continue //this line is empty, restore the old line and continue
@ -258,7 +216,7 @@ bool blank = false;
qsplit(part, "=", line[i]); qsplit(part, "=", line[i]);
l = find(*part[0]); l = find(strptr(part[0]));
if(l == null) { if(l == null) {
//invalid item name, restore the old line and continue //invalid item name, restore the old line and continue
strcpy(line[i], oldline[i]); strcpy(line[i], oldline[i]);
@ -269,9 +227,9 @@ bool blank = false;
set_newline(l); set_newline(l);
//copy the user comment from the old config file, if it exists //copy the user comment from the old config file, if it exists
if(strqpos(oldline[i], "#") != null) { if(qstrpos(oldline[i], "#") != null) {
strcat(newline, " "); strcat(newline, " ");
strcat(newline, *oldline[i] + strqpos(oldline[i], "#")); strcat(newline, strptr(oldline[i]) + qstrpos(oldline[i], "#"));
} }
strcpy(line[i], newline); strcpy(line[i], newline);
@ -279,7 +237,7 @@ bool blank = false;
//write out the old config file + changes first //write out the old config file + changes first
for(i=0;i<count(line);) { for(i=0;i<count(line);) {
fprintf(fp, "%s", *line[i]); fprintf(fp, "%s", strptr(line[i]));
//write a line feed on all lines but the last. //write a line feed on all lines but the last.
//keeps the file from growing everytime it is saved //keeps the file from growing everytime it is saved
@ -291,20 +249,18 @@ int lines_written;
for(i=lines_written=0;i<item_count;i++) { for(i=lines_written=0;i<item_count;i++) {
//if the item was written to the file above... //if the item was written to the file above...
if(set[i] == 1)continue; if(set[i] == 1)continue;
//...or if it is still set to the default value,
//then don't output it to the file here
if(item[i]->changed() == false)continue;
set_newline(i); set_newline(i);
//prevent a newline from appearing at the top of the file //prevent a newline from appearing at the top of the file
//when the config file is created for the first time //when the config file is created for the first time
if(lines_written == 0 && blank == false)fprintf(fp, "\r\n"); if(lines_written == 0 && blank == false)fprintf(fp, "\r\n");
fprintf(fp, "%s\r\n", *newline); fprintf(fp, "%s\r\n", strptr(newline));
lines_written++; lines_written++;
} }
fclose(fp); fclose(fp);
} }
void config::save(substring &fn) { save(strptr(fn)); }
config::config() { config::config() {
item_count = 0; item_count = 0;

View File

@ -1,5 +1,5 @@
/* /*
libconfig : version 0.02 ~byuu libconfig : version 0.03 ~byuu (08/20/05)
*/ */
#ifndef __LIBCONFIG #ifndef __LIBCONFIG
@ -13,7 +13,6 @@ uint32 *source, def, type;
string *strsource, strdef; string *strsource, strdef;
bool is_string; bool is_string;
string name; string name;
bool changed();
config_item(); config_item();
}; };
@ -35,13 +34,10 @@ enum {
void add(uint32 *variable, char *name, uint32 def, uint32 type = DEC); void add(uint32 *variable, char *name, uint32 def, uint32 type = DEC);
void add(string *variable, char *name, char *def, uint32 type = STR); void add(string *variable, char *name, char *def, uint32 type = STR);
uint32 find(char *name); uint32 find(char *name);
uint32 get(char *name);
string &strget(char *name);
void set(char *name, uint32 value);
void set(char *name, char *value);
void load(char *fn); void load(char *fn);
void load(substring &fn);
void save(char *fn); void save(char *fn);
void save(substring &fn);
void set_newline(int i); void set_newline(int i);
config(); config();

View File

@ -1,23 +1,26 @@
#include "libbase.h" #include "libbase.h"
#include "libstring.h" #include "libstring.h"
_string::_string() { substring::substring() {
size = 16; size = 16;
s = (char*)malloc(size + 1); s = (char*)malloc(size + 1);
*s = 0; *s = 0;
} }
_string::~_string() { substring::~substring() {
free(s); if(s) {
} free(s);
s = 0;
void string::addto(uint32 num) {
while(listcount < (num + 1)) {
list[listcount++] = new _string();
} }
} }
_string &string::str(uint32 num) { void string::addto(uint num) {
while(listcount < (num + 1)) {
list[listcount++] = new substring();
}
}
substring &string::str(uint num) {
if(listcount < (num + 1)) { addto(num); } if(listcount < (num + 1)) { addto(num); }
return *list[num]; return *list[num];
} }
@ -31,60 +34,68 @@ string::string() {
string::~string() { string::~string() {
int i; int i;
for(i=listcount-1;i>=0;i--) { for(i=listcount-1;i>=0;i--) {
delete((_string*)list[i]); delete((substring*)list[i]);
} }
} }
uint32 count(string &str) { char chrlower(char c) {
return str.count; if(c >= 'A' && c <= 'Z')return c + ('a' - 'A');
return c;
} }
void strresize(_string &str, uint32 size) { char chrupper(char c) {
char *t; if(c >= 'a' && c <= 'z')return c - ('a' - 'A');
int sl; return c;
if(str.size == size)return; }
sl = strlen(str.s);
t = (char*)malloc(size + 1); uint count(string &str) { return str.count; }
strcpy(t, str.s);
free(str.s); void strresize(substring &str, uint size) {
str.s = t; str.s = (char*)realloc(str.s, size + 1);
str.s[size] = 0;
str.size = size; str.size = size;
} }
char *strptr(_string &str) { char *strptr(substring &str) { return str.s; }
return str.s;
}
void strcpy(_string &dest, char *src) { uint strlen(substring &str) { return strlen(strptr(str)); }
int strcmp(substring &dest, const char *src) { return strcmp(strptr(dest), src); }
int strcmp(const char *dest, substring &src) { return strcmp(dest, strptr(src)); }
int strcmp(substring &dest, substring &src) { return strcmp(strptr(dest), strptr(src)); }
void strcpy(substring &dest, const char *src) {
int srclen = strlen(src); int srclen = strlen(src);
if(srclen > dest.size) { strresize(dest, srclen); } if(srclen > dest.size) { strresize(dest, srclen); }
strcpy(dest.s, src); strcpy(dest.s, src);
} }
void strcpy(substring &dest, substring &src) { strcpy(dest, strptr(src)); }
void strset(_string &dest, uint32 pos, uint8 c) { void strset(substring &dest, uint pos, uint8 c) {
char *s; char *s;
if(pos > dest.size) { strresize(dest, pos); } if(pos > dest.size) { strresize(dest, pos); }
dest.s[pos] = c; dest.s[pos] = c;
} }
void strcat(_string &dest, char *src) { void strcat(substring &dest, const char *src) {
int srclen, destlen; int srclen, destlen;
srclen = strlen(src); srclen = strlen(src);
destlen = strlen(dest.s); destlen = strlen(dest.s);
if(srclen + destlen > dest.size) { strresize(dest, srclen + destlen); } if(srclen + destlen > dest.size) { strresize(dest, srclen + destlen); }
strcat(dest.s, src); strcat(dest.s, src);
} }
void strcat(substring &dest, substring &src) { strcat(dest, strptr(src)); }
void strinsert(_string &dest, char *src, uint32 pos) { void strinsert(substring &dest, const char *src, uint pos) {
_string *s = new _string(); static substring s;
strcpy(*s, strptr(dest) + pos); strcpy(s, strptr(dest) + pos);
strset(dest, pos, 0); strset(dest, pos, 0);
strcat(dest, src); strcat(dest, src);
strcat(dest, *s); strcat(dest, s);
delete(s);
} }
void strinsert(substring &dest, substring &src, uint pos) { strinsert(dest, strptr(src), pos); }
void strremove(_string &dest, uint32 start, uint32 length) { void strremove(substring &dest, uint start, uint length) {
int destlen; int destlen;
char *s; char *s;
int i, sl = strlen(dest.s); int i, sl = strlen(dest.s);
@ -98,36 +109,35 @@ int i, sl = strlen(dest.s);
s[i] = 0; s[i] = 0;
} }
bool stricmp(char *dest, char *src) { int __stricmp(const char *dest, const char *src) {
int i, sl = strlen(dest); while(*dest && *src) {
if(sl != strlen(src))return false; if(chrlower(*dest) != chrlower(*src))break;
for(i=0;i<sl;i++) { dest++;
if(dest[i] >= 'A' && dest[i] <= 'Z') { src++;
if(dest[i] != src[i] && dest[i] + 0x20 != src[i])return false;
} else if(dest[i] >='a' && dest[i] <= 'z') {
if(dest[i] != src[i] && dest[i] - 0x20 != src[i])return false;
} else {
if(dest[i] != src[i])return false;
}
} }
return true; return (int)chrlower(*dest) - (int)chrlower(*src);
} }
int stricmp(substring &dest, const char *src) { return __stricmp(strptr(dest), src); }
int stricmp(const char *dest, substring &src) { return __stricmp(dest, strptr(src)); }
int stricmp(substring &dest, substring &src) { return __stricmp(strptr(dest), strptr(src)); }
void strlower(char *str) { void strlower(char *str) {
int i, sl = strlen(str); while(*str) {
for(i=0;i<sl;i++) { *str = chrlower(*str);
if(str[i] >= 'A' && str[i] <= 'Z')str[i] += 0x20; str++;
} }
} }
void strlower(substring &str) { strlower(strptr(str)); }
void strupper(char *str) { void strupper(char *str) {
int i, sl = strlen(str); while(*str) {
for(i=0;i<sl;i++) { *str = chrupper(*str);
if(str[i] >= 'a' && str[i] <= 'z')str[i] -= 0x20; str++;
} }
} }
void strupper(substring &str) { strupper(strptr(str)); }
uint32 strpos(char *str, char *key) { uint strpos(const char *str, const char *key) {
int i, ssl = strlen(str), ksl = strlen(key); int i, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return null; if(ksl > ssl)return null;
for(i=0;i<=ssl-ksl;i++) { for(i=0;i<=ssl-ksl;i++) {
@ -135,8 +145,11 @@ int i, ssl = strlen(str), ksl = strlen(key);
} }
return null; return null;
} }
uint strpos(substring &str, const char *key) { return strpos(strptr(str), key); }
uint strpos(const char *str, substring &key) { return strpos(str, strptr(key)); }
uint strpos(substring &str, substring &key) { return strpos(strptr(str), strptr(key)); }
uint32 strqpos(char *str, char *key) { uint qstrpos(const char *str, const char *key) {
int i, z, ssl = strlen(str), ksl = strlen(key); int i, z, ssl = strlen(str), ksl = strlen(key);
uint8 x; uint8 x;
if(ksl > ssl)return null; if(ksl > ssl)return null;
@ -155,8 +168,11 @@ uint8 x;
} }
return null; return null;
} }
uint qstrpos(substring &str, const char *key) { return qstrpos(strptr(str), key); }
uint qstrpos(const char *str, substring &key) { return qstrpos(str, strptr(key)); }
uint qstrpos(substring &str, substring &key) { return qstrpos(strptr(str), strptr(key)); }
void strtr(char *dest, char *before, char *after) { void strtr(char *dest, const char *before, const char *after) {
int i, l, sl = strlen(dest), bsl = strlen(before), asl = strlen(after); int i, l, sl = strlen(dest), bsl = strlen(before), asl = strlen(after);
if((bsl != asl) || bsl == 0)return; if((bsl != asl) || bsl == 0)return;
for(i=0;i<sl;i++) { for(i=0;i<sl;i++) {
@ -165,15 +181,17 @@ int i, l, sl = strlen(dest), bsl = strlen(before), asl = strlen(after);
} }
} }
} }
void strtr(substring &dest, const char *before, const char *after) { strtr(strptr(dest), before, after); }
uint32 strbegin(char *str, char *key) { uint strbegin(const char *str, const char *key) {
int i, ssl = strlen(str), ksl = strlen(key); int i, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return 1; if(ksl > ssl)return 1;
if(!memcmp(str, key, ksl))return 0; if(!memcmp(str, key, ksl))return 0;
return 1; return 1;
} }
uint strbegin(substring &str, const char *key) { return strbegin(strptr(str), key); }
uint32 stribegin(char *str, char *key) { uint stribegin(const char *str, const char *key) {
int i, ssl = strlen(str), ksl = strlen(key); int i, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return 1; if(ksl > ssl)return 1;
for(i=0;i<ksl;i++) { for(i=0;i<ksl;i++) {
@ -187,15 +205,17 @@ int i, ssl = strlen(str), ksl = strlen(key);
} }
return 0; return 0;
} }
uint stribegin(substring &str, const char *key) { return stribegin(strptr(str), key); }
uint32 strend(char *str, char *key) { uint strend(const char *str, const char *key) {
int i, ssl = strlen(str), ksl = strlen(key); int i, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return 1; if(ksl > ssl)return 1;
if(!memcmp(str + ssl - ksl, key, ksl))return 0; if(!memcmp(str + ssl - ksl, key, ksl))return 0;
return 1; return 1;
} }
uint strend(substring &str, const char *key) { return strend(strptr(str), key); }
uint32 striend(char *str, char *key) { uint striend(const char *str, const char *key) {
int i, z, ssl = strlen(str), ksl = strlen(key); int i, z, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return 1; if(ksl > ssl)return 1;
for(i=ssl-ksl, z=0;i<ssl;i++, z++) { for(i=ssl-ksl, z=0;i<ssl;i++, z++) {
@ -209,8 +229,9 @@ int i, z, ssl = strlen(str), ksl = strlen(key);
} }
return 0; return 0;
} }
uint striend(substring &str, const char *key) { return striend(strptr(str), key); }
void strltrim(char *str, char *key) { void strltrim(char *str, const char *key) {
int i, ssl = strlen(str), ksl = strlen(key); int i, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return; if(ksl > ssl)return;
if(!strbegin(str, key)) { if(!strbegin(str, key)) {
@ -218,8 +239,9 @@ int i, ssl = strlen(str), ksl = strlen(key);
str[i] = 0; str[i] = 0;
} }
} }
void strltrim(substring &str, const char *key) { strltrim(strptr(str), key); }
void striltrim(char *str, char *key) { void striltrim(char *str, const char *key) {
int i, ssl = strlen(str), ksl = strlen(key); int i, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return; if(ksl > ssl)return;
if(!stribegin(str, key)) { if(!stribegin(str, key)) {
@ -227,25 +249,28 @@ int i, ssl = strlen(str), ksl = strlen(key);
str[i] = 0; str[i] = 0;
} }
} }
void striltrim(substring &str, const char *key) { striltrim(strptr(str), key); }
void strrtrim(char *str, char *key) { void strrtrim(char *str, const char *key) {
int ssl = strlen(str), ksl = strlen(key); int ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return; if(ksl > ssl)return;
if(!strend(str, key)) { if(!strend(str, key)) {
str[ssl - ksl] = 0; str[ssl - ksl] = 0;
} }
} }
void strrtrim(substring &str, const char *key) { strrtrim(strptr(str), key); }
void strirtrim(char *str, char *key) { void strirtrim(char *str, const char *key) {
int ssl = strlen(str), ksl = strlen(key); int ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return; if(ksl > ssl)return;
if(!striend(str, key)) { if(!striend(str, key)) {
str[ssl - ksl] = 0; str[ssl - ksl] = 0;
} }
} }
void strirtrim(substring &str, const char *key) { strirtrim(strptr(str), key); }
/* does not work on type char* because function increases string length */ //does not work on type char* because function increases string length
void strquote(_string &str) { void strquote(substring &str) {
static string t; static string t;
strcpy(t, "\""); strcpy(t, "\"");
strcat(t, str); strcat(t, str);
@ -255,15 +280,15 @@ static string t;
bool strunquote(char *str) { bool strunquote(char *str) {
int i, ssl = strlen(str); int i, ssl = strlen(str);
/* make sure string is long enough to have quotes */ //make sure string is long enough to have quotes
if(ssl < 2)return false; if(ssl < 2)return false;
/* make sure string actually has quotes */ //make sure string actually has quotes
if(str[0] == '\"' && str[ssl - 1] == '\"'); if(str[0] == '\"' && str[ssl - 1] == '\"');
else if(str[0] == '\'' && str[ssl - 1] == '\''); else if(str[0] == '\'' && str[ssl - 1] == '\'');
else return false; else return false;
/* now remove them */ //now remove them
for(i=0;i<ssl;i++) { for(i=0;i<ssl;i++) {
str[i] = str[i + 1]; str[i] = str[i + 1];
} }
@ -271,9 +296,10 @@ int i, ssl = strlen(str);
return true; return true;
} }
bool strunquote(substring &str) { return strunquote(strptr(str)); }
uint32 strhex(char *str) { uint strhex(const char *str) {
uint32 r = 0, m = 0; uint r = 0, m = 0;
int i, ssl = strlen(str); int i, ssl = strlen(str);
uint8 x; uint8 x;
for(i=0;i<ssl;i++) { for(i=0;i<ssl;i++) {
@ -292,31 +318,44 @@ uint8 x;
} }
return r; return r;
} }
uint strhex(substring &str) { return strhex(strptr(str)); }
int strdec(char *str) { int sstrhex(const char *str) {
uint32 m = 1; if(str[0] == '-') {
return -strhex(str + 1);
}
return strhex(str);
}
int sstrhex(substring &str) { return sstrhex(strptr(str)); }
uint strdec(const char *str) {
uint m = 1;
int i, r = 0, ssl = strlen(str); int i, r = 0, ssl = strlen(str);
uint8 x; uint8 x;
for(i=0;i<ssl;i++) { for(i=0;i<ssl;i++) {
if(str[i] >= '0' && str[i] <= '9'); if(str[i] >= '0' && str[i] <= '9');
else if(str[i] == '-' && i == 0);
else break; else break;
} }
for(--i;i>=0;i--, m*=10) { for(--i;i>=0;i--, m*=10) {
x = str[i]; x = str[i];
if(x >= '0' && x <= '9')x -= '0'; if(x >= '0' && x <= '9')x -= '0';
else if(i == 0 && str[i] == '-') {
r *= -1;
return r;
}
else return r; else return r;
r += x * m; r += x * m;
} }
return r; return r;
} }
uint strdec(substring &str) { return strdec(strptr(str)); }
uint32 strbin(char *str) { int sstrdec(const char *str) {
uint32 r = 0, m = 0; if(str[0] == '-') {
return -strdec(str + 1);
}
return strdec(str);
}
int sstrdec(substring &str) { return sstrdec(strptr(str)); }
uint strbin(const char *str) {
uint r = 0, m = 0;
int i, ssl = strlen(str); int i, ssl = strlen(str);
uint8 x; uint8 x;
for(i=0;i<ssl;i++) { for(i=0;i<ssl;i++) {
@ -331,6 +370,15 @@ uint8 x;
} }
return r; return r;
} }
uint strbin(substring &str) { return strbin(strptr(str)); }
int sstrbin(const char *str) {
if(str[0] == '-') {
return -strbin(str + 1);
}
return strbin(str);
}
int sstrbin(substring &str) { return sstrbin(strptr(str)); }
#include "libstring_math.cpp" #include "libstring_math.cpp"
#include "libstring_split.cpp" #include "libstring_split.cpp"

View File

@ -1,5 +1,5 @@
/* /*
libstring : version 0.05 ~byuu libstring : version 0.06a ~byuu (08/22/05)
*/ */
#ifndef __LIBSTRING #ifndef __LIBSTRING
@ -8,247 +8,172 @@
#include "libvector.h" #include "libvector.h"
class string; class string;
class _string; class substring;
uint32 count(string &str); char chrlower(char c);
void strresize(_string &str, uint32 size); char chrupper(char c);
char* strptr(_string &str);
void strcpy(_string &dest, char *src);
void strset(_string &dest, uint32 pos, uint8 c);
void strcat(_string &dest, char *src);
void strinsert(_string &dest, char *src, uint32 pos);
void strremove(_string &dest, uint32 start, uint32 length = 0);
bool stricmp(char *dest, char *src);
void strlower(char *str);
void strupper(char *str);
uint32 strpos(char *str, char *key);
uint32 strqpos(char *str, char *key);
void strtr(char *dest, char *before, char *after);
uint32 strbegin(char *str, char *key);
uint32 stribegin(char *str, char *key);
uint32 strend(char *str, char *key);
uint32 striend(char *str, char *key);
void strltrim(char *str, char *key);
void striltrim(char *str, char *key);
void strrtrim(char *str, char *key);
void strirtrim(char *str, char *key);
void strquote(_string &str);
bool strunquote(char *str);
uint32 strhex(char *str);
int strdec(char *str);
uint32 strbin(char *str);
uint32 strmath(char *in_str);
uint32 strmathentity(char *str);
void replace (_string &str, char *key, char *token);
void qreplace(_string &str, char *key, char *token);
void split (string &dest, char *key, char *src);
void qsplit(string &dest, char *key, char *src);
void sprintf(_string &str, char *s, ...);
class _string { uint count(string &str);
void strresize(substring &str, uint size);
char* strptr(substring &str);
uint strlen(substring &str);
int strcmp(substring &dest, const char *src);
int strcmp(const char *dest, substring &src);
int strcmp(substring &dest, substring &src);
void strcpy(substring &dest, const char *src);
void strcpy(substring &dest, substring &src);
void strset(substring &dest, uint pos, uint8 c);
void strcat(substring &dest, const char *src);
void strcat(substring &dest, substring &src);
void strinsert(substring &dest, const char *src, uint pos);
void strinsert(substring &dest, substring &src, uint pos);
void strremove(substring &dest, uint start, uint length = 0);
//vc6/win32 and gcc/dos only support stricmp, whereas
//gcc/unix only supports strcasecmp. this is an attempt
//to avoid platform-specific defines...
#define stricmp __stricmp
int __stricmp(const char *dest, const char *src);
int stricmp(substring &dest, const char *src);
int stricmp(const char *dest, substring &src);
int stricmp(substring &dest, substring &src);
void strlower(char *str);
void strlower(substring &str);
void strupper(char *str);
void strupper(substring &str);
uint strpos(const char *str, const char *key);
uint strpos(substring &str, const char *key);
uint strpos(const char *str, substring &key);
uint strpos(substring &str, substring &key);
uint qstrpos(const char *str, const char *key);
uint qstrpos(substring &str, const char *key);
uint qstrpos(const char *str, substring &key);
uint qstrpos(substring &str, substring &key);
void strtr(char *dest, const char *before, const char *after);
void strtr(substring &dest, const char *before, const char *after);
uint strbegin(const char *str, const char *key);
uint strbegin(substring &str, const char *key);
uint stribegin(const char *str, const char *key);
uint stribegin(substring &str, const char *key);
uint strend(const char *str, const char *key);
uint strend(substring &str, const char *key);
uint striend(const char *str, const char *key);
uint striend(substring &str, const char *key);
void strltrim(char *str, const char *key);
void strltrim(substring &str, const char *key);
void striltrim(char *str, const char *key);
void striltrim(substring &str, const char *key);
void strrtrim(char *str, const char *key);
void strrtrim(substring &str, const char *key);
void strirtrim(char *str, const char *key);
void strirtrim(substring &str, const char *key);
void strquote(substring &str);
bool strunquote(char *str);
bool strunquote(substring &str);
uint strhex(const char *str);
uint strhex(substring &str);
int sstrhex(const char *str);
int sstrhex(substring &str);
uint strdec(const char *str);
uint strdec(substring &str);
int sstrdec(const char *str);
int sstrdec(substring &str);
uint strbin(const char *str);
uint strbin(substring &str);
int sstrbin(const char *str);
int sstrbin(substring &str);
uint strmath(const char *in_str);
uint strmath(substring &in_str);
bool strmathentity(const char *str);
bool strmathentity(substring &str);
void replace(substring &str, const char *key, const char *token);
void replace(substring &str, const char *key, substring &token);
void qreplace(substring &str, const char *key, const char *token);
void qreplace(substring &str, const char *key, substring &token);
void split(string &dest, const char *key, char *src);
void split(string &dest, const char *key, substring &src);
void qsplit(string &dest, const char *key, char *src);
void qsplit(string &dest, const char *key, substring &src);
void sprintf(substring &str, const char *s, ...);
class substring {
public: public:
char *s; char *s;
uint32 size; uint size;
inline char* operator*() { return s; } //inline char* operator*() { return s; }
//inline operator char*() { return s; }
#ifdef __LIBSTRING_OVERLOADS substring();
inline _string& operator=(char *cpy); ~substring();
inline _string& operator=(_string &cpy);
inline _string& operator=(string &cpy);
inline _string& operator+=(char *cat);
inline _string& operator+=(_string &cat);
inline _string& operator+=(string &cat);
inline _string& operator-=(char *cut);
inline _string& operator-=(_string &cut);
inline _string& operator-=(string &cut);
inline bool operator==(char *cmp);
inline bool operator==(_string &cmp);
inline bool operator==(string &cmp);
inline bool operator!=(char *cmp);
inline bool operator!=(_string &cmp);
inline bool operator!=(string &cmp);
#endif
inline operator char*() { return s; }
_string();
~_string();
}; };
/* listcount is the actual size of list[], used for allocation
* of substrings.
* count is used by split() and count() to return the number of
* active/valid substrings. example: if string T contains 16
* substrings, and split is called, which sets three substrings,
* then count() needs to reflect that only three substrings are
* now used, but listcount still needs to reflect the true size
* of list[].
*/
class string { class string {
public: public:
vector<_string*> list; vector<substring*> list;
uint32 count, listcount; uint listcount, count;
void addto(uint32 num); //creates all needed strings to make list[num] valid void addto(uint num); //creates all needed strings to make list[num] valid
_string &str(uint32 num); //gets a _string reference, creating it + new strings if needed substring &str(uint num); //gets a substring reference, creating it + new strings if needed
inline char* operator*() { return strptr(str(0)); } //inline char* operator*() { return strptr(str(0)); }
//inline operator char*() { return str(0).s; }
#ifdef __LIBSTRING_OVERLOADS inline operator substring&() { return str(0); }
inline string& operator=(char *cpy); inline substring& operator[](uint i) { return str(i); }
inline string& operator=(_string &cpy); inline substring& operator[](uint8 i) { return str(i); }
inline string& operator=(string &cpy); inline substring& operator[](uint16 i) { return str(i); }
inline substring& operator[](uint32 i) { return str(i); }
inline string& operator+=(char *cat); inline substring& operator[](int i) { return str(i); }
inline string& operator+=(_string &cat); inline substring& operator[](int8 i) { return str(i); }
inline string& operator+=(string &cat); inline substring& operator[](int16 i) { return str(i); }
inline substring& operator[](int32 i) { return str(i); }
inline string& operator-=(char *cut);
inline string& operator-=(_string &cut);
inline string& operator-=(string &cut);
inline bool operator==(char *cmp);
inline bool operator==(_string &cmp);
inline bool operator==(string &cmp);
inline bool operator!=(char *cmp);
inline bool operator!=(_string &cmp);
inline bool operator!=(string &cmp);
#endif
inline operator char*() { return str(0).s; }
inline operator _string&() { return str(0); }
inline _string& operator[](uint32 i) { return str(i); }
inline _string& operator[](int i) { return str(i); }
string(); string();
~string(); ~string();
}; };
#ifdef __LIBSTRING_OVERLOADS
inline _string& _string::operator=(char *cpy) {
strcpy(*this, cpy);
return *this;
}
inline _string& _string::operator=(_string &cpy) {
strcpy(*this, cpy);
return *this;
}
inline _string& _string::operator=(string &cpy) {
strcpy(*this, cpy.str(0));
return *this;
}
inline string& string::operator=(char *cpy) {
strcpy(str(0), cpy);
return *this;
}
inline string& string::operator=(_string &cpy) {
strcpy(str(0), cpy);
return *this;
}
inline string& string::operator=(string &cpy) {
strcpy(str(0), cpy.str(0));
return *this;
}
inline _string& _string::operator+=(char *cat) {
strcat(*this, cat);
return *this;
}
inline _string& _string::operator+=(_string &cat) {
strcat(*this, cat);
return *this;
}
inline _string& _string::operator+=(string &cat) {
strcat(*this, cat.str(0));
return *this;
}
inline string& string::operator+=(char *cat) {
strcat(str(0), cat);
return *this;
}
inline string& string::operator+=(_string &cat) {
strcat(str(0), cat);
return *this;
}
inline string& string::operator+=(string &cat) {
strcat(str(0), cat.str(0));
return *this;
}
inline _string& _string::operator-=(char *cut) {
strrtrim(*this, cut);
return *this;
}
inline _string& _string::operator-=(_string &cut) {
strrtrim(*this, cut);
return *this;
}
inline _string& _string::operator-=(string &cut) {
strrtrim(*this, cut.str(0));
return *this;
}
inline string& string::operator-=(char *cut) {
strrtrim(str(0), cut);
return *this;
}
inline string& string::operator-=(_string &cut) {
strrtrim(str(0), cut);
return *this;
}
inline string& string::operator-=(string &cut) {
strrtrim(str(0), cut.str(0));
return *this;
}
inline bool _string::operator==(char *cmp) {
if(!strcmp(*this, cmp))return true;
return false;
}
inline bool _string::operator==(_string &cmp) {
if(!strcmp(*this, cmp))return true;
return false;
}
inline bool _string::operator==(string &cmp) {
if(!strcmp(*this, cmp.str(0)))return true;
return false;
}
inline bool string::operator==(char *cmp) {
if(!strcmp(str(0), cmp))return true;
return false;
}
inline bool string::operator==(_string &cmp) {
if(!strcmp(str(0), cmp))return true;
return false;
}
inline bool string::operator==(string &cmp) {
if(!strcmp(str(0), cmp.str(0)))return true;
return false;
}
inline bool _string::operator!=(char *cmp) {
if(!strcmp(*this, cmp))return false;
return true;
}
inline bool _string::operator!=(_string &cmp) {
if(!strcmp(*this, cmp))return false;
return true;
}
inline bool _string::operator!=(string &cmp) {
if(!strcmp(*this, cmp.str(0)))return false;
return true;
}
inline bool string::operator!=(char *cmp) {
if(!strcmp(str(0), cmp))return false;
return true;
}
inline bool string::operator!=(_string &cmp) {
if(!strcmp(str(0), cmp))return false;
return true;
}
inline bool string::operator!=(string &cmp) {
if(!strcmp(str(0), cmp.str(0)))return false;
return true;
}
#endif //__LIBSTRING_OVERLOADS
#endif //__LIBSTRING #endif //__LIBSTRING

View File

@ -43,10 +43,10 @@ strmath(str)
str, and returns numerical result str, and returns numerical result
example: strmath("5+5")=10 example: strmath("5+5")=10
***************************************/ ***************************************/
uint32 p_strmath(char *str) { uint p_strmath(const char *str) {
int i = 0, ssl = strlen(str); int i = 0, ssl = strlen(str);
uint r, array[128], array_size = 0, z = 0;
uint8 x, mode = 0; uint8 x, mode = 0;
uint32 r, array[128], array_size = 0, z = 0;
uint8 array_gate[128]; uint8 array_gate[128];
char *s1; char *s1;
if(!ssl)return 0; if(!ssl)return 0;
@ -95,11 +95,11 @@ char *s1;
return r; return r;
} }
uint32 strmath(char *in_str) { uint strmath(const char *in_str) {
uint32 r = 0; uint r = 0;
uint32 pdepth = 0, cpdepth, maxpdepth = 0; uint pdepth = 0, cpdepth, maxpdepth = 0;
uint32 pstart, pend, spos; uint pstart, pend, spos;
int i, sc, sl = strlen(in_str); int i, sc, sl = strlen(in_str);
char *str = (char*)malloc(sl + 1), *str0; char *str = (char*)malloc(sl + 1), *str0;
char *pstr; char *pstr;
char num[64]; char num[64];
@ -165,13 +165,15 @@ char num[64];
free(str); free(str);
return r; return r;
} }
uint strmath(substring &in_str) { return strmath(strptr(in_str)); }
uint32 strmathentity(char *str) { bool strmathentity(const char *str) {
int i, ssl = strlen(str); int i, ssl = strlen(str);
for(i=0;i<ssl;i++) { for(i=0;i<ssl;i++) {
if(str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/' || if(str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/' ||
str[i] == '%' || str[i] == '&' || str[i] == '|' || str[i] == '^' || str[i] == '%' || str[i] == '&' || str[i] == '|' || str[i] == '^' ||
(str[i] == '<' && str[i+1] == '<') || (str[i] == '>' && str[i+1] == '>'))return 1; (str[i] == '<' && str[i+1] == '<') || (str[i] == '>' && str[i+1] == '>'))return true;
} }
return 0; return false;
} }
bool strmathentity(substring &str) { return strmathentity(strptr(str)); }

View File

@ -1,6 +1,6 @@
void replace(_string &str, char *key, char *token) { void replace(substring &str, const char *key, const char *token) {
int i, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str); int i, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str);
uint32 replace_count = 0, size = ssl; uint replace_count = 0, size = ssl;
char *data; char *data;
if(ksl > ssl)return; if(ksl > ssl)return;
if(tsl > ksl) { //the new string may be longer than the old string... if(tsl > ksl) { //the new string may be longer than the old string...
@ -27,11 +27,12 @@ char *data;
strcpy(str, data); strcpy(str, data);
free(data); free(data);
} }
void replace(substring &str, const char *key, substring &token) { replace(str, key, strptr(token)); }
void qreplace(_string &str, char *key, char *token) { void qreplace(substring &str, const char *key, const char *token) {
int i, l, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str); int i, l, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str);
uint replace_count = 0, size = ssl;
uint8 x; uint8 x;
uint32 replace_count = 0, size = ssl;
char *data; char *data;
if(ksl > ssl)return; if(ksl > ssl)return;
if(tsl > ksl) { if(tsl > ksl) {
@ -80,3 +81,4 @@ char *data;
strcpy(str, data); strcpy(str, data);
free(data); free(data);
} }
void qreplace(substring &str, const char *key, substring &token) { qreplace(str, key, strptr(token)); }

View File

@ -1,7 +1,7 @@
void split(string &dest, char *key, char *src) { void split(string &dest, const char *key, char *src) {
int i, ssl = strlen(src), ksl = strlen(key); int i, ssl = strlen(src), ksl = strlen(key);
uint lp = 0, split_count = 0;
uint8 x; uint8 x;
uint32 lp = 0, split_count = 0;
for(i=0;i<=ssl-ksl;) { for(i=0;i<=ssl-ksl;) {
if(!memcmp(src + i, key, ksl)) { if(!memcmp(src + i, key, ksl)) {
x = src[i]; x = src[i];
@ -15,11 +15,12 @@ uint32 lp = 0, split_count = 0;
strcpy(dest[split_count++], src + lp); strcpy(dest[split_count++], src + lp);
dest.count = split_count; dest.count = split_count;
} }
void split(string &dest, const char *key, substring &src) { split(dest, key, strptr(src)); }
void qsplit(string &dest, char *key, char *src) { void qsplit(string &dest, const char *key, char *src) {
int i, z, ssl = strlen(src), ksl = strlen(key); int i, z, ssl = strlen(src), ksl = strlen(key);
uint lp = 0, split_count = 0;
uint8 x; uint8 x;
uint32 lp = 0, split_count = 0;
for(i=0;i<=ssl-ksl;) { for(i=0;i<=ssl-ksl;) {
x = src[i]; x = src[i];
if(x=='\"' || x=='\'') { if(x=='\"' || x=='\'') {
@ -39,3 +40,4 @@ uint32 lp = 0, split_count = 0;
strcpy(dest[split_count++], src + lp); strcpy(dest[split_count++], src + lp);
dest.count = split_count; dest.count = split_count;
} }
void qsplit(string &dest, const char *key, substring &src) { qsplit(dest, key, strptr(src)); }

View File

@ -1,5 +1,5 @@
void numtobin(char *s, uint32 num) { void numtobin(char *s, uint num) {
uint32 mask = 0x80000000, len = 0, z = 0; uint mask = 0x80000000, len = 0, z = 0;
for(;mask;mask>>=1,len++) { if(num&mask)break; } for(;mask;mask>>=1,len++) { if(num&mask)break; }
len = 32 - len; len = 32 - len;
do { do {
@ -9,7 +9,7 @@ uint32 mask = 0x80000000, len = 0, z = 0;
s[z] = 0; s[z] = 0;
} }
void sprintf(_string &str, char *s, ...) { void sprintf(substring &str, const char *s, ...) {
va_list args; va_list args;
char t[2], n[256]; char t[2], n[256];
int i, l, sl, z; int i, l, sl, z;
@ -17,7 +17,7 @@ uint8 pad_type, pad_len;
uint32 num; uint32 num;
char *r; char *r;
va_start(args, s); va_start(args, s);
strcpy(*str, ""); strcpy(str, "");
for(i=0;i<strlen(s);i++) { for(i=0;i<strlen(s);i++) {
if(s[i] == '%') { if(s[i] == '%') {
i++; i++;

View File

@ -1,65 +1,70 @@
/* /*
libvector : version 0.01 ~byuu libvector : version 0.03 ~byuu (08/16/05)
*/ */
#ifndef __LIBVECTOR #ifndef __LIBVECTOR
#define __LIBVECTOR #define __LIBVECTOR
template<typename T> class vector { template<typename T> class vector {
public: private:
T *array; T *array;
int size, sizelimit; int size, sizelimit;
//find next array size that is a power of two
int findsize(int newsize) { int findsize(int newsize) {
int r = 1; int r = 1;
while(r >= 1) { while(r >= 1) {
r <<= 1; r <<= 1;
if(r > sizelimit)return sizelimit; if(r > sizelimit)return sizelimit;
if(r >= newsize)return r; if(r >= newsize) return r;
} }
return size; return size;
} }
public:
void resize(int newsize) { void resize(int newsize) {
T *newarray;
newsize = findsize(newsize); newsize = findsize(newsize);
if(newsize > sizelimit)newsize = sizelimit; if(newsize > sizelimit)newsize = sizelimit;
if(newsize == size)return; if(newsize == size)return;
newarray = (T*)malloc(sizeof(T) * newsize); array = (T*)realloc(array, sizeof(T) * newsize);
if(newsize >= size) {
memcpy(newarray, array, sizeof(T) * size);
} else {
memcpy(newarray, array, sizeof(T) * newsize);
}
free(array);
array = newarray; if(newsize > size) {
size = newsize; for(int i=size;i<newsize;i+=sizeof(T)) {
array[i] = (T)0;
}
}
size = newsize;
} }
vector(int newsize, int newsizelimit) { vector(int newsize, int newsizelimit) {
size = newsize; size = newsize;
sizelimit = newsizelimit; sizelimit = newsizelimit;
array = (T*)malloc(sizeof(T) * size); array = (T*)calloc(size, sizeof(T));
} }
vector(int newsize) { vector(int newsize) {
size = newsize; size = newsize;
sizelimit = 1 << 24; sizelimit = 1 << 24;
array = (T*)malloc(sizeof(T) * size); array = (T*)calloc(size, sizeof(T));
} }
vector() { vector() {
size = 16; size = 16;
sizelimit = 1 << 24; sizelimit = 1 << 24;
array = (T*)malloc(sizeof(T) * size); array = (T*)calloc(size, sizeof(T));
} }
~vector() { ~vector() {
if(array)free(array); if(array) {
free(array);
array = 0;
}
} }
//operator T() { return array[0]; }
inline T &operator[](int index) { inline T &operator[](int index) {
if(index >= size)resize(index + 1); if(index >= size)resize(index + 1);
if(index > sizelimit)return array[size - 1]; if(index > sizelimit)return array[size - 1];

View File

@ -0,0 +1,106 @@
void bCartExLoROM::write_protect(bool r) { write_protected = r; }
uint8 bCartExLoROM::read(uint32 addr) {
uint32 b, w;
addr &= 0xffffff;
b = (addr >> 16);
w = (addr & 0xffff);
//SRAM Region A
if((b & 0x7f) >= 0x30 && (b & 0x7f) <= 0x3f && (w & 0xe000) == 0x6000) {
b &= 0x7f;
if(b >= 0x30 && b <= 0x3f) {
if(sram_size) {
addr = (b - 0x30) * 0x2000 + (w - 0x6000);
addr &= (sram_size - 1);
return sram[addr];
} else {
return 0x00; //no SRAM available
}
} else {
return 0x00; //unmapped
}
}
//SRAM Region B
if(b >= 0x70 && b <= 0x7d) {
if(sram_size) {
addr = (addr & 0xffffff) - 0x700000;
addr &= (sram_size - 1);
return sram[addr];
} else {
return 0x00; //no SRAM available
}
}
if(b <= 0x3f) {
addr = (b << 15) | (addr & 0x7fff);
} else if(b <= 0x7f) {
addr &= 0x3fffff;
} else if(b <= 0xbf) {
b &= 0x7f;
addr = (b << 15) | (addr & 0x7fff);
} else {
addr = sdd1->offset(addr);
}
if(addr < rom_size)return rom[addr];
return 0x00;
}
void bCartExLoROM::write(uint32 addr, uint8 value) {
uint32 b, w;
addr &= 0xffffff;
b = (addr >> 16);
w = (addr & 0xffff);
//SRAM Region A
if((b & 0x7f) >= 0x30 && (b & 0x7f) <= 0x3f && (w & 0xe000) == 0x6000) {
b &= 0x7f;
if(b >= 0x30 && b <= 0x3f) {
if(sram_size) {
addr = (b - 0x30) * 0x2000 + (w - 0x6000);
addr &= (sram_size - 1);
sram[addr] = value;
return;
} else {
return; //no SRAM available
}
} else {
return; //unmapped
}
}
//SRAM Region B
if(b >= 0x70 && b <= 0x7d) {
if(sram_size) {
addr = (addr & 0xffffff) - 0x700000;
addr &= (sram_size - 1);
sram[addr] = value;
} else {
return; //no SRAM available
}
}
if(write_protected == true)return;
if(b <= 0x3f) {
addr = (b << 15) | (addr & 0x7fff);
} else if(b <= 0x7f) {
addr &= 0x3fffff;
} else if(b <= 0xbf) {
b &= 0x7f;
addr = (b << 15) | (addr & 0x7fff);
} else {
addr = sdd1->offset(addr);
}
if(addr < rom_size)rom[addr] = value;
}
void bCartExLoROM::set_cartinfo(CartInfo *ci) {
rom = ci->rom;
sram = ci->sram;
rom_size = ci->rom_size;
sram_size = ci->sram_size;
}

View File

@ -0,0 +1,14 @@
class bCartExLoROM : public Cart {
private:
bool write_protected;
public:
uint8 *rom, *sram;
uint32 rom_size, sram_size;
uint8 read (uint32 addr);
void write(uint32 addr, byte value);
void write_protect(bool r);
void set_cartinfo(CartInfo *ci);
bCartExLoROM() : write_protected(true) {}
};

View File

@ -33,10 +33,13 @@ uint32 b, w;
} }
} }
addr &= 0x3fffff; addr &= ROM_mask;
if(addr < rom_size)return rom[addr];
return 0x00; if(addr >= P0_size) {
addr = P0_size + (addr & (P1_size - 1));
}
return rom[addr];
} }
void bCartHiROM::write(uint32 addr, uint8 value) { void bCartHiROM::write(uint32 addr, uint8 value) {
@ -74,8 +77,14 @@ uint32 b, w;
} }
if(write_protected == true)return; if(write_protected == true)return;
addr &= 0x3fffff;
if(addr < rom_size)rom[addr] = value; addr &= ROM_mask;
if(addr >= P0_size) {
addr = P0_size + (addr & (P1_size - 1));
}
rom[addr] = value;
} }
void bCartHiROM::set_cartinfo(CartInfo *ci) { void bCartHiROM::set_cartinfo(CartInfo *ci) {
@ -83,4 +92,15 @@ void bCartHiROM::set_cartinfo(CartInfo *ci) {
sram = ci->sram; sram = ci->sram;
rom_size = ci->rom_size; rom_size = ci->rom_size;
sram_size = ci->sram_size; sram_size = ci->sram_size;
//calculate highest power of 2, which is the size of the first ROM chip
P0_size = 0x800000;
while(!(rom_size & P0_size))P0_size >>= 1;
P1_size = rom_size - P0_size;
if(rom_size == P0_size) { //cart only contains one ROM chip
ROM_mask = (P0_size - 1);
} else { //cart contains two ROM chips
ROM_mask = (P0_size + P0_size - 1);
}
} }

View File

@ -1,6 +1,7 @@
class bCartHiROM : public Cart { class bCartHiROM : public Cart {
private: private:
bool write_protected; bool write_protected;
uint32 P0_size, P1_size, ROM_mask;
public: public:
uint8 *rom, *sram; uint8 *rom, *sram;

View File

@ -35,17 +35,20 @@ uint32 b, w;
if(w & 0x8000) { if(w & 0x8000) {
b &= 0x7f; b &= 0x7f;
b %= 0x60;
addr = (b << 15) | (addr & 0x7fff); addr = (b << 15) | (addr & 0x7fff);
} else { } else {
b &= 0x7f; b &= 0x7f;
b %= 0x60; if(b == 0x00)b = 0x7f;
if(b == 0x00)b = 0x60;
addr = (((b << 15) | (addr & 0x7fff)) - 0x8000); addr = (((b << 15) | (addr & 0x7fff)) - 0x8000);
} }
if(addr < rom_size)return rom[addr];
return 0x00; addr &= ROM_mask;
if(addr >= P0_size) {
addr = P0_size + (addr & (P1_size - 1));
}
return rom[addr];
} }
void bCartLoROM::write(uint32 addr, uint8 value) { void bCartLoROM::write(uint32 addr, uint8 value) {
@ -83,17 +86,23 @@ uint32 b, w;
} }
if(write_protected == true)return; if(write_protected == true)return;
if(w & 0x8000) { if(w & 0x8000) {
b &= 0x7f; b &= 0x7f;
b %= 0x60;
addr = (b << 15) | (addr & 0x7fff); addr = (b << 15) | (addr & 0x7fff);
} else { } else {
b &= 0x7f; b &= 0x7f;
b %= 0x60; if(b == 0x00)b = 0x7f;
if(b == 0x00)b = 0x60;
addr = (((b << 15) | (addr & 0x7fff)) - 0x8000); addr = (((b << 15) | (addr & 0x7fff)) - 0x8000);
} }
if(addr < rom_size)rom[addr] = value;
addr &= ROM_mask;
if(addr >= P0_size) {
addr = P0_size + (addr & (P1_size - 1));
}
rom[addr] = value;
} }
void bCartLoROM::set_cartinfo(CartInfo *ci) { void bCartLoROM::set_cartinfo(CartInfo *ci) {
@ -101,4 +110,15 @@ void bCartLoROM::set_cartinfo(CartInfo *ci) {
sram = ci->sram; sram = ci->sram;
rom_size = ci->rom_size; rom_size = ci->rom_size;
sram_size = ci->sram_size; sram_size = ci->sram_size;
//calculate highest power of 2, which is the size of the first ROM chip
P0_size = 0x800000;
while(!(rom_size & P0_size))P0_size >>= 1;
P1_size = rom_size - P0_size;
if(rom_size == P0_size) { //cart only contains one ROM chip
ROM_mask = (P0_size - 1);
} else { //cart contains two ROM chips
ROM_mask = (P0_size + P0_size - 1);
}
} }

View File

@ -1,6 +1,7 @@
class bCartLoROM : public Cart { class bCartLoROM : public Cart {
private: private:
bool write_protected; bool write_protected;
uint32 P0_size, P1_size, ROM_mask;
public: public:
uint8 *rom, *sram; uint8 *rom, *sram;

View File

@ -1,22 +1,36 @@
#include "../../base.h" #include "../../base.h"
#include "bcart_lorom.cpp" #include "bcart_lorom.cpp"
#include "bcart_hirom.cpp" #include "bcart_hirom.cpp"
#include "bcart_exlorom.cpp"
#include "bcart_exhirom.cpp" #include "bcart_exhirom.cpp"
bool bMemBus::load_cart(Reader *rf) { bool bMemBus::load_cart(Reader *rf) {
uint32 cksum, icksum, index; uint32 cksum, icksum, index;
char cart_title[24]; char cart_title[24];
uint8 mapper; uint8 mapper, region;
if(rom_loaded == true)return false; if(rom_loaded == true)return false;
rf->read(&rom); rf->read(&rom_image);
rom = rom_image;
rom_size = rf->size(); rom_size = rf->size();
if(rom_size < 32768)return false; 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_size >= 0x410000) {
mapper = EXHIROM; if(rom[0x7fd5] == 0x32) {
mapper = EXLOROM;
} else {
mapper = EXHIROM;
}
goto end; goto end;
} }
@ -33,10 +47,17 @@ uint8 mapper;
mapper = LOROM; mapper = LOROM;
} }
if(rom[0x7fd5] == 0x32 && rom[0xffd5] == 0x32) {
//SFA2 detected
mapper = EXLOROM;
goto end;
}
end: end:
switch(mapper) { switch(mapper) {
case LOROM: index = 0x007fc0;break; case LOROM: index = 0x007fc0;break;
case HIROM: index = 0x00ffc0;break; case HIROM: index = 0x00ffc0;break;
case EXLOROM:index = 0x007fc0;break;
case EXHIROM:index = 0x40ffc0;break; case EXHIROM:index = 0x40ffc0;break;
} }
memcpy(cart_title, (char*)rom + index, 21); memcpy(cart_title, (char*)rom + index, 21);
@ -53,7 +74,10 @@ end:
case 7:sram_size = 128 * 1024;break; case 7:sram_size = 128 * 1024;break;
} }
region = rom[index + 0x19];
dprintf("* Image Name : \"%s\"", cart_title); dprintf("* Image Name : \"%s\"", cart_title);
dprintf("* Region : %s", (region <= 1)?"NTSC":"PAL");
dprintf("* MAD : %0.2x", mapper); dprintf("* MAD : %0.2x", mapper);
dprintf("* SRAM Size : %dkb", sram_size / 1024); dprintf("* SRAM Size : %dkb", sram_size / 1024);
dprintf("* Reset:%0.4x NMI:%0.4x IRQ:%0.4x BRK[n]:%0.4x COP[n]:%0.4x BRK[e]:%0.4x COP[e]:%0.4x", dprintf("* Reset:%0.4x NMI:%0.4x IRQ:%0.4x BRK[n]:%0.4x COP[n]:%0.4x BRK[e]:%0.4x COP[e]:%0.4x",
@ -76,12 +100,20 @@ CartInfo ci;
switch(mapper) { switch(mapper) {
case LOROM: cart = new bCartLoROM(); break; case LOROM: cart = new bCartLoROM(); break;
case HIROM: cart = new bCartHiROM(); break; case HIROM: cart = new bCartHiROM(); break;
case EXLOROM:cart = new bCartExLoROM();break;
case EXHIROM:cart = new bCartExHiROM();break; case EXHIROM:cart = new bCartExHiROM();break;
default:return false; default:return false;
} }
cart->set_cartinfo(&ci); cart->set_cartinfo(&ci);
rom_loaded = true; rom_loaded = true;
if(region == 0 || region == 1) {
snes->set_region(SNES::NTSC);
} else {
snes->set_region(SNES::PAL);
}
return true; return true;
} }
@ -108,7 +140,7 @@ bool bMemBus::save_sram(Writer *wf) {
void bMemBus::unload_cart() { void bMemBus::unload_cart() {
if(rom_loaded == false)return; if(rom_loaded == false)return;
if(rom) free(rom); if(rom_image)free(rom_image);
if(sram)free(sram); if(sram)free(sram);
delete(cart); delete(cart);

View File

@ -1,14 +1,21 @@
#include "bcart_lorom.h" #include "bcart_lorom.h"
#include "bcart_hirom.h" #include "bcart_hirom.h"
#include "bcart_exlorom.h"
#include "bcart_exhirom.h" #include "bcart_exhirom.h"
class bMemBus : public MemBus { class bMemBus : public MemBus {
public: public:
uint8 *rom, *sram, *wram;
//rom_image is the actual image, including header.
//rom is the image sans header, which is actually
//just a pointer to rom_image (with no header), or
//rom_image + 512 (if a header is present).
//rom should never be allocated or released directly.
uint8 *rom_image, *rom, *sram, *wram;
uint32 rom_size, sram_size; uint32 rom_size, sram_size;
bool rom_loaded; bool rom_loaded;
enum { LOROM = 0x20, HIROM = 0x21, EXHIROM = 0x25 }; enum { LOROM = 0x20, HIROM = 0x21, EXLOROM = 0x22, EXHIROM = 0x25 };
uint8 read (uint32 addr); uint8 read (uint32 addr);
void write(uint32 addr, byte value); void write(uint32 addr, byte value);

View File

@ -79,7 +79,7 @@ void Memory::write_long(uint32 addr, uint32 value, uint8 wrap) {
} }
MMIO mmio_unmapped; MMIO mmio_unmapped;
uint8 MMIO::read (uint32 addr) { return 0x00; } uint8 MMIO::read (uint32 addr) { return cpu->regs.mdr; }
void MMIO::write(uint32 addr, uint8 value) {} void MMIO::write(uint32 addr, uint8 value) {}
uint8 MemBus::speed(uint32 addr) { uint8 MemBus::speed(uint32 addr) {

View File

@ -75,6 +75,9 @@ void bPPU::power() {
memset(vram, 0, 65536); memset(vram, 0, 65536);
memset(oam, 0, 544); memset(oam, 0, 544);
memset(cgram, 0, 512); memset(cgram, 0, 512);
region = snes->region();
reset(); reset();
} }
@ -84,6 +87,10 @@ void bPPU::reset() {
memset(sprite_list, 0, sizeof(sprite_list)); memset(sprite_list, 0, sizeof(sprite_list));
//open bus support
regs.ppu1_mdr = 0xff;
regs.ppu2_mdr = 0xff;
//$2100 //$2100
regs.display_disabled = 0; regs.display_disabled = 0;
regs.display_brightness = 0; regs.display_brightness = 0;
@ -133,6 +140,8 @@ void bPPU::reset() {
regs.bg_tdaddr[BG4] = 0x0000; regs.bg_tdaddr[BG4] = 0x0000;
//$210d-$2114 //$210d-$2114
regs.bg_ofslatch = 0x00;
regs.m7_hofs = regs.m7_vofs = 0x0000;
regs.bg_hofs[BG1] = regs.bg_vofs[BG1] = 0x0000; regs.bg_hofs[BG1] = regs.bg_vofs[BG1] = 0x0000;
regs.bg_hofs[BG2] = regs.bg_vofs[BG2] = 0x0000; regs.bg_hofs[BG2] = regs.bg_vofs[BG2] = 0x0000;
regs.bg_hofs[BG3] = regs.bg_vofs[BG3] = 0x0000; regs.bg_hofs[BG3] = regs.bg_vofs[BG3] = 0x0000;
@ -152,6 +161,7 @@ void bPPU::reset() {
regs.mode7_hflip = false; regs.mode7_hflip = false;
//$211b-$2120 //$211b-$2120
regs.m7_latch = 0x00;
regs.m7a = 0x0000; regs.m7a = 0x0000;
regs.m7b = 0x0000; regs.m7b = 0x0000;
regs.m7c = 0x0000; regs.m7c = 0x0000;
@ -300,13 +310,21 @@ void bPPU::oam_write(uint16 addr, uint8 value) {
uint8 bPPU::cgram_read(uint16 addr) { uint8 bPPU::cgram_read(uint16 addr) {
uint8 r; uint8 r;
r = cgram[addr & 511]; addr &= 511;
r = cgram[addr];
if(addr & 1) {
r &= 0x7f;
}
snes->notify(SNES::CGRAM_READ, addr, r); snes->notify(SNES::CGRAM_READ, addr, r);
return r; return r;
} }
void bPPU::cgram_write(uint16 addr, uint8 value) { void bPPU::cgram_write(uint16 addr, uint8 value) {
cgram[addr & 511] = value; addr &= 511;
if(addr & 1) {
value &= 0x7f;
}
cgram[addr] = value;
snes->notify(SNES::CGRAM_WRITE, addr, value); snes->notify(SNES::CGRAM_WRITE, addr, value);
} }
@ -326,31 +344,31 @@ bPPU::bPPU() {
init_tiledata_cache(); init_tiledata_cache();
int i, l; int i, l;
byte r, g, b; uint8 r, g, b;
double m; float m;
uint16 *ptr; uint16 *ptr;
for(l=0;l<16;l++) { for(l=0;l<16;l++) {
mosaic_table[l] = (uint16*)memalloc(4096 * 2, "bPPU::mosaic_table[%2d]", l); mosaic_table[l] = (uint16*)malloc(4096 * 2);
for(i=0;i<4096;i++) { for(i=0;i<4096;i++) {
mosaic_table[l][i] = (i / (l + 1)) * (l + 1); mosaic_table[l][i] = (i / (l + 1)) * (l + 1);
} }
} }
light_table = (uint16*)memalloc(16 * 65536 * 2, "bPPU::light_table"); light_table = (uint16*)malloc(16 * 32768 * 2);
ptr = (word*)light_table; ptr = (uint16*)light_table;
for(l=0;l<16;l++) { for(l=0;l<16;l++) {
m = (double)l / 15.0; m = (float)l / 15.0;
for(i=0;i<65536;i++) { for(i=0;i<32768;i++) {
r = (i ) & 31; r = (i ) & 31;
g = (i >> 5) & 31; g = (i >> 5) & 31;
b = (i >> 10) & 31; b = (i >> 10) & 31;
if(l == 0) { r = g = b = 0; } if(l == 0) { r = g = b = 0; }
else if(l == 15); else if(l == 15);
else { else {
r = (uint8)((double)r * m); r = (uint8)((float)r * m);
g = (uint8)((double)g * m); g = (uint8)((float)g * m);
b = (uint8)((double)b * m); b = (uint8)((float)b * m);
} }
*ptr++ = (r) | (g << 5) | (b << 10); *ptr++ = (r) | (g << 5) | (b << 10);
} }
@ -360,14 +378,30 @@ uint16 *ptr;
bPPU::~bPPU() { bPPU::~bPPU() {
delete(mmio); delete(mmio);
if(vram) memfree(vram, "bPPU::vram"); if(vram) {
if(oam) memfree(oam, "bPPU::oam"); free(vram);
if(cgram)memfree(cgram, "bPPU::cgram"); vram = 0;
}
if(oam) {
free(oam);
oam = 0;
}
if(cgram) {
free(cgram);
cgram = 0;
}
for(int i=0;i<16;i++) { for(int i=0;i<16;i++) {
if(mosaic_table[i])memfree(mosaic_table[i], "bPPU::mosaic_table[%2d]", i); if(mosaic_table[i]) {
free(mosaic_table[i]);
mosaic_table[i] = 0;
}
}
if(light_table) {
memfree(light_table);
light_table = 0;
} }
if(light_table)memfree(light_table, "bPPU::light_table");
} }
bPPUMMIO::bPPUMMIO(bPPU *_ppu) { bPPUMMIO::bPPUMMIO(bPPU *_ppu) {

View File

@ -11,7 +11,9 @@ bPPU *ppu;
class bPPU : public PPU { class bPPU : public PPU {
public: public:
uint8 *vram, *oam, *cgram; 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 { 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 { SC_32x32 = 0, SC_32x64 = 1, SC_64x32 = 2, SC_64x64 = 3 };
@ -31,6 +33,9 @@ struct {
}settings; }settings;
struct { struct {
//open bus support
uint8 ppu1_mdr, ppu2_mdr;
//$2100 //$2100
bool display_disabled; bool display_disabled;
uint8 display_brightness; uint8 display_brightness;
@ -64,6 +69,8 @@ struct {
uint16 bg_tdaddr[4]; uint16 bg_tdaddr[4];
//$210d-$2114 //$210d-$2114
uint8 bg_ofslatch;
uint16 m7_hofs, m7_vofs;
uint16 bg_hofs[4]; uint16 bg_hofs[4];
uint16 bg_vofs[4]; uint16 bg_vofs[4];
@ -81,6 +88,7 @@ struct {
bool mode7_hflip; bool mode7_hflip;
//$211b-$2120 //$211b-$2120
uint8 m7_latch;
uint16 m7a, m7b, m7c, m7d, m7x, m7y; uint16 m7a, m7b, m7c, m7d, m7x, m7y;
//$2121 //$2121

View File

@ -117,42 +117,56 @@ void bPPU::mmio_w210c(uint8 value) {
//BG1HOFS //BG1HOFS
void bPPU::mmio_w210d(uint8 value) { void bPPU::mmio_w210d(uint8 value) {
regs.bg_hofs[BG1] = (value << 8) | (regs.bg_hofs[BG1] >> 8); regs.m7_hofs = (value << 8) | regs.m7_latch;
regs.m7_latch = value;
regs.bg_hofs[BG1] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_hofs[BG1] >> 8) & 7);
regs.bg_ofslatch = value;
} }
//BG1VOFS //BG1VOFS
void bPPU::mmio_w210e(uint8 value) { void bPPU::mmio_w210e(uint8 value) {
regs.bg_vofs[BG1] = (value << 8) | (regs.bg_vofs[BG1] >> 8); regs.m7_vofs = (value << 8) | regs.m7_latch;
regs.m7_latch = value;
regs.bg_vofs[BG1] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_vofs[BG1] >> 8) & 7);
regs.bg_ofslatch = value;
} }
//BG2HOFS //BG2HOFS
void bPPU::mmio_w210f(uint8 value) { void bPPU::mmio_w210f(uint8 value) {
regs.bg_hofs[BG2] = (value << 8) | (regs.bg_hofs[BG2] >> 8); regs.bg_hofs[BG2] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_hofs[BG2] >> 8) & 7);
regs.bg_ofslatch = value;
} }
//BG2VOFS //BG2VOFS
void bPPU::mmio_w2110(uint8 value) { void bPPU::mmio_w2110(uint8 value) {
regs.bg_vofs[BG2] = (value << 8) | (regs.bg_vofs[BG2] >> 8); regs.bg_vofs[BG2] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_vofs[BG2] >> 8) & 7);
regs.bg_ofslatch = value;
} }
//BG3HOFS //BG3HOFS
void bPPU::mmio_w2111(uint8 value) { void bPPU::mmio_w2111(uint8 value) {
regs.bg_hofs[BG3] = (value << 8) | (regs.bg_hofs[BG3] >> 8); regs.bg_hofs[BG3] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_hofs[BG3] >> 8) & 7);
regs.bg_ofslatch = value;
} }
//BG3VOFS //BG3VOFS
void bPPU::mmio_w2112(uint8 value) { void bPPU::mmio_w2112(uint8 value) {
regs.bg_vofs[BG3] = (value << 8) | (regs.bg_vofs[BG3] >> 8); regs.bg_vofs[BG3] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_vofs[BG3] >> 8) & 7);
regs.bg_ofslatch = value;
} }
//BG4HOFS //BG4HOFS
void bPPU::mmio_w2113(uint8 value) { void bPPU::mmio_w2113(uint8 value) {
regs.bg_hofs[BG4] = (value << 8) | (regs.bg_hofs[BG4] >> 8); regs.bg_hofs[BG4] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_hofs[BG4] >> 8) & 7);
regs.bg_ofslatch = value;
} }
//BG4VOFS //BG4VOFS
void bPPU::mmio_w2114(uint8 value) { void bPPU::mmio_w2114(uint8 value) {
regs.bg_vofs[BG4] = (value << 8) | (regs.bg_vofs[BG4] >> 8); regs.bg_vofs[BG4] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_vofs[BG4] >> 8) & 7);
regs.bg_ofslatch = value;
} }
//VMAIN //VMAIN
@ -210,38 +224,44 @@ uint16 addr = get_vram_address() + 1;
//M7SEL //M7SEL
void bPPU::mmio_w211a(uint8 value) { void bPPU::mmio_w211a(uint8 value) {
regs.mode7_repeat = (value >> 6) & 3; regs.mode7_repeat = (value >> 6) & 3;
regs.mode7_vflip = !!(value & 0x02); regs.mode7_vflip = !!(value & 0x02);
regs.mode7_hflip = !!(value & 0x01); regs.mode7_hflip = !!(value & 0x01);
} }
//M7A //M7A
void bPPU::mmio_w211b(uint8 value) { void bPPU::mmio_w211b(uint8 value) {
regs.m7a = (value << 8) | (regs.m7a >> 8); regs.m7a = (value << 8) | regs.m7_latch;
regs.m7_latch = value;
} }
//M7B //M7B
void bPPU::mmio_w211c(uint8 value) { void bPPU::mmio_w211c(uint8 value) {
regs.m7b = (value << 8) | (regs.m7b >> 8); regs.m7b = (value << 8) | regs.m7_latch;
regs.m7_latch = value;
} }
//M7C //M7C
void bPPU::mmio_w211d(uint8 value) { void bPPU::mmio_w211d(uint8 value) {
regs.m7c = (value << 8) | (regs.m7c >> 8); regs.m7c = (value << 8) | regs.m7_latch;
regs.m7_latch = value;
} }
//M7D //M7D
void bPPU::mmio_w211e(uint8 value) { void bPPU::mmio_w211e(uint8 value) {
regs.m7d = (value << 8) | (regs.m7d >> 8); regs.m7d = (value << 8) | regs.m7_latch;
regs.m7_latch = value;
} }
//M7X //M7X
void bPPU::mmio_w211f(uint8 value) { void bPPU::mmio_w211f(uint8 value) {
regs.m7x = (value << 8) | (regs.m7x >> 8); regs.m7x = (value << 8) | regs.m7_latch;
regs.m7_latch = value;
} }
//M7Y //M7Y
void bPPU::mmio_w2120(uint8 value) { void bPPU::mmio_w2120(uint8 value) {
regs.m7y = (value << 8) | (regs.m7y >> 8); regs.m7y = (value << 8) | regs.m7_latch;
regs.m7_latch = value;
} }
//CGADD //CGADD
@ -250,7 +270,13 @@ void bPPU::mmio_w2121(uint8 value) {
} }
//CGDATA //CGDATA
//note: CGRAM palette data format is 15-bits
//(0,bbbbb,ggggg,rrrrr). Highest bit is ignored,
//as evidenced by $213b CGRAM data reads.
void bPPU::mmio_w2122(uint8 value) { void bPPU::mmio_w2122(uint8 value) {
if(regs.cgram_addr & 1) {
value &= 0x7f;
}
cgram_write(regs.cgram_addr, value); cgram_write(regs.cgram_addr, value);
regs.cgram_addr++; regs.cgram_addr++;
regs.cgram_addr &= 0x01ff; regs.cgram_addr &= 0x01ff;
@ -404,21 +430,24 @@ void bPPU::mmio_w2133(uint8 value) {
uint8 bPPU::mmio_r2134() { uint8 bPPU::mmio_r2134() {
uint32 r; uint32 r;
r = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
return (r); regs.ppu1_mdr = r;
return regs.ppu1_mdr;
} }
//MPYM //MPYM
uint8 bPPU::mmio_r2135() { uint8 bPPU::mmio_r2135() {
uint32 r; uint32 r;
r = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
return (r >> 8); regs.ppu1_mdr = r >> 8;
return regs.ppu1_mdr;
} }
//MPYH //MPYH
uint8 bPPU::mmio_r2136() { uint8 bPPU::mmio_r2136() {
uint32 r; uint32 r;
r = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
return (r >> 16); regs.ppu1_mdr = r >> 16;
return regs.ppu1_mdr;
} }
//SLHV //SLHV
@ -426,70 +455,84 @@ uint8 bPPU::mmio_r2137() {
if(cpu->pio_status() & 0x80) { if(cpu->pio_status() & 0x80) {
latch_counters(); latch_counters();
} }
return 0x00; return cpu->regs.mdr;
} }
//OAMDATAREAD //OAMDATAREAD
uint8 bPPU::mmio_r2138() { uint8 bPPU::mmio_r2138() {
uint8 r; regs.ppu1_mdr = oam_read(regs.oam_addr);
r = oam_read(regs.oam_addr);
if(!(regs.oam_addr & 1)) { if(!(regs.oam_addr & 1)) {
regs.oam_latchdata = r; regs.oam_latchdata = regs.ppu1_mdr;
} }
regs.oam_addr++; regs.oam_addr++;
regs.oam_addr &= 0x03ff; regs.oam_addr &= 0x03ff;
return r; return regs.ppu1_mdr;
} }
//VMDATALREAD //VMDATALREAD
uint8 bPPU::mmio_r2139() { uint8 bPPU::mmio_r2139() {
uint16 addr = get_vram_address(); uint16 addr = get_vram_address();
uint8 r = regs.vram_readbuffer; regs.ppu1_mdr = regs.vram_readbuffer;
if(regs.vram_incmode == 0) { if(regs.vram_incmode == 0) {
addr &= 0xfffe; addr &= 0xfffe;
regs.vram_readbuffer = vram_read(addr); regs.vram_readbuffer = vram_read(addr);
regs.vram_readbuffer |= vram_read(addr + 1) << 8; regs.vram_readbuffer |= vram_read(addr + 1) << 8;
regs.vram_addr += regs.vram_incsize; regs.vram_addr += regs.vram_incsize;
} }
return r; return regs.ppu1_mdr;
} }
//VMDATAHREAD //VMDATAHREAD
uint8 bPPU::mmio_r213a() { uint8 bPPU::mmio_r213a() {
uint16 addr = get_vram_address() + 1; uint16 addr = get_vram_address() + 1;
uint8 r = regs.vram_readbuffer >> 8; regs.ppu1_mdr = regs.vram_readbuffer >> 8;
if(regs.vram_incmode == 1) { if(regs.vram_incmode == 1) {
addr &= 0xfffe; addr &= 0xfffe;
regs.vram_readbuffer = vram_read(addr); regs.vram_readbuffer = vram_read(addr);
regs.vram_readbuffer |= vram_read(addr + 1) << 8; regs.vram_readbuffer |= vram_read(addr + 1) << 8;
regs.vram_addr += regs.vram_incsize; regs.vram_addr += regs.vram_incsize;
} }
return r; return regs.ppu1_mdr;
} }
//CGDATAREAD //CGDATAREAD
//note: CGRAM palette data is 15-bits (0,bbbbb,ggggg,rrrrr)
//therefore, the high byte read from each color does not
//update bit 7 of the PPU2 MDR.
uint8 bPPU::mmio_r213b() { uint8 bPPU::mmio_r213b() {
uint8 r; if(!(regs.cgram_addr & 1)) {
r = cgram_read(regs.cgram_addr); regs.ppu2_mdr = cgram_read(regs.cgram_addr) & 0xff;
} else {
regs.ppu2_mdr &= 0x80;
regs.ppu2_mdr |= cgram_read(regs.cgram_addr) & 0x7f;
}
regs.cgram_addr++; regs.cgram_addr++;
regs.cgram_addr &= 0x01ff; regs.cgram_addr &= 0x01ff;
return r; return regs.ppu2_mdr;
} }
//OPHCT //OPHCT
uint8 bPPU::mmio_r213c() { uint8 bPPU::mmio_r213c() {
uint16 r = regs.hcounter; if(!regs.latch_hcounter) {
if(regs.latch_hcounter)r >>= 8; regs.ppu2_mdr = regs.hcounter & 0xff;
} else {
regs.ppu2_mdr &= 0xfe;
regs.ppu2_mdr |= (regs.hcounter >> 8) & 1;
}
regs.latch_hcounter ^= 1; regs.latch_hcounter ^= 1;
return r; return regs.ppu2_mdr;
} }
//OPVCT //OPVCT
uint8 bPPU::mmio_r213d() { uint8 bPPU::mmio_r213d() {
uint16 r = regs.vcounter; if(!regs.latch_vcounter) {
if(regs.latch_vcounter)r >>= 8; regs.ppu2_mdr = regs.vcounter & 0xff;
} else {
regs.ppu2_mdr &= 0xfe;
regs.ppu2_mdr |= (regs.vcounter >> 8) & 1;
}
regs.latch_vcounter ^= 1; regs.latch_vcounter ^= 1;
return r; return regs.ppu2_mdr;
} }
//STAT77 //STAT77
@ -498,7 +541,8 @@ uint8 r = 0x00;
r |= (regs.time_over) ?0x80:0x00; r |= (regs.time_over) ?0x80:0x00;
r |= (regs.range_over)?0x40:0x00; r |= (regs.range_over)?0x40:0x00;
r |= 0x01; //PPU1 version number r |= 0x01; //PPU1 version number
return r; regs.ppu1_mdr = r;
return regs.ppu1_mdr;
} }
//STAT78 //STAT78
@ -509,19 +553,39 @@ uint8 r = 0x00;
r |= cpu->interlace_field() << 7; r |= cpu->interlace_field() << 7;
if(!(cpu->pio_status() & 0x80)) { if(!(cpu->pio_status() & 0x80)) {
r |= 1 << 6; r |= 0x40;
} else if(regs.counters_latched == true) { } else if(regs.counters_latched == true) {
r |= 1 << 6; r |= 0x40;
regs.counters_latched = false; regs.counters_latched = false;
} }
r |= (1 << 5); r |= (regs.ppu2_mdr & 0x20);
r |= (region << 4); //0 = NTSC, 1 = PAL
r |= 0x03; //PPU2 version number r |= 0x03; //PPU2 version number
return r; regs.ppu2_mdr = r;
return regs.ppu2_mdr;
} }
uint8 bPPUMMIO::read(uint32 addr) { uint8 bPPUMMIO::read(uint32 addr) {
//cpu->sync();
switch(addr) { switch(addr) {
case 0x2104:
case 0x2105:
case 0x2106:
case 0x2108:
case 0x2109:
case 0x210a:
case 0x2114:
case 0x2115:
case 0x2116:
case 0x2118:
case 0x2119:
case 0x211a:
case 0x2124:
case 0x2125:
case 0x2126:
case 0x2128:
case 0x2129:
case 0x212a:
return ppu->regs.ppu1_mdr;
case 0x2134:return ppu->mmio_r2134(); //MPYL case 0x2134:return ppu->mmio_r2134(); //MPYL
case 0x2135:return ppu->mmio_r2135(); //MPYM case 0x2135:return ppu->mmio_r2135(); //MPYM
case 0x2136:return ppu->mmio_r2136(); //MPYH case 0x2136:return ppu->mmio_r2136(); //MPYH
@ -535,11 +599,11 @@ uint8 bPPUMMIO::read(uint32 addr) {
case 0x213e:return ppu->mmio_r213e(); //STAT77 case 0x213e:return ppu->mmio_r213e(); //STAT77
case 0x213f:return ppu->mmio_r213f(); //STAT78 case 0x213f:return ppu->mmio_r213f(); //STAT78
} }
return 0x00;
return cpu->regs.mdr;
} }
void bPPUMMIO::write(uint32 addr, uint8 value) { void bPPUMMIO::write(uint32 addr, uint8 value) {
//cpu->sync();
switch(addr) { switch(addr) {
case 0x2100:ppu->mmio_w2100(value);return; //INIDISP case 0x2100:ppu->mmio_w2100(value);return; //INIDISP
case 0x2101:ppu->mmio_w2101(value);return; //OBSEL case 0x2101:ppu->mmio_w2101(value);return; //OBSEL

View File

@ -18,6 +18,25 @@ uint16 opt_valid_bit; //offset-per-tile valid flag bit
opt_valid_bit = 0x0000; opt_valid_bit = 0x0000;
} }
//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;
if(regs.bg_mode == 0) {
switch(bg) {
case BG1:bgpal_index = 0;break;
case BG2:bgpal_index = 32;break;
case BG3:bgpal_index = 64;break;
case BG4:bgpal_index = 96;break;
}
} else {
bgpal_index = 0;
}
uint8 pal_size, tiledata_size; uint8 pal_size, tiledata_size;
switch(color_depth) { switch(color_depth) {
case COLORDEPTH_4: case COLORDEPTH_4:
@ -193,7 +212,7 @@ int _pri;
render_bg_tile(color_depth, tile_num); render_bg_tile(color_depth, tile_num);
} }
pal_index = ((t >> 10) & 7) * pal_size; pal_index = ((t >> 10) & 7) * pal_size + bgpal_index;
if(mirror_y) { ypos = (7 - (mosaic_y & 7)); } if(mirror_y) { ypos = (7 - (mosaic_y & 7)); }
else { ypos = ( (mosaic_y & 7)); } else { ypos = ( (mosaic_y & 7)); }

View File

@ -59,7 +59,7 @@ uint16 *ptr;
} }
uint16 *ltable; uint16 *ltable;
ltable = (uint16*)light_table + (regs.display_brightness << 16); ltable = (uint16*)light_table + (regs.display_brightness << 15);
if(_screen_width == 256) { if(_screen_width == 256) {
for(x=0;x<256;x++) { for(x=0;x<256;x++) {

View File

@ -2,25 +2,25 @@
((x) & ((1 << 10) - 1)) + (((((x) & (1 << 13)) ^ (1 << 13)) - (1 << 13)) >> 3) ((x) & ((1 << 10) - 1)) + (((((x) & (1 << 13)) ^ (1 << 13)) - (1 << 13)) >> 3)
#define CAST_WORDTOINT(x) \ #define CAST_WORDTOINT(x) \
(int)(((x & 0x8000)?(x | 0xffff0000):(x & 0x00007fff))) (int32)(((x & 0x8000) ? (x | 0xffff0000) : (x & 0x00007fff)))
void bPPU::render_line_mode7(uint8 bg1_pri, uint8 bg2b_pri, uint8 bg2a_pri) { void bPPU::render_line_mode7(uint8 bg1_pri, uint8 bg2b_pri, uint8 bg2a_pri) {
int x; int32 x;
int step_m7a, step_m7c, m7a, m7b, m7c, m7d; int32 step_m7a, step_m7c, m7a, m7b, m7c, m7d;
int hoffset, voffset; int32 hoffset, voffset;
int centerx, centery; int32 centerx, centery;
int xx, yy; int32 xx, yy;
int px, py; int32 px, py;
int tx, ty, tile, palette; int32 tx, ty, tile, palette;
uint8 layer_pos; uint8 layer_pos;
hoffset = (CAST_WORDTOINT(regs.bg_hofs[BG1]) << 7) >> 7; hoffset = ((int32)regs.m7_hofs << 19) >> 19;
voffset = (CAST_WORDTOINT(regs.bg_vofs[BG1]) << 7) >> 7; voffset = ((int32)regs.m7_vofs << 19) >> 19;
centerx = (CAST_WORDTOINT(regs.m7x) << 7) >> 7; centerx = ((int32)regs.m7x << 19) >> 19;
centery = (CAST_WORDTOINT(regs.m7y) << 7) >> 7; centery = ((int32)regs.m7y << 19) >> 19;
if(regs.mode7_vflip == true) { if(regs.mode7_vflip == true) {
yy = 223 - _y; yy = 255 - _y;
} else { } else {
yy = _y; yy = _y;
} }

View File

@ -1,230 +0,0 @@
void bPPU::set_sprite_attributes(uint8 sprite_num) {
uint32 t;
uint8 size, b;
uint16 x;
t = *((uint32*)oam + sprite_num);
b = oam[512 + (sprite_num >> 2)];
switch(sprite_num & 3) {
case 0: size = !!(b & 0x02); x = (b & 0x01)?0x100:0; break;
case 1: size = !!(b & 0x08); x = (b & 0x04)?0x100:0; break;
case 2: size = !!(b & 0x20); x = (b & 0x10)?0x100:0; break;
case 3: size = !!(b & 0x80); x = (b & 0x40)?0x100:0; break;
}
current_sprite.num = sprite_num;
current_sprite.priority = (t >> 28) & 3;
current_sprite.x = x | (t & 0xff);
current_sprite.y = ((t >> 8) + 1) & 0xff;
current_sprite.v_flip = !!(t & 0x80000000);
current_sprite.h_flip = !!(t & 0x40000000);
current_sprite.palette = (t >> 25) & 7;
current_sprite.character = (t >> 16) & 0x01ff;
//size: 0 = small, 1 = large
switch(regs.oam_basesize) {
case 0:
if(!size) { current_sprite.width = 8; current_sprite.height = 8; }
else { current_sprite.width = 16; current_sprite.height = 16; }
break;
case 1:
if(!size) { current_sprite.width = 8; current_sprite.height = 8; }
else { current_sprite.width = 32; current_sprite.height = 32; }
break;
case 2:
if(!size) { current_sprite.width = 8; current_sprite.height = 8; }
else { current_sprite.width = 64; current_sprite.height = 64; }
break;
case 3:
if(!size) { current_sprite.width = 16; current_sprite.height = 16; }
else { current_sprite.width = 32; current_sprite.height = 32; }
break;
case 4:
if(!size) { current_sprite.width = 16; current_sprite.height = 16; }
else { current_sprite.width = 64; current_sprite.height = 64; }
break;
case 5:
if(!size) { current_sprite.width = 32; current_sprite.height = 32; }
else { current_sprite.width = 64; current_sprite.height = 64; }
break;
case 6:
if(!size) { current_sprite.width = 16; current_sprite.height = 32; }
else { current_sprite.width = 32; current_sprite.height = 64; }
break;
case 7:
if(!size) { current_sprite.width = 16; current_sprite.height = 32; }
else { current_sprite.width = 32; current_sprite.height = 32; }
break;
}
}
void bPPU::render_oam_sprite() {
uint16 pos, col, chr, tiledata_inc;
uint8 d0, d1, d2, d3, pal_index;
int x, y, z, x1, mx, mask, p;
int tile_width;
//uint8 item_inc, tile_inc;
tile_width = current_sprite.width >> 3; //e.x. 16x16 sprite = 2x2 tiles
regs.oam_itemcount++;
//add all visible tiles to regs.oam_tilecount
if(current_sprite.x > 256) {
//if sprite clips on left edge of the screen
regs.oam_tilecount += ((current_sprite.x + current_sprite.width + 7) & 511) >> 3;
} else if(current_sprite.x + current_sprite.width >= 257) {
//if sprite clips on right edge of screen
regs.oam_tilecount += (257 - current_sprite.x + 7) >> 3;
} else {
//if entire sprite is visible
regs.oam_tilecount += current_sprite.width >> 3;
}
//if(_y == 0xa0)dprintf("* oam_itemcount=%d, oam_tilecount=%d", regs.oam_itemcount, regs.oam_tilecount);
if(regs.bg_enabled[OAM] == false && regs.bgsub_enabled[OAM] == false)return;
if(regs.oam_tilecount > 34)return;
if(regs.oam_itemcount > 32)return;
if(_interlace == true && _screen_width == 512) {
y = (_y << 1) + _interlace_field;
} else {
y = _y;
}
x = current_sprite.x;
if(_screen_width == 512) {
x <<= 1;
}
if(current_sprite.v_flip) {
y = ((current_sprite.height - 1) - (_y - current_sprite.y));
} else {
y = (_y - current_sprite.y);
}
if(regs.oam_halve == true) {
y <<= 1;
if(_interlace == true && _screen_width == 512) {
y += _interlace_field;
}
}
y &= 255;
chr = current_sprite.character;
tiledata_inc = (chr & 0x100)?(regs.oam_nameselect << 13):0;
chr += (y >> 3) << 4;
pal_index = (current_sprite.palette << 4);
for(x1=0;x1<tile_width;x1++) {
if(current_sprite.h_flip)mx = (tile_width - 1) - x1;
else mx = x1;
pos = regs.oam_tdaddr + ((chr + mx) << 5) + ((y & 7) << 1) + tiledata_inc;
d0 = vram[pos ];
d1 = vram[pos + 1];
d2 = vram[pos + 16];
d3 = vram[pos + 17];
for(z=0;z<8;z++) {
if(current_sprite.h_flip) {
mask = 0x01 << z;
} else {
mask = 0x80 >> z;
}
x &= 511;
if(x < _screen_width) {
col = 0;
if(d0 & mask)col += 1;
if(d1 & mask)col += 2;
if(d2 & mask)col += 4;
if(d3 & mask)col += 8;
if(col) {
col += pal_index;
col += 128;
if(oam_line_pri[x] == OAM_PRI_NONE) {
oam_line_pal[x] = col;
oam_line_pri[x] = current_sprite.priority;
}
if(_screen_width == 512) {
if(oam_line_pri[x + 1] == OAM_PRI_NONE) {
oam_line_pal[x + 1] = col;
oam_line_pri[x + 1] = current_sprite.priority;
}
}
}
}
x += (_screen_width == 512)?2:1;
}
}
}
void bPPU::render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) {
int s, x;
bool _bg_enabled = regs.bg_enabled[OAM];
bool _bgsub_enabled = regs.bgsub_enabled[OAM];
uint8 *wt_main = main_windowtable[OAM];
uint8 *wt_sub = sub_windowtable[OAM];
build_window_tables(OAM);
regs.oam_itemcount = 0;
regs.oam_tilecount = 0;
memset(oam_line_pri, OAM_PRI_NONE, 512);
for(s=0;s<128;s++) {
set_sprite_attributes((s + regs.oam_firstsprite) & 127);
//if sprite is entirely offscreen and doesn't wrap around to the left side of the screen,
//then it is not counted. 256 is correct, and not 255 -- as one might first expect
if(current_sprite.x > 256 && ((current_sprite.x + current_sprite.width) & 511) > 256)continue;
//if(_y == 0xa0)
//dprintf("* y: %d, fs: %d, sprite: %d, width: %d, height: %d, x: %d, y: %d",
// _y, regs.oam_firstsprite, (s + regs.oam_firstsprite) & 127,
// current_sprite.width, current_sprite.height, current_sprite.x, current_sprite.y);
if(regs.oam_halve == false) {
if(_y >= current_sprite.y && _y < (current_sprite.y + current_sprite.height)) {
render_oam_sprite();
} else if((current_sprite.y + current_sprite.height) >= 256 && _y < ((current_sprite.y + current_sprite.height) & 255)) {
render_oam_sprite();
}
} else {
if(_y >= current_sprite.y && _y < (current_sprite.y + (current_sprite.height >> 1))) {
render_oam_sprite();
} else if((current_sprite.y + (current_sprite.height >> 1)) >= 256 && _y < ((current_sprite.y + (current_sprite.height >> 1)) & 255)) {
render_oam_sprite();
}
}
}
regs.time_over |= (regs.oam_tilecount > 34);
regs.range_over |= (regs.oam_itemcount > 32);
//dprintf("* line: %d, t = %d, r = %d, tc = %d, ic = %d", _y,
//regs.time_over, regs.range_over, regs.oam_tilecount, regs.oam_itemcount);
if(_bg_enabled == false && _bgsub_enabled == false)return;
int _pri;
for(x=0;x<_screen_width;x++) {
if(oam_line_pri[x] == OAM_PRI_NONE)continue;
switch(oam_line_pri[x]) {
case 0:_pri = pri0_pos;break;
case 1:_pri = pri1_pos;break;
case 2:_pri = pri2_pos;break;
case 3:_pri = pri3_pos;break;
}
if(main_colorwindowtable[x]) {
if(_bg_enabled == true && !wt_main[x]) {
if(pixel_cache[x].pri_main < _pri) {
pixel_cache[x].pri_main = _pri;
pixel_cache[x].bg_main = PC_OAM;
pixel_cache[x].src_main = oam_line_pal[x];
}
}
if(_bgsub_enabled == true && !wt_sub[x]) {
if(pixel_cache[x].pri_sub < _pri) {
pixel_cache[x].pri_sub = _pri;
pixel_cache[x].bg_sub = PC_OAM;
pixel_cache[x].src_sub = oam_line_pal[x];
}
}
}
}
}

73
src/reader/filereader.cpp Normal file
View File

@ -0,0 +1,73 @@
uint32 FileReader::size() {
return fsize;
}
//This function will allocate memory even if open() fails.
//This is needed so that when SRAM files do not exist, the
//memory for the SRAM data will be allocated still.
//The memory is flushed to 0x00 when no file is opened.
void FileReader::read(uint8 **buffer, uint32 length) {
uint8 *data;
if(length == 0) {
//read the entire file into RAM
data = (uint8*)memalloc(fsize);
memset(data, 0, fsize);
if(fp)fread(data, 1, fsize, fp);
} else if(length > fsize) {
//read the entire file into RAM, pad the rest with 0x00s
data = (uint8*)memalloc(length);
memset(data, 0, length);
if(fp)fread(data, 1, fsize, fp);
} else { //fsize >= length
//read only what was requested
data = (uint8*)memalloc(length);
memset(data, 0, length);
if(fp)fread(data, 1, length, fp);
}
*buffer = data;
}
bool FileReader::open(char *fn) {
fp = fopen(fn, "rb");
if(!fp)return false;
fseek(fp, 0, SEEK_END);
fsize = ftell(fp);
fseek(fp, 0, SEEK_SET);
//empty file?
if(fsize == 0) {
fclose(fp);
fp = 0;
return false;
}
return true;
}
void FileReader::close() {
if(fp) {
fclose(fp);
fp = 0;
}
}
void FileWriter::write(uint8 *buffer, uint32 length) {
if(!fp)return;
fwrite(buffer, 1, length, fp);
}
bool FileWriter::open(char *fn) {
fp = fopen(fn, "wb");
if(!fp)return false;
return true;
}
void FileWriter::close() {
if(fp) {
fclose(fp);
fp = 0;
}
}

27
src/reader/filereader.h Normal file
View File

@ -0,0 +1,27 @@
class FileReader : public Reader {
private:
FILE *fp;
uint32 fsize;
public:
uint32 size();
void read(uint8 **buffer, uint32 length = 0);
bool open(char *fn);
void close();
FileReader() { fp = 0; fsize = 0; }
~FileReader() { if(fp)fclose(fp); }
};
class FileWriter : public Writer {
private:
FILE *fp;
public:
void write(uint8 *buffer, uint32 length);
bool open(char *fn);
void close();
FileWriter() { fp = 0; }
~FileWriter() { if(fp)fclose(fp); }
};

View File

@ -1,79 +1,2 @@
#include "../base.h" #include "../base.h"
#include "filereader.cpp"
uint32 FileReader::size() {
return fsize;
}
/*
This function will allocate memory even if open() fails.
This is needed so that when SRAM files do not exist, the
memory for the SRAM data will be allocated still.
The memory is flushed to 0x00 when no file is opened.
*/
void FileReader::read(uint8 **buffer, uint32 length) {
uint8 *data;
if(length == 0) {
/* read the entire file into RAM */
data = (uint8*)memalloc(fsize);
memset(data, 0, fsize);
if(fp)fread(data, 1, fsize, fp);
} else if(length > fsize) {
/* read the entire file into RAM, pad the rest with 0x00s */
data = (uint8*)memalloc(length);
memset(data, 0, length);
if(fp)fread(data, 1, fsize, fp);
} else { //fsize >= length
/* read as much of the file as possible, truncate the rest */
data = (uint8*)memalloc(length);
memset(data, 0, length);
if(fp)fread(data, 1, length, fp);
}
*buffer = data;
}
bool FileReader::open(uint8 type, char *fn) {
fp = fopen(fn, "rb");
if(!fp)return false;
fseek(fp, 0, SEEK_END);
fsize = ftell(fp);
fseek(fp, 0, SEEK_SET);
if(type == TYPE_ROM) {
/* remove header if it exists */
if((fsize & 0xfff) == 0x200) {
fsize -= 0x200;
fseek(fp, 0x200, SEEK_SET);
}
}
/* empty file? */
if(fsize == 0) {
fclose(fp);
return false;
}
return true;
}
void FileReader::close() {
if(fp)fclose(fp);
}
void FileWriter::write(uint8 *buffer, uint32 length) {
if(!fp)return;
fwrite(buffer, 1, length, fp);
}
bool FileWriter::open(char *fn) {
fp = fopen(fn, "wb");
if(!fp)return false;
return true;
}
void FileWriter::close() {
if(fp)fclose(fp);
}

View File

@ -4,39 +4,9 @@ public:
virtual void read(uint8 **buffer, uint32 length = 0) = 0; virtual void read(uint8 **buffer, uint32 length = 0) = 0;
}; };
class FileReader : public Reader {
private:
FILE *fp;
uint32 fsize;
public:
enum {
TYPE_ROM = 0,
TYPE_SRAM = 1
};
uint32 size();
void read(uint8 **buffer, uint32 length = 0);
bool open(uint8 type, char *fn);
void close();
FileReader() { fp = 0; fsize = 0; }
~FileReader() { if(fp)fclose(fp); }
};
class Writer { class Writer {
public: public:
virtual void write(uint8 *buffer, uint32 length) = 0; virtual void write(uint8 *buffer, uint32 length) = 0;
}; };
class FileWriter : public Writer { #include "filereader.h"
private:
FILE *fp;
public:
void write(uint8 *buffer, uint32 length);
bool open(char *fn);
void close();
FileWriter() { fp = 0; }
~FileWriter() { if(fp)fclose(fp); }
};

View File

@ -7,7 +7,8 @@ OBJS = sdlmain.o \
cpu.o bcpu.o \ cpu.o bcpu.o \
apu.o bapu.o bapuskip.o \ apu.o bapu.o bapuskip.o \
ppu.o bppu.o \ ppu.o bppu.o \
snes.o snes.o \
srtc.o sdd1.o
all: $(OBJS) all: $(OBJS)
$(CC) $(CFLAGS) $(OBJS) `sdl11-config --cflags --libs` -o bsnes_sdl $(CC) $(CFLAGS) $(OBJS) `sdl11-config --cflags --libs` -o bsnes_sdl
@ -71,7 +72,7 @@ bppu.o: ../ppu/bppu/*
############## ##############
### reader ### ### reader ###
############## ##############
reader.o: ../reader/reader.cpp ../reader/reader.h reader.o: ../reader/*.cpp ../reader/*.h
$(CC) $(CFLAGS) -c ../reader/reader.cpp $(CC) $(CFLAGS) -c ../reader/reader.cpp
############ ############
@ -79,3 +80,15 @@ reader.o: ../reader/reader.cpp ../reader/reader.h
############ ############
snes.o: ../snes/*.cpp ../snes/*.h snes.o: ../snes/*.cpp ../snes/*.h
$(CC) $(CFLAGS) -c ../snes/snes.cpp $(CC) $(CFLAGS) -c ../snes/snes.cpp
############
### srtc ###
############
srtc.o: ../chip/srtc/*.cpp ../chip/srtc/*.h
$(CC) $(CFLAGS) -c ../chip/srtc/srtc.cpp
############
### sdd1 ###
############
sdd1.o: ../chip/sdd1/*.cpp ../chip/sdd1/*.h
$(CC) $(CFLAGS) -c ../chip/sdd1/sdd1.cpp

View File

@ -7,7 +7,8 @@ OBJS = sdlmain.obj \
cpu.obj bcpu.obj \ cpu.obj bcpu.obj \
apu.obj bapu.obj bapuskip.obj \ apu.obj bapu.obj bapuskip.obj \
ppu.obj bppu.obj \ ppu.obj bppu.obj \
snes.obj snes.obj \
srtc.obj sdd1.obj
LIBS = kernel32.lib user32.lib gdi32.lib sdlmain.lib sdl.lib LIBS = kernel32.lib user32.lib gdi32.lib sdlmain.lib sdl.lib
all: $(OBJS) all: $(OBJS)
@ -72,7 +73,7 @@ bppu.obj: ../ppu/bppu/*
############## ##############
### reader ### ### reader ###
############## ##############
reader.obj: ../reader/reader.cpp ../reader/reader.h reader.obj: ../reader/*.cpp ../reader/*.h
$(CC) $(CFLAGS) /c ../reader/reader.cpp $(CC) $(CFLAGS) /c ../reader/reader.cpp
############ ############
@ -80,3 +81,15 @@ reader.obj: ../reader/reader.cpp ../reader/reader.h
############ ############
snes.obj: ../snes/*.cpp ../snes/*.h snes.obj: ../snes/*.cpp ../snes/*.h
$(CC) $(CFLAGS) /c ../snes/snes.cpp $(CC) $(CFLAGS) /c ../snes/snes.cpp
############
### srtc ###
############
srtc.obj: ../chip/srtc/*.cpp ../chip/srtc/*.h
$(CC) $(CFLAGS) /c ../chip/srtc/srtc.cpp
############
### sdd1 ###
############
sdd1.obj: ../chip/sdd1/*.cpp ../chip/sdd1/*.h
$(CC) $(CFLAGS) /c ../chip/sdd1/sdd1.cpp

View File

@ -23,7 +23,7 @@ bool ROMImage::load() {
dprintf("* Loading \"%s\"...", rom_fn); dprintf("* Loading \"%s\"...", rom_fn);
FileReader *rf = new FileReader(); FileReader *rf = new FileReader();
if(!rf->open(FileReader::TYPE_ROM, rom_fn)) { if(!rf->open(rom_fn)) {
alert("Error loading image file [%s]!", rom_fn); alert("Error loading image file [%s]!", rom_fn);
return false; return false;
} }
@ -33,7 +33,7 @@ FileReader *rf = new FileReader();
CartInfo ci; CartInfo ci;
mem_bus->get_cartinfo(&ci); mem_bus->get_cartinfo(&ci);
if(ci.sram_size != 0) { if(ci.sram_size != 0) {
rf->open(FileReader::TYPE_SRAM, sram_fn); rf->open(sram_fn);
mem_bus->load_sram(static_cast<Reader*>(rf)); mem_bus->load_sram(static_cast<Reader*>(rf));
rf->close(); rf->close();
} }

View File

@ -1,10 +1,8 @@
#define _WIN32_
#define INTERFACE_MAIN #define INTERFACE_MAIN
#define BSNES_VERSION "0.010" #define BSNES_VERSION "0.011"
#define BSNES_TITLE "bsnes/SDL v" BSNES_VERSION #define BSNES_TITLE "bsnes/SDL v" BSNES_VERSION
#include "sdlmain.h"
#include "../base.h" #include "../base.h"
#include "sdlmain.h"
#ifdef _WIN32_ #ifdef _WIN32_
HWND hwnd; HWND hwnd;
@ -57,6 +55,8 @@ void init_snes() {
ppu = new bPPU(); ppu = new bPPU();
snes = new bSNES(); snes = new bSNES();
bsnes = static_cast<bSNES*>(snes); bsnes = static_cast<bSNES*>(snes);
snes->init();
} }
void term_snes() { void term_snes() {

View File

@ -1,40 +1,87 @@
#include "../base.h" #include "../base.h"
void SNES::run() { void SNES::run() {
cpu->run(); uint32 cycles;
if(apusync.cycles < 0) {
cpu->run();
apusync.cycles += apusync.apu_multbl[cpu->cycles_executed()];
} else {
apu->run();
apusync.cycles -= apusync.cpu_multbl[apu->cycles_executed()];
}
}
void SNES::init() {
srtc = new SRTC();
sdd1 = new SDD1();
} }
void SNES::power() { void SNES::power() {
cpu->power(); cpu->power();
apu->power(); apu->power();
ppu->power(); ppu->power();
//clock->power();
mem_bus->power(); mem_bus->power();
srtc->power();
sdd1->power();
int i; int i;
mem_bus->flush_mmio_mappers(); mem_bus->flush_mmio_mappers();
for(i=0x2100;i<=0x213f;i++)mem_bus->set_mmio_mapper(i, ppu->mmio); for(i=0x2100;i<=0x213f;i++)mem_bus->set_mmio_mapper(i, ppu->mmio);
for(i=0x2140;i<=0x217f;i++)mem_bus->set_mmio_mapper(i, cpu->mmio); for(i=0x2140;i<=0x217f;i++)mem_bus->set_mmio_mapper(i, cpu->mmio);
for(i=0x2180;i<=0x2183;i++)mem_bus->set_mmio_mapper(i, cpu->mmio); for(i=0x2180;i<=0x2183;i++)mem_bus->set_mmio_mapper(i, cpu->mmio);
//unknown
mem_bus->set_mmio_mapper(0x21c2, cpu->mmio);
mem_bus->set_mmio_mapper(0x21c3, cpu->mmio);
//S-RTC //S-RTC
mem_bus->set_mmio_mapper(0x2800, cpu->mmio); mem_bus->set_mmio_mapper(0x2800, srtc->mmio);
mem_bus->set_mmio_mapper(0x2801, cpu->mmio); mem_bus->set_mmio_mapper(0x2801, srtc->mmio);
//input //input
mem_bus->set_mmio_mapper(0x4016, cpu->mmio); mem_bus->set_mmio_mapper(0x4016, cpu->mmio);
mem_bus->set_mmio_mapper(0x4017, cpu->mmio); mem_bus->set_mmio_mapper(0x4017, cpu->mmio);
for(i=0x4200;i<=0x421f;i++)mem_bus->set_mmio_mapper(i, cpu->mmio); for(i=0x4200;i<=0x421f;i++)mem_bus->set_mmio_mapper(i, cpu->mmio);
for(i=0x4300;i<=0x437f;i++)mem_bus->set_mmio_mapper(i, cpu->mmio); for(i=0x4300;i<=0x437f;i++)mem_bus->set_mmio_mapper(i, cpu->mmio);
//S-DD1
for(i=0x4800;i<=0x4807;i++)mem_bus->set_mmio_mapper(i, sdd1->mmio);
} }
void SNES::reset() { void SNES::reset() {
apusync.cycles = -apusync.cpu_multbl[32];
cpu->reset(); cpu->reset();
apu->reset(); apu->reset();
ppu->reset(); ppu->reset();
//clock->reset();
mem_bus->reset(); mem_bus->reset();
srtc->reset();
sdd1->reset();
}
void SNES::set_region(uint8 new_region) {
if(new_region == NTSC) {
snes_region = NTSC;
} else if(new_region == PAL) {
snes_region = PAL;
} else {
alert("Unsupported region : %0.2x", new_region);
}
update_timing();
}
uint8 SNES::region() { return snes_region; }
void SNES::update_timing() {
apusync.cycles = 0;
if(snes_region == NTSC) {
apusync.cpu_freq = 21477272 >> 3;
} else if(snes_region == PAL) {
apusync.cpu_freq = 21281370 >> 3;
}
apusync.apu_freq = 24576000 >> 3;
int i;
for(i=0;i<1024;i++) {
apusync.cpu_multbl[i] = i * apusync.cpu_freq;
apusync.apu_multbl[i] = i * apusync.apu_freq;
}
} }
/*************************** /***************************
@ -56,4 +103,7 @@ bool SNES::debugger_enabled() {
SNES::SNES() { SNES::SNES() {
is_debugger_enabled = true; is_debugger_enabled = true;
snes_region = NTSC;
update_timing();
} }

View File

@ -2,12 +2,28 @@ class SNES {
protected: protected:
bool is_debugger_enabled; bool is_debugger_enabled;
uint8 snes_region;
//APU synchronization
struct {
int32 cpu_freq, apu_freq;
int32 cpu_multbl[1024], apu_multbl[1024];
int32 cycles;
}apusync;
void update_timing();
public: public:
enum { NTSC = 0, PAL = 1 };
//system functions //system functions
void run(); void run();
virtual void render_frame() = 0; virtual void render_frame() = 0;
virtual void power(); virtual void init();
virtual void reset(); virtual void power();
virtual void reset();
virtual uint8 region();
virtual void set_region(uint8 new_region);
//input functions //input functions
enum { enum {

View File

@ -7,7 +7,8 @@ OBJS = winmain.obj \
cpu.obj bcpu.obj \ cpu.obj bcpu.obj \
apu.obj bapu.obj bapuskip.obj \ apu.obj bapu.obj bapuskip.obj \
ppu.obj bppu.obj \ ppu.obj bppu.obj \
snes.obj snes.obj \
srtc.obj sdd1.obj
LIBS = kernel32.lib user32.lib gdi32.lib comdlg32.lib ddraw.lib dxguid.lib LIBS = kernel32.lib user32.lib gdi32.lib comdlg32.lib ddraw.lib dxguid.lib
all: $(OBJS) all: $(OBJS)
@ -73,7 +74,7 @@ bppu.obj: ../ppu/bppu/*
############## ##############
### reader ### ### reader ###
############## ##############
reader.obj: ../reader/reader.cpp ../reader/reader.h reader.obj: ../reader/*.cpp ../reader/*.h
$(CC) $(CFLAGS) /c ../reader/reader.cpp $(CC) $(CFLAGS) /c ../reader/reader.cpp
############ ############
@ -81,3 +82,15 @@ reader.obj: ../reader/reader.cpp ../reader/reader.h
############ ############
snes.obj: ../snes/*.cpp ../snes/*.h snes.obj: ../snes/*.cpp ../snes/*.h
$(CC) $(CFLAGS) /c ../snes/snes.cpp $(CC) $(CFLAGS) /c ../snes/snes.cpp
############
### srtc ###
############
srtc.obj: ../chip/srtc/*.cpp ../chip/srtc/*.h
$(CC) $(CFLAGS) /c ../chip/srtc/srtc.cpp
############
### sdd1 ###
############
sdd1.obj: ../chip/sdd1/*.cpp ../chip/sdd1/*.h
$(CC) $(CFLAGS) /c ../chip/sdd1/sdd1.cpp

View File

@ -12,11 +12,22 @@ uint8 cpu_op;
status.cpu_ran = false; status.cpu_ran = false;
break; break;
case RUNTOCPUPROCEED: case RUNTOCPUPROCEED:
cpu_op = mem_bus->read(cpu->regs.pc); cpu_op = mem_bus->read(cpu->regs.pc.d);
/* proceed only skips subroutines (jsr <addr>). 0x20, 0x22, and 0xfc are all three jsr opcodes */
if(cpu_op == 0x20 || cpu_op == 0x22 || cpu_op == 0xfc) { if(cpu_op == 0x10 || //bpl rel
cpu_op == 0x30 || //bmi rel
cpu_op == 0x50 || //bvc rel
cpu_op == 0x70 || //bvs rel
cpu_op == 0x90 || //bcc rel
cpu_op == 0xb0 || //bcs rel
cpu_op == 0xd0 || //bne rel
cpu_op == 0xf0 || //beq rel
cpu_op == 0x20 || //jsr addr
cpu_op == 0x22 || //jsl long
cpu_op == 0xfc //jsr (addr,x)
) {
w_console->is_running(true); w_console->is_running(true);
status.cpu_stop_pos = (cpu->regs.pc.b << 16) | ((cpu->regs.pc + cpu->opcode_length()) & 0xffff); status.cpu_stop_pos = (cpu->regs.pc.b << 16) | ((cpu->regs.pc.d + cpu->opcode_length()) & 0xffff);
} else { } else {
status.cpu_ran = false; status.cpu_ran = false;
run_status = RUNTOCPUSTEP; run_status = RUNTOCPUSTEP;
@ -78,7 +89,7 @@ void bSNES::snes_run() {
break; break;
case RUNTOCPUPROCEED: case RUNTOCPUPROCEED:
run(); run();
if(status.cpu_stop_pos == cpu->regs.pc) { if(cpu->in_opcode() == false && status.cpu_stop_pos == cpu->regs.pc.d) {
set_status(STOP); set_status(STOP);
disassemble_cpu_op(); disassemble_cpu_op();
} else if(w_bp->hit() == true) { } else if(w_bp->hit() == true) {
@ -110,7 +121,7 @@ void bSNES::render_frame() {
*** Input functions *** *** Input functions ***
***********************/ ***********************/
void bSNES::poll_input() { void bSNES::poll_input() {
/* Only capture input when main window has focus */ //only capture input when main window has focus
if(GetForegroundWindow() == w_main->hwnd) { if(GetForegroundWindow() == w_main->hwnd) {
joypad1.up = KeyDown(cfg.input.joypad1.up); joypad1.up = KeyDown(cfg.input.joypad1.up);
joypad1.down = KeyDown(cfg.input.joypad1.down); joypad1.down = KeyDown(cfg.input.joypad1.down);
@ -131,7 +142,7 @@ void bSNES::poll_input() {
joypad1.l = joypad1.r = 0; joypad1.l = joypad1.r = 0;
} }
//Check for debugger-based key locks //check for debugger-based key locks
if(is_debugger_enabled == true) { if(is_debugger_enabled == true) {
if(w_console->joypad_lock.up )joypad1.up = true; if(w_console->joypad_lock.up )joypad1.up = true;
if(w_console->joypad_lock.down )joypad1.down = true; if(w_console->joypad_lock.down )joypad1.down = true;
@ -147,7 +158,7 @@ void bSNES::poll_input() {
if(w_console->joypad_lock.start )joypad1.start = true; if(w_console->joypad_lock.start )joypad1.start = true;
} }
//It's impossible to hold both up+down, or left+right down //it's impossible to hold both up+down, or left+right down
//at the same time on a directional pad; and besides, allowing //at the same time on a directional pad; and besides, allowing
//this to happen causes glitches in many SNES games. //this to happen causes glitches in many SNES games.
if(joypad1.up) joypad1.down = 0; if(joypad1.up) joypad1.down = 0;
@ -274,6 +285,7 @@ void bSNES::notify(uint32 message, uint32 param1, uint32 param2) {
case CPU_EXEC_OPCODE_END: case CPU_EXEC_OPCODE_END:
status.cpu_ran = true; status.cpu_ran = true;
status.cpu_trace_pos++; status.cpu_trace_pos++;
//test next opcode for breakpoint
w_bp->test(message, cpu->regs.pc.d, 0); w_bp->test(message, cpu->regs.pc.d, 0);
disassemble_cpu_op(); disassemble_cpu_op();
break; break;

View File

@ -22,7 +22,7 @@ int i, r, g, b;
lpddsb->GetSurfaceDesc(&ddsd); lpddsb->GetSurfaceDesc(&ddsd);
color_depth = ddsd.ddpfPixelFormat.dwRGBBitCount; color_depth = ddsd.ddpfPixelFormat.dwRGBBitCount;
if(color_depth == 15) { if(color_depth == 15) {
for(i=0;i<65536;i++) { for(i=0;i<32768;i++) {
r = (i ) & 31; r = (i ) & 31;
g = (i >> 5) & 31; g = (i >> 5) & 31;
b = (i >> 10) & 31; b = (i >> 10) & 31;
@ -34,7 +34,7 @@ int i, r, g, b;
color_lookup_table[i] = (r << 10) | (g << 5) | (b); color_lookup_table[i] = (r << 10) | (g << 5) | (b);
} }
} else if(color_depth == 16) { } else if(color_depth == 16) {
for(i=0;i<65536;i++) { for(i=0;i<32768;i++) {
r = (i ) & 31; r = (i ) & 31;
g = (i >> 5) & 31; g = (i >> 5) & 31;
b = (i >> 10) & 31; b = (i >> 10) & 31;
@ -48,7 +48,7 @@ int i, r, g, b;
color_lookup_table[i] = (r << 11) | (g << 5) | (b); color_lookup_table[i] = (r << 11) | (g << 5) | (b);
} }
} else if(color_depth == 32) { } else if(color_depth == 32) {
for(i=0;i<65536;i++) { for(i=0;i<32768;i++) {
r = (i ) & 31; r = (i ) & 31;
g = (i >> 5) & 31; g = (i >> 5) & 31;
b = (i >> 10) & 31; b = (i >> 10) & 31;

View File

@ -13,7 +13,7 @@ bool fullscreen;
int width, height; //used for fullscreen mode clipping only int width, height; //used for fullscreen mode clipping only
uint8 color_depth; uint8 color_depth;
uint8 color_curve_table[32]; uint8 color_curve_table[32];
uint32 color_lookup_table[65536]; uint32 color_lookup_table[32768];
void set_window(HWND hwnd_handle); void set_window(HWND hwnd_handle);
void create_backbuffer(); void create_backbuffer();
void to_windowed(); void to_windowed();

View File

@ -23,7 +23,7 @@ bool ROMImage::load() {
dprintf("* Loading \"%s\"...", rom_fn); dprintf("* Loading \"%s\"...", rom_fn);
FileReader *rf = new FileReader(); FileReader *rf = new FileReader();
if(!rf->open(FileReader::TYPE_ROM, rom_fn)) { if(!rf->open(rom_fn)) {
alert("Error loading image file [%s]!", rom_fn); alert("Error loading image file [%s]!", rom_fn);
return false; return false;
} }
@ -33,7 +33,7 @@ FileReader *rf = new FileReader();
CartInfo ci; CartInfo ci;
mem_bus->get_cartinfo(&ci); mem_bus->get_cartinfo(&ci);
if(ci.sram_size != 0) { if(ci.sram_size != 0) {
rf->open(FileReader::TYPE_SRAM, sram_fn); rf->open(sram_fn);
mem_bus->load_sram(static_cast<Reader*>(rf)); mem_bus->load_sram(static_cast<Reader*>(rf));
rf->close(); rf->close();
} }

View File

@ -36,6 +36,7 @@ enum {
MENU_SETTINGS_APUENABLED, MENU_SETTINGS_APUENABLED,
MENU_SETTINGS_INPUTCFG_JOYPAD1, MENU_SETTINGS_INPUTCFG_JOYPAD1,
MENU_SETTINGS_DEBUGGER, MENU_SETTINGS_DEBUGGER,
MENU_MISC_SCREENSHOT,
MENU_MISC_ABOUT MENU_MISC_ABOUT
}; };

View File

@ -22,7 +22,7 @@ int i;
if(!(bp[i].flags & FLAG_X))continue; if(!(bp[i].flags & FLAG_X))continue;
if(bp[i].source != DRAM)continue; if(bp[i].source != DRAM)continue;
if(bp[i].addr != addr)continue; if(bp[i].addr != addr)continue;
dprintf("* Breakpoint %d hit (exec)", i); dprintf("* Breakpoint %d hit (CPU exec)", i);
bp[i].hit_count++; bp[i].hit_count++;
bp_hit = true; bp_hit = true;
w_bp->refresh(); w_bp->refresh();
@ -31,7 +31,7 @@ int i;
if(!(bp[i].flags & FLAG_X))continue; if(!(bp[i].flags & FLAG_X))continue;
if(bp[i].source != SPCRAM)continue; if(bp[i].source != SPCRAM)continue;
if(bp[i].addr != addr)continue; if(bp[i].addr != addr)continue;
dprintf("* Breakpoint %d hit (exec)", i); dprintf("* Breakpoint %d hit (APU exec)", i);
bp[i].hit_count++; bp[i].hit_count++;
bp_hit = true; bp_hit = true;
w_bp->refresh(); w_bp->refresh();

View File

@ -29,13 +29,21 @@ HDC hdc;
break; break;
case CONSOLE_CPUPROCEED: case CONSOLE_CPUPROCEED:
if(bsnes->get_status() == bSNES::STOP) { if(bsnes->get_status() == bSNES::STOP) {
bsnes->set_status(bSNES::RUNTOCPUPROCEED); if(cpu->in_opcode() == true) {
dprintf("* CPU within opcode, proceed aborted");
} else {
bsnes->set_status(bSNES::RUNTOCPUPROCEED);
}
} }
break; break;
case CONSOLE_CPUSKIP: case CONSOLE_CPUSKIP:
if(bsnes->get_status() == bSNES::STOP) { if(bsnes->get_status() == bSNES::STOP) {
cpu->regs.pc.w += cpu->opcode_length(); if(cpu->in_opcode() == true) {
bsnes->disassemble_cpu_op(); dprintf("* CPU within opcode, skip aborted");
} else {
cpu->regs.pc.w += cpu->opcode_length();
bsnes->disassemble_cpu_op();
}
} }
break; break;
case CONSOLE_CPUTRACE: case CONSOLE_CPUTRACE:
@ -49,13 +57,17 @@ HDC hdc;
break; break;
case CONSOLE_CPUDISABLE: case CONSOLE_CPUDISABLE:
if(bsnes->get_status() == bSNES::STOP) { if(bsnes->get_status() == bSNES::STOP) {
addr = cpu->regs.pc.d; if(cpu->in_opcode() == true) {
len = cpu->opcode_length(); dprintf("* CPU within opcode, disable aborted");
for(i=0;i<len;i++) { } else {
bsnes->write(bSNES::DRAM, (addr & 0xff0000) | ((addr + i) & 0xffff), 0xea); addr = cpu->regs.pc.d;
len = cpu->opcode_length();
for(i=0;i<len;i++) {
bsnes->write(bSNES::DRAM, (addr & 0xff0000) | ((addr + i) & 0xffff), 0xea);
}
//cpu->regs.pc.w += len;
bsnes->disassemble_cpu_op();
} }
// cpu->regs.pc.w += len;
bsnes->disassemble_cpu_op();
} }
break; break;
case CONSOLE_APUSTEP: case CONSOLE_APUSTEP:
@ -111,21 +123,25 @@ HDC hdc;
value = strhex(t); value = strhex(t);
pos = SendDlgItemMessage(hwnd, CONSOLE_CFGREGTYPE, CB_GETCURSEL, 0, 0); pos = SendDlgItemMessage(hwnd, CONSOLE_CFGREGTYPE, CB_GETCURSEL, 0, 0);
if(pos == 0) { //Set CPU register if(pos == 0) { //Set CPU register
pos = SendDlgItemMessage(hwnd, CONSOLE_CFGREGNUM, CB_GETCURSEL, 0, 0); if(cpu->in_opcode() == true) {
switch(pos) { dprintf("* CPU within opcode, register set aborted");
case 0:cpu->regs.a.w = value;break; } else {
case 1:cpu->regs.x.w = value;break; pos = SendDlgItemMessage(hwnd, CONSOLE_CFGREGNUM, CB_GETCURSEL, 0, 0);
case 2:cpu->regs.y.w = value;break; switch(pos) {
case 3:cpu->regs.s.w = value;break; case 0:cpu->regs.a.w = value;break;
case 4:cpu->regs.d.w = value;break; case 1:cpu->regs.x.w = value;break;
case 5:cpu->regs.db = value;break; case 2:cpu->regs.y.w = value;break;
case 6:cpu->regs.p = value;break; case 3:cpu->regs.s.w = value;break;
case 7:cpu->regs.e = value;break; case 4:cpu->regs.d.w = value;break;
case 8:cpu->regs.pc.d = value;break; case 5:cpu->regs.db = value;break;
case 6:cpu->regs.p = value;break;
case 7:cpu->regs.e = value;break;
case 8:cpu->regs.pc.d = value;break;
}
//these bits can never be clear in emulation mode
if(cpu->regs.e)cpu->regs.p |= 0x30;
bsnes->disassemble_cpu_op();
} }
//these bits can never be clear in emulation mode
if(cpu->regs.e)cpu->regs.p |= 0x30;
bsnes->disassemble_cpu_op();
} else { //Set APU register } else { //Set APU register
} }
break; break;

View File

@ -132,6 +132,7 @@ void MainWindow::menu_unload() {
} }
long __stdcall wndproc_main(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { long __stdcall wndproc_main(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
time_t timeout;
switch(msg) { switch(msg) {
case WM_KEYDOWN: case WM_KEYDOWN:
if(wparam == VK_ESCAPE) { if(wparam == VK_ESCAPE) {
@ -144,6 +145,13 @@ long __stdcall wndproc_main(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
} }
break; break;
case WM_COMMAND: case WM_COMMAND:
//below code fails becahse it is triggered after snes->poll_input()...
//unsure how to fix this...
// timeout = time(NULL);
// while(difftime(time(NULL), timeout) < 5) {
// if(!KeyDown(VK_RETURN))break;
// }
switch(LOWORD(wparam)) { switch(LOWORD(wparam)) {
case MENU_FILE_LOAD: case MENU_FILE_LOAD:
w_main->menu_load(); w_main->menu_load();
@ -227,6 +235,8 @@ long __stdcall wndproc_main(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
w_main->set_video_mode(VIDEOMODE_256x224w); w_main->set_video_mode(VIDEOMODE_256x224w);
} }
break; break;
case MENU_MISC_SCREENSHOT:
break;
case MENU_MISC_ABOUT: case MENU_MISC_ABOUT:
w_about->center(); w_about->center();
w_about->show(); w_about->show();
@ -315,6 +325,8 @@ HMENU hsubmenu, hbranchmenu;
AppendMenu(hmenu, MF_STRING | MF_POPUP, (unsigned int)hsubmenu, "&Settings"); AppendMenu(hmenu, MF_STRING | MF_POPUP, (unsigned int)hsubmenu, "&Settings");
hsubmenu = CreatePopupMenu(); hsubmenu = CreatePopupMenu();
AppendMenu(hsubmenu, MF_STRING | MF_GRAYED, MENU_MISC_SCREENSHOT, "&Capture Screenshot");
AppendMenu(hsubmenu, MF_SEPARATOR, 0, "");
AppendMenu(hsubmenu, MF_STRING, MENU_MISC_ABOUT, "&About..."); AppendMenu(hsubmenu, MF_STRING, MENU_MISC_ABOUT, "&About...");
AppendMenu(hmenu, MF_STRING | MF_POPUP, (unsigned int)hsubmenu, "&Misc"); AppendMenu(hmenu, MF_STRING | MF_POPUP, (unsigned int)hsubmenu, "&Misc");

View File

@ -1,5 +1,5 @@
#define INTERFACE_MAIN #define INTERFACE_MAIN
#define BSNES_VERSION "0.010" #define BSNES_VERSION "0.011"
#define BSNES_TITLE "bsnes v" BSNES_VERSION #define BSNES_TITLE "bsnes v" BSNES_VERSION
#include "winmain.h" #include "winmain.h"
#include "../base.h" #include "../base.h"
@ -31,6 +31,8 @@ void init_snes() {
ppu = new bPPU(); ppu = new bPPU();
snes = new bSNES(); snes = new bSNES();
bsnes = static_cast<bSNES*>(snes); bsnes = static_cast<bSNES*>(snes);
snes->init();
} }
void term_snes() { void term_snes() {