===== VASYL interrupts and VASYL/CPU coordination ===== While BeamRacer makes it easy to offload many graphics-related operations to VASYL, there are situations where some precisely-timed assistance from the main CPU may be needed. These can be chiefly grouped into three categories: * Writing to an address inaccessible to VASYL. * Performing computations that 6510 is better suited to. * Making sure that CPU operations happen in a specific region of the video frame, to avoid clashes over resources shared with VASYL. Let's review them one by one. === Non-VIC writes === **MOV** and **XFER** display list instructions do an excellent job of fast, precise writes to VIC-II registers. However, there are locations in C64 memory space that influence video output, and yet are beyond VASYL's reach - a canonical example here is VIC bank switching in ''CI2PRA'' register at ''$dd00'', but it could also be just-in-time Color RAM or video matrix updates. === Computations difficult to do with VASYL === As in any well-balanced system, both the 6510 and VASYL have domains of operation where they excel, as well as those where they may be a poor match for the job. Although a lot can be done using display lists, it is only natural that a general CPU like 6510 will be more effective (or even the only) choice for many types of calculations. Their results can afterwards be uploaded to VASYL's local memory for use as look-up tables or display data. === Coordinating raster time between VASYL and CPU === Access to particular hardware resources needs to be properly managed to avoid the risk of visual glitches and odd errors. With both the CPU and the display lists being able to write VASYL registers, certain degree of planning is necessary to avoid situations where, e.g. concurrent use of PORT0 registers would lead to undesirable results. At an intermediate level of BeamRacer programming a good rule of thumb is to dedicate one port for CPU use, and the other for display lists', effectively mitigating the risk of access collisions. However, as you became more proficient in VASYL programming, and the complexity of your display lists increases, so does their appetite for resources - and you quickly find yourself writing VASYL code that uses both ports. If you also need to keep moving the data from CPU side to local RAM, you will need to start coordinating port access, making sure each of them has only one user at a time. A straightforward way to do this is by reserving specific time periods during a frame for each of the port users. You can see this in action in [[https://github.com/madhackerslab/beamracer-examples/blob/master/asm/demo_rastersplit.s|demo_rastersplit.s]], where display list is using both ports most of the time. The CPU has a narrow time window to upload updated rasterbar positions to the local memory - between raster lines 0 and 14. It thus patiently waits for the video beam to reach line number 0, and then quickly does the job. \\ In all of the above scenarios, relying on interrupts makes it possible to avoid busy looping when waiting for the right time, but VASYL IRQs (compared to VIC's) have the added benefit of being triggerable on a specific cycle of a rasterline, thus providing more just-in-time operations. And using CPU/VASYL synchronization technique demonstrated in [[https://github.com/madhackerslab/beamracer-examples/blob/master/asm/demo_irq2.s|demo_irq2.s]], one can execute 6502 writes with a single-cycle precision. ==== Setting up VASYL interrupts ==== Getting VASYL interrupts working is as easy (or as difficult), as setting up VIC raster interrupt: * They are delivered as IRQs, so depending on your ROM configuration and whether you want to rely on the original interrupt handler or do the whole thing yourself, IRQ interrupt vector at either ''$314'' or ''$fffe'' needs to be made to point to your interrupt routine, LDA #irq_handler STA $315 * The interrupt needs to be enabled by setting bit 4 in the ''IRQMASK'' register at ''$d01a'' (the same register that stores bits controlling VIC's interrupts), LDA #$10 STA $d01a * The interrupt needs to be triggered by executing instruction [[https://docs.beamracer.net/doku.php?id=isa#irq|IRQ]] in the display list, e.g. WAITBAD ; wait for the start of a rasterline preceding the next badline DELAYH 10 ; wait 10 more cycles IRQ ; trigger an interrupt DELAYV 10 ; wait for 10 more rasterlines IRQ ; trigger another interrupt, this time at the beginning of the line * In your interrupt handler, you need to make sure that VASYL IRQ is acknowledged by setting bit 4 of ''VICIRQ'' register at ''$d019'', or the interrupt will be retriggered as soon as the handler finishes executing. ; We assume here that no VIC interrupts are enabled and ; VASYL is the only possible video related IRQ source LDA #$10 STA $d019 You can trigger multiple interrupts in a frame, or even in a single rasterline. A complete example showing how to set up VASYL interrupts alongside VIC raster interrupts, how to differentiate between them, and how to use one to set up another can be found in [[https://github.com/madhackerslab/beamracer-examples/blob/master/asm/demo_irq.s|our GitHub repository]].