magazine logo
Welcome to the official Attitude website - Europe's #1 C64 scene disk magazine
IRQ Loader Usage Tutorial
by DJ Gruby/Arsenic/Excess/Protovision

(based on an example of Krill's IRQ loader)


Once you master using IRQ loader, a new world of endless possibilities will open to you. Eventually you will become able to make all those programs you always dreamt of, but you were unable to realise due to memory limitations of a C64. Finally you will begin producing some really cool stuff: trackmos, disk magazines, graphic collections, full disk games, everything you have always wanted to get your hands dirty with. This article will provide you with all the basic knowledge required to accomplish this old dream of yours and free your talent for further exploration of new and unfamiliar areas of C64 programming.


We are about to built a simple program that loads two previously compressed bitmap images from disk in a looped sequence and displays them alternately. An IRQ routine will be setup in order to constantly play a soundtrack while loading, decrunching and rendering processes are in progress. A working example, which is a final result of this tutorial, will cover everything you need to know in order to be able to use this method yourself. You are obviously encouraged to exploit it as a foundation for your own programs.

An entire example described in this article is available as an integral part of Attitude #15 package found in a subdirectory named irq-loader-usage-tutorial. There is also a pre-prepared D64 disk image available, which lets you immediately find out how the final result will look like.


This tutorial is based on Krill's IRQ loader, which is the current state-of-the-art in IRQ loaders. I assume you have got an already compiled binary with a filename-based loading procedure available for an inclusion within your program (if not, you can use one provided in a ZIP file). You need both an installer routine and a loading procedure. Please note that this tutorial does not cover the topic of Krill's IRQ loader compilation (please consult a separate article available in this issue of Attitude for more information).

Image files preparation

First we need to prepare files we are going to load from within of our program. They will be two graphic images. Let one of them be a Koala Painter multicolour picture (with a default loading address of $6000), and the other one an Art Studio hires bitmap (with a default loading address of $2000).

You are of course not limited to only load data from disk during the course of your program. You may load an actually executable code as well, and simply perform an appropriate jump once your file is loaded and depacked.

In this tutorial I stick to two graphic images for the sake of its simplicity, as the main purpose of this tutorial is to teach you how to adopt proper IRQ loader usage approach rather than listing all possible applications of this technique.

Given that both images are available in the current working directory under names image001.prg and image002.prg, we will compress them first in order to save some space on disk as well as use them as a basis for showing you how to decompress files after they are loaded. For this let us use HCL's ByteBoozer, as it is available for the PC and it works on a command line, which simplifies the process of project build automation. Compressing files on the PC has also the advantage of being carried out almost instantly (yes, 1 GHz of a computational power of a moderate PC versus 1 MHz of a C64 makes a difference).

Under an assumption that your ByteBoozer binary is available on the PATH environment variable and is named BB, execute the following two commands:

$ BB image001.prg

$ BB image002.prg

They will produce two compressed files named and respectively.

Now we need to hack their loading addresses. It will show how to guarantee that a file you load from disk does not overwrite any data that might still be in use during loading phase. By default ByteBoozer automatically shifts the compressed file up to $FFF9. Although this is not ultimately necessary for our simple program to work properly, you always need to be careful when deciding where to load your data, so that you do not overwrite an existing code that is still in use. To accomplish this you can use any binary editor of your choice. My personal preference is GHex, because it is very simple and designed to run in my favourite desktop environment (GNOME).

Every Commodore 64 file consists of two parts: a two-byte loading address, and a variable length data. The first two bytes hold the information about file's loading address. Edit both files:

$ ghex

Now replace the first two bytes of both files with the following values: 00 A0. They state that a new loading address will point to $A000 (this is a safe place, which does not conflict with the source code of our program - we will compile it at $C100). Save both files and exit an editor.

Disk preparation

Our files are ready to be loaded from disk, so let us create an empty D64 disk image and write both previously compressed and relocated image files onto it. Name them AA and AB (these names we will refer to in our exemplary program).

Whether you prefer a fully automated solution, or you are a big fan of doing all the work with an assistance of a graphic interface, I leave this decision entirely up to you. If you like to employ Perl scripting to write your automation script, I can recommend using D64::Disk::Image library, which has been described in detail in an article entitled D64 With Perl published in Attitude #13. If you prefer a GUI based solution for copying files between your system and D64 disk images, DiskImagery64 provides everything you need to accomplish this task. Once the disk is ready, it is time for writing some assembly code.

Loader setup

For the purpose of this tutorial we are going to assume that IRQ loader binaries have been saved as installer-c64.prg and loader-c64.prg files and copied over to your project directory. Hence, we begin to code our exemplary program with a few necessary definitions and inclusions. Create a new file and name it test.src. This is where all the main program code and data will be added.

; Start address of a loading procedure binary:

loader = $0800

; Execution address of a loading procedure:
load = $0800

; Start address of an installation procedure binary:
installer = $2000

; Execution address of an installation procedure:
install = $2fa6

        *= installer
.binclude "installer-c64.prg",2

        *= loader
.binclude "loader-c64.prg",2

Please replace all the addresses in an above example with the proper values corresponding to your IRQ loader configuration.

Note that installer routine is called only once during the course of a program, and can be safely removed once executed. Here we use an installer compiled at $2000, which is later replaced by an uncompressed Art Studio picture. That is okay, because an image will be loaded later from a disk. Loader code on the other hand is resident and cannot be overwritten as long as the loader is in use.

Other includes

Additional includes we need to take care of are: sound track and a decruncher routine. Krill's IRQ loader is capable of decrunching byteboozed files on the fly. Although this speeds up an entire process a bit, this may or may not be desired. Additionally it needs to be first configured while compiling a loader program itself.

Depending on a memory usage of your program, it may sometimes be not possible to decompress loaded files on the fly, because target memory area is still in use by an IRQ routine which is executed while the loader operates in the main loop of your program.

Decruncher is bundled as a part of a ByteBoozer source code package. Soundtrack choice is entirely your own decision. Simply pick up any chip tune you enjoy to listen, copy it over to a project directory, and add the following lines to a source code file.

        *= $1000

.binclude "soundtrack.prg",2

        *= $c000
#include "decruncher.src"

Please note the dreamass-like syntax. Binary file inclusions use .binclude directive followed by a file name, followed by a number of skipped bytes separated by a comma (we do not want to include sound track's loading address, so we skip those bytes - you remember that every C64 file begins with a loading address, right?). Source code inclusions use #include directive followed by an included file name (the contents of a source code file will be pasted there by a compiler and literally replace the line with an original directive).

IRQ setup and initialisation

We are going to come up with a couple of auxiliary routines to be called later in the main loop of our program. One of them is an IRQ setup routine.

It is a pretty standard code which initialises the program by setting up IRQ interrupts, as well as calling loader installation procedure, initialising the soundtrack, setting up background and border colours.

To keep the main program file clear we may want to setup a separate source code file named proc.src that contains this and other auxiliary routines.

init    ; Setup background and border colours:

        lda #$00
        sta $d020
        sta $d021

        ; Blank screen to border colour:
        lda #$00
        sta $d011

        ; Call loader installation routine:
        jsr install

        ; Initialise the soundtrack:
        lda #$00
        jsr $1000

        ; Configure IRQ interrupts:
        lda #$36 ; switch off the BASIC ROM
        sta $01
        lda #<irq
        sta $0314
        lda #>irq
        sta $0315
        lda #$00
        sta $d012
        lda #$01
        sta $d019
        lda #$81
        sta $d01a
        lda #$7b
        sta $dc0d
        lda #$00
        sta $dc0e


irq     inc $d020 ; play music and at the same time

        jsr $1003 ; visualize how much raster time is
        dec $d020 ; consumed by a player routine

        inc $d019
        jmp $ea7e

Once the init procedure is called, your IRQ routine will be properly executed and play chosen soundtrack regardless of an IRQ loader being busy loading other files from disk.

Graphic display routines

When a pictures is loaded from disk, it needs to be displayed on a screen (well, we need a prove that this entire tutorial is not a rubbish, it needs to carry out its task properly). Displaying Koala Painter and Art Studio images can also be extracted to separate routines and placed into proc.src file created in a previous paragraph.

koala   ; Copy screen and colours data into $4400

        ; and $d800:
        ldx #$00
        lda $7f40,x
        sta $4400,x
        lda $8040,x
        sta $4500,x
        lda $8140,x
        sta $4600,x
        lda $8240,x
        sta $4700,x
        lda $8328,x
        sta $d800,x
        lda $8428,x
        sta $d900,x
        lda $8528,x
        sta $da00,x
        lda $8628,x
        sta $db00,x
        bne *-49

        ; Display bitmap at $6000, where it has been
        ; previously decrunched:
        lda $dd00
        and #$fc
        ora #$02
        sta $dd00
        lda #$18
        sta $d016
        lda #$18
        sta $d018
        lda #$3b
        sta $d011


hires   ; Copy screen data into $0c00:
        ldx #$00
        lda $3f40,x
        sta $0c00,x
        lda $4040,x
        sta $0d00,x
        lda $4140,x
        sta $0e00,x
        lda $4240,x
        sta $0f00,x
        bne *-25

        ; Display bitmap at $2000, where it has been
        ; previously decrunched:
        lda $dd00
        and #$fc
        ora #$03
        sta $dd00
        lda #$08
        sta $d016
        lda #$38
        sta $d018
        lda #$3b
        sta $d011


Once a Koala Painter picture is loaded, koala routine will be called to display it on a screen. For an Art Studio picture, we will use hires procedure.

Main loop

Now the time has come to construct the heart of our program and put everything we have built so far together. The goal is to have an IRQ routine up and running, and a loader procedure installed and ready to use. Once this is accomplished, we will loop our program and perform the following steps alternately:

1. Load a Koala Painter picture from disk.

2. Decrunch and display loaded picture.

3. Load an Art Studio picture from disk.

4. Decrunch and display loaded picture.

We have built a solid foundation for making the main loop of our program clean and robust. Would you believe that it was going to be resolved in so few lines of code? Take a look below.

        *= $c100

        ; Initialise IRQ loader and setup IRQ interrupt
        ; routine:
        jsr init

loop    ; Load Koala Painter file named "AA" from disk:
        ; Vector pointing to a string containing loaded
        ; file name:
        ldx #<file1
        ldy #>file1

        ; Load file to a memory address of $A000:
        jsr load

        ; Decrunch loaded file into $6000:
        ldy #<$a000
        ldx #>$a000
        jsr decrunch

        ; Display Koala Painter bitmap:
        jsr koala

        ; Load Art Studio file named "AB" from disk:
        ; Vector pointing to a string containing loaded
        ; file name:
        ldx #<file2
        ldy #>file2

        ; Load file to a memory address of $A000:
        jsr load

        ; Decrunch loaded file into $2000:
        ldy #<$a000
        ldx #>$a000
        jsr decrunch

        ; Display Art Studio bitmap:
        jsr hires

        ; Loop over:
        jmp loop

file1    .dp "aa"
        .byte $00

file2    .dp "ab"
        .byte $00

; Do not forget to include the source code file with all
; auxiliary routines:
#include "proc.src"

Add those lines to test.src file and save it to disk. Every section is explained with a comment, so it should be self-evident what the code here does. Now is the time to test all of this and see it rocking.

Compilation and execution

In order to compile the code we will use Dreamass, then we compress it and create an executable using ByteBoozer. Under an assumption that both binaries are available on the PATH environment variable, execute the following two commands:

$ dreamass -o test test.src

$ BB -c c100 test

Almost done. Copy over an executable file (here named onto a D64 disk image created in a preparation phase of this tutorial and either load it into your VICE emulator or transfer it onto a 5,25" disk and try it on a real thing. As a result you will see the IRQ loader in action. IRQ interrupt runs and plays the soundtrack. Main loop alternately loads two image files, displays them and continues loading another one until you reset the machine. Well done, the mission has been accomplished. You are now well set for stepping onto an exciting journey to explore endless possibilities of new product development and you will no longer be limited by an amount of memory your C64 offers to you.


Is Krill's loader the only choice you have? Of course not. There is a plethora of different IRQ loaders available. They were created by various demo coders throughout the years. Their usage is generally very similar to Krill's solution: they have an installation procedure that can be removed from memory once executed, and they have a resident loading function to call every time a file needs to be loaded from disk. They support loading files either by track/sector locations or by their file names (first two letters or entire names). They implement 1 or 2 bit transfer protocols. There are faster and slower implementations. There are more or less compatible solutions. If you are interested in diving more into this topic, there is a lot of room left for further exploration.

I have tried to give you a ready to use example and show how easily an IRQ loader can be used in your own productions. I hope I have managed to achieve this goal and you will soon begin building your first big C64 releases.


   Add/view comments on this article (comments: 0)

Do you believe we are
able to cope with
releasing "Attitude"
on a regular basis?

yes no

 YES: 277 (70.66%)
NO:115 (29.34%) 



all visits:

visits today:

website started:
Official Webpage
of Attitude
Copyright 2004-2017