mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
970dcea0ac
commit
7e2cfb6d40
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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.
|
@ -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);
|
||||
|
|
10
src/base.h
10
src/base.h
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
};
|
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
|
@ -0,0 +1,161 @@
|
|||
/************************************************************************
|
||||
|
||||
S-DD1'algorithm emulation code
|
||||
------------------------------
|
||||
|
||||
Author: Andreas Naive
|
||||
Date: August 2003
|
||||
Last update: October 2004
|
||||
|
||||
This code is Public Domain. There is no copyright holded by the author.
|
||||
Said this, the author wish to explicitly emphasize his inalienable moral rights
|
||||
over this piece of intelectual work and the previous research that made it
|
||||
possible, as recognized by most of the copyright laws around the world.
|
||||
|
||||
This code is provided 'as-is', with no warranty, expressed or implied.
|
||||
No responsability is assumed by the author in connection with it.
|
||||
|
||||
The author is greatly indebted with The Dumper, without whose help and
|
||||
patience providing him with real S-DD1 data the research would have never been
|
||||
possible. He also wish to note that in the very beggining of his research,
|
||||
Neviksti had done some steps in the right direction. By last, the author is
|
||||
indirectly indebted to all the people that worked and contributed in the
|
||||
S-DD1 issue in the past.
|
||||
|
||||
An algorithm's documentation is available as a separate document.
|
||||
The implementation is obvious when the algorithm is
|
||||
understood.
|
||||
|
||||
************************************************************************/
|
||||
|
||||
|
||||
class SDD1_IM { //Input Manager
|
||||
|
||||
public:
|
||||
SDD1_IM(void) {}
|
||||
void prepareDecomp(uint32 in_buf);
|
||||
uint8 getCodeword(const uint8 code_len);
|
||||
|
||||
private:
|
||||
uint32 byte_ptr;
|
||||
uint8 bit_count;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_GCD { //Golomb-Code Decoder
|
||||
|
||||
public:
|
||||
SDD1_GCD(SDD1_IM *associatedIM);
|
||||
void getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind);
|
||||
|
||||
private:
|
||||
SDD1_IM *const IM;
|
||||
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_BG { // Bits Generator
|
||||
|
||||
public:
|
||||
SDD1_BG(SDD1_GCD *associatedGCD, uint8 code);
|
||||
void prepareDecomp(void);
|
||||
uint8 getBit(bool8 *endOfRun);
|
||||
|
||||
private:
|
||||
const uint8 code_num;
|
||||
uint8 MPScount;
|
||||
bool8 LPSind;
|
||||
SDD1_GCD *const GCD;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_PEM { //Probability Estimation Module
|
||||
|
||||
public:
|
||||
SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
|
||||
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
|
||||
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
|
||||
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7);
|
||||
void prepareDecomp(void);
|
||||
uint8 getBit(uint8 context);
|
||||
|
||||
private:
|
||||
struct state {
|
||||
uint8 code_num;
|
||||
uint8 nextIfMPS;
|
||||
uint8 nextIfLPS;
|
||||
};
|
||||
static const state evolution_table[];
|
||||
struct SDD1_ContextInfo {
|
||||
uint8 status;
|
||||
uint8 MPS;
|
||||
} contextInfo[32];
|
||||
SDD1_BG * BG[8];
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_CM { //Context Model
|
||||
|
||||
public:
|
||||
SDD1_CM(SDD1_PEM *associatedPEM);
|
||||
void prepareDecomp(uint32 first_byte);
|
||||
uint8 getBit(void);
|
||||
|
||||
private:
|
||||
uint8 bitplanesInfo;
|
||||
uint8 contextBitsInfo;
|
||||
uint8 bit_number;
|
||||
uint8 currBitplane;
|
||||
uint16 prevBitplaneBits[8];
|
||||
SDD1_PEM *const PEM;
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1_OL { //Output Logic
|
||||
|
||||
public:
|
||||
SDD1_OL(SDD1_CM *associatedCM);
|
||||
void prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf);
|
||||
void launch(void);
|
||||
|
||||
private:
|
||||
uint8 bitplanesInfo;
|
||||
uint16 length;
|
||||
uint8 *buffer;
|
||||
SDD1_CM *const CM;
|
||||
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class SDD1emu {
|
||||
|
||||
public:
|
||||
SDD1emu(void);
|
||||
void decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf);
|
||||
|
||||
private:
|
||||
SDD1_IM IM;
|
||||
SDD1_GCD GCD;
|
||||
SDD1_BG BG0; SDD1_BG BG1; SDD1_BG BG2; SDD1_BG BG3;
|
||||
SDD1_BG BG4; SDD1_BG BG5; SDD1_BG BG6; SDD1_BG BG7;
|
||||
SDD1_PEM PEM;
|
||||
SDD1_CM CM;
|
||||
SDD1_OL OL;
|
||||
|
||||
};
|
|
@ -50,7 +50,9 @@
|
|||
whenever the RTC is set.
|
||||
*/
|
||||
|
||||
void bCPU::srtc_set_time() {
|
||||
#include "../../base.h"
|
||||
|
||||
void SRTC::set_time() {
|
||||
time_t rawtime;
|
||||
tm *t;
|
||||
::time(&rawtime);
|
||||
|
@ -72,12 +74,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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
};
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
@ -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
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
@ -3,8 +3,7 @@ nop(0xea) {
|
|||
}
|
||||
|
||||
wdm(0x42) {
|
||||
1:cpu_io();
|
||||
regs.pc.w++;
|
||||
1:op_read();
|
||||
}
|
||||
|
||||
xba(0xeb) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -43,10 +43,10 @@ strmath(str)
|
|||
str, and returns numerical result
|
||||
example: strmath("5+5")=10
|
||||
***************************************/
|
||||
uint32 p_strmath(char *str) {
|
||||
int i = 0, ssl = strlen(str);
|
||||
uint p_strmath(const char *str) {
|
||||
int i = 0, ssl = strlen(str);
|
||||
uint r, array[128], array_size = 0, z = 0;
|
||||
uint8 x, mode = 0;
|
||||
uint32 r, array[128], array_size = 0, z = 0;
|
||||
uint8 array_gate[128];
|
||||
char *s1;
|
||||
if(!ssl)return 0;
|
||||
|
@ -95,11 +95,11 @@ char *s1;
|
|||
return r;
|
||||
}
|
||||
|
||||
uint32 strmath(char *in_str) {
|
||||
uint32 r = 0;
|
||||
uint32 pdepth = 0, cpdepth, maxpdepth = 0;
|
||||
uint32 pstart, pend, spos;
|
||||
int i, sc, sl = strlen(in_str);
|
||||
uint strmath(const char *in_str) {
|
||||
uint r = 0;
|
||||
uint pdepth = 0, cpdepth, maxpdepth = 0;
|
||||
uint pstart, pend, spos;
|
||||
int i, sc, sl = strlen(in_str);
|
||||
char *str = (char*)malloc(sl + 1), *str0;
|
||||
char *pstr;
|
||||
char num[64];
|
||||
|
@ -165,13 +165,15 @@ char num[64];
|
|||
free(str);
|
||||
return r;
|
||||
}
|
||||
uint strmath(substring &in_str) { return strmath(strptr(in_str)); }
|
||||
|
||||
uint32 strmathentity(char *str) {
|
||||
bool strmathentity(const char *str) {
|
||||
int i, ssl = strlen(str);
|
||||
for(i=0;i<ssl;i++) {
|
||||
if(str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/' ||
|
||||
str[i] == '%' || str[i] == '&' || str[i] == '|' || str[i] == '^' ||
|
||||
(str[i] == '<' && str[i+1] == '<') || (str[i] == '>' && str[i+1] == '>'))return 1;
|
||||
(str[i] == '<' && str[i+1] == '<') || (str[i] == '>' && str[i+1] == '>'))return true;
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
bool strmathentity(substring &str) { return strmathentity(strptr(str)); }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
void replace(_string &str, char *key, char *token) {
|
||||
int i, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str);
|
||||
uint32 replace_count = 0, size = ssl;
|
||||
void replace(substring &str, const char *key, const char *token) {
|
||||
int i, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str);
|
||||
uint replace_count = 0, size = ssl;
|
||||
char *data;
|
||||
if(ksl > ssl)return;
|
||||
if(tsl > ksl) { //the new string may be longer than the old string...
|
||||
|
@ -27,11 +27,12 @@ char *data;
|
|||
strcpy(str, data);
|
||||
free(data);
|
||||
}
|
||||
void replace(substring &str, const char *key, substring &token) { replace(str, key, strptr(token)); }
|
||||
|
||||
void qreplace(_string &str, char *key, char *token) {
|
||||
int i, l, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str);
|
||||
void qreplace(substring &str, const char *key, const char *token) {
|
||||
int i, l, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str);
|
||||
uint replace_count = 0, size = ssl;
|
||||
uint8 x;
|
||||
uint32 replace_count = 0, size = ssl;
|
||||
char *data;
|
||||
if(ksl > ssl)return;
|
||||
if(tsl > ksl) {
|
||||
|
@ -80,3 +81,4 @@ char *data;
|
|||
strcpy(str, data);
|
||||
free(data);
|
||||
}
|
||||
void qreplace(substring &str, const char *key, substring &token) { qreplace(str, key, strptr(token)); }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
void split(string &dest, char *key, char *src) {
|
||||
int i, ssl = strlen(src), ksl = strlen(key);
|
||||
void split(string &dest, const char *key, char *src) {
|
||||
int i, ssl = strlen(src), ksl = strlen(key);
|
||||
uint lp = 0, split_count = 0;
|
||||
uint8 x;
|
||||
uint32 lp = 0, split_count = 0;
|
||||
for(i=0;i<=ssl-ksl;) {
|
||||
if(!memcmp(src + i, key, ksl)) {
|
||||
x = src[i];
|
||||
|
@ -15,11 +15,12 @@ uint32 lp = 0, split_count = 0;
|
|||
strcpy(dest[split_count++], src + lp);
|
||||
dest.count = split_count;
|
||||
}
|
||||
void split(string &dest, const char *key, substring &src) { split(dest, key, strptr(src)); }
|
||||
|
||||
void qsplit(string &dest, char *key, char *src) {
|
||||
int i, z, ssl = strlen(src), ksl = strlen(key);
|
||||
void qsplit(string &dest, const char *key, char *src) {
|
||||
int i, z, ssl = strlen(src), ksl = strlen(key);
|
||||
uint lp = 0, split_count = 0;
|
||||
uint8 x;
|
||||
uint32 lp = 0, split_count = 0;
|
||||
for(i=0;i<=ssl-ksl;) {
|
||||
x = src[i];
|
||||
if(x=='\"' || x=='\'') {
|
||||
|
@ -39,3 +40,4 @@ uint32 lp = 0, split_count = 0;
|
|||
strcpy(dest[split_count++], src + lp);
|
||||
dest.count = split_count;
|
||||
}
|
||||
void qsplit(string &dest, const char *key, substring &src) { qsplit(dest, key, strptr(src)); }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
void numtobin(char *s, uint32 num) {
|
||||
uint32 mask = 0x80000000, len = 0, z = 0;
|
||||
void numtobin(char *s, uint num) {
|
||||
uint mask = 0x80000000, len = 0, z = 0;
|
||||
for(;mask;mask>>=1,len++) { if(num&mask)break; }
|
||||
len = 32 - len;
|
||||
do {
|
||||
|
@ -9,7 +9,7 @@ uint32 mask = 0x80000000, len = 0, z = 0;
|
|||
s[z] = 0;
|
||||
}
|
||||
|
||||
void sprintf(_string &str, char *s, ...) {
|
||||
void sprintf(substring &str, const char *s, ...) {
|
||||
va_list args;
|
||||
char t[2], n[256];
|
||||
int i, l, sl, z;
|
||||
|
@ -17,7 +17,7 @@ uint8 pad_type, pad_len;
|
|||
uint32 num;
|
||||
char *r;
|
||||
va_start(args, s);
|
||||
strcpy(*str, "");
|
||||
strcpy(str, "");
|
||||
for(i=0;i<strlen(s);i++) {
|
||||
if(s[i] == '%') {
|
||||
i++;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
void bCartExLoROM::write_protect(bool r) { write_protected = r; }
|
||||
|
||||
uint8 bCartExLoROM::read(uint32 addr) {
|
||||
uint32 b, w;
|
||||
addr &= 0xffffff;
|
||||
b = (addr >> 16);
|
||||
w = (addr & 0xffff);
|
||||
|
||||
//SRAM Region A
|
||||
if((b & 0x7f) >= 0x30 && (b & 0x7f) <= 0x3f && (w & 0xe000) == 0x6000) {
|
||||
b &= 0x7f;
|
||||
if(b >= 0x30 && b <= 0x3f) {
|
||||
if(sram_size) {
|
||||
addr = (b - 0x30) * 0x2000 + (w - 0x6000);
|
||||
addr &= (sram_size - 1);
|
||||
return sram[addr];
|
||||
} else {
|
||||
return 0x00; //no SRAM available
|
||||
}
|
||||
} else {
|
||||
return 0x00; //unmapped
|
||||
}
|
||||
}
|
||||
|
||||
//SRAM Region B
|
||||
if(b >= 0x70 && b <= 0x7d) {
|
||||
if(sram_size) {
|
||||
addr = (addr & 0xffffff) - 0x700000;
|
||||
addr &= (sram_size - 1);
|
||||
return sram[addr];
|
||||
} else {
|
||||
return 0x00; //no SRAM available
|
||||
}
|
||||
}
|
||||
|
||||
if(b <= 0x3f) {
|
||||
addr = (b << 15) | (addr & 0x7fff);
|
||||
} else if(b <= 0x7f) {
|
||||
addr &= 0x3fffff;
|
||||
} else if(b <= 0xbf) {
|
||||
b &= 0x7f;
|
||||
addr = (b << 15) | (addr & 0x7fff);
|
||||
} else {
|
||||
addr = sdd1->offset(addr);
|
||||
}
|
||||
|
||||
if(addr < rom_size)return rom[addr];
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void bCartExLoROM::write(uint32 addr, uint8 value) {
|
||||
uint32 b, w;
|
||||
addr &= 0xffffff;
|
||||
b = (addr >> 16);
|
||||
w = (addr & 0xffff);
|
||||
|
||||
//SRAM Region A
|
||||
if((b & 0x7f) >= 0x30 && (b & 0x7f) <= 0x3f && (w & 0xe000) == 0x6000) {
|
||||
b &= 0x7f;
|
||||
if(b >= 0x30 && b <= 0x3f) {
|
||||
if(sram_size) {
|
||||
addr = (b - 0x30) * 0x2000 + (w - 0x6000);
|
||||
addr &= (sram_size - 1);
|
||||
sram[addr] = value;
|
||||
return;
|
||||
} else {
|
||||
return; //no SRAM available
|
||||
}
|
||||
} else {
|
||||
return; //unmapped
|
||||
}
|
||||
}
|
||||
|
||||
//SRAM Region B
|
||||
if(b >= 0x70 && b <= 0x7d) {
|
||||
if(sram_size) {
|
||||
addr = (addr & 0xffffff) - 0x700000;
|
||||
addr &= (sram_size - 1);
|
||||
sram[addr] = value;
|
||||
} else {
|
||||
return; //no SRAM available
|
||||
}
|
||||
}
|
||||
|
||||
if(write_protected == true)return;
|
||||
|
||||
if(b <= 0x3f) {
|
||||
addr = (b << 15) | (addr & 0x7fff);
|
||||
} else if(b <= 0x7f) {
|
||||
addr &= 0x3fffff;
|
||||
} else if(b <= 0xbf) {
|
||||
b &= 0x7f;
|
||||
addr = (b << 15) | (addr & 0x7fff);
|
||||
} else {
|
||||
addr = sdd1->offset(addr);
|
||||
}
|
||||
|
||||
if(addr < rom_size)rom[addr] = value;
|
||||
}
|
||||
|
||||
void bCartExLoROM::set_cartinfo(CartInfo *ci) {
|
||||
rom = ci->rom;
|
||||
sram = ci->sram;
|
||||
rom_size = ci->rom_size;
|
||||
sram_size = ci->sram_size;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
class bCartExLoROM : public Cart {
|
||||
private:
|
||||
bool write_protected;
|
||||
|
||||
public:
|
||||
uint8 *rom, *sram;
|
||||
uint32 rom_size, sram_size;
|
||||
uint8 read (uint32 addr);
|
||||
void write(uint32 addr, byte value);
|
||||
void write_protect(bool r);
|
||||
void set_cartinfo(CartInfo *ci);
|
||||
|
||||
bCartExLoROM() : write_protected(true) {}
|
||||
};
|
|
@ -33,10 +33,13 @@ uint32 b, w;
|
|||
}
|
||||
}
|
||||
|
||||
addr &= 0x3fffff;
|
||||
if(addr < rom_size)return rom[addr];
|
||||
addr &= ROM_mask;
|
||||
|
||||
return 0x00;
|
||||
if(addr >= P0_size) {
|
||||
addr = P0_size + (addr & (P1_size - 1));
|
||||
}
|
||||
|
||||
return rom[addr];
|
||||
}
|
||||
|
||||
void bCartHiROM::write(uint32 addr, uint8 value) {
|
||||
|
@ -74,8 +77,14 @@ uint32 b, w;
|
|||
}
|
||||
|
||||
if(write_protected == true)return;
|
||||
addr &= 0x3fffff;
|
||||
if(addr < rom_size)rom[addr] = value;
|
||||
|
||||
addr &= ROM_mask;
|
||||
|
||||
if(addr >= P0_size) {
|
||||
addr = P0_size + (addr & (P1_size - 1));
|
||||
}
|
||||
|
||||
rom[addr] = value;
|
||||
}
|
||||
|
||||
void bCartHiROM::set_cartinfo(CartInfo *ci) {
|
||||
|
@ -83,4 +92,15 @@ void bCartHiROM::set_cartinfo(CartInfo *ci) {
|
|||
sram = ci->sram;
|
||||
rom_size = ci->rom_size;
|
||||
sram_size = ci->sram_size;
|
||||
|
||||
//calculate highest power of 2, which is the size of the first ROM chip
|
||||
P0_size = 0x800000;
|
||||
while(!(rom_size & P0_size))P0_size >>= 1;
|
||||
P1_size = rom_size - P0_size;
|
||||
|
||||
if(rom_size == P0_size) { //cart only contains one ROM chip
|
||||
ROM_mask = (P0_size - 1);
|
||||
} else { //cart contains two ROM chips
|
||||
ROM_mask = (P0_size + P0_size - 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,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;
|
||||
|
|
|
@ -35,17 +35,20 @@ uint32 b, w;
|
|||
|
||||
if(w & 0x8000) {
|
||||
b &= 0x7f;
|
||||
b %= 0x60;
|
||||
addr = (b << 15) | (addr & 0x7fff);
|
||||
} else {
|
||||
b &= 0x7f;
|
||||
b %= 0x60;
|
||||
if(b == 0x00)b = 0x60;
|
||||
if(b == 0x00)b = 0x7f;
|
||||
addr = (((b << 15) | (addr & 0x7fff)) - 0x8000);
|
||||
}
|
||||
if(addr < rom_size)return rom[addr];
|
||||
|
||||
return 0x00;
|
||||
addr &= ROM_mask;
|
||||
|
||||
if(addr >= P0_size) {
|
||||
addr = P0_size + (addr & (P1_size - 1));
|
||||
}
|
||||
|
||||
return rom[addr];
|
||||
}
|
||||
|
||||
void bCartLoROM::write(uint32 addr, uint8 value) {
|
||||
|
@ -83,17 +86,23 @@ uint32 b, w;
|
|||
}
|
||||
|
||||
if(write_protected == true)return;
|
||||
|
||||
if(w & 0x8000) {
|
||||
b &= 0x7f;
|
||||
b %= 0x60;
|
||||
addr = (b << 15) | (addr & 0x7fff);
|
||||
} else {
|
||||
b &= 0x7f;
|
||||
b %= 0x60;
|
||||
if(b == 0x00)b = 0x60;
|
||||
if(b == 0x00)b = 0x7f;
|
||||
addr = (((b << 15) | (addr & 0x7fff)) - 0x8000);
|
||||
}
|
||||
if(addr < rom_size)rom[addr] = value;
|
||||
|
||||
addr &= ROM_mask;
|
||||
|
||||
if(addr >= P0_size) {
|
||||
addr = P0_size + (addr & (P1_size - 1));
|
||||
}
|
||||
|
||||
rom[addr] = value;
|
||||
}
|
||||
|
||||
void bCartLoROM::set_cartinfo(CartInfo *ci) {
|
||||
|
@ -101,4 +110,15 @@ void bCartLoROM::set_cartinfo(CartInfo *ci) {
|
|||
sram = ci->sram;
|
||||
rom_size = ci->rom_size;
|
||||
sram_size = ci->sram_size;
|
||||
|
||||
//calculate highest power of 2, which is the size of the first ROM chip
|
||||
P0_size = 0x800000;
|
||||
while(!(rom_size & P0_size))P0_size >>= 1;
|
||||
P1_size = rom_size - P0_size;
|
||||
|
||||
if(rom_size == P0_size) { //cart only contains one ROM chip
|
||||
ROM_mask = (P0_size - 1);
|
||||
} else { //cart contains two ROM chips
|
||||
ROM_mask = (P0_size + P0_size - 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)); }
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
uint32 FileReader::size() {
|
||||
return fsize;
|
||||
}
|
||||
|
||||
//This function will allocate memory even if open() fails.
|
||||
//This is needed so that when SRAM files do not exist, the
|
||||
//memory for the SRAM data will be allocated still.
|
||||
//The memory is flushed to 0x00 when no file is opened.
|
||||
void FileReader::read(uint8 **buffer, uint32 length) {
|
||||
uint8 *data;
|
||||
if(length == 0) {
|
||||
//read the entire file into RAM
|
||||
data = (uint8*)memalloc(fsize);
|
||||
memset(data, 0, fsize);
|
||||
if(fp)fread(data, 1, fsize, fp);
|
||||
} else if(length > fsize) {
|
||||
//read the entire file into RAM, pad the rest with 0x00s
|
||||
data = (uint8*)memalloc(length);
|
||||
memset(data, 0, length);
|
||||
if(fp)fread(data, 1, fsize, fp);
|
||||
} else { //fsize >= length
|
||||
//read only what was requested
|
||||
data = (uint8*)memalloc(length);
|
||||
memset(data, 0, length);
|
||||
if(fp)fread(data, 1, length, fp);
|
||||
}
|
||||
*buffer = data;
|
||||
}
|
||||
|
||||
bool FileReader::open(char *fn) {
|
||||
fp = fopen(fn, "rb");
|
||||
if(!fp)return false;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
fsize = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
//empty file?
|
||||
if(fsize == 0) {
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileReader::close() {
|
||||
if(fp) {
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void FileWriter::write(uint8 *buffer, uint32 length) {
|
||||
if(!fp)return;
|
||||
|
||||
fwrite(buffer, 1, length, fp);
|
||||
}
|
||||
|
||||
bool FileWriter::open(char *fn) {
|
||||
fp = fopen(fn, "wb");
|
||||
if(!fp)return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileWriter::close() {
|
||||
if(fp) {
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
class FileReader : public Reader {
|
||||
private:
|
||||
FILE *fp;
|
||||
uint32 fsize;
|
||||
|
||||
public:
|
||||
uint32 size();
|
||||
void read(uint8 **buffer, uint32 length = 0);
|
||||
bool open(char *fn);
|
||||
void close();
|
||||
|
||||
FileReader() { fp = 0; fsize = 0; }
|
||||
~FileReader() { if(fp)fclose(fp); }
|
||||
};
|
||||
|
||||
class FileWriter : public Writer {
|
||||
private:
|
||||
FILE *fp;
|
||||
|
||||
public:
|
||||
void write(uint8 *buffer, uint32 length);
|
||||
bool open(char *fn);
|
||||
void close();
|
||||
|
||||
FileWriter() { fp = 0; }
|
||||
~FileWriter() { if(fp)fclose(fp); }
|
||||
};
|
|
@ -1,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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ enum {
|
|||
MENU_SETTINGS_APUENABLED,
|
||||
MENU_SETTINGS_INPUTCFG_JOYPAD1,
|
||||
MENU_SETTINGS_DEBUGGER,
|
||||
MENU_MISC_SCREENSHOT,
|
||||
MENU_MISC_ABOUT
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue