mirror of
https://github.com/garrettsworkshop/GWRAM.SYSTEM.git
synced 2024-06-13 12:29:55 +00:00
Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ba6a9cf09b | ||
|
ea540e0321 | ||
|
5ecb7c90bf | ||
|
a3bf3ec152 | ||
|
5ae6aaa429 | ||
|
cf68a42152 | ||
|
745358d37b | ||
|
e8399af9da | ||
|
8622e2776a | ||
|
44bd31fe50 | ||
|
0dc8b9b981 | ||
|
ac1d41f282 | ||
|
c93999003d | ||
|
214c3f27ea | ||
|
bb0ae40761 | ||
|
54a61e6104 | ||
|
40481a8237 | ||
|
286c58269c | ||
|
6f5d9731af | ||
|
7cd9993b55 | ||
|
71cafa58a5 | ||
|
69095871ae | ||
|
d52bbe4757 | ||
|
ff31b44109 | ||
|
8a90077d1e | ||
|
75c06e1ccd | ||
|
312cba4375 | ||
|
8a76da3d31 | ||
|
4bba555e7d |
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
||||||
*.o
|
*.o
|
||||||
*.sys
|
*.sys
|
||||||
obj/*.s
|
obj/*.s
|
||||||
|
.vscode/*
|
||||||
|
|
BIN
Documentation/Banner.png
Normal file
BIN
Documentation/Banner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 200 KiB |
64
Makefile
64
Makefile
|
@ -1,4 +1,8 @@
|
||||||
all: GWRAM.po GWRAM.dbg.po
|
cflags = -O --cpu 6502 -t apple2
|
||||||
|
|
||||||
|
.PHONY: clean all copy
|
||||||
|
|
||||||
|
all: bin/GWRAM.po bin/GWRAM.dbg.po
|
||||||
|
|
||||||
obj:
|
obj:
|
||||||
@mkdir obj
|
@mkdir obj
|
||||||
|
@ -7,46 +11,60 @@ bin:
|
||||||
@mkdir bin
|
@mkdir bin
|
||||||
|
|
||||||
obj/main.o: obj main.c
|
obj/main.o: obj main.c
|
||||||
cc65 main.c -O --cpu 6502 -t apple2enh -o obj/main.s
|
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
|
obj/ram2e.o: obj ram2e.c
|
||||||
cc65 ram2e.c -O --cpu 6502 -t apple2enh -o obj/ram2e.s
|
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
|
obj/ram2e.dbg.o: obj ram2e.c
|
||||||
cc65 ram2e.c -O --cpu 6502 -t apple2enh -o obj/ram2e.dbg.s -DSKIP_RAM2E_DETECT
|
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
|
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
|
obj/ram2gs.o: obj ram2gs.c
|
||||||
cc65 ram2gs.c -O --cpu 6502 -t apple2enh -o obj/ram2gs.s
|
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
|
obj/ram2gs.dbg.o: obj ram2gs.c
|
||||||
cc65 ram2gs.c -O --cpu 6502 -t apple2enh -o obj/ram2gs.dbg.s -DSKIP_RAM2GS_DETECT
|
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
|
obj/util.o: obj util.c
|
||||||
cc65 util.c -O --cpu 6502 -t apple2enh -o obj/util.s
|
cc65 util.c $(cflags) -o obj/util.s
|
||||||
ca65 obj/util.s -o obj/util.o
|
ca65 obj/util.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: obj gwconio.s
|
||||||
ld65 -o bin/main.sys obj/main.o obj/ram2gs.o obj/ram2e.o obj/ram2gs_asm.o obj/util.o -C apple2enh-system.cfg --lib apple2enh.lib -D __EXEHDR__=0
|
ca65 gwconio.s -o $@
|
||||||
|
|
||||||
bin/main.dbg.sys: bin obj/main.o obj/ram2e.dbg.o obj/ram2gs.dbg.o obj/ram2gs_asm.o obj/util.o
|
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 bin/main.dbg.sys obj/main.o obj/ram2gs.dbg.o obj/ram2e.dbg.o obj/ram2gs_asm.o obj/util.o -C apple2enh-system.cfg --lib apple2enh.lib -D __EXEHDR__=0
|
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
|
||||||
|
|
||||||
GWRAM.po: bin/main.sys
|
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
|
||||||
|
|
||||||
|
bin/GWRAM.po: bin/main.sys
|
||||||
cp prodos140.po bin/GWRAM.po
|
cp prodos140.po bin/GWRAM.po
|
||||||
cat bin/main.sys | java -jar ./AppleCommander-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
|
cp prodos140.po bin/GWRAM.dbg.po
|
||||||
cat bin/main.dbg.sys | java -jar ./AppleCommander-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:
|
clean:
|
||||||
rm -fr bin obj
|
rm -fr bin obj
|
||||||
|
|
||||||
|
copy: bin/GWRAM.po
|
||||||
|
cp bin/GWRAM.po /Volumes/FLOPPYEMU/GWRAM.po
|
||||||
|
diskutil unmount /Volumes/FLOPPYEMU/
|
||||||
|
|
BIN
bin/GWRAM.dbg.po
BIN
bin/GWRAM.dbg.po
Binary file not shown.
BIN
bin/GWRAM.po
BIN
bin/GWRAM.po
Binary file not shown.
|
@ -36,7 +36,7 @@
|
||||||
.I16
|
.I16
|
||||||
.endmacro
|
.endmacro
|
||||||
|
|
||||||
.segment "CODE"
|
.code
|
||||||
|
|
||||||
.proc _gsram_getsize: near
|
.proc _gsram_getsize: near
|
||||||
.A8
|
.A8
|
||||||
|
|
9
gwconio.h
Normal file
9
gwconio.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef GWCONIO_H
|
||||||
|
#define GWCONIO_H
|
||||||
|
|
||||||
|
void gwcputsxy (unsigned char x, unsigned char y, const char* s);
|
||||||
|
void gwcputs (const char* s);
|
||||||
|
void __fastcall__ gwcputcxy (unsigned char x, unsigned char y, char c);
|
||||||
|
void __fastcall__ gwcputc (char c);
|
||||||
|
|
||||||
|
#endif /* GWCONIO_H */
|
122
gwconio.s
Normal file
122
gwconio.s
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
;
|
||||||
|
; Ullrich von Bassewitz, 06.08.1998
|
||||||
|
; Modified Sep. 6, 2020 by Zane Kaminski, Engineer @ Garrett's Workshop
|
||||||
|
;
|
||||||
|
;
|
||||||
|
.ifdef __APPLE2ENH__
|
||||||
|
.constructor initconio
|
||||||
|
.endif
|
||||||
|
.export _gwcputcxy, _gwcputc
|
||||||
|
.export _gwcputsxy, _gwcputs
|
||||||
|
.import _gwconiomask
|
||||||
|
.import gotoxy, VTABZ
|
||||||
|
.importzp ptr1, tmp1
|
||||||
|
|
||||||
|
.include "apple2.inc"
|
||||||
|
|
||||||
|
.segment "ONCE"
|
||||||
|
|
||||||
|
.ifdef __APPLE2ENH__
|
||||||
|
initconio:
|
||||||
|
sta SETALTCHAR ; Switch in alternate charset
|
||||||
|
bit LORES ; Limit SET80COL-HISCR to text
|
||||||
|
rts
|
||||||
|
.endif
|
||||||
|
|
||||||
|
.code
|
||||||
|
|
||||||
|
|
||||||
|
; void gwcputsxy (unsigned char x, unsigned char y, const char* s);
|
||||||
|
_gwcputsxy:
|
||||||
|
sta ptr1 ; Save s for later
|
||||||
|
stx ptr1+1
|
||||||
|
jsr gotoxy ; Set cursor, pop x and y
|
||||||
|
jmp L0 ; Same as cputs...
|
||||||
|
; void gwcputs (const char* s);
|
||||||
|
_gwcputs: sta ptr1 ; Save s
|
||||||
|
stx ptr1+1
|
||||||
|
L0: ldy #0
|
||||||
|
L1: lda (ptr1),y
|
||||||
|
beq L9 ; Jump if done
|
||||||
|
iny
|
||||||
|
sty tmp1 ; Save offset
|
||||||
|
jsr _gwcputc ; Output char, advance cursor
|
||||||
|
ldy tmp1 ; Get offset
|
||||||
|
bne L1 ; Next char
|
||||||
|
inc ptr1+1 ; Bump high byte
|
||||||
|
bne L1
|
||||||
|
; Done
|
||||||
|
L9: rts
|
||||||
|
|
||||||
|
|
||||||
|
; void __fastcall__ gwcputcxy (unsigned char x, unsigned char y, char c);
|
||||||
|
_gwcputcxy:
|
||||||
|
pha ; Save C
|
||||||
|
jsr gotoxy ; Call this one, will pop params
|
||||||
|
pla ; Restore C and run into _gwcputc
|
||||||
|
; void __fastcall__ gwcputc (char c);
|
||||||
|
_gwcputc:
|
||||||
|
cmp #$0D ; Test for \r = carrage return
|
||||||
|
beq left
|
||||||
|
cmp #$0A ; Test for \n = line feed
|
||||||
|
beq newline
|
||||||
|
eor #$80 ; Invert high bit
|
||||||
|
; .ifndef __APPLE2ENH__
|
||||||
|
cmp #$E0 ; Test for lowercase
|
||||||
|
bcc cputdirect
|
||||||
|
; and #$DF ; Convert to uppercase
|
||||||
|
and _gwconiomask ; Convert to uppercase using mask
|
||||||
|
; .endif
|
||||||
|
|
||||||
|
cputdirect:
|
||||||
|
jsr putchar
|
||||||
|
inc CH ; Bump to next column
|
||||||
|
lda CH
|
||||||
|
cmp WNDWDTH
|
||||||
|
bcc :+
|
||||||
|
jsr newline
|
||||||
|
left: lda #$00 ; Goto left edge of screen
|
||||||
|
sta CH
|
||||||
|
: rts
|
||||||
|
|
||||||
|
newline:
|
||||||
|
inc CV ; Bump to next line
|
||||||
|
lda CV
|
||||||
|
cmp WNDBTM
|
||||||
|
bcc :+
|
||||||
|
lda WNDTOP ; Goto top of screen
|
||||||
|
sta CV
|
||||||
|
: jmp VTABZ
|
||||||
|
|
||||||
|
putchar:
|
||||||
|
.ifdef __APPLE2ENH__
|
||||||
|
ldy INVFLG
|
||||||
|
cpy #$FF ; Normal character display mode?
|
||||||
|
beq putchardirect
|
||||||
|
cmp #$E0 ; Lowercase?
|
||||||
|
bcc mask
|
||||||
|
and #$7F ; Inverse lowercase
|
||||||
|
bra putchardirect
|
||||||
|
.endif
|
||||||
|
mask: and INVFLG ; Apply normal, inverse, flash
|
||||||
|
|
||||||
|
putchardirect:
|
||||||
|
pha
|
||||||
|
ldy CH
|
||||||
|
.ifdef __APPLE2ENH__
|
||||||
|
bit RD80VID ; In 80 column mode?
|
||||||
|
bpl put ; No, just go ahead
|
||||||
|
tya
|
||||||
|
lsr ; Div by 2
|
||||||
|
tay
|
||||||
|
bcs put ; Odd cols go in main memory
|
||||||
|
bit HISCR ; Assume SET80COL
|
||||||
|
.endif
|
||||||
|
put: lda (BASL),Y ; Get current character
|
||||||
|
tax ; Return old character for _cgetc
|
||||||
|
pla
|
||||||
|
sta (BASL),Y
|
||||||
|
.ifdef __APPLE2ENH__
|
||||||
|
bit LOWSCR ; Doesn't hurt in 40 column mode
|
||||||
|
.endif
|
||||||
|
rts
|
16
main.c
16
main.c
|
@ -4,9 +4,14 @@
|
||||||
|
|
||||||
#include "ram2e.h"
|
#include "ram2e.h"
|
||||||
#include "ram2gs.h"
|
#include "ram2gs.h"
|
||||||
|
#include "gwconio.h"
|
||||||
|
|
||||||
|
char gwconiomask;
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
gwconiomask = 0xFF;
|
||||||
|
|
||||||
// First clear screen
|
// First clear screen
|
||||||
clrscr();
|
clrscr();
|
||||||
|
|
||||||
|
@ -19,16 +24,15 @@ int main(void)
|
||||||
__asm__("sta $C073");
|
__asm__("sta $C073");
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
case APPLE_IIGS:
|
case APPLE_IIGS:
|
||||||
ram2gs_main();
|
ram2gs_main();
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
default:
|
default:
|
||||||
|
gwconiomask = 0xDF;
|
||||||
// If not on IIe or IIgs, show an error message and quit
|
// If not on IIe or IIgs, show an error message and quit
|
||||||
gotoxy(0, 8);
|
gwcputsxy(0, 8, " THIS PROGRAM REQUIRES APPLE IIE OR IIGS");
|
||||||
cputs(" THIS PROGRAM REQUIRES APPLE IIE OR IIGS");
|
gwcputsxy(0, 10, " PRESS ANY KEY TO QUIT.");
|
||||||
gotoxy(0, 10);
|
|
||||||
cputs(" PRESS ANY KEY TO QUIT.");
|
|
||||||
cgetc(); // Wait for key
|
cgetc(); // Wait for key
|
||||||
clrscr(); // Clear screen before quitting
|
clrscr(); // Clear screen before quitting
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
459
ram2e.c
459
ram2e.c
|
@ -6,324 +6,119 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "gwconio.h"
|
||||||
|
#include "ram2e_hal.h"
|
||||||
|
#include "ram2e_save.h"
|
||||||
|
|
||||||
static char _rwsave[256];
|
static void menu()
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
gotoxy(5, 1);
|
clrscr(); // Clear screen
|
||||||
cputs("-- RAM2E Capacity Settings --");
|
|
||||||
|
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); }
|
if (bankcount < 2) { gotoxy(5, 3); }
|
||||||
else { gotoxy(4, 3); }
|
else { gotoxy(4, 3); }
|
||||||
printf("Current RAM2E capacity: %d kB", bankcount * 64);
|
gwcputs("Current RAM2E capacity: ");
|
||||||
|
printf("%d", bankcount * 64);
|
||||||
|
gwcputs(" kB");
|
||||||
|
|
||||||
gotoxy(1, 5);
|
if(has16m) { gwcputsxy(4, 12, "6. 16 megabytes"); }
|
||||||
cputs("Select desired memory capacity:");
|
}
|
||||||
|
|
||||||
gotoxy(4, 7);
|
static void menu_led(char enled) {
|
||||||
cputs("1. 64 kilobytes");
|
if (enled) {
|
||||||
gotoxy(4, 9);
|
gwcputsxy(1, 14, "LED enabled. Press [L] to disable LED.");
|
||||||
cputs("2. 512 kilobytes");
|
} else {
|
||||||
gotoxy(4, 11);
|
gwcputsxy(1, 14, "LED disabled. Press [L] to enable LED.");
|
||||||
cputs("3. 1 megabyte");
|
}
|
||||||
gotoxy(4, 13);
|
|
||||||
cputs("4. 4 megabytes");
|
|
||||||
gotoxy(4, 15);
|
|
||||||
cputs("5. 8 megabytes");
|
|
||||||
|
|
||||||
gotoxy(1, 18);
|
|
||||||
cputs("Capacity will be saved until power-off.");
|
|
||||||
|
|
||||||
gotoxy(1, 20);
|
|
||||||
cputs("To remember capacity setting in");
|
|
||||||
gotoxy(1, 21);
|
|
||||||
cputs("nonvolatile memory, press Apple+number.");
|
|
||||||
|
|
||||||
gotoxy(1, 23);
|
|
||||||
cputs("Press [Q] to quit without saving.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ram2e_main(void)
|
int ram2e_main(void)
|
||||||
{
|
{
|
||||||
char mask;
|
char type;
|
||||||
char nvm;
|
|
||||||
int reset_count;
|
|
||||||
uint16_t bankcount;
|
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
|
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();
|
ramworks_restore();
|
||||||
// If no RAM2E, show an error message and quit
|
// If no RAM2E, show an error message and quit
|
||||||
gotoxy(0, 8);
|
gwcputsxy(0, 8, " No RAM2E II detected.");
|
||||||
cputs(" No RAM2E II detected.");
|
gwcputsxy(0, 10, " Press any key to quit.");
|
||||||
gotoxy(0, 10);
|
|
||||||
cputs(" Press any key to quit.");
|
|
||||||
cgetc(); // Wait for key
|
cgetc(); // Wait for key
|
||||||
clrscr(); // Clear screen before quitting
|
clrscr(); // Clear screen before quitting
|
||||||
return EXIT_SUCCESS;
|
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();
|
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
|
ramworks_restore(); // Restore RAMWorks contents
|
||||||
|
|
||||||
// Get user choice from menu
|
// Get user choice from menu
|
||||||
mask = 0;
|
|
||||||
nvm = 0;
|
|
||||||
reset_count = 0;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// Set capacity mask or quit according to keypress.
|
// Set capacity mask or quit according to keypress.
|
||||||
switch (toupper(cgetc() & 0x7F)) {
|
switch (toupper(cgetc() & 0x7F)) {
|
||||||
|
@ -336,29 +131,48 @@ int ram2e_main(void)
|
||||||
case '3': mask = 0x0F; break;
|
case '3': mask = 0x0F; break;
|
||||||
case '4': mask = 0x3F; break;
|
case '4': mask = 0x3F; break;
|
||||||
case '5': mask = 0x7F; 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++;
|
reset_count++;
|
||||||
if (reset_count >= 100) {
|
if (reset_count >= 25) {
|
||||||
// Show message about saving.
|
// Show message about resetting.
|
||||||
clrscr(); // Clear screen
|
clrscr(); // Clear screen
|
||||||
gotoxy(1, 8);
|
gwcputsxy(1, 8, "Resetting RAM2E settings.");
|
||||||
cputs("Resetting RAM2E settings.");
|
gwcputsxy(1, 9, "Do not turn off your Apple.");
|
||||||
gotoxy(1, 9);
|
|
||||||
cputs("Do not turn off your Apple.");
|
|
||||||
|
|
||||||
ufm_erase(); // Erase RAM2E settings memory
|
ram2e_erase(); // Erase RAM2E settings memory
|
||||||
set_mask_temp(0x7F); // Set mask to default (0x7F)
|
ram2e_set_mask(0x7F); // Set mask to default (0x7F)
|
||||||
|
|
||||||
// Wait for >= 500ms on even the fastest systems.
|
// Wait for >= 500ms on even the fastest systems.
|
||||||
spin(32, 8);
|
spin(32, 8);
|
||||||
|
|
||||||
// Show success message and quit
|
// Show success message and quit
|
||||||
clrscr(); // Clear screen
|
clrscr(); // Clear screen
|
||||||
gotoxy(1, 8);
|
gwcputsxy(1, 8, "RAM2E settings reset successfully.");
|
||||||
cputs("RAM2E settings reset successfully.");
|
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
} default: continue;
|
continue;
|
||||||
|
} default: reset_count = 0; continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if pressed with apple key. If so, save to nonvolatile memory.
|
// Check if pressed with apple key. If so, save to nonvolatile memory.
|
||||||
|
@ -367,43 +181,36 @@ int ram2e_main(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set capacity in volatile memory.
|
// Set capacity in volatile memory.
|
||||||
set_mask_temp(mask);
|
ram2e_set_mask(mask);
|
||||||
|
|
||||||
// Clear screen in preparation to show saving or success message.
|
// Clear screen in preparation to show saving or success message.
|
||||||
clrscr();
|
clrscr();
|
||||||
|
|
||||||
if (nvm) { // Save in NVM if requested.
|
if (nvm) { // Save in NVM if requested.
|
||||||
// Show message about saving.
|
// Show message about saving.
|
||||||
gotoxy(1, 8);
|
gwcputsxy(1, 8, "Saving RAM2E capacity setting.");
|
||||||
cputs("Saving RAM2E capacity setting.");
|
gwcputsxy(1, 9, "Do not turn off your Apple.");
|
||||||
gotoxy(1, 9);
|
|
||||||
cputs("Do not turn off your Apple.");
|
|
||||||
// Save capacity in nonvolatile memory.
|
// Save capacity in nonvolatile memory.
|
||||||
set_nvm(mask);
|
ram2e_save_start(mask, enled);
|
||||||
// Wait for >= 500ms on even the fastest systems.
|
// Wait for >= 500ms on even the fastest systems.
|
||||||
spin(32, 8);
|
spin(32, 8);
|
||||||
|
// Finish saving
|
||||||
|
ram2e_save_end(mask, enled);
|
||||||
// Print success message
|
// Print success message
|
||||||
clrscr(); // Clear screen
|
clrscr(); // Clear screen
|
||||||
gotoxy(1, 8);
|
gwcputsxy(1, 8, "RAM2E capacity saved successfully.");
|
||||||
cputs("RAM2E capacity saved successfully.");
|
|
||||||
} else { // Print success message if not saving in NVM.
|
} else { // Print success message if not saving in NVM.
|
||||||
gotoxy(1, 8);
|
gwcputsxy(1, 8, "RAM2E capacity set successfully.");
|
||||||
cputs("RAM2E capacity set successfully.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (nvm) { // Show end message for nonvolatile save
|
if (nvm) { // Show end message for nonvolatile save
|
||||||
gotoxy(1, 10);
|
gwcputsxy(1, 10, "You may now turn off your Apple.");
|
||||||
cputs("You may now turn off your Apple.");
|
gwcputsxy(1, 12, "You may also reset your Apple for");
|
||||||
gotoxy(1, 12);
|
gwcputsxy(1, 13, "the setting change to take effect.");
|
||||||
cputs("You may also reset your Apple for");
|
|
||||||
gotoxy(1, 13);
|
|
||||||
cputs("the setting change to take effect.");
|
|
||||||
} else { // Show end message for volatile save
|
} else { // Show end message for volatile save
|
||||||
gotoxy(1, 10);
|
gwcputsxy(1, 10, "Please reset your Apple for");
|
||||||
cputs("Please reset your Apple for");
|
gwcputsxy(1, 11, "the setting change to take effect.");
|
||||||
gotoxy(1, 11);
|
|
||||||
cputs("the setting change to take effect.");
|
|
||||||
}
|
}
|
||||||
// Don't quit. Instead leave prompt asking user to reset.
|
// Don't quit. Instead leave prompt asking user to reset.
|
||||||
while(1) { cgetc(); }
|
while(1) { cgetc(); }
|
||||||
|
|
242
ram2e_hal.c
Normal file
242
ram2e_hal.c
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "util.h"
|
||||||
|
#include "ram2e_hal.h"
|
||||||
|
|
||||||
|
static char _cmd_cmd;
|
||||||
|
static char _cmd_arg;
|
||||||
|
/* ram2e_cmd(...) issues a coded command+argument sequence to the RAM2E */
|
||||||
|
static void ram2e_cmd(char cmd, char arg) {
|
||||||
|
// Load operation and data bytes into X and Y registers
|
||||||
|
// in preparation for command sequence
|
||||||
|
_cmd_cmd = cmd;
|
||||||
|
_cmd_arg = arg;
|
||||||
|
__asm__("ldx %v", _cmd_cmd); // X = command
|
||||||
|
__asm__("ldy %v", _cmd_arg); // Y = argument
|
||||||
|
|
||||||
|
// First, reset command sequence just in case it,
|
||||||
|
// for some reason, has not timed out. (e.g. crazy fast accelerator?)
|
||||||
|
// Write 0 twice because command and argument steps always advance seq.
|
||||||
|
__asm__("lda #0");
|
||||||
|
__asm__("sta $C073");
|
||||||
|
__asm__("sta $C073");
|
||||||
|
|
||||||
|
// Command sequence
|
||||||
|
__asm__("lda #$FF");
|
||||||
|
__asm__("sta $C073");
|
||||||
|
__asm__("lda #$00");
|
||||||
|
__asm__("sta $C073");
|
||||||
|
__asm__("lda #$55");
|
||||||
|
__asm__("sta $C073");
|
||||||
|
__asm__("lda #$AA");
|
||||||
|
__asm__("sta $C073");
|
||||||
|
__asm__("lda #$C1");
|
||||||
|
__asm__("sta $C073");
|
||||||
|
__asm__("lda #$AD");
|
||||||
|
__asm__("sta $C073");
|
||||||
|
// Command
|
||||||
|
__asm__("stx $C073");
|
||||||
|
// Argument
|
||||||
|
__asm__("sty $C073");
|
||||||
|
|
||||||
|
// Reset RAMWorks bank register just in case
|
||||||
|
__asm__("lda #0");
|
||||||
|
__asm__("sta $C073");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* auxram_detect() returns true if a RAMWorks memory is detected */
|
||||||
|
char auxram_detect() {
|
||||||
|
// Switch to RW bank 0 for ZP
|
||||||
|
__asm__("lda #$00"); // Get 0x00
|
||||||
|
__asm__("sta $C009"); // Store in ALTZP
|
||||||
|
__asm__("sta $C073"); // Set RW bank 0
|
||||||
|
|
||||||
|
// Store 00 FF 55 AA in RW bank 0 ZP
|
||||||
|
__asm__("lda #$00");
|
||||||
|
__asm__("sta $00");
|
||||||
|
__asm__("lda #$FF");
|
||||||
|
__asm__("sta $01");
|
||||||
|
__asm__("lda #$55");
|
||||||
|
__asm__("sta $02");
|
||||||
|
__asm__("lda #$AA");
|
||||||
|
__asm__("sta $03");
|
||||||
|
|
||||||
|
// Check for 00 FF 55 AA
|
||||||
|
__asm__("lda $00");
|
||||||
|
__asm__("cmp #$00");
|
||||||
|
__asm__("bne %g", noramworks);
|
||||||
|
__asm__("lda $01");
|
||||||
|
__asm__("cmp #$FF");
|
||||||
|
__asm__("bne %g", noramworks);
|
||||||
|
__asm__("lda $02");
|
||||||
|
__asm__("cmp #$55");
|
||||||
|
__asm__("bne %g", noramworks);
|
||||||
|
__asm__("lda $03");
|
||||||
|
__asm__("cmp #$AA");
|
||||||
|
__asm__("bne %g", noramworks);
|
||||||
|
|
||||||
|
// Found aux ram card
|
||||||
|
__asm__("sta $C008"); // Don't store in ALTZP
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Not found
|
||||||
|
noramworks:
|
||||||
|
__asm__("sta $C008"); // Don't store in ALTZP
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ram2e_detect() returns true if a RAM2E II has been detected */
|
||||||
|
static uint8_t _detect;
|
||||||
|
char ram2e_detect(char command) {
|
||||||
|
#ifdef SKIP_RAM2E_DETECT
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
// Move command into X register
|
||||||
|
_detect = command;
|
||||||
|
__asm__("lda %v", _detect); // Save in _detect
|
||||||
|
__asm__("tax");
|
||||||
|
|
||||||
|
// Store in ALTZP
|
||||||
|
__asm__("sta $C009");
|
||||||
|
|
||||||
|
// Store 0x00 at beginning of bank 0x00
|
||||||
|
__asm__("lda #$00");
|
||||||
|
__asm__("sta $C073");
|
||||||
|
__asm__("sta $00");
|
||||||
|
|
||||||
|
// Send SetRWBankFF-class command
|
||||||
|
__asm__("lda #$FF");
|
||||||
|
__asm__("sta $C073");
|
||||||
|
__asm__("lda #$00");
|
||||||
|
__asm__("sta $C073");
|
||||||
|
__asm__("lda #$55");
|
||||||
|
__asm__("sta $C073");
|
||||||
|
__asm__("lda #$AA");
|
||||||
|
__asm__("sta $C073");
|
||||||
|
__asm__("lda #$C1");
|
||||||
|
__asm__("sta $C073");
|
||||||
|
__asm__("lda #$AD");
|
||||||
|
__asm__("sta $C073");
|
||||||
|
__asm__("stx $C073");
|
||||||
|
__asm__("lda #$00");
|
||||||
|
__asm__("sta $C073");
|
||||||
|
// Now bank should be 0xFF if we are running on a RAM2E II
|
||||||
|
// Other RAMWorks cards will instead set the bank to 0x00
|
||||||
|
|
||||||
|
// Store 0xFF in this bank
|
||||||
|
__asm__("lda #$FF");
|
||||||
|
__asm__("sta $00");
|
||||||
|
|
||||||
|
// Go back to bank 0
|
||||||
|
__asm__("lda #$00");
|
||||||
|
__asm__("sta $C073");
|
||||||
|
__asm__("sta $C073");
|
||||||
|
|
||||||
|
// Save result and return
|
||||||
|
__asm__("lda $00"); // Get beginning of bank 0
|
||||||
|
__asm__("sta $C008"); // Store in STDZP
|
||||||
|
__asm__("sta %v", _detect); // Save in _detect
|
||||||
|
return _detect == 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ramworks_getsize() returns the number of banks of RAM2E aux memory */
|
||||||
|
static uint8_t _rwsize;
|
||||||
|
static uint8_t _rwnot16mb;
|
||||||
|
uint16_t ramworks_getsize() {
|
||||||
|
_rwnot16mb = 1; // Set "not 16 mb" flag
|
||||||
|
|
||||||
|
// Store bank number at address 0 in each bnak
|
||||||
|
__asm__("sta $C009"); // ALTZP
|
||||||
|
__asm__("ldy #$FF"); // Start at bank 0xFF
|
||||||
|
BankSetLoop:
|
||||||
|
__asm__("sty $C073"); // Set bank
|
||||||
|
__asm__("sty $00"); // Store bank number at 0
|
||||||
|
__asm__("dey"); // Prev. bank
|
||||||
|
__asm__("cpy #$FF"); // Have we wrapped around?
|
||||||
|
__asm__("bne %g", BankSetLoop); // If not, repeat
|
||||||
|
|
||||||
|
// Count banks with matching bank number
|
||||||
|
__asm__("ldy #$00"); // Y is bank
|
||||||
|
__asm__("ldx #$00"); // X is count
|
||||||
|
CountLoop:
|
||||||
|
__asm__("sty $C073"); // Set bank
|
||||||
|
__asm__("cpy $00"); // Is bank num stored at address 0?
|
||||||
|
__asm__("bne %g", AfterInc); // If not, skip increment
|
||||||
|
__asm__("inx"); // If so, increment bank count
|
||||||
|
__asm__("bne %g", AfterInc); // Skip next if x!=0
|
||||||
|
__asm__("stx %v", _rwnot16mb); // Othwerwise rolled over so clear rwnot16mb
|
||||||
|
AfterInc:
|
||||||
|
__asm__("iny"); // Move to next bank
|
||||||
|
__asm__("bne %g", CountLoop); // Repeat if not on bank 0
|
||||||
|
|
||||||
|
// Done. Switch back to regular zeropage and get result.
|
||||||
|
__asm__("sta $C008"); // STDZP
|
||||||
|
__asm__("stx %v", _rwsize); // _rwsize = X (bank count)
|
||||||
|
|
||||||
|
if (_rwnot16mb) { return _rwsize; }
|
||||||
|
else { return 256; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ram2e_set_mask(...) sends the "Set RAMWorks Capacity Mask" to the RAM2E */
|
||||||
|
void ram2e_set_mask(char mask) { ram2e_cmd(0xE0, mask); }
|
||||||
|
|
||||||
|
/* ram2e_set_led(...) */
|
||||||
|
void ram2e_set_led(char enled) { ram2e_cmd(0xE2, enled); }
|
||||||
|
|
||||||
|
|
||||||
|
static void ram2e_flashled1() {
|
||||||
|
__asm__("sta $C009"); // ALTZP
|
||||||
|
|
||||||
|
// Save address 0x0000 in every bank
|
||||||
|
__asm__("lda $0");
|
||||||
|
__asm__("lda $0");
|
||||||
|
__asm__("lda $0");
|
||||||
|
__asm__("lda $0");
|
||||||
|
__asm__("lda $0");
|
||||||
|
__asm__("lda $0");
|
||||||
|
__asm__("lda $0");
|
||||||
|
__asm__("lda $0");
|
||||||
|
|
||||||
|
__asm__("sta $C008"); // No ALTZP
|
||||||
|
}
|
||||||
|
void ram2e_flashled(char frames) {
|
||||||
|
char i;
|
||||||
|
for (i = 0; i < frames; i++) {
|
||||||
|
unsigned int l;
|
||||||
|
for (l = 0; *VBL < 0 && l < 2500; l++) { ram2e_flashled1(); }
|
||||||
|
for (l = 0; *VBL >= 0 && l < 2500; l++) { ram2e_flashled1(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "ram2e_hal_max.c"
|
||||||
|
#include "ram2e_hal_spi.c"
|
||||||
|
#include "ram2e_hal_lcmxo2.c"
|
||||||
|
|
||||||
|
static char _type;
|
||||||
|
void ram2e_hal_set_type(char type) { _type = type; }
|
||||||
|
|
||||||
|
void ram2e_erase() {
|
||||||
|
switch (_type) {
|
||||||
|
case 0xFF: ram2e_max_erase(); break; // Altera MAX II / V
|
||||||
|
case 0xFE: ram2e_spi_erase(); break; // Lattice MachXO / iCE40 / AGM AG256
|
||||||
|
case 0xFD: ram2e_lcmxo2_erase(); break; // Lattice MachXO2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void ram2e_save_start(char mask, char enled) {
|
||||||
|
switch (_type) {
|
||||||
|
case 0xFF: ram2e_max_save(mask, enled); break; // Altera MAX II / V
|
||||||
|
case 0xFE: ram2e_spi_erase(); break; // Lattice MachXO / iCE40 / AGM AG256
|
||||||
|
case 0xFD: ram2e_lcmxo2_erase(); break; // Lattice MachXO2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void ram2e_save_end(char mask, char enled) {
|
||||||
|
switch (_type) {
|
||||||
|
case 0xFF: break; // Altera MAX II / V
|
||||||
|
case 0xFE: ram2e_spi_save(mask, enled); break; // Lattice MachXO / iCE40 / AGM AG256
|
||||||
|
case 0xFD: ram2e_lcmxo2_save(mask, enled); break; // Lattice MachXO2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
18
ram2e_hal.h
Normal file
18
ram2e_hal.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef RAM2E_HAL_H
|
||||||
|
#define RAM2E_HAL_H
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
char auxram_detect();
|
||||||
|
char ram2e_detect(char type);
|
||||||
|
uint16_t ramworks_getsize();
|
||||||
|
void ram2e_set_mask(char mask);
|
||||||
|
void ram2e_set_led(char enled);
|
||||||
|
void ram2e_flashled(char frames);
|
||||||
|
|
||||||
|
void ram2e_hal_set_type(char type);
|
||||||
|
void ram2e_erase();
|
||||||
|
void ram2e_save_start(char mask, char enled);
|
||||||
|
void ram2e_save_end(char mask, char enled);
|
||||||
|
|
||||||
|
#endif
|
89
ram2e_hal_lcmxo2.c
Normal file
89
ram2e_hal_lcmxo2.c
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
/* _spi_erase(...) */
|
||||||
|
static void ram2e_lcmxo2_rw(char we, char addr, char data) {
|
||||||
|
ram2e_cmd(0xEC, data);
|
||||||
|
ram2e_cmd(0xEC, addr);
|
||||||
|
ram2e_cmd(0xED, we ? 1 : 0);
|
||||||
|
}
|
||||||
|
static void ram2e_lcmxo2_open() { ram2e_lcmxo2_rw(1, 0x70, 0x80); }
|
||||||
|
static void ram2e_lcmxo2_close() { ram2e_lcmxo2_rw(1, 0x70, 0x00); }
|
||||||
|
static void ram2e_lcmxo2_cmd_op3(char cmd, char op1, char op2, char op3) {
|
||||||
|
ram2e_lcmxo2_open();
|
||||||
|
ram2e_lcmxo2_rw(1, 0x71, cmd); // Command
|
||||||
|
ram2e_lcmxo2_rw(1, 0x71, op1); // Operand 1/3
|
||||||
|
ram2e_lcmxo2_rw(1, 0x71, op2); // Operand 2/3
|
||||||
|
ram2e_lcmxo2_rw(1, 0x71, op3); // Operand 3/3
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ram2e_lcmxo2_encfg() {
|
||||||
|
ram2e_lcmxo2_cmd_op3(0x74, 0x08, 0x00, 0x00);
|
||||||
|
ram2e_lcmxo2_close();
|
||||||
|
}
|
||||||
|
static void ram2e_lcmxo2_discfg() {
|
||||||
|
ram2e_lcmxo2_cmd_op3(0x26, 0x08, 0x00, 0x00);
|
||||||
|
ram2e_lcmxo2_close();
|
||||||
|
}
|
||||||
|
static void ram2e_lcmxo2_bypass() {
|
||||||
|
ram2e_lcmxo2_open();
|
||||||
|
ram2e_lcmxo2_rw(1, 0x71, 0xFF); // Command
|
||||||
|
ram2e_lcmxo2_close();
|
||||||
|
}
|
||||||
|
static void ram2e_lcmxo2_pollstat() {
|
||||||
|
ram2e_lcmxo2_cmd_op3(0x3C, 0x00, 0x00, 0x00);
|
||||||
|
ram2e_lcmxo2_rw(0, 0x73, 0x00); // Data 1/4
|
||||||
|
ram2e_lcmxo2_rw(0, 0x73, 0x00); // Data 2/4
|
||||||
|
ram2e_lcmxo2_rw(0, 0x73, 0x00); // Data 3/4
|
||||||
|
ram2e_lcmxo2_rw(0, 0x73, 0x00); // Data 4/4
|
||||||
|
ram2e_lcmxo2_close();
|
||||||
|
}
|
||||||
|
static void ram2e_lcmxo2_erase() {
|
||||||
|
// Enable configuration interface
|
||||||
|
ram2e_lcmxo2_encfg();
|
||||||
|
// Poll status register
|
||||||
|
ram2e_lcmxo2_pollstat();
|
||||||
|
|
||||||
|
// Erase UFM
|
||||||
|
ram2e_lcmxo2_cmd_op3(0xCB, 0x00, 0x00, 0x00);
|
||||||
|
ram2e_lcmxo2_close();
|
||||||
|
}
|
||||||
|
static void ram2e_lcmxo2_save(char mask, char enled) {
|
||||||
|
char i;
|
||||||
|
// Poll status register
|
||||||
|
ram2e_lcmxo2_pollstat();
|
||||||
|
// Disable configuration interface
|
||||||
|
ram2e_lcmxo2_discfg();
|
||||||
|
// Bypass
|
||||||
|
ram2e_lcmxo2_bypass();
|
||||||
|
// Enable configuration interface
|
||||||
|
ram2e_lcmxo2_encfg();
|
||||||
|
// Poll status register
|
||||||
|
ram2e_lcmxo2_pollstat();
|
||||||
|
|
||||||
|
// Set UFM address
|
||||||
|
ram2e_lcmxo2_cmd_op3(0xB4, 0x00, 0x00, 0x00);
|
||||||
|
ram2e_lcmxo2_rw(1, 0x71, 0x40); // Data 1/4
|
||||||
|
ram2e_lcmxo2_rw(1, 0x71, 0x00); // Data 2/4
|
||||||
|
ram2e_lcmxo2_rw(1, 0x71, 0x00); // Data 3/4
|
||||||
|
ram2e_lcmxo2_rw(1, 0x71, 190); // Data 4/4
|
||||||
|
ram2e_lcmxo2_close();
|
||||||
|
|
||||||
|
// Write UFM page
|
||||||
|
ram2e_lcmxo2_cmd_op3(0xC9, 0x00, 0x00, 0x01);
|
||||||
|
// Data 0
|
||||||
|
mask = (mask & 0x80) | (~mask & 0x7F);
|
||||||
|
ram2e_lcmxo2_rw(1, 0x71, mask);
|
||||||
|
// Data 1
|
||||||
|
if (enled) ram2e_lcmxo2_rw(1, 0x71, 1);
|
||||||
|
else ram2e_lcmxo2_rw(1, 0x71, 0);
|
||||||
|
// Data 2-15
|
||||||
|
for (i = 2; i < 16; i++) {
|
||||||
|
ram2e_lcmxo2_rw(1, 0x71, 0x00);
|
||||||
|
}
|
||||||
|
ram2e_lcmxo2_close();
|
||||||
|
|
||||||
|
// Poll status register
|
||||||
|
ram2e_lcmxo2_pollstat();
|
||||||
|
// Disable configuration interface
|
||||||
|
ram2e_lcmxo2_discfg();
|
||||||
|
// Bypass
|
||||||
|
ram2e_lcmxo2_bypass();
|
||||||
|
}
|
43
ram2e_hal_max.c
Normal file
43
ram2e_hal_max.c
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/* 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 wmask;
|
||||||
|
|
||||||
|
// Encode 0xFF mask properly
|
||||||
|
if (mask == 0xFF) { wmask = 0x80; }
|
||||||
|
else { wmask = mask; }
|
||||||
|
|
||||||
|
// Shift mask into UFMD
|
||||||
|
ram2e_max_bitbang(0x80 | ((wmask >> 1) & 0x40));
|
||||||
|
ram2e_max_bitbang(0x80 | ((wmask >> 0) & 0x40));
|
||||||
|
ram2e_max_bitbang(0x80 | ((wmask << 1) & 0x40));
|
||||||
|
ram2e_max_bitbang(0x80 | ((wmask << 2) & 0x40));
|
||||||
|
ram2e_max_bitbang(0x80 | ((wmask << 3) & 0x40));
|
||||||
|
ram2e_max_bitbang(0x80 | ((wmask << 4) & 0x40));
|
||||||
|
ram2e_max_bitbang(0x80 | ((wmask << 5) & 0x40));
|
||||||
|
ram2e_max_bitbang(0x80 | ((wmask << 6) & 0x40));
|
||||||
|
|
||||||
|
// Shift mask into UFMD
|
||||||
|
if (( enled && (wmask >> 7)) ||
|
||||||
|
(!enled && !(wmask >> 7))) {
|
||||||
|
ram2e_max_bitbang(0x80);
|
||||||
|
} else { ram2e_max_bitbang(0xC0); }
|
||||||
|
ram2e_max_bitbang(0xC0);
|
||||||
|
ram2e_max_bitbang(0xC0);
|
||||||
|
ram2e_max_bitbang(0xC0);
|
||||||
|
ram2e_max_bitbang(0xC0);
|
||||||
|
ram2e_max_bitbang(0xC0);
|
||||||
|
ram2e_max_bitbang(0xC0);
|
||||||
|
ram2e_max_bitbang(0xC0);
|
||||||
|
|
||||||
|
// Program UFM
|
||||||
|
ram2e_max_program();
|
||||||
|
}
|
42
ram2e_hal_spi.c
Normal file
42
ram2e_hal_spi.c
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
static void ram2e_spi_select() { ram2e_cmd(0xEB, 0x04); }
|
||||||
|
static void ram2e_spi_deselect() { ram2e_cmd(0xEB, 0x00); }
|
||||||
|
static void ram2e_spi_tx8(char data) {
|
||||||
|
char i;
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
char d = (data >> (7-i)) & 1;
|
||||||
|
d <<= 1;
|
||||||
|
d |= 0x04;
|
||||||
|
ram2e_cmd(0xEB, d);
|
||||||
|
d |= 0x01;
|
||||||
|
ram2e_cmd(0xEB, d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void ram2e_spi_wren() {
|
||||||
|
ram2e_spi_deselect();
|
||||||
|
ram2e_spi_select();
|
||||||
|
ram2e_spi_tx8(0x06); // 0x06 is write enable
|
||||||
|
ram2e_spi_deselect();
|
||||||
|
}
|
||||||
|
static void ram2e_spi_erase() {
|
||||||
|
ram2e_spi_wren();
|
||||||
|
ram2e_spi_select();
|
||||||
|
ram2e_spi_tx8(0x20); // 0x20 is sector erase (4 kB)
|
||||||
|
ram2e_spi_tx8(0x00); // address[23:16]
|
||||||
|
ram2e_spi_tx8(0x10); // address[15:8]
|
||||||
|
ram2e_spi_tx8(0x00); // address[7:0]
|
||||||
|
ram2e_spi_deselect();
|
||||||
|
}
|
||||||
|
static void ram2e_spi_save(char en8meg, char enled) {
|
||||||
|
ram2e_spi_wren();
|
||||||
|
ram2e_spi_select();
|
||||||
|
ram2e_spi_tx8(0x02); // 0x02 is page (byte) program
|
||||||
|
ram2e_spi_tx8(0x00); // address[23:16]
|
||||||
|
ram2e_spi_tx8(0x10); // address[15:8]
|
||||||
|
ram2e_spi_tx8(0x00); // address[7:0]
|
||||||
|
// data[7:0]
|
||||||
|
if (!en8meg && !enled) { ram2e_spi_tx8(0x7F); }
|
||||||
|
else if (!en8meg && enled) { ram2e_spi_tx8(0x3F); }
|
||||||
|
else if ( en8meg && !enled) { ram2e_spi_tx8(0xFF); }
|
||||||
|
else if ( en8meg && enled) { ram2e_spi_tx8(0xBF); }
|
||||||
|
ram2e_spi_deselect();
|
||||||
|
}
|
58
ram2e_save.h
Normal file
58
ram2e_save.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#ifndef RAM2E_SAVE_H
|
||||||
|
#define RAM2E_SAVE_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
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
209
ram2gs.c
209
ram2gs.c
|
@ -6,91 +6,101 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "ram2gs_asm.h"
|
#include "gwconio.h"
|
||||||
|
#include "ram2gs_hal.h"
|
||||||
|
|
||||||
static void ram2gs_erase() { ram2gs_cmd(0x28); }
|
static void menu()
|
||||||
static void ram2gs_program() { ram2gs_cmd(0x24); }
|
{
|
||||||
static void ram2gs_set4mb() { ram2gs_cmd(0x10); }
|
clrscr(); // Clear screen
|
||||||
static void ram2gs_set8mb() { ram2gs_cmd(0x11); }
|
|
||||||
static void ram2gs_setnvm(char en8meg) {
|
gwcputsxy(5, 1, "-- RAM2GS Capacity Settings --");
|
||||||
char i;
|
gwcputsxy(4, 3, "Current RAM2GS capacity: ...");
|
||||||
// Clock in 0 to enable this setting entry
|
|
||||||
ram2gs_cmd(0x20);
|
|
||||||
ram2gs_cmd(0x22);
|
|
||||||
|
|
||||||
if (en8meg) {
|
gwcputsxy(1, 6, "Select desired memory capacity:");
|
||||||
// Clock in 1 to enable 8mb
|
|
||||||
ram2gs_cmd(0x21);
|
|
||||||
ram2gs_cmd(0x23);
|
|
||||||
} else {
|
|
||||||
// Clock in 0 to disable 8mb
|
|
||||||
ram2gs_cmd(0x20);
|
|
||||||
ram2gs_cmd(0x22);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clock in 14 dummy "1"s
|
gwcputsxy(4, 8, "1. 4 megabytes");
|
||||||
for (i = 0; i < 14; i++) {
|
gwcputsxy(4, 10, "2. 8 megabytes");
|
||||||
ram2gs_cmd(0x21);
|
|
||||||
ram2gs_cmd(0x23);
|
|
||||||
}
|
|
||||||
|
|
||||||
ram2gs_program();
|
gwcputsxy(1, 18, "Capacity will be saved until power-off.");
|
||||||
|
|
||||||
|
gwcputsxy(1, 20, "To remember capacity and LED setting in");
|
||||||
|
gwcputsxy(1, 21, "nonvolatile memory, press Apple+number.");
|
||||||
|
|
||||||
|
gwcputsxy(1, 23, "Press [Q] to quit without saving.");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void menu(void)
|
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()
|
||||||
{
|
{
|
||||||
uint8_t bankcount = ram2gs_getsize();
|
clrscr(); // Clear screen
|
||||||
gotoxy(5, 1);
|
gwcputsxy(8, 1, "Loading RAM2GS settings...");
|
||||||
cputs("-- RAM2GS Capacity Settings --");
|
|
||||||
gotoxy(4, 3);
|
|
||||||
printf("Current RAM2GS capacity: %d kB", bankcount * 64);
|
|
||||||
|
|
||||||
gotoxy(1, 6);
|
|
||||||
cputs("Select desired memory capacity:");
|
|
||||||
|
|
||||||
gotoxy(4, 8);
|
|
||||||
cputs("1. 4 megabytes");
|
|
||||||
gotoxy(4, 10);
|
|
||||||
cputs("2. 8 megabytes");
|
|
||||||
|
|
||||||
gotoxy(1, 18);
|
|
||||||
cputs("Capacity will be saved until power-off.");
|
|
||||||
|
|
||||||
gotoxy(1, 20);
|
|
||||||
cputs("To remember capacity setting in");
|
|
||||||
gotoxy(1, 21);
|
|
||||||
cputs("nonvolatile memory, press Apple+number.");
|
|
||||||
|
|
||||||
gotoxy(1, 23);
|
|
||||||
cputs("Press [Q] to quit without saving.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ram2gs_main(void)
|
int ram2gs_main(void)
|
||||||
{
|
{
|
||||||
char en8meg;
|
char type;
|
||||||
char nvm;
|
uint8_t bankcount;
|
||||||
int reset_count;
|
char en8meg = true;
|
||||||
|
char hasled = true;
|
||||||
|
char enled = false;
|
||||||
|
|
||||||
// Check for RAM2GS
|
char nvm = false;
|
||||||
#ifndef SKIP_RAM2GS_DETECT
|
int reset_count = 0;
|
||||||
if(!ram2gs_detect()) {
|
|
||||||
|
loading_screen();
|
||||||
|
|
||||||
|
if (ram2gs_detect(0x00)) { // Altera MAX II / V
|
||||||
|
type = 0x00;
|
||||||
|
hasled = !ram2gs_detect(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
|
// If no RAM2GS, show an error message and quit
|
||||||
gotoxy(0, 8);
|
gwcputsxy(0, 8, " No RAM2GS II detected.");
|
||||||
cputs(" No RAM2GS II detected.");
|
gwcputsxy(0, 10, " Press any key to quit.");
|
||||||
gotoxy(0, 10);
|
|
||||||
cputs(" Press any key to quit.");
|
|
||||||
cgetc(); // Wait for key
|
cgetc(); // Wait for key
|
||||||
clrscr(); // Clear screen before quitting
|
clrscr(); // Clear screen before quitting
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
#else
|
||||||
|
hasled = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set chip type
|
||||||
|
ram2gs_hal_set_type(type);
|
||||||
|
|
||||||
|
// Print menu
|
||||||
|
menu();
|
||||||
|
|
||||||
|
// Detect and print current capacity
|
||||||
|
bankcount = ram2gs_getsize();
|
||||||
|
en8meg = bankcount >= 128;
|
||||||
|
menu_size(bankcount);
|
||||||
|
|
||||||
|
// Detect and print LED menu
|
||||||
|
#ifndef SKIP_RAM2GS_DETECT
|
||||||
|
if (hasled) {
|
||||||
|
enled = !ram2gs_detect(type | 0x02);
|
||||||
|
menu_led(enled);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
menu(); // Print menu
|
|
||||||
|
|
||||||
// Get user choice from menu
|
// Get user choice from menu
|
||||||
en8meg = 0;
|
|
||||||
nvm = 0;
|
|
||||||
reset_count = 0;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// Set capacity or quit according to keypress.
|
// Set capacity or quit according to keypress.
|
||||||
switch (toupper(cgetc() & 0x7F)) {
|
switch (toupper(cgetc() & 0x7F)) {
|
||||||
|
@ -98,31 +108,43 @@ int ram2gs_main(void)
|
||||||
clrscr();
|
clrscr();
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
case '1': en8meg = 0; ram2gs_set4mb(); break;
|
case '1': en8meg = false; ram2gs_set(en8meg, enled); break;
|
||||||
case '2': en8meg = 1; ram2gs_set8mb(); break;
|
case '2': en8meg = true; ram2gs_set(en8meg, enled); break;
|
||||||
case 'R': {
|
case 'L': {
|
||||||
|
enled = !enled;
|
||||||
|
ram2gs_set(en8meg, enled);
|
||||||
|
if (hasled) {
|
||||||
|
menu_led(enled);
|
||||||
|
if (enled) {
|
||||||
|
wait(1);
|
||||||
|
ram2gs_flashled(10);
|
||||||
|
wait(10);
|
||||||
|
ram2gs_flashled(10);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
continue;
|
||||||
|
} case 'R': {
|
||||||
reset_count++;
|
reset_count++;
|
||||||
if (reset_count >= 100) {
|
if (reset_count >= 25) {
|
||||||
// Show message about saving.
|
// Show message about resetting.
|
||||||
clrscr(); // Clear screen
|
clrscr(); // Clear screen
|
||||||
gotoxy(1, 8);
|
gwcputsxy(1, 8, "Resetting RAM2GS settings.");
|
||||||
cputs("Resetting RAM2GS settings.");
|
gwcputsxy(1, 9, "Do not turn off your Apple.");
|
||||||
gotoxy(1, 9);
|
|
||||||
cputs("Do not turn off your Apple.");
|
|
||||||
|
|
||||||
ram2gs_erase(); // Erase RAM2GS settings memory
|
ram2gs_erase(); // Erase RAM2GS settings memory
|
||||||
ram2gs_set8mb(); // Enable 8 megabytes now
|
ram2gs_set(1, 0); // Enable 8 megabytes and disable LED
|
||||||
|
|
||||||
// Wait for >= 500ms on even the fastest systems.
|
// Wait for >= 500ms on even the fastest systems.
|
||||||
spin(32, 8);
|
spin(32, 8);
|
||||||
|
|
||||||
// Show success message and quit
|
// Show success message and quit
|
||||||
clrscr(); // Clear screen
|
clrscr(); // Clear screen
|
||||||
gotoxy(1, 8);
|
gwcputsxy(1, 8, "RAM2GS settings reset successfully.");
|
||||||
cputs("RAM2GS settings reset successfully.");
|
nvm = true;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
} default: continue;
|
continue;
|
||||||
|
} default: reset_count = 0; continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if pressed with apple key. If so, save to nonvolatile memory.
|
// Check if pressed with apple key. If so, save to nonvolatile memory.
|
||||||
|
@ -135,36 +157,29 @@ int ram2gs_main(void)
|
||||||
|
|
||||||
if (nvm) { // Save in NVM if requested.
|
if (nvm) { // Save in NVM if requested.
|
||||||
// Show message about saving.
|
// Show message about saving.
|
||||||
gotoxy(1, 8);
|
gwcputsxy(1, 8, "Saving RAM2GS capacity setting.");
|
||||||
cputs("Saving RAM2GS capacity setting.");
|
gwcputsxy(1, 9, "Do not turn off your Apple.");
|
||||||
gotoxy(1, 9);
|
|
||||||
cputs("Do not turn off your Apple.");
|
|
||||||
// Save capacity in nonvolatile memory.
|
// Save capacity in nonvolatile memory.
|
||||||
ram2gs_setnvm(en8meg);
|
ram2gs_save_start(en8meg, enled);
|
||||||
// Wait for >= 500ms on even the fastest systems.
|
// Wait for >= 500ms on even the fastest systems.
|
||||||
spin(33, 8);
|
spin(33, 8);
|
||||||
|
// Finish saving
|
||||||
|
ram2gs_save_end(en8meg, enled);
|
||||||
// Print success message
|
// Print success message
|
||||||
clrscr(); // Clear screen
|
clrscr(); // Clear screen
|
||||||
gotoxy(1, 8);
|
gwcputsxy(1, 8, "RAM2GS capacity saved successfully.");
|
||||||
cputs("RAM2GS capacity saved successfully.");
|
|
||||||
} else { // Print success message if not saving in NVM.
|
} else { // Print success message if not saving in NVM.
|
||||||
gotoxy(1, 8);
|
gwcputsxy(1, 8, "RAM2GS capacity set successfully.");
|
||||||
cputs("RAM2GS capacity set successfully.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (nvm) { // Show end message for nonvolatile save
|
if (nvm) { // Show end message for nonvolatile save
|
||||||
gotoxy(1, 10);
|
gwcputsxy(1, 10, "You may now turn off your Apple.");
|
||||||
cputs("You may now turn off your Apple.");
|
gwcputsxy(1, 12, "You may also reset your Apple for");
|
||||||
gotoxy(1, 12);
|
gwcputsxy(1, 13, "the setting change to take effect.");
|
||||||
cputs("You may also reset your Apple for");
|
|
||||||
gotoxy(1, 13);
|
|
||||||
cputs("the setting change to take effect.");
|
|
||||||
} else { // Show end message for volatile save
|
} else { // Show end message for volatile save
|
||||||
gotoxy(1, 10);
|
gwcputsxy(1, 10, "Please reset your Apple for");
|
||||||
cputs("Please reset your Apple for");
|
gwcputsxy(1, 11, "the setting change to take effect.");
|
||||||
gotoxy(1, 11);
|
|
||||||
cputs("the setting change to take effect.");
|
|
||||||
}
|
}
|
||||||
// Don't quit. Instead leave prompt asking user to reset.
|
// Don't quit. Instead leave prompt asking user to reset.
|
||||||
while(1) { cgetc(); }
|
while(1) { cgetc(); }
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
#ifndef RAM2GS_ASM_H
|
|
||||||
#define RAM2GS_ASM_H
|
|
||||||
|
|
||||||
uint8_t __fastcall__ ram2gs_getsize(void);
|
|
||||||
uint8_t __fastcall__ ram2gs_detect(void);
|
|
||||||
uint8_t __fastcall__ ram2gs_cmd(char cmd);
|
|
||||||
|
|
||||||
#endif /* RAM2GS_ASM_H */
|
|
461
ram2gs_asm.s
461
ram2gs_asm.s
|
@ -2,9 +2,10 @@
|
||||||
.autoimport on
|
.autoimport on
|
||||||
.importzp sp
|
.importzp sp
|
||||||
|
|
||||||
|
.export _ram2gs_cmd
|
||||||
.export _ram2gs_getsize
|
.export _ram2gs_getsize
|
||||||
.export _ram2gs_detect
|
.export _ram2gs_detect
|
||||||
.export _ram2gs_cmd
|
.export _ram2gs_flashled1
|
||||||
|
|
||||||
.macro A8
|
.macro A8
|
||||||
sep #$20 ; put the 65C816 in 8-bit accumulator mode
|
sep #$20 ; put the 65C816 in 8-bit accumulator mode
|
||||||
|
@ -40,189 +41,83 @@
|
||||||
|
|
||||||
.segment "CODE"
|
.segment "CODE"
|
||||||
|
|
||||||
.proc _ram2gs_getsize: near
|
.proc _thrash: near
|
||||||
.A8
|
.A8
|
||||||
.I8
|
.I8
|
||||||
; Preamble
|
; Preamble
|
||||||
php ; Push status
|
php ; Push status
|
||||||
sei ; Disable interrupts
|
AI16
|
||||||
clc ; Clear carry
|
|
||||||
xce ; Clear emulation bit
|
|
||||||
php ; Push status again, reflecting emulation bit
|
|
||||||
phb ; Push bank
|
phb ; Push bank
|
||||||
|
pha ; Push accumulator
|
||||||
|
pha ; Push X
|
||||||
|
phy ; Push Y
|
||||||
|
|
||||||
|
; Read 0x100000-0x11FFFF
|
||||||
AI8
|
AI8
|
||||||
|
lda #$20 ; A = 0x10 (bank)
|
||||||
; Go to bank 3F
|
_thrash_loop:
|
||||||
ldy #$3F
|
pha ; Switch to bank stored in A
|
||||||
phy
|
|
||||||
plb
|
plb
|
||||||
; Save 3F/3456
|
AI16
|
||||||
ldx $3456
|
lda #$0000 ; Get index in A
|
||||||
|
clc ; Clear carry in preparation to add in loop
|
||||||
|
|
||||||
; Go to bank 7F
|
; Read loop
|
||||||
ldy #$7F
|
_thrash_loop0:
|
||||||
phy
|
tax ; Get index from A into X to do LDYs
|
||||||
plb
|
ldy $0100,X ; Read 64 bytes
|
||||||
; Invert 7F/3456
|
ldy $0102,X ; ...
|
||||||
lda $3456
|
ldy $0104,X
|
||||||
eor #$FF
|
ldy $0106,X
|
||||||
sta $3456
|
ldy $0108,X
|
||||||
|
ldy $010A,X
|
||||||
|
ldy $010C,X
|
||||||
|
ldy $010E,X
|
||||||
|
ldy $0110,X
|
||||||
|
ldy $0112,X
|
||||||
|
ldy $0114,X
|
||||||
|
ldy $0116,X
|
||||||
|
ldy $0118,X
|
||||||
|
ldy $011A,X
|
||||||
|
ldy $011C,X
|
||||||
|
ldy $011E,X
|
||||||
|
ldy $0120,X
|
||||||
|
ldy $0122,X
|
||||||
|
ldy $0124,X
|
||||||
|
ldy $0126,X
|
||||||
|
ldy $0128,X
|
||||||
|
ldy $012A,X
|
||||||
|
ldy $012C,X
|
||||||
|
ldy $012E,X
|
||||||
|
ldy $0130,X
|
||||||
|
ldy $0132,X
|
||||||
|
ldy $0134,X
|
||||||
|
ldy $0136,X
|
||||||
|
ldy $0138,X
|
||||||
|
ldy $013A,X
|
||||||
|
ldy $013C,X
|
||||||
|
ldy $013E,X
|
||||||
|
adc #$0040 ; Add 64 to index in A
|
||||||
|
cmp #0
|
||||||
|
bne _thrash_loop0 ; Repeat if we haven't passed 0xFFFF
|
||||||
|
|
||||||
; Go to bank 3F
|
; Bank increment
|
||||||
ldy #$3F
|
AI8
|
||||||
phy
|
phb ; Transfer bank to A
|
||||||
plb
|
pla
|
||||||
; Has 3F/3456 changed?
|
inc ; Increment bank
|
||||||
cpx $3456
|
cmp #$21 ; Stop after bank 0x20
|
||||||
php
|
bne _thrash_loop
|
||||||
|
|
||||||
; Go to bank 7F
|
|
||||||
ldy #$7F
|
|
||||||
phy
|
|
||||||
plb
|
|
||||||
; Restore 7F/3456
|
|
||||||
eor #$FF
|
|
||||||
sta $3456
|
|
||||||
|
|
||||||
; Check result
|
|
||||||
ldx #$80
|
|
||||||
plp
|
|
||||||
beq _ram2gs_getsize_return
|
|
||||||
ldx #$40
|
|
||||||
|
|
||||||
; Postamble
|
; Postamble
|
||||||
_ram2gs_getsize_return:
|
AI16
|
||||||
|
ply ; Restore Y
|
||||||
|
plx ; Restore X
|
||||||
|
pla ; Restore accumulator
|
||||||
plb ; Restore bank
|
plb ; Restore bank
|
||||||
plp ; Restore status
|
|
||||||
xce ; Restore emulation bit
|
|
||||||
txa ; Transfer bank count to A
|
|
||||||
plp ; Pull status again to pull I flag
|
|
||||||
rts
|
|
||||||
.endproc
|
|
||||||
|
|
||||||
|
|
||||||
.proc _unswap: near
|
|
||||||
.A8
|
|
||||||
.I8
|
|
||||||
; Save current bank and accumulator
|
|
||||||
phb
|
|
||||||
pha
|
|
||||||
; Switch to bank 0xFB
|
|
||||||
lda #$FB
|
|
||||||
pha
|
|
||||||
plb
|
|
||||||
; Submit C1AD
|
|
||||||
lda #$C1
|
|
||||||
sta $FFFE
|
|
||||||
lda #$AD
|
|
||||||
sta $FFFF
|
|
||||||
; Pull and submit command
|
|
||||||
lda #$00
|
|
||||||
sta $FFFD
|
|
||||||
; Restore accumulator and bank and return
|
|
||||||
pla
|
|
||||||
plb
|
|
||||||
rts
|
|
||||||
.endproc
|
|
||||||
|
|
||||||
.proc _swap: near
|
|
||||||
.A8
|
|
||||||
.I8
|
|
||||||
; Save current bank and accumulator
|
|
||||||
phb
|
|
||||||
pha
|
|
||||||
; Switch to bank 0xFB
|
|
||||||
lda #$FB
|
|
||||||
pha
|
|
||||||
plb
|
|
||||||
; Submit C1AD
|
|
||||||
lda #$C1
|
|
||||||
sta $FFFE
|
|
||||||
lda #$AD
|
|
||||||
sta $FFFF
|
|
||||||
; Pull and submit command
|
|
||||||
lda #$01
|
|
||||||
sta $FFFD
|
|
||||||
; Restore accumulator and bank and return
|
|
||||||
pla
|
|
||||||
plb
|
|
||||||
rts
|
|
||||||
.endproc
|
|
||||||
|
|
||||||
.proc _ram2gs_detect: near
|
|
||||||
.A8
|
|
||||||
.I8
|
|
||||||
; Preamble
|
|
||||||
php ; Push status
|
|
||||||
sei ; Disable interrupts
|
|
||||||
clc ; Clear carry
|
|
||||||
xce ; Clear emulation bit
|
|
||||||
php ; Push status again, reflecting emulation bit
|
|
||||||
phb ; Push bank
|
|
||||||
AI8
|
AI8
|
||||||
|
|
||||||
; Switch to bank 0x3F
|
|
||||||
lda #$3F
|
|
||||||
pha
|
|
||||||
plb
|
|
||||||
|
|
||||||
; Unswap
|
|
||||||
jsr _unswap
|
|
||||||
; Save unswapped 3F/8000
|
|
||||||
lda $8000
|
|
||||||
pha
|
|
||||||
; Swap
|
|
||||||
jsr _swap
|
|
||||||
; Save swapped 3F/8000
|
|
||||||
lda $8000
|
|
||||||
pha
|
|
||||||
|
|
||||||
; Store 0xFF in swapped
|
|
||||||
lda #$FF
|
|
||||||
sta $8000
|
|
||||||
; Verify 0xFF stored
|
|
||||||
lda $8000
|
|
||||||
cmp #$FF
|
|
||||||
bne _ram2gs_detect_fail
|
|
||||||
|
|
||||||
; Unswap
|
|
||||||
jsr _unswap
|
|
||||||
; Store 0x00 in unswapped
|
|
||||||
lda #$00
|
|
||||||
sta $8000
|
|
||||||
; Verify 0x00 stored
|
|
||||||
lda $8000
|
|
||||||
cmp #$00
|
|
||||||
bne _ram2gs_detect_fail
|
|
||||||
|
|
||||||
; Swap
|
|
||||||
jsr _swap
|
|
||||||
; Verify 0xFF stored
|
|
||||||
lda $8000
|
|
||||||
cmp #$FF
|
|
||||||
bne _ram2gs_detect_fail
|
|
||||||
|
|
||||||
; Get success return value and jump to postamble
|
|
||||||
ldx #$01 ; Get success falue
|
|
||||||
bne _ram2gs_detect_return ; Jump to postamble
|
|
||||||
|
|
||||||
; Fail
|
|
||||||
_ram2gs_detect_fail:
|
|
||||||
ldx #$00 ; Get fail value
|
|
||||||
|
|
||||||
; Postamble
|
|
||||||
_ram2gs_detect_return:
|
|
||||||
jsr _swap ; Swap
|
|
||||||
pla ; Get value to restore to swapped bank 3F
|
|
||||||
sta $8000 ; Restore
|
|
||||||
jsr _unswap ; Unswap
|
|
||||||
pla ; Get value to restore to unswapped bank 3F
|
|
||||||
sta $8000 ; Restore
|
|
||||||
txa ; Put return value in accumulator
|
|
||||||
plb ; Restore bank
|
|
||||||
plp ; Restore status
|
plp ; Restore status
|
||||||
xce ; Restore emulation bit
|
|
||||||
plp ; Pull status again to pull I flag
|
|
||||||
rts
|
rts
|
||||||
.endproc
|
.endproc
|
||||||
|
|
||||||
|
@ -257,3 +152,231 @@
|
||||||
plp ; Pull status again to pull I flag
|
plp ; Pull status again to pull I flag
|
||||||
rts
|
rts
|
||||||
.endproc
|
.endproc
|
||||||
|
|
||||||
|
.proc _unswap: near
|
||||||
|
.A8
|
||||||
|
.I8
|
||||||
|
tya
|
||||||
|
ora #$00
|
||||||
|
jmp _ram2gs_cmd
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
.proc _swap: near
|
||||||
|
.A8
|
||||||
|
.I8
|
||||||
|
tya
|
||||||
|
ora #$01
|
||||||
|
jmp _ram2gs_cmd
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
.proc _ram2gs_getsize: near
|
||||||
|
.A8
|
||||||
|
.I8
|
||||||
|
; Preamble
|
||||||
|
php ; Push status
|
||||||
|
sei ; Disable interrupts
|
||||||
|
clc ; Clear carry
|
||||||
|
xce ; Clear emulation bit
|
||||||
|
php ; Push status again, reflecting emulation bit
|
||||||
|
phb ; Push bank
|
||||||
|
AI8
|
||||||
|
|
||||||
|
; Go to bank 3F
|
||||||
|
ldy #$3F
|
||||||
|
phy
|
||||||
|
plb
|
||||||
|
; Save 3F/3456
|
||||||
|
lda $3456
|
||||||
|
pha
|
||||||
|
|
||||||
|
; Go to bank 7F
|
||||||
|
ldy #$7F
|
||||||
|
phy
|
||||||
|
plb
|
||||||
|
; Save and then invert 7F/3456
|
||||||
|
lda $3456
|
||||||
|
pha
|
||||||
|
eor #$FF
|
||||||
|
sta $3456
|
||||||
|
|
||||||
|
; Go to bank 3F
|
||||||
|
ldy #$3F
|
||||||
|
phy
|
||||||
|
plb
|
||||||
|
; Has 3F/3456 changed?
|
||||||
|
jsr _thrash
|
||||||
|
plx ; X = saved 7F/3456
|
||||||
|
pla ; A = saved 3F/3456
|
||||||
|
cmp $3456
|
||||||
|
php ; Push to save processor status
|
||||||
|
|
||||||
|
; Go to bank 7F
|
||||||
|
ldy #$7F
|
||||||
|
phy
|
||||||
|
plb
|
||||||
|
; Restore 3F/3456
|
||||||
|
sta $3456
|
||||||
|
|
||||||
|
; Go to bank 7F
|
||||||
|
ldy #$7F
|
||||||
|
phy
|
||||||
|
plb
|
||||||
|
; Restore 7F/3456
|
||||||
|
stx $3456
|
||||||
|
|
||||||
|
; Check result
|
||||||
|
lda #$80
|
||||||
|
plp
|
||||||
|
beq _ram2gs_getsize_return
|
||||||
|
lda #$40
|
||||||
|
|
||||||
|
; Postamble
|
||||||
|
_ram2gs_getsize_return:
|
||||||
|
plb ; Restore bank
|
||||||
|
plp ; Restore status
|
||||||
|
xce ; Restore emulation bit
|
||||||
|
plp ; Pull status again to pull I flag
|
||||||
|
rts
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
.proc _ram2gs_detect_internal: near
|
||||||
|
.A8
|
||||||
|
.I8
|
||||||
|
; Switch to bank 0x3F
|
||||||
|
lda #$3F
|
||||||
|
pha
|
||||||
|
plb
|
||||||
|
|
||||||
|
; Unswap
|
||||||
|
jsr _unswap
|
||||||
|
; Save unswapped 3F/8000
|
||||||
|
jsr _thrash
|
||||||
|
lda $8000
|
||||||
|
pha
|
||||||
|
; Swap
|
||||||
|
jsr _swap
|
||||||
|
; Save swapped 3F/8000
|
||||||
|
jsr _thrash
|
||||||
|
lda $8000
|
||||||
|
pha
|
||||||
|
|
||||||
|
; Store 0xFF in swapped
|
||||||
|
lda #$FF
|
||||||
|
sta $8000
|
||||||
|
; Verify 0xFF stored
|
||||||
|
jsr _thrash
|
||||||
|
lda $8000
|
||||||
|
cmp #$FF
|
||||||
|
bne _ram2gs_detect_fail
|
||||||
|
|
||||||
|
; Unswap
|
||||||
|
jsr _unswap
|
||||||
|
; Store 0x00 in unswapped
|
||||||
|
lda #$00
|
||||||
|
sta $8000
|
||||||
|
; Verify 0x00 stored
|
||||||
|
jsr _thrash
|
||||||
|
lda $8000
|
||||||
|
cmp #$00
|
||||||
|
bne _ram2gs_detect_fail
|
||||||
|
|
||||||
|
; Swap
|
||||||
|
jsr _swap
|
||||||
|
; Verify 0xFF stored
|
||||||
|
jsr _thrash
|
||||||
|
lda $8000
|
||||||
|
cmp #$FF
|
||||||
|
bne _ram2gs_detect_fail
|
||||||
|
|
||||||
|
; Get success return value and jump to postamble
|
||||||
|
ldx #$01 ; Get success falue
|
||||||
|
bne _ram2gs_detect_done ; Jump to postamble
|
||||||
|
|
||||||
|
; Fail
|
||||||
|
_ram2gs_detect_fail:
|
||||||
|
ldx #$00 ; Get fail value
|
||||||
|
|
||||||
|
; Done, now put back clobbered bytes
|
||||||
|
_ram2gs_detect_done:
|
||||||
|
jsr _swap ; Swap
|
||||||
|
pla ; Get value to restore to swapped bank 3F
|
||||||
|
sta $8000 ; Restore
|
||||||
|
jsr _unswap ; Unswap
|
||||||
|
pla ; Get value to restore to unswapped bank 3F
|
||||||
|
sta $8000 ; Restore
|
||||||
|
|
||||||
|
; Return
|
||||||
|
rts
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
.proc _ram2gs_detect: 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
|
||||||
|
|
||||||
|
; Transfer typecode (shifted) to Y register
|
||||||
|
and #$0E
|
||||||
|
tay
|
||||||
|
|
||||||
|
jsr _ram2gs_detect_internal
|
||||||
|
|
||||||
|
; Postamble
|
||||||
|
txa ; Get return value
|
||||||
|
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
|
||||||
|
|
||||||
|
.proc _ram2gs_flashled1: near
|
||||||
|
.A8
|
||||||
|
.I8
|
||||||
|
; Preamble
|
||||||
|
phx ; Push X
|
||||||
|
phy ; Push Y
|
||||||
|
php ; Push status
|
||||||
|
sei ; Disable interrupts
|
||||||
|
clc ; Clear carry
|
||||||
|
xce ; Clear emulation bit
|
||||||
|
php ; Push status again, reflecting emulation bit
|
||||||
|
phb ; Push bank
|
||||||
|
AI8
|
||||||
|
|
||||||
|
lda #$20
|
||||||
|
pha
|
||||||
|
plb
|
||||||
|
ldx #0
|
||||||
|
_ram2gs_flashled1_loop:
|
||||||
|
lda $3456
|
||||||
|
lda $3456
|
||||||
|
lda $3456
|
||||||
|
lda $3456
|
||||||
|
lda $3456
|
||||||
|
lda $3456
|
||||||
|
lda $3456
|
||||||
|
lda $3456
|
||||||
|
inx
|
||||||
|
cpx #0
|
||||||
|
bne _ram2gs_flashled1_loop
|
||||||
|
|
||||||
|
; Postamble
|
||||||
|
plb ; Restore bank
|
||||||
|
plp ; Restore status
|
||||||
|
xce ; Restore emulation bit
|
||||||
|
plp ; Pull status again to pull I flag
|
||||||
|
ply ; Pull X
|
||||||
|
plx ; Pull Y
|
||||||
|
rts
|
||||||
|
.endproc
|
||||||
|
|
54
ram2gs_hal.c
Normal file
54
ram2gs_hal.c
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "util.h"
|
||||||
|
#include "ram2gs_hal.h"
|
||||||
|
|
||||||
|
uint8_t __fastcall__ ram2gs_cmd(char cmd);
|
||||||
|
|
||||||
|
void ram2gs_set(char en8meg, char enled) {
|
||||||
|
char cmd = 0x10;
|
||||||
|
if (en8meg) { cmd |= 0x01; }
|
||||||
|
if (enled) { cmd |= 0x02; }
|
||||||
|
ram2gs_cmd(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ram2gs_flashled(char frames) {
|
||||||
|
char i;
|
||||||
|
for (i = 0; i < frames; i++) {
|
||||||
|
unsigned int l;
|
||||||
|
for (l = 0; *VBL < 0 && l < 2500; l++) { ram2gs_flashled1(); }
|
||||||
|
for (l = 0; *VBL >= 0 && l < 2500; l++) { ram2gs_flashled1(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "ram2gs_hal_max.c"
|
||||||
|
#include "ram2gs_hal_spi.c"
|
||||||
|
#include "ram2gs_hal_lcmxo2.c"
|
||||||
|
|
||||||
|
static char _type;
|
||||||
|
void ram2gs_hal_set_type(char type) { _type = type; }
|
||||||
|
|
||||||
|
void ram2gs_erase() {
|
||||||
|
switch (_type) {
|
||||||
|
case 0x00: ram2gs_max_erase(); break; // Altera MAX II / V
|
||||||
|
case 0x04: ram2gs_spi_erase(); break; // Lattice MachXO / iCE40 / AGM AG256
|
||||||
|
case 0x08: ram2gs_lcmxo2_erase(); break; // Lattice MachXO2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void ram2gs_save_start(char en8meg, char enled) {
|
||||||
|
switch (_type) {
|
||||||
|
case 0x00: ram2gs_max_save(en8meg, enled); break; // Altera MAX II / V
|
||||||
|
case 0x04: ram2gs_spi_erase(); break; // Lattice MachXO / iCE40 / AGM AG256
|
||||||
|
case 0x08: ram2gs_lcmxo2_erase(); break; // Lattice MachXO2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void ram2gs_save_end(char en8meg, char enled) {
|
||||||
|
switch (_type) {
|
||||||
|
case 0x00: break; // Altera MAX II / V
|
||||||
|
case 0x04: ram2gs_spi_save(en8meg, enled); break; // Lattice MachXO / iCE40 / AGM AG256
|
||||||
|
case 0x08: ram2gs_lcmxo2_save(en8meg, enled); break; // Lattice MachXO2
|
||||||
|
}
|
||||||
|
}
|
19
ram2gs_hal.h
Normal file
19
ram2gs_hal.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef RAM2GS_HAL_H
|
||||||
|
#define RAM2GS_HAL_H
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
uint8_t __fastcall__ ram2gs_detect(char typecode);
|
||||||
|
uint8_t __fastcall__ ram2gs_getsize(void);
|
||||||
|
uint8_t __fastcall__ ram2gs_flashled1(void);
|
||||||
|
|
||||||
|
void ram2gs_set(char en8meg, char enled);
|
||||||
|
|
||||||
|
void ram2gs_flashled(char frames);
|
||||||
|
|
||||||
|
void ram2gs_hal_set_type(char typecode);
|
||||||
|
void ram2gs_erase();
|
||||||
|
void ram2gs_save_start(char en8meg, char enled);
|
||||||
|
void ram2gs_save_end(char en8meg, char enled);
|
||||||
|
|
||||||
|
#endif
|
88
ram2gs_hal_lcmxo2.c
Normal file
88
ram2gs_hal_lcmxo2.c
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
static void ram2gs_lcmxo2_rw(char we, char addr, char data) {
|
||||||
|
char i;
|
||||||
|
for (i = 0; i < 8; i++) { ram2gs_cmd(0x38 + ((addr >> (7-i)) & 1)); }
|
||||||
|
for (i = 0; i < 8; i++) { ram2gs_cmd(0x38 + ((data >> (7-i)) & 1)); }
|
||||||
|
if (we) { ram2gs_cmd(0x39); }
|
||||||
|
else { ram2gs_cmd(0x38); }
|
||||||
|
ram2gs_cmd(0x3A);
|
||||||
|
}
|
||||||
|
static void ram2gs_lcmxo2_open() { ram2gs_lcmxo2_rw(1, 0x70, 0x80); }
|
||||||
|
static void ram2gs_lcmxo2_close() { ram2gs_lcmxo2_rw(1, 0x70, 0x00); }
|
||||||
|
static void ram2gs_lcmxo2_cmd_op3(char cmd, char op1, char op2, char op3) {
|
||||||
|
ram2gs_lcmxo2_open();
|
||||||
|
ram2gs_lcmxo2_rw(1, 0x71, cmd); // Command
|
||||||
|
ram2gs_lcmxo2_rw(1, 0x71, op1); // Operand 1/3
|
||||||
|
ram2gs_lcmxo2_rw(1, 0x71, op2); // Operand 2/3
|
||||||
|
ram2gs_lcmxo2_rw(1, 0x71, op3); // Operand 3/3
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ram2gs_lcmxo2_encfg() {
|
||||||
|
ram2gs_lcmxo2_cmd_op3(0x74, 0x08, 0x00, 0x00);
|
||||||
|
ram2gs_lcmxo2_close();
|
||||||
|
}
|
||||||
|
static void ram2gs_lcmxo2_discfg() {
|
||||||
|
ram2gs_lcmxo2_cmd_op3(0x26, 0x08, 0x00, 0x00);
|
||||||
|
ram2gs_lcmxo2_close();
|
||||||
|
}
|
||||||
|
static void ram2gs_lcmxo2_bypass() {
|
||||||
|
ram2gs_lcmxo2_open();
|
||||||
|
ram2gs_lcmxo2_rw(1, 0x71, 0xFF); // Command
|
||||||
|
ram2gs_lcmxo2_close();
|
||||||
|
}
|
||||||
|
static void ram2gs_lcmxo2_pollstat() {
|
||||||
|
ram2gs_lcmxo2_cmd_op3(0x3C, 0x00, 0x00, 0x00);
|
||||||
|
ram2gs_lcmxo2_rw(0, 0x73, 0x00); // Data 1/4
|
||||||
|
ram2gs_lcmxo2_rw(0, 0x73, 0x00); // Data 2/4
|
||||||
|
ram2gs_lcmxo2_rw(0, 0x73, 0x00); // Data 3/4
|
||||||
|
ram2gs_lcmxo2_rw(0, 0x73, 0x00); // Data 4/4
|
||||||
|
ram2gs_lcmxo2_close();
|
||||||
|
}
|
||||||
|
static void ram2gs_lcmxo2_erase() {
|
||||||
|
// Enable configuration interface
|
||||||
|
ram2gs_lcmxo2_encfg();
|
||||||
|
// Poll status register
|
||||||
|
ram2gs_lcmxo2_pollstat();
|
||||||
|
|
||||||
|
// Erase UFM
|
||||||
|
ram2gs_lcmxo2_cmd_op3(0xCB, 0x00, 0x00, 0x00);
|
||||||
|
ram2gs_lcmxo2_close();
|
||||||
|
}
|
||||||
|
static void ram2gs_lcmxo2_save(char en8meg, char enled) {
|
||||||
|
char i;
|
||||||
|
// Poll status register
|
||||||
|
ram2gs_lcmxo2_pollstat();
|
||||||
|
// Disable configuration interface
|
||||||
|
ram2gs_lcmxo2_discfg();
|
||||||
|
// Bypass
|
||||||
|
ram2gs_lcmxo2_bypass();
|
||||||
|
// Enable configuration interface
|
||||||
|
ram2gs_lcmxo2_encfg();
|
||||||
|
// Poll status register
|
||||||
|
ram2gs_lcmxo2_pollstat();
|
||||||
|
|
||||||
|
// Set UFM address
|
||||||
|
ram2gs_lcmxo2_cmd_op3(0xB4, 0x00, 0x00, 0x00);
|
||||||
|
ram2gs_lcmxo2_rw(1, 0x71, 0x40); // Data 1/4
|
||||||
|
ram2gs_lcmxo2_rw(1, 0x71, 0x00); // Data 2/4
|
||||||
|
ram2gs_lcmxo2_rw(1, 0x71, 0x00); // Data 3/4
|
||||||
|
ram2gs_lcmxo2_rw(1, 0x71, 190); // Data 4/4
|
||||||
|
ram2gs_lcmxo2_close();
|
||||||
|
|
||||||
|
// Write UFM page
|
||||||
|
ram2gs_lcmxo2_cmd_op3(0xC9, 0x00, 0x00, 0x01);
|
||||||
|
// Data 0
|
||||||
|
if (!en8meg && !enled) { ram2gs_lcmxo2_rw(1, 0x71, 0x01); }
|
||||||
|
else if (!en8meg && enled) { ram2gs_lcmxo2_rw(1, 0x71, 0x03); }
|
||||||
|
else if ( en8meg && !enled) { ram2gs_lcmxo2_rw(1, 0x71, 0x00); }
|
||||||
|
else if ( en8meg && enled) { ram2gs_lcmxo2_rw(1, 0x71, 0x02); }
|
||||||
|
// Data 1-15
|
||||||
|
for (i = 1; i < 16; i++) { ram2gs_lcmxo2_rw(1, 0x71, 0x00); }
|
||||||
|
ram2gs_lcmxo2_close();
|
||||||
|
|
||||||
|
// Poll status register
|
||||||
|
ram2gs_lcmxo2_pollstat();
|
||||||
|
// Disable configuration interface
|
||||||
|
ram2gs_lcmxo2_discfg();
|
||||||
|
// Bypass
|
||||||
|
ram2gs_lcmxo2_bypass();
|
||||||
|
}
|
16
ram2gs_hal_max.c
Normal file
16
ram2gs_hal_max.c
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
static void ram2gs_max_erase() { ram2gs_cmd(0x28); }
|
||||||
|
static void ram2gs_max_shift(char bit) {
|
||||||
|
char data = 0x20;
|
||||||
|
if (bit) data |= 0x01;
|
||||||
|
ram2gs_cmd(data);
|
||||||
|
data |= 0x02;
|
||||||
|
ram2gs_cmd(data);
|
||||||
|
}
|
||||||
|
static void ram2gs_max_save(char en8meg, char enled) {
|
||||||
|
char i;
|
||||||
|
ram2gs_max_shift(0); // Clock in 0 to enable this setting entry
|
||||||
|
ram2gs_max_shift(en8meg); // Clock in 8 mb enable bit
|
||||||
|
ram2gs_max_shift(!enled); // Clock in LED enable bit
|
||||||
|
for (i = 0; i < 13; i++) { ram2gs_max_shift(1); } // Clock in 13 dummy 1s
|
||||||
|
ram2gs_cmd(0x24); // Program
|
||||||
|
}
|
38
ram2gs_hal_spi.c
Normal file
38
ram2gs_hal_spi.c
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
static void ram2gs_spi_select() { ram2gs_cmd(0x34); }
|
||||||
|
static void ram2gs_spi_deselect() { ram2gs_cmd(0x30); }
|
||||||
|
static void ram2gs_spi_tx8(char data) {
|
||||||
|
char i;
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
ram2gs_cmd(0x34 + ((data >> (7-i)) & 1));
|
||||||
|
ram2gs_cmd(0x36 + ((data >> (7-i)) & 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void ram2gs_spi_wren() {
|
||||||
|
ram2gs_spi_deselect();
|
||||||
|
ram2gs_spi_select();
|
||||||
|
ram2gs_spi_tx8(0x06); // 0x06 is write enable
|
||||||
|
ram2gs_spi_deselect();
|
||||||
|
}
|
||||||
|
static void ram2gs_spi_erase() {
|
||||||
|
ram2gs_spi_wren();
|
||||||
|
ram2gs_spi_select();
|
||||||
|
ram2gs_spi_tx8(0x20); // 0x20 is sector erase (4 kB)
|
||||||
|
ram2gs_spi_tx8(0x00); // address[23:16]
|
||||||
|
ram2gs_spi_tx8(0x10); // address[15:8]
|
||||||
|
ram2gs_spi_tx8(0x00); // address[7:0]
|
||||||
|
ram2gs_spi_deselect();
|
||||||
|
}
|
||||||
|
static void ram2gs_spi_save(char en8meg, char enled) {
|
||||||
|
ram2gs_spi_wren();
|
||||||
|
ram2gs_spi_select();
|
||||||
|
ram2gs_spi_tx8(0x02); // 0x02 is page (byte) program
|
||||||
|
ram2gs_spi_tx8(0x00); // address[23:16]
|
||||||
|
ram2gs_spi_tx8(0x10); // address[15:8]
|
||||||
|
ram2gs_spi_tx8(0x00); // address[7:0]
|
||||||
|
// data[7:0]
|
||||||
|
if (!en8meg && !enled) { ram2gs_spi_tx8(0x7F); }
|
||||||
|
else if (!en8meg && enled) { ram2gs_spi_tx8(0x3F); }
|
||||||
|
else if ( en8meg && !enled) { ram2gs_spi_tx8(0xFF); }
|
||||||
|
else if ( en8meg && enled) { ram2gs_spi_tx8(0xBF); }
|
||||||
|
ram2gs_spi_deselect();
|
||||||
|
}
|
24
util.c
24
util.c
|
@ -8,14 +8,22 @@
|
||||||
#define PB1 ((char*)0xC062)
|
#define PB1 ((char*)0xC062)
|
||||||
char read_applekey(void) { return ((*PB0) | (*PB1)) & 0x80; }
|
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_HALFCYCLES 3
|
||||||
#define SPIN_FRAMESPERCHAR 4
|
#define SPIN_FRAMESPERCHAR 4
|
||||||
void spin(uint8_t x, uint8_t y) {
|
void spin(uint8_t x, uint8_t y) {
|
||||||
char i;
|
char i;
|
||||||
|
|
||||||
// Sync to frame before starting
|
// Sync to frame before starting
|
||||||
while (*VBL >= 0);
|
wait(1);
|
||||||
|
|
||||||
// Wait and animate spinner.
|
// Wait and animate spinner.
|
||||||
// Spin_half
|
// Spin_half
|
||||||
|
@ -23,8 +31,6 @@ void spin(uint8_t x, uint8_t y) {
|
||||||
char j;
|
char j;
|
||||||
for (j = 0; j < 4; j++) {
|
for (j = 0; j < 4; j++) {
|
||||||
char spinchar;
|
char spinchar;
|
||||||
char k;
|
|
||||||
|
|
||||||
// Assign spinner char based on j
|
// Assign spinner char based on j
|
||||||
switch (j) {
|
switch (j) {
|
||||||
case 0: spinchar = '\\'; break;
|
case 0: spinchar = '\\'; break;
|
||||||
|
@ -39,14 +45,10 @@ void spin(uint8_t x, uint8_t y) {
|
||||||
putchar(spinchar);
|
putchar(spinchar);
|
||||||
|
|
||||||
// Wait specificed number of frames
|
// Wait specificed number of frames
|
||||||
for (k = 0; k < SPIN_FRAMESPERCHAR; k++) {
|
wait(SPIN_FRAMESPERCHAR);
|
||||||
while (*VBL < 0);
|
|
||||||
while (*VBL >= 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait a frame when finished
|
// Wait a frame when finished
|
||||||
while (*VBL < 0);
|
wait(1);
|
||||||
while (*VBL >= 0);
|
}
|
||||||
}
|
|
||||||
|
|
3
util.h
3
util.h
|
@ -6,7 +6,10 @@
|
||||||
#define true 1
|
#define true 1
|
||||||
#define false 0
|
#define false 0
|
||||||
|
|
||||||
|
#define VBL ((signed char*)0xC019)
|
||||||
|
|
||||||
char read_applekey(void);
|
char read_applekey(void);
|
||||||
|
void wait(char frames);
|
||||||
void spin(uint8_t x, uint8_t y);
|
void spin(uint8_t x, uint8_t y);
|
||||||
|
|
||||||
#endif /* UTIL_H */
|
#endif /* UTIL_H */
|
Loading…
Reference in New Issue
Block a user