Adresse absolue d'une fonction dans Microchip XC16

8

Appareil: dsPIC33FJ128GP802

J'ai quelques fichiers * .s comme suit

.global _D1
.section .speex, code
_D1:
.pword 0x66C821,  0x1B0090,  0xD96C36,  0x9B60B0,  0xDD4E36,  0xBF4E53
.pword 0xD1098B,  0x719BD9,  0x873989,  0x003B69,  0x279035,  0xED4244
.pword 0xE1403C,  0x54D439,  0x826550,  0xC59627,  0xDD0432,  0x88FA29

J'ai déclaré la même chose dans un * .h

extern void D1(void);

Maintenant, je passe le D1 à une fonction de lecture de table

nowPlaying.file1 = (unsigned long) D1;
function(nowPlaying.file1);

Mon problème est que, si l'adresse de D1 est supérieure à 0X8000, la routine n'est pas correcte. J'ai essayé des modèles de code petits et grands, mais le résultat est le même. Je pense que cela est dû à la limitation de 16 bits des pointeurs Existe-t-il une méthode pour accéder à l'adresse absolue de D1 directement à partir du code. Peut être quelque chose comme une fonction intégrée ou des macros.

Saneesh AT
la source
Je n'ai jamais utilisé la série dsPIC, mais pour quelle raison ne pouvez-vous pas utiliser un tableau C const au lieu de l'assembleur? Je pense qu'il existe des options pour placer cela à des emplacements de code spécifiques (si vous en avez besoin pour une autre raison). Le simple fait de penser qu'une optimisation du compilateur raccourcit les pointeurs, car il ne s'attend pas à référencer des données aux emplacements de mémoire supérieurs.
PeterJ
Oui, le manuel du compilateur indique que tous les pointeurs, y compris les pointeurs de fonction, sont de 16 bits. Je cherche une autre méthode pour accéder à l'adresse mémoire. Si nous utilisons const array, nous ne pouvons pas utiliser l'octet supérieur d'un mot de 3 octets dans dsPIC. Une autre raison est que le fichier d'assemblage est généré par un logiciel informatique fourni par micropuce pour compresser les données vocales.
Saneesh AT le
Question connexe: electronics.stackexchange.com/questions/56058/… (bien que ce soit pour PIC, dsPIC fonctionne probablement de la même façon)
Les données sont-elles D1censées représenter une fonction ou un tableau de données?
The Photon
2
@Saneesh Alors répondez à mes questions. S'agit-il de code ou de données? Si c'est du code, le système ne le prend pas en charge au-delà de l'espace d'adressage 16 bits, donc ce que vous essayez de faire est impossible, peu importe la façon dont vous l'exprimez. S'il s'agit de données, veuillez le dire et essayez de les traiter en tant que const short D1[].
user207421

Réponses:

4

Les données que vous décrivez (utilisation complète de 24 bits de la mémoire du programme pour stocker les données) ne peuvent pas être définies et initialisées en C, et ne peuvent pas être lues directement via C; la seule façon d'y accéder est d'encapsuler dans une fonction d'assemblage appelable C ou intrinsèque.

Il y a vraiment deux questions ici:

  1. comment bien jouer avec le compilateur, l'assembleur et l'éditeur de liens, de sorte que lorsque vous définissez vos données 24 bits dans un fichier d'assemblage en tant que données déplaçables avec un nom symbolique D1, plutôt que des données sans nom à une adresse fixe, le compilateur peut voir cette variable pour déterminer son adresse

  2. comment accéder aux données

La deuxième question (comment accéder aux données) est répondue pour les pièces 33EP dans DS70613C et doit être répondue pour les pièces 33FJ dans DS70204C (mais les exemples dans le manuel 33FJ n'utilisent que les 16 bits bas). Voici un exemple d'extrait de code du manuel de référence 33EP qui fonctionne pour les pièces 33EP + devrait pour 33FJ (je n'ai pas de périphérique 33FJ facilement disponible):

(Remarque: le code utilise int, alors qu'il serait préférable d'utiliser uint16_tet #include <stdint.h>)

int prog_data[10] __attribute__((space(prog))) =
  {0x0000, 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888, 0x9999};

unsigned int lowWord[10], highWord[10];
unsigned int tableOffset, loopCount;

int main(void){
    TBLPAG = __builtin_tblpage (prog_data);
    tableOffset = __builtin_tbloffset (prog_data);
    /* Read all 10 constants into the lowWord and highWord arrays */
    for (loopCount = 0; loopCount < 10; loopCount ++)
    {
        lowWord[loopCount] = __builtin_tblrdl (tableOffset);
        highWord[loopCount] = __builtin_tblrdh (tableOffset);
        tableOffset +=2;
    }
    while(1)
        ;
}

Vous remarquerez que les fonctions intégrées __builtin_tblrdl()et __builtin_tblrdh()sont utilisées pour lire les mots de données bas et hauts de 16 bits à partir d'un emplacement de mémoire de programme, et __builtin_tblpage() and __builtin_tbloffset()peuvent être utilisées pour extraire la page et le décalage de l'adresse. Dans cet exemple particulier, le tableau highWord est toujours 0 et le tableau lowWord correspond au prog_data défini et initialisé en C.

Veuillez noter qu'aucun pointeur n'est utilisé ici! Bien qu'il soit possible d'utiliser des variables normales qui sont étiquetées avec const, afin qu'elles soient localisées par l'éditeur de liens dans l'espace programme en lecture seule, et que vous puissiez lire la mémoire en utilisant des techniques de pointeur C standard, le compilateur gérant automatiquement les registres de pagination pour vous, vous ne pouvez stocker que des données 16 bits. Vous devez accéder aux fonctions intégrées TBLRDL et TBLRDH pour obtenir les 24 bits de données.

Quant à savoir comment bien jouer avec le compilateur / éditeur de liens / etc, vous devez tromper le compilateur et lui dire qu'il ne voit que des données 16 bits. Voici un exemple qui a fonctionné pour obtenir la variable D1 déclarée ailleurs:

#define D1_SIZE 18
extern uint16_t __attribute__((space(prog))) D1[D1_SIZE];

#define READ_DATA(dst, v, len) readData(dst, __builtin_tblpage(v), __builtin_tbloffset(v), len)
void readData(uint32_t *pdst, uint16_t page, uint16_t offset, uint16_t len)
{
    TBLPAG = page;
    while (len-- > 0)
    {
        uint16_t lo = __builtin_tblrdl (offset);
        uint16_t hi = __builtin_tblrdh (offset);
        *pdst++ = (((uint32_t)(hi)) << 16) | ((uint32_t)(lo));
        offset += 2;
    }
}

...

uint32_t d1copy[D1_SIZE];
READ_DATA(d1copy, D1, D1_SIZE);

Cela lit correctement les valeurs 24 bits et les stocke dans les 24 derniers bits d'un uint32_t. La variable extern D1 déclaré dans C est une variable factice qui ne sert à obtenir à l'adresse de départ en tirant parti de la façon dont le compilateur / assembleur / éditeur de liens de travail ensemble. Les fonctions intégrées gèrent le reste du travail.

Ce que je ne sais pas, c'est comment obtenir automatiquement la taille des données, car elles sont définies + initialisées en assembleur.

Jason S
la source
1

Ne le convertissez pas en long et en arrière non signé. Demander des ennuis. Vous mentez au compilateur. La déclaration correcte pour nowPlaying.file1 est

struct
{
    // other stuff ...
    void (*D1)(void);
    // other stuff ...
} nowPlaying;

Et de même pour function ():

extern void function(void (*file)(void));

et supprimez toutes les typecasts.

Ou, si @PeterJ le suggère, ce sont des données, elles doivent être déclarées comme externe short D1 [] aux deux endroits: et vous n'avez pas vraiment besoin de l'assembleur; vous auriez pu tout déclarer en C comme const short D1 [] = {...}; Le compilateur doit le placer dans le segment de code tel qu'il est const.

user207421
la source
À moins que je ne lise quelque chose, D1 n'est pas un pointeur vers une fonction, ce sont des données stockées dans l'espace de code.
PeterJ
1
@PeterJ Ensuite, il ne doit pas être déclaré comme vide externe D1 (void), il doit être défini comme externe court D1 []. Rien de tout cela ne me convainc que la question n'appartient pas à SO.
user207421
Ce dont parle l'OP ne peut pas du tout être exprimé en C, il doit être encapsulé par une fonction d'assemblage appelable C ou intrinsèque.
Jason S
@JasonS Il n'y a aucune preuve de cela dans la question, et le PO n'a pas clarifié.
user207421
Oui, si vous connaissez les architectures PIC33F / PIC33E.
Jason S
0

Il semble que la réponse simple soit d'écrire le sous-programme dans l'assembleur. Si je me souviens bien, le C30 n'accède pas à la mémoire du programme en tant que données à l'aide de pointeurs 24 bits. Au mieux, il peut accéder à la mémoire de programme via la fenêtre PSV, mais vous ne pouvez alors voir que les 16 bits les plus faibles de chaque mot de mémoire de programme de 24 bits.

Il serait très simple d'écrire une routine d'assembleur qui peut être appelée à partir de C30 qui renvoie les 24 bits de données à une adresse de mémoire de programme de 24 bits. Cependant, vos données sont-elles une collection de valeurs de 24 bits ou vraiment une liste d'octets qui se trouvent être emballés 3 par mot? Si ce dernier, c'est encore plus facile. Écrivez une routine d'assembleur qui vous donne une vue des adresses d'octets de la mémoire du programme. L'adresse devrait toujours être de 24 bits, mais les valeurs de données ne sont plus que de 8 bits.

Ou écrivez simplement la routine entière dans l'assembleur. Si vous effectuez ce type de frappe d'octets de bas niveau et de mémoire, c'est probablement plus facile. Dans l'assembleur, vous pouvez simplement faire ce que vous voulez de la façon dont la machine veut le faire. En C, vous devez déterminer quelles incantations murmurer au compilateur pour qu'il écrive le code machine pour vous. Parfois, il est simplement plus facile de le faire directement. L'architecture dsPIC est particulièrement facile à écrire pour le code assembleur, certainement plus facile qu'un PIC 16.

Olin Lathrop
la source
TBLRDL et TBLRDH sont la clé ici, que vous utilisiez l'assemblage ou les __builtin_tblrdX()fonctions. Je suis d'accord avec vous + vous avez tiré un coup de pied de votre phrase "En C, vous devez comprendre quelles incantations murmurer au compilateur". Ironiquement, cependant, si vous essayez vraiment de réduire les performances maximales, les __builtin()fonctions sont parfois meilleures, car le compilateur peut optimiser la façon dont il génère du code, alors qu'il doit traiter les fonctions d'assemblage codées à la main comme des boîtes noires qu'il ne peut pas modifier. .
Jason S