Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

c64 Interrupts Eng Part03

Download as pdf or txt
Download as pdf or txt
You are on page 1of 5

RetroProgramming Italia - RP Italia presents :

Interrupts C64 tutorial – Part 3


By
Attilio Capuozzo – Founder of RetroProgramming Italia
– RP Italia Facebook Group
& Antonia Savona – C64 GameCoder & DemoCoder

The previous times we have seen that some chips of the C64 constitute
the main sources of Hardware Interrupt Requests addressed to the 6510
cpu. Specifically, the VIC (acronym for Video Interface Controller)
and the CIA 1 (Complex Interface Adapter) generate IRQ type Interrupt
Requests while the integrated CIA 2 is a source of Non Maskable
Interrupt Requests (NMI).

The RESTORE key is also another source of Interrupt: its pressure is


NOT detected by normal physical keyboard scanning but generates an NMI
Interrupt Request.

Finally, "external" sources include the Expansion (or Cartridge) Port


that can generate either an IRQ Interrupt Request (Pin 4 of the
aforementioned Port) or an NMI Interrupt (Pin D).

We have also analysed the flow of operations performed when an IRQ


Interrupt occurs.

This time, Let's study the Flowchart for an NMI Interrupt. See Figure
1, already published in Part 2 of this Tutorial, for reference, which
we'll bring back here again to make it easier for readers.
As explained in figure 1, After completing the currently executing
machine language instruction, the 6510 saves (PUSH) the process status
register as well as the program counter in the stack.

Figure 1 - Flowchart of the operations carried out following both an IRQ and an NMI
Interrupt Request

Then, the processor jumps to the address contained in the $fffa-$fffb


vector, i.e. $fe43; this address corresponds to the location of the
NMI Main Interrupt Routine.

The Routine sets the Interrupt Disable Flag of the CPU Status Register
and then reads the contents of the NMINV vector $0318-$0319. NMINV is
a RAM vector that contains the start address ($fe47) of the NMI
Handler.

First of all, the NMI Handler saves in the stack (PUSH) the 3 Data
Registers of 6510, i.e. the Accumulator, the Index X Register and the
Index Y Register.
Then the Routine tries to identify the source of the NMI Interrupt;
it checks if the Interrupt Request comes from CIA 2 by testing if the
high bit of $dd0d, the CIA 2 Interrupt Control Register (ICR), is set.

If the condition is satisfied then the control is passed to the RS-


232 software interface management Routine and then the NMI Handler
ends with the Pull from the Stack of the 3 Data Register of 6510
followed by an RTI.

For completeness we remind you that the C64 User Port implements the
RS-232 Protocol managed via software (Kernal).

If instead, the source of the Interrupt Request is NOT the CIA 2, then
the Handler checks for the presence of a possible ROM Cartridge
inserted in the Expansion Port and, if so, it will execute the Warm
Start procedure whose address is contained in the vector $8002-$8003.

If no Cartridge is present, the Handler assumes that the RESTORE key


has been pressed and therefore checks if the RUN/STOP key has been
pressed at the same time to skip, if necessary, to the BRK Routine
allocated in memory at the address $fe66, the same Routine performed
when a software BRK Interrupt occurs.

If the user has NOT pressed the RUN/STOP and RESTORE key combination,
we first pull Y, X and A Registers from the stack then exit the NMI
Handler through the usual RTI (ReTurn from Interrupt) instruction.

Let's now see a simple application of an IRQ Handler.

In order to make it easier especially for newbies, we will initially


show some examples with an Assembly syntax compatible with CBM Prg
Studio.

CBM Prg Studio is an IDE (Integrated Development Environment), i.e.


an immediate and intuitive Integrated Development Environment used
mainly for the development of programs in the various BASIC dialects
used by the 8 bit Commodore.

The next examples will be written for KickAssembler, an Assembler


widely used also and especially for the current development of Games
and Demos for the C64.

The KickAssembler, which, by the way, has a rather evolved script


language, should still be integrated in a future version of CBM Prg
Studio.
Below is the Routine for handling an IRQ Interrupt:

*=$c000 ; Our code starts at address $c000 (49152)


setup
sei ; we disable new IRQ interrupt requests
; (Set Interrupt Disable Flag)
jsr $e544 ; we clear the screen using the KERNAL routine
; mapped to $e544

; we modify the CINV vector ($0314-$0315)


; so that it points to the address of our custom IRQ handler
lda #<newIRQ ; low byte of the custom IRQ handler address
sta $0314
lda #>newIRQ ; high byte of the custom IRQ handler address
sta $0315
cli ; we enable new IRQ interrupt requests
; (CLear Interrupt Disable Flag)
rts ; we exit from our main code

newIRQ ; custom IRQ handler code


inc $0450 ; we Increase by 1 the value stored in the screen memory
; location $0450 (1104) (Initial value $20 corresponding
; to the « space » character)
jmp $ea31 ; we then jump to the standard default IRQ handler address
; and execute it (Keyboard Scan, etc.)

The comments are rather explanatory for understanding the code. We


would just like to point out that a Handler will basically consist of
a Setup - executed 1 time only - and the actual Interrupt handling
routine executed every time the Interrupt is triggered.

In the Setup, essentially, we are going to modify the Vector pointing


to the default Interrupt Handler (in the example above the CINV Vector
$0314-$0315), saving in it the address of our custom irq handler in
the low byte/high byte format (aka "little endian").

It should be noted that the above code section must necessarily be


enclosed between a SEI (Set Interrupt Disable Flag) and a CLI (Clear
Interrupt Disable Flag) instruction so that no further IRQ Interrupts
can occur during the delicate Vector modification phase, otherwise we
could risk a system crash.

We will see later, in more elaborate examples, that in the


configuration, in addition to changing the interrupt vector, we will
generally execute other preparatory instructions for the correct
operation of our service routine.

Finally, we would like to point out that the output of our routine is
managed by a JUMP at $ea31, which is the default IRQ handler to perform
the standard system operations performed 60 times per second, i.e.
keyboard scanning, cursor flashing, Jiffy clock update, etc.
As mentioned several times, the IRQ type interruption of the system
is triggered every 1/60 of a second by Timer A of the CIA1.

To conclude, let's look at a simple example of an NMI interrupt handler


whose logic is very similar to the IRQ interrupt handler presented
above.

Remember that both Routines are implemented at address $c000 and must
therefore be executed by writing the command SYS 49152 in the VICE
window which emulates the Commodore 64 screen.

*=$c000

; We modify the NMINV vector ($0318-$0319)


; so that it points to the address of our custom NMI handler

lda #<newNMI ; low byte of the custom NMI handler address


sta $0318
lda #>newNMI ; high byte of the custom NMI handler address
sta $0319
jsr $e544 ; we clear the screen
rts ; we exit our main code

newNMI
inc $d020 ;we increase the border colour
jmp $fe47 ;we jump to $fe47 address
;in order to execute the default NMI handler

Let's just add that this NMI interrupt handler can be tested by
repeatedly pressing the RESTORE key which, as we have said, is NOT
part of the keyboard matrix - containing 64 physical keys of the C64
- cannot be detected by the standard KERNEL keyboard reading routine
(SCNKEY) but generates an NMI type interrupt request.

In VICE 3.4, the RESTORE key of a real C64 corresponds to the F12 key
of a normal extended PC keyboard.

For the moment, we stop here and refer you to the next part of the
tutorial, part 4, where we will start to approach the most interesting
part of the interrupts with a theoretical analysis and a practical
application (code examples) for the implementation of "RASTER
INTERRUPTS" type interrupts (or "frame interrupts"). A "RASTER
INTERRUPT" type interrupt is an interrupt trigger signal that the
Commodore 64 graphics processor (VIC-II) can send whenever the raster
of the VIC video signal reaches a specific line on the screen.

That's all folks!

Attilio Capuozzo – Founder of "RetroProgramming


Italia – RP Italia Facebook" Group
& Antonia Savona – C64 GameCoder & DemoCoder

You might also like