diff --git a/.gitignore b/.gitignore index f0b678a..34bd2e8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.o *.sys obj/*.s +.vscode/* diff --git a/Makefile b/Makefile index 64f35c2..82912a0 100644 --- a/Makefile +++ b/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: diff --git a/bin/GWRAM.dbg.po b/bin/GWRAM.dbg.po index 7d0f5df..5d02111 100644 Binary files a/bin/GWRAM.dbg.po and b/bin/GWRAM.dbg.po differ diff --git a/bin/GWRAM.po b/bin/GWRAM.po index 0a46eb8..53d6729 100644 Binary files a/bin/GWRAM.po and b/bin/GWRAM.po differ diff --git a/bnc.sh b/bnc.sh new file mode 100755 index 0000000..8123a84 --- /dev/null +++ b/bnc.sh @@ -0,0 +1,4 @@ +make clean +make +cp bin/GWRAM.po /Volumes/FLOPPYEMU/GWRAM.po +diskutil unmount /Volumes/FLOPPYEMU/ diff --git a/ram2e.c b/ram2e.c index 97b5c7a..a8d5985 100644 --- a/ram2e.c +++ b/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."); diff --git a/ram2e_hal.c b/ram2e_hal.c new file mode 100644 index 0000000..c82c63a --- /dev/null +++ b/ram2e_hal.c @@ -0,0 +1,242 @@ +#include +#include +#include +#include +#include +#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 + } +} + diff --git a/ram2e_hal.h b/ram2e_hal.h new file mode 100644 index 0000000..04b53b0 --- /dev/null +++ b/ram2e_hal.h @@ -0,0 +1,72 @@ +#ifndef RAM2GS_HAL_H +#define RAM2GS_HAL_H +#include +#include + +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 \ No newline at end of file diff --git a/ram2e_hal_lcmxo2.c b/ram2e_hal_lcmxo2.c new file mode 100644 index 0000000..a5b9403 --- /dev/null +++ b/ram2e_hal_lcmxo2.c @@ -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(); +} diff --git a/ram2e_hal_max.c b/ram2e_hal_max.c new file mode 100644 index 0000000..5e9d47d --- /dev/null +++ b/ram2e_hal_max.c @@ -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(); +} diff --git a/ram2e_hal_spi.c b/ram2e_hal_spi.c new file mode 100644 index 0000000..555892d --- /dev/null +++ b/ram2e_hal_spi.c @@ -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(); +} \ No newline at end of file diff --git a/ram2gs.c b/ram2gs.c index 7533edf..ddd5b67 100644 --- a/ram2gs.c +++ b/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."); diff --git a/ram2gs_asm.h b/ram2gs_asm.h deleted file mode 100644 index d4dbea5..0000000 --- a/ram2gs_asm.h +++ /dev/null @@ -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 */ diff --git a/ram2gs_asm.s b/ram2gs_asm.s index 40464b5..996c52e 100644 --- a/ram2gs_asm.s +++ b/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 diff --git a/ram2gs_hal.c b/ram2gs_hal.c new file mode 100644 index 0000000..62a3758 --- /dev/null +++ b/ram2gs_hal.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include +#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 + } +} diff --git a/ram2gs_hal.h b/ram2gs_hal.h new file mode 100644 index 0000000..490138a --- /dev/null +++ b/ram2gs_hal.h @@ -0,0 +1,19 @@ +#ifndef RAM2GS_HAL_H +#define RAM2GS_HAL_H +#include +#include + +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 \ No newline at end of file diff --git a/ram2gs_hal_lcmxo2.c b/ram2gs_hal_lcmxo2.c new file mode 100644 index 0000000..cfb8647 --- /dev/null +++ b/ram2gs_hal_lcmxo2.c @@ -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(); +} diff --git a/ram2gs_hal_max.c b/ram2gs_hal_max.c new file mode 100644 index 0000000..5812118 --- /dev/null +++ b/ram2gs_hal_max.c @@ -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 +} diff --git a/ram2gs_hal_spi.c b/ram2gs_hal_spi.c new file mode 100644 index 0000000..79fa624 --- /dev/null +++ b/ram2gs_hal_spi.c @@ -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(); +} diff --git a/ramtest.c b/ramtest.c deleted file mode 100644 index 610ad79..0000000 --- a/ramtest.c +++ /dev/null @@ -1,103 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#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"); -} diff --git a/ramtest.h b/ramtest.h deleted file mode 100644 index c9e8909..0000000 --- a/ramtest.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef TEST_H -#define TEST_H - -char test_run(); - -#endif /* TEST_H */ diff --git a/ramtest.s b/ramtest.s deleted file mode 100644 index 0fc9765..0000000 --- a/ramtest.s +++ /dev/null @@ -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 diff --git a/ramtestpat.c b/ramtestpat.c deleted file mode 100644 index fd3edc9..0000000 --- a/ramtestpat.c +++ /dev/null @@ -1,4 +0,0 @@ -#define RAMTESTPAT_SIZE 4097 -char ramtestpat[RAMTESTPAT_SIZE] = { - 1, 2, 3, 4, 5, 6, 7, 8, 9 -}; \ No newline at end of file diff --git a/util.c b/util.c index 6474d50..6c6c69d 100644 --- a/util.c +++ b/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); } diff --git a/util.h b/util.h index a591b63..1905716 100644 --- a/util.h +++ b/util.h @@ -6,7 +6,10 @@ #define true 1 #define false 0 +#define VBL ((signed char*)0xC019) + char read_applekey(void); +void wait(char frames); void spin(uint8_t x, uint8_t y); #endif /* UTIL_H */ \ No newline at end of file