Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Source/Teensy/MinimalBoot/Common/IOHandlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ struct stcIOHandlers
#ifndef MinimumBuild
#include "IO_Handlers/IOH_MIDI.c"
#include "IO_Handlers/IOH_Debug.c"
#include "IO_Handlers/RAMBanks.c"
#include "IO_Handlers/IOH_GeoRAM.c"
#ifdef Fab04_REU
#include "IO_Handlers/IOH_REU.c"
#endif
Expand Down Expand Up @@ -158,6 +160,7 @@ stcIOHandlers* IOHandler[] = //Synch order/qty with enum enumIOHandlers
&IOHndlr_KernalReplace, //IOH_KernalReplace,
#endif
&IOHndlr_Debug, //IOH_Debug,
&IOHndlr_GeoRAM, //IOH_GeoRAM,

//*not* manually selectable, see LastSelectableIOH

Expand Down
103 changes: 103 additions & 0 deletions Source/Teensy/MinimalBoot/Common/IO_Handlers/IOH_GeoRAM.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// SPDX-License-Identifier: MIT

// Berkeley Softworks geoRAM: a 256-byte window at $DE00 onto the page selected by two
// write-only registers, $DFFE (page 0-63 within a 16K block) and $DFFF (16K block).
// No DMA, so it runs on every TR, in C64 and C128 mode.
// ref: VICE src/c64/cart/georam.c

void IO1Hndlr_GeoRAM(uint8_t Address, bool R_Wn);
void IO2Hndlr_GeoRAM(uint8_t Address, bool R_Wn);
void InitHndlr_GeoRAM();
extern void (*fSpecialBtnChange)(bool Up_nDn);

stcIOHandlers IOHndlr_GeoRAM =
{
"GeoRAM", //Name of handler
&InitHndlr_GeoRAM, //Called once at handler startup
&IO1Hndlr_GeoRAM, //IO1 R/W handler
&IO2Hndlr_GeoRAM, //IO2 R/W handler
NULL, //ROML Read handler, in addition to any ROM data sent
NULL, //ROMH Read handler, in addition to any ROM data sent
NULL, //Polled in main routine
NULL, //called at the end of EVERY c64 cycle
};

#define GeoRAM_Filename "SD:/georam.ram"
#define MAX_GEORAM_BANKS 64 // 512K, the original geoRAM
#define MIN_GEORAM_BANKS 16 // 128K
#define GeoRAM_PagesPerBlock 64
#define GeoRAM_BanksPerBlock (16384 / RAM_Bank_Size)

// VICE decodes the registers across $DF80-$DFFF (A0 picks which); $DF00-$DF7F is left free.
#define GeoRAM_RegsBase 0x80
#define GeoRAM_RegBlockBit 0x01

// volatile: the IO ISRs read the page only while there are banks, so the two stores
// must reach memory in the order written
static volatile uint8_t NumGeoRAM_Banks = 0;
static uint8_t *GeoRAM_Bank[MAX_GEORAM_BANKS];
static uint8_t GeoRAM_Block, GeoRAM_PageNum;
static uint8_t * volatile GeoRAM_Page;

static void GeoRAM_SelectPage()
{
if (NumGeoRAM_Banks == 0) return;
// the unused high register bits wrap, as on real hardware
uint32_t Offset = ((GeoRAM_Block & (NumGeoRAM_Banks / GeoRAM_BanksPerBlock - 1)) * GeoRAM_PagesPerBlock
+ (GeoRAM_PageNum & (GeoRAM_PagesPerBlock - 1))) * 256;
GeoRAM_Page = GeoRAM_Bank[Offset / RAM_Bank_Size] + (Offset % RAM_Bank_Size);
}

FLASHMEM void FreeGeoRAM()
{
// the handler is still installed and the C64 may be running: the IO ISRs must stop
// touching the banks before the first one is freed
uint8_t NumBanks = NumGeoRAM_Banks;
NumGeoRAM_Banks = 0;
FreeRAMBanks(GeoRAM_Bank, &NumBanks);
}

FLASHMEM void SpecialBtn_GeoRAM(bool Up_nDn)
{
// on button release save GeoRAM contents
if(Up_nDn) SaveRAMBanksReplacing(GeoRAM_Bank, NumGeoRAM_Banks, GeoRAM_Filename);
}

FLASHMEM void InitHndlr_GeoRAM()
{
FreeGeoRAM();
GeoRAM_Block = GeoRAM_PageNum = 0;
uint8_t NumBanks = AllocRAMBanks(GeoRAM_Bank, MAX_GEORAM_BANKS, MIN_GEORAM_BANKS);
if (NumBanks == 0)
{
Serial.printf("GeoRAM is disabled\n");
return;
}
GeoRAM_Page = GeoRAM_Bank[0];
NumGeoRAM_Banks = NumBanks;
fSpecialBtnChange = &SpecialBtn_GeoRAM;
Serial.printf("GeoRAM Size: %dK bytes\n", NumBanks * RAM_Bank_Size / 1024);
LoadRAMBanks(GeoRAM_Bank, NumBanks, GeoRAM_Filename);
}

void IO1Hndlr_GeoRAM(uint8_t Address, bool R_Wn)
{
if (NumGeoRAM_Banks == 0) return; // disabled: $DE00 stays open bus, so software sees no geoRAM
if (R_Wn) DataPortWriteWaitLog(GeoRAM_Page[Address]);
else
{
uint8_t Data = DataPortWaitRead();
GeoRAM_Page[Address] = Data;
TraceLogAddValidData(Data);
}
}

void IO2Hndlr_GeoRAM(uint8_t Address, bool R_Wn)
{
if (R_Wn || Address < GeoRAM_RegsBase) return; // write-only registers
uint8_t Data = DataPortWaitRead();
if (Address & GeoRAM_RegBlockBit) GeoRAM_Block = Data;
else GeoRAM_PageNum = Data;
GeoRAM_SelectPage();
TraceLogAddValidData(Data);
}
182 changes: 11 additions & 171 deletions Source/Teensy/MinimalBoot/Common/IO_Handlers/IOH_REU.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@

#ifdef USE_RAM12

#define REU_RAM_Bank_Size 0x2000
#define REU_Size (NumREU_Banks * REU_RAM_Bank_Size) //Dynamically allocated based on NumREU_Banks, each bank is 8k (0x2000)
#define REU_Size (NumREU_Banks * RAM_Bank_Size) //Dynamically allocated based on NumREU_Banks, each bank is 8k (0x2000)
#define REU_RAM_READ(a,d) d=REU_Bank[a>>13][a&0x1fff]
#define REU_RAM_WRITE(a,d) REU_Bank[a>>13][a&0x1fff]=d
#define MIN_REU_BANKS 16 // 128K, smallest real REU (1700)
Expand Down Expand Up @@ -76,11 +75,6 @@ stcIOHandlers IOHndlr_REU =
extern bool PerformDMA(DMA_Trans_RnW RnW, uint16_t StartAddr, uint8_t *Buffer, uint32_t Length, DMA_Addr_Mode FixC64Addr);
extern bool CloseDMA();
extern void (*fSpecialBtnChange)(bool Up_nDn); //Pointer to function called when Special Button Changes
extern void EEPreadStr(uint16_t addr, char* buf);
extern RegMenuTypes RegMenuTypeFromFileName(char** ptrptrFileName);
extern bool SDFullInit();
extern bool USBFileSystemWait();
extern FS *FSfromSourceID(RegMenuTypes SourceID);

//ref: https://codebase64.net/doku.php?id=base:reu_registers
//tests:
Expand Down Expand Up @@ -145,17 +139,11 @@ extern bool DMA_RnW, DMA_FixC64Addr;
extern uint32_t DMA_Length, DMA_Count, DMA_StartAddr;
extern bool DMAByte(uint8_t *Data);

extern void FreeDriveDirMenu();
extern uint8_t RAM_Image[];
// CrtChips.h declares the main image's static table and count.
extern StructMenuItem *DriveDirMenu;
extern uint8_t *ptrRAM_ImageEnd; // points to end of CRT-used RAM1 buffer

void FreeREU()
{ //free banks allocated in RAM2 and reset NumREUBanks
for(uint16_t cnt=0; cnt < NumREU_Banks; cnt++)
if((uint32_t)REU_Bank[cnt] >= 0x20200000) free(REU_Bank[cnt]);
NumREU_Banks = 0;
{
FreeRAMBanks(REU_Bank, &NumREU_Banks);
}

void DMAByte_BASkip(uint8_t *Data1)
Expand Down Expand Up @@ -455,83 +443,12 @@ FLASHMEM void ReadWriteREU(bool RnW, uint32_t REUAddr, uint8_t *REUBuf, uint16_t

FLASHMEM void Save_REU()
{
if (NumREU_Banks == 0) return; // nothing to save: probably due to failure to allocate 128K

//Create filename based on current. reu000.reu becomes reu001.reu, etc
#ifndef USE_RAM12
#error Save_REU saves RAM1/2 banks only
#endif
char Filename[MaxPathLength];
EEPreadStr(eepAdREUFilename, Filename);
char *ptrFileName = Filename; //pointer to move past SD/USB/TR:
RegMenuTypes MenuSourceID = RegMenuTypeFromFileName(&ptrFileName);

if (MenuSourceID == rmtSD) SDFullInit(); // SD.begin(BUILTIN_SDCARD); with retry if presence detected
if (MenuSourceID == rmtUSBDrive) USBFileSystemWait(); //wait up to 1.5 sec in case USB drive just changed or powered up
//rmtTeensy not allowed, no reu files in Teensy Mem

FS *sourceFS = FSfromSourceID(MenuSourceID);

char Extension[20];
char *pDot = strrchr(ptrFileName, '.'); //find last dot
if (pDot == NULL) pDot = ptrFileName + strlen(ptrFileName); //if no extension, set to end of filename
strcpy(Extension, pDot); //copy extension
*pDot = 0; //terminate at dot/extension

bool IsNum = true; //are last 3digits of filename all numbers?
if (strlen(ptrFileName)>=3)
{
for(char *charloc=pDot-3; charloc<pDot; charloc++)
{
if (*charloc<'0' || *charloc>'9') IsNum = false;
//Serial.printf("%08x: %c %02x\n", (uint32_t)charloc, *charloc, *charloc);
}
}
else IsNum = false;


uint16_t NewNum = 0;
if (IsNum)
{ //find current number and then terminate it
NewNum = atoi(pDot-3);
*(pDot-3) = 0; //terminate number
}

//now see if the file exists, or itterate until it doesn't
char NewFilename[MaxPathLength];

do sprintf(NewFilename, "%s%03d%s", ptrFileName, NewNum++, Extension);
while (sourceFS->exists(NewFilename));

Serial.printf("Saving REU: %s\n", NewFilename);
File SaveFile = sourceFS->open(NewFilename, FILE_WRITE);
if (!SaveFile)
{
Serial.println("Unable to open!");
return;
}

//uint32_t StartmS = millis();
uint8_t NextByte;

for (uint32_t CharNum=0; CharNum<REU_Size; CharNum++)
{
REU_RAM_READ(CharNum, NextByte);
SaveFile.write(NextByte);
}
//Serial.printf("Saved %lu KBytes in %lumS\n", REU_Size/1024, millis()-StartmS);
Serial.printf("Saved %dKBytes\n", REU_Size/1024);
SaveFile.close();

//Flash LED to ack save
uint32_t LastmS = millis();
bool LEDState = true;

for (uint32_t FlashCount=0; FlashCount<20; FlashCount++)
{
while(millis()-LastmS < 75);
LastmS = millis();
if ((LEDState = !LEDState)) SetLEDOn;
else SetLEDOff;
}

SaveRAMBanks(REU_Bank, NumREU_Banks, Filename);
}

// This only applies to REU-Only mode.
Expand Down Expand Up @@ -559,59 +476,10 @@ FLASHMEM void InitHndlr_REU()
#endif

#ifdef USE_RAM12
//Allocate full REU size in Ram 1 and 2
//FreeCrtChips(); //re-using CrtChips for this, free mem allocated in RAM2 and reset NumCrtChips
FreeDriveDirMenu(); //free/clear prev loaded directory to make space. Doing it regardless to preserve continuity
//Serial.printf("RAM2#x- %d\n", RAM2blocks());

if (NumCrtChips == 0) ptrRAM_ImageEnd = RAM_Image; //If no CRT loaded, RAM1 is entirely free for REU
uint8_t *pRAM_Image = ptrRAM_ImageEnd; //start at end of any CRT-used RAM1

//Serial.printf("%dk REU, (%d banks x %d bytes)\n", REU_Size/1024, REU_Size/REU_RAM_Bank_Size, REU_RAM_Bank_Size);

//First use RAM_Image from RAM1:
while (((uint32_t)pRAM_Image - (uint32_t)RAM_Image + REU_RAM_Bank_Size <= RAM_ImageSize)
&& (NumREU_Banks < MAX_REU_BANKS))
{
//CrtChips[NumCrtChips].ChipROM = pRAM_Image;
REU_Bank[NumREU_Banks] = pRAM_Image;
pRAM_Image += REU_RAM_Bank_Size;
NumREU_Banks++;
}
Printf_dbg_reu("Used %lu/%lu Bytes of RAM1 Image\n", (uint32_t)NumREU_Banks * REU_RAM_Bank_Size, RAM_ImageSize);

//allocate the rest from RAM2
while((NumREU_Banks < MAX_REU_BANKS && // while NumREU_Banks < 64 (512k/8k)
(NULL != (REU_Bank[NumREU_Banks] = (uint8_t*)malloc(REU_RAM_Bank_Size))))) // and allocation of 8k succeeds
{
NumREU_Banks++; // if allocation a success, increment NumREU_Banks
}

// NumREU_Banks = number of banks allocated, one higher than the last index of REU_Bank[] that was allocated

Printf_dbg_reu("After parsing RAM2, %luK bytes allocated\n", (uint32_t)NumREU_Banks * REU_RAM_Bank_Size / 1024);

//resize REU to a power of 2 if needed and free unused banks
if (NumREU_Banks & (NumREU_Banks-1)) //not a power of 2
{
uint8_t unused_bank;
// largest power less than or equal to NumREU_Banks
uint8_t NewNumREU_Banks = 1 << (7 - (__builtin_clz(NumREU_Banks) - 24));
Serial.printf("Resizing REU from %d banks to %d banks\n", NumREU_Banks, NewNumREU_Banks);

for (unused_bank = NewNumREU_Banks; unused_bank < NumREU_Banks; unused_bank++)
if((uint32_t)REU_Bank[unused_bank] >= 0x20200000)
free(REU_Bank[unused_bank]);
NumREU_Banks = NewNumREU_Banks;
}

Printf_dbg_reu("After resizing to power of 2, %luK bytes allocated\n", (uint32_t)NumREU_Banks * REU_RAM_Bank_Size / 1024);

if (NumREU_Banks < MIN_REU_BANKS) // If REU is not 128k or larger
NumREU_Banks = AllocRAMBanks(REU_Bank, MAX_REU_BANKS, MIN_REU_BANKS);
if (NumREU_Banks == 0)
{
Serial.printf("Unable to allocate minimum REU size of 128K\n"
"REU is disabled\n");
FreeREU();
Serial.printf("REU is disabled\n");
return;
}

Expand All @@ -622,37 +490,9 @@ uint8_t *pRAM_Image = ptrRAM_ImageEnd; //start at end of any CRT-used RAM1
fSpecialBtnChange = &SpecialBtn_REU; //REU RAM is ready; enable button now so a failed/missing preload below doesn't skip it
Serial.printf("REU Size: %luK bytes\n", (uint32_t)REU_Size / 1024);

//pre-load REU into RAM here:
char Filename[MaxPathLength];
EEPreadStr(eepAdREUFilename, Filename);
char *ptrFileName = Filename; //pointer to move past SD/USB/TR:
Serial.printf("Loading REU: %s\n", Filename);
RegMenuTypes MenuSourceID = RegMenuTypeFromFileName(&ptrFileName);

if (MenuSourceID == rmtSD) SDFullInit(); // SD.begin(BUILTIN_SDCARD); with retry if presence detected
if (MenuSourceID == rmtUSBDrive) USBFileSystemWait(); //wait up to 1.5 sec in case USB drive just changed or powered up
//rmtTeensy not allowed, no reu files in Teensy Mem

FS *sourceFS = FSfromSourceID(MenuSourceID);
File LoadFile = sourceFS->open(ptrFileName, FILE_READ);
if (!LoadFile)
{
Serial.println("Not found!");
return;
}

if (LoadFile.size() > REU_Size)
Serial.printf("Too Large! Loading first %luK\n", (uint32_t)REU_Size/1024);

//uint32_t StartmS = millis();
uint32_t CharNum = 0;
for (uint8_t Bank = 0; Bank < NumREU_Banks && LoadFile.available(); Bank++)
CharNum += LoadFile.read(REU_Bank[Bank], REU_RAM_Bank_Size);
//Serial.printf("Read %lu Bytes in %lumS\n", CharNum, millis()-StartmS);
Serial.printf("Read %lu Bytes into REU\n", CharNum);
LoadFile.close();
//delay(250);

LoadRAMBanks(REU_Bank, NumREU_Banks, Filename);

#elif defined(USE_PSRAM)
//higher clock speed and shorter CS setup/hold do help, but still not enough for NUVIEs w/ sound
Expand Down
Loading
Loading