Skip to content

Commit f155946

Browse files
Merge pull request #61 from kfox/georam
GeoRAM IO handler for GEOS 64, sharing the REU's RAM bank code
2 parents 29b3462 + 4210842 commit f155946

7 files changed

Lines changed: 360 additions & 174 deletions

File tree

‎Source/Teensy/MinimalBoot/Common/IOHandlers.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ struct stcIOHandlers
109109
#ifndef MinimumBuild
110110
#include "IO_Handlers/IOH_MIDI.c"
111111
#include "IO_Handlers/IOH_Debug.c"
112+
#include "IO_Handlers/RAMBanks.c"
113+
#include "IO_Handlers/IOH_GeoRAM.c"
112114
#ifdef Fab04_REU
113115
#include "IO_Handlers/IOH_REU.c"
114116
#endif
@@ -158,6 +160,7 @@ stcIOHandlers* IOHandler[] = //Synch order/qty with enum enumIOHandlers
158160
&IOHndlr_KernalReplace, //IOH_KernalReplace,
159161
#endif
160162
&IOHndlr_Debug, //IOH_Debug,
163+
&IOHndlr_GeoRAM, //IOH_GeoRAM,
161164

162165
//*not* manually selectable, see LastSelectableIOH
163166

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
// Berkeley Softworks geoRAM: a 256-byte window at $DE00 onto the page selected by two
4+
// write-only registers, $DFFE (page 0-63 within a 16K block) and $DFFF (16K block).
5+
// No DMA, so it runs on every TR, in C64 and C128 mode.
6+
// ref: VICE src/c64/cart/georam.c
7+
8+
void IO1Hndlr_GeoRAM(uint8_t Address, bool R_Wn);
9+
void IO2Hndlr_GeoRAM(uint8_t Address, bool R_Wn);
10+
void InitHndlr_GeoRAM();
11+
extern void (*fSpecialBtnChange)(bool Up_nDn);
12+
13+
stcIOHandlers IOHndlr_GeoRAM =
14+
{
15+
"GeoRAM", //Name of handler
16+
&InitHndlr_GeoRAM, //Called once at handler startup
17+
&IO1Hndlr_GeoRAM, //IO1 R/W handler
18+
&IO2Hndlr_GeoRAM, //IO2 R/W handler
19+
NULL, //ROML Read handler, in addition to any ROM data sent
20+
NULL, //ROMH Read handler, in addition to any ROM data sent
21+
NULL, //Polled in main routine
22+
NULL, //called at the end of EVERY c64 cycle
23+
};
24+
25+
#define GeoRAM_Filename "SD:/georam.ram"
26+
#define MAX_GEORAM_BANKS 64 // 512K, the original geoRAM
27+
#define MIN_GEORAM_BANKS 16 // 128K
28+
#define GeoRAM_PagesPerBlock 64
29+
#define GeoRAM_BanksPerBlock (16384 / RAM_Bank_Size)
30+
31+
// VICE decodes the registers across $DF80-$DFFF (A0 picks which); $DF00-$DF7F is left free.
32+
#define GeoRAM_RegsBase 0x80
33+
#define GeoRAM_RegBlockBit 0x01
34+
35+
// volatile: the IO ISRs read the page only while there are banks, so the two stores
36+
// must reach memory in the order written
37+
static volatile uint8_t NumGeoRAM_Banks = 0;
38+
static uint8_t *GeoRAM_Bank[MAX_GEORAM_BANKS];
39+
static uint8_t GeoRAM_Block, GeoRAM_PageNum;
40+
static uint8_t * volatile GeoRAM_Page;
41+
42+
static void GeoRAM_SelectPage()
43+
{
44+
if (NumGeoRAM_Banks == 0) return;
45+
// the unused high register bits wrap, as on real hardware
46+
uint32_t Offset = ((GeoRAM_Block & (NumGeoRAM_Banks / GeoRAM_BanksPerBlock - 1)) * GeoRAM_PagesPerBlock
47+
+ (GeoRAM_PageNum & (GeoRAM_PagesPerBlock - 1))) * 256;
48+
GeoRAM_Page = GeoRAM_Bank[Offset / RAM_Bank_Size] + (Offset % RAM_Bank_Size);
49+
}
50+
51+
FLASHMEM void FreeGeoRAM()
52+
{
53+
// the handler is still installed and the C64 may be running: the IO ISRs must stop
54+
// touching the banks before the first one is freed
55+
uint8_t NumBanks = NumGeoRAM_Banks;
56+
NumGeoRAM_Banks = 0;
57+
FreeRAMBanks(GeoRAM_Bank, &NumBanks);
58+
}
59+
60+
FLASHMEM void SpecialBtn_GeoRAM(bool Up_nDn)
61+
{
62+
// on button release save GeoRAM contents
63+
if(Up_nDn) SaveRAMBanksReplacing(GeoRAM_Bank, NumGeoRAM_Banks, GeoRAM_Filename);
64+
}
65+
66+
FLASHMEM void InitHndlr_GeoRAM()
67+
{
68+
FreeGeoRAM();
69+
GeoRAM_Block = GeoRAM_PageNum = 0;
70+
uint8_t NumBanks = AllocRAMBanks(GeoRAM_Bank, MAX_GEORAM_BANKS, MIN_GEORAM_BANKS);
71+
if (NumBanks == 0)
72+
{
73+
Serial.printf("GeoRAM is disabled\n");
74+
return;
75+
}
76+
GeoRAM_Page = GeoRAM_Bank[0];
77+
NumGeoRAM_Banks = NumBanks;
78+
fSpecialBtnChange = &SpecialBtn_GeoRAM;
79+
Serial.printf("GeoRAM Size: %dK bytes\n", NumBanks * RAM_Bank_Size / 1024);
80+
LoadRAMBanks(GeoRAM_Bank, NumBanks, GeoRAM_Filename);
81+
}
82+
83+
void IO1Hndlr_GeoRAM(uint8_t Address, bool R_Wn)
84+
{
85+
if (NumGeoRAM_Banks == 0) return; // disabled: $DE00 stays open bus, so software sees no geoRAM
86+
if (R_Wn) DataPortWriteWaitLog(GeoRAM_Page[Address]);
87+
else
88+
{
89+
uint8_t Data = DataPortWaitRead();
90+
GeoRAM_Page[Address] = Data;
91+
TraceLogAddValidData(Data);
92+
}
93+
}
94+
95+
void IO2Hndlr_GeoRAM(uint8_t Address, bool R_Wn)
96+
{
97+
if (R_Wn || Address < GeoRAM_RegsBase) return; // write-only registers
98+
uint8_t Data = DataPortWaitRead();
99+
if (Address & GeoRAM_RegBlockBit) GeoRAM_Block = Data;
100+
else GeoRAM_PageNum = Data;
101+
GeoRAM_SelectPage();
102+
TraceLogAddValidData(Data);
103+
}

‎Source/Teensy/MinimalBoot/Common/IO_Handlers/IOH_REU.c‎

Lines changed: 11 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@
2929

3030
#ifdef USE_RAM12
3131

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

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

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

154144
void FreeREU()
155-
{ //free banks allocated in RAM2 and reset NumREUBanks
156-
for(uint16_t cnt=0; cnt < NumREU_Banks; cnt++)
157-
if((uint32_t)REU_Bank[cnt] >= 0x20200000) free(REU_Bank[cnt]);
158-
NumREU_Banks = 0;
145+
{
146+
FreeRAMBanks(REU_Bank, &NumREU_Banks);
159147
}
160148

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

456444
FLASHMEM void Save_REU()
457445
{
458-
if (NumREU_Banks == 0) return; // nothing to save: probably due to failure to allocate 128K
459-
460-
//Create filename based on current. reu000.reu becomes reu001.reu, etc
446+
#ifndef USE_RAM12
447+
#error Save_REU saves RAM1/2 banks only
448+
#endif
461449
char Filename[MaxPathLength];
462450
EEPreadStr(eepAdREUFilename, Filename);
463-
char *ptrFileName = Filename; //pointer to move past SD/USB/TR:
464-
RegMenuTypes MenuSourceID = RegMenuTypeFromFileName(&ptrFileName);
465-
466-
if (MenuSourceID == rmtSD) SDFullInit(); // SD.begin(BUILTIN_SDCARD); with retry if presence detected
467-
if (MenuSourceID == rmtUSBDrive) USBFileSystemWait(); //wait up to 1.5 sec in case USB drive just changed or powered up
468-
//rmtTeensy not allowed, no reu files in Teensy Mem
469-
470-
FS *sourceFS = FSfromSourceID(MenuSourceID);
471-
472-
char Extension[20];
473-
char *pDot = strrchr(ptrFileName, '.'); //find last dot
474-
if (pDot == NULL) pDot = ptrFileName + strlen(ptrFileName); //if no extension, set to end of filename
475-
strcpy(Extension, pDot); //copy extension
476-
*pDot = 0; //terminate at dot/extension
477-
478-
bool IsNum = true; //are last 3digits of filename all numbers?
479-
if (strlen(ptrFileName)>=3)
480-
{
481-
for(char *charloc=pDot-3; charloc<pDot; charloc++)
482-
{
483-
if (*charloc<'0' || *charloc>'9') IsNum = false;
484-
//Serial.printf("%08x: %c %02x\n", (uint32_t)charloc, *charloc, *charloc);
485-
}
486-
}
487-
else IsNum = false;
488-
489-
490-
uint16_t NewNum = 0;
491-
if (IsNum)
492-
{ //find current number and then terminate it
493-
NewNum = atoi(pDot-3);
494-
*(pDot-3) = 0; //terminate number
495-
}
496-
497-
//now see if the file exists, or itterate until it doesn't
498-
char NewFilename[MaxPathLength];
499-
500-
do sprintf(NewFilename, "%s%03d%s", ptrFileName, NewNum++, Extension);
501-
while (sourceFS->exists(NewFilename));
502-
503-
Serial.printf("Saving REU: %s\n", NewFilename);
504-
File SaveFile = sourceFS->open(NewFilename, FILE_WRITE);
505-
if (!SaveFile)
506-
{
507-
Serial.println("Unable to open!");
508-
return;
509-
}
510-
511-
//uint32_t StartmS = millis();
512-
uint8_t NextByte;
513-
514-
for (uint32_t CharNum=0; CharNum<REU_Size; CharNum++)
515-
{
516-
REU_RAM_READ(CharNum, NextByte);
517-
SaveFile.write(NextByte);
518-
}
519-
//Serial.printf("Saved %lu KBytes in %lumS\n", REU_Size/1024, millis()-StartmS);
520-
Serial.printf("Saved %dKBytes\n", REU_Size/1024);
521-
SaveFile.close();
522-
523-
//Flash LED to ack save
524-
uint32_t LastmS = millis();
525-
bool LEDState = true;
526-
527-
for (uint32_t FlashCount=0; FlashCount<20; FlashCount++)
528-
{
529-
while(millis()-LastmS < 75);
530-
LastmS = millis();
531-
if ((LEDState = !LEDState)) SetLEDOn;
532-
else SetLEDOff;
533-
}
534-
451+
SaveRAMBanks(REU_Bank, NumREU_Banks, Filename);
535452
}
536453

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

561478
#ifdef USE_RAM12
562-
//Allocate full REU size in Ram 1 and 2
563-
//FreeCrtChips(); //re-using CrtChips for this, free mem allocated in RAM2 and reset NumCrtChips
564-
FreeDriveDirMenu(); //free/clear prev loaded directory to make space. Doing it regardless to preserve continuity
565-
//Serial.printf("RAM2#x- %d\n", RAM2blocks());
566-
567-
if (NumCrtChips == 0) ptrRAM_ImageEnd = RAM_Image; //If no CRT loaded, RAM1 is entirely free for REU
568-
uint8_t *pRAM_Image = ptrRAM_ImageEnd; //start at end of any CRT-used RAM1
569-
570-
//Serial.printf("%dk REU, (%d banks x %d bytes)\n", REU_Size/1024, REU_Size/REU_RAM_Bank_Size, REU_RAM_Bank_Size);
571-
572-
//First use RAM_Image from RAM1:
573-
while (((uint32_t)pRAM_Image - (uint32_t)RAM_Image + REU_RAM_Bank_Size <= RAM_ImageSize)
574-
&& (NumREU_Banks < MAX_REU_BANKS))
575-
{
576-
//CrtChips[NumCrtChips].ChipROM = pRAM_Image;
577-
REU_Bank[NumREU_Banks] = pRAM_Image;
578-
pRAM_Image += REU_RAM_Bank_Size;
579-
NumREU_Banks++;
580-
}
581-
Printf_dbg_reu("Used %lu/%lu Bytes of RAM1 Image\n", (uint32_t)NumREU_Banks * REU_RAM_Bank_Size, RAM_ImageSize);
582-
583-
//allocate the rest from RAM2
584-
while((NumREU_Banks < MAX_REU_BANKS && // while NumREU_Banks < 64 (512k/8k)
585-
(NULL != (REU_Bank[NumREU_Banks] = (uint8_t*)malloc(REU_RAM_Bank_Size))))) // and allocation of 8k succeeds
586-
{
587-
NumREU_Banks++; // if allocation a success, increment NumREU_Banks
588-
}
589-
590-
// NumREU_Banks = number of banks allocated, one higher than the last index of REU_Bank[] that was allocated
591-
592-
Printf_dbg_reu("After parsing RAM2, %luK bytes allocated\n", (uint32_t)NumREU_Banks * REU_RAM_Bank_Size / 1024);
593-
594-
//resize REU to a power of 2 if needed and free unused banks
595-
if (NumREU_Banks & (NumREU_Banks-1)) //not a power of 2
596-
{
597-
uint8_t unused_bank;
598-
// largest power less than or equal to NumREU_Banks
599-
uint8_t NewNumREU_Banks = 1 << (7 - (__builtin_clz(NumREU_Banks) - 24));
600-
Serial.printf("Resizing REU from %d banks to %d banks\n", NumREU_Banks, NewNumREU_Banks);
601-
602-
for (unused_bank = NewNumREU_Banks; unused_bank < NumREU_Banks; unused_bank++)
603-
if((uint32_t)REU_Bank[unused_bank] >= 0x20200000)
604-
free(REU_Bank[unused_bank]);
605-
NumREU_Banks = NewNumREU_Banks;
606-
}
607-
608-
Printf_dbg_reu("After resizing to power of 2, %luK bytes allocated\n", (uint32_t)NumREU_Banks * REU_RAM_Bank_Size / 1024);
609-
610-
if (NumREU_Banks < MIN_REU_BANKS) // If REU is not 128k or larger
479+
NumREU_Banks = AllocRAMBanks(REU_Bank, MAX_REU_BANKS, MIN_REU_BANKS);
480+
if (NumREU_Banks == 0)
611481
{
612-
Serial.printf("Unable to allocate minimum REU size of 128K\n"
613-
"REU is disabled\n");
614-
FreeREU();
482+
Serial.printf("REU is disabled\n");
615483
return;
616484
}
617485

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

625-
//pre-load REU into RAM here:
626493
char Filename[MaxPathLength];
627494
EEPreadStr(eepAdREUFilename, Filename);
628-
char *ptrFileName = Filename; //pointer to move past SD/USB/TR:
629-
Serial.printf("Loading REU: %s\n", Filename);
630-
RegMenuTypes MenuSourceID = RegMenuTypeFromFileName(&ptrFileName);
631-
632-
if (MenuSourceID == rmtSD) SDFullInit(); // SD.begin(BUILTIN_SDCARD); with retry if presence detected
633-
if (MenuSourceID == rmtUSBDrive) USBFileSystemWait(); //wait up to 1.5 sec in case USB drive just changed or powered up
634-
//rmtTeensy not allowed, no reu files in Teensy Mem
635-
636-
FS *sourceFS = FSfromSourceID(MenuSourceID);
637-
File LoadFile = sourceFS->open(ptrFileName, FILE_READ);
638-
if (!LoadFile)
639-
{
640-
Serial.println("Not found!");
641-
return;
642-
}
643-
644-
if (LoadFile.size() > REU_Size)
645-
Serial.printf("Too Large! Loading first %luK\n", (uint32_t)REU_Size/1024);
646-
647-
//uint32_t StartmS = millis();
648-
uint32_t CharNum = 0;
649-
for (uint8_t Bank = 0; Bank < NumREU_Banks && LoadFile.available(); Bank++)
650-
CharNum += LoadFile.read(REU_Bank[Bank], REU_RAM_Bank_Size);
651-
//Serial.printf("Read %lu Bytes in %lumS\n", CharNum, millis()-StartmS);
652-
Serial.printf("Read %lu Bytes into REU\n", CharNum);
653-
LoadFile.close();
654-
//delay(250);
655-
495+
LoadRAMBanks(REU_Bank, NumREU_Banks, Filename);
656496

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

0 commit comments

Comments
 (0)