How to code for the EasyFlash cart
(a Quick-Start, see EasySDK Guide for detailed information)
EasyFlash consists of 2 Flash memory chips of 512 KB each.
It has a total of 1MB.
One Flash chip for low bank (at $8000),
one for high bank (at $a000 or $e000 in UMAX mode).
8 kb per chip can be banked into c64 memory at a time.
There is a total of 64 Banks.
The active bank is selected via $de00.
$de00 always selects low and high bank simultaneously.
$de02 selects the configuration:
- bit 7: toggle board LED
- bit 6: reserved
- bit 5: reserved
- bit 4: reserved
- bit 3: reserved
- bit 2: GAME MODE /1: controlled via bit0 /0: from jumper
- bit 1: EXROM state /0: high
- bit 0: GAME state (if bit 2 set) /0: high
In practice this means:
lda #%00000100 ;Cartridge ROM off (256 Bytes of RAM still available at $dfxx) lda #%00000101 ;Ultimax Mode (low bank at $8000, high bank at $e000) lda #%00000110 ; 8 Kb cart (low bank at $8000) lda #%00000111 ;16 Kb cart (low bank at $8000, high bank at $a000) sta $de02
Example:
To access 8Kb low and 8Kb high of Bank 0:
lda #$37 ;enable CART ROM sta $01 lda #$00 ;select bank sta $de00 lda #%00000111 ;select 16 Kb configuration, low at $8000, high at $a000 sta $de02 ldx #00 lda $8000,x ;access data from EasyFlash ($8000-$bfff in this case)
$de00 and $de02 are WRITE ONLY, so you can not use INC or DEC to change banks or settings.
Naturally the memory configuration via $01 remains valid,
i.e. #$37 or #$33 to enable CART ROM.
Note, that the additional RAM is always visible in I/O space at $dfxx.
EasyFlash always starts up in Ultimax mode after Reset,
hence you have to provide some startup code if you write your own crt.
The following snippet provides a commented working framework (ACME Assembler format) by skoe.
; EasyFlashSDK sample code ; see README for a description details * = $0000 EASYFLASH_BANK = $DE00 EASYFLASH_CONTROL = $DE02 EASYFLASH_LED = $80 EASYFLASH_16K = $07 EASYFLASH_KILL = $04 ; ============================================================================= ; 00:0:0000 (LOROM, bank 0) bankStart_00_0: ; This code resides on LOROM, it becomes visible at $8000 !pseudopc $8000 { ; === the main application entry point === ; copy the main code to $C000 (or whereever) - we don't run it here ; since the banking would make it invisible ; it may be a good idea to let exomizer do this in real life ldx #0 lp1: lda main,x sta $c000,x dex bne lp1 jmp $c000 main: !pseudopc $C000 { ; Switch to bank 1, get a byte from LOROM and HIROM lda #1 sta EASYFLASH_BANK lda $8000 ldx $a000 ; and put them to the screen, we should see "A" and "B" there sta $0400 stx $0401 ; Switch to bank 2, get a byte from LOROM and HIROM lda #2 sta EASYFLASH_BANK lda $8000 ldx $a000 ; and put them to the screen, we should see "C" and "D" there sta $0400 + 40 stx $0401 + 40 ; effect! lp2: dec $d020 jmp lp2 } ; fill the whole bank with value $ff !align $ffff, $a000, $ff } ; ============================================================================= ; 00:1:0000 (HIROM, bank 0) bankStart_00_1: ; This code runs in Ultimax mode after reset, so this memory becomes ; visible at $E000..$FFFF first and must contain a reset vector !pseudopc $e000 { coldStart: ; === the reset vector points here === sei ldx #$ff txs cld ; enable VIC (e.g. RAM refresh) lda #8 sta $d016 ; write to RAM to make sure it starts up correctly (=> RAM datasheets) startWait: sta $0100, x dex bne startWait ; copy the final start-up code to RAM (bottom of CPU stack) ldx #(startUpEnd - startUpCode) l1: lda startUpCode, x sta $0100, x dex bpl l1 jmp $0100 startUpCode: !pseudopc $0100 { ; === this code is copied to the stack area, does some inits === ; === scans the keyboard and kills the cartridge or === ; === starts the main application === lda #EASYFLASH_16K + EASYFLASH_LED sta EASYFLASH_CONTROL ; Check if one of the magic kill keys is pressed ; This should be done in the same way on any EasyFlash cartridge! ; Prepare the CIA to scan the keyboard lda #$7f sta $dc00 ; pull down row 7 (DPA) ldx #$ff stx $dc02 ; DDRA $ff = output (X is still $ff from copy loop) inx stx $dc03 ; DDRB $00 = input ; Read the keys pressed on this row lda $dc01 ; read coloumns (DPB) ; Restore CIA registers to the state after (hard) reset stx $dc02 ; DDRA input again stx $dc00 ; Now row pulled down ; Check if one of the magic kill keys was pressed and #$e0 ; only leave "Run/Stop", "Q" and "C=" cmp #$e0 bne kill ; branch if one of these keys is pressed ; same init stuff the kernel calls after reset ldx #0 stx $d016 jsr $ff84 ; Initialise I/O ; These may not be needed - depending on what you'll do jsr $ff87 ; Initialise System Constants jsr $ff8a ; Restore Kernal Vectors jsr $ff81 ; Initialize screen editor ; start the application code jmp $8000 kill: lda #EASYFLASH_KILL sta EASYFLASH_CONTROL jmp ($fffc) ; reset } startUpEnd: ; fill it up to $FFFA to put the vectors there !align $ffff, $fffa, $ff !word reti ; NMI !word coldStart ; RESET ; we don't need the IRQ vector and can put RTI here to save space :) reti: rti !byte 0xff } ; ============================================================================= ; 01:0:0000 (LOROM, bank 1) bankStart_01_0: ; fill the whole bank with value 1 = 'A' !fill $2000, 1 ; ============================================================================= ; 01:1:0000 (HIROM, bank 1) bankStart_01_1: ; fill the whole bank with value 2 = 'B' !fill $2000, 2 ; ============================================================================= ; 02:0:0000 (LOROM, bank 2) bankStart_02_0: ; fill the whole bank with value 3 = 'C' !fill $2000, 3 ; ============================================================================= ; 02:1:0000 (HIROM, bank 2) bankStart_02_1: ; fill the whole bank with value 4 = 'D' !fill $2000, 4