Version 1.1b with some tweaks to the VIC for color lookup efficiency. Improvements to the Slide-n-Glide to make it more responsive. Minor cleanups.

This commit is contained in:
Dave Bernazzani 2025-05-13 07:20:21 -04:00
parent 5f31e1b4cd
commit 9c44689c80
10 changed files with 66 additions and 174 deletions

Binary file not shown.

View File

@ -9,7 +9,7 @@ include $(DEVKITARM)/ds_rules
export TARGET := GimliDS
export TOPDIR := $(CURDIR)
export VERSION := 1.1a
export VERSION := 1.1b
ICON := -b $(CURDIR)/C64_icon.bmp "GimliDS $(VERSION);wavemotion-dave;https://github.com/wavemotion-dave/GimliDS"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -58,11 +58,12 @@ uint8 myRAM[C64_RAM_SIZE];
uint8 myKERNAL[KERNAL_ROM_SIZE];
uint8 myBASIC[BASIC_ROM_SIZE];
uint8 myRAM1541[DRIVE_RAM_SIZE] __attribute__((section(".dtcm")));
uint8 myCOLOR[0x400] __attribute__((section(".dtcm")));
uint8 bTurboWarp __attribute__((section(".dtcm"))) = 0;
uint8 cart_in __attribute__((section(".dtcm"))) = 0;
MOS6510 myCPU __attribute__((section(".dtcm"))); // Put the entire CPU object into fast memory...
MOS6510 myCPU __attribute__((section(".dtcm"))); // Put the entire CPU object into fast memory...
C64 *gTheC64 = nullptr;
@ -77,7 +78,7 @@ C64::C64()
{
quit_thyself = false;
have_a_break = false;
gTheC64 = this;
// System-dependent things
@ -91,7 +92,7 @@ C64::C64()
Basic = myBASIC;
Kernal = myKERNAL;
Char = new uint8[CHAR_ROM_SIZE];
Color = new uint8[COLOR_RAM_SIZE];
Color = myCOLOR;
RAM1541 = myRAM1541;
ROM1541 = new uint8[DRIVE_ROM_SIZE];
@ -123,7 +124,7 @@ void C64::InitMemory(void)
{
// Clear all of memory...
memset(RAM, 0x00, sizeof(myRAM));
// Then Initialize RAM with powerup pattern
// Sampled from a PAL C64 (Assy 250425) with Fujitsu MB8264A-15 DRAM chips
uint8_t *p = RAM;
@ -184,7 +185,6 @@ C64::~C64()
delete TheREU;
delete[] Char;
delete[] Color;
delete[] ROM1541;
c64_dtor();
@ -208,7 +208,7 @@ void C64::Reset(void)
TheVIC->Reset();
TheCart->Reset();
if (myConfig.reuType) TheREU->Reset();
bTurboWarp = 0;
}
@ -223,16 +223,16 @@ void C64::NMI(void)
}
/*
* Load PRG file directly into memory
* Inject PRG file directly into memory
*/
void C64::LoadPRG(char *filename)
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;
@ -242,7 +242,7 @@ void C64::LoadPRG(char *filename)
start_hi=*prg++;
start=(start_hi<<8)+start_lo;
for(i=0; i<(prg_size-2); i++)
for(i=0; i<(prg_size-2); i++)
{
myRAM[start+i]=prg[i];
}
@ -262,23 +262,23 @@ void C64::NewPrefs(Prefs *prefs)
TheDisplay->NewPrefs(prefs);
// Changed order of calls. If 1541 mode hasn't changed the order is insignificant.
if (prefs->TrueDrive)
if (prefs->TrueDrive)
{
// New prefs have 1541 enabled ==> if old prefs had disabled free drives FIRST
TheIEC->NewPrefs(prefs);
TheJob1541->NewPrefs(prefs);
}
else
else
{
// New prefs has 1541 disabled ==> if old prefs had enabled free job FIRST
TheJob1541->NewPrefs(prefs);
TheIEC->NewPrefs(prefs);
}
TheSID->NewPrefs(prefs);
// Reset 1541 processor if turned on or off (to bring IEC lines back to sane state)
if (ThePrefs.TrueDrive != prefs->TrueDrive)
if (ThePrefs.TrueDrive != prefs->TrueDrive)
{
TheCPU1541->AsyncReset();
}
@ -613,7 +613,7 @@ bool C64::SaveREUState(FILE *f)
{
REUState state;
TheREU->GetState(&state);
// ---------------------------------------------------------
// Compress the REU RAM data using 'high' compression ratio...
// ---------------------------------------------------------
@ -624,7 +624,7 @@ bool C64::SaveREUState(FILE *f)
i += fwrite(&comp_len, sizeof(comp_len), 1, f);
i += fwrite(&CompressBuffer, comp_len, 1, f);
i += fwrite((void*)&state, sizeof(state), 1, f);
return (i == 3) ? true:false;
}
else
@ -989,9 +989,9 @@ ITCM_CODE void C64::VBlank(bool draw_frame)
TheCIA1->Joystick1 = poll_joystick(0);
TheCIA1->Joystick2 = poll_joystick(1);
TheCIA1->CountTOD();
TheCIA2->CountTOD();
TheCIA2->CountTOD();
frames++;
while (GetTicks() < (((unsigned int)TICKS_PER_SEC/(unsigned int)50) * (unsigned int)frames))
@ -1059,29 +1059,29 @@ uint8 C64::poll_joystick(int port)
u8 joy_right = 0;
u8 joy_fire = 0;
u8 mappable_key_press[8] = {0,0,0,0,0,0,0,0};
if (keys & (KEY_UP | KEY_DOWN | KEY_LEFT | KEY_RIGHT | KEY_A | KEY_B | KEY_X | KEY_Y))
{
if (myConfig.joyMode == JOYMODE_SLIDE_N_GLIDE)
{
if (keys & KEY_UP)
{
slide_n_glide_key_up = 12;
slide_n_glide_key_up = 20;
slide_n_glide_key_down = 0;
}
if (keys & KEY_DOWN)
{
slide_n_glide_key_down = 12;
slide_n_glide_key_down = 20;
slide_n_glide_key_up = 0;
}
if (keys & KEY_LEFT)
{
slide_n_glide_key_left = 12;
slide_n_glide_key_left = 20;
slide_n_glide_key_right = 0;
}
if (keys & KEY_RIGHT)
{
slide_n_glide_key_right = 12;
slide_n_glide_key_right = 20;
slide_n_glide_key_left = 0;
}
@ -1109,7 +1109,7 @@ uint8 C64::poll_joystick(int port)
keys |= KEY_RIGHT;
}
}
if (keys & KEY_UP) mappable_key_press[0] = 1;
if (keys & KEY_DOWN) mappable_key_press[1] = 1;
if (keys & KEY_LEFT) mappable_key_press[2] = 1;
@ -1190,7 +1190,7 @@ uint8 C64::poll_joystick(int port)
WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;
}
break;
// Handle all other keypresses... mark the key as pressed for the PollKeyboard() routine
default:
TheDisplay->IssueKeypress(key_row_map[myConfig.key_map[i]-8], key_col_map[myConfig.key_map[i]-8], TheCIA1->KeyMatrix, TheCIA1->RevMatrix);
@ -1276,8 +1276,8 @@ uint8 C64::poll_joystick(int port)
if (!dampen) // Handle joystick
{
// Handle the joystick input... never dampen this!
if(port != myConfig.joyPort) return j;
// Make sure this is the configured joystick...
if (port != myConfig.joyPort) return j;
if( joy_up ) j&=0xfe; // Up
if( joy_down ) j&=0xfd; // Down

View File

@ -86,6 +86,7 @@ enum
};
extern uint8 myRAM[];
extern uint8 myCOLOR[];
uint8 *MemMap[0x10] __attribute__((section(".dtcm"))) ;
@ -215,7 +216,7 @@ __attribute__ ((noinline)) uint8_t MOS6510::read_byte_io(uint16 adr)
case 0x9:
case 0xa:
case 0xb:
return color_ram[adr & 0x03ff] | (rand() & 0xf0);
return myCOLOR[adr & 0x03ff] | (rand() & 0xf0);
case 0xc: // CIA 1
return TheCIA1->ReadRegister(adr & 0x0f);
case 0xd: // CIA 2
@ -299,7 +300,7 @@ __attribute__ ((noinline)) void MOS6510::write_byte_io(uint16 adr, uint8 byte)
case 0x9:
case 0xa:
case 0xb:
color_ram[adr & 0x03ff] = byte & 0x0f;
myCOLOR[adr & 0x03ff] = byte & 0x0f;
return;
case 0xc: // CIA 1
TheCIA1->WriteRegister(adr & 0x0f, byte);
@ -703,6 +704,12 @@ __attribute__((noinline)) void MOS6510::IntNMI(void)
jump(adr);
}
// Called whenever a vblank occurs - resync the borrowed cycles so every frame starts fresh
void MOS6510::VBlank(void)
{
borrowed_cycles = 0;
}
/*
* Emulate cycles_left worth of 6510 instructions
* Returns number of cycles of last instruction

View File

@ -72,6 +72,7 @@ public:
void Reset(void);
void AsyncReset(void); // Reset the CPU asynchronously
void AsyncNMI(void); // Raise NMI asynchronously (NMI pulse)
void VBlank(void);
void GetState(MOS6510State *s);
void SetState(MOS6510State *s);

View File

@ -130,12 +130,12 @@
#ifndef IS_CPU_1541 // If main C64 CPU we handle borrowed cycles
// Main opcode fetch/execute loop
if (cycles_left) cycles_left -= borrowed_cycles;
if (cycles_left != 1) cycles_left -= borrowed_cycles;
while (true)
{
if (page_plus_cyc) {last_cycles++; page_plus_cyc=0;}
if ((cycles_left -= last_cycles) < 0)
if ((cycles_left -= last_cycles) <= 0)
{
borrowed_cycles = -cycles_left;
break;
@ -147,12 +147,12 @@
if (page_plus_cyc) {last_cycles++; page_plus_cyc=0;}
cycle_counter += last_cycles; // In case we have any initial interrupt cycles
while ((cycles_left -= last_cycles) >= 0)
while ((cycles_left -= last_cycles) > 0)
{
// If we are 1541CPU, we want to alternate running instructions with the main CPU ...
while (cpu_cycles > cycles_left)
{
cpu_cycles -= localCPU->EmulateLine(0);
cpu_cycles -= localCPU->EmulateLine(1);
}
#endif
@ -1390,7 +1390,7 @@
illegal_op(read_byte(pc-1), pc-1);
break;
// Extension opcode - mostly for Kernal / 1541 hooks
// Extension opcode - for Kernal / 1541 hooks
case 0xf2: extended_opcode(); break;
}
@ -1402,6 +1402,6 @@
// See if there are any straggler cycles left for the CPU
while (cpu_cycles > 0)
{
cpu_cycles -= the_c64->TheCPU->EmulateLine(0);
cpu_cycles -= the_c64->TheCPU->EmulateLine(1);
}
#endif

View File

@ -452,11 +452,11 @@ void MOS6569::GetState(MOS6569State *vd)
vd->last_vic_byte = 0;
vd->ud_border_on = border_on;
vd->total_frames = total_frames;
vd->spare1 = 0;
vd->spare2 = 0;
vd->spare3 = 0;
vd->spare4 = 0;
vd->spare4 = 0;
}
@ -861,11 +861,12 @@ 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 % 3) == 0) frame_skipped = 0; // But every so often toss in an odd frame to smooth out the display
}
}
the_c64->VBlank(!frame_skipped);
the_c64->TheCPU->VBlank();
}
@ -1026,12 +1027,12 @@ __attribute__ ((noinline)) ITCM_CODE void MOS6569::el_std_idle(uint8 *p, uint8
uint32 conv1 = TextColorTable[0][b0c][data&0xf].b;
uint32 data32 = (data << 24) | (data << 16) | (data << 8) | data;
for (int i=0; i<40; i++)
for (int i=0; i<40; i++)
{
*lp++ = conv0;
*lp++ = conv1;
}
u32 *r32 = (uint32 *)r;
*r32++ = data32; *r32++ = data32; *r32++ = data32; *r32++ = data32; *r32++ = data32;
*r32++ = data32; *r32++ = data32; *r32++ = data32; *r32++ = data32; *r32 = data32;
@ -1051,7 +1052,7 @@ void MOS6569::el_mc_idle(uint8 *p, uint8 *r)
uint16 conv0 = (lookup[(data >> 6) & 3] << 16) | lookup[(data >> 4) & 3];
uint16 conv1 = (lookup[(data >> 2) & 3] << 16) | lookup[(data >> 0) & 3];
for (int i=0; i<40; i++)
for (int i=0; i<40; i++)
{
*++lp = conv0;
*++lp = conv1;
@ -1081,7 +1082,7 @@ __attribute__ ((noinline)) ITCM_CODE void MOS6569::el_sprites(uint8 *chunky_ptr
// Fetch sprite data and mask
uint8_t *sdatap = get_physical(matrix_base[0x3f8 + snum] << 6 | (mc[snum]*3));
uint32_t sdata = (*sdatap << 24) | (*(sdatap+1) << 16) | (*(sdatap+2) << 8);
if (!sdata) continue; // No data... no draw... no collision...
uint8_t color = spr_color[snum];
@ -1407,16 +1408,14 @@ int MOS6569::EmulateLine(void)
unsigned int raster = raster_y+1;
// End of screen reached?
if (raster != TOTAL_RASTERS)
if (raster == TOTAL_RASTERS)
{
raster_y = raster;
}
else // Yes, enter vblank - new frame coming up
{
vblank();
raster = 0;
vblank(); // Yes, enter vblank - new frame coming up
raster = 0; // Start back at line 0
}
raster_y = raster;
// Trigger raster IRQ if IRQ line reached
if (raster == irq_raster)
raster_irq();
@ -1428,7 +1427,7 @@ int MOS6569::EmulateLine(void)
// Skip frame? Only calculate Bad Lines then
if (frame_skipped)
{
if (raster >= FIRST_DMA_LINE && raster <= LAST_DMA_LINE && ((raster & 7) == y_scroll) && bad_lines_enabled)
if (raster >= FIRST_DMA_LINE && raster <= LAST_DMA_LINE && ((raster & 7) == y_scroll) && bad_lines_enabled)
{
is_bad_line = true;
cycles_left = BAD_CYCLES_PER_LINE + CycleDeltas[myConfig.cpuCycles] + CycleDeltas[myConfig.badCycles];
@ -1460,7 +1459,7 @@ int MOS6569::EmulateLine(void)
uint8 *cp = color_line;
uint8 *mbp = matrix_base + vc;
uint8 *crp = color_ram + vc;
// If we're on a 32-bit boundary, copy faster...
if ((((u32)mbp & 3) == 0) && (((u32)crp & 3) == 0))
{
@ -1589,12 +1588,12 @@ int MOS6569::EmulateLine(void)
case 0: // Standard text
case 1: // Multicolor text
case 4: // ECM text
if (x_scroll & 3)
if (x_scroll & 3)
{
el_std_idle(text_chunky_buf, r);
// Experimentally, this is slightly faster than memcpy()
u32 *dest=(u32*)p; u32 *src=(u32*)text_chunky_buf; for (int i=0; i<80; i++) *dest++ = *src++;
}
}
else
{
el_std_idle(p, r);
@ -1602,7 +1601,7 @@ int MOS6569::EmulateLine(void)
break;
case 3: // Multicolor bitmap
if (x_scroll & 3)
if (x_scroll & 3)
{
el_mc_idle(text_chunky_buf, r);
// Experimentally, this is slightly faster than memcpy()
@ -1690,7 +1689,7 @@ int MOS6569::EmulateLine(void)
}
// Increment row counter, go to idle state on overflow
if (rc == 7)
if (rc == 7)
{
display_state = false;
vc_base = vc;

View File

@ -41,17 +41,6 @@
extern const unsigned FIRST_DISP_LINE;
// Define this if you want global variables instead of member variables
#if defined(__i386) || defined(mc68000) || defined(__MC68K__)
#define GLOBAL_VARS
#endif
// Define this if you have a processor that can do unaligned accesses quickly
#if defined(__i386) || defined(mc68000) || defined(__MC68K__)
#define CAN_ACCESS_UNALIGNED
#endif
// Total number of raster lines (PAL)
const unsigned TOTAL_RASTERS = 0x138;
@ -93,78 +82,6 @@ private:
int el_update_mc(int raster);
void init_text_color_table(uint8 *colors);
void make_mc_table(void);
#ifndef GLOBAL_VARS
uint16 mx[8]; // VIC registers
uint8 my[8];
uint8 mx8;
uint8 ctrl1, ctrl2;
uint8 lpx, lpy;
uint8 me, mxe, mye, mdp, mmc;
uint8 vbase;
uint8 irq_flag, irq_mask;
uint8 clx_spr, clx_bgr;
uint8 ec, b0c, b1c, b2c, b3c, mm0, mm1;
uint8 sc[8];
uint8 *ram, *char_rom, *color_ram; // Pointers to RAM and ROM
C64 *the_c64; // Pointer to C64
C64Display *the_display; // Pointer to C64Display
MOS6510 *the_cpu; // Pointer to 6510
uint8 colors[256]; // Indices of the 16 C64 colors (16 times mirrored to avoid "& 0x0f")
uint8 ec_color, b0c_color, b1c_color,
b2c_color, b3c_color; // Indices for exterior/background colors
uint8 mm0_color, mm1_color; // Indices for MOB multicolors
uint8 spr_color[8]; // Indices for MOB colors
uint32 ec_color_long; // ec_color expanded to 32 bits
uint8 matrix_line[40]; // Buffer for video line, read in Bad Lines
uint8 color_line[40]; // Buffer for color line, read in Bad Lines
uint8 *chunky_line_start; // Pointer to start of current line in bitmap buffer
int xmod; // Number of bytes per row
uint16 raster_y; // Current raster line
uint16 irq_raster; // Interrupt raster line
uint16 dy_start; // Comparison values for border logic
uint16 dy_stop;
uint16 rc; // Row counter
uint16 vc; // Video counter
uint16 vc_base; // Video counter base
uint16 x_scroll; // X scroll value
uint16 y_scroll; // Y scroll value
uint16 cia_vabase; // CIA VA14/15 video base
uint16 mc[8]; // Sprite data counters
int display_idx; // Index of current display mode
long pad0; // Keep buffers long-aligned
uint8 spr_coll_buf[DISPLAY_X]; // Buffer for sprite-sprite collisions and priorities
uint8 fore_mask_buf[DISPLAY_X/8]; // Foreground mask for sprite-graphics collisions and priorities
#ifndef CAN_ACCESS_UNALIGNED
uint8 text_chunky_buf[40*8]; // Line graphics buffer
#endif
bool display_state; // true: Display state, false: Idle state
bool border_on; // Flag: Upper/lower border on (Frodo SC: Main border flipflop)
bool frame_skipped; // Flag: Frame is being skipped
uint8 bad_lines_enabled; // Flag: Bad Lines enabled for this frame
bool lp_triggered; // Flag: Lightpen was triggered in this frame
uint16 mc_color_lookup[4];
bool border_40_col; // Flag: 40 column border
uint8 sprite_on; // 8 flags: Sprite display/DMA active
uint8 *matrix_base; // Video matrix base
uint8 *char_base; // Character generator base
uint8 *bitmap_base; // Bitmap base
#endif
};

View File

@ -1,33 +1 @@
/*
* debug.h - Debugging utilities
*
* Frodo Copyright (C) Christian Bauer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef DEBUG_H
#define DEBUG_H
#include <stdio.h>
#define bug printf
#if DEBUG
#define D(x) (x);
#else
#define D(x) ;
#endif
#endif // ndef DEBUG_H
// Obsoleted