mirror of
https://github.com/cc65/cc65.git
synced 2024-12-27 00:29:31 +00:00
493 lines
14 KiB
ArmAsm
493 lines
14 KiB
ArmAsm
;
|
|
; Extended memory driver for the Atari 130XE memory standard
|
|
; Shawn Jefferson, 2012-08-11
|
|
;
|
|
; Banking Register $D301:
|
|
; Bit 7: Self-Test on/off
|
|
; Bit 6: Unused
|
|
; Bit 5: Antic sees bank
|
|
; Bit 4: CPU sees bank
|
|
; Bit 3: bank control
|
|
; Bit 2: bank control
|
|
; Bit 1: BASIC on/off
|
|
; Bit 0: OS RAM on/off
|
|
;
|
|
; Masks: %11100011 $E3 Bank 0
|
|
; %11100111 $E7 Bank 1
|
|
; %11101011 $EB Bank 2
|
|
; %11101111 $EF Bank 3
|
|
; %11111111 $FF Off
|
|
;
|
|
; Based on the Extended memory driver for the Apple II auxiliary memory
|
|
; by
|
|
; Stefan Haubenthal, 2003-12-12
|
|
; Ullrich von Bassewitz, 2002-12-02
|
|
;
|
|
|
|
.include "zeropage.inc"
|
|
|
|
.include "em-kernel.inc"
|
|
.include "em-error.inc"
|
|
|
|
|
|
.macpack generic
|
|
.macpack module
|
|
|
|
|
|
; ------------------------------------------------------------------------
|
|
; Header. Includes jump table
|
|
|
|
.ifdef __ATARIXL__
|
|
module_header _atrx130_emd
|
|
.else
|
|
module_header _atr130_emd
|
|
.endif
|
|
|
|
; 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
|
|
|
|
; ------------------------------------------------------------------------
|
|
; Constants
|
|
|
|
BANK = $4000 ; bank window
|
|
STACK = $0100 ; stack location
|
|
PAGES = 256 ; 4 x 16k banks
|
|
|
|
|
|
; ------------------------------------------------------------------------
|
|
; Data.
|
|
|
|
.rodata
|
|
banks: .byte $E3,$E7,$EB,$EF ; 130XE banks for cpu banking
|
|
|
|
stacktest: sei
|
|
ldy banks
|
|
sty $D301
|
|
tax ; A is set by caller
|
|
inx
|
|
stx $4000 ; change $4000
|
|
ldy #$FF ; STACK+13
|
|
sty $D301
|
|
cmp $4000 ; changed?
|
|
beq @1
|
|
sec ; error
|
|
bcs @2
|
|
@1: clc
|
|
@2: sta $4000 ; restore
|
|
cli
|
|
rts
|
|
stacktest_end:
|
|
|
|
stackcopy: sei ; disable interrupts
|
|
@1: dex ; pre-decrement (full page x=0)
|
|
ldy #$FF ; this will be replaced STACK+3
|
|
sty $D301 ; set bank
|
|
lda $FF00,x ; address to copy from STACK+8,+9
|
|
ldy #$FF ; this will be replaced STACK+11
|
|
sty $D301
|
|
sta $FF00,x ; address to copy to STACK+16,+17
|
|
cpx #0
|
|
bne @1
|
|
ldy #$FF ; portb_save STACK+23
|
|
sty $D301
|
|
cli ; enable interrupts
|
|
rts
|
|
stackcopy_end:
|
|
|
|
stackcopy_byte: sei
|
|
ldy #$FF ; STACK+2
|
|
sty $D301
|
|
lda $FFFF ; STACK+7 +8
|
|
ldy #$FF ; STACK+10
|
|
sty $D301
|
|
sta $FFFF ; STACK+15 +16
|
|
ldy #$FF ; STACK+18
|
|
sty $D301
|
|
cli
|
|
rts
|
|
stackcopy_byte_end:
|
|
|
|
|
|
.data
|
|
curpage: .byte $FF ; Current page number in bank (invalid)
|
|
curbank: .byte $FF ; Current bank number
|
|
|
|
.bss
|
|
window: .res 256 ; Memory "window"
|
|
portb_save: .res 1 ; portb state
|
|
|
|
.code
|
|
|
|
install_transfer:
|
|
ldx #stackcopy_end - stackcopy - 1
|
|
@1: lda stackcopy,x
|
|
sta STACK,x
|
|
dex
|
|
bpl @1
|
|
rts
|
|
|
|
install_byte_transfer:
|
|
ldx #stackcopy_byte_end - stackcopy_byte - 1
|
|
@2: lda stackcopy_byte,x
|
|
sta STACK,x
|
|
dex
|
|
bpl @2
|
|
rts
|
|
|
|
install_test:
|
|
ldx #stacktest_end - stacktest - 1
|
|
@3: lda stacktest,x
|
|
sta STACK,x
|
|
dex
|
|
bpl @3
|
|
rts
|
|
|
|
setpage:
|
|
tax ; save page
|
|
and #$C0 ; mask out bank
|
|
clc
|
|
ror
|
|
ror ; divide by 64
|
|
ror ; 64 pages in each bank
|
|
ror
|
|
ror
|
|
ror
|
|
sta curbank ; Remember the new bank
|
|
txa ; bring back page
|
|
and #$3F ; mask out page
|
|
sta curpage ; curpage in bank
|
|
rts
|
|
|
|
|
|
; ------------------------------------------------------------------------
|
|
; 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:
|
|
lda $D301 ; save state of portb
|
|
sta portb_save
|
|
tay
|
|
|
|
jsr install_test ; doesn't touch Y
|
|
sty STACK+13
|
|
|
|
lda $4000 ; test for extended memory
|
|
jsr STACK
|
|
bcs @1
|
|
lda #EM_ERR_OK
|
|
rts
|
|
@1: lda #EM_ERR_NO_DEVICE
|
|
rts
|
|
|
|
; ------------------------------------------------------------------------
|
|
; 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 #<PAGES
|
|
ldx #>PAGES
|
|
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: jsr setpage ; extract the bank/page
|
|
add #>BANK ; $4000 + page (carry is cleared)
|
|
sta ptr1+1
|
|
;ldy #$00
|
|
;sty ptr1
|
|
|
|
lda #<window
|
|
sta ptr2
|
|
lda #>window
|
|
sta ptr2+1
|
|
|
|
; Transfer one page
|
|
|
|
jsr install_transfer ; Transfer one page
|
|
|
|
ldx curbank
|
|
lda banks,x
|
|
sta STACK+3 ; set bank to copy from
|
|
; lda ptr1
|
|
; sta STACK+8
|
|
lda ptr1+1
|
|
sta STACK+9 ; set copy from address
|
|
lda portb_save
|
|
sta STACK+11 ; set portb restore
|
|
sta STACK+23 ; set final portb restore
|
|
lda ptr2
|
|
sta STACK+16
|
|
lda ptr2+1
|
|
sta STACK+17 ; set copy to address
|
|
|
|
ldx #0 ; full page copy
|
|
jsr STACK ; do the copy!
|
|
|
|
; Return the memory window
|
|
|
|
lda #<window
|
|
ldx #>window ; Return the window address
|
|
|
|
rts
|
|
|
|
; ------------------------------------------------------------------------
|
|
; USE: Tell the driver that the window is now associated with a given page.
|
|
|
|
USE: ;sta curpage ; Remember the page
|
|
jsr setpage ; extract bank/page
|
|
lda #<window
|
|
ldx #>window ; Return the window
|
|
rts
|
|
|
|
; ------------------------------------------------------------------------
|
|
; COMMIT: Commit changes in the memory window to extended storage.
|
|
|
|
COMMIT: lda curpage ; Get the current page
|
|
cmp #$FF
|
|
beq commit_done ; Jump if no page mapped
|
|
|
|
clc
|
|
add #>BANK
|
|
sta ptr2+1
|
|
;ldy #$00
|
|
;sty ptr2
|
|
|
|
lda #<window
|
|
sta ptr1
|
|
lda #>window
|
|
sta ptr1+1
|
|
|
|
; Transfer one page/all bytes
|
|
|
|
jsr install_transfer ; Transfer one page
|
|
|
|
lda portb_save
|
|
sta STACK+3 ; set bank to copy from
|
|
sta STACK+23 ; set final portb restore
|
|
lda ptr1
|
|
sta STACK+8
|
|
lda ptr1+1
|
|
sta STACK+9 ; set copy from address
|
|
ldx curbank
|
|
lda banks,x
|
|
sta STACK+11 ; set bank to copy to
|
|
;lda ptr2
|
|
;sta STACK+16
|
|
lda ptr2+1
|
|
sta STACK+17 ; set copy to address
|
|
|
|
ldx #0 ; full page copy
|
|
jsr STACK ; do the copy!
|
|
|
|
commit_done:
|
|
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 ptr3
|
|
stx ptr3+1 ; Save the passed em_copy pointer
|
|
|
|
jsr install_byte_transfer ; install the stack copy routine
|
|
|
|
ldy #EM_COPY::OFFS
|
|
lda (ptr3),y
|
|
sta STACK+7 ; offset goes into BANK low
|
|
|
|
ldy #EM_COPY::PAGE
|
|
lda (ptr3),y
|
|
sta tmp1 ; save page for later
|
|
;add #>BANK
|
|
;sta STACK+8 ; BANK + page goes into BANK high
|
|
|
|
ldy #EM_COPY::BUF
|
|
lda (ptr3),y
|
|
sta STACK+15 ; buffer goes into dest low
|
|
iny
|
|
lda (ptr3),y
|
|
sta STACK+16 ; buffer goes into dest high
|
|
|
|
ldy #EM_COPY::COUNT
|
|
lda (ptr3),y ; Get bytes in last page
|
|
sta ptr4
|
|
iny
|
|
lda (ptr3),y ; Get number of pages
|
|
sta ptr4+1
|
|
|
|
lda tmp1 ; extract bank/page
|
|
jsr setpage ; sets curbank/curpage
|
|
lda curpage
|
|
add #>BANK ; add to BANK address
|
|
sta STACK+8 ; current page in bank
|
|
ldx curbank
|
|
lda banks,x
|
|
sta STACK+2 ; set bank in stack
|
|
lda portb_save
|
|
sta STACK+10 ; set bank restore in stack
|
|
sta STACK+18 ; set final restore too
|
|
|
|
copyfrom_copy:
|
|
lda ptr4 ; check if count is zero
|
|
bne @4
|
|
lda ptr4+1
|
|
beq done
|
|
|
|
@4: jsr STACK ; copy one byte
|
|
|
|
sec
|
|
lda ptr4
|
|
sub #1
|
|
sta ptr4
|
|
bcs @1
|
|
lda ptr4+1
|
|
beq @1
|
|
sub #1
|
|
sta ptr4+1
|
|
|
|
@1: inc STACK+7 ; increment address in BANK
|
|
bne @2
|
|
inc STACK+8
|
|
lda STACK+8
|
|
cmp #$80 ; we stepped outside bank
|
|
bne @2
|
|
|
|
inc curbank ; get next bank
|
|
ldx curbank
|
|
lda banks,x
|
|
sta STACK+2 ; set new bank
|
|
lda #$40 ; set address back to $4000
|
|
sta STACK+8
|
|
|
|
@2: inc STACK+15 ; increment buffer address
|
|
bne @3
|
|
inc STACK+16
|
|
|
|
@3: jmp copyfrom_copy ; copy another byte
|
|
|
|
done:
|
|
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 ptr3
|
|
stx ptr3+1 ; Save the passed em_copy pointer
|
|
|
|
jsr install_byte_transfer ; install the stack copy routine
|
|
|
|
ldy #EM_COPY::OFFS
|
|
lda (ptr3),y
|
|
sta STACK+15 ; offset goes into BANK low
|
|
|
|
ldy #EM_COPY::PAGE
|
|
lda (ptr3),y
|
|
sta tmp1 ; save page for later
|
|
;add #>BANK
|
|
;sta STACK+16 ; BANK + page goes into BANK high
|
|
|
|
ldy #EM_COPY::BUF
|
|
lda (ptr3),y
|
|
sta STACK+7 ; buffer goes into dest low
|
|
iny
|
|
lda (ptr3),y
|
|
sta STACK+8 ; buffer goes into dest high
|
|
|
|
ldy #EM_COPY::COUNT
|
|
lda (ptr3),y ; Get bytes in last page
|
|
sta ptr4
|
|
iny
|
|
lda (ptr3),y ; Get number of pages
|
|
sta ptr4+1
|
|
|
|
lda tmp1 ; extract bank/page
|
|
jsr setpage ; sets curbank/curpage
|
|
lda curpage
|
|
add #>BANK ; add to BANK address
|
|
sta STACK+16 ; current page in bank
|
|
ldx curbank
|
|
lda banks,x
|
|
sta STACK+10 ; set bank in stack
|
|
lda portb_save
|
|
sta STACK+2 ; set bank restore in stack
|
|
sta STACK+18 ; set final restore too
|
|
|
|
copyto_copy:
|
|
lda ptr4 ; check if count is zero
|
|
bne @4
|
|
lda ptr4+1
|
|
beq done
|
|
|
|
@4: jsr STACK ; copy one byte
|
|
|
|
sec
|
|
lda ptr4
|
|
sub #1
|
|
sta ptr4
|
|
bcs @1
|
|
lda ptr4+1
|
|
beq @1
|
|
sub #1
|
|
sta ptr4+1
|
|
|
|
@1: inc STACK+15 ; increment address in BANK
|
|
bne @2
|
|
inc STACK+16
|
|
lda STACK+16
|
|
cmp #$80 ; we stepped outside bank
|
|
bne @2
|
|
|
|
inc curbank ; get next bank
|
|
ldx curbank
|
|
lda banks,x
|
|
sta STACK+10 ; set new bank
|
|
lda #$40 ; set address back to $4000
|
|
sta STACK+16
|
|
|
|
@2: inc STACK+7 ; increment buffer address
|
|
bne @3
|
|
inc STACK+8
|
|
|
|
@3: jmp copyto_copy ; copy another byte
|
|
|