Created
May 17, 2024 18:49
-
-
Save juj/9e0e27c58f6b362732338844f4b16a32 to your computer and use it in GitHub Desktop.
Commodore 64 REU interface in C/C++
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "reucpy.h" | |
static volatile uint8_t *const reu_status = (uint8_t*)0xDF00; | |
static volatile uint8_t *const reu_command = (uint8_t*)0xDF01; | |
static volatile uintptr_t *const reu_c64_addr = (uintptr_t*)0xDF02; | |
static volatile reu_addr_t *const reu_cart_addr = (reu_addr_t*)0xDF04; | |
static volatile uint16_t *const reu_xfer_length = (uint16_t*)0xDF07; | |
static volatile uint8_t *const reu_address_ctl = (uint8_t*)0xDF0A; | |
void reucpy(void *c64_addr, reu_addr_t reu_addr, uint16_t size, uint8_t direction) | |
{ | |
// Call reu_init() first if this assert() triggers, or if manually | |
// having done REU accesses in between, be sure to reset bits 7 and 6 | |
// of REU address control register back to zero. | |
assert((*reu_address_ctl & 0xC0) == 0); | |
*reu_c64_addr = (uintptr_t)c64_addr; | |
*reu_cart_addr = reu_addr; | |
*reu_xfer_length = size; | |
*reu_command = direction; | |
} | |
void reuset(reu_addr_t reu_addr, uint8_t val, uint16_t size) | |
{ | |
*reu_address_ctl = (*reu_address_ctl & 0x3F) | 0x80; // Fix C64 address, advance REU address | |
*reu_c64_addr = (uintptr_t)&val; | |
*reu_cart_addr = reu_addr; | |
*reu_xfer_length = size; | |
*reu_command = RAM2REU; | |
*reu_address_ctl = *reu_address_ctl & 0x3F; // Restore both C64 and REU addresses to advance per each transferred byte | |
} | |
int reu_init() | |
{ | |
*reu_address_ctl = *reu_address_ctl & 0x3F; // Make both C64 and REU addresses advance per each transferred byte | |
char data[5] = { 'a', 'r', 'e', 'u', 0 }; | |
for(int bank = 255; bank >= 0; --bank) | |
{ | |
data[0] = (uint8_t)bank; | |
reucpy(data, (reu_addr_t)bank << 16, 4, RAM2REU); | |
} | |
memset(data, 0, sizeof(data)); | |
for(int bank = 0; bank < 256; ++bank) | |
{ | |
reucpy(data, (reu_addr_t)bank << 16, 4, REU2RAM); | |
if (data[0] != bank || data[1] != 'r' || data[2] != 'e' || data[3] != 'u') return bank; | |
} | |
return 256; // Full 16MB of REU available | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#define RAM2REU 0x90 // Copy from C64 RAM to REU memory | |
#define REU2RAM 0x91 // Copy from REU memory to C64 RAM | |
#define REUSWAP 0x92 // Swap contents between REU and C64 RAM addresses | |
#define REUCMP 0x93 // Compare contents between REU and C64 RAM | |
typedef unsigned _BitInt(24) reu_addr_t; | |
// Like memcpy, but copies data between C64 RAM and REU. | |
// size: number of bytes to write. Note that 0 is interpreted as 65536 bytes! | |
// direction: specifies the direction of copy. Use one of the defines above. | |
void reucpy(void *c64_addr, reu_addr_t reu_addr, uint16_t size, uint8_t direction); | |
// Like memset, for setting data in REU memory. | |
// reu_addr: Starting byte address in REU memory. | |
// val: the byte value to fill. | |
// size: the number of bytes to fill. Note that 0 is interpreted as 65536 bytes! | |
void reuset(reu_addr_t reu_addr, uint8_t val, uint16_t size); | |
// Initializes REU, and returns the number of 64KB REU banks that were detected: | |
// 0 - no REU detected. | |
// 1 - 64KB REU detected, | |
// 256: 16MB REU detected. | |
// Call this once before calling reucpy(). | |
int reu_init(void); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment