From 8622e2776a4647c6614e3ef7098ca21768adab25 Mon Sep 17 00:00:00 2001 From: Zane Kaminski Date: Thu, 21 Sep 2023 04:25:33 -0400 Subject: [PATCH] RC --- .gitignore | 1 + Makefile | 46 +++--- bin/GWRAM.dbg.po | Bin 143360 -> 143360 bytes bin/GWRAM.po | Bin 143360 -> 143360 bytes bnc.sh | 4 + ram2e.c | 394 +++++++++++++------------------------------- ram2e_hal.c | 242 +++++++++++++++++++++++++++ ram2e_hal.h | 72 ++++++++ ram2e_hal_lcmxo2.c | 89 ++++++++++ ram2e_hal_max.c | 34 ++++ ram2e_hal_spi.c | 42 +++++ ram2gs.c | 178 ++++++-------------- ram2gs_asm.h | 8 - ram2gs_asm.s | 46 +++++- ram2gs_hal.c | 54 ++++++ ram2gs_hal.h | 19 +++ ram2gs_hal_lcmxo2.c | 88 ++++++++++ ram2gs_hal_max.c | 16 ++ ram2gs_hal_spi.c | 38 +++++ ramtest.c | 103 ------------ ramtest.h | 6 - ramtest.s | 190 --------------------- ramtestpat.c | 4 - util.c | 23 +-- util.h | 3 + 25 files changed, 944 insertions(+), 756 deletions(-) create mode 100755 bnc.sh create mode 100644 ram2e_hal.c create mode 100644 ram2e_hal.h create mode 100644 ram2e_hal_lcmxo2.c create mode 100644 ram2e_hal_max.c create mode 100644 ram2e_hal_spi.c delete mode 100644 ram2gs_asm.h create mode 100644 ram2gs_hal.c create mode 100644 ram2gs_hal.h create mode 100644 ram2gs_hal_lcmxo2.c create mode 100644 ram2gs_hal_max.c create mode 100644 ram2gs_hal_spi.c delete mode 100644 ramtest.c delete mode 100644 ramtest.h delete mode 100644 ramtest.s delete mode 100644 ramtestpat.c 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 7d0f5df085db5f16b7adeadd03ea0f989c8bb5f2..5d02111cab85294bcca13f2cc84bca73b640f558 100644 GIT binary patch delta 7775 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 HsnP!j1-nU1 delta 5589 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 delta 5630 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 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