mirror of
https://github.com/wavemotion-dave/GimliDS.git
synced 2025-06-18 13:55:32 -04:00
Version 0.9b with CART support. See readme file.
This commit is contained in:
parent
a417d7910d
commit
d20408a9b2
BIN
GimliDS.nds
BIN
GimliDS.nds
Binary file not shown.
2
Makefile
2
Makefile
@ -9,7 +9,7 @@ include $(DEVKITARM)/ds_rules
|
||||
|
||||
export TARGET := GimliDS
|
||||
export TOPDIR := $(CURDIR)
|
||||
export VERSION := 0.9a
|
||||
export VERSION := 0.9b
|
||||
|
||||
ICON := -b $(CURDIR)/C64_icon.bmp "GimliDS $(VERSION);wavemotion-dave;https://github.com/wavemotion-dave/GimliDS"
|
||||
|
||||
|
@ -109,6 +109,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
```
|
||||
## Change Log
|
||||
|
||||
Version 0.9b release 05-May-2025 by wavemotion-dave
|
||||
* Pressing L+R shoulder buttons together is WARP mode (run emulator fast while the buttons are held)
|
||||
* Improved L/R + DPAD scale/offset (so it doesn't also produce joystick input at the same time)
|
||||
* Minor tweaks to TrueDrive mode for improved cycle accuracy
|
||||
* CRT and PRG Cartridge support. Most popular game-based formats are supported. Use the new CART icon.
|
||||
|
||||
Version 0.9a release 02-May-2025 by wavemotion-dave
|
||||
* Fixed TrueDrive loading so it doesn't alter the CPU speed (for games like Pang which were playing quite 'uneven').
|
||||
* Bumped up volume of the SID output by 50% (was too quiet)
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 40 KiB |
Binary file not shown.
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
@ -46,31 +46,38 @@
|
||||
#include "IEC.h"
|
||||
#include "1541gcr.h"
|
||||
#include "Display.h"
|
||||
#include "Cartridge.h"
|
||||
#include "Prefs.h"
|
||||
#include "mainmenu.h"
|
||||
#include "lzav.h"
|
||||
#include <maxmod9.h>
|
||||
#include "soundbank.h"
|
||||
|
||||
|
||||
uint8 myRAM[C64_RAM_SIZE];
|
||||
uint8 myKERNAL[KERNAL_ROM_SIZE];
|
||||
uint8 myBASIC[BASIC_ROM_SIZE];
|
||||
uint8 myRAM1541[DRIVE_RAM_SIZE] __attribute__((section(".dtcm")));
|
||||
|
||||
uint8 bTurboWarp __attribute__((section(".dtcm"))) = 0;
|
||||
uint8 cart_in __attribute__((section(".dtcm"))) = 0;
|
||||
|
||||
#define SNAPSHOT_VERSION 1
|
||||
C64 *gTheC64 = nullptr;
|
||||
|
||||
u8 CompressBuffer[0x20000]; //128K more than enough
|
||||
|
||||
#define SNAPSHOT_VERSION 2
|
||||
|
||||
/*
|
||||
* Constructor: Allocate objects and memory
|
||||
*/
|
||||
|
||||
C64::C64()
|
||||
{
|
||||
// The thread is not yet running
|
||||
thread_running = false;
|
||||
quit_thyself = false;
|
||||
have_a_break = false;
|
||||
|
||||
gTheC64 = this;
|
||||
|
||||
// System-dependent things
|
||||
c64_ctor1();
|
||||
@ -80,7 +87,7 @@ C64::C64()
|
||||
|
||||
// Allocate RAM/ROM memory
|
||||
RAM = myRAM;
|
||||
Basic = new uint8[BASIC_ROM_SIZE];
|
||||
Basic = myBASIC;
|
||||
Kernal = myKERNAL;
|
||||
Char = new uint8[CHAR_ROM_SIZE];
|
||||
Color = new uint8[COLOR_RAM_SIZE];
|
||||
@ -93,11 +100,12 @@ C64::C64()
|
||||
TheJob1541 = new Job1541(RAM1541);
|
||||
TheCPU1541 = new MOS6502_1541(this, TheJob1541, TheDisplay, RAM1541, ROM1541);
|
||||
|
||||
TheVIC = TheCPU->TheVIC = new MOS6569(this, TheDisplay, TheCPU, RAM, Char, Color);
|
||||
TheSID = TheCPU->TheSID = new MOS6581(this);
|
||||
TheVIC = TheCPU->TheVIC = new MOS6569(this, TheDisplay, TheCPU, RAM, Char, Color);
|
||||
TheSID = TheCPU->TheSID = new MOS6581(this);
|
||||
TheCIA1 = TheCPU->TheCIA1 = new MOS6526_1(TheCPU, TheVIC);
|
||||
TheCIA2 = TheCPU->TheCIA2 = TheCPU1541->TheCIA2 = new MOS6526_2(TheCPU, TheVIC, TheCPU1541);
|
||||
TheIEC = TheCPU->TheIEC = new IEC(TheDisplay);
|
||||
TheIEC = TheCPU->TheIEC = new IEC(TheDisplay);
|
||||
TheCart = TheCPU->TheCart = new Cartridge();
|
||||
|
||||
InitMemory();
|
||||
|
||||
@ -172,7 +180,6 @@ C64::~C64()
|
||||
delete TheCPU;
|
||||
delete TheDisplay;
|
||||
|
||||
delete[] Basic;
|
||||
delete[] Char;
|
||||
delete[] Color;
|
||||
delete[] ROM1541;
|
||||
@ -196,6 +203,7 @@ void C64::Reset(void)
|
||||
TheCIA2->Reset();
|
||||
TheIEC->Reset();
|
||||
TheVIC->Reset();
|
||||
TheCart->Reset();
|
||||
|
||||
bTurboWarp = 0;
|
||||
}
|
||||
@ -210,6 +218,29 @@ void C64::NMI(void)
|
||||
TheCPU->AsyncNMI();
|
||||
}
|
||||
|
||||
void C64::LoadPRG(char *filename)
|
||||
{
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
if (fp)
|
||||
{
|
||||
int prg_size = fread(CompressBuffer, 1, sizeof(CompressBuffer), fp);
|
||||
|
||||
uint8 start_hi, start_lo;
|
||||
uint16 start;
|
||||
int i;
|
||||
|
||||
u8 *prg = CompressBuffer;
|
||||
start_lo=*prg++;
|
||||
start_hi=*prg++;
|
||||
start=(start_hi<<8)+start_lo;
|
||||
|
||||
for(i=0; i<(prg_size-2); i++)
|
||||
{
|
||||
myRAM[start+i]=prg[i];
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The preferences have changed. prefs is a pointer to the new
|
||||
@ -337,8 +368,6 @@ void C64::PatchKernal(bool fast_reset, bool true_drive)
|
||||
* -1: Instruction not completed
|
||||
*/
|
||||
|
||||
u8 CompressBuffer[0x20000]; //128K more than enough
|
||||
|
||||
int C64::SaveCPUState(FILE *f)
|
||||
{
|
||||
MOS6510State state;
|
||||
@ -535,6 +564,32 @@ bool C64::LoadCIAState(FILE *f)
|
||||
} else { iprintf("LoadCIAState2\n"); return false;}
|
||||
}
|
||||
|
||||
/*
|
||||
* Save Cartridge state to snapshot
|
||||
*/
|
||||
|
||||
bool C64::SaveCARTState(FILE *f)
|
||||
{
|
||||
CartridgeState state;
|
||||
TheCart->GetState(&state);
|
||||
return fwrite((void*)&state, sizeof(state), 1, f) == 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load Cartridge state from snapshot
|
||||
*/
|
||||
|
||||
bool C64::LoadCARTState(FILE *f)
|
||||
{
|
||||
CartridgeState state;
|
||||
|
||||
if (fread((void*)&state, sizeof(state), 1, f) == 1)
|
||||
{
|
||||
TheCart->SetState(&state);
|
||||
return true;
|
||||
} else { iprintf("LoadCARTState\n"); return false;}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Save 1541 GCR state to snapshot
|
||||
@ -599,6 +654,7 @@ bool C64::SaveSnapshot(char *filename)
|
||||
bool bSIDSave = SaveSIDState(f);
|
||||
bool bCIASave = SaveCIAState(f);
|
||||
bool bCPUSave = SaveCPUState(f);
|
||||
bool bCARTSave= SaveCARTState(f);
|
||||
fputc(0, f); // No delay
|
||||
|
||||
if (ThePrefs.TrueDrive)
|
||||
@ -610,7 +666,7 @@ bool C64::SaveSnapshot(char *filename)
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (bVICSave && bSIDSave && bCIASave && bCPUSave) return true;
|
||||
if (bVICSave && bSIDSave && bCIASave && bCPUSave && bCARTSave) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -653,6 +709,7 @@ bool C64::LoadSnapshot(char *filename)
|
||||
error |= !LoadSIDState(f);
|
||||
error |= !LoadCIAState(f);
|
||||
error |= !LoadCPUState(f);
|
||||
error |= !LoadCARTState(f);
|
||||
|
||||
delay = fgetc(f); // Number of cycles the 6510 is ahead of the previous chips
|
||||
(void)delay;
|
||||
@ -843,19 +900,6 @@ void kbd_buf_update(C64 *TheC64)
|
||||
}
|
||||
}
|
||||
|
||||
void load_prg(C64 *TheC64, uint8 *prg, int prg_size) {
|
||||
uint8 start_hi, start_lo;
|
||||
uint16 start;
|
||||
int i;
|
||||
|
||||
start_lo=*prg++;
|
||||
start_hi=*prg++;
|
||||
start=(start_hi<<8)+start_lo;
|
||||
|
||||
for(i=0; i<(prg_size-2); i++) {
|
||||
TheC64->RAM[start+i]=prg[i];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Vertical blank: Poll keyboard and joysticks, update window
|
||||
@ -1168,6 +1212,36 @@ uint8 C64::poll_joystick(int port)
|
||||
return j;
|
||||
}
|
||||
|
||||
void C64::InsertCart(char *filename)
|
||||
{
|
||||
Cartridge * new_cart = nullptr;
|
||||
|
||||
char errBuffer[40];
|
||||
new_cart = Cartridge::FromFile(filename, errBuffer);
|
||||
|
||||
// Swap cartridge object if successful
|
||||
if (new_cart)
|
||||
{
|
||||
delete TheCart;
|
||||
TheCart = TheCPU->TheCart = new_cart;
|
||||
}
|
||||
else
|
||||
{
|
||||
DSPrint(0, 0, 6, (char*)errBuffer);
|
||||
WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;
|
||||
WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;
|
||||
DSPrint(0, 0, 6, (char*)" ");
|
||||
}
|
||||
}
|
||||
|
||||
void C64::RemoveCart(void)
|
||||
{
|
||||
extern u8 cart_in;
|
||||
delete TheCart;
|
||||
TheCart = TheCPU->TheCart = new Cartridge();
|
||||
cart_in = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The emulation's main loop
|
||||
|
@ -35,6 +35,12 @@ const int DRIVE_ROM_SIZE = 0x4000;
|
||||
#define BAD_CYCLES_PER_LINE 23
|
||||
#define FLOPPY_CYCLES_PER_LINE 64
|
||||
|
||||
#define MEM_TYPE_RAM 0x01
|
||||
#define MEM_TYPE_KERNAL 0x02
|
||||
#define MEM_TYPE_BASIC 0x03
|
||||
#define MEM_TYPE_CART 0x04
|
||||
#define MEM_TYPE_OTHER 0x05
|
||||
|
||||
class Prefs;
|
||||
class C64Display;
|
||||
class MOS6510;
|
||||
@ -45,6 +51,7 @@ class MOS6526_2;
|
||||
class IEC;
|
||||
class MOS6502_1541;
|
||||
class Job1541;
|
||||
class Cartridge;
|
||||
class CmdPipe;
|
||||
|
||||
class C64 {
|
||||
@ -71,12 +78,17 @@ public:
|
||||
bool SaveVICState(FILE *f);
|
||||
bool SaveSIDState(FILE *f);
|
||||
bool SaveCIAState(FILE *f);
|
||||
bool SaveCARTState(FILE *f);
|
||||
bool LoadCPUState(FILE *f);
|
||||
bool Load1541State(FILE *f);
|
||||
bool Load1541JobState(FILE *f);
|
||||
bool LoadVICState(FILE *f);
|
||||
bool LoadSIDState(FILE *f);
|
||||
bool LoadCIAState(FILE *f);
|
||||
bool LoadCARTState(FILE *f);
|
||||
void InsertCart(char *filename);
|
||||
void RemoveCart(void);
|
||||
void LoadPRG(char *filename);
|
||||
|
||||
uint8 *RAM, *Basic, *Kernal,
|
||||
*Char, *Color; // C64
|
||||
@ -90,6 +102,7 @@ public:
|
||||
MOS6526_1 *TheCIA1;
|
||||
MOS6526_2 *TheCIA2;
|
||||
IEC *TheIEC;
|
||||
Cartridge *TheCart;
|
||||
|
||||
MOS6502_1541 *TheCPU1541; // 1541
|
||||
Job1541 *TheJob1541;
|
||||
@ -112,5 +125,9 @@ private:
|
||||
};
|
||||
|
||||
extern void floppy_soundfx(u8 type);
|
||||
extern uint8 cart_in;
|
||||
extern u8 cartROM[];
|
||||
|
||||
#define WAITVBL swiWaitForVBlank();swiWaitForVBlank();swiWaitForVBlank();
|
||||
|
||||
#endif
|
||||
|
@ -100,7 +100,6 @@ private:
|
||||
|
||||
void jump(uint16 adr);
|
||||
void illegal_op(uint8 op, uint16 at);
|
||||
void illegal_jump(uint16 at, uint16 to);
|
||||
|
||||
void do_adc(uint8 byte);
|
||||
void do_sbc(uint8 byte);
|
||||
|
@ -76,6 +76,7 @@
|
||||
#include "CIA.h"
|
||||
#include "IEC.h"
|
||||
#include "Display.h"
|
||||
#include "Cartridge.h"
|
||||
#include "mainmenu.h"
|
||||
|
||||
enum {
|
||||
@ -84,6 +85,9 @@ enum {
|
||||
|
||||
extern uint8 myRAM[];
|
||||
|
||||
uint8 *MemMap[0x10] __attribute__((section(".dtcm"))) ;
|
||||
|
||||
|
||||
/*
|
||||
* 6510 constructor: Initialize registers
|
||||
*/
|
||||
@ -97,8 +101,6 @@ MOS6510::MOS6510(C64 *c64, uint8 *Ram, uint8 *Basic, uint8 *Kernal, uint8 *Char,
|
||||
v_flag = d_flag = c_flag = false;
|
||||
i_flag = true;
|
||||
|
||||
kernal_rom_offset = Kernal - 0xe000; // For faster indexing during emulation...
|
||||
|
||||
interrupt.intr[INT_VICIRQ] = false;
|
||||
interrupt.intr[INT_CIAIRQ] = false;
|
||||
interrupt.intr[INT_NMI] = false;
|
||||
@ -131,6 +133,12 @@ void MOS6510::AsyncNMI(void)
|
||||
interrupt.intr[INT_NMI] = true;
|
||||
}
|
||||
|
||||
void MOS6510::setCharVsIO(void)
|
||||
{
|
||||
uint8 port = ~ram[0] | ram[1];
|
||||
char_in = (port & 3) && !(port & 4);
|
||||
io_in = (port & 3) && (port & 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* Memory configuration has probably changed
|
||||
@ -138,7 +146,8 @@ void MOS6510::AsyncNMI(void)
|
||||
|
||||
void MOS6510::new_config(void)
|
||||
{
|
||||
if ((ram[0] & 0x10) == 0) {
|
||||
if ((ram[0] & 0x10) == 0)
|
||||
{
|
||||
ram[1] |= 0x10; // Keep cassette sense line high
|
||||
}
|
||||
|
||||
@ -148,69 +157,69 @@ void MOS6510::new_config(void)
|
||||
kernal_in = port & 2;
|
||||
char_in = (port & 3) && !(port & 4);
|
||||
io_in = (port & 3) && (port & 4);
|
||||
|
||||
MemMap[0x0] = myRAM;
|
||||
MemMap[0x1] = myRAM;
|
||||
MemMap[0x2] = myRAM;
|
||||
MemMap[0x3] = myRAM;
|
||||
MemMap[0x4] = myRAM;
|
||||
MemMap[0x5] = myRAM;
|
||||
MemMap[0x6] = myRAM;
|
||||
MemMap[0x7] = myRAM;
|
||||
|
||||
MemMap[0x8] = myRAM;
|
||||
MemMap[0x9] = myRAM;
|
||||
MemMap[0xa] = basic_in ? (basic_rom - 0xa000) : myRAM;
|
||||
MemMap[0xb] = basic_in ? (basic_rom - 0xa000) : myRAM;
|
||||
MemMap[0xc] = myRAM;
|
||||
MemMap[0xd] = myRAM; // Usually will be I/O
|
||||
MemMap[0xe] = kernal_in ? (kernal_rom - 0xe000) : myRAM;
|
||||
MemMap[0xf] = kernal_in ? (kernal_rom - 0xe000) : myRAM;
|
||||
|
||||
// If a Cartridge is inserted, it may respond in some of these memory regions
|
||||
TheCart->MapThyself();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read a byte from I/O / ROM space
|
||||
*/
|
||||
|
||||
__attribute__ ((noinline)) uint8 MOS6510::read_byte_io(uint16 adr)
|
||||
{
|
||||
switch (adr >> 12) {
|
||||
case 0xa:
|
||||
case 0xb:
|
||||
if (basic_in)
|
||||
{
|
||||
return basic_rom[adr & 0x1fff];
|
||||
}
|
||||
else
|
||||
return myRAM[adr];
|
||||
case 0x8:
|
||||
case 0x9:
|
||||
case 0xc:
|
||||
return myRAM[adr];
|
||||
case 0xd:
|
||||
if (io_in)
|
||||
switch ((adr >> 8) & 0x0f) {
|
||||
case 0x0: // VIC
|
||||
case 0x1:
|
||||
case 0x2:
|
||||
case 0x3:
|
||||
return TheVIC->ReadRegister(adr & 0x3f);
|
||||
case 0x4: // SID
|
||||
case 0x5:
|
||||
case 0x6:
|
||||
case 0x7:
|
||||
return TheSID->ReadRegister(adr & 0x1f);
|
||||
case 0x8: // Color RAM
|
||||
case 0x9:
|
||||
case 0xa:
|
||||
case 0xb:
|
||||
return color_ram[adr & 0x03ff] | (rand() & 0xf0);
|
||||
case 0xc: // CIA 1
|
||||
return TheCIA1->ReadRegister(adr & 0x0f);
|
||||
case 0xd: // CIA 2
|
||||
return TheCIA2->ReadRegister(adr & 0x0f);
|
||||
case 0xe: // REU/Open I/O
|
||||
case 0xf:
|
||||
return rand();
|
||||
}
|
||||
else if (char_in)
|
||||
return char_rom[adr & 0x0fff];
|
||||
else
|
||||
return myRAM[adr];
|
||||
case 0xe:
|
||||
case 0xf:
|
||||
if (kernal_in)
|
||||
{
|
||||
return kernal_rom_offset[adr];
|
||||
}
|
||||
else
|
||||
return myRAM[adr];
|
||||
default: // Can't happen
|
||||
return 0;
|
||||
__attribute__ ((noinline)) uint8_t MOS6510::read_byte_io(uint16 adr)
|
||||
{
|
||||
if (io_in)
|
||||
{
|
||||
switch ((adr >> 8) & 0x0f)
|
||||
{
|
||||
case 0x0: // VIC
|
||||
case 0x1:
|
||||
case 0x2:
|
||||
case 0x3:
|
||||
return TheVIC->ReadRegister(adr & 0x3f);
|
||||
case 0x4: // SID
|
||||
case 0x5:
|
||||
case 0x6:
|
||||
case 0x7:
|
||||
return TheSID->ReadRegister(adr & 0x1f);
|
||||
case 0x8: // Color RAM
|
||||
case 0x9:
|
||||
case 0xa:
|
||||
case 0xb:
|
||||
return color_ram[adr & 0x03ff] | (rand() & 0xf0);
|
||||
case 0xc: // CIA 1
|
||||
return TheCIA1->ReadRegister(adr & 0x0f);
|
||||
case 0xd: // CIA 2
|
||||
return TheCIA2->ReadRegister(adr & 0x0f);
|
||||
case 0xe: // Cartridge I/O 1 (or open)
|
||||
return TheCart->ReadIO1(adr & 0xff, rand());
|
||||
case 0xf: // Cartridge I/O 2 (or open)
|
||||
return TheCart->ReadIO2(adr & 0xff, rand());
|
||||
}
|
||||
}
|
||||
else if (char_in)
|
||||
{
|
||||
return char_rom[adr & 0x0fff];
|
||||
}
|
||||
|
||||
return myRAM[adr];
|
||||
}
|
||||
|
||||
|
||||
@ -220,8 +229,8 @@ __attribute__ ((noinline)) uint8 MOS6510::read_byte_io(uint16 adr)
|
||||
|
||||
inline __attribute__((always_inline)) uint8 MOS6510::read_byte(uint16 adr)
|
||||
{
|
||||
if (adr & 0x8000) return read_byte_io(adr);
|
||||
else return myRAM[adr];
|
||||
if ((adr>>12) == 0xd) return read_byte_io(adr);
|
||||
else return MemMap[adr>>12][adr];
|
||||
}
|
||||
|
||||
/*
|
||||
@ -239,11 +248,10 @@ __attribute__ ((noinline)) uint16 MOS6510::read_word(uint16 adr)
|
||||
|
||||
__attribute__ ((noinline)) void MOS6510::write_byte_io(uint16 adr, uint8 byte)
|
||||
{
|
||||
if (adr >= 0xe000)
|
||||
if (io_in)
|
||||
{
|
||||
myRAM[adr] = byte;
|
||||
} else if (io_in)
|
||||
switch ((adr >> 8) & 0x0f) {
|
||||
switch ((adr >> 8) & 0x0f)
|
||||
{
|
||||
case 0x0: // VIC
|
||||
case 0x1:
|
||||
case 0x2:
|
||||
@ -268,11 +276,15 @@ __attribute__ ((noinline)) void MOS6510::write_byte_io(uint16 adr, uint8 byte)
|
||||
case 0xd: // CIA 2
|
||||
TheCIA2->WriteRegister(adr & 0x0f, byte);
|
||||
return;
|
||||
case 0xe: // REU/Open I/O
|
||||
case 0xf:
|
||||
case 0xe: // Cartridge I/O 1 (or open)
|
||||
TheCart->WriteIO1(adr & 0xff, byte);
|
||||
return;
|
||||
case 0xf: // Cartridge I/O 2 (or open)
|
||||
TheCart->WriteIO2(adr & 0xff, byte);
|
||||
return;
|
||||
}
|
||||
else
|
||||
}
|
||||
else // Write through even if char_in is enabled
|
||||
{
|
||||
myRAM[adr] = byte;
|
||||
}
|
||||
@ -285,11 +297,12 @@ __attribute__ ((noinline)) void MOS6510::write_byte_io(uint16 adr, uint8 byte)
|
||||
|
||||
inline void MOS6510::write_byte(uint16 adr, uint8 byte)
|
||||
{
|
||||
if (adr < 0xd000)
|
||||
if ((adr >> 12) == 0xd) write_byte_io(adr, byte);
|
||||
else
|
||||
{
|
||||
myRAM[adr] = byte;
|
||||
if (!(adr & 0xFFFE)) new_config(); // First two bytes are special...
|
||||
} else write_byte_io(adr, byte);
|
||||
if (adr < 2) new_config(); // First two bytes are special...
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -323,8 +336,7 @@ inline void MOS6510::write_zp(uint16 adr, uint8 byte)
|
||||
myRAM[adr] = byte;
|
||||
|
||||
// Check if memory configuration may have changed.
|
||||
if (adr < 2)
|
||||
new_config();
|
||||
if (adr < 2) new_config(); // First two bytes are special...
|
||||
}
|
||||
|
||||
|
||||
@ -338,7 +350,7 @@ inline void MOS6510::write_zp(uint16 adr, uint8 byte)
|
||||
* Adc instruction
|
||||
*/
|
||||
|
||||
void MOS6510::do_adc(uint8 byte)
|
||||
ITCM_CODE void MOS6510::do_adc(uint8 byte)
|
||||
{
|
||||
if (!d_flag) {
|
||||
uint16 tmp = a + (byte) + (c_flag ? 1 : 0);
|
||||
@ -419,6 +431,40 @@ void MOS6510::GetState(MOS6510State *s)
|
||||
s->nmi_state = nmi_state;
|
||||
s->dfff_byte = dfff_byte;
|
||||
s->instruction_complete = true;
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Now the tricky part... we use MemMap[] as our CPU memory mapper
|
||||
// so we can quickly index into RAM, Kernal, Basic or Cart ROM and
|
||||
// it's possible that from build-to-build that this memory moves...
|
||||
// So we must determine the memory type and save the offset so we
|
||||
// can properly restore it when loading save states.
|
||||
// ----------------------------------------------------------------
|
||||
for (u8 i=0; i<16; i++)
|
||||
{
|
||||
if ((MemMap[i] >= myRAM) && (MemMap[i] <= (myRAM+0x10000)))
|
||||
{
|
||||
s->MemMap_Type[i] = MEM_TYPE_RAM;
|
||||
s->MemMap_Offset[i] = MemMap[i] - myRAM;
|
||||
}
|
||||
else
|
||||
if ((MemMap[i] >= (kernal_rom-0xe000)) && (MemMap[i] <= (kernal_rom+0x2000)))
|
||||
{
|
||||
s->MemMap_Type[i] = MEM_TYPE_KERNAL;
|
||||
s->MemMap_Offset[i] = MemMap[i] - kernal_rom;
|
||||
}
|
||||
else
|
||||
if ((MemMap[i] >= (basic_rom-0xa000)) && (MemMap[i] <= (basic_rom+0x2000)))
|
||||
{
|
||||
s->MemMap_Type[i] = MEM_TYPE_BASIC;
|
||||
s->MemMap_Offset[i] = MemMap[i] - basic_rom;
|
||||
}
|
||||
else
|
||||
if ((MemMap[i] >= (cartROM-0xe000)) && (MemMap[i] <= (cartROM+(1024*1024))))
|
||||
{
|
||||
s->MemMap_Type[i] = MEM_TYPE_CART;
|
||||
s->MemMap_Offset[i] = MemMap[i] - cartROM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -452,6 +498,30 @@ void MOS6510::SetState(MOS6510State *s)
|
||||
interrupt.intr[INT_RESET] = s->intr[INT_RESET];
|
||||
nmi_state = s->nmi_state;
|
||||
dfff_byte = s->dfff_byte;
|
||||
|
||||
for (u8 i=0; i<16; i++)
|
||||
{
|
||||
if (s->MemMap_Type[i] == MEM_TYPE_RAM)
|
||||
{
|
||||
MemMap[i] = myRAM + s->MemMap_Offset[i];
|
||||
}
|
||||
else if (s->MemMap_Type[i] == MEM_TYPE_KERNAL)
|
||||
{
|
||||
MemMap[i] = kernal_rom + s->MemMap_Offset[i];
|
||||
}
|
||||
else if (s->MemMap_Type[i] == MEM_TYPE_BASIC)
|
||||
{
|
||||
MemMap[i] = basic_rom + s->MemMap_Offset[i];
|
||||
}
|
||||
else if (s->MemMap_Type[i] == MEM_TYPE_CART)
|
||||
{
|
||||
MemMap[i] = cartROM + s->MemMap_Offset[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
MemMap[i] = (uint8_t *)s->MemMap_Offset[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -479,7 +549,6 @@ void MOS6510::Reset(void)
|
||||
interrupt.intr[INT_NMI] = false;
|
||||
interrupt.intr[INT_RESET] = false;
|
||||
|
||||
|
||||
// Read reset vector
|
||||
jump(read_word(0xfffc));
|
||||
}
|
||||
@ -491,29 +560,15 @@ void MOS6510::Reset(void)
|
||||
|
||||
void MOS6510::illegal_op(uint8 op, uint16 at)
|
||||
{
|
||||
char illop_msg[80];
|
||||
char illop_msg[40];
|
||||
|
||||
sprintf(illop_msg, "Illegal opcode %02x at %04x.", op, at);
|
||||
sprintf(illop_msg, "Illegal opcode %02x at %04x", op, at);
|
||||
ShowRequester(illop_msg, "Reset");
|
||||
the_c64->Reset();
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Jump to illegal address space (PC_IS_POINTER only)
|
||||
*/
|
||||
|
||||
void MOS6510::illegal_jump(uint16 at, uint16 to)
|
||||
{
|
||||
char illop_msg[80];
|
||||
|
||||
sprintf(illop_msg, "Jump to I/O space at %04x to %04x.", at, to);
|
||||
ShowRequester(illop_msg, "Reset");
|
||||
the_c64->Reset();
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Stack macros
|
||||
|
@ -61,6 +61,7 @@ class MOS6581;
|
||||
class MOS6526_1;
|
||||
class MOS6526_2;
|
||||
class IEC;
|
||||
class Cartridge;
|
||||
struct MOS6510State;
|
||||
|
||||
// 6510 emulation (C64)
|
||||
@ -82,6 +83,7 @@ public:
|
||||
void ClearCIAIRQ(void);
|
||||
void TriggerNMI(void);
|
||||
void ClearNMI(void);
|
||||
void setCharVsIO(void);
|
||||
|
||||
int ExtConfig; // Memory configuration for ExtRead/WriteByte (0..7)
|
||||
|
||||
@ -90,11 +92,13 @@ public:
|
||||
MOS6526_1 *TheCIA1; // Pointer to CIA 1
|
||||
MOS6526_2 *TheCIA2; // Pointer to CIA 2
|
||||
IEC *TheIEC; // Pointer to drive array
|
||||
Cartridge *TheCart; // Pointer to cartridge object
|
||||
|
||||
private:
|
||||
void ext_opcode(void);
|
||||
uint8 read_byte(uint16 adr);
|
||||
uint8 read_byte_io(uint16 adr);
|
||||
uint8 read_byte_io_cart(uint16 adr);
|
||||
uint16 read_word(uint16 adr);
|
||||
uint16 read_word_slow(uint16 adr);
|
||||
void write_byte(uint16 adr, uint8 byte);
|
||||
@ -106,7 +110,6 @@ private:
|
||||
|
||||
void new_config(void);
|
||||
void illegal_op(uint8 op, uint16 at);
|
||||
void illegal_jump(uint16 at, uint16 to);
|
||||
|
||||
void do_adc(uint8 byte);
|
||||
void do_sbc(uint8 byte);
|
||||
@ -119,8 +122,7 @@ private:
|
||||
|
||||
uint8 *ram; // Pointer to main RAM
|
||||
uint8 *basic_rom, *kernal_rom, *char_rom, *color_ram; // Pointers to ROMs and color RAM
|
||||
uint8 *kernal_rom_offset;
|
||||
|
||||
|
||||
union { // Pending interrupts
|
||||
uint8 intr[4]; // Index: See definitions above
|
||||
unsigned long intr_any;
|
||||
@ -147,6 +149,8 @@ struct MOS6510State {
|
||||
bool nmi_state;
|
||||
uint8 dfff_byte;
|
||||
bool instruction_complete;
|
||||
uint8 MemMap_Type[0x10];
|
||||
int32 MemMap_Offset[0x10];
|
||||
};
|
||||
|
||||
|
||||
|
@ -3,12 +3,12 @@
|
||||
//
|
||||
// As GimliDS is a port of the Frodo emulator for the DS/DSi/XL/LL handhelds,
|
||||
// any copying or distribution of this emulator, its source code and associated
|
||||
// readme files, with or without modification, are permitted per the original
|
||||
// readme files, with or without modification, are permitted per the original
|
||||
// Frodo emulator license shown below. Hugest thanks to Christian Bauer for his
|
||||
// efforts to provide a clean open-source emulation base for the C64.
|
||||
//
|
||||
// Numerous hacks and 'unsafe' optimizations have been performed on the original
|
||||
// Frodo emulator codebase to get it running on the small handheld system. You
|
||||
// Numerous hacks and 'unsafe' optimizations have been performed on the original
|
||||
// Frodo emulator codebase to get it running on the small handheld system. You
|
||||
// are strongly encouraged to seek out the official Frodo sources if you're at
|
||||
// all interested in this emulator code.
|
||||
//
|
||||
@ -42,6 +42,7 @@
|
||||
#include "IEC.h"
|
||||
#include "C64.h"
|
||||
#include "Prefs.h"
|
||||
#include "Cartridge.h"
|
||||
#include "mainmenu.h"
|
||||
#include <maxmod9.h>
|
||||
#include "soundbank.h"
|
||||
@ -151,8 +152,9 @@ void C64Display::UpdateLEDs(int l0, int l1)
|
||||
#define F_7 0x7
|
||||
#define F_8 0x18
|
||||
|
||||
#define MOUNT_DISK 0xFE
|
||||
#define MAIN_MENU 0xFF
|
||||
#define INSERT_CART 0xFD
|
||||
#define MOUNT_DISK 0xFE
|
||||
#define MAIN_MENU 0xFF
|
||||
|
||||
#define LFA 0x095 //Left arrow
|
||||
#define CLR 0x147 // Home/clear
|
||||
@ -181,6 +183,7 @@ static int keystate[256];
|
||||
|
||||
extern u8 MainMenu(C64 *the_c64);
|
||||
void show_joysticks(void);
|
||||
void show_cartstatus(void);
|
||||
void show_shift_key(void);
|
||||
|
||||
char str[300];
|
||||
@ -201,12 +204,12 @@ void ShowKeyboard(void)
|
||||
dmaCopy((void*) keyboardPal,(void*) BG_PALETTE_SUB,256*2);
|
||||
unsigned short dmaVal = *(bgGetMapPtr(bg1b)+24*32);
|
||||
dmaFillWords(dmaVal | (dmaVal<<16),(void*) bgGetMapPtr(bg1b),32*24*2);
|
||||
|
||||
|
||||
show_joysticks();
|
||||
show_shift_key();
|
||||
show_cartstatus();
|
||||
}
|
||||
|
||||
void WaitForVblank();
|
||||
|
||||
/*
|
||||
C64 keyboard matrix:
|
||||
@ -319,14 +322,14 @@ int init_graphics(void)
|
||||
//D is not used..if you need a bigger background then you will need to map
|
||||
//more vram banks consecutivly (VRAM A-D are all 0x20000 bytes in size)
|
||||
vramSetPrimaryBanks(VRAM_A_MAIN_BG_0x06000000, VRAM_B_MAIN_BG_0x06020000, VRAM_C_SUB_BG , VRAM_D_LCD);
|
||||
|
||||
|
||||
vramSetBankD(VRAM_D_LCD); // Not using this for video but 128K of faster RAM always useful! Mapped at 0x06860000 - 256K Used for tape patch look-up
|
||||
vramSetBankE(VRAM_E_LCD); // Not using this for video but 64K of faster RAM always useful! Mapped at 0x06880000 - ..
|
||||
vramSetBankF(VRAM_F_LCD); // Not using this for video but 16K of faster RAM always useful! Mapped at 0x06890000 - ..
|
||||
vramSetBankG(VRAM_G_LCD); // Not using this for video but 16K of faster RAM always useful! Mapped at 0x06894000 - ..
|
||||
vramSetBankH(VRAM_H_LCD); // Not using this for video but 32K of faster RAM always useful! Mapped at 0x06898000 - ..
|
||||
vramSetBankI(VRAM_I_LCD); // Not using this for video but 16K of faster RAM always useful! Mapped at 0x068A0000 - Unused - reserved for future use
|
||||
|
||||
|
||||
|
||||
videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE | DISPLAY_BG1_ACTIVE); //sub bg 0 will be used to print text
|
||||
REG_BG0CNT_SUB = BG_MAP_BASE(31);
|
||||
@ -432,6 +435,18 @@ void show_joysticks(void)
|
||||
}
|
||||
}
|
||||
|
||||
void show_cartstatus(void)
|
||||
{
|
||||
if (cart_in)
|
||||
{
|
||||
DSPrint(21, 22, 2, (char*)"PQR");
|
||||
}
|
||||
else
|
||||
{
|
||||
DSPrint(21, 22, 2, (char*)"012");
|
||||
}
|
||||
}
|
||||
|
||||
void show_shift_key(void)
|
||||
{
|
||||
if (m_Mode == KB_SHIFT)
|
||||
@ -472,9 +487,6 @@ void C64Display::Speedometer(int speed)
|
||||
|
||||
if (bDebugDisplay)
|
||||
{
|
||||
debug[0] = getMemUsed();
|
||||
debug[1] = getMemFree();
|
||||
|
||||
sprintf(tmp, "%-8d", speed);
|
||||
DSPrint(19, 1, 6, tmp);
|
||||
|
||||
@ -484,6 +496,7 @@ void C64Display::Speedometer(int speed)
|
||||
|
||||
show_joysticks();
|
||||
show_shift_key();
|
||||
show_cartstatus();
|
||||
}
|
||||
|
||||
|
||||
@ -538,10 +551,42 @@ void C64Display::IssueKeypress(uint8 row, uint8 col, uint8 *key_matrix, uint8 *r
|
||||
lastc64key=c64_key;
|
||||
}
|
||||
|
||||
int bDelayLoadPRG = 0;
|
||||
int bDelayLoadCRT = 0;
|
||||
void C64Display::PollKeyboard(uint8 *key_matrix, uint8 *rev_matrix, uint8 *joystick)
|
||||
{
|
||||
// For PRG files, we wait about half-a-sec before loading in the program...
|
||||
if (bDelayLoadPRG)
|
||||
{
|
||||
if (--bDelayLoadPRG)
|
||||
{
|
||||
TheC64->LoadPRG(CartFilename);
|
||||
}
|
||||
}
|
||||
|
||||
// For PRG files, we wait about half-a-sec before loading in the program...
|
||||
if (bDelayLoadCRT)
|
||||
{
|
||||
if (--bDelayLoadCRT)
|
||||
{
|
||||
TheC64->InsertCart(CartFilename);
|
||||
|
||||
// Magic Desk requires TRUE DRIVE emulation
|
||||
Prefs *prefs = new Prefs(ThePrefs);
|
||||
strcpy(prefs->DrivePath[0], Drive8File);
|
||||
strcpy(prefs->DrivePath[1], Drive9File);
|
||||
myConfig.trueDrive = TheC64->TheCart->isTrueDriveRequired();
|
||||
prefs->TrueDrive = myConfig.trueDrive;
|
||||
TheC64->NewPrefs(prefs);
|
||||
ThePrefs = *prefs;
|
||||
delete prefs;
|
||||
|
||||
TheC64->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
scanKeys();
|
||||
|
||||
|
||||
if (issue_commodore_key)
|
||||
{
|
||||
issue_commodore_key = 0;
|
||||
@ -657,8 +702,9 @@ void C64Display::PollKeyboard(uint8 *key_matrix, uint8 *rev_matrix, uint8 *joyst
|
||||
else if (tilex < 42) c = F_3;
|
||||
else if (tilex < 61) c = F_5;
|
||||
else if (tilex < 80) c = F_7;
|
||||
else if (tilex < 190) c = ' ';
|
||||
else if (tilex < 222) c = MOUNT_DISK;
|
||||
else if (tilex < 164) c = ' ';
|
||||
else if (tilex < 193) c = INSERT_CART;
|
||||
else if (tilex < 223) c = MOUNT_DISK;
|
||||
else if (tilex < 256) c = MAIN_MENU;
|
||||
}
|
||||
|
||||
@ -669,6 +715,44 @@ void C64Display::PollKeyboard(uint8 *key_matrix, uint8 *rev_matrix, uint8 *joyst
|
||||
ShowKeyboard();
|
||||
TheC64->Resume();
|
||||
}
|
||||
else if (c==INSERT_CART)
|
||||
{
|
||||
TheC64->Pause();
|
||||
u8 reload = mount_cart(TheC64);
|
||||
ShowKeyboard();
|
||||
if ((reload == 1) || (reload == 2))
|
||||
{
|
||||
// Remove any disks...
|
||||
Prefs *prefs = new Prefs(ThePrefs);
|
||||
strcpy(prefs->DrivePath[0], "");
|
||||
strcpy(prefs->DrivePath[1], "");
|
||||
prefs->TrueDrive = myConfig.trueDrive;
|
||||
TheC64->NewPrefs(prefs);
|
||||
ThePrefs = *prefs;
|
||||
delete prefs;
|
||||
|
||||
if (reload == 1) // load cart THEN reset
|
||||
{
|
||||
TheC64->PatchKernal(ThePrefs.FastReset, ThePrefs.TrueDrive);
|
||||
bDelayLoadCRT = 3; // 3 frames and load the CRT file
|
||||
}
|
||||
else // reload is 2 - PRG file reset FIRST
|
||||
{
|
||||
TheC64->PatchKernal(ThePrefs.FastReset, ThePrefs.TrueDrive);
|
||||
TheC64->Reset();
|
||||
bDelayLoadPRG = 10; // 10 frames and load the PRG file
|
||||
}
|
||||
cart_in = 1;
|
||||
}
|
||||
else if (reload == 3)
|
||||
{
|
||||
TheC64->RemoveCart();
|
||||
TheC64->PatchKernal(ThePrefs.FastReset, ThePrefs.TrueDrive);
|
||||
TheC64->Reset();
|
||||
cart_in = 0;
|
||||
}
|
||||
TheC64->Resume();
|
||||
}
|
||||
else if (c==MOUNT_DISK)
|
||||
{
|
||||
TheC64->Pause();
|
||||
@ -691,6 +775,7 @@ void C64Display::PollKeyboard(uint8 *key_matrix, uint8 *rev_matrix, uint8 *joyst
|
||||
// See if we should issue a system-wide RESET
|
||||
if (reload == 2)
|
||||
{
|
||||
TheC64->RemoveCart();
|
||||
TheC64->PatchKernal(ThePrefs.FastReset, ThePrefs.TrueDrive);
|
||||
TheC64->Reset();
|
||||
}
|
||||
@ -797,7 +882,8 @@ void C64Display::PollKeyboard(uint8 *key_matrix, uint8 *rev_matrix, uint8 *joyst
|
||||
case '-': c64_key = MATRIX(5,3); break;
|
||||
|
||||
case CTL: c64_key = MATRIX(7,2); break;
|
||||
case RST: c64_key = MATRIX(7,7); break;
|
||||
case RST: c64_key = MATRIX(7,7); TheC64->NMI(); break;
|
||||
|
||||
case CLR: c64_key = MATRIX(6,3); break;
|
||||
case LFA: c64_key = MATRIX(7,1); break;
|
||||
case UPA: c64_key = MATRIX(6,6); break;
|
||||
@ -834,7 +920,7 @@ void C64Display::PollKeyboard(uint8 *key_matrix, uint8 *rev_matrix, uint8 *joyst
|
||||
/*
|
||||
* Allocate C64 colors
|
||||
*/
|
||||
|
||||
|
||||
typedef struct {
|
||||
int r;
|
||||
int g;
|
||||
|
@ -855,7 +855,7 @@ inline void MOS6569::vblank(void)
|
||||
frame_skipped = (total_frames & 1); // Skip every other...
|
||||
if (frame_skipped)
|
||||
{
|
||||
if ((total_frames % 3) == 0) frame_skipped = 0; // But every so often toss in an odd frame
|
||||
if ((total_frames % 5) == 0) frame_skipped = 0; // But every so often toss in an odd frame
|
||||
}
|
||||
}
|
||||
|
||||
@ -1012,7 +1012,7 @@ void MOS6569::el_ecm_text(uint8 *p, uint8 *q, uint8 *r)
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((noinline)) ITCM_CODE void MOS6569::el_std_idle(uint8 *p, uint8 *r)
|
||||
void MOS6569::el_std_idle(uint8 *p, uint8 *r)
|
||||
{
|
||||
uint8 data = *get_physical(ctrl1 & 0x40 ? 0x39ff : 0x3fff);
|
||||
uint32 *lp = (uint32 *)p;
|
||||
|
@ -36,16 +36,18 @@
|
||||
|
||||
char Drive8File[MAX_FILENAME_LEN];
|
||||
char Drive9File[MAX_FILENAME_LEN];
|
||||
char CartFilename[MAX_FILENAME_LEN];
|
||||
|
||||
extern int bg0b, bg1b;
|
||||
int countZX=0;
|
||||
int ucGameAct=0;
|
||||
int ucGameChoice = -1;
|
||||
int diskCount=0;
|
||||
int diskGameAct=0;
|
||||
int diskGameChoice = -1;
|
||||
FIC64 gpFic[MAX_FILES];
|
||||
char szName[256];
|
||||
char szFile[256];
|
||||
u32 file_size = 0;
|
||||
char strBuf[40];
|
||||
u8 bLastFileTypeLoaded = 0;
|
||||
|
||||
#define WAITVBL swiWaitForVBlank();swiWaitForVBlank();swiWaitForVBlank();
|
||||
|
||||
@ -61,12 +63,12 @@ void dsDisplayFiles(u16 NoDebGame, u8 ucSel)
|
||||
u8 maxLen;
|
||||
|
||||
DSPrint(31,5,0,(NoDebGame>0 ? (char*)"<" : (char*)" "));
|
||||
DSPrint(31,22,0,(NoDebGame+14<countZX ? (char*)">" : (char*)" "));
|
||||
DSPrint(31,22,0,(NoDebGame+14<diskCount ? (char*)">" : (char*)" "));
|
||||
|
||||
for (ucBcl=0;ucBcl<18; ucBcl++)
|
||||
{
|
||||
ucGame= ucBcl+NoDebGame;
|
||||
if (ucGame < countZX)
|
||||
if (ucGame < diskCount)
|
||||
{
|
||||
maxLen=(int)strlen(gpFic[ucGame].szName);
|
||||
strcpy(szName,gpFic[ucGame].szName);
|
||||
@ -115,14 +117,14 @@ int Filescmp (const void *c1, const void *c2)
|
||||
/*********************************************************************************
|
||||
* Find files (TAP/TZX/Z80/SNA) available - sort them for display.
|
||||
********************************************************************************/
|
||||
void gimliDSFindFiles(u8 bTapeOnly)
|
||||
void gimliDSFindFiles(u8 bCartOnly)
|
||||
{
|
||||
u32 uNbFile;
|
||||
DIR *dir;
|
||||
struct dirent *pent;
|
||||
|
||||
uNbFile=0;
|
||||
countZX=0;
|
||||
diskCount=0;
|
||||
|
||||
dir = opendir(".");
|
||||
while (((pent=readdir(dir))!=NULL) && (uNbFile<MAX_FILES))
|
||||
@ -139,18 +141,40 @@ void gimliDSFindFiles(u8 bTapeOnly)
|
||||
strcpy(gpFic[uNbFile].szName,szFile);
|
||||
gpFic[uNbFile].uType = DIRECTORY;
|
||||
uNbFile++;
|
||||
countZX++;
|
||||
diskCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((strlen(szFile)>4) && (strlen(szFile)<(MAX_FILENAME_LEN-4)) && (szFile[0] != '.') && (szFile[0] != '_')) // For MAC don't allow files starting with an underscore
|
||||
{
|
||||
if ( (strcasecmp(strrchr(szFile, '.'), ".D64") == 0) ) {
|
||||
strcpy(gpFic[uNbFile].szName,szFile);
|
||||
gpFic[uNbFile].uType = NORMALFILE;
|
||||
uNbFile++;
|
||||
countZX++;
|
||||
if (bCartOnly)
|
||||
{
|
||||
if ( (strcasecmp(strrchr(szFile, '.'), ".CRT") == 0) )
|
||||
{
|
||||
strcpy(gpFic[uNbFile].szName,szFile);
|
||||
gpFic[uNbFile].uType = NORMALFILE;
|
||||
uNbFile++;
|
||||
diskCount++;
|
||||
}
|
||||
|
||||
if ( (strcasecmp(strrchr(szFile, '.'), ".PRG") == 0) )
|
||||
{
|
||||
strcpy(gpFic[uNbFile].szName,szFile);
|
||||
gpFic[uNbFile].uType = NORMALFILE;
|
||||
uNbFile++;
|
||||
diskCount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (strcasecmp(strrchr(szFile, '.'), ".D64") == 0) )
|
||||
{
|
||||
strcpy(gpFic[uNbFile].szName,szFile);
|
||||
gpFic[uNbFile].uType = NORMALFILE;
|
||||
uNbFile++;
|
||||
diskCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -160,44 +184,50 @@ void gimliDSFindFiles(u8 bTapeOnly)
|
||||
// ----------------------------------------------
|
||||
// If we found any files, go sort the list...
|
||||
// ----------------------------------------------
|
||||
if (countZX)
|
||||
if (diskCount)
|
||||
{
|
||||
qsort (gpFic, countZX, sizeof(FIC64), Filescmp);
|
||||
qsort (gpFic, diskCount, sizeof(FIC64), Filescmp);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Let the user select a new game (rom) file and load it up!
|
||||
// ----------------------------------------------------------------
|
||||
u8 gimliDSLoadFile(u8 bTapeOnly)
|
||||
u8 gimliDSLoadFile(u8 bCartOnly)
|
||||
{
|
||||
bool bDone=false;
|
||||
u16 ucHaut=0x00, ucBas=0x00,ucSHaut=0x00, ucSBas=0x00, romSelected= 0, firstRomDisplay=0,nbRomPerPage, uNbRSPage;
|
||||
s16 uLenFic=0, ucFlip=0, ucFlop=0;
|
||||
u8 retVal = 0;
|
||||
|
||||
if (bLastFileTypeLoaded != bCartOnly)
|
||||
{
|
||||
diskCount=0;
|
||||
diskGameAct=0;
|
||||
}
|
||||
|
||||
// Show the menu...
|
||||
while ((keysCurrent() & (KEY_TOUCH | KEY_START | KEY_SELECT | KEY_A | KEY_B))!=0);
|
||||
|
||||
gimliDSFindFiles(bTapeOnly);
|
||||
gimliDSFindFiles(bCartOnly);
|
||||
|
||||
ucGameChoice = -1;
|
||||
diskGameChoice = -1;
|
||||
|
||||
nbRomPerPage = (countZX>=18 ? 18 : countZX);
|
||||
uNbRSPage = (countZX>=5 ? 5 : countZX);
|
||||
nbRomPerPage = (diskCount>=18 ? 18 : diskCount);
|
||||
uNbRSPage = (diskCount>=5 ? 5 : diskCount);
|
||||
|
||||
if (ucGameAct>countZX-nbRomPerPage)
|
||||
if (diskGameAct>diskCount-nbRomPerPage)
|
||||
{
|
||||
firstRomDisplay=countZX-nbRomPerPage;
|
||||
romSelected=ucGameAct-countZX+nbRomPerPage;
|
||||
firstRomDisplay=diskCount-nbRomPerPage;
|
||||
romSelected=diskGameAct-diskCount+nbRomPerPage;
|
||||
}
|
||||
else
|
||||
{
|
||||
firstRomDisplay=ucGameAct;
|
||||
firstRomDisplay=diskGameAct;
|
||||
romSelected=0;
|
||||
}
|
||||
|
||||
if (romSelected >= countZX) romSelected = 0; // Just start at the top
|
||||
if (romSelected >= diskCount) romSelected = 0; // Just start at the top
|
||||
|
||||
dsDisplayFiles(firstRomDisplay,romSelected);
|
||||
|
||||
@ -210,14 +240,14 @@ u8 gimliDSLoadFile(u8 bTapeOnly)
|
||||
{
|
||||
if (!ucHaut)
|
||||
{
|
||||
ucGameAct = (ucGameAct>0 ? ucGameAct-1 : countZX-1);
|
||||
diskGameAct = (diskGameAct>0 ? diskGameAct-1 : diskCount-1);
|
||||
if (romSelected>uNbRSPage) { romSelected -= 1; }
|
||||
else {
|
||||
if (firstRomDisplay>0) { firstRomDisplay -= 1; }
|
||||
else {
|
||||
if (romSelected>0) { romSelected -= 1; }
|
||||
else {
|
||||
firstRomDisplay=countZX-nbRomPerPage;
|
||||
firstRomDisplay=diskCount-nbRomPerPage;
|
||||
romSelected=nbRomPerPage-1;
|
||||
}
|
||||
}
|
||||
@ -239,10 +269,10 @@ u8 gimliDSLoadFile(u8 bTapeOnly)
|
||||
if (keysCurrent() & KEY_DOWN)
|
||||
{
|
||||
if (!ucBas) {
|
||||
ucGameAct = (ucGameAct< countZX-1 ? ucGameAct+1 : 0);
|
||||
diskGameAct = (diskGameAct< diskCount-1 ? diskGameAct+1 : 0);
|
||||
if (romSelected<uNbRSPage-1) { romSelected += 1; }
|
||||
else {
|
||||
if (firstRomDisplay<countZX-nbRomPerPage) { firstRomDisplay += 1; }
|
||||
if (firstRomDisplay<diskCount-nbRomPerPage) { firstRomDisplay += 1; }
|
||||
else {
|
||||
if (romSelected<nbRomPerPage-1) { romSelected += 1; }
|
||||
else {
|
||||
@ -272,10 +302,10 @@ u8 gimliDSLoadFile(u8 bTapeOnly)
|
||||
{
|
||||
if (!ucSBas)
|
||||
{
|
||||
ucGameAct = (ucGameAct< countZX-nbRomPerPage ? ucGameAct+nbRomPerPage : countZX-nbRomPerPage);
|
||||
if (firstRomDisplay<countZX-nbRomPerPage) { firstRomDisplay += nbRomPerPage; }
|
||||
else { firstRomDisplay = countZX-nbRomPerPage; }
|
||||
if (ucGameAct == countZX-nbRomPerPage) romSelected = 0;
|
||||
diskGameAct = (diskGameAct< diskCount-nbRomPerPage ? diskGameAct+nbRomPerPage : diskCount-nbRomPerPage);
|
||||
if (firstRomDisplay<diskCount-nbRomPerPage) { firstRomDisplay += nbRomPerPage; }
|
||||
else { firstRomDisplay = diskCount-nbRomPerPage; }
|
||||
if (diskGameAct == diskCount-nbRomPerPage) romSelected = 0;
|
||||
ucSBas=0x01;
|
||||
dsDisplayFiles(firstRomDisplay,romSelected);
|
||||
}
|
||||
@ -297,11 +327,11 @@ u8 gimliDSLoadFile(u8 bTapeOnly)
|
||||
{
|
||||
if (!ucSHaut)
|
||||
{
|
||||
ucGameAct = (ucGameAct> nbRomPerPage ? ucGameAct-nbRomPerPage : 0);
|
||||
diskGameAct = (diskGameAct> nbRomPerPage ? diskGameAct-nbRomPerPage : 0);
|
||||
if (firstRomDisplay>nbRomPerPage) { firstRomDisplay -= nbRomPerPage; }
|
||||
else { firstRomDisplay = 0; }
|
||||
if (ucGameAct == 0) romSelected = 0;
|
||||
if (romSelected > ucGameAct) romSelected = ucGameAct;
|
||||
if (diskGameAct == 0) romSelected = 0;
|
||||
if (romSelected > diskGameAct) romSelected = diskGameAct;
|
||||
ucSHaut=0x01;
|
||||
dsDisplayFiles(firstRomDisplay,romSelected);
|
||||
}
|
||||
@ -331,27 +361,27 @@ u8 gimliDSLoadFile(u8 bTapeOnly)
|
||||
// -------------------------------------------------------------------
|
||||
if (keysCurrent() & KEY_A || keysCurrent() & KEY_Y || keysCurrent() & KEY_X)
|
||||
{
|
||||
if (gpFic[ucGameAct].uType != DIRECTORY)
|
||||
if (gpFic[diskGameAct].uType != DIRECTORY)
|
||||
{
|
||||
bDone=true;
|
||||
if (keysCurrent() & KEY_X) retVal = 2; else retVal = 1;
|
||||
if (keysCurrent() & KEY_Y) bDebugDisplay = 1; else bDebugDisplay = 0;
|
||||
ucGameChoice = ucGameAct;
|
||||
diskGameChoice = diskGameAct;
|
||||
WAITVBL;
|
||||
}
|
||||
else
|
||||
{
|
||||
chdir(gpFic[ucGameAct].szName);
|
||||
gimliDSFindFiles(bTapeOnly);
|
||||
ucGameAct = 0;
|
||||
nbRomPerPage = (countZX>=14 ? 14 : countZX);
|
||||
uNbRSPage = (countZX>=5 ? 5 : countZX);
|
||||
if (ucGameAct>countZX-nbRomPerPage) {
|
||||
firstRomDisplay=countZX-nbRomPerPage;
|
||||
romSelected=ucGameAct-countZX+nbRomPerPage;
|
||||
chdir(gpFic[diskGameAct].szName);
|
||||
gimliDSFindFiles(bCartOnly);
|
||||
diskGameAct = 0;
|
||||
nbRomPerPage = (diskCount>=14 ? 14 : diskCount);
|
||||
uNbRSPage = (diskCount>=5 ? 5 : diskCount);
|
||||
if (diskGameAct>diskCount-nbRomPerPage) {
|
||||
firstRomDisplay=diskCount-nbRomPerPage;
|
||||
romSelected=diskGameAct-diskCount+nbRomPerPage;
|
||||
}
|
||||
else {
|
||||
firstRomDisplay=ucGameAct;
|
||||
firstRomDisplay=diskGameAct;
|
||||
romSelected=0;
|
||||
}
|
||||
dsDisplayFiles(firstRomDisplay,romSelected);
|
||||
@ -362,14 +392,14 @@ u8 gimliDSLoadFile(u8 bTapeOnly)
|
||||
// --------------------------------------------
|
||||
// If the filename is too long... scroll it.
|
||||
// --------------------------------------------
|
||||
if ((int)strlen(gpFic[ucGameAct].szName) > 30)
|
||||
if ((int)strlen(gpFic[diskGameAct].szName) > 30)
|
||||
{
|
||||
ucFlip++;
|
||||
if (ucFlip >= 25)
|
||||
{
|
||||
ucFlip = 0;
|
||||
uLenFic++;
|
||||
if ((uLenFic+30)>(int)strlen(gpFic[ucGameAct].szName))
|
||||
if ((uLenFic+30)>(int)strlen(gpFic[diskGameAct].szName))
|
||||
{
|
||||
ucFlop++;
|
||||
if (ucFlop >= 15)
|
||||
@ -380,7 +410,7 @@ u8 gimliDSLoadFile(u8 bTapeOnly)
|
||||
else
|
||||
uLenFic--;
|
||||
}
|
||||
strncpy(szName,gpFic[ucGameAct].szName+uLenFic,30);
|
||||
strncpy(szName,gpFic[diskGameAct].szName+uLenFic,30);
|
||||
szName[30] = '\0';
|
||||
DSPrint(1,5+romSelected,2,szName);
|
||||
}
|
||||
@ -398,11 +428,17 @@ u16 nds_key;
|
||||
|
||||
void LoadGameConfig(void)
|
||||
{
|
||||
if (strlen(Drive8File) > 1)
|
||||
// Cart overrides disk...
|
||||
if (strlen(CartFilename) > 1)
|
||||
{
|
||||
file_crc = getCRC32((u8*)CartFilename, strlen(CartFilename));
|
||||
FindConfig();
|
||||
}
|
||||
else if (strlen(Drive8File) > 1)
|
||||
{
|
||||
file_crc = getCRC32((u8*)Drive8File, strlen(Drive8File));
|
||||
FindConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BottomScreenDiskette(void)
|
||||
@ -475,6 +511,10 @@ void DisplayFileNameDiskette(void)
|
||||
#define MENU_ACTION_REBOOT_C64 4 // Force C64 Reboot
|
||||
#define MENU_ACTION_TRUE_DRIVE 5 // Toggle True Drive
|
||||
#define MENU_ACTION_CONFIG 6 // Configure Game
|
||||
|
||||
#define MENU_ACTION_INSERT_CART 10
|
||||
#define MENU_ACTION_REMOVE_CART 11
|
||||
|
||||
#define MENU_ACTION_SKIP 99 // Skip this MENU choice
|
||||
|
||||
typedef struct
|
||||
@ -505,6 +545,17 @@ DiskMenu_t disk_menu =
|
||||
},
|
||||
};
|
||||
|
||||
DiskMenu_t cart_menu =
|
||||
{
|
||||
(char *)" ", 10,
|
||||
{
|
||||
{(char *)" INSERT CARTRIDGE ", MENU_ACTION_INSERT_CART},
|
||||
{(char *)" REMOVE CARTRIDGE ", MENU_ACTION_REMOVE_CART},
|
||||
{(char *)" EXIT MENU ", MENU_ACTION_EXIT},
|
||||
{(char *)" NULL ", MENU_ACTION_END},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
static DiskMenu_t *menu = &disk_menu;
|
||||
|
||||
@ -601,10 +652,10 @@ u8 DisketteMenu(C64 *the_c64)
|
||||
case MENU_ACTION_DRIVE8:
|
||||
BottomScreenMainMenu();
|
||||
retVal = gimliDSLoadFile(0);
|
||||
if (ucGameChoice >= 0)
|
||||
if (diskGameChoice >= 0)
|
||||
{
|
||||
retVal = 1;
|
||||
strcpy(Drive8File, gpFic[ucGameChoice].szName);
|
||||
strcpy(Drive8File, gpFic[diskGameChoice].szName);
|
||||
LoadGameConfig();
|
||||
}
|
||||
DiskMenuShow(true, menuSelection);
|
||||
@ -613,10 +664,10 @@ u8 DisketteMenu(C64 *the_c64)
|
||||
case MENU_ACTION_DRIVE9:
|
||||
BottomScreenMainMenu();
|
||||
retVal = gimliDSLoadFile(0);
|
||||
if (ucGameChoice >= 0)
|
||||
if (diskGameChoice >= 0)
|
||||
{
|
||||
retVal = 1;
|
||||
strcpy(Drive9File, gpFic[ucGameChoice].szName);
|
||||
strcpy(Drive9File, gpFic[diskGameChoice].szName);
|
||||
}
|
||||
DiskMenuShow(true, menuSelection);
|
||||
break;
|
||||
@ -685,5 +736,140 @@ u8 mount_disk(C64 *the_c64)
|
||||
|
||||
u8 retVal = DisketteMenu(the_c64);
|
||||
|
||||
if (retVal) bLastFileTypeLoaded = 0;
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------
|
||||
// Show the Disk Menu text - highlight the selected row.
|
||||
// -------------------------------------------------------
|
||||
void CartMenuShow(bool bClearScreen, u8 sel)
|
||||
{
|
||||
diskette_menu_items = 0;
|
||||
|
||||
if (bClearScreen)
|
||||
{
|
||||
// -------------------------------------
|
||||
// Put up the Diskette menu background
|
||||
// -------------------------------------
|
||||
BottomScreenDiskette();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
// Pick the right context menu based on the machine
|
||||
// ---------------------------------------------------
|
||||
menu = &cart_menu;
|
||||
|
||||
// Display the menu title
|
||||
DSPrint(15-(strlen(menu->title)/2), menu->start_row, 6, menu->title);
|
||||
|
||||
// And display all of the menu items
|
||||
while (menu->menulist[diskette_menu_items].menu_action != MENU_ACTION_END)
|
||||
{
|
||||
DSPrint(16-(strlen(menu->menulist[diskette_menu_items].menu_string)/2), menu->start_row+2+diskette_menu_items, (diskette_menu_items == sel) ? 7:6, menu->menulist[diskette_menu_items].menu_string);
|
||||
diskette_menu_items++;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// And near the bottom, display the file/rom/disk that is currently loaded into memory.
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
DisplayFileNameDiskette();
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Handle Disk mini-menu interface... Allows rewind, swap tape, etc.
|
||||
// ------------------------------------------------------------------------
|
||||
u8 CartMenu(C64 *the_c64)
|
||||
{
|
||||
u8 menuSelection = 0;
|
||||
u8 retVal = 0;
|
||||
|
||||
while ((keysCurrent() & (KEY_TOUCH | KEY_LEFT | KEY_RIGHT | KEY_A ))!=0);
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
//Show the cassette menu background - we'll draw text on top of this
|
||||
// ------------------------------------------------------------------
|
||||
CartMenuShow(true, menuSelection);
|
||||
|
||||
u8 bExitMenu = false;
|
||||
while (true)
|
||||
{
|
||||
nds_key = keysCurrent();
|
||||
if (nds_key)
|
||||
{
|
||||
if (nds_key & KEY_UP)
|
||||
{
|
||||
menuSelection = (menuSelection > 0) ? (menuSelection-1):(diskette_menu_items-1);
|
||||
while (menu->menulist[menuSelection].menu_action == MENU_ACTION_SKIP)
|
||||
{
|
||||
menuSelection = (menuSelection > 0) ? (menuSelection-1):(diskette_menu_items-1);
|
||||
}
|
||||
CartMenuShow(false, menuSelection);
|
||||
}
|
||||
if (nds_key & KEY_DOWN)
|
||||
{
|
||||
menuSelection = (menuSelection+1) % diskette_menu_items;
|
||||
while (menu->menulist[menuSelection].menu_action == MENU_ACTION_SKIP)
|
||||
{
|
||||
menuSelection = (menuSelection+1) % diskette_menu_items;
|
||||
}
|
||||
CartMenuShow(false, menuSelection);
|
||||
}
|
||||
|
||||
if (nds_key & KEY_B) // Treat this as selecting 'exit'
|
||||
{
|
||||
bExitMenu = true;
|
||||
}
|
||||
else
|
||||
if (nds_key & KEY_A) // User has picked a menu item... let's see what it is!
|
||||
{
|
||||
switch(menu->menulist[menuSelection].menu_action)
|
||||
{
|
||||
case MENU_ACTION_EXIT:
|
||||
bExitMenu = true;
|
||||
break;
|
||||
|
||||
case MENU_ACTION_INSERT_CART:
|
||||
BottomScreenMainMenu();
|
||||
retVal = gimliDSLoadFile(1);
|
||||
if (diskGameChoice >= 0)
|
||||
{
|
||||
retVal = 1;
|
||||
strcpy(CartFilename, gpFic[diskGameChoice].szName);
|
||||
if ( (strcasecmp(strrchr(CartFilename, '.'), ".PRG") == 0) ) retVal = 2;
|
||||
LoadGameConfig();
|
||||
}
|
||||
bExitMenu = true;
|
||||
break;
|
||||
|
||||
case MENU_ACTION_REMOVE_CART:
|
||||
BottomScreenMainMenu();
|
||||
retVal = 3;
|
||||
strcpy(CartFilename, "");
|
||||
bExitMenu = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bExitMenu) break;
|
||||
while ((keysCurrent() & (KEY_UP | KEY_DOWN | KEY_A ))!=0);
|
||||
WAITVBL;WAITVBL;WAITVBL;
|
||||
}
|
||||
}
|
||||
|
||||
while ((keysCurrent() & (KEY_UP | KEY_DOWN | KEY_A ))!=0);
|
||||
WAITVBL;WAITVBL;WAITVBL;
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
u8 mount_cart(C64 *the_c64)
|
||||
{
|
||||
u8 retVal = CartMenu(the_c64);
|
||||
|
||||
if (retVal) bLastFileTypeLoaded = 1;
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
@ -14,8 +14,10 @@ typedef struct {
|
||||
|
||||
extern char Drive8File[MAX_FILENAME_LEN];
|
||||
extern char Drive9File[MAX_FILENAME_LEN];
|
||||
extern char CartFilename[MAX_FILENAME_LEN];
|
||||
|
||||
extern FIC64 gpFic[MAX_FILES];
|
||||
extern int ucGameChoice;
|
||||
|
||||
extern u8 mount_disk(C64 *the_c64);
|
||||
extern u8 mount_cart(C64 *the_c64);
|
||||
|
@ -34,8 +34,6 @@
|
||||
|
||||
extern C64 *TheC64;
|
||||
extern int bg0b, bg1b;
|
||||
|
||||
#define WAITVBL swiWaitForVBlank();swiWaitForVBlank();swiWaitForVBlank();
|
||||
static u16 nds_key;
|
||||
extern void BottomScreenMainMenu(void);
|
||||
|
||||
@ -181,6 +179,7 @@ u8 MainMenu(C64 *the_c64)
|
||||
break;
|
||||
|
||||
case MENU_ACTION_RESET_EMU:
|
||||
the_c64->RemoveCart();
|
||||
the_c64->PatchKernal(ThePrefs.FastReset, ThePrefs.TrueDrive);
|
||||
the_c64->Reset();
|
||||
bExitMenu = true;
|
||||
@ -214,8 +213,17 @@ u8 MainMenu(C64 *the_c64)
|
||||
case MENU_ACTION_SAVE_STATE:
|
||||
{
|
||||
check_and_make_sav_directory();
|
||||
sprintf(theDrivePath,"sav/%s", ThePrefs.DrivePath[0]);
|
||||
int len = strlen(theDrivePath);
|
||||
int len = 0;
|
||||
if (strlen(CartFilename) > 1) // Cart overrides disk
|
||||
{
|
||||
sprintf(theDrivePath,"sav/%s", CartFilename);
|
||||
len = strlen(CartFilename);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(theDrivePath,"sav/%s", ThePrefs.DrivePath[0]);
|
||||
len = strlen(theDrivePath);
|
||||
}
|
||||
if (len > 4)
|
||||
{
|
||||
char *p=&theDrivePath[len-4];
|
||||
@ -240,8 +248,17 @@ u8 MainMenu(C64 *the_c64)
|
||||
case MENU_ACTION_LOAD_STATE:
|
||||
{
|
||||
check_and_make_sav_directory();
|
||||
sprintf(theDrivePath,"sav/%s", ThePrefs.DrivePath[0]);
|
||||
int len = strlen(theDrivePath);
|
||||
int len = 0;
|
||||
if (strlen(CartFilename) > 1) // Cart overrides disk
|
||||
{
|
||||
sprintf(theDrivePath,"sav/%s", CartFilename);
|
||||
len = strlen(CartFilename);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(theDrivePath,"sav/%s", ThePrefs.DrivePath[0]);
|
||||
len = strlen(theDrivePath);
|
||||
}
|
||||
if (len > 4)
|
||||
{
|
||||
char *p=&theDrivePath[len-4];
|
||||
|
Loading…
Reference in New Issue
Block a user