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 reset() = 0;
//debugging functions
virtual bool in_opcode();
void disassemble_opcode(char *output);
inline uint16 __relb(int8 offset, int op_len);
};

View File

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

View File

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

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() {
#include "bapu_optable.cpp"
}

View File

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

Binary file not shown.

View File

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

View File

@ -1,6 +1,16 @@
#include <time.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
typedef struct {
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.
*/
void bCPU::srtc_set_time() {
#include "../../base.h"
void SRTC::set_time() {
time_t rawtime;
tm *t;
::time(&rawtime);
@ -72,12 +74,12 @@ tm *t;
srtc.data[12] = t->tm_wday;
}
void bCPU::srtc_power() {
void SRTC::power() {
memset(&srtc, 0, sizeof(srtc));
reset();
}
void bCPU::srtc_reset() {
void SRTC::reset() {
srtc.index = -1;
srtc.mode = SRTC_READ;
}
@ -87,7 +89,7 @@ void bCPU::srtc_reset() {
//as reads will refresh the data array with the current system
//time. The write method is only here for the sake of faux
//emulation of the real hardware.
void bCPU::srtc_write(uint8 data) {
void SRTC::write(uint8 data) {
data &= 0x0f; //only the low four bits are used
if(data >= 0x0d) {
@ -140,10 +142,10 @@ void bCPU::srtc_write(uint8 data) {
}
}
uint8 bCPU::srtc_read() {
uint8 SRTC::read() {
if(srtc.mode == SRTC_READ) {
if(srtc.index < 0) {
srtc_set_time();
set_time();
srtc.index++;
return 0x0f; //send start message
} else if(srtc.index > MAX_SRTC_INDEX) {
@ -156,3 +158,21 @@ uint8 bCPU::srtc_read() {
return 0x00;
}
}
SRTC::SRTC() {
mmio = new SRTCMMIO();
}
uint8 SRTCMMIO::read(uint32 addr) {
switch(addr) {
case 0x2800:return srtc->read();
}
return 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();
void srtc_power();
void srtc_reset();
void srtc_write(uint8 data);
uint8 srtc_read();
class SRTCMMIO : public MMIO {
public:
inline uint8 read (uint32 addr);
inline void write(uint32 addr, uint8 value);
};
#define MAX_SRTC_INDEX 0x0c
class SRTC {
public:
enum { MAX_SRTC_INDEX = 0x0c };
enum {
SRTC_READ = 0,
@ -18,9 +20,7 @@ enum {
SRTC_COMMAND_CLEAR = 4
};
#define DAYTICKS (60*60*24)
#define HOURTICKS (60*60)
#define MINUTETICKS (60)
SRTCMMIO *mmio;
/******************************
[srtc.data structure]
@ -38,11 +38,18 @@ Index Description Range
9 Year ones 0-9
10 Year tens 0-9
11 Year hundreds 9-11 (9=19xx, 10=20xx, 11=21xx)
12 Day of week 0-6 (0=Sunday, ...)
12 Day of week 0-6 (0=Sunday, ...)
******************************/
struct {
int8 index;
uint8 mode;
uint8 data[MAX_SRTC_INDEX + 1];
}srtc;
void set_time();
void power();
void reset();
void write(uint8 data);
uint8 read();
SRTC();
};

View File

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

View File

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

View File

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

View File

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

View File

@ -41,16 +41,7 @@ uint8 r;
return r;
}
//???
uint8 bCPU::mmio_r21c2() {
return 0x20;
}
//???
uint8 bCPU::mmio_r21c3() {
return 0x00;
}
//JOYSER0
/*
The joypad contains a small bit shifter that has 16 bits.
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,
so that reads will increment the bit shifting position.
*/
//JOYSER0
//7-2 = MDR
//1-0 = Joypad serial data
uint8 bCPU::mmio_r4016() {
uint8 r = 0x00;
uint8 r;
r = regs.mdr & 0xfc;
if(status.joypad1_strobe_value == 1) {
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_B);
} else {
@ -85,45 +79,85 @@ uint8 r = 0x00;
}
if(++status.joypad1_read_pos > 17)status.joypad1_read_pos = 17;
}
return r;
}
//JOYSER1
//7-5 = MDR
//4-2 = Always 1
//1-0 = Joypad serial data
uint8 bCPU::mmio_r4017() {
uint8 r;
r = regs.mdr & 0xe0;
r |= 0x1c;
return r;
}
//RDNMI
/* $4210 bit 7 (NMI triggered bit) is set at:
* V=225/240,HC>=2,
* V>225
* The bit is only set once per NMI trigger, so
* subsequent reads return this bit as being clear.
* There is but one exception: if the $4210 read
* occurs at *exactly* V=225/240,HC==2, then $4210
* bit 7 will be set, and the next read will also
* have this bit set.
*/
//7 = NMI acknowledge
//6-4 = MDR
//3-0 = CPU (5a22) version
uint8 bCPU::mmio_r4210() {
uint8 r = 0x00;
uint8 r;
uint16 v, h, hc, vs;
r = regs.mdr & 0x70;
v = vcounter();
h = hcounter();
hc = hcycles();
vs = (overscan()?239:224);
if(status.r4210_read == false) {
if((v == (vs + 1) && hc >= 2) || v > (vs + 1)) {
if(status.nmi_read == false) {
if(
(v == (vs + 1) && hc >= 2) ||
(v > (vs + 1))
) {
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
return r;
}
//TIMEUP
//7 = IRQ acknowledge
//6-0 = MDR
uint8 bCPU::mmio_r4211() {
uint8 r = 0x00;
r |= 0x40;
if(status.irq_triggered == true)r |= 0x80;
status.irq_triggered = false;
uint8 r;
r = regs.mdr & 0x7f;
if(status.irq_exec == true)r |= 0x80;
status.irq_exec = false;
status.irq_read = true;
return r;
}
//HVBJOY
//7 = in vblank
//6 = in hblank
//5-1 = MDR
//0 = joypad ready
uint8 bCPU::mmio_r4212() {
uint8 r;
uint16 v, h, hc, vs;
r = 0x00;
r = regs.mdr & 0x3e;
v = vcounter();
h = hcounter();
@ -168,7 +202,7 @@ uint8 bCPU::mmio_r4217() {
//JOY1L
uint8 bCPU::mmio_r4218() {
uint8 r = 0x00;
uint8 r = 0x00;
uint16 v = vcounter();
if(status.auto_joypad_poll == false)return 0x00; //can't read joypad if auto polling not enabled
//if(v >= 225 && v <= 227)return 0x00; //can't read joypad while SNES is polling input
@ -181,7 +215,7 @@ uint16 v = vcounter();
//JOY1H
uint8 bCPU::mmio_r4219() {
uint8 r = 0x00;
uint8 r = 0x00;
uint16 v = vcounter();
if(status.auto_joypad_poll == false)return 0x00; //can't read joypad if auto polling not enabled
//if(v >= 225 && v <= 227)return 0x00; //can't read joypad while SNES is polling input
@ -218,7 +252,7 @@ uint8 bCPU::mmio_r43x3(uint8 i) {
//A1Bx
uint8 bCPU::mmio_r43x4(uint8 i) {
return channel[i].srcaddr >> 16;
return channel[i].srcbank;
}
//DASxL
@ -233,17 +267,17 @@ uint8 bCPU::mmio_r43x6(uint8 i) {
//DASBx
uint8 bCPU::mmio_r43x7(uint8 i) {
return channel[i].hdma_indirect_bank;
return channel[i].hdma_ibank;
}
//A2AxL
uint8 bCPU::mmio_r43x8(uint8 i) {
return channel[i].hdma_taddr;
return channel[i].hdma_addr;
}
//A2AxH
uint8 bCPU::mmio_r43x9(uint8 i) {
return channel[i].hdma_taddr >> 8;
return channel[i].hdma_addr >> 8;
}
//NTRLx
@ -281,19 +315,17 @@ uint8 i;
case 0x9:return cpu->mmio_r43x9(i);
case 0xa:return cpu->mmio_r43xa(i);
case 0xb:return cpu->mmio_r43xb(i);
case 0xc:return 0x43; //unmapped
case 0xd:return 0x43; //unmapped
case 0xe:return 0x43; //unmapped
case 0xc:return cpu->regs.mdr; //unmapped
case 0xd:return cpu->regs.mdr; //unmapped
case 0xe:return cpu->regs.mdr; //unmapped
case 0xf:return cpu->mmio_r43xb(i); //mirror of 43xb
}
}
switch(addr) {
case 0x2180:return cpu->mmio_r2180(); //WMDATA
case 0x21c2:return cpu->mmio_r21c2(); //???
case 0x21c3:return cpu->mmio_r21c3(); //???
case 0x2800:return cpu->srtc_read();
case 0x4016:return cpu->mmio_r4016(); //JOYSER0
case 0x4017:return cpu->mmio_r4017(); //JOYSER1
case 0x4210:return cpu->mmio_r4210(); //RDNMI
case 0x4211:return cpu->mmio_r4211(); //TIMEUP
case 0x4212:return cpu->mmio_r4212(); //HVBJOY
@ -306,7 +338,8 @@ uint8 i;
case 0x4219:return cpu->mmio_r4219(); //JOY1H
case 0x421a:case 0x421b:case 0x421c:case 0x421d:case 0x421e:case 0x421f:return 0x00;
}
return 0x00;
return cpu->regs.mdr;
}
//WMDATA
@ -351,11 +384,12 @@ void bCPU::mmio_w4200(uint8 value) {
status.auto_joypad_poll = !!(value & 0x01);
if(status.nmi_enabled == false) {
status.nmi_pin = 0;
status.nmi_read = false;
}
if(status.virq_enabled == false && status.hirq_enabled == false) {
status.irq_pin = 0;
status.irq_exec = false;
if(status.virq_enabled == true || status.hirq_enabled == true) {
status.irq_read = false;
}
}
@ -397,37 +431,40 @@ void bCPU::mmio_w4206(uint8 value) {
//HTIMEL
void bCPU::mmio_w4207(uint8 value) {
status.hirq_pos = (status.hirq_pos & 0xff00) | value;
if(status.irq_triggered == false)status.irq_pin = 1;
status.irq_read = false;
}
//HTIMEH
void bCPU::mmio_w4208(uint8 value) {
status.hirq_pos = (status.hirq_pos & 0x00ff) | (value << 8);
if(status.irq_triggered == false)status.irq_pin = 1;
status.irq_read = false;
}
//VTIMEL
void bCPU::mmio_w4209(uint8 value) {
status.virq_pos = (status.virq_pos & 0xff00) | value;
if(status.irq_triggered == false)status.irq_pin = 1;
status.irq_read = false;
}
//VTIMEH
void bCPU::mmio_w420a(uint8 value) {
status.virq_pos = (status.virq_pos & 0x00ff) | (value << 8);
if(status.irq_triggered == false)status.irq_pin = 1;
status.irq_read = false;
}
//DMAEN
void bCPU::mmio_w420b(uint8 value) {
int len;
if(value != 0x00) {
status.dma_state = DMASTATE_INIT;
status.dma_state = DMASTATE_DMASYNC;
}
for(int i=0;i<8;i++) {
if(value & (1 << i)) {
channel[i].active = true;
channel[i].hdma_active = false;
channel[i].active = true;
channel[i].hdma_enabled = false;
channel[i].hdma_active = false;
channel[i].read_index = 0;
}
}
}
@ -435,7 +472,8 @@ void bCPU::mmio_w420b(uint8 value) {
//HDMAEN
void bCPU::mmio_w420c(uint8 value) {
for(int i=0;i<8;i++) {
channel[i].hdma_active = !!(value & (1 << i));
channel[i].hdma_enabled = !!(value & (1 << i));
channel[i].hdma_active = !!(value & (1 << i));
}
}
@ -461,17 +499,17 @@ void bCPU::mmio_w43x1(uint8 value, uint8 i) {
//A1TxL
void bCPU::mmio_w43x2(uint8 value, uint8 i) {
channel[i].srcaddr = (channel[i].srcaddr & 0xffff00) | value;
channel[i].srcaddr = (channel[i].srcaddr & 0xff00) | value;
}
//A1TxH
void bCPU::mmio_w43x3(uint8 value, uint8 i) {
channel[i].srcaddr = (channel[i].srcaddr & 0xff00ff) | (value << 8);
channel[i].srcaddr = (channel[i].srcaddr & 0x00ff) | (value << 8);
}
//A1Bx
void bCPU::mmio_w43x4(uint8 value, uint8 i) {
channel[i].srcaddr = (channel[i].srcaddr & 0x00ffff) | (value << 16);
channel[i].srcbank = value;
}
//DASxL
@ -486,17 +524,17 @@ void bCPU::mmio_w43x6(uint8 value, uint8 i) {
//DASBx
void bCPU::mmio_w43x7(uint8 value, uint8 i) {
channel[i].hdma_indirect_bank = value;
channel[i].hdma_ibank = value;
}
//A2AxL
void bCPU::mmio_w43x8(uint8 value, uint8 i) {
channel[i].hdma_taddr = (channel[i].hdma_taddr & 0xffff00) | value;
channel[i].hdma_addr = (channel[i].hdma_addr & 0xff00) | value;
}
//A2AxH
void bCPU::mmio_w43x9(uint8 value, uint8 i) {
channel[i].hdma_taddr = (channel[i].hdma_taddr & 0xff00ff) | (value << 8);
channel[i].hdma_addr = (channel[i].hdma_addr & 0x00ff) | (value << 8);
}
//NTRLx
@ -547,7 +585,6 @@ uint8 i;
case 0x2181:cpu->mmio_w2181(value);return; //WMADDL
case 0x2182:cpu->mmio_w2182(value);return; //WMADDM
case 0x2183:cpu->mmio_w2183(value);return; //WMADDH
case 0x2801:cpu->srtc_write(value);return;
case 0x4016:cpu->mmio_w4016(value);return; //JOYSER0
case 0x4200:cpu->mmio_w4200(value);return; //NMITIMEN
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() {
l1:
rd.l = op_read();
if(1) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
switch(status.cycle_pos++) {
case 1:
rd.l = op_read();
if(1) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
break;
case 2:
cpu_c6(aa.w);
break;
case 3:
cpu_io();
status.cycle_pos = 0;
break;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bcc() {
l1:
rd.l = op_read();
if(!regs.p.c) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
switch(status.cycle_pos++) {
case 1:
rd.l = op_read();
if(!regs.p.c) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
break;
case 2:
cpu_c6(aa.w);
break;
case 3:
cpu_io();
status.cycle_pos = 0;
break;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bcs() {
l1:
rd.l = op_read();
if(regs.p.c) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
switch(status.cycle_pos++) {
case 1:
rd.l = op_read();
if(regs.p.c) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
break;
case 2:
cpu_c6(aa.w);
break;
case 3:
cpu_io();
status.cycle_pos = 0;
break;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bne() {
l1:
rd.l = op_read();
if(!regs.p.z) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
switch(status.cycle_pos++) {
case 1:
rd.l = op_read();
if(!regs.p.z) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
break;
case 2:
cpu_c6(aa.w);
break;
case 3:
cpu_io();
status.cycle_pos = 0;
break;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_beq() {
l1:
rd.l = op_read();
if(regs.p.z) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
switch(status.cycle_pos++) {
case 1:
rd.l = op_read();
if(regs.p.z) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
break;
case 2:
cpu_c6(aa.w);
break;
case 3:
cpu_io();
status.cycle_pos = 0;
break;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bpl() {
l1:
rd.l = op_read();
if(!regs.p.n) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
switch(status.cycle_pos++) {
case 1:
rd.l = op_read();
if(!regs.p.n) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
break;
case 2:
cpu_c6(aa.w);
break;
case 3:
cpu_io();
status.cycle_pos = 0;
break;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bmi() {
l1:
rd.l = op_read();
if(regs.p.n) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
switch(status.cycle_pos++) {
case 1:
rd.l = op_read();
if(regs.p.n) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
break;
case 2:
cpu_c6(aa.w);
break;
case 3:
cpu_io();
status.cycle_pos = 0;
break;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bvc() {
l1:
rd.l = op_read();
if(!regs.p.v) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
switch(status.cycle_pos++) {
case 1:
rd.l = op_read();
if(!regs.p.v) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
break;
case 2:
cpu_c6(aa.w);
break;
case 3:
cpu_io();
status.cycle_pos = 0;
break;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_bvs() {
l1:
rd.l = op_read();
if(regs.p.v) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
return;
switch(status.cycle_pos++) {
case 1:
rd.l = op_read();
if(regs.p.v) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
status.cycle_pos = 0;
}
break;
case 2:
cpu_c6(aa.w);
break;
case 3:
cpu_io();
status.cycle_pos = 0;
break;
}
l2:
cpu_c6(aa.w);
l3:
cpu_io();
}
void bCPU::op_brl() {
l1:
rd.l = op_read();
l2:
rd.h = op_read();
l3:
cpu_io();
regs.pc.w = regs.pc.d + (int16)rd.w;
switch(status.cycle_pos++) {
case 1:
rd.l = op_read();
break;
case 2:
rd.h = op_read();
break;
case 3:
cpu_io();
regs.pc.w = regs.pc.d + (int16)rd.w;
status.cycle_pos = 0;
break;
}
}
void bCPU::op_jmp_addr() {
l1:
rd.l = op_read();
l2:
rd.h = op_read();
regs.pc.w = rd.w;
switch(status.cycle_pos++) {
case 1:
rd.l = op_read();
break;
case 2:
rd.h = op_read();
regs.pc.w = rd.w;
status.cycle_pos = 0;
break;
}
}
void bCPU::op_jmp_long() {
l1:
rd.l = op_read();
l2:
rd.h = op_read();
l3:
rd.b = op_read();
regs.pc.d = rd.d & 0xffffff;
switch(status.cycle_pos++) {
case 1:
rd.l = op_read();
break;
case 2:
rd.h = op_read();
break;
case 3:
rd.b = op_read();
regs.pc.d = rd.d & 0xffffff;
status.cycle_pos = 0;
break;
}
}
void bCPU::op_jmp_iaddr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
rd.l = op_read(OPMODE_ADDR, aa.w);
l4:
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
regs.pc.w = rd.w;
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
rd.l = op_read(OPMODE_ADDR, aa.w);
break;
case 4:
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
regs.pc.w = rd.w;
status.cycle_pos = 0;
break;
}
}
void bCPU::op_jmp_iaddrx() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_io();
l4:
rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
l5:
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
regs.pc.w = rd.w;
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
cpu_io();
break;
case 4:
rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
break;
case 5:
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
regs.pc.w = rd.w;
status.cycle_pos = 0;
break;
}
}
void bCPU::op_jmp_iladdr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
rd.l = op_read(OPMODE_ADDR, aa.w);
l4:
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
l5:
rd.b = op_read(OPMODE_ADDR, aa.w + 2);
regs.pc.d = rd.d & 0xffffff;
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
rd.l = op_read(OPMODE_ADDR, aa.w);
break;
case 4:
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
break;
case 5:
rd.b = op_read(OPMODE_ADDR, aa.w + 2);
regs.pc.d = rd.d & 0xffffff;
status.cycle_pos = 0;
break;
}
}
void bCPU::op_jsr_addr() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_io();
l4:
regs.pc.w--;
stack_write(regs.pc.h);
l5:
stack_write(regs.pc.l);
regs.pc.w = aa.w;
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
cpu_io();
break;
case 4:
regs.pc.w--;
stack_write(regs.pc.h);
break;
case 5:
stack_write(regs.pc.l);
regs.pc.w = aa.w;
status.cycle_pos = 0;
break;
}
}
void bCPU::op_jsr_long() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
stack_write(regs.pc.b);
l4:
cpu_io();
l5:
aa.b = op_read();
l6:
regs.pc.w--;
stack_write(regs.pc.h);
l7:
stack_write(regs.pc.l);
regs.pc.d = aa.d & 0xffffff;
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
stack_write(regs.pc.b);
break;
case 4:
cpu_io();
break;
case 5:
aa.b = op_read();
break;
case 6:
regs.pc.w--;
stack_write(regs.pc.h);
break;
case 7:
stack_write(regs.pc.l);
regs.pc.d = aa.d & 0xffffff;
status.cycle_pos = 0;
break;
}
}
void bCPU::op_jsr_iaddrx() {
l1:
aa.l = op_read();
l2:
stack_write(regs.pc.h);
l3:
stack_write(regs.pc.l);
l4:
aa.h = op_read();
l5:
cpu_io();
l6:
rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
l7:
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
regs.pc.w = rd.w;
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
stack_write(regs.pc.h);
break;
case 3:
stack_write(regs.pc.l);
break;
case 4:
aa.h = op_read();
break;
case 5:
cpu_io();
break;
case 6:
rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
break;
case 7:
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
regs.pc.w = rd.w;
status.cycle_pos = 0;
break;
}
}
void bCPU::op_rti() {
l1:
cpu_io();
l2:
cpu_io();
l3:
regs.p = stack_read();
if(regs.e)regs.p |= 0x30;
if(regs.p.x) {
regs.x.h = 0x00;
regs.y.h = 0x00;
switch(status.cycle_pos++) {
case 1:
cpu_io();
break;
case 2:
cpu_io();
break;
case 3:
regs.p = stack_read();
if(regs.e)regs.p |= 0x30;
if(regs.p.x) {
regs.x.h = 0x00;
regs.y.h = 0x00;
}
break;
case 4:
rd.l = stack_read();
break;
case 5:
rd.h = stack_read();
if(regs.e) {
regs.pc.w = rd.w;
status.cycle_pos = 0;
}
break;
case 6:
rd.b = stack_read();
regs.pc.d = rd.d & 0xffffff;
status.cycle_pos = 0;
break;
}
l4:
rd.l = stack_read();
l5:
rd.h = stack_read();
if(regs.e) {
regs.pc.w = rd.w;
return;
}
l6:
rd.b = stack_read();
regs.pc.d = rd.d & 0xffffff;
}
void bCPU::op_rts() {
l1:
cpu_io();
l2:
cpu_io();
l3:
rd.l = stack_read();
l4:
rd.h = stack_read();
l5:
cpu_io();
regs.pc.w = rd.w;
regs.pc.w++;
switch(status.cycle_pos++) {
case 1:
cpu_io();
break;
case 2:
cpu_io();
break;
case 3:
rd.l = stack_read();
break;
case 4:
rd.h = stack_read();
break;
case 5:
cpu_io();
regs.pc.w = rd.w;
regs.pc.w++;
status.cycle_pos = 0;
break;
}
}
void bCPU::op_rtl() {
l1:
cpu_io();
l2:
cpu_io();
l3:
rd.l = stack_read();
l4:
rd.h = stack_read();
l5:
rd.b = stack_read();
regs.pc.d = rd.d & 0xffffff;
regs.pc.w++;
switch(status.cycle_pos++) {
case 1:
cpu_io();
break;
case 2:
cpu_io();
break;
case 3:
rd.l = stack_read();
break;
case 4:
rd.h = stack_read();
break;
case 5:
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() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
op_write(OPMODE_DBR, aa.w, regs.a.w);
if(regs.p.m)return;
l4:
op_write(OPMODE_DBR, aa.w + 1, regs.a.w >> 8);
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
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() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
op_write(OPMODE_DBR, aa.w, regs.x.w);
if(regs.p.x)return;
l4:
op_write(OPMODE_DBR, aa.w + 1, regs.x.w >> 8);
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
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() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
op_write(OPMODE_DBR, aa.w, regs.y.w);
if(regs.p.x)return;
l4:
op_write(OPMODE_DBR, aa.w + 1, regs.y.w >> 8);
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
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() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
op_write(OPMODE_DBR, aa.w, 0x0000);
if(regs.p.m)return;
l4:
op_write(OPMODE_DBR, aa.w + 1, 0x0000 >> 8);
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
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() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_c4(aa.w, aa.w + regs.x.w);
l4:
op_write(OPMODE_DBR, aa.w + regs.x.w, regs.a.w);
if(regs.p.m)return;
l5:
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, regs.a.w >> 8);
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
cpu_c4(aa.w, aa.w + regs.x.w);
break;
case 4:
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() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_c4(aa.w, aa.w + regs.x.w);
l4:
op_write(OPMODE_DBR, aa.w + regs.x.w, 0x0000);
if(regs.p.m)return;
l5:
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, 0x0000 >> 8);
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
cpu_c4(aa.w, aa.w + regs.x.w);
break;
case 4:
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() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
cpu_c4(aa.w, aa.w + regs.y.w);
l4:
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
if(regs.p.m)return;
l5:
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
cpu_c4(aa.w, aa.w + regs.y.w);
break;
case 4:
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() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
aa.b = op_read();
l4:
op_write(OPMODE_LONG, aa.d, regs.a.l);
if(regs.p.m)return;
l5:
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
aa.b = op_read();
break;
case 4:
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() {
l1:
aa.l = op_read();
l2:
aa.h = op_read();
l3:
aa.b = op_read();
l4:
op_write(OPMODE_LONG, aa.d + regs.x.w, regs.a.l);
if(regs.p.m)return;
l5:
op_write(OPMODE_LONG, aa.d + regs.x.w + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
aa.l = op_read();
break;
case 2:
aa.h = op_read();
break;
case 3:
aa.b = op_read();
break;
case 4:
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() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
op_write(OPMODE_DP, dp, regs.a.w);
if(regs.p.m)return;
l4:
op_write(OPMODE_DP, dp + 1, regs.a.w >> 8);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
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() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
op_write(OPMODE_DP, dp, regs.x.w);
if(regs.p.x)return;
l4:
op_write(OPMODE_DP, dp + 1, regs.x.w >> 8);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
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() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
op_write(OPMODE_DP, dp, regs.y.w);
if(regs.p.x)return;
l4:
op_write(OPMODE_DP, dp + 1, regs.y.w >> 8);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
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() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
op_write(OPMODE_DP, dp, 0x0000);
if(regs.p.m)return;
l4:
op_write(OPMODE_DP, dp + 1, 0x0000 >> 8);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
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() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
op_write(OPMODE_DP, dp + regs.x.w, regs.a.w);
if(regs.p.m)return;
l5:
op_write(OPMODE_DP, dp + regs.x.w + 1, regs.a.w >> 8);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
cpu_io();
break;
case 4:
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() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
op_write(OPMODE_DP, dp + regs.x.w, regs.y.w);
if(regs.p.x)return;
l5:
op_write(OPMODE_DP, dp + regs.x.w + 1, regs.y.w >> 8);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
cpu_io();
break;
case 4:
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() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
op_write(OPMODE_DP, dp + regs.x.w, 0x0000);
if(regs.p.m)return;
l5:
op_write(OPMODE_DP, dp + regs.x.w + 1, 0x0000 >> 8);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
cpu_io();
break;
case 4:
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() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
op_write(OPMODE_DP, dp + regs.y.w, regs.x.l);
if(regs.p.x)return;
l5:
op_write(OPMODE_DP, dp + regs.y.w + 1, regs.x.h);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
cpu_io();
break;
case 4:
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() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
aa.l = op_read(OPMODE_DP, dp);
l4:
aa.h = op_read(OPMODE_DP, dp + 1);
l5:
op_write(OPMODE_DBR, aa.w, regs.a.l);
if(regs.p.m)return;
l6:
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
aa.l = op_read(OPMODE_DP, dp);
break;
case 4:
aa.h = op_read(OPMODE_DP, dp + 1);
break;
case 5:
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() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
aa.l = op_read(OPMODE_DP, dp);
l4:
aa.h = op_read(OPMODE_DP, dp + 1);
l5:
aa.b = op_read(OPMODE_DP, dp + 2);
l6:
op_write(OPMODE_LONG, aa.d, regs.a.l);
if(regs.p.m)return;
l7:
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
aa.l = op_read(OPMODE_DP, dp);
break;
case 4:
aa.h = op_read(OPMODE_DP, dp + 1);
break;
case 5:
aa.b = op_read(OPMODE_DP, dp + 2);
break;
case 6:
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() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
cpu_io();
l4:
aa.l = op_read(OPMODE_DP, dp + regs.x.w);
l5:
aa.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
l6:
op_write(OPMODE_DBR, aa.w, regs.a.l);
if(regs.p.m)return;
l7:
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
cpu_io();
break;
case 4:
aa.l = op_read(OPMODE_DP, dp + regs.x.w);
break;
case 5:
aa.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
break;
case 6:
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() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
aa.l = op_read(OPMODE_DP, dp);
l4:
aa.h = op_read(OPMODE_DP, dp + 1);
l5:
cpu_c4(aa.w, aa.w + regs.y.w);
l6:
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
if(regs.p.m)return;
l7:
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
aa.l = op_read(OPMODE_DP, dp);
break;
case 4:
aa.h = op_read(OPMODE_DP, dp + 1);
break;
case 5:
cpu_c4(aa.w, aa.w + regs.y.w);
break;
case 6:
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() {
l1:
dp = op_read();
l2:
cpu_c2();
l3:
aa.l = op_read(OPMODE_DP, dp);
l4:
aa.h = op_read(OPMODE_DP, dp + 1);
l5:
aa.b = op_read(OPMODE_DP, dp + 2);
l6:
op_write(OPMODE_LONG, aa.d + regs.y.w, regs.a.l);
if(regs.p.m)return;
l7:
op_write(OPMODE_LONG, aa.d + regs.y.w + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
dp = op_read();
break;
case 2:
cpu_c2();
break;
case 3:
aa.l = op_read(OPMODE_DP, dp);
break;
case 4:
aa.h = op_read(OPMODE_DP, dp + 1);
break;
case 5:
aa.b = op_read(OPMODE_DP, dp + 2);
break;
case 6:
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() {
l1:
sp = op_read();
l2:
cpu_io();
l3:
op_write(OPMODE_SP, sp, regs.a.l);
if(regs.p.m)return;
l4:
op_write(OPMODE_SP, sp + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
sp = op_read();
break;
case 2:
cpu_io();
break;
case 3:
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() {
l1:
sp = op_read();
l2:
cpu_io();
l3:
aa.l = op_read(OPMODE_SP, sp);
l4:
aa.h = op_read(OPMODE_SP, sp + 1);
l5:
cpu_io();
l6:
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
if(regs.p.m)return;
l7:
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
switch(status.cycle_pos++) {
case 1:
sp = op_read();
break;
case 2:
cpu_io();
break;
case 3:
aa.l = op_read(OPMODE_SP, sp);
break;
case 4:
aa.h = op_read(OPMODE_SP, sp + 1);
break;
case 5:
cpu_io();
break;
case 6:
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; }
uint16 bCPU::hcounter() { return get_hcounter(); }
uint16 bCPU::hcycles() { return time.hc; }
bool bCPU::interlace() { return time.interlace; }
bool bCPU::interlace_field() { return time.interlace_field; }
bool bCPU::overscan() { return time.overscan; }
/* Notes about PAL timing:
* As I do not have PAL hardware to run timing tests on, I've
* had to guess on a lot of things. Below is how I've arrived
* at various calculations:
*
* NTSC timing crystal: ~21477272hz
* PAL timing crystal: ~21281370hz
* NTSC ~60fps, PAL ~50fps
* NTSC ~262 lines/frame, PAL ~312 lines/frame
* NTSC 21477272 / (262 * 60) = ~1366 cycles/line
* PAL 21281370 / (312 * 50) = ~1364 cycles/line
*
* As the cycles/line are very close between the two systems,
* I have left the known NTSC anomalies intact for PAL timing.
* In reality, some of these may not exist, and some may be
* slightly different.
*
* [known]
* - DRAM refresh occurs at about the same time every
* scanline on PAL units (per Overload).
* [unknown]
* - Are dots 323/327 still 2 cycles longer than the
* other dots?
* - Is scanline 240 on non-interlace odd frames still
* 4 cycles short?
*/
uint16 bCPU::vcounter() { return time.v; }
uint16 bCPU::hcounter() { return get_hcounter(); }
uint16 bCPU::hcycles() { return time.hc; }
bool bCPU::interlace() { return time.interlace; }
bool bCPU::interlace_field() { return time.interlace_field; }
bool bCPU::overscan() { return time.overscan; }
uint16 bCPU::region_scanlines() { return time.region_scanlines; }
void bCPU::set_interlace(bool r) { time.interlace = r; }
void bCPU::set_overscan(bool r) { time.overscan = r; }
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
//on non-interlace odd-frames, which is 1360 cycles long.
//[NTSC]
//interlace mode has 525 scanlines: 263 on the even frame,
//and 262 on the odd.
//non-interlace mode has 524 scanlines: 262 scanlines on
//both even and odd frames.
//[PAL] <PAL info is unverified on hardware>
//interlace mode has 625 scanlines: 313 on the even frame,
//and 312 on the odd.
//non-interlace mode has 624 scanlines: 312 scanlines on
//both even and odd frames.
//
//cycles per frame:
// 263 * 1364 = 358732
@ -28,9 +62,9 @@ void bCPU::inc_vcounter() {
time.interlace_field ^= 1;
if(time.interlace == true && time.interlace_field == 0) {
time.frame_lines = 263;
time.frame_lines = time.region_scanlines + 1;
} else {
time.frame_lines = 262;
time.frame_lines = time.region_scanlines;
}
}
@ -44,31 +78,19 @@ void bCPU::inc_vcounter() {
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
//240 on non-interlace odd frames. the reason for this is because this
//scanline is only 1360 cycles long, instead of 1364 like all other
//scanlines.
//this makes the effective range of hscan_pos 0-339 at all times.
//dot 322 range = { 1288, 1290, 1292 }
//dot 326 range = { 1306, 1308, 1310 }
//dot 323 range = { 1292, 1294, 1296 }
//dot 327 range = { 1310, 1312, 1314 }
uint16 bCPU::get_hcounter() {
if(time.v == 240 && time.interlace == false && time.interlace_field == 1) {
return time.hc >> 2;
}
return (time.hc - ((time.hc > 1288) << 1) - ((time.hc > 1306) << 1)) >> 2;
}
void bCPU::apu_sync() {
int cycles;
while(apusync.cycles >= 0) {
apu->run();
cycles = apu->cycles_executed();
if(cycles) {
apusync.cycles -= apusync.cpu_multbl[cycles];
}
}
return (time.hc - ((time.hc > 1292) << 1) - ((time.hc > 1310) << 1)) >> 2;
}
void bCPU::dram_refresh() {
@ -76,15 +98,22 @@ void bCPU::dram_refresh() {
add_cycles(40);
if(time.v != 240 || time.interlace != false || time.interlace_field != 1) {
//alternate between 534 and 538 every scanline except 240ni1
//in reality, this is probably based on frame cycle length...
time.dram_refresh_pos ^= 12;
}
}
uint32 bCPU::cycles_executed() {
uint32 r = status.cycles_executed;
status.cycles_executed = 0;
return r;
}
void bCPU::add_cycles(int cycles) {
status.cycles_executed += cycles;
cycles >>= 1;
while(cycles--) {
apusync.cycles += apusync.apu_freq << 1;
apu_sync();
time.hc += 2;
if(time.hc >= time.line_cycles) {
@ -119,23 +148,20 @@ void bCPU::time_reset() {
time.interlace_field = false;
time.overscan = false;
time.line_cycles = 1364;
time.frame_lines = 262;
time.dram_refreshed = false;
time.dram_refresh_pos = 538;
time.dma_counter = 0;
apusync.cycles = apusync.cpu_multbl[255];
}
void bCPU::time_init() {
apusync.cpu_freq = 21477272 >> 3;
apusync.apu_freq = 24576000 >> 3;
int i;
for(i=0;i<1024;i++) {
apusync.cpu_multbl[i] = i * apusync.cpu_freq;
apusync.apu_multbl[i] = i * apusync.apu_freq;
switch(region) {
case NTSC:
time.region_scanlines = 262;
break;
case PAL:
time.region_scanlines = 312;
break;
}
time.frame_lines = time.region_scanlines;
}

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

View File

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

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) {
uint32 addr;
addr = (regs.pc.d & 0xff0000) | ((regs.pc.d + 2) & 0xffff);
@ -81,16 +95,24 @@ uint32 r = 0;
}
void CPU::disassemble_opcode(char *output) {
char *s = output;
char *s;
char t[256];
uint8 op, op0, op1, op2;
sprintf(s, "%0.6x ", regs.pc.d);
static CPUReg24 pc;
s = output;
//TODO: This should wrap around the bank byte
op = mem_bus->read(regs.pc.d);
op0 = mem_bus->read(regs.pc.d + 1);
op1 = mem_bus->read(regs.pc.d + 2);
op2 = mem_bus->read(regs.pc.d + 3);
if(in_opcode() == true) {
strcpy(s, "?????? <CPU within opcode>");
return;
}
pc.d = regs.pc.d;
sprintf(s, "%0.6x ", pc.d);
op = 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) {
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
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);
len = op_len_tbl[op];
if(len == 5)return (regs.p.m)?2:3;

View File

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

View File

@ -1,5 +1,5 @@
/*
libbase : version 0.01 ~byuu
libbase : version 0.03 ~byuu (08/20/05)
*/
#ifndef __LIBBASE
@ -10,10 +10,21 @@
#include <stdarg.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 short word;
typedef unsigned long ulong;
typedef unsigned char bool8;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned long uint32;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -79,7 +79,7 @@ void Memory::write_long(uint32 addr, uint32 value, uint8 wrap) {
}
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) {}
uint8 MemBus::speed(uint32 addr) {

View File

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

View File

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

View File

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

View File

@ -18,6 +18,25 @@ uint16 opt_valid_bit; //offset-per-tile valid flag bit
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;
switch(color_depth) {
case COLORDEPTH_4:
@ -193,7 +212,7 @@ int _pri;
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)); }
else { ypos = ( (mosaic_y & 7)); }

View File

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

View File

@ -2,25 +2,25 @@
((x) & ((1 << 10) - 1)) + (((((x) & (1 << 13)) ^ (1 << 13)) - (1 << 13)) >> 3)
#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) {
int x;
int step_m7a, step_m7c, m7a, m7b, m7c, m7d;
int hoffset, voffset;
int centerx, centery;
int xx, yy;
int px, py;
int tx, ty, tile, palette;
int32 x;
int32 step_m7a, step_m7c, m7a, m7b, m7c, m7d;
int32 hoffset, voffset;
int32 centerx, centery;
int32 xx, yy;
int32 px, py;
int32 tx, ty, tile, palette;
uint8 layer_pos;
hoffset = (CAST_WORDTOINT(regs.bg_hofs[BG1]) << 7) >> 7;
voffset = (CAST_WORDTOINT(regs.bg_vofs[BG1]) << 7) >> 7;
hoffset = ((int32)regs.m7_hofs << 19) >> 19;
voffset = ((int32)regs.m7_vofs << 19) >> 19;
centerx = (CAST_WORDTOINT(regs.m7x) << 7) >> 7;
centery = (CAST_WORDTOINT(regs.m7y) << 7) >> 7;
centerx = ((int32)regs.m7x << 19) >> 19;
centery = ((int32)regs.m7y << 19) >> 19;
if(regs.mode7_vflip == true) {
yy = 223 - _y;
yy = 255 - _y;
} else {
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"
uint32 FileReader::size() {
return fsize;
}
/*
This function will allocate memory even if open() fails.
This is needed so that when SRAM files do not exist, the
memory for the SRAM data will be allocated still.
The memory is flushed to 0x00 when no file is opened.
*/
void FileReader::read(uint8 **buffer, uint32 length) {
uint8 *data;
if(length == 0) {
/* read the entire file into RAM */
data = (uint8*)memalloc(fsize);
memset(data, 0, fsize);
if(fp)fread(data, 1, fsize, fp);
} else if(length > fsize) {
/* read the entire file into RAM, pad the rest with 0x00s */
data = (uint8*)memalloc(length);
memset(data, 0, length);
if(fp)fread(data, 1, fsize, fp);
} else { //fsize >= length
/* read as much of the file as possible, truncate the rest */
data = (uint8*)memalloc(length);
memset(data, 0, length);
if(fp)fread(data, 1, length, fp);
}
*buffer = data;
}
bool FileReader::open(uint8 type, char *fn) {
fp = fopen(fn, "rb");
if(!fp)return false;
fseek(fp, 0, SEEK_END);
fsize = ftell(fp);
fseek(fp, 0, SEEK_SET);
if(type == TYPE_ROM) {
/* remove header if it exists */
if((fsize & 0xfff) == 0x200) {
fsize -= 0x200;
fseek(fp, 0x200, SEEK_SET);
}
}
/* empty file? */
if(fsize == 0) {
fclose(fp);
return false;
}
return true;
}
void FileReader::close() {
if(fp)fclose(fp);
}
void FileWriter::write(uint8 *buffer, uint32 length) {
if(!fp)return;
fwrite(buffer, 1, length, fp);
}
bool FileWriter::open(char *fn) {
fp = fopen(fn, "wb");
if(!fp)return false;
return true;
}
void FileWriter::close() {
if(fp)fclose(fp);
}
#include "filereader.cpp"

View File

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

View File

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

View File

@ -7,7 +7,8 @@ OBJS = sdlmain.obj \
cpu.obj bcpu.obj \
apu.obj bapu.obj bapuskip.obj \
ppu.obj bppu.obj \
snes.obj
snes.obj \
srtc.obj sdd1.obj
LIBS = kernel32.lib user32.lib gdi32.lib sdlmain.lib sdl.lib
all: $(OBJS)
@ -72,7 +73,7 @@ bppu.obj: ../ppu/bppu/*
##############
### reader ###
##############
reader.obj: ../reader/reader.cpp ../reader/reader.h
reader.obj: ../reader/*.cpp ../reader/*.h
$(CC) $(CFLAGS) /c ../reader/reader.cpp
############
@ -80,3 +81,15 @@ reader.obj: ../reader/reader.cpp ../reader/reader.h
############
snes.obj: ../snes/*.cpp ../snes/*.h
$(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);
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);
return false;
}
@ -33,7 +33,7 @@ FileReader *rf = new FileReader();
CartInfo ci;
mem_bus->get_cartinfo(&ci);
if(ci.sram_size != 0) {
rf->open(FileReader::TYPE_SRAM, sram_fn);
rf->open(sram_fn);
mem_bus->load_sram(static_cast<Reader*>(rf));
rf->close();
}

View File

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

View File

@ -1,40 +1,87 @@
#include "../base.h"
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() {
cpu->power();
apu->power();
ppu->power();
//clock->power();
mem_bus->power();
srtc->power();
sdd1->power();
int i;
mem_bus->flush_mmio_mappers();
for(i=0x2100;i<=0x213f;i++)mem_bus->set_mmio_mapper(i, ppu->mmio);
for(i=0x2140;i<=0x217f;i++)mem_bus->set_mmio_mapper(i, cpu->mmio);
for(i=0x2180;i<=0x2183;i++)mem_bus->set_mmio_mapper(i, cpu->mmio);
//unknown
mem_bus->set_mmio_mapper(0x21c2, cpu->mmio);
mem_bus->set_mmio_mapper(0x21c3, cpu->mmio);
//S-RTC
mem_bus->set_mmio_mapper(0x2800, cpu->mmio);
mem_bus->set_mmio_mapper(0x2801, cpu->mmio);
mem_bus->set_mmio_mapper(0x2800, srtc->mmio);
mem_bus->set_mmio_mapper(0x2801, srtc->mmio);
//input
mem_bus->set_mmio_mapper(0x4016, cpu->mmio);
mem_bus->set_mmio_mapper(0x4017, cpu->mmio);
for(i=0x4200;i<=0x421f;i++)mem_bus->set_mmio_mapper(i, cpu->mmio);
for(i=0x4300;i<=0x437f;i++)mem_bus->set_mmio_mapper(i, cpu->mmio);
//S-DD1
for(i=0x4800;i<=0x4807;i++)mem_bus->set_mmio_mapper(i, sdd1->mmio);
}
void SNES::reset() {
apusync.cycles = -apusync.cpu_multbl[32];
cpu->reset();
apu->reset();
ppu->reset();
//clock->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() {
is_debugger_enabled = true;
snes_region = NTSC;
update_timing();
}

View File

@ -2,12 +2,28 @@ class SNES {
protected:
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:
enum { NTSC = 0, PAL = 1 };
//system functions
void run();
virtual void render_frame() = 0;
virtual void power();
virtual void reset();
virtual void render_frame() = 0;
virtual void init();
virtual void power();
virtual void reset();
virtual uint8 region();
virtual void set_region(uint8 new_region);
//input functions
enum {

View File

@ -7,7 +7,8 @@ OBJS = winmain.obj \
cpu.obj bcpu.obj \
apu.obj bapu.obj bapuskip.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
all: $(OBJS)
@ -73,7 +74,7 @@ bppu.obj: ../ppu/bppu/*
##############
### reader ###
##############
reader.obj: ../reader/reader.cpp ../reader/reader.h
reader.obj: ../reader/*.cpp ../reader/*.h
$(CC) $(CFLAGS) /c ../reader/reader.cpp
############
@ -81,3 +82,15 @@ reader.obj: ../reader/reader.cpp ../reader/reader.h
############
snes.obj: ../snes/*.cpp ../snes/*.h
$(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;
break;
case RUNTOCPUPROCEED:
cpu_op = mem_bus->read(cpu->regs.pc);
/* 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) {
cpu_op = mem_bus->read(cpu->regs.pc.d);
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);
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 {
status.cpu_ran = false;
run_status = RUNTOCPUSTEP;
@ -78,7 +89,7 @@ void bSNES::snes_run() {
break;
case RUNTOCPUPROCEED:
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);
disassemble_cpu_op();
} else if(w_bp->hit() == true) {
@ -110,7 +121,7 @@ void bSNES::render_frame() {
*** Input functions ***
***********************/
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) {
joypad1.up = KeyDown(cfg.input.joypad1.up);
joypad1.down = KeyDown(cfg.input.joypad1.down);
@ -131,7 +142,7 @@ void bSNES::poll_input() {
joypad1.l = joypad1.r = 0;
}
//Check for debugger-based key locks
//check for debugger-based key locks
if(is_debugger_enabled == true) {
if(w_console->joypad_lock.up )joypad1.up = 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;
}
//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
//this to happen causes glitches in many SNES games.
if(joypad1.up) joypad1.down = 0;
@ -274,6 +285,7 @@ void bSNES::notify(uint32 message, uint32 param1, uint32 param2) {
case CPU_EXEC_OPCODE_END:
status.cpu_ran = true;
status.cpu_trace_pos++;
//test next opcode for breakpoint
w_bp->test(message, cpu->regs.pc.d, 0);
disassemble_cpu_op();
break;

View File

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

View File

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

View File

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

View File

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

View File

@ -22,7 +22,7 @@ int i;
if(!(bp[i].flags & FLAG_X))continue;
if(bp[i].source != DRAM)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_hit = true;
w_bp->refresh();
@ -31,7 +31,7 @@ int i;
if(!(bp[i].flags & FLAG_X))continue;
if(bp[i].source != SPCRAM)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_hit = true;
w_bp->refresh();

View File

@ -29,13 +29,21 @@ HDC hdc;
break;
case CONSOLE_CPUPROCEED:
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;
case CONSOLE_CPUSKIP:
if(bsnes->get_status() == bSNES::STOP) {
cpu->regs.pc.w += cpu->opcode_length();
bsnes->disassemble_cpu_op();
if(cpu->in_opcode() == true) {
dprintf("* CPU within opcode, skip aborted");
} else {
cpu->regs.pc.w += cpu->opcode_length();
bsnes->disassemble_cpu_op();
}
}
break;
case CONSOLE_CPUTRACE:
@ -49,13 +57,17 @@ HDC hdc;
break;
case CONSOLE_CPUDISABLE:
if(bsnes->get_status() == bSNES::STOP) {
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);
if(cpu->in_opcode() == true) {
dprintf("* CPU within opcode, disable aborted");
} else {
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;
case CONSOLE_APUSTEP:
@ -111,21 +123,25 @@ HDC hdc;
value = strhex(t);
pos = SendDlgItemMessage(hwnd, CONSOLE_CFGREGTYPE, CB_GETCURSEL, 0, 0);
if(pos == 0) { //Set CPU register
pos = SendDlgItemMessage(hwnd, CONSOLE_CFGREGNUM, CB_GETCURSEL, 0, 0);
switch(pos) {
case 0:cpu->regs.a.w = value;break;
case 1:cpu->regs.x.w = value;break;
case 2:cpu->regs.y.w = value;break;
case 3:cpu->regs.s.w = value;break;
case 4:cpu->regs.d.w = 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;
if(cpu->in_opcode() == true) {
dprintf("* CPU within opcode, register set aborted");
} else {
pos = SendDlgItemMessage(hwnd, CONSOLE_CFGREGNUM, CB_GETCURSEL, 0, 0);
switch(pos) {
case 0:cpu->regs.a.w = value;break;
case 1:cpu->regs.x.w = value;break;
case 2:cpu->regs.y.w = value;break;
case 3:cpu->regs.s.w = value;break;
case 4:cpu->regs.d.w = 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
}
break;

View File

@ -132,6 +132,7 @@ void MainWindow::menu_unload() {
}
long __stdcall wndproc_main(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
time_t timeout;
switch(msg) {
case WM_KEYDOWN:
if(wparam == VK_ESCAPE) {
@ -144,6 +145,13 @@ long __stdcall wndproc_main(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
}
break;
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)) {
case MENU_FILE_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);
}
break;
case MENU_MISC_SCREENSHOT:
break;
case MENU_MISC_ABOUT:
w_about->center();
w_about->show();
@ -315,6 +325,8 @@ HMENU hsubmenu, hbranchmenu;
AppendMenu(hmenu, MF_STRING | MF_POPUP, (unsigned int)hsubmenu, "&Settings");
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(hmenu, MF_STRING | MF_POPUP, (unsigned int)hsubmenu, "&Misc");

View File

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