Simply making an array of 16-bit integers solved the problem. Casts between function pointers and integers are well-defined in ISO C, and even if the function pointer happens to be a 24 bit one, it will be truncated into 16 bits. Though of course you will still need to allocate all ISR in non-banked memory.
So for the record, this is how you write a fully ISO C compliant vector table for HCS12 (D family) Codewarrior. The only thing I couldn't do in standard C was to set the stack pointer. Feel free to use the code in your own projects, and please let me know if you find any errors.
It comes with some useful practice for how to handle unused interrupts. It also allows you to replace the horrid "start12.c", assuming you aren't using any static initalization in your project.
/* .prm file */
SEGMENTS
VECTOR_RESERVED
= NO_INIT 0xFF80 TO 0xFF8B;
VECTOR_TABLE
= READ_ONLY 0xFF8C TO 0xFFFF;
ROM_4000 = READ_ONLY 0x4000 TO 0x7FFF;
ROM_C000 = READ_ONLY 0xC000 TO 0xFEFF;
END
PLACEMENT
INTERRUPT_ROM INTO ROM_C000;
VECTORS INTO VECTOR_TABLE;
END
ENTRIES
vector_table
END/* vectortable_hcs12.h */
#ifndef _VECTORTABLE_HCS12_H
#define _VECTORTABLE_HCS12_H
/*** Include files ***/
#include "s12reg.h" /* your register map goes here */
#include "types.h" /* your uint16 etc typedef header goes here */
/*** Macros and numeric constants ***/
#define DEFAULT_VECTOR interrupt_unused
/*** Function prototypes ***/
#pragma CODE_SEG NEAR INTERRUPT_ROM
extern void interrupt_unused (void);
extern void interrupt_reset (void);
extern void interrupt_clock_fail (void);
extern void interrupt_cop_reset (void);
extern void interrupt_SWI (void);
extern void interrupt_RTI (void);
extern void interrupt_ECT_timer0 (void);
extern void interrupt_ECT_timer1 (void);
extern void interrupt_ECT_timer2 (void);
extern void interrupt_ECT_timer3 (void);
extern void interrupt_ECT_timer4 (void);
extern void interrupt_ECT_timer5 (void);
extern void interrupt_ECT_timer6 (void);
extern void interrupt_ECT_timer7 (void);
extern void interrupt_ECT_overflow (void);
extern void interrupt_ECT_PACA (void);
extern void interrupt_ECT_PACIE (void);
extern void interrupt_SPI0 (void);
extern void interrupt_SCI0 (void);
extern void interrupt_SCI1 (void);
extern void interrupt_PortJ (void);
extern void interrupt_PortH (void);
extern void interrupt_ECT_PACB (void);
extern void interrupt_PLL_lock (void);
extern void interrupt_SPI1 (void);
extern void interrupt_PortP (void);
#pragma CODE_SEG DEFAULT
#endif /* _VECTORTABLE_HCS12_H */
/* vectortable_hsc12.c */
#include "vectortable_hcs12.h"
/*** Function prototypes ***/
/* external interrupt routines */
#pragma CODE_SEG NEAR INTERRUPT_ROM
extern void main (void);
#pragma CODE_SEG DEFAULT
/*** Global constants ***/
#pragma CONST_SEG NEAR VECTORS
const uint16 vector_table[] =
{
/* */ /* $FF00:8B Reserved*/
(uint16) DEFAULT_VECTOR, /* $FF8C:8D PWM Emergency Shutdown */
(uint16) interrupt_PortP, /* $FF8E:8F Port P Interrupt */
(uint16) DEFAULT_VECTOR, /* $FF90:91 MSCAN 4 transmit */
(uint16) DEFAULT_VECTOR, /* $FF92:93 MSCAN 4 receive */
(uint16) DEFAULT_VECTOR, /* $FF94:95 MSCAN 4 errors */
(uint16) DEFAULT_VECTOR, /* $FF96:97 MSCAN 4 wake- up */
(uint16) DEFAULT_VECTOR, /* $FF98:99 MSCAN 3 transmit */
(uint16) DEFAULT_VECTOR, /* $FF9A:9B MSCAN 3 receive */
(uint16) DEFAULT_VECTOR, /* $FF9C:9D MSCAN 3 errors */
(uint16) DEFAULT_VECTOR, /* $FF9E:9F MSCAN 3 wake- p */
(uint16) DEFAULT_VECTOR, /* $FFA0:A1 MSCAN 2 transmit */
(uint16) DEFAULT_VECTOR, /* $FFA2:A3 MSCAN 2 receive */
(uint16) DEFAULT_VECTOR, /* $FFA4:A5 MSCAN 2 errors */
(uint16) DEFAULT_VECTOR, /* $FFA6:A7 MSCAN 2 wake-up */
(uint16) DEFAULT_VECTOR, /* $FFA8:A9 MSCAN 1 transmit */
(uint16) DEFAULT_VECTOR, /* $FFAA:AB MSCAN 1 receive */
(uint16) DEFAULT_VECTOR, /* $FFAC:AD MSCAN 1 errors */
(uint16) DEFAULT_VECTOR, /* $FFAE:AF MSCAN 1 wake-up */
(uint16) DEFAULT_VECTOR, /* $FFB0:B1 MSCAN 0 transmit */
(uint16) DEFAULT_VECTOR, /* $FFB2:B3 MSCAN 0 receive */
(uint16) DEFAULT_VECTOR, /* $FFB4:B5 MSCAN 0 errors */
(uint16) DEFAULT_VECTOR, /* $FFB6:B7 MSCAN 0 wake-up */
(uint16) DEFAULT_VECTOR, /* $FFB8:B9 FLASH */
(uint16) DEFAULT_VECTOR, /* $FFBA:BB EEPROM */
(uint16) DEFAULT_VECTOR, /* $FFBC:BD SPI2 */
(uint16) interrupt_SPI1, /* $FFBE:BF SPI1 */
(uint16) DEFAULT_VECTOR, /* $FFC0:C1 IIC Bus */
(uint16) DEFAULT_VECTOR, /* $FFC2:C3 DLC */
(uint16) DEFAULT_VECTOR, /* $FFC4:C5 SCME */
(uint16) interrupt_PLL_lock, /* $FFC6:C7 CRG lock */
(uint16) interrupt_ECT_PACB, /* $FFC8:C9 Pulse Accumulator B Overflow */
(uint16) DEFAULT_VECTOR, /* $FFCA:CB Modulus Down Counter underflow */
(uint16) interrupt_PortH, /* $FFCC:CD Port H*/
(uint16) interrupt_PortJ, /* $FFCE:CF Port J */
(uint16) DEFAULT_VECTOR, /* $FFD0:D1 ATD1 */
(uint16) DEFAULT_VECTOR, /* $FFD2:D3 ATD0 */
(uint16) interrupt_SCI1, /* $FFD4:D5 SCI1 */
(uint16) interrupt_SCI0, /* $FFD6:D7 SCI0 */
(uint16) interrupt_SPI0, /* $FFD8:D9 SPI0 */
(uint16) interrupt_ECT_PACIE, /* $FFDA:DB Pulse accumulator input edge */
(uint16) interrupt_ECT_PACA, /* $FFDC:DD Pulse accumulator A overflow */
(uint16) interrupt_ECT_overflow, /* $FFDE:DF Timer overflow */
(uint16) interrupt_ECT_timer7, /* $FFE0:E1 Timer channel 7 */
(uint16) interrupt_ECT_timer6, /* $FFE2:E3 Timer channel 6 */
(uint16) interrupt_ECT_timer5, /* $FFE4:E5 Timer channel 5 */
(uint16) interrupt_ECT_timer4, /* $FFE6:E7 Timer channel 4 */
(uint16) interrupt_ECT_timer3, /* $FFE8:E9 Timer channel 3 */
(uint16) interrupt_ECT_timer2, /* $FFEA:EB Timer channel 2 */
(uint16) interrupt_ECT_timer1, /* $FFEC:ED Timer channel 1 */
(uint16) interrupt_ECT_timer0, /* $FFEE:EF Timer channel 0 */
(uint16) DEFAULT_VECTOR, /* $FFF0:F1 Real Time Interrupt */
(uint16) DEFAULT_VECTOR, /* $FFF2:F3 IRQ */
(uint16) DEFAULT_VECTOR, /* $FFF4:F5 XIRQ */
(uint16) DEFAULT_VECTOR, /* $FFF6:F7 SWI */
(uint16) DEFAULT_VECTOR, /* $FFF8:F9 Unimplemented instruction trap */
(uint16) interrupt_cop_reset, /* $FFFA:FB COP failure reset */
(uint16) DEFAULT_VECTOR, /* $FFFC:FD Clock Monitor fail reset */
(uint16) interrupt_reset /* $FFFE:FF Reset */
};
#pragma CONST_SEG DEFAULT
/*** Function definitions ***/
/* Unused interrupt implementations */
#pragma CODE_SEG NEAR INTERRUPT_ROM
#pragma TRAP_PROC
void interrupt_unused (void)
{}
#pragma TRAP_PROC
void interrupt_reset(void)
{
#pragma MESSAGE DISABLE C12053
asm LDS #$2500;
INITRM = 0x21;
INITEE = 0x09;
main();
}
#pragma TRAP_PROC
void interrupt_cop_reset(void)
{
#pragma MESSAGE DISABLE C12053
asm LDS #$2500;
INITRM = 0x21;
INITEE = 0x09;
main();
}
#pragma TRAP_PROC
void interrupt_SWI (void)
{}
#pragma TRAP_PROC
void interrupt_RTI (void)
{
CRGINT &= ~RTIE;
}
#pragma TRAP_PROC
void interrupt_ECT_timer0 (void)
{
TIE &= ~0x01;
}
#pragma TRAP_PROC
void interrupt_ECT_timer1 (void)
{
TIE &= ~0x02;
}
#pragma TRAP_PROC
void interrupt_ECT_timer2 (void)
{
TIE &= ~0x04;
}
#pragma TRAP_PROC
void interrupt_ECT_timer3 (void)
{
TIE &= ~0x08;
}
#pragma TRAP_PROC
void interrupt_ECT_timer4 (void)
{
TIE &= ~0x10;
}
#pragma TRAP_PROC
void interrupt_ECT_timer5 (void)
{
TIE &= ~0x20;
}
#pragma TRAP_PROC
void interrupt_ECT_timer6 (void)
{
TIE &= ~0x40;
}
#pragma TRAP_PROC
void interrupt_ECT_timer7 (void)
{
TIE &= ~0x80;
}
#pragma TRAP_PROC
void interrupt_ECT_overflow (void)
{
TSCR2 &= ~TOI;
}
#pragma TRAP_PROC
void interrupt_ECT_PACA (void)
{
PACTL &= ~PAOVI;
}
#pragma TRAP_PROC
void interrupt_ECT_PACIE (void)
{
PACTL &= ~PAI;
}
#pragma TRAP_PROC
void interrupt_SPI0 (void)
{
SPI0CR1 &= ~(SPIE | SPTIE);
}
#pragma TRAP_PROC
void interrupt_SCI0 (void)
{
SCI0CR2 &= ~(0x80|TCIE|RIE|ILIE); /* 0x80 == TIE */
}
#pragma TRAP_PROC
void interrupt_SCI1 (void)
{
SCI1CR2 &= ~(0x80|TCIE|RIE|ILIE); /* 0x80 == TIE */
}
#pragma TRAP_PROC
void interrupt_PortJ (void)
{
PIEJ = 0x00;
}
#pragma TRAP_PROC
void interrupt_PortH (void)
{
PIEH = 0x00;
}
#pragma TRAP_PROC
void interrupt_ECT_PACB (void)
{
PBCTL &= ~PBOVI;
}
#pragma TRAP_PROC
void interrupt_PLL_lock (void)
{
CRGINT &= ~LOCKIE;
}
#pragma TRAP_PROC
void interrupt_SPI1 (void)
{
SPI1CR1 &= ~(SPIE | SPTIE);
}
#pragma TRAP_PROC
void interrupt_PortP (void)
{
PIEP = 0x00;
}
#pragma CODE_SEG DEFAULT