Forum: Mikrocontroller und Digitale Elektronik PIC32 - Ausführen von Code im RAM


von PIC32 (Gast)


Lesenswert?

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?

von PIC32 (Gast)


Lesenswert?

Edit:
1
    li t9,0xa0006000
2
    jr t9

muss natürlich
1
    li t9,0xa0000000
2
    jr t9

lauten.

von Frank K. (fchk)


Lesenswert?

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

von PIC32 (Gast)


Lesenswert?

Ja, danke für die Tips.

Den letzteren Titel habe ich schon eine konsultiert.
Den Inhalt der SFRs werde ich prüfen.

von PIC32 (Gast)


Lesenswert?

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.

von Frank K. (fchk)


Lesenswert?

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

von PIC32 (Gast)


Lesenswert?

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:
1
/* on_bootstrap.S */
2
3
#include <p32xxxx.h>
4
5
  .text
6
  .align 4
7
  .globl _on_bootstrap
8
9
_on_bootstrap:
10
  li  t1,0x800
11
  la  t2,BMXDKPBA
12
  sw  t1,0(t2)
13
  lui  t1,0x2
14
  la  t2,BMXDUDBA
15
  sw  t1,0(t2)
16
  la  t2,BMXDUPBA
17
  sw  t1,0(t2)
18
  jr  ra

ersetzt.

von PIC32 (Gast)


Lesenswert?

Es handelt sich im übrigen um das hier:

https://github.com/OLIMEX/DuinoMite/tree/master/SOFTWARE/DMBasic/src

Und ein ordentliches Basic braucht natürlich ein SYS.

von Frank K. (fchk)


Lesenswert?

Du hast das obligatorische nop hinter dem finalen jr vergessen.

fchk

von PIC32 (Gast)


Lesenswert?

> 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...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.