When an IRQ occurs, the 6502 microprocessor and its derivatives in the C64 and C128 push the status register to the stack and then load the contents of a two-byte vector at memory address
$FFFE/$FFFF into the program counter to continue program execution at the address specified by the vector. Usually, the address pointed by this vector leads to a Kernal routine that does some register saving and then jumps into the actual interrupt service routine specified by the vector in
On a C64 there are thus two possibilities to install a custom interrupt service routine: either by modifying the address in
$0314/$0315 or by switching off the ROM and putting the address of your ISR into the RAM at
$FFFE/$FFFF. The latter method requires that you do some more register housekeeping, but it saves a considerable number of cycles until your routine starts. Thus, when timing is important, the second method is preferred.
The IRQ mechanisms are very similar on a Commodore 128 in the C128 mode, but according to my understanding, the mapping of memory area
$FF00-$FFFF is fixed. In particular, reading
$FFFE/$FFFF always gives a predefined vector from ROM, pointing to
$FF17 on my machine. The hardware IRQ vector is thus fixed in all memory configurations, allowing the C128 to execute an interrupt no matter what memory configuration is active. However, this would also mean that the direct hardware interrupt configuration is not possible in C128 mode. Since this is necessary for advanced IRQ routines (e.g. the "double IRQ" method used in many demos) this would deprive the C128 mode of an important feature.
Is this analysis correct? Or did I overlook a possibility to customize the IRQ hardware vector on a Commodore 128 in C128 mode?
After checking Brian's answer it becomes clear that this analysis was not correct. The reason why the ROM seems to appear at $FF05-FFFF in every bank is simply because the OS copied it there. But, as shown by Brian's example, this area can be simply overwritten.