; ; Extended memory driver for 65816 based extra RAM. Driver works without ; problems when statically linked. ; ; Marco van den Heuvel, 2015-12-01 ; .include "zeropage.inc" .include "em-kernel.inc" .include "em-error.inc" .macpack generic .macpack module ; ------------------------------------------------------------------------ ; Header. Includes jump table module_header _c64_65816_emd ; Driver signature .byte $65, $6d, $64 ; "emd" .byte EMD_API_VERSION ; EM API version number ; Library reference .addr $0000 ; Jump table .addr INSTALL .addr UNINSTALL .addr PAGECOUNT .addr MAP .addr USE .addr COMMIT .addr COPYFROM .addr COPYTO ; ------------------------------------------------------------------------ ; Data. .bss isnotscpu: .res 1 ; SuperCPU not present curpage: .res 1 ; Current page number curbank: .res 1 ; Current bank number (+1) bankcount: .res 1 ; Number of available banks (pages = banks * 256) window: .res 256 ; Memory "window" .code ; ------------------------------------------------------------------------ ; INSTALL routine. Is called after the driver is loaded into memory. If ; possible, check if the hardware is present and determine the amount of ; memory available. ; Must return an EM_ERR_xx code in a/x. ; INSTALL: sei clc sed lda #$99 adc #$01 ; on 65C02, 65SC02, 65CE02, 65802 and 65816 sets the zero flag correctly cld bne @not_present clc .P816 sep #$01 ; nop #$01 on 65C02/65SC02 and lda ($01,s),y on 65CE02 .P02 bcc @not_present lda $d0bc and #$80 sta isnotscpu lda $07e8 pha ; save value incase it was used somewhere else ldx #$ff @fillloop: ; fill from top (bank 255) to bottom txa pha .P816 plb ; pull dbr .P02 stx $07e8 dex cpx #$ff bne @fillloop inx @compareloop: ; check from bottom to top txa pha .P816 plb .P02 cmp $07e8 bne @found_pages .P816 inc .P02 sta $07e8 cmp $07e8 bne @found_pages inx bne @compareloop @found_pages: dex lda #$00 pha .P816 plb .P02 pla sta $07e8 cli lda isnotscpu bne @noextradex dex @noextradex: stx bankcount lda #EM_ERR_OK .assert EM_ERR_OK = 0, error tax rts @not_present: cli lda #EM_ERR_NO_DEVICE ldx #0 ; return value is char ; rts ; Run into UNINSTALL instead ; ------------------------------------------------------------------------ ; UNINSTALL routine. Is called before the driver is removed from memory. ; Can do cleanup or whatever. Must not return anything. ; UNINSTALL: rts ; ------------------------------------------------------------------------ ; PAGECOUNT: Return the total number of available pages in a/x. ; PAGECOUNT: lda #$00 ; a whole bank is either usable or not ldx bankcount rts ; ------------------------------------------------------------------------ ; MAP: Map the page in a/x into memory and return a pointer to the page in ; a/x. The contents of the currently mapped page (if any) may be discarded ; by the driver. ; MAP: sta curpage ; Remember the new page stx curbank ; Remember the new bank sta ptr2+1 ; src address low lda #$00 sta ptr2 ; src address high inx ldy isnotscpu ; check if not scpu bne @notscpu inx @notscpu: stx tmp2 ; src bank sta tmp1 ; dst bank sta ptr3+1 ; length high lda #$ff sta ptr3 ; length low lda #window stx ptr1+1 ; dst address high jsr transfer rts ; ------------------------------------------------------------------------ ; USE: Tell the driver that the window is now associated with a given page. USE: sta curpage ; Remember the page stx curbank ; Remember the bank lda #window ; Return the window rts ; ------------------------------------------------------------------------ ; COMMIT: Commit changes in the memory window to extended storage. COMMIT: lda curpage ; Get the current page sta ptr1+1 ; dst high ldx #$00 stx ptr1 ; dst low lda #window sta ptr2+1 ; src high stx ptr3+1 ; length high lda #$ff sta ptr3 ; length low stx tmp2 ; src bank ldy curbank ; Get the current bank iny ldx isnotscpu bne @notascpu iny @notascpu: sty tmp1 ; dst bank jsr transfer rts ; ------------------------------------------------------------------------ ; COPYFROM: Copy from extended into linear memory. A pointer to a structure ; describing the request is passed in a/x. ; The function must not return anything. ; COPYFROM: sta ptr4 stx ptr4+1 ; Save the passed em_copy pointer ldy #EM_COPY::COUNT+1 ; start at the end of the struct lda (ptr4),y ; get high byte of count tax dey lda (ptr4),y ; get low byte of count bne @nodex dex @nodex: .P816 dec .P02 sta ptr3 ; length low stx ptr3+1 ; length high dey lda (ptr4),y ; get bank .P816 inc .P02 ldx isnotscpu bne @notscpu64 .P816 inc .P02 @notscpu64: sta tmp2 ; src bank dey lda (ptr4),y ; get page sta ptr2+1 ; src high dey lda (ptr4),y ; get offset in page sta ptr2 ; src low dey lda (ptr4),y ; get memory buffer high sta ptr1+1 ; dst high dey lda (ptr4),y ; get memory buffer low sta ptr1 ; dst low lda #$00 sta tmp1 ; dst bank jsr transfer rts ; ------------------------------------------------------------------------ ; COPYTO: Copy from linear into extended memory. A pointer to a structure ; describing the request is passed in a/x. ; The function must not return anything. ; COPYTO: sta ptr4 stx ptr4+1 ; Save the passed em_copy pointer ldy #EM_COPY::COUNT+1 ; start at the end of the struct lda (ptr4),y ; get high byte of count tax dey lda (ptr4),y ; get low byte of count bne @nodex2 dex @nodex2: .P816 dec .P02 sta ptr3 ; length low txa sta ptr3+1 ; length high dey lda (ptr4),y ; get bank .P816 inc .P02 ldx isnotscpu bne @notascpu64 .P816 inc .P02 @notascpu64: sta tmp1 ; dst bank dey lda (ptr4),y ; get page sta ptr1+1 ; dst high dey lda (ptr4),y ; get page offset sta ptr1 ; dst low dey lda (ptr4),y ; get memory buffer high sta ptr2+1 ; src low dey lda (ptr4),y ; get memory buffer low sta ptr2 ; src high lda #$00 sta tmp2 ; src bank jsr transfer rts ; ------------------------------------------------------------------------ ; Helper function for moving a block, the following is used: ; ptr1: dst ; ptr2: src ; ptr3: length ; tmp1: dst bank ; tmp2: src bank transfer: .P816 .A8 .I8 sei pha phx phy ldx tmp1 ; load srcbank stx @move+1 ; store srcbank in move + 1 ldy tmp2 ; load dstbank sty @move+2 ; store dstbank in move + 2 clc ; switch to native mode xce php ; save status bits rep #%00110000 ; set A and index to 16bit .A16 .I16 ldy ptr1 ldx ptr2 lda ptr3 @move: mvn 0,0 plp ; restore status bits .A8 .I8 lda #$00 pha plb ; restore dbr sec xce ; switch to emul mode ply plx pla cli rts .P02