Added RAM2GS functionality

This commit is contained in:
Zane Kaminski 2020-07-22 00:47:25 -04:00
parent 1e1ecf9592
commit 08f6a7017b
12 changed files with 634 additions and 89 deletions

View File

@ -1,14 +1,14 @@
all: RAM2Eutil.po RAM2Eutil.dbg.po
.PHONY: clean
obj:
@mkdir obj
bin:
@mkdir bin
ram2e.c:
obj/main.o: obj main.c
cc65 main.c -O --cpu 6502 -t apple2enh -o obj/main.s
ca65 obj/main.s -o obj/main.o
obj/ram2e.o: obj ram2e.c
cc65 ram2e.c -O --cpu 6502 -t apple2enh -o obj/ram2e.s
@ -18,19 +18,35 @@ obj/ram2e.dbg.o: obj ram2e.c
cc65 ram2e.c -O --cpu 6502 -t apple2enh -o obj/ram2e.dbg.s -DSKIP_RAM2E_DETECT
ca65 obj/ram2e.dbg.s -o obj/ram2e.dbg.o
bin/ram2e.sys: bin obj/ram2e.o
ld65 -o bin/ram2e.sys obj/ram2e.o -C apple2enh-system.cfg --lib apple2enh.lib -D __EXEHDR__=0
obj/ram2gs_asm.o: obj ram2gs_asm.s
ca65 ram2gs_asm.s -o obj/ram2gs_asm.o
bin/ram2e.dbg.sys: bin obj/ram2e.dbg.o
ld65 -o bin/ram2e.dbg.sys obj/ram2e.dbg.o -C apple2enh-system.cfg --lib apple2enh.lib -D __EXEHDR__=0
obj/ram2gs.o: obj ram2gs.c
cc65 ram2gs.c -O --cpu 6502 -t apple2enh -o obj/ram2gs.s
ca65 obj/ram2gs.s -o obj/ram2gs.o
RAM2Eutil.po: bin/ram2e.sys
obj/ram2gs.dbg.o: obj ram2gs.c
cc65 ram2gs.c -O --cpu 6502 -t apple2enh -o obj/ram2gs.dbg.s -DSKIP_RAM2GS_DETECT
ca65 obj/ram2gs.dbg.s -o obj/ram2gs.dbg.o
obj/util.o: obj util.c
cc65 util.c -O --cpu 6502 -t apple2enh -o obj/util.s
ca65 obj/util.s -o obj/util.o
bin/main.sys: bin obj/main.o obj/ram2e.o obj/ram2gs.o obj/ram2gs_asm.o obj/util.o
ld65 -o bin/main.sys obj/main.o obj/ram2gs.o obj/ram2e.o obj/ram2gs_asm.o obj/util.o -C apple2enh-system.cfg --lib apple2enh.lib -D __EXEHDR__=0
bin/main.dbg.sys: bin obj/main.o obj/ram2e.dbg.o obj/ram2gs.dbg.o obj/ram2gs_asm.o obj/util.o
ld65 -o bin/main.dbg.sys obj/main.o obj/ram2gs.dbg.o obj/ram2e.dbg.o obj/ram2gs_asm.o obj/util.o -C apple2enh-system.cfg --lib apple2enh.lib -D __EXEHDR__=0
RAM2Eutil.po: bin/main.sys
cp prodos140.po bin/RAM2Eutil.po
cat bin/ram2e.sys | java -jar ./AppleCommander-ac-1.6.0.jar -p bin/RAM2Eutil.po ram2e.system sys 0x2000
cat bin/main.sys | java -jar ./AppleCommander-ac-1.6.0.jar -p bin/RAM2Eutil.po gwram.system sys 0x2000
RAM2Eutil.dbg.po: bin/ram2e.dbg.sys
RAM2Eutil.dbg.po: bin/main.dbg.sys
cp prodos140.po bin/RAM2Eutil.dbg.po
cat bin/ram2e.dbg.sys | java -jar ./AppleCommander-ac-1.6.0.jar -p bin/RAM2Eutil.dbg.po ram2e.system sys 0x2000
cat bin/main.dbg.sys | java -jar ./AppleCommander-ac-1.6.0.jar -p bin/RAM2Eutil.dbg.po gwram.system sys 0x2000
.PHONY: clean
clean:
rm -fr bin obj

Binary file not shown.

Binary file not shown.

32
main.c Normal file
View File

@ -0,0 +1,32 @@
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include "ram2e.h"
#include "ram2gs.h"
int main(void)
{
// First clear screen
clrscr();
// Check machine type
switch ((get_ostype() & 0xF0)) {
case APPLE_IIE:
ram2e_main();
break;
case APPLE_IIGS:
ram2gs_main();
break;
default:
// If not on IIe or IIgs, show an error message and quit
gotoxy(0, 8);
cputs(" THIS PROGRAM REQUIRES APPLE IIE OR IIGS");
gotoxy(0, 10);
cputs(" PRESS ANY KEY TO QUIT.");
cgetc(); // Wait for key
clrscr(); // Clear screen before quitting
return EXIT_SUCCESS;
break;
}
}

90
ram2e.c
View File

@ -5,20 +5,10 @@
#include <ctype.h>
#include <stdint.h>
#define true 1
#define false 0
#include "util.h"
#define VBL ((signed char*)0xC019)
const uint8_t SPIN_HALFCYCLES = 3;
const uint8_t SPIN_FRAMESPERCHAR = 4;
#define PB0 ((char*)0xC061)
#define PB1 ((char*)0xC062)
static char read_applekey(void) { return (*PB0 | *PB1) & 0x80; }
char _cmd;
char _arg;
static char _cmd;
static 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
@ -100,7 +90,7 @@ static char auxram_detect() {
}
/* ram2e_detect() returns true if a RAM2E II has been detected */
uint8_t _detect;
static uint8_t _detect;
static char ram2e_detect() {
#ifdef SKIP_RAM2E_DETECT
return true;
@ -148,8 +138,8 @@ static char ram2e_detect() {
}
/* ramworks_getsize() returns the number of banks of RAM2E aux memory */
uint8_t _rwsize;
uint8_t _rwnot16mb;
static uint8_t _rwsize;
static uint8_t _rwnot16mb;
static uint16_t ramworks_getsize() {
_rwnot16mb = 1; // Set "not 16 mb" flag
@ -169,11 +159,11 @@ static uint16_t ramworks_getsize() {
CountLoop:
__asm__("sty $C073"); // Set bank
__asm__("cpy $00"); // Is bank num stored at address 0?
__asm__("bne %g", NotMem); // If not, skip increment
__asm__("bne %g", AfterInc); // If not, skip increment
__asm__("inx"); // If so, increment bank count
__asm__("bne %g", NotMem); // Skip next if x!=0
__asm__("bne %g", AfterInc); // Skip next if x!=0
__asm__("stx %v", _rwnot16mb); // Othwerwise rolled over so clear rwnot16mb
NotMem:
AfterInc:
__asm__("iny"); // Move to next bank
__asm__("bne %g", CountLoop); // Repeat if not on bank 0
@ -250,67 +240,12 @@ static void menu(void)
cputs("Press [Q] to quit without saving.");
}
static void spin(uint8_t x, uint8_t y) {
char i;
// Sync to frame before starting
while (*VBL >= 0);
// 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);
putchar(spinchar);
// Wait specificed number of frames
for (k = 0; k < SPIN_FRAMESPERCHAR; k++) {
while (*VBL < 0);
while (*VBL >= 0);
}
}
}
// Wait a frame when finished
while (*VBL < 0);
while (*VBL >= 0);
}
int main(void)
int ram2e_main(void)
{
char mask;
char nvm;
int reset_count;
// First clear screen
clrscr();
// Make sure we are running on an Apple IIe
if((get_ostype() & 0xF0) != APPLE_IIE) {
// If not on Apple IIe, show an error message and quit
gotoxy(0, 8);
cputs(" THIS PROGRAM REQUIRES AN APPLE IIE.");
gotoxy(0, 10);
cputs(" PRESS ANY KEY TO QUIT.");
cgetc(); // Wait for key
clrscr(); // Clear screen before quitting
return EXIT_SUCCESS;
}
// Check for RAM2E
if(!auxram_detect() || !ram2e_detect()) {
// If no RAM2E, show an error message and quit
@ -331,7 +266,7 @@ int main(void)
reset_count = 0;
while (true) {
// Set capacity mask or quit according to keypress.
switch (toupper(cgetc())) {
switch (toupper(cgetc() & 0x7F)) {
case 'Q' : {
clrscr();
return EXIT_SUCCESS;
@ -366,8 +301,7 @@ int main(void)
} default: continue;
}
// Check if pressed with apple key.
// If so, save to nonvolatile memory.
// Check if pressed with apple key. If so, save to nonvolatile memory.
if (read_applekey()) { nvm = true; }
break;
}

6
ram2e.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef RAM2E_H
#define RAM2E_H
int ram2e_main(void);
#endif /* RAM2E_H */

173
ram2gs.c Normal file
View File

@ -0,0 +1,173 @@
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <stdint.h>
#include "util.h"
#include "ram2gs_asm.h"
static void ram2gs_erase() { ram2gs_cmd(0x28); }
static void ram2gs_program() { ram2gs_cmd(0x24); }
static void ram2gs_set4mb() { ram2gs_cmd(0x10); }
static void ram2gs_set8mb() { ram2gs_cmd(0x11); }
static void ram2gs_setnvm(char en8meg) {
char i;
// Clock in 0 to enable this setting entry
ram2gs_cmd(0x20);
ram2gs_cmd(0x22);
if (en8meg) {
// Clock in 1 to enable 8mb
ram2gs_cmd(0x21);
ram2gs_cmd(0x23);
} else {
// Clock in 0 to disable 8mb
ram2gs_cmd(0x20);
ram2gs_cmd(0x22);
}
// Clock in 14 dummy "1"s
for (i = 0; i < 14; i++) {
ram2gs_cmd(0x21);
ram2gs_cmd(0x23);
}
ram2gs_program();
}
static void menu(void)
{
uint8_t bankcount = ram2gs_getsize();
gotoxy(5, 1);
cputs("-- RAM2GS Capacity Settings --");
gotoxy(4, 3);
printf("Current RAM2GS capacity: %d kB", bankcount * 64);
gotoxy(1, 6);
cputs("Select desired memory capacity:");
gotoxy(4, 8);
cputs("1. 4 megabytes");
gotoxy(4, 10);
cputs("2. 8 megabytes");
gotoxy(1, 18);
cputs("Capacity will be saved until power-off.");
gotoxy(1, 20);
cputs("To remember capacity setting in");
gotoxy(1, 21);
cputs("nonvolatile memory, press Apple+number.");
gotoxy(1, 23);
cputs("Press [Q] to quit without saving.");
}
int ram2gs_main(void)
{
char en8meg;
char nvm;
int reset_count;
// Check for RAM2GS
#ifndef SKIP_RAM2GS_DETECT
if(!ram2gs_detect()) {
// If no RAM2GS, show an error message and quit
gotoxy(0, 8);
cputs(" No RAM2GS II detected.");
gotoxy(0, 10);
cputs(" Press any key to quit.");
cgetc(); // Wait for key
clrscr(); // Clear screen before quitting
return EXIT_SUCCESS;
}
#endif
menu(); // Print menu
// Get user choice from menu
en8meg = 0;
nvm = 0;
reset_count = 0;
while (true) {
// Set capacity or quit according to keypress.
switch (toupper(cgetc() & 0x7F)) {
case 'Q' : {
clrscr();
return EXIT_SUCCESS;
}
case '!': nvm = true;
case '1': en8meg = 0; ram2gs_set4mb(); break;
case '@': nvm = true;
case '2': en8meg = 1; ram2gs_set8mb(); break;
case 'R': {
reset_count++;
if (reset_count >= 100) {
// Show message about saving.
clrscr(); // Clear screen
gotoxy(1, 8);
cputs("Resetting RAM2GS settings.");
gotoxy(1, 9);
cputs("Do not turn off your Apple.");
ram2gs_erase(); // Erase RAM2GS settings memory
ram2gs_set8mb(); // Enable 8 megabytes now
// Wait for >= 500ms on even the fastest systems.
spin(32, 8);
// Show success message and quit
clrscr(); // Clear screen
gotoxy(1, 8);
cputs("RAM2GS settings reset successfully.");
goto end;
}
} default: continue;
}
// Check if pressed with apple key. If so, save to nonvolatile memory.
if (read_applekey()) { nvm = true; }
break;
}
// Clear screen in preparation to show saving or success message.
clrscr();
if (nvm) { // Save in NVM if requested.
// Show message about saving.
gotoxy(1, 8);
cputs("Saving RAM2GS capacity setting.");
gotoxy(1, 9);
cputs("Do not turn off your Apple.");
// Save capacity in nonvolatile memory.
ram2gs_setnvm(en8meg);
// Wait for >= 500ms on even the fastest systems.
spin(33, 8);
// Print success message
clrscr(); // Clear screen
gotoxy(1, 8);
cputs("RAM2GS capacity saved successfully.");
} else { // Print success message if not saving in NVM.
gotoxy(1, 8);
cputs("RAM2GS capacity set successfully.");
}
end:
if (nvm) { // Show end message for nonvolatile save
gotoxy(1, 10);
cputs("You may now turn off your Apple.");
gotoxy(1, 12);
cputs("You may also reset your Apple for");
gotoxy(1, 13);
cputs("the setting change to take effect.");
} else { // Show end message for volatile save
gotoxy(1, 10);
cputs("Please reset your Apple for");
gotoxy(1, 11);
cputs("the setting change to take effect.");
}
// Don't quit. Instead leave prompt asking user to reset.
while(1) { cgetc(); }
}

6
ram2gs.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef RAM2GS_H
#define RAM2GS_H
int ram2gs_main(void);
#endif /* RAM2GS_H */

8
ram2gs_asm.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef RAM2GS_ASM_H
#define RAM2GS_ASM_H
uint8_t __fastcall__ ram2gs_getsize(void);
uint8_t __fastcall__ ram2gs_detect(void);
uint8_t __fastcall__ ram2gs_cmd(char cmd);
#endif /* RAM2GS_ASM_H */

306
ram2gs_asm.s Normal file
View File

@ -0,0 +1,306 @@
.setcpu "65816"
.autoimport on
.importzp sp
.export _ram2gs_getsize
.export _ram2gs_detect
.export _ram2gs_cmd
.macro A8
sep #$20 ; put the 65C816 in 8-bit accumulator mode
.A8
.endmacro
.macro I8
sep #$10 ; put the 65C816 in 8-bit index register mode
.I8
.endmacro
.macro AI8
sep #$30 ; put the 65C816 in 8-bit accumulator and index register mode
.A8
.I8
.endmacro
.macro A16
rep #$20 ; put the 65C816 in 8-bit accumulator mode
.A16
.endmacro
.macro I16
rep #$10 ; put the 65C816 in 8-bit index register mode
.I16
.endmacro
.macro AI16
rep #$30 ; put the 65C816 in 8-bit accumulator and index register mode
.A16
.I16
.endmacro
.segment "CODE"
.proc _gsram_getsize: near
.A8
.I8
; Preamble
sei ; Disable interrupts
clc ; Clear carry
xce ; Clear emulation bit
php ; Push status
phb ; Push bank
AI8
; Store bank number at address 0xFFFF in each bank
ldy #$7F ; Start at bank 0x7F
BankSetLoop:
phy ; Push future bank
plb ; Pull bank
lda $8000 ; Get address 0xFFFF in this bank
pha ; Save old address 0xFFFF contents
tya ; A = Y
eor #$FF ; Flip all bits
tay ; Y = A
sty $8000 ; Overwrite address 0xFFFF with bank number
eor #$FF ; Flip all bits back
tay ; Y = A
dey ; Decrement bank number
cpy #$FF ; Have we wrapped around?
bne BankSetLoop ; If not, repeat
; Count banks with matching bank number
ldy #$00 ; Y is bank
ldx #$00 ; X is count
CountLoop:
phy ; Push future bank
plb ; Pull bank
tya ; A = Y
eor #$FF ; Flip all bits
tay ; Y = A
cpy $8000 ; Is bank num stored at address 0xFFFF?
bne AfterInc ; If not, skip increment
inx ; If so, increment bank count
AfterInc:
eor #$FF ; Flip all bits back
tay ; Y = A
pla ; Get contents to restore
sta $8000 ; Restore address 0xFFFF in this bank
iny ; Move to next bank
cpy #$80 ; Are we at bank 0x80 yet?
bne CountLoop ; If not, repeat
; Postamble
plb ; Restore bank
plp ; Restore status
xce ; Restore emulation bit
cli ; Enable interrupts
txa ; Transfer bank count to A
rts
.endproc
.proc _ram2gs_getsize: near
.A8
.I8
; Preamble
sei ; Disable interrupts
clc ; Clear carry
xce ; Clear emulation bit
php ; Push status
phb ; Push bank
AI8
; Go to bank 3F
ldy #$3F
phy
plb
; Save 3F/3456
ldx $3456
; Go to bank 7F
ldy #$7F
phy
plb
; Invert 7F/3456
lda $3456
eor #$FF
sta $3456
; Go to bank 3F
ldy #$3F
phy
plb
; Has 3F/3456 changed?
cpx $3456
php
; Go to bank 7F
ldy #$7F
phy
plb
; Restore 7F/3456
eor #$FF
sta $3456
; Check result
ldx #$80
plp
beq _ram2gs_getsize_return
ldx #$40
; Postamble
_ram2gs_getsize_return:
plb ; Restore bank
plp ; Restore status
xce ; Restore emulation bit
cli ; Enable interrupts
txa ; Transfer bank count to A
rts
.endproc
.proc _unswap: near
.A8
.I8
; Save current bank and accumulator
phb
pha
; Switch to bank 0xFB
lda #$FB
pha
plb
; Submit C1AD
lda #$C1
sta $FFFE
lda #$AD
sta $FFFF
; Pull and submit command
lda #$00
sta $FFFD
; Restore accumulator and bank and return
pla
plb
rts
.endproc
.proc _swap: near
.A8
.I8
; Save current bank and accumulator
phb
pha
; Switch to bank 0xFB
lda #$FB
pha
plb
; Submit C1AD
lda #$C1
sta $FFFE
lda #$AD
sta $FFFF
; Pull and submit command
lda #$01
sta $FFFD
; Restore accumulator and bank and return
pla
plb
rts
.endproc
.proc _ram2gs_detect: near
.A8
.I8
; Preamble
sei ; Disable interrupts
clc ; Clear carry
xce ; Clear emulation bit
php ; Push status
phb ; Push bank
AI8
; Switch to bank 0x3F
lda #$3F
pha
plb
; Unswap
jsr _unswap
; Save unswapped 3F/8000
lda $8000
pha
; Swap
jsr _swap
; Save swapped 3F/8000
lda $8000
pha
; Store 0xFF in swapped
lda #$FF
sta $8000
; Verify 0xFF stored
lda $8000
cmp #$FF
bne _ram2gs_detect_fail
; Unswap
jsr _unswap
; Store 0x00 in unswapped
lda #$00
sta $8000
; Verify 0x00 stored
lda $8000
cmp #$00
bne _ram2gs_detect_fail
; Swap
jsr _swap
; Verify 0xFF stored
lda $8000
cmp #$FF
bne _ram2gs_detect_fail
; Get success return value and jump to postamble
ldx #$01 ; Get success falue
bne _ram2gs_detect_return ; Jump to postamble
; Fail
_ram2gs_detect_fail:
ldx #$00 ; Get fail value
; Postamble
_ram2gs_detect_return:
jsr _swap ; Swap
pla ; Get value to restore to swapped bank 3F
sta $8000 ; Restore
jsr _unswap ; Unswap
pla ; Get value to restore to unswapped bank 3F
sta $8000 ; Restore
txa ; Put return value in accumulator
plb ; Restore bank
plp ; Restore status
xce ; Restore emulation bit
cli ; Enable interrupts
rts
.endproc
.proc _ram2gs_cmd: near
.A8
.I8
; Save current bank and command in accumulator
phb
pha
; Switch to bank 0xFB
lda #$FB
pha
plb
; Submit C1AD
lda #$C1
sta $FFFE
lda #$AD
sta $FFFF
; Pull and submit command
pla
sta $FFFD
; Restore bank and return
plb
rts
.endproc

52
util.c Normal file
View File

@ -0,0 +1,52 @@
#include "util.h"
#include <stdint.h>
#include <stdio.h>
#include <conio.h>
#define PB0 ((char*)0xC061)
#define PB1 ((char*)0xC062)
char read_applekey(void) { return ((*PB0) | (*PB1)) & 0x80; }
#define VBL ((signed char*)0xC019)
#define SPIN_HALFCYCLES 3
#define SPIN_FRAMESPERCHAR 4
void spin(uint8_t x, uint8_t y) {
char i;
// Sync to frame before starting
while (*VBL >= 0);
// 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);
putchar(spinchar);
// Wait specificed number of frames
for (k = 0; k < SPIN_FRAMESPERCHAR; k++) {
while (*VBL < 0);
while (*VBL >= 0);
}
}
}
// Wait a frame when finished
while (*VBL < 0);
while (*VBL >= 0);
}

12
util.h Normal file
View File

@ -0,0 +1,12 @@
#include <stdint.h>
#ifndef UTIL_H
#define UTIL_H
#define true 1
#define false 0
char read_applekey(void);
void spin(uint8_t x, uint8_t y);
#endif /* UTIL_H */