mirror of
https://github.com/garrettsworkshop/GWRAM.SYSTEM.git
synced 2024-06-04 16:29:31 +00:00
RC
This commit is contained in:
parent
44bd31fe50
commit
8622e2776a
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
|||
*.o
|
||||
*.sys
|
||||
obj/*.s
|
||||
.vscode/*
|
||||
|
|
46
Makefile
46
Makefile
|
@ -1,6 +1,6 @@
|
|||
cflags = -O --cpu 6502 -t apple2
|
||||
|
||||
all: GWRAM.po GWRAM.dbg.po
|
||||
all: bin/GWRAM.po bin/GWRAM.dbg.po
|
||||
|
||||
obj:
|
||||
@mkdir obj
|
||||
|
@ -10,51 +10,55 @@ bin:
|
|||
|
||||
obj/main.o: obj main.c
|
||||
cc65 main.c $(cflags) -o obj/main.s
|
||||
ca65 obj/main.s -o obj/main.o
|
||||
ca65 obj/main.s -o $@
|
||||
|
||||
obj/ram2e_hal.o: obj ram2e_hal.c
|
||||
cc65 ram2e_hal.c $(cflags) -o obj/ram2e_hal.s
|
||||
ca65 obj/ram2e_hal.s -o $@
|
||||
|
||||
obj/ram2e.o: obj ram2e.c
|
||||
cc65 ram2e.c $(cflags) -o obj/ram2e.s
|
||||
ca65 obj/ram2e.s -o obj/ram2e.o
|
||||
ca65 obj/ram2e.s -o $@
|
||||
|
||||
obj/ram2e.dbg.o: obj ram2e.c
|
||||
cc65 ram2e.c $(cflags) -o obj/ram2e.dbg.s -DSKIP_RAM2E_DETECT
|
||||
ca65 obj/ram2e.dbg.s -o obj/ram2e.dbg.o
|
||||
ca65 obj/ram2e.dbg.s -o $@
|
||||
|
||||
obj/ram2gs_asm.o: obj ram2gs_asm.s
|
||||
ca65 ram2gs_asm.s -o obj/ram2gs_asm.o
|
||||
ca65 ram2gs_asm.s -o $@
|
||||
|
||||
obj/ram2gs_hal.o: obj ram2gs_hal.c
|
||||
cc65 ram2gs_hal.c $(cflags) -o obj/ram2gs_hal.s
|
||||
ca65 obj/ram2gs_hal.s -o $@
|
||||
|
||||
obj/ram2gs.o: obj ram2gs.c
|
||||
cc65 ram2gs.c $(cflags) -o obj/ram2gs.s
|
||||
ca65 obj/ram2gs.s -o obj/ram2gs.o
|
||||
ca65 obj/ram2gs.s -o $@
|
||||
|
||||
obj/ram2gs.dbg.o: obj ram2gs.c
|
||||
cc65 ram2gs.c $(cflags) -o obj/ram2gs.dbg.s -DSKIP_RAM2GS_DETECT
|
||||
ca65 obj/ram2gs.dbg.s -o obj/ram2gs.dbg.o
|
||||
ca65 obj/ram2gs.dbg.s -o $@
|
||||
|
||||
obj/util.o: obj util.c
|
||||
cc65 util.c $(cflags) -o obj/util.s
|
||||
ca65 obj/util.s -o obj/util.o
|
||||
|
||||
#obj/ramtest.o: obj ramtest.c
|
||||
# cc65 ramtest.c $(cflags) -o obj/ramtest.s
|
||||
# ca65 obj/ramtest.s -o obj/ramtest.o
|
||||
ca65 obj/util.s -o $@
|
||||
|
||||
obj/gwconio.o: obj gwconio.s
|
||||
ca65 gwconio.s -o obj/gwconio.o
|
||||
ca65 gwconio.s -o $@
|
||||
|
||||
bin/main.sys: bin obj/main.o obj/ram2e.o obj/ram2gs.o obj/ram2gs_asm.o obj/util.o obj/gwconio.o
|
||||
ld65 -o bin/main.sys obj/main.o obj/ram2gs.o obj/ram2e.o obj/ram2gs_asm.o obj/util.o obj/gwconio.o -C apple2-system.cfg --lib apple2.lib -D __EXEHDR__=0
|
||||
bin/main.sys: bin obj/main.o obj/ram2e.o obj/ram2gs_hal.o obj/ram2gs.o obj/ram2e_hal.o obj/ram2gs_asm.o obj/util.o obj/gwconio.o
|
||||
ld65 -o $@ obj/main.o obj/ram2gs_hal.o obj/ram2gs.o obj/ram2e_hal.o obj/ram2e.o obj/ram2gs_asm.o obj/util.o obj/gwconio.o -C apple2-system.cfg --lib apple2.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 obj/gwconio.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 obj/gwconio.o -C apple2-system.cfg --lib apple2.lib -D __EXEHDR__=0
|
||||
bin/main.dbg.sys: bin obj/main.o obj/ram2e.dbg.o obj/ram2gs_hal.o obj/ram2gs.dbg.o obj/ram2e_hal.o obj/ram2gs_asm.o obj/util.o obj/gwconio.o
|
||||
ld65 -o $@ obj/main.o obj/ram2gs_hal.o obj/ram2gs.dbg.o obj/ram2e.dbg.o obj/ram2e_hal.o obj/ram2gs_asm.o obj/util.o obj/gwconio.o -C apple2-system.cfg --lib apple2.lib -D __EXEHDR__=0
|
||||
|
||||
GWRAM.po: bin/main.sys
|
||||
bin/GWRAM.po: bin/main.sys
|
||||
cp prodos140.po bin/GWRAM.po
|
||||
cat bin/main.sys | java -jar ./ac-1.6.0.jar -p bin/GWRAM.po gwram.system sys 0x2000
|
||||
cat bin/main.sys | java -jar ./ac-1.6.0.jar -p $@ gwram.system sys 0x2000
|
||||
|
||||
GWRAM.dbg.po: bin/main.dbg.sys
|
||||
bin/GWRAM.dbg.po: bin/main.dbg.sys
|
||||
cp prodos140.po bin/GWRAM.dbg.po
|
||||
cat bin/main.dbg.sys | java -jar ./ac-1.6.0.jar -p bin/GWRAM.dbg.po gwram.system sys 0x2000
|
||||
cat bin/main.dbg.sys | java -jar ./ac-1.6.0.jar -p $@ gwram.system sys 0x2000
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
|
|
BIN
bin/GWRAM.dbg.po
BIN
bin/GWRAM.dbg.po
Binary file not shown.
BIN
bin/GWRAM.po
BIN
bin/GWRAM.po
Binary file not shown.
4
bnc.sh
Executable file
4
bnc.sh
Executable file
|
@ -0,0 +1,4 @@
|
|||
make clean
|
||||
make
|
||||
cp bin/GWRAM.po /Volumes/FLOPPYEMU/GWRAM.po
|
||||
diskutil unmount /Volumes/FLOPPYEMU/
|
394
ram2e.c
394
ram2e.c
|
@ -7,314 +7,117 @@
|
|||
|
||||
#include "util.h"
|
||||
#include "gwconio.h"
|
||||
#include "ram2e_hal.h"
|
||||
|
||||
static char _rwsave[256];
|
||||
static char _rwsave0_1;
|
||||
static char _rwsave0_2;
|
||||
static char _rwsave0_3;
|
||||
static void ramworks_save() {
|
||||
__asm__("sta $C009"); // Store in ALTZP
|
||||
|
||||
// Save address 0x0000 in every bank
|
||||
__asm__("ldx #0");
|
||||
saveloop:
|
||||
__asm__("stx $C073");
|
||||
__asm__("lda $00,X");
|
||||
__asm__("sta %v,X", _rwsave);
|
||||
__asm__("inx");
|
||||
__asm__("bne %g", saveloop);
|
||||
|
||||
// Save addresses 0x0001-3 in bank 0
|
||||
__asm__("ldx #0");
|
||||
__asm__("stx $C073");
|
||||
__asm__("lda $01");
|
||||
__asm__("sta %v", _rwsave0_1);
|
||||
__asm__("lda $02");
|
||||
__asm__("sta %v", _rwsave0_2);
|
||||
__asm__("lda $03");
|
||||
__asm__("sta %v", _rwsave0_3);
|
||||
|
||||
__asm__("sta $C008"); // Don't store in ALTZP
|
||||
}
|
||||
|
||||
static void ramworks_restore() {
|
||||
__asm__("sta $C009"); // Store in ALTZP
|
||||
|
||||
// Restore address 0x0000 in every bank
|
||||
__asm__("ldx #0");
|
||||
restoreloop:
|
||||
__asm__("stx $C073");
|
||||
__asm__("lda %v,X", _rwsave);
|
||||
__asm__("sta $00,X");
|
||||
__asm__("inx");
|
||||
__asm__("bne %g", restoreloop);
|
||||
|
||||
// Restore addresses 0x0001-3 in bank 0
|
||||
__asm__("ldx #0");
|
||||
__asm__("stx $C073");
|
||||
__asm__("lda %v", _rwsave0_1);
|
||||
__asm__("sta $01");
|
||||
__asm__("lda %v", _rwsave0_2);
|
||||
__asm__("sta $02");
|
||||
__asm__("lda %v", _rwsave0_3);
|
||||
__asm__("sta $03");
|
||||
|
||||
__asm__("sta $C008"); // Don't store in ALTZP
|
||||
}
|
||||
|
||||
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
|
||||
// in preparation for command sequence
|
||||
_cmd = cmd;
|
||||
_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
|
||||
__asm__("lda #$FF");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$00");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$55");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$AA");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$C1");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$AD");
|
||||
__asm__("sta $C073");
|
||||
// Command
|
||||
__asm__("stx $C073");
|
||||
// Argument
|
||||
__asm__("sty $C073");
|
||||
|
||||
// Reset RAMWorks bank register just in case
|
||||
__asm__("lda #0");
|
||||
__asm__("sta $C073");
|
||||
}
|
||||
|
||||
/* auxram_detect() returns true if a RAMWorks memory is detected */
|
||||
static char auxram_detect() {
|
||||
// Switch to RW bank 0 for ZP
|
||||
__asm__("lda #$00"); // Get 0x00
|
||||
__asm__("sta $C009"); // Store in ALTZP
|
||||
__asm__("sta $C073"); // Set RW bank 0
|
||||
|
||||
// Store 00 FF 55 AA in RW bank 0 ZP
|
||||
__asm__("lda #$00");
|
||||
__asm__("sta $00");
|
||||
__asm__("lda #$FF");
|
||||
__asm__("sta $01");
|
||||
__asm__("lda #$55");
|
||||
__asm__("sta $02");
|
||||
__asm__("lda #$AA");
|
||||
__asm__("sta $03");
|
||||
|
||||
// Check for 00 FF 55 AA
|
||||
__asm__("lda $00");
|
||||
__asm__("cmp #$00");
|
||||
__asm__("bne %g", noramworks);
|
||||
__asm__("lda $01");
|
||||
__asm__("cmp #$FF");
|
||||
__asm__("bne %g", noramworks);
|
||||
__asm__("lda $02");
|
||||
__asm__("cmp #$55");
|
||||
__asm__("bne %g", noramworks);
|
||||
__asm__("lda $03");
|
||||
__asm__("cmp #$AA");
|
||||
__asm__("bne %g", noramworks);
|
||||
|
||||
// Found aux ram card
|
||||
__asm__("sta $C008"); // Don't store in ALTZP
|
||||
return true;
|
||||
|
||||
// Not found
|
||||
noramworks:
|
||||
__asm__("sta $C008"); // Don't store in ALTZP
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ram2e_detect() returns true if a RAM2E II has been detected */
|
||||
static uint8_t _detect;
|
||||
static char ram2e_detect() {
|
||||
#ifdef SKIP_RAM2E_DETECT
|
||||
return true;
|
||||
#endif
|
||||
__asm__("sta $C009"); // Store in ALTZP
|
||||
|
||||
// Store 0x00 at beginning of bank 0x00
|
||||
__asm__("lda #$00");
|
||||
__asm__("sta $C073");
|
||||
__asm__("sta $00");
|
||||
|
||||
// Send SetRWBankFF command
|
||||
__asm__("lda #$FF");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$00");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$55");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$AA");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$C1");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$AD");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$FF");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$00");
|
||||
__asm__("sta $C073");
|
||||
// Now bank should be 0xFF if we are running on a RAM2E II
|
||||
// Other RAMWorks cards will instead set the bank to 0x00
|
||||
|
||||
// Store 0xFF in this bank
|
||||
__asm__("lda #$FF");
|
||||
__asm__("sta $00");
|
||||
|
||||
// Go back to bank 0
|
||||
__asm__("lda #$00");
|
||||
__asm__("sta $C073");
|
||||
__asm__("sta $C073");
|
||||
|
||||
// Save result and return
|
||||
__asm__("lda $00"); // Get beginning of bank 0
|
||||
__asm__("sta $C008"); // Store in STDZP
|
||||
__asm__("sta %v", _detect); // Save in _detect
|
||||
return _detect == 0x00;
|
||||
}
|
||||
|
||||
/* ramworks_getsize() returns the number of banks of RAM2E aux memory */
|
||||
static uint8_t _rwsize;
|
||||
static uint8_t _rwnot16mb;
|
||||
static uint16_t ramworks_getsize() {
|
||||
_rwnot16mb = 1; // Set "not 16 mb" flag
|
||||
|
||||
// Store bank number at address 0 in each bnak
|
||||
__asm__("sta $C009"); // ALTZP
|
||||
__asm__("ldy #$FF"); // Start at bank 0xFF
|
||||
BankSetLoop:
|
||||
__asm__("sty $C073"); // Set bank
|
||||
__asm__("sty $00"); // Store bank number at 0
|
||||
__asm__("dey"); // Prev. bank
|
||||
__asm__("cpy #$FF"); // Have we wrapped around?
|
||||
__asm__("bne %g", BankSetLoop); // If not, repeat
|
||||
|
||||
// Count banks with matching bank number
|
||||
__asm__("ldy #$00"); // Y is bank
|
||||
__asm__("ldx #$00"); // X is count
|
||||
CountLoop:
|
||||
__asm__("sty $C073"); // Set bank
|
||||
__asm__("cpy $00"); // Is bank num stored at address 0?
|
||||
__asm__("bne %g", AfterInc); // If not, skip increment
|
||||
__asm__("inx"); // If so, increment bank count
|
||||
__asm__("bne %g", AfterInc); // Skip next if x!=0
|
||||
__asm__("stx %v", _rwnot16mb); // Othwerwise rolled over so clear rwnot16mb
|
||||
AfterInc:
|
||||
__asm__("iny"); // Move to next bank
|
||||
__asm__("bne %g", CountLoop); // Repeat if not on bank 0
|
||||
|
||||
// Done. Switch back to regular zeropage and get result.
|
||||
__asm__("sta $C008"); // STDZP
|
||||
__asm__("stx %v", _rwsize); // _rwsize = X (bank count)
|
||||
|
||||
if (_rwnot16mb) { return _rwsize; }
|
||||
else { return 256; }
|
||||
}
|
||||
|
||||
/* set_mask_temp(...) sends the "Set RAMWorks Capacity Mask" to the RAM2E */
|
||||
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); }
|
||||
|
||||
/* 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) {
|
||||
int i;
|
||||
// Shift mask OR'd with data register clock pulse trigger into UFMD twice
|
||||
for (i = 0; i < 2; i++) {
|
||||
ufm_bitbang(0x80 | ((mask >> 1) & 0x40));
|
||||
ufm_bitbang(0x80 | ((mask >> 0) & 0x40));
|
||||
ufm_bitbang(0x80 | ((mask << 1) & 0x40));
|
||||
ufm_bitbang(0x80 | ((mask << 2) & 0x40));
|
||||
ufm_bitbang(0x80 | ((mask << 3) & 0x40));
|
||||
ufm_bitbang(0x80 | ((mask << 4) & 0x40));
|
||||
ufm_bitbang(0x80 | ((mask << 5) & 0x40));
|
||||
ufm_bitbang(0x80 | ((mask << 6) & 0x40));
|
||||
}
|
||||
// Program UFM
|
||||
ufm_program();
|
||||
}
|
||||
|
||||
static void menu(uint16_t bankcount)
|
||||
static void menu()
|
||||
{
|
||||
gwcputsxy(5, 1, "-- RAM2E Capacity Settings --");
|
||||
clrscr(); // Clear screen
|
||||
|
||||
gwcputsxy(5, 1, "-- RAM2E Capacity Settings --");
|
||||
|
||||
gwcputsxy(1, 6, "Select desired memory capacity:");
|
||||
|
||||
gwcputsxy(4, 7, "1. 64 kilobytes");
|
||||
gwcputsxy(4, 8, "2. 512 kilobytes");
|
||||
gwcputsxy(4, 9, "3. 1 megabyte");
|
||||
gwcputsxy(4, 10, "4. 4 megabytes");
|
||||
gwcputsxy(4, 11, "5. 8 megabytes");
|
||||
|
||||
gwcputsxy(1, 17, "Capacity will be saved until power-off.");
|
||||
|
||||
gwcputsxy(1, 19, "To remember capacity setting in");
|
||||
gwcputsxy(1, 20, "nonvolatile memory, press Apple+number.");
|
||||
|
||||
gwcputsxy(1, 22, "Press [Q] to quit without saving.");
|
||||
}
|
||||
|
||||
static void menu_size(uint16_t bankcount, char has16m) {
|
||||
if (bankcount < 2) { gotoxy(5, 3); }
|
||||
else { gotoxy(4, 3); }
|
||||
gwcputs("Current RAM2E capacity: ");
|
||||
printf("%d", bankcount * 64);
|
||||
gwcputs(" kB");
|
||||
|
||||
gwcputsxy(1, 5, "Select desired memory capacity:");
|
||||
if(has16m) { gwcputsxy(4, 12, "6. 16 megabytes"); }
|
||||
}
|
||||
|
||||
gwcputsxy(4, 7, "1. 64 kilobytes");
|
||||
gwcputsxy(4, 9, "2. 512 kilobytes");
|
||||
gwcputsxy(4, 11, "3. 1 megabyte");
|
||||
gwcputsxy(4, 13, "4. 4 megabytes");
|
||||
gwcputsxy(4, 15, "5. 8 megabytes");
|
||||
|
||||
gwcputsxy(1, 18, "Capacity will be saved until power-off.");
|
||||
|
||||
gwcputsxy(1, 20, "To remember capacity setting in");
|
||||
gwcputsxy(1, 21, "nonvolatile memory, press Apple+number.");
|
||||
|
||||
gwcputsxy(1, 23, "Press [Q] to quit without saving.");
|
||||
static void menu_led(char enled) {
|
||||
if (enled) {
|
||||
gwcputsxy(1, 14, "LED enabled. Press [L] to disable LED.");
|
||||
} else {
|
||||
gwcputsxy(1, 14, "LED disabled. Press [L] to enable LED.");
|
||||
}
|
||||
}
|
||||
|
||||
int ram2e_main(void)
|
||||
{
|
||||
char mask;
|
||||
char nvm;
|
||||
int reset_count;
|
||||
char type;
|
||||
uint16_t bankcount;
|
||||
char mask = 0;
|
||||
char has16m = false;
|
||||
char hasled = false;
|
||||
char enled = false;
|
||||
|
||||
char nvm = false;
|
||||
int reset_count = 0;
|
||||
|
||||
// Check for RAM2E
|
||||
ramworks_save(); // Save what will be clobbered
|
||||
if(!auxram_detect() || !ram2e_detect()) {
|
||||
if (auxram_detect()) {
|
||||
if (ram2e_detect(0xFF)) { // MAX
|
||||
type = 0xFF;
|
||||
/*} else if (ram2e_detect(0xFE)) { // SPI
|
||||
type = 0xFE;*/
|
||||
} else if (ram2e_detect(0xFD)) { // MachXO2
|
||||
type = 0xFD;
|
||||
} else { type = 0; }
|
||||
}
|
||||
|
||||
if (type == 0) {
|
||||
#ifndef SKIP_RAM2E_DETECT
|
||||
ramworks_restore();
|
||||
// If no RAM2E, show an error message and quit
|
||||
gwcputsxy(0, 8, " No RAM2E II detected.");
|
||||
gwcputsxy(0, 8, " No RAM2E II detected.");
|
||||
gwcputsxy(0, 10, " Press any key to quit.");
|
||||
cgetc(); // Wait for key
|
||||
clrscr(); // Clear screen before quitting
|
||||
return EXIT_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get size and print menu
|
||||
// Set chip type
|
||||
ram2e_hal_set_type(type);
|
||||
|
||||
// Print menu
|
||||
menu();
|
||||
|
||||
// Detect and print current capacity plus 16 MB option
|
||||
#ifndef SKIP_RAM2E_DETECT
|
||||
bankcount = ramworks_getsize();
|
||||
menu(bankcount); // Print menu
|
||||
// If set for 8 MB, check for 16 MB capability
|
||||
if (bankcount >= 128) {
|
||||
ram2e_set_mask(0xFF);
|
||||
has16m = ramworks_getsize() == 256;
|
||||
ram2e_set_mask(0x7F);
|
||||
}
|
||||
#else
|
||||
bankcount = 128;
|
||||
#endif
|
||||
menu_size(bankcount, has16m); // Print size
|
||||
|
||||
// Detect and print LED menu
|
||||
#ifndef SKIP_RAM2E_DETECT
|
||||
hasled = ram2e_detect(0xF0);
|
||||
if (hasled) {
|
||||
enled = ram2e_detect(0xE3);
|
||||
menu_led(enled);
|
||||
}
|
||||
#else
|
||||
hasled = true;
|
||||
#endif
|
||||
|
||||
ramworks_restore(); // Restore RAMWorks contents
|
||||
|
||||
// Get user choice from menu
|
||||
mask = 0;
|
||||
nvm = 0;
|
||||
reset_count = 0;
|
||||
while (true) {
|
||||
// Set capacity mask or quit according to keypress.
|
||||
switch (toupper(cgetc() & 0x7F)) {
|
||||
|
@ -327,7 +130,28 @@ int ram2e_main(void)
|
|||
case '3': mask = 0x0F; break;
|
||||
case '4': mask = 0x3F; break;
|
||||
case '5': mask = 0x7F; break;
|
||||
case 'R': {
|
||||
case '6': {
|
||||
if (has16m) { mask = 0xFF; break; }
|
||||
else { continue; }
|
||||
#ifdef SKIP_RAM2E_DETECT
|
||||
} case '7': {
|
||||
menu_size(bankcount, 1);
|
||||
continue;
|
||||
#endif
|
||||
} case 'L': {
|
||||
if (hasled) {
|
||||
enled = !enled;
|
||||
ram2e_set_led(enled);
|
||||
menu_led(enled);
|
||||
if (enled) {
|
||||
wait(1);
|
||||
ram2e_flashled(10);
|
||||
wait(10);
|
||||
ram2e_flashled(10);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} case 'R': {
|
||||
reset_count++;
|
||||
if (reset_count >= 25) {
|
||||
// Show message about resetting.
|
||||
|
@ -335,8 +159,8 @@ int ram2e_main(void)
|
|||
gwcputsxy(1, 8, "Resetting RAM2E settings.");
|
||||
gwcputsxy(1, 9, "Do not turn off your Apple.");
|
||||
|
||||
ufm_erase(); // Erase RAM2E settings memory
|
||||
set_mask_temp(0x7F); // Set mask to default (0x7F)
|
||||
ram2e_erase(); // Erase RAM2E settings memory
|
||||
ram2e_set_mask(0x7F); // Set mask to default (0x7F)
|
||||
|
||||
// Wait for >= 500ms on even the fastest systems.
|
||||
spin(32, 8);
|
||||
|
@ -356,7 +180,7 @@ int ram2e_main(void)
|
|||
}
|
||||
|
||||
// Set capacity in volatile memory.
|
||||
set_mask_temp(mask);
|
||||
ram2e_set_mask(mask);
|
||||
|
||||
// Clear screen in preparation to show saving or success message.
|
||||
clrscr();
|
||||
|
@ -366,9 +190,11 @@ int ram2e_main(void)
|
|||
gwcputsxy(1, 8, "Saving RAM2E capacity setting.");
|
||||
gwcputsxy(1, 9, "Do not turn off your Apple.");
|
||||
// Save capacity in nonvolatile memory.
|
||||
set_nvm(mask);
|
||||
ram2e_save_start(mask, enled);
|
||||
// Wait for >= 500ms on even the fastest systems.
|
||||
spin(32, 8);
|
||||
// Finish saving
|
||||
ram2e_save_end(mask, enled);
|
||||
// Print success message
|
||||
clrscr(); // Clear screen
|
||||
gwcputsxy(1, 8, "RAM2E capacity saved successfully.");
|
||||
|
|
242
ram2e_hal.c
Normal file
242
ram2e_hal.c
Normal file
|
@ -0,0 +1,242 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include "util.h"
|
||||
#include "ram2e_hal.h"
|
||||
|
||||
static char _cmd_cmd;
|
||||
static char _cmd_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
|
||||
// in preparation for command sequence
|
||||
_cmd_cmd = cmd;
|
||||
_cmd_arg = arg;
|
||||
__asm__("ldx %v", _cmd_cmd); // X = command
|
||||
__asm__("ldy %v", _cmd_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
|
||||
__asm__("lda #$FF");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$00");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$55");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$AA");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$C1");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$AD");
|
||||
__asm__("sta $C073");
|
||||
// Command
|
||||
__asm__("stx $C073");
|
||||
// Argument
|
||||
__asm__("sty $C073");
|
||||
|
||||
// Reset RAMWorks bank register just in case
|
||||
__asm__("lda #0");
|
||||
__asm__("sta $C073");
|
||||
}
|
||||
|
||||
/* auxram_detect() returns true if a RAMWorks memory is detected */
|
||||
char auxram_detect() {
|
||||
// Switch to RW bank 0 for ZP
|
||||
__asm__("lda #$00"); // Get 0x00
|
||||
__asm__("sta $C009"); // Store in ALTZP
|
||||
__asm__("sta $C073"); // Set RW bank 0
|
||||
|
||||
// Store 00 FF 55 AA in RW bank 0 ZP
|
||||
__asm__("lda #$00");
|
||||
__asm__("sta $00");
|
||||
__asm__("lda #$FF");
|
||||
__asm__("sta $01");
|
||||
__asm__("lda #$55");
|
||||
__asm__("sta $02");
|
||||
__asm__("lda #$AA");
|
||||
__asm__("sta $03");
|
||||
|
||||
// Check for 00 FF 55 AA
|
||||
__asm__("lda $00");
|
||||
__asm__("cmp #$00");
|
||||
__asm__("bne %g", noramworks);
|
||||
__asm__("lda $01");
|
||||
__asm__("cmp #$FF");
|
||||
__asm__("bne %g", noramworks);
|
||||
__asm__("lda $02");
|
||||
__asm__("cmp #$55");
|
||||
__asm__("bne %g", noramworks);
|
||||
__asm__("lda $03");
|
||||
__asm__("cmp #$AA");
|
||||
__asm__("bne %g", noramworks);
|
||||
|
||||
// Found aux ram card
|
||||
__asm__("sta $C008"); // Don't store in ALTZP
|
||||
return true;
|
||||
|
||||
// Not found
|
||||
noramworks:
|
||||
__asm__("sta $C008"); // Don't store in ALTZP
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ram2e_detect() returns true if a RAM2E II has been detected */
|
||||
static uint8_t _detect;
|
||||
char ram2e_detect(char command) {
|
||||
#ifdef SKIP_RAM2E_DETECT
|
||||
return true;
|
||||
#endif
|
||||
// Move command into X register
|
||||
_detect = command;
|
||||
__asm__("lda %v", _detect); // Save in _detect
|
||||
__asm__("tax");
|
||||
|
||||
// Store in ALTZP
|
||||
__asm__("sta $C009");
|
||||
|
||||
// Store 0x00 at beginning of bank 0x00
|
||||
__asm__("lda #$00");
|
||||
__asm__("sta $C073");
|
||||
__asm__("sta $00");
|
||||
|
||||
// Send SetRWBankFF-class command
|
||||
__asm__("lda #$FF");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$00");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$55");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$AA");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$C1");
|
||||
__asm__("sta $C073");
|
||||
__asm__("lda #$AD");
|
||||
__asm__("sta $C073");
|
||||
__asm__("stx $C073");
|
||||
__asm__("lda #$00");
|
||||
__asm__("sta $C073");
|
||||
// Now bank should be 0xFF if we are running on a RAM2E II
|
||||
// Other RAMWorks cards will instead set the bank to 0x00
|
||||
|
||||
// Store 0xFF in this bank
|
||||
__asm__("lda #$FF");
|
||||
__asm__("sta $00");
|
||||
|
||||
// Go back to bank 0
|
||||
__asm__("lda #$00");
|
||||
__asm__("sta $C073");
|
||||
__asm__("sta $C073");
|
||||
|
||||
// Save result and return
|
||||
__asm__("lda $00"); // Get beginning of bank 0
|
||||
__asm__("sta $C008"); // Store in STDZP
|
||||
__asm__("sta %v", _detect); // Save in _detect
|
||||
return _detect == 0x00;
|
||||
}
|
||||
|
||||
/* ramworks_getsize() returns the number of banks of RAM2E aux memory */
|
||||
static uint8_t _rwsize;
|
||||
static uint8_t _rwnot16mb;
|
||||
uint16_t ramworks_getsize() {
|
||||
_rwnot16mb = 1; // Set "not 16 mb" flag
|
||||
|
||||
// Store bank number at address 0 in each bnak
|
||||
__asm__("sta $C009"); // ALTZP
|
||||
__asm__("ldy #$FF"); // Start at bank 0xFF
|
||||
BankSetLoop:
|
||||
__asm__("sty $C073"); // Set bank
|
||||
__asm__("sty $00"); // Store bank number at 0
|
||||
__asm__("dey"); // Prev. bank
|
||||
__asm__("cpy #$FF"); // Have we wrapped around?
|
||||
__asm__("bne %g", BankSetLoop); // If not, repeat
|
||||
|
||||
// Count banks with matching bank number
|
||||
__asm__("ldy #$00"); // Y is bank
|
||||
__asm__("ldx #$00"); // X is count
|
||||
CountLoop:
|
||||
__asm__("sty $C073"); // Set bank
|
||||
__asm__("cpy $00"); // Is bank num stored at address 0?
|
||||
__asm__("bne %g", AfterInc); // If not, skip increment
|
||||
__asm__("inx"); // If so, increment bank count
|
||||
__asm__("bne %g", AfterInc); // Skip next if x!=0
|
||||
__asm__("stx %v", _rwnot16mb); // Othwerwise rolled over so clear rwnot16mb
|
||||
AfterInc:
|
||||
__asm__("iny"); // Move to next bank
|
||||
__asm__("bne %g", CountLoop); // Repeat if not on bank 0
|
||||
|
||||
// Done. Switch back to regular zeropage and get result.
|
||||
__asm__("sta $C008"); // STDZP
|
||||
__asm__("stx %v", _rwsize); // _rwsize = X (bank count)
|
||||
|
||||
if (_rwnot16mb) { return _rwsize; }
|
||||
else { return 256; }
|
||||
}
|
||||
|
||||
/* ram2e_set_mask(...) sends the "Set RAMWorks Capacity Mask" to the RAM2E */
|
||||
void ram2e_set_mask(char mask) { ram2e_cmd(0xE0, mask); }
|
||||
|
||||
/* ram2e_set_led(...) */
|
||||
void ram2e_set_led(char enled) { ram2e_cmd(0xE2, enled); }
|
||||
|
||||
|
||||
static void ram2e_flashled1() {
|
||||
__asm__("sta $C009"); // ALTZP
|
||||
|
||||
// Save address 0x0000 in every bank
|
||||
__asm__("lda $0");
|
||||
__asm__("lda $0");
|
||||
__asm__("lda $0");
|
||||
__asm__("lda $0");
|
||||
__asm__("lda $0");
|
||||
__asm__("lda $0");
|
||||
__asm__("lda $0");
|
||||
__asm__("lda $0");
|
||||
|
||||
__asm__("sta $C008"); // No ALTZP
|
||||
}
|
||||
void ram2e_flashled(char frames) {
|
||||
char i;
|
||||
for (i = 0; i < frames; i++) {
|
||||
unsigned int l;
|
||||
for (l = 0; *VBL < 0 && l < 2500; l++) { ram2e_flashled1(); }
|
||||
for (l = 0; *VBL >= 0 && l < 2500; l++) { ram2e_flashled1(); }
|
||||
}
|
||||
}
|
||||
|
||||
#include "ram2e_hal_max.c"
|
||||
#include "ram2e_hal_spi.c"
|
||||
#include "ram2e_hal_lcmxo2.c"
|
||||
|
||||
static char _type;
|
||||
void ram2e_hal_set_type(char type) { _type = type; }
|
||||
|
||||
void ram2e_erase() {
|
||||
switch (_type) {
|
||||
case 0xFF: ram2e_max_erase(); break; // Altera MAX II / V
|
||||
case 0xFE: ram2e_spi_erase(); break; // Lattice MachXO / iCE40 / AGM AG256
|
||||
case 0xFD: ram2e_lcmxo2_erase(); break; // Lattice MachXO2
|
||||
}
|
||||
}
|
||||
void ram2e_save_start(char mask, char enled) {
|
||||
switch (_type) {
|
||||
case 0xFF: ram2e_max_save(mask, enled); break; // Altera MAX II / V
|
||||
case 0xFE: ram2e_spi_erase(); break; // Lattice MachXO / iCE40 / AGM AG256
|
||||
case 0xFD: ram2e_lcmxo2_erase(); break; // Lattice MachXO2
|
||||
}
|
||||
}
|
||||
void ram2e_save_end(char mask, char enled) {
|
||||
switch (_type) {
|
||||
case 0xFF: break; // Altera MAX II / V
|
||||
case 0xFE: ram2e_spi_save(mask, enled); break; // Lattice MachXO / iCE40 / AGM AG256
|
||||
case 0xFD: ram2e_lcmxo2_save(mask, enled); break; // Lattice MachXO2
|
||||
}
|
||||
}
|
||||
|
72
ram2e_hal.h
Normal file
72
ram2e_hal.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
#ifndef RAM2GS_HAL_H
|
||||
#define RAM2GS_HAL_H
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
|
||||
char auxram_detect();
|
||||
char ram2e_detect(char type);
|
||||
uint16_t ramworks_getsize();
|
||||
void ram2e_set_mask(char mask);
|
||||
void ram2e_set_led(char enled);
|
||||
void ram2e_flashled(char frames);
|
||||
|
||||
void ram2e_hal_set_type(char type);
|
||||
void ram2e_erase();
|
||||
void ram2e_save_start(char mask, char enled);
|
||||
void ram2e_save_end(char mask, char enled);
|
||||
|
||||
static char _rwsave[256];
|
||||
static char _rwsave0_1;
|
||||
static char _rwsave0_2;
|
||||
static char _rwsave0_3;
|
||||
static void ramworks_save() {
|
||||
__asm__("sta $C009"); // Store in ALTZP
|
||||
|
||||
// Save address 0x0000 in every bank
|
||||
__asm__("ldx #0");
|
||||
saveloop:
|
||||
__asm__("stx $C073");
|
||||
__asm__("lda $00,X");
|
||||
__asm__("sta %v,X", _rwsave);
|
||||
__asm__("inx");
|
||||
__asm__("bne %g", saveloop);
|
||||
|
||||
// Save addresses 0x0001-3 in bank 0
|
||||
__asm__("ldx #0");
|
||||
__asm__("stx $C073");
|
||||
__asm__("lda $01");
|
||||
__asm__("sta %v", _rwsave0_1);
|
||||
__asm__("lda $02");
|
||||
__asm__("sta %v", _rwsave0_2);
|
||||
__asm__("lda $03");
|
||||
__asm__("sta %v", _rwsave0_3);
|
||||
|
||||
__asm__("sta $C008"); // Don't store in ALTZP
|
||||
}
|
||||
|
||||
static void ramworks_restore() {
|
||||
__asm__("sta $C009"); // Store in ALTZP
|
||||
|
||||
// Restore address 0x0000 in every bank
|
||||
__asm__("ldx #0");
|
||||
restoreloop:
|
||||
__asm__("stx $C073");
|
||||
__asm__("lda %v,X", _rwsave);
|
||||
__asm__("sta $00,X");
|
||||
__asm__("inx");
|
||||
__asm__("bne %g", restoreloop);
|
||||
|
||||
// Restore addresses 0x0001-3 in bank 0
|
||||
__asm__("ldx #0");
|
||||
__asm__("stx $C073");
|
||||
__asm__("lda %v", _rwsave0_1);
|
||||
__asm__("sta $01");
|
||||
__asm__("lda %v", _rwsave0_2);
|
||||
__asm__("sta $02");
|
||||
__asm__("lda %v", _rwsave0_3);
|
||||
__asm__("sta $03");
|
||||
|
||||
__asm__("sta $C008"); // Don't store in ALTZP
|
||||
}
|
||||
|
||||
#endif
|
89
ram2e_hal_lcmxo2.c
Normal file
89
ram2e_hal_lcmxo2.c
Normal file
|
@ -0,0 +1,89 @@
|
|||
/* _spi_erase(...) */
|
||||
static void ram2e_lcmxo2_rw(char we, char addr, char data) {
|
||||
ram2e_cmd(0xEC, data);
|
||||
ram2e_cmd(0xEC, addr);
|
||||
ram2e_cmd(0xED, we ? 1 : 0);
|
||||
}
|
||||
static void ram2e_lcmxo2_open() { ram2e_lcmxo2_rw(1, 0x70, 0x80); }
|
||||
static void ram2e_lcmxo2_close() { ram2e_lcmxo2_rw(1, 0x70, 0x00); }
|
||||
static void ram2e_lcmxo2_cmd_op3(char cmd, char op1, char op2, char op3) {
|
||||
ram2e_lcmxo2_open();
|
||||
ram2e_lcmxo2_rw(1, 0x71, cmd); // Command
|
||||
ram2e_lcmxo2_rw(1, 0x71, op1); // Operand 1/3
|
||||
ram2e_lcmxo2_rw(1, 0x71, op2); // Operand 2/3
|
||||
ram2e_lcmxo2_rw(1, 0x71, op3); // Operand 3/3
|
||||
}
|
||||
|
||||
static void ram2e_lcmxo2_encfg() {
|
||||
ram2e_lcmxo2_cmd_op3(0x74, 0x08, 0x00, 0x00);
|
||||
ram2e_lcmxo2_close();
|
||||
}
|
||||
static void ram2e_lcmxo2_discfg() {
|
||||
ram2e_lcmxo2_cmd_op3(0x26, 0x08, 0x00, 0x00);
|
||||
ram2e_lcmxo2_close();
|
||||
}
|
||||
static void ram2e_lcmxo2_bypass() {
|
||||
ram2e_lcmxo2_open();
|
||||
ram2e_lcmxo2_rw(1, 0x71, 0xFF); // Command
|
||||
ram2e_lcmxo2_close();
|
||||
}
|
||||
static void ram2e_lcmxo2_pollstat() {
|
||||
ram2e_lcmxo2_cmd_op3(0x3C, 0x00, 0x00, 0x00);
|
||||
ram2e_lcmxo2_rw(0, 0x73, 0x00); // Data 1/4
|
||||
ram2e_lcmxo2_rw(0, 0x73, 0x00); // Data 2/4
|
||||
ram2e_lcmxo2_rw(0, 0x73, 0x00); // Data 3/4
|
||||
ram2e_lcmxo2_rw(0, 0x73, 0x00); // Data 4/4
|
||||
ram2e_lcmxo2_close();
|
||||
}
|
||||
static void ram2e_lcmxo2_erase() {
|
||||
// Enable configuration interface
|
||||
ram2e_lcmxo2_encfg();
|
||||
// Poll status register
|
||||
ram2e_lcmxo2_pollstat();
|
||||
|
||||
// Erase UFM
|
||||
ram2e_lcmxo2_cmd_op3(0xCB, 0x00, 0x00, 0x00);
|
||||
ram2e_lcmxo2_close();
|
||||
}
|
||||
static void ram2e_lcmxo2_save(char mask, char enled) {
|
||||
char i;
|
||||
// Poll status register
|
||||
ram2e_lcmxo2_pollstat();
|
||||
// Disable configuration interface
|
||||
ram2e_lcmxo2_discfg();
|
||||
// Bypass
|
||||
ram2e_lcmxo2_bypass();
|
||||
// Enable configuration interface
|
||||
ram2e_lcmxo2_encfg();
|
||||
// Poll status register
|
||||
ram2e_lcmxo2_pollstat();
|
||||
|
||||
// Set UFM address
|
||||
ram2e_lcmxo2_cmd_op3(0xB4, 0x00, 0x00, 0x00);
|
||||
ram2e_lcmxo2_rw(1, 0x71, 0x40); // Data 1/4
|
||||
ram2e_lcmxo2_rw(1, 0x71, 0x00); // Data 2/4
|
||||
ram2e_lcmxo2_rw(1, 0x71, 0x00); // Data 3/4
|
||||
ram2e_lcmxo2_rw(1, 0x71, 190); // Data 4/4
|
||||
ram2e_lcmxo2_close();
|
||||
|
||||
// Write UFM page
|
||||
ram2e_lcmxo2_cmd_op3(0xC9, 0x00, 0x00, 0x01);
|
||||
// Data 0
|
||||
mask = (mask & 0x80) | (~mask & 0x7F);
|
||||
ram2e_lcmxo2_rw(1, 0x71, mask);
|
||||
// Data 1
|
||||
if (enled) ram2e_lcmxo2_rw(1, 0x71, 1);
|
||||
else ram2e_lcmxo2_rw(1, 0x71, 0);
|
||||
// Data 2-15
|
||||
for (i = 2; i < 16; i++) {
|
||||
ram2e_lcmxo2_rw(1, 0x71, 0x00);
|
||||
}
|
||||
ram2e_lcmxo2_close();
|
||||
|
||||
// Poll status register
|
||||
ram2e_lcmxo2_pollstat();
|
||||
// Disable configuration interface
|
||||
ram2e_lcmxo2_discfg();
|
||||
// Bypass
|
||||
ram2e_lcmxo2_bypass();
|
||||
}
|
34
ram2e_hal_max.c
Normal file
34
ram2e_hal_max.c
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* ram2e_max_bitbang(...) sends the "Set UFM Bitbang Outputs" to the RAM2E */
|
||||
static void ram2e_max_bitbang(char bitbang) { ram2e_cmd(0xEA, bitbang); }
|
||||
|
||||
/* ram2e_max_program(...) sends the "UFM Program Once" command to the RAM2E */
|
||||
static void ram2e_max_program() { ram2e_cmd(0xEF, 0x00); }
|
||||
|
||||
/* ram2e_max_erase(...) sends the "UFM Erase Once" command to the RAM2E */
|
||||
static void ram2e_max_erase() { ram2e_cmd(0xEE, 0x00); }
|
||||
|
||||
/* ram2e_max_save(...) */
|
||||
static void ram2e_max_save(char mask, char enled) {
|
||||
char i;
|
||||
char led;
|
||||
if (mask == 0xFF) { mask = 0x80; } // Encode 0xFF mask properly
|
||||
|
||||
// Shift mask into UFMD
|
||||
for (i = 0; i < 8; i++) {
|
||||
ram2e_max_bitbang(0x80 | ((mask << (i-1)) & 0x40));
|
||||
}
|
||||
|
||||
// Shift LED setting into UFMD
|
||||
if (( enled && (mask >> 7)) ||
|
||||
(!enled && !(mask >> 7))) { led = 0x80; }
|
||||
else { led = 0xC0; }
|
||||
ram2e_max_bitbang(led);
|
||||
|
||||
// Shift low six bits of mask into UFMD again
|
||||
for (i = 1; i < 8; i++) {
|
||||
ram2e_max_bitbang(0x80 | ((mask << (i-1)) & 0x40));
|
||||
}
|
||||
|
||||
// Program UFM
|
||||
ram2e_max_program();
|
||||
}
|
42
ram2e_hal_spi.c
Normal file
42
ram2e_hal_spi.c
Normal file
|
@ -0,0 +1,42 @@
|
|||
static void ram2e_spi_select() { ram2e_cmd(0xEB, 0x04); }
|
||||
static void ram2e_spi_deselect() { ram2e_cmd(0xEB, 0x00); }
|
||||
static void ram2e_spi_tx8(char data) {
|
||||
char i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
char d = (data >> (7-i)) & 1;
|
||||
d <<= 1;
|
||||
d |= 0x04;
|
||||
ram2e_cmd(0xEB, d);
|
||||
d |= 0x01;
|
||||
ram2e_cmd(0xEB, d);
|
||||
}
|
||||
}
|
||||
static void ram2e_spi_wren() {
|
||||
ram2e_spi_deselect();
|
||||
ram2e_spi_select();
|
||||
ram2e_spi_tx8(0x06); // 0x06 is write enable
|
||||
ram2e_spi_deselect();
|
||||
}
|
||||
static void ram2e_spi_erase() {
|
||||
ram2e_spi_wren();
|
||||
ram2e_spi_select();
|
||||
ram2e_spi_tx8(0x20); // 0x20 is sector erase (4 kB)
|
||||
ram2e_spi_tx8(0x00); // address[23:16]
|
||||
ram2e_spi_tx8(0x10); // address[15:8]
|
||||
ram2e_spi_tx8(0x00); // address[7:0]
|
||||
ram2e_spi_deselect();
|
||||
}
|
||||
static void ram2e_spi_save(char en8meg, char enled) {
|
||||
ram2e_spi_wren();
|
||||
ram2e_spi_select();
|
||||
ram2e_spi_tx8(0x02); // 0x02 is page (byte) program
|
||||
ram2e_spi_tx8(0x00); // address[23:16]
|
||||
ram2e_spi_tx8(0x10); // address[15:8]
|
||||
ram2e_spi_tx8(0x00); // address[7:0]
|
||||
// data[7:0]
|
||||
if (!en8meg && !enled) { ram2e_spi_tx8(0x7F); }
|
||||
else if (!en8meg && enled) { ram2e_spi_tx8(0x3F); }
|
||||
else if ( en8meg && !enled) { ram2e_spi_tx8(0xFF); }
|
||||
else if ( en8meg && enled) { ram2e_spi_tx8(0xBF); }
|
||||
ram2e_spi_deselect();
|
||||
}
|
178
ram2gs.c
178
ram2gs.c
|
@ -7,119 +7,10 @@
|
|||
|
||||
#include "util.h"
|
||||
#include "gwconio.h"
|
||||
#include "ram2gs_asm.h"
|
||||
|
||||
static void ram2gs_set(char en8meg, char enled) {
|
||||
char cmd = 0x10;
|
||||
if (en8meg) { cmd |= 0x01; }
|
||||
if (enled) { cmd |= 0x02; }
|
||||
ram2gs_cmd(cmd);
|
||||
}
|
||||
|
||||
static void ram2gs_max_erase() { ram2gs_cmd(0x28); }
|
||||
static void ram2gs_max_set_nvm(char en8meg, char enled) {
|
||||
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);
|
||||
}
|
||||
|
||||
if (enled) {
|
||||
// Clock in 0 to enable LED
|
||||
ram2gs_cmd(0x20);
|
||||
ram2gs_cmd(0x22);
|
||||
} else {
|
||||
// Clock in 1 to disable LED
|
||||
ram2gs_cmd(0x21);
|
||||
ram2gs_cmd(0x23);
|
||||
}
|
||||
|
||||
// Clock in 13 dummy "1"s
|
||||
for (i = 0; i < 13; i++) {
|
||||
ram2gs_cmd(0x21);
|
||||
ram2gs_cmd(0x23);
|
||||
}
|
||||
|
||||
// Program
|
||||
ram2gs_cmd(0x24);
|
||||
}
|
||||
|
||||
static void ram2gs_spi_select() { ram2gs_cmd(0x34); }
|
||||
static void ram2gs_spi_deselect() { ram2gs_cmd(0x30); }
|
||||
static void ram2gs_spi_tx8(char data) {
|
||||
char i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
ram2gs_cmd(0x34 + ((data >> (7-i)) & 1));
|
||||
ram2gs_cmd(0x36 + ((data >> (7-i)) & 1));
|
||||
}
|
||||
}
|
||||
static void ram2gs_spi_wren() {
|
||||
ram2gs_spi_deselect();
|
||||
ram2gs_spi_select();
|
||||
ram2gs_spi_tx8(0x06); // 0x06 is write enable
|
||||
ram2gs_spi_deselect();
|
||||
}
|
||||
static void ram2gs_spi_erase() {
|
||||
ram2gs_spi_wren();
|
||||
ram2gs_spi_select();
|
||||
ram2gs_spi_tx8(0x20); // 0x20 is sector erase (4 kB)
|
||||
ram2gs_spi_tx8(0x00); // address[23:16]
|
||||
ram2gs_spi_tx8(0x10); // address[15:8]
|
||||
ram2gs_spi_tx8(0x00); // address[7:0]
|
||||
ram2gs_spi_deselect();
|
||||
}
|
||||
static void ram2gs_spi_set_nvm(char en8meg, char enled) {
|
||||
ram2gs_spi_erase(); // First erase
|
||||
spin(33, 8); // Wait for >= 500ms on even the fastest systems.
|
||||
ram2gs_spi_wren();
|
||||
ram2gs_spi_select();
|
||||
ram2gs_spi_tx8(0x02); // 0x02 is page (byte) program
|
||||
ram2gs_spi_tx8(0x00); // address[23:16]
|
||||
ram2gs_spi_tx8(0x10); // address[15:8]
|
||||
ram2gs_spi_tx8(0x00); // address[7:0]
|
||||
// data[7:0]
|
||||
if (!en8meg && !enled) { ram2gs_spi_tx8(0x7F); }
|
||||
else if (!en8meg && enled) { ram2gs_spi_tx8(0x3F); }
|
||||
else if ( en8meg && !enled) { ram2gs_spi_tx8(0xFF); }
|
||||
else if ( en8meg && enled) { ram2gs_spi_tx8(0xBF); }
|
||||
ram2gs_spi_deselect();
|
||||
}
|
||||
|
||||
static void ram2gs_erase(char typecode) {
|
||||
switch (typecode) {
|
||||
case 0x00: ram2gs_max_erase(); break; // Altera MAX II / V
|
||||
case 0x04: ram2gs_spi_erase(); break; // Lattice MachXO / iCE40 / AGM AG256
|
||||
//case 0x08: ram2gs_erase_lcmxo2(); break; // Lattice MachXO2
|
||||
}
|
||||
}
|
||||
static void ram2gs_set_nvm(char typecode, char en8meg, char enled) {
|
||||
switch (typecode) {
|
||||
case 0x00: ram2gs_max_set_nvm(en8meg, enled); break; // Altera MAX II / V
|
||||
case 0x04: ram2gs_spi_set_nvm(en8meg, enled); break; // Lattice MachXO / iCE40 / AGM AG256
|
||||
//case 0x08: ram2gs_set_nvm_lcmxo2(en8meg, enled); break; // Lattice MachXO2
|
||||
}
|
||||
}
|
||||
|
||||
static void menu_led(char enled) {
|
||||
if (enled) {
|
||||
gwcputsxy(1, 15, "LED enabled. Press [L] to disable LED.");
|
||||
} else {
|
||||
gwcputsxy(1, 15, "LED disabled. Press [L] to enable LED.");
|
||||
}
|
||||
}
|
||||
#include "ram2gs_hal.h"
|
||||
|
||||
static void menu()
|
||||
{
|
||||
uint8_t bankcount;
|
||||
clrscr(); // Clear screen
|
||||
|
||||
gwcputsxy(5, 1, "-- RAM2GS Capacity Settings --");
|
||||
|
@ -136,13 +27,19 @@ static void menu()
|
|||
gwcputsxy(1, 21, "nonvolatile memory, press Apple+number.");
|
||||
|
||||
gwcputsxy(1, 23, "Press [Q] to quit without saving.");
|
||||
}
|
||||
|
||||
bankcount = ram2gs_getsize();
|
||||
static void menu_size(uint16_t bankcount) {
|
||||
gotoxy(29, 3);
|
||||
printf("%d", bankcount * 64);
|
||||
gwcputs(" kB");
|
||||
}
|
||||
|
||||
static void menu_led(char enled) {
|
||||
if (enled) { gwcputsxy(1, 15, "LED enabled. Press [L] to disable LED."); }
|
||||
else { gwcputsxy(1, 15, "LED disabled. Press [L] to enable LED."); }
|
||||
}
|
||||
|
||||
static void loading_screen()
|
||||
{
|
||||
clrscr(); // Clear screen
|
||||
|
@ -151,35 +48,56 @@ static void loading_screen()
|
|||
|
||||
int ram2gs_main(void)
|
||||
{
|
||||
char hasled = true;
|
||||
char typecode = false;
|
||||
char enled = false;
|
||||
char type;
|
||||
uint16_t bankcount;
|
||||
char en8meg = true;
|
||||
char hasled = true;
|
||||
char enled = false;
|
||||
|
||||
char nvm = false;
|
||||
int reset_count = false;
|
||||
int reset_count = 0;
|
||||
|
||||
loading_screen();
|
||||
|
||||
if (ram2gs_detect(0x00)) {
|
||||
typecode = 0x00;
|
||||
if (ram2gs_detect(0x00)) { // Altera MAX II / V
|
||||
type = 0x00;
|
||||
hasled = !ram2gs_detect(0x04);
|
||||
} else if (ram2gs_detect(0x04)) {
|
||||
typecode = 0x04;
|
||||
} else if (ram2gs_detect(0x04)) { // Lattice MachXO / iCE40 / AGM AG256
|
||||
type = 0x04;
|
||||
hasled = true;
|
||||
} else if (ram2gs_detect(0x08)) { // Lattice MachXO2
|
||||
type = 0x08;
|
||||
hasled = true;
|
||||
} else {
|
||||
#ifndef SKIP_RAM2GS_DETECT
|
||||
// If no RAM2GS, show an error message and quit
|
||||
gwcputsxy(0, 8, " No RAM2GS II detected.");
|
||||
gwcputsxy(0, 8, " No RAM2GS II detected.");
|
||||
gwcputsxy(0, 10, " Press any key to quit.");
|
||||
cgetc(); // Wait for key
|
||||
clrscr(); // Clear screen before quitting
|
||||
return EXIT_SUCCESS;
|
||||
#else
|
||||
hasled = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (hasled) { enled = !ram2gs_detect(typecode | 0x02); }
|
||||
// Set chip type
|
||||
ram2gs_hal_set_type(type);
|
||||
|
||||
// Print menu
|
||||
menu();
|
||||
if (hasled) { menu_led(enled); }
|
||||
|
||||
// Detect and print current capacity
|
||||
bankcount = ram2gs_getsize();
|
||||
menu_size(bankcount);
|
||||
|
||||
// Detect and print LED menu
|
||||
#ifndef SKIP_RAM2GS_DETECT
|
||||
if (hasled) {
|
||||
enled = !ram2gs_detect(type | 0x02);
|
||||
menu_led(enled);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get user choice from menu
|
||||
while (true) {
|
||||
|
@ -194,7 +112,15 @@ int ram2gs_main(void)
|
|||
case 'L': {
|
||||
enled = !enled;
|
||||
ram2gs_set(en8meg, enled);
|
||||
if (hasled) { menu_led(enled); };
|
||||
if (hasled) {
|
||||
menu_led(enled);
|
||||
if (enled) {
|
||||
wait(1);
|
||||
ram2gs_flashled(10);
|
||||
wait(10);
|
||||
ram2gs_flashled(10);
|
||||
}
|
||||
};
|
||||
continue;
|
||||
} case 'R': {
|
||||
reset_count++;
|
||||
|
@ -204,7 +130,7 @@ int ram2gs_main(void)
|
|||
gwcputsxy(1, 8, "Resetting RAM2GS settings.");
|
||||
gwcputsxy(1, 9, "Do not turn off your Apple.");
|
||||
|
||||
ram2gs_erase(typecode); // Erase RAM2GS settings memory
|
||||
ram2gs_erase(); // Erase RAM2GS settings memory
|
||||
ram2gs_set(1, 0); // Enable 8 megabytes and disable LED
|
||||
|
||||
// Wait for >= 500ms on even the fastest systems.
|
||||
|
@ -233,9 +159,11 @@ int ram2gs_main(void)
|
|||
gwcputsxy(1, 8, "Saving RAM2GS capacity setting.");
|
||||
gwcputsxy(1, 9, "Do not turn off your Apple.");
|
||||
// Save capacity in nonvolatile memory.
|
||||
ram2gs_set_nvm(typecode, en8meg, enled);
|
||||
ram2gs_save_start(en8meg, enled);
|
||||
// Wait for >= 500ms on even the fastest systems.
|
||||
spin(33, 8);
|
||||
// Finish saving
|
||||
ram2gs_save_end(en8meg, enled);
|
||||
// Print success message
|
||||
clrscr(); // Clear screen
|
||||
gwcputsxy(1, 8, "RAM2GS capacity saved successfully.");
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
#ifndef RAM2GS_ASM_H
|
||||
#define RAM2GS_ASM_H
|
||||
|
||||
uint8_t __fastcall__ ram2gs_cmd(char cmd);
|
||||
uint8_t __fastcall__ ram2gs_detect(char typecode);
|
||||
uint8_t __fastcall__ ram2gs_getsize(void);
|
||||
|
||||
#endif /* RAM2GS_ASM_H */
|
46
ram2gs_asm.s
46
ram2gs_asm.s
|
@ -5,10 +5,7 @@
|
|||
.export _ram2gs_cmd
|
||||
.export _ram2gs_getsize
|
||||
.export _ram2gs_detect
|
||||
|
||||
.define GetTWConfig $BCFF3C
|
||||
.define SetTWConfig $BCFF40
|
||||
.define DisableDataCache $BCFF4C
|
||||
.export _ram2gs_flashled1
|
||||
|
||||
.macro A8
|
||||
sep #$20 ; put the 65C816 in 8-bit accumulator mode
|
||||
|
@ -342,3 +339,44 @@
|
|||
plx ; Pull Y
|
||||
rts
|
||||
.endproc
|
||||
|
||||
.proc _ram2gs_flashled1: near
|
||||
.A8
|
||||
.I8
|
||||
; Preamble
|
||||
phx ; Push X
|
||||
phy ; Push Y
|
||||
php ; Push status
|
||||
sei ; Disable interrupts
|
||||
clc ; Clear carry
|
||||
xce ; Clear emulation bit
|
||||
php ; Push status again, reflecting emulation bit
|
||||
phb ; Push bank
|
||||
AI8
|
||||
|
||||
lda #$20
|
||||
pha
|
||||
plb
|
||||
ldx #0
|
||||
_ram2gs_flashled1_loop:
|
||||
lda $3456
|
||||
lda $3456
|
||||
lda $3456
|
||||
lda $3456
|
||||
lda $3456
|
||||
lda $3456
|
||||
lda $3456
|
||||
lda $3456
|
||||
inx
|
||||
cpx #0
|
||||
bne _ram2gs_flashled1_loop
|
||||
|
||||
; Postamble
|
||||
plb ; Restore bank
|
||||
plp ; Restore status
|
||||
xce ; Restore emulation bit
|
||||
plp ; Pull status again to pull I flag
|
||||
ply ; Pull X
|
||||
plx ; Pull Y
|
||||
rts
|
||||
.endproc
|
||||
|
|
54
ram2gs_hal.c
Normal file
54
ram2gs_hal.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include "util.h"
|
||||
#include "ram2gs_hal.h"
|
||||
|
||||
uint8_t __fastcall__ ram2gs_cmd(char cmd);
|
||||
|
||||
void ram2gs_set(char en8meg, char enled) {
|
||||
char cmd = 0x10;
|
||||
if (en8meg) { cmd |= 0x01; }
|
||||
if (enled) { cmd |= 0x02; }
|
||||
ram2gs_cmd(cmd);
|
||||
}
|
||||
|
||||
void ram2gs_flashled(char frames) {
|
||||
char i;
|
||||
for (i = 0; i < frames; i++) {
|
||||
unsigned int l;
|
||||
for (l = 0; *VBL < 0 && l < 2500; l++) { ram2gs_flashled1(); }
|
||||
for (l = 0; *VBL >= 0 && l < 2500; l++) { ram2gs_flashled1(); }
|
||||
}
|
||||
}
|
||||
|
||||
#include "ram2gs_hal_max.c"
|
||||
#include "ram2gs_hal_spi.c"
|
||||
#include "ram2gs_hal_lcmxo2.c"
|
||||
|
||||
static char _type;
|
||||
void ram2gs_hal_set_type(char type) { _type = type; }
|
||||
|
||||
void ram2gs_erase() {
|
||||
switch (_type) {
|
||||
case 0x00: ram2gs_max_erase(); break; // Altera MAX II / V
|
||||
case 0x04: ram2gs_spi_erase(); break; // Lattice MachXO / iCE40 / AGM AG256
|
||||
case 0x08: ram2gs_lcmxo2_erase(); break; // Lattice MachXO2
|
||||
}
|
||||
}
|
||||
void ram2gs_save_start(char en8meg, char enled) {
|
||||
switch (_type) {
|
||||
case 0x00: ram2gs_max_save(en8meg, enled); break; // Altera MAX II / V
|
||||
case 0x04: ram2gs_spi_erase(); break; // Lattice MachXO / iCE40 / AGM AG256
|
||||
case 0x08: ram2gs_lcmxo2_erase(); break; // Lattice MachXO2
|
||||
}
|
||||
}
|
||||
void ram2gs_save_end(char en8meg, char enled) {
|
||||
switch (_type) {
|
||||
case 0x00: break; // Altera MAX II / V
|
||||
case 0x04: ram2gs_spi_save(en8meg, enled); break; // Lattice MachXO / iCE40 / AGM AG256
|
||||
case 0x08: ram2gs_lcmxo2_save(en8meg, enled); break; // Lattice MachXO2
|
||||
}
|
||||
}
|
19
ram2gs_hal.h
Normal file
19
ram2gs_hal.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef RAM2GS_HAL_H
|
||||
#define RAM2GS_HAL_H
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t __fastcall__ ram2gs_detect(char typecode);
|
||||
uint8_t __fastcall__ ram2gs_getsize(void);
|
||||
uint8_t __fastcall__ ram2gs_flashled1(void);
|
||||
|
||||
void ram2gs_set(char en8meg, char enled);
|
||||
|
||||
void ram2gs_flashled(char frames);
|
||||
|
||||
void ram2gs_hal_set_type(char typecode);
|
||||
void ram2gs_erase();
|
||||
void ram2gs_save_start(char en8meg, char enled);
|
||||
void ram2gs_save_end(char en8meg, char enled);
|
||||
|
||||
#endif
|
88
ram2gs_hal_lcmxo2.c
Normal file
88
ram2gs_hal_lcmxo2.c
Normal file
|
@ -0,0 +1,88 @@
|
|||
static void ram2gs_lcmxo2_rw(char we, char addr, char data) {
|
||||
char i;
|
||||
for (i = 0; i < 8; i++) { ram2gs_cmd(0x38 + ((addr >> (7-i)) & 1)); }
|
||||
for (i = 0; i < 8; i++) { ram2gs_cmd(0x38 + ((data >> (7-i)) & 1)); }
|
||||
if (we) { ram2gs_cmd(0x39); }
|
||||
else { ram2gs_cmd(0x38); }
|
||||
ram2gs_cmd(0x3A);
|
||||
}
|
||||
static void ram2gs_lcmxo2_open() { ram2gs_lcmxo2_rw(1, 0x70, 0x80); }
|
||||
static void ram2gs_lcmxo2_close() { ram2gs_lcmxo2_rw(1, 0x70, 0x00); }
|
||||
static void ram2gs_lcmxo2_cmd_op3(char cmd, char op1, char op2, char op3) {
|
||||
ram2gs_lcmxo2_open();
|
||||
ram2gs_lcmxo2_rw(1, 0x71, cmd); // Command
|
||||
ram2gs_lcmxo2_rw(1, 0x71, op1); // Operand 1/3
|
||||
ram2gs_lcmxo2_rw(1, 0x71, op2); // Operand 2/3
|
||||
ram2gs_lcmxo2_rw(1, 0x71, op3); // Operand 3/3
|
||||
}
|
||||
|
||||
static void ram2gs_lcmxo2_encfg() {
|
||||
ram2gs_lcmxo2_cmd_op3(0x74, 0x08, 0x00, 0x00);
|
||||
ram2gs_lcmxo2_close();
|
||||
}
|
||||
static void ram2gs_lcmxo2_discfg() {
|
||||
ram2gs_lcmxo2_cmd_op3(0x26, 0x08, 0x00, 0x00);
|
||||
ram2gs_lcmxo2_close();
|
||||
}
|
||||
static void ram2gs_lcmxo2_bypass() {
|
||||
ram2gs_lcmxo2_open();
|
||||
ram2gs_lcmxo2_rw(1, 0x71, 0xFF); // Command
|
||||
ram2gs_lcmxo2_close();
|
||||
}
|
||||
static void ram2gs_lcmxo2_pollstat() {
|
||||
ram2gs_lcmxo2_cmd_op3(0x3C, 0x00, 0x00, 0x00);
|
||||
ram2gs_lcmxo2_rw(0, 0x73, 0x00); // Data 1/4
|
||||
ram2gs_lcmxo2_rw(0, 0x73, 0x00); // Data 2/4
|
||||
ram2gs_lcmxo2_rw(0, 0x73, 0x00); // Data 3/4
|
||||
ram2gs_lcmxo2_rw(0, 0x73, 0x00); // Data 4/4
|
||||
ram2gs_lcmxo2_close();
|
||||
}
|
||||
static void ram2gs_lcmxo2_erase() {
|
||||
// Enable configuration interface
|
||||
ram2gs_lcmxo2_encfg();
|
||||
// Poll status register
|
||||
ram2gs_lcmxo2_pollstat();
|
||||
|
||||
// Erase UFM
|
||||
ram2gs_lcmxo2_cmd_op3(0xCB, 0x00, 0x00, 0x00);
|
||||
ram2gs_lcmxo2_close();
|
||||
}
|
||||
static void ram2gs_lcmxo2_save(char en8meg, char enled) {
|
||||
char i;
|
||||
// Poll status register
|
||||
ram2gs_lcmxo2_pollstat();
|
||||
// Disable configuration interface
|
||||
ram2gs_lcmxo2_discfg();
|
||||
// Bypass
|
||||
ram2gs_lcmxo2_bypass();
|
||||
// Enable configuration interface
|
||||
ram2gs_lcmxo2_encfg();
|
||||
// Poll status register
|
||||
ram2gs_lcmxo2_pollstat();
|
||||
|
||||
// Set UFM address
|
||||
ram2gs_lcmxo2_cmd_op3(0xB4, 0x00, 0x00, 0x00);
|
||||
ram2gs_lcmxo2_rw(1, 0x71, 0x40); // Data 1/4
|
||||
ram2gs_lcmxo2_rw(1, 0x71, 0x00); // Data 2/4
|
||||
ram2gs_lcmxo2_rw(1, 0x71, 0x00); // Data 3/4
|
||||
ram2gs_lcmxo2_rw(1, 0x71, 190); // Data 4/4
|
||||
ram2gs_lcmxo2_close();
|
||||
|
||||
// Write UFM page
|
||||
ram2gs_lcmxo2_cmd_op3(0xC9, 0x00, 0x00, 0x01);
|
||||
// Data 0
|
||||
if (!en8meg && !enled) { ram2gs_lcmxo2_rw(1, 0x71, 0x01); }
|
||||
else if (!en8meg && enled) { ram2gs_lcmxo2_rw(1, 0x71, 0x03); }
|
||||
else if ( en8meg && !enled) { ram2gs_lcmxo2_rw(1, 0x71, 0x00); }
|
||||
else if ( en8meg && enled) { ram2gs_lcmxo2_rw(1, 0x71, 0x02); }
|
||||
// Data 1-15
|
||||
for (i = 1; i < 16; i++) { ram2gs_lcmxo2_rw(1, 0x71, 0x00); }
|
||||
ram2gs_lcmxo2_close();
|
||||
|
||||
// Poll status register
|
||||
ram2gs_lcmxo2_pollstat();
|
||||
// Disable configuration interface
|
||||
ram2gs_lcmxo2_discfg();
|
||||
// Bypass
|
||||
ram2gs_lcmxo2_bypass();
|
||||
}
|
16
ram2gs_hal_max.c
Normal file
16
ram2gs_hal_max.c
Normal file
|
@ -0,0 +1,16 @@
|
|||
static void ram2gs_max_erase() { ram2gs_cmd(0x28); }
|
||||
static void ram2gs_max_shift(char bit) {
|
||||
char data = 0x20;
|
||||
if (bit) data |= 0x01;
|
||||
ram2gs_cmd(data);
|
||||
data |= 0x02;
|
||||
ram2gs_cmd(data);
|
||||
}
|
||||
static void ram2gs_max_save(char en8meg, char enled) {
|
||||
char i;
|
||||
ram2gs_max_shift(0); // Clock in 0 to enable this setting entry
|
||||
ram2gs_max_shift(en8meg); // Clock in 8 mb enable bit
|
||||
ram2gs_max_shift(!enled); // Clock in LED enable bit
|
||||
for (i = 0; i < 13; i++) { ram2gs_max_shift(1); } // Clock in 13 dummy 1s
|
||||
ram2gs_cmd(0x24); // Program
|
||||
}
|
38
ram2gs_hal_spi.c
Normal file
38
ram2gs_hal_spi.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
static void ram2gs_spi_select() { ram2gs_cmd(0x34); }
|
||||
static void ram2gs_spi_deselect() { ram2gs_cmd(0x30); }
|
||||
static void ram2gs_spi_tx8(char data) {
|
||||
char i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
ram2gs_cmd(0x34 + ((data >> (7-i)) & 1));
|
||||
ram2gs_cmd(0x36 + ((data >> (7-i)) & 1));
|
||||
}
|
||||
}
|
||||
static void ram2gs_spi_wren() {
|
||||
ram2gs_spi_deselect();
|
||||
ram2gs_spi_select();
|
||||
ram2gs_spi_tx8(0x06); // 0x06 is write enable
|
||||
ram2gs_spi_deselect();
|
||||
}
|
||||
static void ram2gs_spi_erase() {
|
||||
ram2gs_spi_wren();
|
||||
ram2gs_spi_select();
|
||||
ram2gs_spi_tx8(0x20); // 0x20 is sector erase (4 kB)
|
||||
ram2gs_spi_tx8(0x00); // address[23:16]
|
||||
ram2gs_spi_tx8(0x10); // address[15:8]
|
||||
ram2gs_spi_tx8(0x00); // address[7:0]
|
||||
ram2gs_spi_deselect();
|
||||
}
|
||||
static void ram2gs_spi_save(char en8meg, char enled) {
|
||||
ram2gs_spi_wren();
|
||||
ram2gs_spi_select();
|
||||
ram2gs_spi_tx8(0x02); // 0x02 is page (byte) program
|
||||
ram2gs_spi_tx8(0x00); // address[23:16]
|
||||
ram2gs_spi_tx8(0x10); // address[15:8]
|
||||
ram2gs_spi_tx8(0x00); // address[7:0]
|
||||
// data[7:0]
|
||||
if (!en8meg && !enled) { ram2gs_spi_tx8(0x7F); }
|
||||
else if (!en8meg && enled) { ram2gs_spi_tx8(0x3F); }
|
||||
else if ( en8meg && !enled) { ram2gs_spi_tx8(0xFF); }
|
||||
else if ( en8meg && enled) { ram2gs_spi_tx8(0xBF); }
|
||||
ram2gs_spi_deselect();
|
||||
}
|
103
ramtest.c
103
ramtest.c
|
@ -1,103 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <conio.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "gwconio.h"
|
||||
#include "ramtestpat.c"
|
||||
|
||||
#define TEST_SIZE (8*1024*1024)
|
||||
#define BANK_SIZE (65536)
|
||||
#define NUM_BANKS (TEST_SIZE/BANK_SIZE)
|
||||
|
||||
static char getpat(uint32_t i) {
|
||||
return ramtestpat[i % RAMTESTPAT_SIZE];
|
||||
}
|
||||
|
||||
char test_run() {
|
||||
uint32_t i;
|
||||
uint8_t ah;
|
||||
|
||||
// Put read/write stubs in low RAM
|
||||
|
||||
|
||||
for (ah = 0, i = 0; ah < NUM_BANKS; ah++) {
|
||||
uint16_t al = 0;
|
||||
|
||||
// Copy 0x0000-01FF
|
||||
*((char*)_test_wr1_dm1 + 1) = getpat(i);
|
||||
for (; al < 0x200; al++, i++) {
|
||||
_test_wr1_dm1:
|
||||
__asm__("lda #$00");
|
||||
__asm__("sta $C009"); // SETALTZP
|
||||
_test_wr1_am1:
|
||||
__asm__("lda $0000");
|
||||
__asm__("sta $C008"); // SETSTDZP
|
||||
}
|
||||
|
||||
// Copy 0x0200-BFFF
|
||||
for (; al < 0xC000; al++, i++) {
|
||||
|
||||
}
|
||||
|
||||
// Copy 0xC000-CFFF to LC2 D000-DFFF
|
||||
for (; al < 0xD000; al++, i++) {
|
||||
|
||||
}
|
||||
|
||||
// Copy 0xD000-FFFF to LC1 D000-FFFF
|
||||
for (; al != 0x0000; al++, i++) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t a = 0; a < TEST_SIZE) {
|
||||
char d = rd(a);
|
||||
if (d != getpat(a)) { return -1; }
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rd_zplc() {
|
||||
_rd_zplc:
|
||||
__asm__("sta $C009"); // SETALTZP
|
||||
_rd_zplc_am1:
|
||||
__asm__("lda $0000");
|
||||
__asm__("sta $C008"); // SETSTDZP
|
||||
__asm__("rts");
|
||||
}
|
||||
|
||||
static void rd_main() {
|
||||
_rd_main:
|
||||
__asm__("sta $C003"); // WRCARDRAM
|
||||
_rd_main_am1:
|
||||
__asm__("lda $0000");
|
||||
__asm__("sta $C002"); // WRMAINRAM
|
||||
__asm__("rts");
|
||||
}
|
||||
|
||||
static void wr_zplc() {
|
||||
_wr_zplc:
|
||||
_wr_zplc_dm1:
|
||||
__asm__("lda #$00");
|
||||
__asm__("sta $C009"); // SETALTZP
|
||||
_wr_zplc_am1:
|
||||
__asm__("lda $0000");
|
||||
__asm__("sta $C008"); // SETSTDZP
|
||||
__asm__("rts");
|
||||
}
|
||||
|
||||
static void wr_main() {
|
||||
_wr_main:
|
||||
_wr_zplc_dm1:
|
||||
__asm__("lda #$00");
|
||||
__asm__("sta $C005"); // WRCARDRAM
|
||||
_wr_main_am1:
|
||||
__asm__("lda $0000");
|
||||
__asm__("sta $C004"); // WRMAINRAM
|
||||
__asm__("rts");
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef TEST_H
|
||||
#define TEST_H
|
||||
|
||||
char test_run();
|
||||
|
||||
#endif /* TEST_H */
|
190
ramtest.s
190
ramtest.s
|
@ -1,190 +0,0 @@
|
|||
.autoimport on
|
||||
.importzp sp
|
||||
|
||||
.export rtst_run
|
||||
.import rtst_pat
|
||||
.import rtst_scratch
|
||||
|
||||
.code
|
||||
|
||||
.proc ramtest_run: near
|
||||
; Preamble
|
||||
php ; Push status
|
||||
sei ; Disable interrupts
|
||||
phx ; Push X
|
||||
phy ; Push Y
|
||||
|
||||
; Save entire ZP
|
||||
ldx #0 ; X = 0
|
||||
savezp:
|
||||
lda $00,X
|
||||
sta rtst_scratch,X
|
||||
inx
|
||||
bne savezp
|
||||
|
||||
; Set bank counter and address to 0
|
||||
lda #0
|
||||
sta $04
|
||||
sta $03
|
||||
sta $02
|
||||
|
||||
; Set pattern address to 0xA000
|
||||
lda #$A0
|
||||
sta $01
|
||||
lda #$00
|
||||
sta $00
|
||||
|
||||
bankloop:
|
||||
; Store 0x0000-01FF
|
||||
|
||||
; Store 0x0200-BFFF
|
||||
|
||||
; Switch to LC2
|
||||
|
||||
; Store in 0xD000-DFFF
|
||||
|
||||
; Switch to LC1
|
||||
|
||||
; Store in 0xD000-FFFF
|
||||
|
||||
; Increment bank and repeat if < 128
|
||||
inc $04
|
||||
lda $04
|
||||
cmp #$80
|
||||
blt bankloop
|
||||
|
||||
; Restore entire ZP
|
||||
ldx #0 ; X = 0
|
||||
savezp:
|
||||
lda rtst_scratch,X
|
||||
sta $00,X
|
||||
inx
|
||||
bne savezp
|
||||
|
||||
; Postamble
|
||||
ply ; Pull Y
|
||||
plx ; Pull X
|
||||
plp ; Pull status
|
||||
.endproc
|
||||
|
||||
.proc ramtest_incpat: near
|
||||
; Increment pattern pointer
|
||||
inc $00 ; Increment low byte
|
||||
bne incpat1 ; If low byte nonzero, skip incrementing high byte
|
||||
inc $01 ; If low byte zero, increment high byte
|
||||
bne incpat2 ; Unconditional branch to return
|
||||
beq incpat2
|
||||
|
||||
; Check if pointer == 0xB001
|
||||
; if low byte didn't roll around
|
||||
incpat1:
|
||||
lda $01 ; Load high byte of pointer
|
||||
cmp #$B0 ; Check == 0xB0
|
||||
bne incpat2 ; If not, goto return
|
||||
lda $00 ; Load low byte of pointer
|
||||
cmp #$01 ; Check == 0x01
|
||||
bne incpat2 ; If not, goto return
|
||||
; Otherwise fall through
|
||||
|
||||
; Reset pattern pointer
|
||||
lda #$A0
|
||||
sta $01
|
||||
lda #$00
|
||||
sta $00
|
||||
|
||||
incpat2:
|
||||
rts
|
||||
.endproc
|
||||
|
||||
.proc ramtest_wr256zp: near
|
||||
; Set up to copy
|
||||
ldy $02 ; Y = address lo
|
||||
sty wr256zp_am1_1+1 ; Set 1st address lo = 0
|
||||
sty wr256zp_am1_2+1 ; Set 2nd address lo = 0
|
||||
ldy $03 ; Y = address hi
|
||||
sty wr256zp_am1_1+2 ; Set 1st address hi
|
||||
sty wr256zp_am1_2+2 ; Set 2nd address hi
|
||||
ldy #0 ; Y = 0
|
||||
|
||||
wr256zp_loop:
|
||||
; Load two pattern bytes
|
||||
lda ($00) ; A = next pattern byte
|
||||
jsr ramtest_incpat ; Increment pattern pointer
|
||||
ldx ($00) ; Y = next pattern byte
|
||||
jsr ramtest_incpat ; Increment pattern pointer
|
||||
; Switch into ALTZP, store two pattern bytes, switch back
|
||||
sta $C009 ; SETALTZP
|
||||
wr256zp_am1_1:
|
||||
sta $0000,Y ; Store in RAM
|
||||
iny ; Y++
|
||||
wr256zp_am1_2:
|
||||
stx $0000,Y ; Store in RAM
|
||||
iny ; Y++
|
||||
sta $C008 ; SETSTDZP
|
||||
; Repeat
|
||||
bne wr256zp_loop ; Repeat until X rolls over (256 times)
|
||||
|
||||
; Success exit
|
||||
rts
|
||||
.endproc
|
||||
|
||||
.proc ramtest_wr256mn: near
|
||||
; Set up to copy
|
||||
ldy $02 ; Y = address lo
|
||||
sty wr256zp_am1_1+1 ; Set 1st address lo
|
||||
sty wr256zp_am1_2+1 ; Set 2nd address lo
|
||||
ldy $03 ; Y = address hi
|
||||
sty wr256zp_am1_1+2 ; Set 1st address hi
|
||||
sty wr256zp_am1_2+2 ; Set 2nd address hi
|
||||
ldy #0 ; Y = 0
|
||||
|
||||
wr256mn_loop:
|
||||
; Load two pattern bytes
|
||||
lda ($00) ; A = next pattern byte
|
||||
jsr ramtest_incpat ; Increment pattern pointer
|
||||
ldx ($00) ; Y = next pattern byte
|
||||
jsr ramtest_incpat ; Increment pattern pointer
|
||||
; RAMWRTON, store two pattern bytes, RAMWRTOFF
|
||||
sta $C009 ; RAMWRTON
|
||||
wr256mn_am1_1:
|
||||
sta $0000,Y ; Store in RAM
|
||||
iny ; X++
|
||||
wr256mn_am1_2:
|
||||
stx $0000,Y ; Store in RAM
|
||||
iny ; X++
|
||||
sta $C008 ; RAMWRTOFF
|
||||
; Repeat
|
||||
bne wr256mn_loop ; Repeat until X rolls over (256 times)
|
||||
|
||||
; Success exit
|
||||
rts
|
||||
.endproc
|
||||
|
||||
.proc ramtest_vfy256zp: near
|
||||
; Set up to verify
|
||||
ldx #0 ; X = 0
|
||||
stx vfy256zp_am1+1 ; Address lo = 0
|
||||
sty vfy256zp_am1+2 ; Address hi = Y
|
||||
ldy #0 ; Y = 0
|
||||
|
||||
vfy256zp_loop:
|
||||
; Switch into ALTZP, load byte from RAM, switch back
|
||||
sta $C009 ; SETALTZP
|
||||
vfy256zp_am1:
|
||||
lda $0000,X ; A = next RAM byte
|
||||
sta $C008 ; SETSTDZP
|
||||
; Compare loaded byte from RAM with pattern
|
||||
cmp ($00),Y ; Compare with pattern byte
|
||||
bne vfy256zp_vfail
|
||||
jsr ramtest_incpat ; Increment pattern pointer
|
||||
inx
|
||||
; Repeat
|
||||
bne vfy256zp_loop ; Repeat until X rolls over (256 times)
|
||||
|
||||
; Success exit
|
||||
rts
|
||||
; Fail exit
|
||||
vfy256zp_vfail:
|
||||
lda #$FF
|
||||
rts
|
||||
.endproc
|
|
@ -1,4 +0,0 @@
|
|||
#define RAMTESTPAT_SIZE 4097
|
||||
char ramtestpat[RAMTESTPAT_SIZE] = {
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9
|
||||
};
|
23
util.c
23
util.c
|
@ -8,15 +8,22 @@
|
|||
#define PB1 ((char*)0xC062)
|
||||
char read_applekey(void) { return ((*PB0) | (*PB1)) & 0x80; }
|
||||
|
||||
#define VBL ((signed char*)0xC019)
|
||||
void wait(char frames) {
|
||||
char i;
|
||||
for (i = 0; i < frames; i++) {
|
||||
unsigned int l;
|
||||
for (l = 0; *VBL < 0 && l < 2500; l++);
|
||||
for (l = 0; *VBL >= 0 && l < 2500; l++);
|
||||
}
|
||||
}
|
||||
|
||||
#define SPIN_HALFCYCLES 3
|
||||
#define SPIN_FRAMESPERCHAR 4
|
||||
void spin(uint8_t x, uint8_t y) {
|
||||
char i;
|
||||
unsigned int l;
|
||||
|
||||
// Sync to frame before starting
|
||||
for (l = 0; *VBL >= 0 && l < 2500; l++);
|
||||
wait(1);
|
||||
|
||||
// Wait and animate spinner.
|
||||
// Spin_half
|
||||
|
@ -24,8 +31,6 @@ void spin(uint8_t x, uint8_t y) {
|
|||
char j;
|
||||
for (j = 0; j < 4; j++) {
|
||||
char spinchar;
|
||||
char k;
|
||||
|
||||
// Assign spinner char based on j
|
||||
switch (j) {
|
||||
case 0: spinchar = '\\'; break;
|
||||
|
@ -40,14 +45,10 @@ void spin(uint8_t x, uint8_t y) {
|
|||
putchar(spinchar);
|
||||
|
||||
// Wait specificed number of frames
|
||||
for (k = 0; k < SPIN_FRAMESPERCHAR; k++) {
|
||||
for (l = 0; *VBL < 0 && l < 2500; l++);
|
||||
for (l = 0; *VBL >= 0 && l < 2500; l++);
|
||||
}
|
||||
wait(SPIN_FRAMESPERCHAR);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait a frame when finished
|
||||
for (l = 0; *VBL < 0 && l < 2500; l++);
|
||||
for (l = 0; *VBL >= 0 && l < 2500; l++);
|
||||
wait(1);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user