Ich habe ein bestehendes PIC32-Projekt für den 32MX795F512H.
Verwendeter Compiler ist C32-v1_11b und MPLAB 8.92.
Dort will ich eine Routine die im RAM läuft hinzufügen.
Die naheliegende Methode per _longramfunc_ scheitert, da das
Projekt offenbar diesen Bereich ebenfalls als Scratch-RAM nutzt.
Als schnellen Workaround habe ich mir ein Array aus meiner
Funktion erzeugt, die auch vom Startup-Code als Kopie im
RAM initialisiert wird, und die ich über einen Functionpointer
anspringen könnte. sysarr liegt auf der Adresse 0xa0000000.
1
volatile int sysarr[]={
2
0x27BDFFF8, // 00 __asm__ (" addiu sp,sp,-8");
3
0xAFA20004, // 04 __asm__ (" sw v0,4(sp)");
4
0xAFBF0000, // 08 __asm__ (" sw ra,0(sp)");
5
0x3C02A000, // 0c __asm__ (" lui v0,0xa000");
6
0x34426000, // 10 __asm__ (" ori v0,v0,0x6000");
7
0x0040F809, // 14 __asm__ (" jalr ra,v0");
8
0x00000000, // 18 __asm__ (" nop");
9
0x00000000, // 1c __asm__ (" nop");
10
0x8FBF0000, // 20 __asm__ (" lw ra,0(sp)");
11
0x8FA20004, // 24 __asm__ (" lw v0,4(sp)");
12
0x03E00008, // 28 __asm__ (" jr ra");
13
0x27BD0008}; // 2c __asm__ (" addiu sp,sp,8");
14
15
void sys(void){
16
void (*sysptr)();
17
sysptr = 0xa0000000;
18
(* sysptr)();
19
}
Die Funktion sys() wird vom Compiler in:
1
li t9,0xa0006000
2
jr t9
übersetzt. Soweit scheint mir alles richtig.
Nur sobald die Funktion sys() aufgerufen wird, crasht das
ganze System.
Auch wenn ich die Zeile:
0x0040F809, // 14 _asm_ (" jalr ra,v0");
durch
0x00000000, // 14 _asm_ (" nop");
ersetze.
Oder gleich am Eingang ein jr ra, nop einfüge.
Es scheint, dass bereits der Sprung in den RAM den
Fehler auslöst.
Hat jemand eine Idee was da schief geht?
Bevor Du irgendetwas weiter machst, besorge Dir die Kapitel 2 und 3 des
PIC32 Reference Manuals und lies die. Komplett.
Dann:
https://www.mips.com/develop/training-courses/mips-basic-training-course/
Das ganze ist nämlich etwas komplexer:
PIC32 hat einen MIPS-Prozessorkern. MIPS ist eine der ältesten
RISC-Architekturen aus den 80'ern. Ich habe Anfang der 90'er Jahre an
einer DECStation 3100 mit MIPS R2000 mit 20 MHz gesessen, und das, was
dort in mehreren Chips für 1000'e von $ lauf der Hauptplatine war, ist
jetzt in Deinem PIC32 für wenige € - und Faktor 4 höherem Takt.
MIPS hat heutzutage immer eine MMU dabei. Heißt also: Du hast
physikalische Adressen (für DMA wichtig) und Du hast virtuelle Adressen.
Bei größen MIPS-Prozessoren (quasi alles, wo Linux drauf läuft) sind die
Umsetzungstabellen konfigurierbar. PIC32 hat nur die Minimalversion, wo
die Adressumsetzung fix ist.
MIPS unterscheidet wie viele andere Architekturen auch zwischen Kernel
Mode und User Mode. Kernel Mode kann alles, User Mode hat Restriktionen.
Flash und RAM sind mehrfach in den virtuellen Adressraum eingeblendet.
Von 0x00000000 bis 0x7fffffff ist das USEG, das Segment für den User
Mode. Im User Mode kannst Du nur darauf zugreifen. Sollte Dein Code im
User Mode laufen, musst Du das USEG benutzen.
Im Kernel Mode hast Du noch KSEG0 bis KSEG3. Das 12k Boot Flash liegt
sowohl im KSEG1 also auch KSEG0. KSEG1 ist nicht cachebar, und der
Prozessor startet in diesem Segment. KSEG0 ist cachebar, kann aber erst
benutzt werden, wenn selbiger initialisiert worden ist. Wenn Du irgend
ein Interese hast, dass Dein Code schnell abläuft, solltest Du ihn im
KSEG0 ausführen.
Auch das RAM ist sowohl in KSEG1 als auch KSEG0 gemappt. Dafür gilt das
gleiche.
Dann:
Du kannst nicht einfach so Code im RAM laufen lassen. Geht nicht. Die
MMU muss wissen, welcher Bereich Daten und welcher Bereich Code ist.
Dafür gibts die SFRs BMXCON, BMXDKPBA, BMXDUDBA, BMXDUPBA etc, die
passend gesetzt sein müssen. Diese Einstellungen müssen mit den
Einstellungen im Linker Skript übereinstimmen, sonst gibt das Bruch.
Das nur so zum Einstieg. In der Dokumentation findest Du mehr, und den
Training Course solltest Du auch machen, um die ganze Architektur und
solche Dinge wie CP0 usw kennenzulernen.
Wenn dann noch was unklar ist:
http://read.pudn.com/downloads92/ebook/361542/See.MIPS.Run.2nd.Edition.pdf
fchk
Ein gewisser Fortschritt.
Ich habe die Werte BMXDKPBA, BMXDUDBA und BMXDUPBA konfigurierbar
gemacht, so dass sie nach einem Reset per on_bootstrap mit Werten
aus dem Flash, die ich per Setup ändern kann, gesetzt werden.
Leider ist BMXDKPBA = 0 keine valide Konfiguration, so dass ein
Start ab 0xa0000000 nach wie vor fehlschlägt, aber ab 0xa0000800
klappt es. Immerhin etwas.
PIC32 schrieb im Beitrag #6156378:
> Leider ist BMXDKPBA = 0 keine valide Konfiguration, so dass ein> Start ab 0xa0000000 nach wie vor fehlschlägt, aber ab 0xa0000800> klappt es. Immerhin etwas.
Kann ja auch nicht, denn wo sollen sonst Stack und Heap liegen? Die 128k
RAM sind ja nur einmal vorhanden, und Du musst eben einstellen, bis
wohin Dein Datensegment geht und ab wo Dein Codesegment anfängt. Und
genau das muss dann auch so im Linkerskript stehen.
Wenn Dein Altprojekt den Speicher einfach so ohne malloc verwendet, und
dann auch noch hardgecodete Adressen, dann hast Du ein Problem. Bzw. Du
hattest dann schon vorher eines, nur Du wusstest nichts davon, oder es
war ein PAL (Problem Anderer Leute).
fchk
Da keine ramfuncs verwendet werden, stehen in den Registern
BMXDKPBA, BMXDUDBA und BMXDUPBA nur Nullen. D.h. die gesamten
128 k wären nur für Daten.
Aber es stört die (Kernel-)Datenzugriffe überhaupt nicht, wenn
auch die Codeausführung erlaubt ist.
Daher habe ich die Konfiguration per Setup durch ein einfaches:
> Du hast das obligatorische nop hinter dem finalen jr vergessen.
Nur wenn ich den Assembler mit:
.set noreorder
dazu gezwungen hätte.
Sonst wandert der vorletzte Befehl:
sw t1,0(t2)
von alleine in den Delayslot, und damit hinter das jr ra...