;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Commodore 64 Basic Runtime File
;;
;; Include this at the TOP of your C64 program, and it will handle
;; hiding away the BASIC ROM and data and restoring it at the end.
;;
;; You will have a contiguous block of RAM from $0800 to $CFFF, and
;; Zero Page access from $02 to $8F in the segment "zp".

.include "c64header.oph"

.data zp ; Zero Page memory segment.
.org $0002

.text

.scope
	; Cache BASIC zero page underneath the KERNAL, while also
	; making RAM copies of the NMI routines
	ldx	#$00
*	lda	$00, x
	sta	$e000, x
	lda	$fe00, x
	sta	$fe00, x
	lda	$ff00, x
	sta	$ff00, x
	inx
	bne	-

	; Swap out the BASIC ROM for RAM
	lda	$01
	and	#$fe
	ora	#$06
	sta	$01

	; Run the real program
	jsr	_main

	; Swap out KERNAL to expose cached BASIC ZP values
	; Block IRQs during this period. NMIs cannot be blocked,
	; but we copied enough of the processing code into the
	; RAM under the KERNAL that we can disable NMI processing
	; during this period
	sei				; Disable IRQs
	lda	#$c1			; Defang NMIs
	sta	$318

	lda	$01			; Swap out KERNAL
	and	#$fd
	sta	$01

	; Restore BASIC zero page
	ldx	#$8E
*	lda	$e001, x
	sta	$01, x
	dex
	bne	-

	; Restore BASIC ROM, KERNAL, and interrupts
	lda	$01
	ora	#$07
	sta	$01
	lda	#$47		; Restore NMI vector
	sta	$318
	cli			; Re-enable interrupts

	; Back to BASIC. We do this by clearing the keyboard
	; buffer and then jumping through the warm start
	; vector. This will more cleanly handle case where
	; the program has somehow modified BASIC's state,
	; such as running through PUCRUNCH or a onefiler.
	stx	$c6		; .X is zero from previous loop
	jmp	($a002)

_main:
	; Program follows...
.scend
