mirror of
https://github.com/catseye/SixtyPical.git
synced 2024-11-22 17:32:01 +00:00
180 lines
6.0 KiB
Plaintext
180 lines
6.0 KiB
Plaintext
; ribos2.p65 - p65 assembly source for RIBOS2:
|
|
; Demonstration of the VIC-II raster interrupt on the Commodore 64:
|
|
; Alter the border colour in the middle part of the screen only,
|
|
; Simplified (KERNAL IRQ vector) version.
|
|
; By Chris Pressey, Cat's Eye Technologies.
|
|
; This work has been placed in the public domain.
|
|
|
|
; ----- BEGIN ribos2.p65 -----
|
|
|
|
; This is a simplified version of ribos.p65 which uses the Commodore 64
|
|
; KERNAL's support for interrupt handling. Whereas ribos.p65 could run
|
|
; with the KERNAL completely disabled, ribos2.p65 relies on it.
|
|
|
|
; I'll assume you've read through ribos.p65 at least once, and won't
|
|
; say much about the code that's shared between the two programs.
|
|
; Again, page references are from the 'Commodore 64 Programmer's
|
|
; Reference Guide'.
|
|
|
|
.org 0
|
|
.word $C000
|
|
.org $C000
|
|
|
|
; ----- Constants -----
|
|
|
|
; The CIA #1 chip.
|
|
|
|
.alias cia1 $dc00 ; pp. 328-331
|
|
.alias intr_ctrl cia1+$d ; "CIA Interrupt Control Register
|
|
; (Read IRQs/Write Mask)"
|
|
|
|
; The VIC-II chip.
|
|
|
|
.alias vic $d000 ; Appendix G:
|
|
.alias vic_ctrl vic+$11 ; "Y SCROLL MODE"
|
|
.alias vic_raster vic+$12 ; "RASTER"
|
|
.alias vic_intr vic+$19 ; "Interrupt Request's" (sic)
|
|
.alias vic_intr_enable vic+$1a ; "Interrupt Request MASKS"
|
|
.alias border_color vic+$20 ; "BORDER COLOR"
|
|
|
|
; The address at which the IRQ vector is stored.
|
|
|
|
.alias cinv $0314 ; p. 319, "Vector: Hardware
|
|
; IRQ Interrupt"
|
|
|
|
; ----- Main Routine -----
|
|
|
|
; This routine is intended to be called by the user (by, e.g., SYS 49152).
|
|
; It installs the raster interrupt handler and returns to the caller.
|
|
|
|
; Key to installing the interrupt handler is altering the IRQ service
|
|
; vector. As I learned from a careful reading of Sheldon Leemon's
|
|
; "Mapping the Commodore 64", if we wish to leave the KERNAL intact and
|
|
; operational, it gives us an easy way to do that. Whenever it handles
|
|
; an IRQ, it has to decide whether the IRQ was generated by a BRK
|
|
; instruction, or some external device issuing an interrupt request. In
|
|
; either case, it jumps indirectly through its IRQ-handling vector. We
|
|
; can simply modify this vector (at $314) to point to our routine. In
|
|
; fact, this is the "CINV" vector, which may already be familiar to you
|
|
; if you have done any modest amount of C64 machine language programming;
|
|
; it is normally called every 1/60 of a second due to the interrupt
|
|
; request generated by CIA#1 Timer B. Here we will simply be using it
|
|
; to detect when a raster interrupt has occurred, as well.
|
|
|
|
; First, disable interrupts before changing interrupt vectors.
|
|
|
|
sei
|
|
|
|
; We obtain the address of the current IRQ service routine in CINV
|
|
; and save it in the variable 'saved_irq_vec'.
|
|
|
|
lda cinv
|
|
sta saved_irq_vec
|
|
lda cinv+1
|
|
sta saved_irq_vec+1
|
|
|
|
; We then store the address of our IRQ service routine in its place.
|
|
|
|
lda #<our_service_routine
|
|
sta cinv
|
|
lda #>our_service_routine
|
|
sta cinv+1
|
|
|
|
; Now we must specify the raster line at which the interrupt gets called,
|
|
; setting the ninth bit to zero.
|
|
|
|
lda scanline
|
|
sta vic_raster
|
|
lda vic_ctrl
|
|
and #%01111111
|
|
sta vic_ctrl
|
|
|
|
; Then we enable the raster interrupt on the VIC-II chip.
|
|
|
|
lda #$01
|
|
sta vic_intr_enable
|
|
|
|
; We read the interrupt control port of CIA #1 for good measure.
|
|
|
|
lda intr_ctrl
|
|
|
|
; And we re-enable interrupts to resume normal operation -- plus our jazz.
|
|
|
|
cli
|
|
|
|
; Finally, we return to the caller.
|
|
|
|
rts
|
|
|
|
; ----- Raster Interrupt Service Routine ------
|
|
|
|
our_service_routine:
|
|
|
|
; First, we check to see if the current interrupt was caused by the raster.
|
|
|
|
lda vic_intr
|
|
sta vic_intr
|
|
and #$01
|
|
cmp #$01
|
|
beq we_handle_it
|
|
|
|
; If the interrupt was not caused by the raster, we continue execution as
|
|
; normal, with the existing interrupt service routine.
|
|
|
|
jmp (saved_irq_vec)
|
|
|
|
we_handle_it:
|
|
|
|
; If we got here, the interrupt was caused by the raster, so we do our thing.
|
|
|
|
lda border_color
|
|
eor #$ff
|
|
sta border_color
|
|
|
|
; Now, we make the interrupt trigger on the other scan line next time.
|
|
|
|
lda scanline
|
|
eor #$ff
|
|
sta scanline
|
|
sta vic_raster
|
|
|
|
; Return to normal operation. If we simply continue with the standard
|
|
; interrupt service routine by jumping through saved_irq_req, we will
|
|
; confuse it a bit, as it expects to be called 60 times per second, and
|
|
; continuing it here would make it occur more frequently. The result
|
|
; would be the cursor blinking more frequently and the time of day clock
|
|
; running fast.
|
|
|
|
; So, we issue a plain return from interrupt (RTI) here. But first, we
|
|
; must make sure that the state of the system is back to the way it was
|
|
; when the interrupt service routine was called. Since it can be called
|
|
; from anywhere, and since the code that was interrupted likely cares
|
|
; deeply about the values in its registers, the KERNAL routine which
|
|
; dispatches through CINV first carefully saves the contents of the
|
|
; registers on the stack. We must be equally careful about restoring
|
|
; those values before switching back to that interrupted code.
|
|
|
|
pla
|
|
tay
|
|
pla
|
|
tax
|
|
pla
|
|
|
|
rti
|
|
|
|
|
|
; ----- Variables -----
|
|
|
|
; 'scanline' stores the raster line that we want the interrupt to trigger
|
|
; on; it gets loaded into the VIC-II's 'vic_raster' register.
|
|
|
|
scanline: .byte %01010101
|
|
|
|
; We also reserve space to store the address of the interrupt service
|
|
; routine that we are replacing in the IRQ vector, so that we can transfer
|
|
; control to it at the end of our routine.
|
|
|
|
.space saved_irq_vec 2
|
|
|
|
; ----- END of ribos2.p65 -----
|