Version 0.9b with CART support. See readme file.

This commit is contained in:
Dave Bernazzani 2025-05-05 07:50:02 -04:00
parent a417d7910d
commit d20408a9b2
15 changed files with 648 additions and 202 deletions

Binary file not shown.

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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];
};

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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];