Replaced whole bunch for Makefiles with a single generic Makefile.
- No complex shell logic. - "Source file shadowing" for all targets via vpath. - Dependency handling. - True incremental build. - Don't write into source directories. - Easy cleanup by just removing 'wrk'.
This commit is contained in:
502
libsrc/c64/emd/c64-c256k.s
Normal file
502
libsrc/c64/emd/c64-c256k.s
Normal file
@@ -0,0 +1,502 @@
|
||||
;
|
||||
; Extended memory driver for the C256K memory expansion
|
||||
; Marco van den Heuvel, 2010-01-27
|
||||
;
|
||||
|
||||
.include "zeropage.inc"
|
||||
|
||||
.include "em-kernel.inc"
|
||||
.include "em-error.inc"
|
||||
|
||||
|
||||
.macpack generic
|
||||
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Header. Includes jump table
|
||||
|
||||
.segment "JUMPTABLE"
|
||||
|
||||
; Driver signature
|
||||
|
||||
.byte $65, $6d, $64 ; "emd"
|
||||
.byte EMD_API_VERSION ; EM API version number
|
||||
|
||||
; Jump table.
|
||||
|
||||
.word INSTALL
|
||||
.word UNINSTALL
|
||||
.word PAGECOUNT
|
||||
.word MAP
|
||||
.word USE
|
||||
.word COMMIT
|
||||
.word COPYFROM
|
||||
.word COPYTO
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Constants
|
||||
|
||||
BASE = $4000
|
||||
PAGES = 3 * 256
|
||||
TARGETLOC = $200 ; Target location for copy/check code
|
||||
PIA = $DFC0
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Data.
|
||||
|
||||
.data
|
||||
|
||||
|
||||
; This function is used to copy code from and to the extended memory
|
||||
.proc copy
|
||||
template:
|
||||
.org ::TARGETLOC ; Assemble for target location
|
||||
entry:
|
||||
stx PIA
|
||||
stashop = $91 ; 'sta' opcode
|
||||
operation := * ; Location and opcode is patched at runtime
|
||||
address := *+1
|
||||
lda ($00),y
|
||||
ldx #$dc
|
||||
stx PIA
|
||||
rts
|
||||
.reloc
|
||||
.endproc
|
||||
|
||||
; This function is used to check for the existence of the extended memory
|
||||
.proc check
|
||||
template:
|
||||
.org ::TARGETLOC
|
||||
entry:
|
||||
ldy #$00 ; Assume hardware not present
|
||||
|
||||
lda #$fc
|
||||
sta PIA
|
||||
lda $01
|
||||
tax
|
||||
and #$f8
|
||||
sta $01
|
||||
lda $4000
|
||||
cmp $c000
|
||||
bne done ; Jump if not found
|
||||
inc $c000
|
||||
cmp $4000
|
||||
beq done ; Jump if not found
|
||||
|
||||
; Hardware is present
|
||||
iny
|
||||
done: stx $01
|
||||
ldx #$dc
|
||||
stx PIA
|
||||
rts
|
||||
.reloc
|
||||
.endproc
|
||||
|
||||
|
||||
|
||||
.bss
|
||||
|
||||
curpage: .res 2 ; Current page number
|
||||
curbank: .res 1 ; Current bank
|
||||
window: .res 256 ; Memory "window"
|
||||
|
||||
; Since the functions above are copied to $200, the current contents of this
|
||||
; memory area must be saved into backup storage. Allocate enough space.
|
||||
backup: .res .max (.sizeof (copy), .sizeof (check))
|
||||
|
||||
|
||||
|
||||
.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:
|
||||
lda PIA+1 ; Select Peripheral Registers
|
||||
ora #4
|
||||
sta PIA+1
|
||||
tax
|
||||
lda PIA+3
|
||||
ora #4
|
||||
sta PIA+3
|
||||
tay
|
||||
|
||||
lda #$DC ; Set the default memory bank data
|
||||
sta PIA
|
||||
lda #$FE
|
||||
sta PIA+2
|
||||
|
||||
txa ; Select Data Direction Registers
|
||||
and #$FB
|
||||
sta PIA+1
|
||||
tya
|
||||
and #$FB
|
||||
sta PIA+3
|
||||
|
||||
lda #$FF ; Set the ports to output
|
||||
sta PIA
|
||||
sta PIA+2
|
||||
|
||||
txa
|
||||
and #$C7
|
||||
ora #$30 ; Set CA1 and
|
||||
sta PIA+1 ; select Peripheral Registers
|
||||
sty PIA+3
|
||||
|
||||
jsr backup_and_setup_check_routine
|
||||
jsr check::entry
|
||||
cli
|
||||
ldx #.sizeof (check) - 1
|
||||
jsr restore_data
|
||||
cpy #$01
|
||||
beq @present
|
||||
lda #<EM_ERR_NO_DEVICE
|
||||
ldx #>EM_ERR_NO_DEVICE
|
||||
rts
|
||||
|
||||
@present:
|
||||
lda #<EM_ERR_OK
|
||||
ldx #>EM_ERR_OK
|
||||
; 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 #<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:
|
||||
sei
|
||||
sta curpage ; Remember the new page
|
||||
stx curpage+1
|
||||
jsr adjust_page_and_bank
|
||||
stx curbank
|
||||
clc
|
||||
adc #>BASE
|
||||
sta ptr1+1
|
||||
ldy #0
|
||||
sty ptr1
|
||||
jsr backup_and_setup_copy_routine
|
||||
ldx #<ptr1
|
||||
stx copy::address
|
||||
@L1:
|
||||
ldx curbank
|
||||
jsr copy::entry
|
||||
ldx ptr1
|
||||
sta window,x
|
||||
inc ptr1
|
||||
bne @L1
|
||||
|
||||
; Return the memory window
|
||||
|
||||
jsr restore_copy_routine
|
||||
lda #<window
|
||||
ldx #>window ; Return the window address
|
||||
cli
|
||||
rts
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; USE: Tell the driver that the window is now associated with a given page.
|
||||
|
||||
USE: sta curpage ; Remember the page
|
||||
stx curpage+1
|
||||
lda #<window
|
||||
ldx #>window ; Return the window
|
||||
rts
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; COMMIT: Commit changes in the memory window to extended storage.
|
||||
|
||||
COMMIT:
|
||||
sei
|
||||
lda curpage ; Get the current page
|
||||
ldx curpage+1
|
||||
|
||||
jsr adjust_page_and_bank
|
||||
stx curbank
|
||||
clc
|
||||
adc #>BASE
|
||||
sta ptr1+1
|
||||
ldy #0
|
||||
sty ptr1
|
||||
jsr backup_and_setup_copy_routine
|
||||
ldx #<ptr1
|
||||
stx copy::address
|
||||
ldx #<copy::stashop
|
||||
stx copy::operation
|
||||
@L1:
|
||||
ldx ptr1
|
||||
lda window,x
|
||||
ldx curbank
|
||||
jsr copy::entry
|
||||
inc ptr1
|
||||
bne @L1
|
||||
|
||||
; Return the memory window
|
||||
|
||||
jsr restore_copy_routine
|
||||
done:
|
||||
cli
|
||||
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:
|
||||
sei
|
||||
jsr setup
|
||||
jsr backup_and_setup_copy_routine
|
||||
|
||||
; Setup is:
|
||||
;
|
||||
; - ptr1 contains the struct pointer
|
||||
; - ptr2 contains the linear memory buffer
|
||||
; - ptr3 contains -(count-1)
|
||||
; - ptr4 contains the page memory buffer plus offset
|
||||
; - tmp1 contains zero (to be used for linear memory buffer offset)
|
||||
; - tmp2 contains the bank value
|
||||
|
||||
lda #<ptr4
|
||||
sta copy::address
|
||||
jmp @L3
|
||||
|
||||
@L1:
|
||||
ldx tmp2
|
||||
ldy #0
|
||||
jsr copy::entry
|
||||
ldy tmp1
|
||||
sta (ptr2),y
|
||||
inc tmp1
|
||||
bne @L2
|
||||
inc ptr2+1
|
||||
@L2:
|
||||
inc ptr4
|
||||
beq @L4
|
||||
|
||||
; Bump count and repeat
|
||||
|
||||
@L3:
|
||||
inc ptr3
|
||||
bne @L1
|
||||
inc ptr3+1
|
||||
bne @L1
|
||||
jsr restore_copy_routine
|
||||
cli
|
||||
rts
|
||||
|
||||
; Bump page register
|
||||
|
||||
@L4:
|
||||
inc ptr4+1
|
||||
lda ptr4+1
|
||||
cmp #$80
|
||||
bne @L3
|
||||
lda #>BASE
|
||||
sta ptr4+1
|
||||
lda tmp2
|
||||
clc
|
||||
adc #$10
|
||||
sta tmp2
|
||||
jmp @L3
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; 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:
|
||||
sei
|
||||
jsr setup
|
||||
jsr backup_and_setup_copy_routine
|
||||
|
||||
; Setup is:
|
||||
;
|
||||
; - ptr1 contains the struct pointer
|
||||
; - ptr2 contains the linear memory buffer
|
||||
; - ptr3 contains -(count-1)
|
||||
; - ptr4 contains the page memory buffer plus offset
|
||||
; - tmp1 contains zero (to be used for linear memory buffer offset)
|
||||
; - tmp2 contains the bank value
|
||||
|
||||
lda #<ptr4
|
||||
sta copy::address
|
||||
lda #<copy::stashop
|
||||
sta copy::operation
|
||||
jmp @L3
|
||||
|
||||
@L1:
|
||||
ldy tmp1
|
||||
lda (ptr2),y
|
||||
ldx tmp2
|
||||
ldy #0
|
||||
jsr copy::entry
|
||||
inc tmp1
|
||||
bne @L2
|
||||
inc ptr2+1
|
||||
@L2:
|
||||
inc ptr4
|
||||
beq @L4
|
||||
|
||||
; Bump count and repeat
|
||||
|
||||
@L3:
|
||||
inc ptr3
|
||||
bne @L1
|
||||
inc ptr3+1
|
||||
bne @L1
|
||||
jsr restore_copy_routine
|
||||
cli
|
||||
rts
|
||||
|
||||
; Bump page register
|
||||
|
||||
@L4:
|
||||
inc ptr4+1
|
||||
lda ptr4+1
|
||||
cmp #$80
|
||||
bne @L3
|
||||
lda #>BASE
|
||||
sta ptr4+1
|
||||
lda tmp2
|
||||
clc
|
||||
adc #$10
|
||||
sta tmp2
|
||||
jmp @L3
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Helper function for COPYFROM and COPYTO: Store the pointer to the request
|
||||
; structure and prepare data for the copy
|
||||
|
||||
setup:
|
||||
sta ptr1
|
||||
stx ptr1+1 ; Save passed pointer
|
||||
|
||||
; Get the page number from the struct and adjust it so that it may be used
|
||||
; with the hardware. That is: ptr4 has the page address and page offset
|
||||
; tmp2 will hold the bank value
|
||||
|
||||
ldy #EM_COPY::PAGE+1
|
||||
lda (ptr1),y
|
||||
tax
|
||||
ldy #EM_COPY::PAGE
|
||||
lda (ptr1),y
|
||||
jsr adjust_page_and_bank
|
||||
clc
|
||||
adc #>BASE
|
||||
sta ptr4+1
|
||||
stx tmp2
|
||||
|
||||
; Get the buffer pointer into ptr2
|
||||
|
||||
ldy #EM_COPY::BUF
|
||||
lda (ptr1),y
|
||||
sta ptr2
|
||||
iny
|
||||
lda (ptr1),y
|
||||
sta ptr2+1
|
||||
|
||||
; Get the count, calculate -(count-1) and store it into ptr3
|
||||
|
||||
ldy #EM_COPY::COUNT
|
||||
lda (ptr1),y
|
||||
eor #$FF
|
||||
sta ptr3
|
||||
iny
|
||||
lda (ptr1),y
|
||||
eor #$FF
|
||||
sta ptr3+1
|
||||
|
||||
; Get the page offset into ptr4 and clear tmp1
|
||||
|
||||
ldy #EM_COPY::OFFS
|
||||
lda (ptr1),y
|
||||
sta ptr4
|
||||
lda #0
|
||||
sta tmp1
|
||||
|
||||
; Done
|
||||
|
||||
rts
|
||||
|
||||
; Helper routines for copying to and from the +256k ram
|
||||
|
||||
backup_and_setup_copy_routine:
|
||||
ldx #.sizeof (copy) - 1
|
||||
@L1:
|
||||
lda copy::entry,x
|
||||
sta backup,x
|
||||
lda copy::template,x
|
||||
sta copy::entry,x
|
||||
dex
|
||||
bpl @L1
|
||||
rts
|
||||
|
||||
backup_and_setup_check_routine:
|
||||
ldx #.sizeof (check) - 1
|
||||
@L1:
|
||||
lda check::entry,x
|
||||
sta backup,x
|
||||
lda check::template,x
|
||||
sta check::entry,x
|
||||
dex
|
||||
bpl @L1
|
||||
rts
|
||||
|
||||
restore_copy_routine:
|
||||
ldx #.sizeof (copy) - 1
|
||||
restore_data:
|
||||
lda backup,x
|
||||
sta TARGETLOC,x
|
||||
dex
|
||||
bpl restore_data
|
||||
rts
|
||||
|
||||
; Helper routine to correct for the bank and page
|
||||
adjust_page_and_bank:
|
||||
sta tmp4
|
||||
lda #$0C
|
||||
sta tmp3
|
||||
lda tmp4
|
||||
and #$c0
|
||||
lsr
|
||||
lsr
|
||||
ora tmp3
|
||||
sta tmp3
|
||||
txa
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
ora tmp3
|
||||
tax
|
||||
lda tmp4
|
||||
and #$3f
|
||||
rts
|
||||
441
libsrc/c64/emd/c64-dqbb.s
Normal file
441
libsrc/c64/emd/c64-dqbb.s
Normal file
@@ -0,0 +1,441 @@
|
||||
;
|
||||
; Extended memory driver for the Double Quick Brown Box cartridge
|
||||
; Marco van den Heuvel, 2010-01-27
|
||||
;
|
||||
|
||||
.include "zeropage.inc"
|
||||
|
||||
.include "em-kernel.inc"
|
||||
.include "em-error.inc"
|
||||
|
||||
|
||||
.macpack generic
|
||||
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Header. Includes jump table
|
||||
|
||||
.segment "JUMPTABLE"
|
||||
|
||||
; Driver signature
|
||||
|
||||
.byte $65, $6d, $64 ; "emd"
|
||||
.byte EMD_API_VERSION ; EM API version number
|
||||
|
||||
; Jump table.
|
||||
|
||||
.word INSTALL
|
||||
.word UNINSTALL
|
||||
.word PAGECOUNT
|
||||
.word MAP
|
||||
.word USE
|
||||
.word COMMIT
|
||||
.word COPYFROM
|
||||
.word COPYTO
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Constants
|
||||
|
||||
BASE = $8000
|
||||
PAGES = ($C000 - BASE) / 256
|
||||
TARGETLOC = $200 ; Target location for copy/check code
|
||||
CONTROL = $DE00
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Data.
|
||||
|
||||
.proc check
|
||||
template:
|
||||
.org ::TARGETLOC ; Assemble for target location
|
||||
entry:
|
||||
lda $01
|
||||
pha
|
||||
lda #$37
|
||||
sta $01
|
||||
ldx #$14
|
||||
ldy #$90
|
||||
sty CONTROL
|
||||
lda $8000
|
||||
stx CONTROL
|
||||
cmp $8000
|
||||
bne present
|
||||
sty CONTROL
|
||||
inc $8000
|
||||
stx CONTROL
|
||||
cmp $8000
|
||||
beq present
|
||||
dec $8000
|
||||
ldy #$00
|
||||
|
||||
done: pla
|
||||
sta $01
|
||||
rts
|
||||
|
||||
present:
|
||||
sty CONTROL
|
||||
ldy #$01
|
||||
bne done
|
||||
.reloc
|
||||
.endproc
|
||||
|
||||
|
||||
.proc copy
|
||||
template:
|
||||
.org ::TARGETLOC ; Assemble for target location
|
||||
entry:
|
||||
.proc fetch
|
||||
stx CONTROL
|
||||
ldx $01
|
||||
lda #$37
|
||||
sta $01
|
||||
address := *+1 ; Patched at runtime
|
||||
lda ($00),y
|
||||
stx $01
|
||||
ldx #$90
|
||||
stx CONTROL
|
||||
rts
|
||||
.endproc
|
||||
|
||||
.proc stash
|
||||
stx CONTROL
|
||||
ldx $01
|
||||
ldy #$37
|
||||
sty $01
|
||||
ldy #$00
|
||||
address := *+1 ; Patched at runtime
|
||||
sta ($00),y
|
||||
stx $01
|
||||
ldx #$90
|
||||
stx CONTROL
|
||||
rts
|
||||
.endproc
|
||||
.reloc
|
||||
.endproc
|
||||
|
||||
|
||||
.bss
|
||||
|
||||
curpage: .res 1 ; Current page number
|
||||
window: .res 256 ; Memory "window"
|
||||
|
||||
; Since the functions above are copied to $200, the current contents of this
|
||||
; memory area must be saved into backup storage. Allocate enough space.
|
||||
backup: .res .max (.sizeof (copy), .sizeof (check))
|
||||
|
||||
|
||||
|
||||
.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
|
||||
jsr backup_and_setup_check_routine
|
||||
jsr check::entry
|
||||
cli
|
||||
ldx #.sizeof (check) - 1
|
||||
jsr restore_data
|
||||
cpy #$01
|
||||
beq @present
|
||||
lda #<EM_ERR_NO_DEVICE
|
||||
ldx #>EM_ERR_NO_DEVICE
|
||||
rts
|
||||
|
||||
@present:
|
||||
lda #<EM_ERR_OK
|
||||
ldx #>EM_ERR_OK
|
||||
; 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 #<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:
|
||||
sei
|
||||
sta curpage ; Remember the new page
|
||||
clc
|
||||
adc #>BASE
|
||||
sta ptr1+1
|
||||
ldy #0
|
||||
sty ptr1
|
||||
jsr backup_and_setup_copy_routine
|
||||
ldx #<ptr1
|
||||
stx copy::fetch::address
|
||||
@L1:
|
||||
ldx #$14
|
||||
jsr copy::fetch
|
||||
ldx ptr1
|
||||
sta window,x
|
||||
inc ptr1
|
||||
bne @L1
|
||||
|
||||
; Return the memory window
|
||||
|
||||
jsr restore_copy_routine
|
||||
lda #<window
|
||||
ldx #>window ; Return the window address
|
||||
cli
|
||||
rts
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; USE: Tell the driver that the window is now associated with a given page.
|
||||
|
||||
USE: sta curpage ; Remember the page
|
||||
lda #<window
|
||||
ldx #>window ; Return the window
|
||||
rts
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; COMMIT: Commit changes in the memory window to extended storage.
|
||||
|
||||
COMMIT:
|
||||
sei
|
||||
lda curpage ; Get the current page
|
||||
clc
|
||||
adc #>BASE
|
||||
sta ptr1+1
|
||||
ldy #0
|
||||
sty ptr1
|
||||
jsr backup_and_setup_copy_routine
|
||||
ldx #<ptr1
|
||||
stx copy::stash::address
|
||||
@L1:
|
||||
ldx ptr1
|
||||
lda window,x
|
||||
ldx #$14
|
||||
jsr copy::stash
|
||||
inc ptr1
|
||||
bne @L1
|
||||
|
||||
; Return the memory window
|
||||
|
||||
jsr restore_copy_routine
|
||||
cli
|
||||
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:
|
||||
sei
|
||||
pha
|
||||
txa
|
||||
pha
|
||||
jsr backup_and_setup_copy_routine
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
jsr setup
|
||||
|
||||
; Setup is:
|
||||
;
|
||||
; - ptr1 contains the struct pointer
|
||||
; - ptr2 contains the linear memory buffer
|
||||
; - ptr3 contains -(count-1)
|
||||
; - ptr4 contains the page memory buffer plus offset
|
||||
; - tmp1 contains zero (to be used for linear memory buffer offset)
|
||||
|
||||
lda #<ptr4
|
||||
sta copy::fetch::address
|
||||
jmp @L3
|
||||
|
||||
@L1:
|
||||
ldx #$14
|
||||
ldy #0
|
||||
jsr copy::fetch
|
||||
ldy tmp1
|
||||
sta (ptr2),y
|
||||
inc tmp1
|
||||
bne @L2
|
||||
inc ptr2+1
|
||||
@L2:
|
||||
inc ptr4
|
||||
beq @L4
|
||||
|
||||
; Bump count and repeat
|
||||
|
||||
@L3:
|
||||
inc ptr3
|
||||
bne @L1
|
||||
inc ptr3+1
|
||||
bne @L1
|
||||
jsr restore_copy_routine
|
||||
cli
|
||||
rts
|
||||
|
||||
; Bump page register
|
||||
|
||||
@L4:
|
||||
inc ptr4+1
|
||||
jmp @L3
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; 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:
|
||||
sei
|
||||
pha
|
||||
txa
|
||||
pha
|
||||
jsr backup_and_setup_copy_routine
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
jsr setup
|
||||
|
||||
; Setup is:
|
||||
;
|
||||
; - ptr1 contains the struct pointer
|
||||
; - ptr2 contains the linear memory buffer
|
||||
; - ptr3 contains -(count-1)
|
||||
; - ptr4 contains the page memory buffer plus offset
|
||||
; - tmp1 contains zero (to be used for linear memory buffer offset)
|
||||
|
||||
lda #<ptr4
|
||||
sta copy::stash::address
|
||||
jmp @L3
|
||||
|
||||
@L1:
|
||||
ldy tmp1
|
||||
lda (ptr2),y
|
||||
ldx #$14
|
||||
ldy #0
|
||||
jsr copy::stash
|
||||
inc tmp1
|
||||
bne @L2
|
||||
inc ptr2+1
|
||||
@L2:
|
||||
inc ptr4
|
||||
beq @L4
|
||||
|
||||
; Bump count and repeat
|
||||
|
||||
@L3:
|
||||
inc ptr3
|
||||
bne @L1
|
||||
inc ptr3+1
|
||||
bne @L1
|
||||
jsr restore_copy_routine
|
||||
cli
|
||||
rts
|
||||
|
||||
; Bump page register
|
||||
|
||||
@L4:
|
||||
inc ptr4+1
|
||||
jmp @L3
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Helper function for COPYFROM and COPYTO: Store the pointer to the request
|
||||
; structure and prepare data for the copy
|
||||
|
||||
setup:
|
||||
sta ptr1
|
||||
stx ptr1+1 ; Save passed pointer
|
||||
|
||||
; Get the page number from the struct and adjust it so that it may be used
|
||||
; with the hardware. That is: ptr4 has the page address and page offset
|
||||
; tmp2 will hold the bank value
|
||||
|
||||
ldy #EM_COPY::PAGE
|
||||
lda (ptr1),y
|
||||
clc
|
||||
adc #>BASE
|
||||
sta ptr4+1
|
||||
|
||||
; Get the buffer pointer into ptr2
|
||||
|
||||
ldy #EM_COPY::BUF
|
||||
lda (ptr1),y
|
||||
sta ptr2
|
||||
iny
|
||||
lda (ptr1),y
|
||||
sta ptr2+1
|
||||
|
||||
; Get the count, calculate -(count-1) and store it into ptr3
|
||||
|
||||
ldy #EM_COPY::COUNT
|
||||
lda (ptr1),y
|
||||
eor #$FF
|
||||
sta ptr3
|
||||
iny
|
||||
lda (ptr1),y
|
||||
eor #$FF
|
||||
sta ptr3+1
|
||||
|
||||
; Get the page offset into ptr4 and clear tmp1
|
||||
|
||||
ldy #EM_COPY::OFFS
|
||||
lda (ptr1),y
|
||||
sta ptr4
|
||||
lda #0
|
||||
sta tmp1
|
||||
|
||||
; Done
|
||||
|
||||
rts
|
||||
|
||||
; Helper routines for copying to and from the +256k ram
|
||||
|
||||
backup_and_setup_copy_routine:
|
||||
ldx #.sizeof (copy) - 1
|
||||
@L1:
|
||||
lda copy::entry,x
|
||||
sta backup,x
|
||||
lda copy::template,x
|
||||
sta copy::entry,x
|
||||
dex
|
||||
bpl @L1
|
||||
rts
|
||||
|
||||
backup_and_setup_check_routine:
|
||||
ldx #.sizeof (check) - 1
|
||||
@L1:
|
||||
lda check::entry,x
|
||||
sta backup,x
|
||||
lda check::template,x
|
||||
sta check::entry,x
|
||||
dex
|
||||
bpl @L1
|
||||
rts
|
||||
|
||||
restore_copy_routine:
|
||||
ldx #.sizeof (copy) - 1
|
||||
restore_data:
|
||||
lda backup,x
|
||||
sta TARGETLOC,x
|
||||
dex
|
||||
bpl restore_data
|
||||
rts
|
||||
349
libsrc/c64/emd/c64-georam.s
Normal file
349
libsrc/c64/emd/c64-georam.s
Normal file
@@ -0,0 +1,349 @@
|
||||
;
|
||||
; Extended memory driver for the GEORAM cartridge. Driver works without
|
||||
; problems when statically linked.
|
||||
;
|
||||
; Ullrich von Bassewitz, 2002-11-29
|
||||
;
|
||||
; GEORAM page size checking routine by
|
||||
; Marco van den Heuvel, 2010-01-21
|
||||
;
|
||||
|
||||
.include "zeropage.inc"
|
||||
|
||||
.include "em-kernel.inc"
|
||||
.include "em-error.inc"
|
||||
|
||||
|
||||
.macpack generic
|
||||
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Header. Includes jump table
|
||||
|
||||
.segment "JUMPTABLE"
|
||||
|
||||
; Driver signature
|
||||
|
||||
.byte $65, $6d, $64 ; "emd"
|
||||
.byte EMD_API_VERSION ; EM API version number
|
||||
|
||||
; Jump table.
|
||||
|
||||
.word INSTALL
|
||||
.word UNINSTALL
|
||||
.word PAGECOUNT
|
||||
.word MAP
|
||||
.word USE
|
||||
.word COMMIT
|
||||
.word COPYFROM
|
||||
.word COPYTO
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Constants
|
||||
|
||||
GR_WINDOW = $DE00 ; Address of GEORAM window
|
||||
GR_PAGE_LO = $DFFE ; Page register low
|
||||
GR_PAGE_HI = $DFFF ; Page register high
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Data.
|
||||
|
||||
.data
|
||||
|
||||
pagecount: .res 2 ; Number of available pages
|
||||
|
||||
.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:
|
||||
ldx GR_WINDOW
|
||||
cpx GR_WINDOW
|
||||
bne @notpresent
|
||||
inc GR_WINDOW
|
||||
cpx GR_WINDOW
|
||||
beq @notpresent
|
||||
|
||||
lda #4
|
||||
jsr check
|
||||
cpy GR_WINDOW
|
||||
beq @has64k
|
||||
lda #8
|
||||
jsr check
|
||||
cpy GR_WINDOW
|
||||
beq @has128k
|
||||
lda #16
|
||||
jsr check
|
||||
cpy GR_WINDOW
|
||||
beq @has256k
|
||||
lda #32
|
||||
jsr check
|
||||
cpy GR_WINDOW
|
||||
beq @has512k
|
||||
lda #64
|
||||
jsr check
|
||||
cpy GR_WINDOW
|
||||
beq @has1024k
|
||||
lda #128
|
||||
jsr check
|
||||
cpy GR_WINDOW
|
||||
beq @has2048k
|
||||
ldx #>16384
|
||||
bne @setok
|
||||
|
||||
@has64k:
|
||||
ldx #>256
|
||||
bne @setok
|
||||
@has128k:
|
||||
ldx #>512
|
||||
bne @setok
|
||||
@has256k:
|
||||
ldx #>1024
|
||||
bne @setok
|
||||
@has512k:
|
||||
ldx #>2048
|
||||
bne @setok
|
||||
@has1024k:
|
||||
ldx #>4096
|
||||
bne @setok
|
||||
@has2048k:
|
||||
ldx #>8192
|
||||
bne @setok
|
||||
|
||||
@notpresent:
|
||||
lda #<EM_ERR_NO_DEVICE
|
||||
ldx #>EM_ERR_NO_DEVICE
|
||||
rts
|
||||
|
||||
@setok:
|
||||
lda #0
|
||||
sta pagecount
|
||||
stx pagecount+1
|
||||
lda #<EM_ERR_OK
|
||||
ldx #>EM_ERR_OK
|
||||
rts
|
||||
|
||||
check:
|
||||
ldx #0
|
||||
stx GR_PAGE_LO
|
||||
stx GR_PAGE_HI
|
||||
ldy GR_WINDOW
|
||||
iny
|
||||
sta GR_PAGE_HI
|
||||
sty GR_WINDOW
|
||||
ldx #0
|
||||
stx GR_PAGE_HI
|
||||
; 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 pagecount
|
||||
ldx pagecount+1
|
||||
rts
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; USE: Tell the driver that the window is now associated with a given page.
|
||||
; The GeoRAM cartridge does not copy but actually map the window, so USE is
|
||||
; identical to MAP.
|
||||
|
||||
USE = MAP
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; 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 tmp1
|
||||
txa
|
||||
asl tmp1
|
||||
rol a
|
||||
asl tmp1
|
||||
rol a
|
||||
|
||||
sta GR_PAGE_HI
|
||||
lda tmp1
|
||||
lsr a
|
||||
lsr a
|
||||
sta GR_PAGE_LO
|
||||
|
||||
lda #<GR_WINDOW
|
||||
ldx #>GR_WINDOW
|
||||
|
||||
; Use the RTS from COMMIT below to save a precious byte of storage
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; COMMIT: Commit changes in the memory window to extended storage.
|
||||
|
||||
COMMIT: 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:
|
||||
jsr setup
|
||||
|
||||
; Setup is:
|
||||
;
|
||||
; - ptr1 contains the struct pointer
|
||||
; - ptr2 contains the linear memory buffer
|
||||
; - ptr3 contains -(count-1)
|
||||
; - tmp1 contains the low page register value
|
||||
; - tmp2 contains the high page register value
|
||||
; - X contains the page offset
|
||||
; - Y contains zero
|
||||
|
||||
jmp @L5
|
||||
|
||||
@L1: lda GR_WINDOW,x
|
||||
sta (ptr2),y
|
||||
iny
|
||||
bne @L2
|
||||
inc ptr2+1
|
||||
@L2: inx
|
||||
beq @L4
|
||||
|
||||
; Bump count and repeat
|
||||
|
||||
@L3: inc ptr3
|
||||
bne @L1
|
||||
inc ptr3+1
|
||||
bne @L1
|
||||
rts
|
||||
|
||||
; Bump page register
|
||||
|
||||
@L4: inc tmp1 ; Bump low page register
|
||||
bit tmp1 ; Check for overflow in bit 6
|
||||
bvc @L6 ; Jump if no overflow
|
||||
inc tmp2
|
||||
@L5: lda tmp2
|
||||
sta GR_PAGE_HI
|
||||
@L6: lda tmp1
|
||||
sta GR_PAGE_LO
|
||||
jmp @L3
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; 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:
|
||||
jsr setup
|
||||
|
||||
; Setup is:
|
||||
;
|
||||
; - ptr1 contains the struct pointer
|
||||
; - ptr2 contains the linear memory buffer
|
||||
; - ptr3 contains -(count-1)
|
||||
; - tmp1 contains the low page register value
|
||||
; - tmp2 contains the high page register value
|
||||
; - X contains the page offset
|
||||
; - Y contains zero
|
||||
|
||||
jmp @L5
|
||||
|
||||
@L1: lda (ptr2),y
|
||||
sta GR_WINDOW,x
|
||||
iny
|
||||
bne @L2
|
||||
inc ptr2+1
|
||||
@L2: inx
|
||||
beq @L4
|
||||
|
||||
; Bump count and repeat
|
||||
|
||||
@L3: inc ptr3
|
||||
bne @L1
|
||||
inc ptr3+1
|
||||
bne @L1
|
||||
rts
|
||||
|
||||
; Bump page register
|
||||
|
||||
@L4: inc tmp1 ; Bump low page register
|
||||
bit tmp1 ; Check for overflow in bit 6
|
||||
bvc @L6 ; Jump if no overflow
|
||||
inc tmp2
|
||||
@L5: lda tmp2
|
||||
sta GR_PAGE_HI
|
||||
@L6: lda tmp1
|
||||
sta GR_PAGE_LO
|
||||
jmp @L3
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Helper function for COPYFROM and COPYTO: Store the pointer to the request
|
||||
; structure and prepare data for the copy
|
||||
|
||||
setup: sta ptr1
|
||||
stx ptr1+1 ; Save passed pointer
|
||||
|
||||
; Get the page number from the struct and adjust it so that it may be used
|
||||
; with the hardware. That is: lower 6 bits in tmp1, high bits in tmp2.
|
||||
|
||||
ldy #EM_COPY::PAGE+1
|
||||
lda (ptr1),y
|
||||
sta tmp2
|
||||
dey
|
||||
lda (ptr1),y
|
||||
asl a
|
||||
rol tmp2
|
||||
asl a
|
||||
rol tmp2
|
||||
lsr a
|
||||
lsr a
|
||||
sta tmp1
|
||||
|
||||
; Get the buffer pointer into ptr2
|
||||
|
||||
ldy #EM_COPY::BUF
|
||||
lda (ptr1),y
|
||||
sta ptr2
|
||||
iny
|
||||
lda (ptr1),y
|
||||
sta ptr2+1
|
||||
|
||||
; Get the count, calculate -(count-1) and store it into ptr3
|
||||
|
||||
ldy #EM_COPY::COUNT
|
||||
lda (ptr1),y
|
||||
eor #$FF
|
||||
sta ptr3
|
||||
iny
|
||||
lda (ptr1),y
|
||||
eor #$FF
|
||||
sta ptr3+1
|
||||
|
||||
; Get the page offset into X and clear Y
|
||||
|
||||
ldy #EM_COPY::OFFS
|
||||
lda (ptr1),y
|
||||
tax
|
||||
ldy #$00
|
||||
|
||||
; Done
|
||||
|
||||
rts
|
||||
|
||||
|
||||
270
libsrc/c64/emd/c64-isepic.s
Normal file
270
libsrc/c64/emd/c64-isepic.s
Normal file
@@ -0,0 +1,270 @@
|
||||
;
|
||||
; Extended memory driver for the ISEPIC cartridge.
|
||||
; Marco van den Heuvel, 2010-01-24
|
||||
;
|
||||
|
||||
.include "zeropage.inc"
|
||||
|
||||
.include "em-kernel.inc"
|
||||
.include "em-error.inc"
|
||||
|
||||
|
||||
.macpack generic
|
||||
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Header. Includes jump table
|
||||
|
||||
.segment "JUMPTABLE"
|
||||
|
||||
; Driver signature
|
||||
|
||||
.byte $65, $6d, $64 ; "emd"
|
||||
.byte EMD_API_VERSION ; EM API version number
|
||||
|
||||
; Jump table.
|
||||
|
||||
.word INSTALL
|
||||
.word UNINSTALL
|
||||
.word PAGECOUNT
|
||||
.word MAP
|
||||
.word USE
|
||||
.word COMMIT
|
||||
.word COPYFROM
|
||||
.word COPYTO
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Constants
|
||||
|
||||
IP_WINDOW = $DF00 ; Address of ISEPIC window
|
||||
IP_CTRL_BASE = $DE00
|
||||
PAGES = 8
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Code.
|
||||
|
||||
.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:
|
||||
lda #0
|
||||
sta IP_CTRL_BASE
|
||||
ldx IP_WINDOW
|
||||
cpx IP_WINDOW
|
||||
bne @notpresent
|
||||
inc IP_WINDOW
|
||||
cpx IP_WINDOW
|
||||
beq @notpresent
|
||||
ldx IP_WINDOW
|
||||
sta IP_CTRL_BASE+1
|
||||
inx
|
||||
stx IP_WINDOW
|
||||
dex
|
||||
sta IP_CTRL_BASE
|
||||
cpx IP_WINDOW
|
||||
beq @setok
|
||||
|
||||
@notpresent:
|
||||
lda #<EM_ERR_NO_DEVICE
|
||||
ldx #>EM_ERR_NO_DEVICE
|
||||
rts
|
||||
|
||||
@setok:
|
||||
lda #<EM_ERR_OK
|
||||
ldx #>EM_ERR_OK
|
||||
; 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 #<PAGES
|
||||
ldx #>PAGES
|
||||
rts
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; USE: Tell the driver that the window is now associated with a given page.
|
||||
; The Isepic cartridge does not copy but actually map the window, so USE is
|
||||
; identical to MAP.
|
||||
|
||||
USE := MAP
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; 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:
|
||||
tax
|
||||
sta IP_CTRL_BASE,x
|
||||
lda #<IP_WINDOW
|
||||
ldx #>IP_WINDOW
|
||||
|
||||
; Use the RTS from COMMIT below to save a precious byte of storage
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; COMMIT: Commit changes in the memory window to extended storage.
|
||||
|
||||
COMMIT:
|
||||
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:
|
||||
jsr setup
|
||||
|
||||
; Setup is:
|
||||
;
|
||||
; - ptr1 contains the struct pointer
|
||||
; - ptr2 contains the linear memory buffer
|
||||
; - ptr3 contains -(count-1)
|
||||
; - tmp1 contains the low page register value
|
||||
; - X contains the page offset
|
||||
; - Y contains zero
|
||||
|
||||
jmp @L5
|
||||
|
||||
@L1:
|
||||
lda IP_WINDOW,x
|
||||
sta (ptr2),y
|
||||
iny
|
||||
bne @L2
|
||||
inc ptr2+1
|
||||
@L2:
|
||||
inx
|
||||
beq @L4
|
||||
|
||||
; Bump count and repeat
|
||||
|
||||
@L3:
|
||||
inc ptr3
|
||||
bne @L1
|
||||
inc ptr3+1
|
||||
bne @L1
|
||||
rts
|
||||
|
||||
; Bump page register
|
||||
|
||||
@L4:
|
||||
inc tmp1 ; Bump low page register
|
||||
@L5:
|
||||
stx tmp2
|
||||
ldx tmp1
|
||||
sta IP_CTRL_BASE,x
|
||||
ldx tmp2
|
||||
jmp @L3
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; 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:
|
||||
jsr setup
|
||||
|
||||
; Setup is:
|
||||
;
|
||||
; - ptr1 contains the struct pointer
|
||||
; - ptr2 contains the linear memory buffer
|
||||
; - ptr3 contains -(count-1)
|
||||
; - tmp1 contains the low page register value
|
||||
; - X contains the page offset
|
||||
; - Y contains zero
|
||||
|
||||
jmp @L5
|
||||
|
||||
@L1:
|
||||
lda (ptr2),y
|
||||
sta IP_WINDOW,x
|
||||
iny
|
||||
bne @L2
|
||||
inc ptr2+1
|
||||
@L2:
|
||||
inx
|
||||
beq @L4
|
||||
|
||||
; Bump count and repeat
|
||||
|
||||
@L3:
|
||||
inc ptr3
|
||||
bne @L1
|
||||
inc ptr3+1
|
||||
bne @L1
|
||||
rts
|
||||
|
||||
; Bump page register
|
||||
|
||||
@L4:
|
||||
inc tmp1 ; Bump page register
|
||||
@L5:
|
||||
stx tmp2
|
||||
ldx tmp1
|
||||
sta IP_CTRL_BASE,x
|
||||
ldx tmp2
|
||||
jmp @L3
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Helper function for COPYFROM and COPYTO: Store the pointer to the request
|
||||
; structure and prepare data for the copy
|
||||
|
||||
setup:
|
||||
sta ptr1
|
||||
stx ptr1+1 ; Save passed pointer
|
||||
|
||||
; Get the page number from the struct and remember it.
|
||||
|
||||
ldy #EM_COPY::PAGE
|
||||
lda (ptr1),y
|
||||
sta tmp1
|
||||
|
||||
; Get the buffer pointer into ptr2
|
||||
|
||||
ldy #EM_COPY::BUF
|
||||
lda (ptr1),y
|
||||
sta ptr2
|
||||
iny
|
||||
lda (ptr1),y
|
||||
sta ptr2+1
|
||||
|
||||
; Get the count, calculate -(count-1) and store it into ptr3
|
||||
|
||||
ldy #EM_COPY::COUNT
|
||||
lda (ptr1),y
|
||||
eor #$FF
|
||||
sta ptr3
|
||||
iny
|
||||
lda (ptr1),y
|
||||
eor #$FF
|
||||
sta ptr3+1
|
||||
|
||||
; Get the page offset into X and clear Y
|
||||
|
||||
ldy #EM_COPY::OFFS
|
||||
lda (ptr1),y
|
||||
tax
|
||||
ldy #0
|
||||
|
||||
; Done
|
||||
|
||||
rts
|
||||
266
libsrc/c64/emd/c64-ram.s
Normal file
266
libsrc/c64/emd/c64-ram.s
Normal file
@@ -0,0 +1,266 @@
|
||||
;
|
||||
; Extended memory driver for the C64 hidden RAM. Driver works without
|
||||
; problems when statically linked.
|
||||
;
|
||||
; Ullrich von Bassewitz, 2002-12-02
|
||||
;
|
||||
|
||||
.include "zeropage.inc"
|
||||
|
||||
.include "em-kernel.inc"
|
||||
.include "em-error.inc"
|
||||
|
||||
|
||||
.macpack generic
|
||||
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Header. Includes jump table
|
||||
|
||||
.segment "JUMPTABLE"
|
||||
|
||||
; Driver signature
|
||||
|
||||
.byte $65, $6d, $64 ; "emd"
|
||||
.byte EMD_API_VERSION ; EM API version number
|
||||
|
||||
; Jump table.
|
||||
|
||||
.word INSTALL
|
||||
.word UNINSTALL
|
||||
.word PAGECOUNT
|
||||
.word MAP
|
||||
.word USE
|
||||
.word COMMIT
|
||||
.word COPYFROM
|
||||
.word COPYTO
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Constants
|
||||
|
||||
BASE = $D000
|
||||
PAGES = ($10000 - BASE) / 256
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Data.
|
||||
|
||||
.bss
|
||||
curpage: .res 1 ; Current page number
|
||||
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:
|
||||
ldx #$FF
|
||||
stx curpage ; Invalidate the current page
|
||||
inx ; X = 0
|
||||
txa ; A = X = EM_ERR_OK
|
||||
; 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 #<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: sta curpage ; Remember the new page
|
||||
|
||||
clc
|
||||
adc #>BASE
|
||||
sta ptr1+1
|
||||
ldy #$00
|
||||
sty ptr1
|
||||
|
||||
lda #<window
|
||||
sta ptr2
|
||||
lda #>window
|
||||
sta ptr2+1
|
||||
|
||||
; Transfer one page
|
||||
|
||||
jsr transfer ; Transfer one page
|
||||
|
||||
; 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
|
||||
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
|
||||
bmi done ; Jump if no page mapped
|
||||
|
||||
clc
|
||||
adc #>BASE
|
||||
sta ptr2+1
|
||||
ldy #$00
|
||||
sty ptr2
|
||||
|
||||
lda #<window
|
||||
sta ptr1
|
||||
lda #>window
|
||||
sta ptr1+1
|
||||
|
||||
; Transfer one page. Y must be zero on entry
|
||||
|
||||
transfer:
|
||||
ldx $01 ; Remember c64 control port
|
||||
txa
|
||||
and #$F8 ; Bank out ROMs, I/O
|
||||
sei
|
||||
sta $01
|
||||
|
||||
; Unroll the following loop
|
||||
|
||||
loop: .repeat 8
|
||||
lda (ptr1),y
|
||||
sta (ptr2),y
|
||||
iny
|
||||
.endrepeat
|
||||
|
||||
bne loop
|
||||
|
||||
; Restore the old memory configuration, allow interrupts
|
||||
|
||||
stx $01 ; Restore the old configuration
|
||||
cli
|
||||
|
||||
; Done
|
||||
|
||||
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
|
||||
|
||||
ldy #EM_COPY::OFFS
|
||||
lda (ptr3),y
|
||||
sta ptr1
|
||||
ldy #EM_COPY::PAGE
|
||||
lda (ptr3),y
|
||||
clc
|
||||
adc #>BASE
|
||||
sta ptr1+1 ; From
|
||||
|
||||
ldy #EM_COPY::BUF
|
||||
lda (ptr3),y
|
||||
sta ptr2
|
||||
iny
|
||||
lda (ptr3),y
|
||||
sta ptr2+1 ; To
|
||||
|
||||
common: ldy #EM_COPY::COUNT+1
|
||||
lda (ptr3),y ; Get number of pages
|
||||
beq @L2 ; Skip if no full pages
|
||||
sta tmp1
|
||||
|
||||
; Copy full pages allowing interrupts after each page copied
|
||||
|
||||
ldy #$00
|
||||
@L1: jsr transfer
|
||||
inc ptr1+1
|
||||
inc ptr2+1
|
||||
dec tmp1
|
||||
bne @L1
|
||||
|
||||
; Copy the remainder of the page
|
||||
|
||||
@L2: ldy #EM_COPY::COUNT
|
||||
lda (ptr3),y ; Get bytes in last page
|
||||
beq @L4
|
||||
tax
|
||||
|
||||
lda $01 ; Remember c64 control port
|
||||
pha
|
||||
and #$F8 ; Bank out ROMs, I/O
|
||||
sei
|
||||
sta $01
|
||||
|
||||
; Transfer the bytes in the last page
|
||||
|
||||
ldy #$00
|
||||
@L3: lda (ptr1),y
|
||||
sta (ptr2),y
|
||||
iny
|
||||
dex
|
||||
bne @L3
|
||||
|
||||
; Restore the old memory configuration, allow interrupts
|
||||
|
||||
pla
|
||||
sta $01 ; Restore the old configuration
|
||||
cli
|
||||
|
||||
; Done
|
||||
|
||||
@L4: 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
|
||||
|
||||
ldy #EM_COPY::OFFS
|
||||
lda (ptr3),y
|
||||
sta ptr2
|
||||
ldy #EM_COPY::PAGE
|
||||
lda (ptr3),y
|
||||
clc
|
||||
adc #>BASE
|
||||
sta ptr2+1 ; To
|
||||
|
||||
ldy #EM_COPY::BUF
|
||||
lda (ptr3),y
|
||||
sta ptr1
|
||||
iny
|
||||
lda (ptr3),y
|
||||
sta ptr1+1 ; From
|
||||
|
||||
jmp common
|
||||
|
||||
|
||||
292
libsrc/c64/emd/c64-ramcart.s
Normal file
292
libsrc/c64/emd/c64-ramcart.s
Normal file
@@ -0,0 +1,292 @@
|
||||
;
|
||||
; Extended memory driver for the RamCart 64/128KB cartridge. Driver works
|
||||
; without problems when statically linked.
|
||||
; Code is based on GEORAM code by Ullrich von Bassewitz.
|
||||
; Maciej 'YTM/Elysium' Witkowiak <ytm@elysium.pl>
|
||||
; 06,22.12.2002
|
||||
;
|
||||
|
||||
|
||||
.include "zeropage.inc"
|
||||
|
||||
.include "em-kernel.inc"
|
||||
.include "em-error.inc"
|
||||
|
||||
|
||||
.macpack generic
|
||||
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Header. Includes jump table
|
||||
|
||||
.segment "JUMPTABLE"
|
||||
|
||||
; Driver signature
|
||||
|
||||
.byte $65, $6d, $64 ; "emd"
|
||||
.byte EMD_API_VERSION ; EM API version number
|
||||
|
||||
; Jump table.
|
||||
|
||||
.word INSTALL
|
||||
.word UNINSTALL
|
||||
.word PAGECOUNT
|
||||
.word MAP
|
||||
.word USE
|
||||
.word COMMIT
|
||||
.word COPYFROM
|
||||
.word COPYTO
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Constants
|
||||
|
||||
RAMC_WINDOW = $DF00 ; Address of RamCart window
|
||||
RAMC_PAGE_LO = $DE00 ; Page register low
|
||||
RAMC_PAGE_HI = $DE01 ; Page register high (only for RC128)
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Data.
|
||||
|
||||
.bss
|
||||
|
||||
pagecount: .res 2 ; Number of available pages
|
||||
|
||||
.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:
|
||||
ldx RAMC_WINDOW
|
||||
cpx RAMC_WINDOW
|
||||
bne @notpresent
|
||||
|
||||
lda #0
|
||||
sta RAMC_PAGE_LO
|
||||
sta RAMC_PAGE_HI
|
||||
ldx RAMC_WINDOW
|
||||
cpx RAMC_WINDOW
|
||||
bne @notpresent
|
||||
lda #2
|
||||
sta RAMC_WINDOW
|
||||
cmp RAMC_WINDOW
|
||||
beq @cont
|
||||
cpx RAMC_WINDOW
|
||||
beq @readonly
|
||||
@cont: ldy #1
|
||||
sty RAMC_PAGE_HI
|
||||
sty RAMC_WINDOW
|
||||
dey
|
||||
sty RAMC_PAGE_HI
|
||||
iny
|
||||
cpy RAMC_WINDOW
|
||||
beq @rc64
|
||||
; we're on rc128
|
||||
ldx #>512
|
||||
bne @setsize
|
||||
@rc64: ldx #>256
|
||||
@setsize:
|
||||
lda #0
|
||||
sta pagecount
|
||||
stx pagecount+1
|
||||
lda #<EM_ERR_OK
|
||||
ldx #>EM_ERR_OK
|
||||
rts
|
||||
@notpresent:
|
||||
@readonly:
|
||||
lda #<EM_ERR_NO_DEVICE
|
||||
ldx #>EM_ERR_NO_DEVICE
|
||||
; 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 pagecount
|
||||
ldx pagecount+1
|
||||
rts
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; USE: Tell the driver that the window is now associated with a given page.
|
||||
; The RamCart cartridge does not copy but actually map the window, so USE is
|
||||
; identical to MAP.
|
||||
|
||||
USE = MAP
|
||||
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; 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 RAMC_PAGE_LO
|
||||
stx RAMC_PAGE_HI
|
||||
lda #<RAMC_WINDOW
|
||||
ldx #>RAMC_WINDOW
|
||||
|
||||
; Use the RTS from COMMIT below to save a precious byte of storage
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; COMMIT: Commit changes in the memory window to extended storage.
|
||||
|
||||
COMMIT: 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:
|
||||
jsr setup
|
||||
|
||||
; Setup is:
|
||||
;
|
||||
; - ptr1 contains the struct pointer
|
||||
; - ptr2 contains the linear memory buffer
|
||||
; - ptr3 contains -(count-1)
|
||||
; - tmp1 contains the low page register value
|
||||
; - tmp2 contains the high page register value
|
||||
; - X contains the page offset
|
||||
; - Y contains zero
|
||||
|
||||
jmp @L5
|
||||
|
||||
@L1: lda RAMC_WINDOW,x
|
||||
sta (ptr2),y
|
||||
iny
|
||||
bne @L2
|
||||
inc ptr2+1
|
||||
@L2: inx
|
||||
beq @L4
|
||||
|
||||
; Bump count and repeat
|
||||
|
||||
@L3: inc ptr3
|
||||
bne @L1
|
||||
inc ptr3+1
|
||||
bne @L1
|
||||
rts
|
||||
|
||||
; Bump page register
|
||||
|
||||
@L4: inc tmp1
|
||||
bne @L5
|
||||
inc tmp2
|
||||
@L5: lda tmp1
|
||||
sta RAMC_PAGE_LO
|
||||
lda tmp2
|
||||
sta RAMC_PAGE_HI
|
||||
jmp @L3
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; 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:
|
||||
jsr setup
|
||||
|
||||
; Setup is:
|
||||
;
|
||||
; - ptr1 contains the struct pointer
|
||||
; - ptr2 contains the linear memory buffer
|
||||
; - ptr3 contains -(count-1)
|
||||
; - tmp1 contains the low page register value
|
||||
; - tmp2 contains the high page register value
|
||||
; - X contains the page offset
|
||||
; - Y contains zero
|
||||
|
||||
jmp @L5
|
||||
|
||||
@L1: lda (ptr2),y
|
||||
sta RAMC_WINDOW,x
|
||||
iny
|
||||
bne @L2
|
||||
inc ptr2+1
|
||||
@L2: inx
|
||||
beq @L4
|
||||
|
||||
; Bump count and repeat
|
||||
|
||||
@L3: inc ptr3
|
||||
bne @L1
|
||||
inc ptr3+1
|
||||
bne @L1
|
||||
rts
|
||||
|
||||
; Bump page register
|
||||
|
||||
@L4: inc tmp1
|
||||
bne @L5
|
||||
inc tmp2
|
||||
@L5: lda tmp1
|
||||
sta RAMC_PAGE_LO
|
||||
lda tmp2
|
||||
sta RAMC_PAGE_HI
|
||||
jmp @L3
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Helper function for COPYFROM and COPYTO: Store the pointer to the request
|
||||
; structure and prepare data for the copy
|
||||
|
||||
setup: sta ptr1
|
||||
stx ptr1+1 ; Save passed pointer
|
||||
|
||||
; Get the page number from the struct and adjust it so that it may be used
|
||||
; with the hardware. That is: lower 6 bits in tmp1, high bits in tmp2.
|
||||
|
||||
ldy #EM_COPY::PAGE+1
|
||||
lda (ptr1),y
|
||||
sta tmp2
|
||||
dey
|
||||
lda (ptr1),y
|
||||
sta tmp1
|
||||
|
||||
; Get the buffer pointer into ptr2
|
||||
|
||||
ldy #EM_COPY::BUF
|
||||
lda (ptr1),y
|
||||
sta ptr2
|
||||
iny
|
||||
lda (ptr1),y
|
||||
sta ptr2+1
|
||||
|
||||
; Get the count, calculate -(count-1) and store it into ptr3
|
||||
|
||||
ldy #EM_COPY::COUNT
|
||||
lda (ptr1),y
|
||||
eor #$FF
|
||||
sta ptr3
|
||||
iny
|
||||
lda (ptr1),y
|
||||
eor #$FF
|
||||
sta ptr3+1
|
||||
|
||||
; Get the page offset into X and clear Y
|
||||
|
||||
ldy #EM_COPY::OFFS
|
||||
lda (ptr1),y
|
||||
tax
|
||||
ldy #$00
|
||||
|
||||
; Done
|
||||
|
||||
rts
|
||||
|
||||
236
libsrc/c64/emd/c64-reu.s
Normal file
236
libsrc/c64/emd/c64-reu.s
Normal file
@@ -0,0 +1,236 @@
|
||||
;
|
||||
; Extended memory driver for the Commodore REU. Driver works without
|
||||
; problems when statically linked.
|
||||
;
|
||||
; Ullrich von Bassewitz, 2002-11-29
|
||||
;
|
||||
|
||||
.include "zeropage.inc"
|
||||
|
||||
.include "em-kernel.inc"
|
||||
.include "em-error.inc"
|
||||
|
||||
|
||||
.macpack generic
|
||||
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Header. Includes jump table
|
||||
|
||||
.segment "JUMPTABLE"
|
||||
|
||||
; Driver signature
|
||||
|
||||
.byte $65, $6d, $64 ; "emd"
|
||||
.byte EMD_API_VERSION ; EM API version number
|
||||
|
||||
; Jump table.
|
||||
|
||||
.word INSTALL
|
||||
.word UNINSTALL
|
||||
.word PAGECOUNT
|
||||
.word MAP
|
||||
.word USE
|
||||
.word COMMIT
|
||||
.word COPYFROM
|
||||
.word COPYTO
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Constants
|
||||
|
||||
REU_STATUS = $DF00 ; Status register
|
||||
REU_COMMAND = $DF01 ; Command register
|
||||
REU_C64ADDR = $DF02 ; C64 base address register
|
||||
REU_REUADDR = $DF04 ; REU base address register
|
||||
REU_COUNT = $DF07 ; Transfer count register
|
||||
REU_IRQMASK = $DF09 ; IRQ mask register
|
||||
REU_CONTROL = $DF0A ; Control register
|
||||
REU_TRIGGER = $FF00 ; REU command trigger
|
||||
|
||||
OP_COPYFROM = $ED
|
||||
OP_COPYTO = $EC
|
||||
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Data.
|
||||
|
||||
.bss
|
||||
pagecount: .res 2 ; Number of pages available
|
||||
curpage: .res 2 ; Current page number
|
||||
|
||||
window: .res 256 ; Memory "window"
|
||||
|
||||
reu_params: .word $0000 ; Host address, lo, hi
|
||||
.word $0000 ; Exp address, lo, hi
|
||||
.byte $00 ; Expansion bank no.
|
||||
.word $0000 ; # bytes to move, lo, hi
|
||||
.byte $00 ; Interrupt mask reg.
|
||||
.byte $00 ; Adress control reg.
|
||||
|
||||
.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:
|
||||
ldx #$00 ; High byte of return code
|
||||
lda #$55
|
||||
sta REU_REUADDR
|
||||
cmp REU_REUADDR ; Check for presence of REU
|
||||
bne nodevice
|
||||
asl a ; A = $AA
|
||||
sta REU_REUADDR
|
||||
cmp REU_REUADDR ; Check for presence of REU
|
||||
bne nodevice
|
||||
|
||||
ldy #>(128*4) ; Assume 128KB
|
||||
lda REU_STATUS
|
||||
and #$10 ; Check size bit
|
||||
beq @L1
|
||||
ldy #>(256*4) ; 256KB when size bit is set
|
||||
@L1: sty pagecount+1
|
||||
|
||||
ldy #$FF
|
||||
sty curpage
|
||||
sty curpage+1 ; Invalidate the current page
|
||||
txa ; X = A = EM_ERR_OK
|
||||
rts
|
||||
|
||||
; No REU found
|
||||
|
||||
nodevice:
|
||||
lda #EM_ERR_NO_DEVICE
|
||||
; 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 pagecount
|
||||
ldx pagecount+1
|
||||
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
|
||||
stx curpage+1 ; Remember the new page
|
||||
|
||||
ldy #OP_COPYFROM
|
||||
jsr common ; Copy the window
|
||||
|
||||
lda #<window
|
||||
ldx #>window ; Return the window address
|
||||
done: rts
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; USE: Tell the driver that the window is now associated with a given page.
|
||||
|
||||
USE: sta curpage
|
||||
stx curpage+1 ; Remember the page
|
||||
lda #<window
|
||||
ldx #>window ; Return the window
|
||||
rts
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; COMMIT: Commit changes in the memory window to extended storage.
|
||||
|
||||
COMMIT: lda curpage
|
||||
ldx curpage+1 ; Do we have a page mapped?
|
||||
bmi done ; Jump if no page mapped
|
||||
|
||||
ldy #OP_COPYTO
|
||||
common: sty tmp1
|
||||
|
||||
ldy #<window
|
||||
sty REU_C64ADDR
|
||||
ldy #>window
|
||||
sty REU_C64ADDR+1
|
||||
|
||||
ldy #0
|
||||
sty REU_REUADDR+0
|
||||
sta REU_REUADDR+1
|
||||
stx REU_REUADDR+2
|
||||
|
||||
sty REU_COUNT+0
|
||||
ldy #1
|
||||
sty REU_COUNT+1 ; Move 256 bytes
|
||||
bne transfer1 ; Transfer 256 bytes into REU
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; 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:
|
||||
ldy #OP_COPYFROM
|
||||
.byte $2C
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; 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:
|
||||
ldy #OP_COPYTO
|
||||
sty tmp1
|
||||
|
||||
; Remember the passed pointer
|
||||
|
||||
sta ptr1
|
||||
stx ptr1+1 ; Save the pointer
|
||||
|
||||
; The structure passed to the functions has the same layout as the registers
|
||||
; of the Commodore REU, so register programming is easy.
|
||||
|
||||
ldy #7-1
|
||||
@L1: lda (ptr1),y
|
||||
sta REU_C64ADDR,y
|
||||
dey
|
||||
bpl @L1
|
||||
|
||||
; Invalidate the page in the memory window
|
||||
|
||||
sty curpage+1 ; Y = $FF
|
||||
|
||||
; Reload the REU command and start the transfer
|
||||
|
||||
transfer1:
|
||||
ldy tmp1
|
||||
|
||||
; Transfer subroutine for the REU. Expects command in Y.
|
||||
|
||||
transfer:
|
||||
sty REU_COMMAND ; Issue command
|
||||
|
||||
ldy $01 ; Save the value of the c64 control port...
|
||||
tya ;
|
||||
and #$F8 ; Disable ROMs and I/O.
|
||||
sei ;
|
||||
sta $01
|
||||
lda REU_TRIGGER ; Don't change $FF00
|
||||
sta REU_TRIGGER ; Start the transfer...
|
||||
|
||||
sty $01 ; Restore the old configuration
|
||||
cli
|
||||
rts
|
||||
|
||||
399
libsrc/c64/emd/c64-vdc.s
Normal file
399
libsrc/c64/emd/c64-vdc.s
Normal file
@@ -0,0 +1,399 @@
|
||||
;
|
||||
; Extended memory driver for the VDC RAM available on all C128 machines
|
||||
; (based on code by Ullrich von Bassewitz)
|
||||
; Maciej 'YTM/Elysium' Witkowiak <ytm@elysium.pl>
|
||||
; 06,20.12.2002
|
||||
;
|
||||
; VDC test added by
|
||||
; Marco van den Heuvel, 2010-01-22
|
||||
;
|
||||
|
||||
.include "zeropage.inc"
|
||||
|
||||
.include "em-kernel.inc"
|
||||
.include "em-error.inc"
|
||||
|
||||
|
||||
.macpack generic
|
||||
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Header. Includes jump table
|
||||
|
||||
.segment "JUMPTABLE"
|
||||
|
||||
; Driver signature
|
||||
|
||||
.byte $65, $6d, $64 ; "emd"
|
||||
.byte EMD_API_VERSION ; EM API version number
|
||||
|
||||
; Jump table.
|
||||
|
||||
.word INSTALL
|
||||
.word UNINSTALL
|
||||
.word PAGECOUNT
|
||||
.word MAP
|
||||
.word USE
|
||||
.word COMMIT
|
||||
.word COPYFROM
|
||||
.word COPYTO
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Constants
|
||||
|
||||
VDC_ADDR_REG = $D600 ; VDC address
|
||||
VDC_DATA_REG = $D601 ; VDC data
|
||||
|
||||
VDC_DATA_HI = 18 ; used registers
|
||||
VDC_DATA_LO = 19
|
||||
VDC_CSET = 28
|
||||
VDC_DATA = 31
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Data.
|
||||
|
||||
.data
|
||||
|
||||
pagecount: .word 64 ; $0000-$3fff as 16k default
|
||||
curpage: .word $ffff ; currently mapped-in page (invalid)
|
||||
|
||||
.bss
|
||||
|
||||
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:
|
||||
ldx #0
|
||||
ldy #0
|
||||
lda #VDC_CSET ; determine size of RAM...
|
||||
sta VDC_ADDR_REG
|
||||
|
||||
@L0: bit VDC_ADDR_REG
|
||||
bmi @present
|
||||
inx
|
||||
bne @L0
|
||||
iny
|
||||
bne @L0
|
||||
lda #<EM_ERR_NO_DEVICE
|
||||
ldx #>EM_ERR_NO_DEVICE
|
||||
rts
|
||||
|
||||
@present:
|
||||
ldx #VDC_CSET ; determine size of RAM...
|
||||
jsr vdcgetreg
|
||||
sta tmp1
|
||||
ora #%00010000
|
||||
jsr vdcputreg ; turn on 64k
|
||||
|
||||
jsr settestadr1 ; save original value of test byte
|
||||
jsr vdcgetbyte
|
||||
sta tmp2
|
||||
|
||||
lda #$55 ; write $55 here
|
||||
ldy #ptr1
|
||||
jsr test64k ; read it here and there
|
||||
lda #$aa ; write $aa here
|
||||
ldy #ptr2
|
||||
jsr test64k ; read it here and there
|
||||
|
||||
jsr settestadr1
|
||||
lda tmp2
|
||||
jsr vdcputbyte ; restore original value of test byte
|
||||
|
||||
lda ptr1 ; do bytes match?
|
||||
cmp ptr1+1
|
||||
bne @have64k
|
||||
lda ptr2
|
||||
cmp ptr2+1
|
||||
bne @have64k
|
||||
|
||||
ldx #VDC_CSET
|
||||
lda tmp1
|
||||
jsr vdcputreg ; restore 16/64k flag
|
||||
jmp @endok ; and leave default values for 16k
|
||||
|
||||
@have64k:
|
||||
lda #<256
|
||||
ldx #>256
|
||||
sta pagecount
|
||||
stx pagecount+1
|
||||
@endok:
|
||||
lda #<EM_ERR_OK
|
||||
ldx #>EM_ERR_OK
|
||||
rts
|
||||
|
||||
test64k:
|
||||
sta tmp1
|
||||
sty ptr3
|
||||
lda #0
|
||||
sta ptr3+1
|
||||
jsr settestadr1
|
||||
lda tmp1
|
||||
jsr vdcputbyte ; write $55
|
||||
jsr settestadr1
|
||||
jsr vdcgetbyte ; read here
|
||||
pha
|
||||
jsr settestadr2
|
||||
jsr vdcgetbyte ; and there
|
||||
ldy #1
|
||||
sta (ptr3),y
|
||||
pla
|
||||
dey
|
||||
sta (ptr3),y
|
||||
rts
|
||||
|
||||
settestadr1:
|
||||
ldy #$02 ; test page 2 (here)
|
||||
.byte $2c
|
||||
settestadr2:
|
||||
ldy #$42 ; or page 64+2 (there)
|
||||
lda #0
|
||||
jmp vdcsetsrcaddr
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; UNINSTALL routine. Is called before the driver is removed from memory.
|
||||
; Can do cleanup or whatever. Must not return anything.
|
||||
;
|
||||
|
||||
UNINSTALL:
|
||||
;on C128 restore font and clear the screen?
|
||||
rts
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; PAGECOUNT: Return the total number of available pages in a/x.
|
||||
;
|
||||
|
||||
PAGECOUNT:
|
||||
lda pagecount
|
||||
ldx pagecount+1
|
||||
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
|
||||
stx curpage+1
|
||||
sta ptr1+1
|
||||
ldy #0
|
||||
sty ptr1
|
||||
|
||||
lda #<window
|
||||
sta ptr2
|
||||
lda #>window
|
||||
sta ptr2+1
|
||||
|
||||
jsr transferin
|
||||
|
||||
lda #<window
|
||||
ldx #>window
|
||||
rts
|
||||
|
||||
; copy a single page from (ptr1):VDCRAM to (ptr2):RAM
|
||||
|
||||
transferin:
|
||||
lda ptr1
|
||||
ldy ptr1+1
|
||||
jsr vdcsetsrcaddr ; set source address in VDC
|
||||
ldy #0
|
||||
ldx #VDC_DATA
|
||||
stx VDC_ADDR_REG
|
||||
@L0: bit VDC_ADDR_REG
|
||||
bpl @L0
|
||||
lda VDC_DATA_REG ; get 2 bytes at a time to speed-up
|
||||
sta (ptr2),y ; (in fact up to 8 bytes could be fetched with special VDC config)
|
||||
iny
|
||||
lda VDC_DATA_REG
|
||||
sta (ptr2),y
|
||||
iny
|
||||
bne @L0
|
||||
rts
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; USE: Tell the driver that the window is now associated with a given page.
|
||||
|
||||
USE: sta curpage
|
||||
stx curpage+1 ; Remember the page
|
||||
lda #<window
|
||||
ldx #>window ; Return the window
|
||||
done: rts
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; COMMIT: Commit changes in the memory window to extended storage.
|
||||
|
||||
COMMIT:
|
||||
lda curpage ; jump if no page mapped
|
||||
ldx curpage+1
|
||||
bmi done
|
||||
sta ptr1+1
|
||||
ldy #0
|
||||
sty ptr1
|
||||
|
||||
lda #<window
|
||||
sta ptr2
|
||||
lda #>window
|
||||
sta ptr2+1
|
||||
|
||||
; fall through to transferout
|
||||
|
||||
; copy a single page from (ptr2):RAM to (ptr1):VDCRAM
|
||||
|
||||
transferout:
|
||||
lda ptr1
|
||||
ldy ptr1+1
|
||||
jsr vdcsetsrcaddr ; set source address in VDC
|
||||
ldy #0
|
||||
ldx #VDC_DATA
|
||||
stx VDC_ADDR_REG
|
||||
@L0: bit VDC_ADDR_REG
|
||||
bpl @L0
|
||||
lda (ptr2),y ; speedup does not work for writing
|
||||
sta VDC_DATA_REG
|
||||
iny
|
||||
bne @L0
|
||||
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:
|
||||
jsr setup
|
||||
beq @L2 ; Skip if no full pages
|
||||
|
||||
; Copy full pages
|
||||
|
||||
@L1: jsr transferin
|
||||
inc ptr1+1
|
||||
inc ptr2+1
|
||||
dec tmp1
|
||||
bne @L1
|
||||
|
||||
; Copy the remainder of the page
|
||||
|
||||
@L2: ldy #EM_COPY::COUNT
|
||||
lda (ptr3),y ; Get bytes in last page
|
||||
beq @L4
|
||||
sta tmp1
|
||||
|
||||
; Transfer the bytes in the last page
|
||||
|
||||
ldy #0
|
||||
@L3: jsr vdcgetbyte
|
||||
sta (ptr2),y
|
||||
iny
|
||||
dec tmp1
|
||||
lda tmp1
|
||||
bne @L3
|
||||
@L4: 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:
|
||||
jsr setup
|
||||
beq @L2 ; Skip if no full pages
|
||||
|
||||
; Copy full pages
|
||||
|
||||
@L1: jsr transferout
|
||||
inc ptr1+1
|
||||
inc ptr2+1
|
||||
dec tmp1
|
||||
bne @L1
|
||||
|
||||
; Copy the remainder of the page
|
||||
|
||||
@L2: ldy #EM_COPY::COUNT
|
||||
lda (ptr3),y ; Get bytes in last page
|
||||
beq @L4
|
||||
sta tmp1
|
||||
|
||||
; Transfer the bytes in the last page
|
||||
|
||||
ldy #0
|
||||
@L3: lda (ptr2),y
|
||||
jsr vdcputbyte
|
||||
iny
|
||||
dec tmp1
|
||||
lda tmp1
|
||||
bne @L3
|
||||
@L4: rts
|
||||
|
||||
;-------------------------------------------------------------------------
|
||||
; Helper functions to handle VDC ram
|
||||
;
|
||||
|
||||
vdcsetsrcaddr:
|
||||
ldx #VDC_DATA_LO
|
||||
stx VDC_ADDR_REG
|
||||
@L0: bit VDC_ADDR_REG
|
||||
bpl @L0
|
||||
sta VDC_DATA_REG
|
||||
dex
|
||||
tya
|
||||
stx VDC_ADDR_REG
|
||||
sta VDC_DATA_REG
|
||||
rts
|
||||
|
||||
vdcgetbyte:
|
||||
ldx #VDC_DATA
|
||||
vdcgetreg:
|
||||
stx VDC_ADDR_REG
|
||||
@L0: bit VDC_ADDR_REG
|
||||
bpl @L0
|
||||
lda VDC_DATA_REG
|
||||
rts
|
||||
|
||||
vdcputbyte:
|
||||
ldx #VDC_DATA
|
||||
vdcputreg:
|
||||
stx VDC_ADDR_REG
|
||||
@L0: bit VDC_ADDR_REG
|
||||
bpl @L0
|
||||
sta VDC_DATA_REG
|
||||
rts
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Helper function for COPYFROM and COPYTO: Store the pointer to the request
|
||||
; structure and prepare data for the copy
|
||||
;
|
||||
|
||||
setup:
|
||||
sta ptr3
|
||||
stx ptr3+1 ; Save the passed em_copy pointer
|
||||
|
||||
ldy #EM_COPY::OFFS
|
||||
lda (ptr3),y
|
||||
sta ptr1
|
||||
ldy #EM_COPY::PAGE
|
||||
lda (ptr3),y
|
||||
sta ptr1+1 ; From
|
||||
|
||||
ldy #EM_COPY::BUF
|
||||
lda (ptr3),y
|
||||
sta ptr2
|
||||
iny
|
||||
lda (ptr3),y
|
||||
sta ptr2+1 ; To
|
||||
|
||||
ldy #EM_COPY::COUNT+1
|
||||
lda (ptr3),y ; Get number of pages
|
||||
sta tmp1
|
||||
rts
|
||||
|
||||
245
libsrc/c64/emd/dtv-himem.s
Normal file
245
libsrc/c64/emd/dtv-himem.s
Normal file
@@ -0,0 +1,245 @@
|
||||
;
|
||||
; Extended memory driver for the C64 D2TV (the second or PAL version).
|
||||
; Driver works without problems when statically linked.
|
||||
;
|
||||
; Ullrich von Bassewitz, 2005-11-27
|
||||
;
|
||||
|
||||
|
||||
.include "zeropage.inc"
|
||||
|
||||
.include "em-kernel.inc"
|
||||
.include "em-error.inc"
|
||||
.import _get_ostype
|
||||
|
||||
|
||||
.macpack generic
|
||||
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Header. Includes jump table
|
||||
|
||||
.segment "JUMPTABLE"
|
||||
|
||||
; Driver signature
|
||||
|
||||
.byte $65, $6d, $64 ; "emd"
|
||||
.byte EMD_API_VERSION ; EM API version number
|
||||
|
||||
; Jump table.
|
||||
|
||||
.word INSTALL
|
||||
.word UNINSTALL
|
||||
.word PAGECOUNT
|
||||
.word MAP
|
||||
.word USE
|
||||
.word COMMIT
|
||||
.word COPYFROM
|
||||
.word COPYTO
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Constants
|
||||
|
||||
OP_COPYFROM = %00001101
|
||||
OP_COPYTO = %00001111
|
||||
|
||||
START_BANK = 2 ; Start at $20000
|
||||
PAGES = (2048 - 128) * 4
|
||||
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; Data.
|
||||
|
||||
.bss
|
||||
window: .res 256 ; Memory "window"
|
||||
|
||||
.data
|
||||
|
||||
; The MAP and COMMIT entries will actually call COPYFROM/COPYTO with
|
||||
; a pointer to the following data structure:
|
||||
|
||||
dma_params: .word window ; Host address
|
||||
.byte 0 ; Offset in page
|
||||
curpage: .word $0000 ; Page
|
||||
.word .sizeof (window); # bytes to move, lo, hi
|
||||
|
||||
.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:
|
||||
|
||||
; Check for a DTV
|
||||
|
||||
ldx #1
|
||||
stx $d03f
|
||||
ldx $d040
|
||||
cpx $d000
|
||||
bne @present
|
||||
inc $d000
|
||||
cpx $d040
|
||||
beq @present
|
||||
dec $d000
|
||||
|
||||
; DTV not found
|
||||
|
||||
lda #<EM_ERR_NO_DEVICE
|
||||
ldx #>EM_ERR_NO_DEVICE
|
||||
rts
|
||||
|
||||
@present:
|
||||
ldx #$FF
|
||||
stx curpage+1 ; Invalidate curpage
|
||||
inx ; X = 0
|
||||
txa ; A/X = EM_ERR_OK
|
||||
|
||||
; 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 #<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: sta curpage
|
||||
stx curpage+1 ; Remember the new page
|
||||
|
||||
lda #<dma_params
|
||||
ldx #>dma_params
|
||||
jsr COPYFROM ; Copy data into the window
|
||||
|
||||
lda #<window
|
||||
ldx #>window ; Return the window address
|
||||
done: rts
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; USE: Tell the driver that the window is now associated with a given page.
|
||||
|
||||
USE: sta curpage
|
||||
stx curpage+1 ; Remember the page
|
||||
lda #<window
|
||||
ldx #>window ; Return the window
|
||||
rts
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; COMMIT: Commit changes in the memory window to extended storage.
|
||||
|
||||
COMMIT: lda curpage+1 ; Do we have a page mapped?
|
||||
bmi done ; Jump if no page mapped
|
||||
|
||||
lda #<dma_params
|
||||
ldx #>dma_params
|
||||
|
||||
; Run into COPYTO
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; 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 ptr1
|
||||
stx ptr1+1 ; Save the pointer
|
||||
|
||||
ldx #OP_COPYTO ; Load the command
|
||||
bne transfer
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; 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 ptr1
|
||||
stx ptr1+1 ; Save the pointer
|
||||
|
||||
ldx #OP_COPYFROM
|
||||
|
||||
; DTV DMA transfer routine. Expects the command in X.
|
||||
; NOTE: We're using knowledge about field order in the EM_COPY struct here!
|
||||
|
||||
transfer:
|
||||
jsr WAIT ; Wait until DMA is finished
|
||||
|
||||
; Modulo disable
|
||||
|
||||
ldy #$00
|
||||
sty $d31e
|
||||
|
||||
; Setup the target address and the source and target steps. Y contains zero,
|
||||
; which is EM_COPY::BUF.
|
||||
|
||||
sty $d307 ; Source step high = 0
|
||||
sty $d309 ; Dest step high = 0
|
||||
lda (ptr1),y
|
||||
sta $d303 ; Dest address low
|
||||
iny ; Y = 1
|
||||
sty $d306 ; Source step low = 1
|
||||
sty $d308 ; Dest step low = 1
|
||||
lda (ptr1),y
|
||||
sta $d304
|
||||
lda #$40 ; Dest is always RAM, start at $00000
|
||||
sta $d305
|
||||
|
||||
; Setup the source address. Incrementing Y will make it point to EM_COPY::OFFS.
|
||||
; We will allow page numbers higher than PAGES and map them to ROM. This will
|
||||
; allow reading the ROM by specifying a page starting with PAGES.
|
||||
|
||||
iny ; EM_COPY::OFFS
|
||||
lda (ptr1),y
|
||||
sta $d300
|
||||
iny ; EM_COPY::PAGE
|
||||
lda (ptr1),y
|
||||
sta $d301
|
||||
iny
|
||||
lda (ptr1),y
|
||||
adc #START_BANK ; Carry clear here from WAIT
|
||||
and #$3f
|
||||
cmp #>PAGES+START_BANK ; Valid range?
|
||||
bcs @L1 ; Jump if no
|
||||
ora #$40 ; Address RAM
|
||||
@L1: sta $d302
|
||||
|
||||
; Length
|
||||
|
||||
iny ; EM_COPY::COUNT
|
||||
lda (ptr1),y
|
||||
sta $d30a
|
||||
iny
|
||||
lda (ptr1),y
|
||||
sta $d30b
|
||||
|
||||
; Start DMA
|
||||
|
||||
stx $d31f
|
||||
|
||||
; Wait until DMA is done
|
||||
|
||||
WAIT: lda $d31f
|
||||
lsr a
|
||||
bcs WAIT
|
||||
rts
|
||||
|
||||
Reference in New Issue
Block a user