Added VBL-based waiting

This commit is contained in:
Zane Kaminski 2020-05-22 18:25:08 -04:00
parent 34cc77a8b2
commit e240409449

204
ram2e.c
View File

@ -8,15 +8,32 @@
#define true 1 #define true 1
#define false 0 #define false 0
#define VBL ((signed char*)0xC019)
const uint8_t SPIN_HALFCYCLES = 3;
const uint8_t SPIN_FRAMESPERCHAR = 4;
#define PB0 ((char*)0xC061) #define PB0 ((char*)0xC061)
#define PB1 ((char*)0xC062) #define PB1 ((char*)0xC062)
static char read_applekey(void) { return (*PB0 | *PB1) & 0x80; } static char read_applekey(void) { return (*PB0 | *PB1) & 0x80; }
static void ram2e_cmd(char operation, char data) { char _cmd;
char _arg;
/* ram2e_cmd(...) issues a coded command+argument sequence to the RAM2E */
static void ram2e_cmd(char cmd, char arg) {
// Load operation and data bytes into X and Y registers // Load operation and data bytes into X and Y registers
// in preparation for command sequence // in preparation for command sequence
__asm__("ldx %o", operation); _cmd = cmd;
__asm__("ldy %o", data); _arg = arg;
__asm__("ldx %v", _cmd); // X = command
__asm__("ldy %v", _arg); // Y = argument
// First, reset command sequence just in case it,
// for some reason, has not timed out. (e.g. crazy fast accelerator?)
// Write 0 twice because command and argument steps always advance seq.
__asm__("lda #0");
__asm__("sta $C073");
__asm__("sta $C073");
// Command sequence // Command sequence
__asm__("lda #$FF"); __asm__("lda #$FF");
@ -31,44 +48,44 @@ static void ram2e_cmd(char operation, char data) {
__asm__("sta $C073"); __asm__("sta $C073");
__asm__("lda #$AD"); __asm__("lda #$AD");
__asm__("sta $C073"); __asm__("sta $C073");
// Operation // Command
__asm__("stx $C073"); __asm__("stx $C073");
// Data // Argument
__asm__("sty $C073"); __asm__("sty $C073");
// Reset RAMWorks bank register just in case
__asm__("lda #0");
__asm__("sta $C073");
} }
/* set_mask_temp(...) sends the "Set RAMWorks Capacity Mask" to the RAM2E */
static void set_mask_temp(char mask) { ram2e_cmd(0xE0, mask); } static void set_mask_temp(char mask) { ram2e_cmd(0xE0, mask); }
/* ufm_bitbang(...) sends the "Set UFM Bitbang Outputs" to the RAM2E */
static void ufm_bitbang(char bitbang) { ram2e_cmd(0xEA, bitbang); } static void ufm_bitbang(char bitbang) { ram2e_cmd(0xEA, bitbang); }
/* ufm_program(...) sends the "UFM Program Once" command to the RAM2E */
static void ufm_program() { ram2e_cmd(0xEF, 0x00); }
/* ufm_erase(...) sends the "UFM Erase Once" command to the RAM2E */
static void ufm_erase() { ram2e_cmd(0xEE, 0x00); }
/* set_mask_temp(...) sends the "Set RAMWorks Capacity Mask" */
static void set_nvm(char mask) { static void set_nvm(char mask) {
int i; int i;
// Shift mask into UFMD twice // Shift mask OR'd with data register clock pulse trigger into UFMD twice
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
char maskpart; ufm_bitbang(0x80 | ((mask >> 1) & 0x40));
ufm_bitbang(0x80 | ((mask >> 0) & 0x40));
maskpart = 0x80 | ((mask >> 1) & 0x40); ufm_bitbang(0x80 | ((mask << 1) & 0x40));
ufm_bitbang(maskpart); ufm_bitbang(0x80 | ((mask << 2) & 0x40));
ufm_bitbang(0x80 | ((mask << 3) & 0x40));
maskpart = 0x80 | ((mask ) & 0x40); ufm_bitbang(0x80 | ((mask << 4) & 0x40));
ufm_bitbang(maskpart); ufm_bitbang(0x80 | ((mask << 5) & 0x40));
ufm_bitbang(0x80 | ((mask << 6) & 0x40));
maskpart = 0x80 | ((mask << 1) & 0x40);
ufm_bitbang(maskpart);
maskpart = 0x80 | ((mask << 2) & 0x40);
ufm_bitbang(maskpart);
maskpart = 0x80 | ((mask << 3) & 0x40);
ufm_bitbang(maskpart);
maskpart = 0x80 | ((mask << 4) & 0x40);
ufm_bitbang(maskpart);
maskpart = 0x80 | ((mask << 5) & 0x40);
ufm_bitbang(maskpart);
maskpart = 0x80 | ((mask << 6) & 0x40);
ufm_bitbang(maskpart);
} }
// Program UFM
ufm_program();
} }
static void menu(void) static void menu(void)
@ -103,114 +120,131 @@ static void menu(void)
} }
static void spin(uint8_t x, uint8_t y) { static void spin(uint8_t x, uint8_t y) {
int i; char i;
const uint8_t spin_big = 10;
const uint8_t spin_small = 150;
for (i = 0; i < spin_big; i++) { // Sync to frame before starting
int j; while (*VBL >= 0);
for (j = 0; j < spin_small; j++) {
__asm__("lda $C000"); // Wait and animate spinner.
// Spin_half
for (i = 0; i < SPIN_HALFCYCLES; i++) {
char j;
for (j = 0; j < 4; j++) {
char spinchar;
char k;
// Assign spinner char based on j
switch (j) {
case 0: spinchar = '\\'; break;
case 1: spinchar = '|'; break;
case 2: spinchar = '/'; break;
case 3: spinchar = '-'; break;
default: spinchar = '-'; break;
}
// Write it to screen
gotoxy(x, y); gotoxy(x, y);
__asm__("lda $C000"); putchar(spinchar);
cputs("-");
__asm__("lda $C000"); // Wait specificed number of frames
} for (k = 0; k < SPIN_FRAMESPERCHAR; k++) {
for (j = 0; j < spin_small; j++) { while (*VBL < 0);
__asm__("lda $C000"); while (*VBL >= 0);
gotoxy(x, y); }
__asm__("lda $C000");
cputs("\\");
__asm__("lda $C000");
}
for (j = 0; j < spin_small; j++) {
__asm__("lda $C000");
gotoxy(x, y);
__asm__("lda $C000");
cputs("|");
__asm__("lda $C000");
}
for (j = 0; j < spin_small; j++) {
__asm__("lda $C000");
gotoxy(x, y);
__asm__("lda $C000");
cputs("/");
__asm__("lda $C000");
} }
} }
// Wait a frame when finished
while (*VBL < 0);
while (*VBL >= 0);
} }
int main(void) int main(void)
{ {
char key;
char mask; char mask;
char nvm; char nvm;
int reset_count;
// First clear screen
clrscr(); clrscr();
// Make sure we are running on an Apple IIe // Make sure we are running on an Apple IIe
if((get_ostype() & 0xF0) != APPLE_IIE) { if((get_ostype() & 0xF0) != APPLE_IIE) {
// If not on Apple IIe, show an error message and quit
gotoxy(0, 8); gotoxy(0, 8);
cputs(" THIS PROGRAM REQUIRES AN APPLE IIE."); cputs(" THIS PROGRAM REQUIRES AN APPLE IIE.");
gotoxy(0, 10); gotoxy(0, 10);
cputs(" PRESS ANY KEY TO QUIT."); cputs(" PRESS ANY KEY TO QUIT.");
cgetc(); cgetc(); // Wait for key
clrscr(); clrscr(); // Clear screen before quitting
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
// Show menu // Show menu
menu(); menu();
// Get user choice // Get user choice from menu
mask = 0; mask = 0;
nvm = 0; nvm = 0;
reset_count = 0;
while (true) { while (true) {
key = toupper(cgetc()); // Set capacity mask or quit according to keypress.
switch (toupper(cgetc())) {
// Set capacity mask or quit according to keypress case 'Q' : {
if (key == 'Q') { clrscr();
// Quit return EXIT_SUCCESS;
clrscr(); }
return EXIT_SUCCESS; case '1': mask = 0x00; break;
case '2': mask = 0x07; break;
case '3': mask = 0x0F; break;
case '4': mask = 0x3F; break;
case '5': mask = 0x7F; break;
case 'R': {
if (reset_count > 127) {
ufm_erase();
reset_count = 0;
} else { reset_count++; }
} default: continue;
} }
else if (key == '1') { mask = 0x00; }
else if (key == '2') { mask = 0x07; }
else if (key == '3') { mask = 0x0F; }
else if (key == '4') { mask = 0x3F; }
else if (key == '5') { mask = 0x7F; }
else { continue; }
// Check if pressed with apple key // Check if pressed with apple key.
// If so, save to nonvolatile memory.
if (read_applekey()) { nvm = true; } if (read_applekey()) { nvm = true; }
break; break;
} }
// Set capacity in volatile memory // Set capacity in volatile memory.
set_mask_temp(mask); set_mask_temp(mask);
// Clear screen in preparation to show saving or success message.
clrscr(); clrscr();
if (nvm) { // Save in NVM if requested
set_nvm(mask);
if (nvm) { // Save in NVM if requested.
// Show message about saving.
gotoxy(1, 8); gotoxy(1, 8);
cputs("Saving RAM2E capacity setting."); cputs("Saving RAM2E capacity setting.");
gotoxy(1, 9); gotoxy(1, 9);
cputs("Do not turn off your Apple."); cputs("Do not turn off your Apple.");
// Save capacity in nonvolatile memory.
set_nvm(mask);
// Wait for >= 500ms on even the fastest systems.
spin(32, 8); spin(32, 8);
// Clear screen again.
clrscr(); clrscr();
gotoxy(1, 8); gotoxy(1, 8);
cputs("RAM2E capacity saved successfully."); cputs("RAM2E capacity saved successfully.");
} else { // Print success message } else { // Print success message if not saving in NVM.
gotoxy(1, 8); gotoxy(1, 8);
cputs("RAM2E capacity set successfully."); cputs("RAM2E capacity set successfully.");
} }
gotoxy(1, 10); gotoxy(1, 10);
cputs("Press any key to quit."); cputs("Press any key to quit.");
gotoxy(1, 11);
cputs("You may also turn off your Apple.");
cgetc(); cgetc();
// Quit // Quit