Bei mir beginnt die App bei 0x2000. Ich definiere im Linker-Script:
1 | MEMORY
|
2 | {
|
3 | data (a!xr) : ORIGIN = 0x800, LENGTH = 0x4000
|
4 | reset : ORIGIN = 0x2000, LENGTH = 0x4
|
5 | ivt : ORIGIN = 0x2004, LENGTH = 0x1FC
|
6 | program (xr) : ORIGIN = 0x2208, LENGTH = 0x289F0
|
7 | CONFIG3 : ORIGIN = 0x2ABFA, LENGTH = 0x2
|
8 | CONFIG2 : ORIGIN = 0x2ABFC, LENGTH = 0x2
|
9 | CONFIG1 : ORIGIN = 0x2ABFE, LENGTH = 0x2
|
10 | }
|
11 |
|
12 | __CONFIG3 = 0x2ABFA;
|
13 | __CONFIG2 = 0x2ABFC;
|
14 | __CONFIG1 = 0x2ABFE;
|
15 | __CODE_BASE = 0x2200;
|
16 | __CODE_LENGTH = 0x289F0;
|
17 | __IVT_BASE = 0x2004;
|
18 | __AIVT_BASE = 0x2104;
|
und biege die Interrupts um:
1 | .ivt __IVT_BASE :
|
2 | {
|
3 | SHORT(DEFINED(__ReservedTrap0) ? ABSOLUTE(__ReservedTrap0) : ABSOLUTE(__DefaultInterrupt));
|
4 | SHORT(0x04);
|
5 | SHORT(DEFINED(__ReservedTrap0) ? ((ABSOLUTE(__ReservedTrap0)>>16)&0x7f) : ((ABSOLUTE(__DefaultInterrupt)>>16)&0x7f));
|
6 | SHORT(0x00);
|
7 |
|
8 | SHORT(DEFINED(__OscillatorFail) ? ABSOLUTE(__OscillatorFail) : ABSOLUTE(__DefaultInterrupt));
|
9 | SHORT(0x04);
|
10 | SHORT(DEFINED(__OscillatorFail) ? ((ABSOLUTE(__OscillatorFail)>>16)&0x7f) : ((ABSOLUTE(__DefaultInterrupt)>>16)&0x7f));
|
11 | SHORT(0x00);
|
12 | ....
|
Heißt also: Ich lasse GOTO-Anweisungen generieren, die entweder auf den
immer vorhanden DefaultInterrupt oder meinen Interrupt-Vektor zeigen.
Im Bootloader definiere ich dann im Linkerscript die Interrupt-Vektoren
passend um:
1 | .ivt __IVT_BASE :
|
2 | {
|
3 | LONG(ABSOLUTE(0x2004)); /*__ReservedTrap0*/
|
4 | LONG(ABSOLUTE(0x2008)); /*__OscillatorFail*/
|
5 | LONG(ABSOLUTE(0x200c)); /*__AddressError*/
|
6 | LONG(ABSOLUTE(0x2010)); /*__StackError*/
|
7 | LONG(ABSOLUTE(0x2014)); /*__MathError*/
|
8 | LONG(ABSOLUTE(0x2018)); /*__ReservedTrap5*/
|
9 | ...
|
Der Bootloader muss also nichts von den Vektoren in der App wissen, weil
ich ja dort die GOTOs hab generieren lassen, so dass die
Einsprungsstellen immer konstant sind, um im Bootloader feste Adressen
eintragen zu können.
fchk