J'essaye d'écrire un programmateur préemptif pour AVR et donc j'ai besoin d'un peu de code assembleur ... mais je n'ai aucune expérience avec l'assembleur. Cependant, j'ai écrit tout le code assembleur dont je pense avoir besoin dans certaines macros C. A la compilation j'obtiens quelques erreurs liées à l'assembleur (valeur constante requise et garbage at et of line), ce qui me fait penser que quelque chose n'est pas correct dans mes macros ...Macros en ligne assembleur C pour un AVR RTOS
La macro suivante, load_SP (some_unsigned_char, some_unsigned_char) , positionne le pointeur de la pile sur un emplacement de mémoire connu ... Je garde l'emplacement dans la structure globale aux aux; Quelque chose de similaire est avec load_PC (...) qui charge sur la pile, un compteur de programme: "func_pointer" qui est en fait, comme son nom l'indique, un pointeur vers une fonction. Je suppose ici que le compteur de programme ainsi que le pointeur de fonction sont représentés sur 2 octets (car le flash est assez petit)
Pour cela j'utilise le registre de processeur R16. Afin de ne pas toucher à ce registre, j'enregistre d'abord sa valeur avec la macro "save_R16 (tempR)" et la restauration de sa valeur avec la macro "load_R16 (tempR)" où "tempR" peut être vu comme une variable C globale .
Ceci est simplement écrit dans un fichier d'en-tête. Ceci avec deux autres macros (pas écrites ici en raison de leur taille) "pushRegs()" et "popRegs()" qui poussent et puis éclatent tous les registres des processeurs est TOUS mon code assembleur ...
Je fais pour corriger mes macros?
// used to store the current StackPointer when creating a new task until it is restored at the
// end of createNewTask function.
struct auxSP
{
unsigned char auxSPH;
unsigned char auxSPL;
};
struct auxSP cSP = {0,0};
// used to restore processor register when using load_SP or load_PC macros to perform
// a Stack Pointer or Program Counter load.
unsigned char tempReg = 0;
////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// assembler macros begin ////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// save processor register R16
#define save_R16(tempR) \
asm volatile( \
"STS tempR, R16 \n\t" \
);
// load processor register R16
#define load_R16(tempR) \
asm volatile( \
"LDS R16, tempR \n\t" \
);
// load the Stack Pointer. Warning: Alters the processor registers
#define load_SP(new_SP_H, new_SP_L) \
asm volatile( \
"LDI R16, new_SP_H \n\t" \
"OUT SPH, R16 \n\t" \
"LDI R16, new_SP_L \n\t" \
"OUT SPL, R16 \n\t" \
);
// load the Program Counter on stack. Warning: Alters the processor registers
#define load_PC(func_pointer) \
asm volatile( \
"LDS r16, LOW(func_pointer) \n\t" \
"PUSH r16 \n\t" \
"LDS r16, HIGH(func_pointer) \n\t" \
"PUSH r16 \n\t" \
);
Lisez dans la documentation de gcc comment utiliser les paramètres C et variobles dans l'assemblage en ligne. –
Pour un changement de thread réussi, vous devez restaurer ** tous ** les registres à l'état dans lequel ils se trouvaient lorsque vous avez interrompu le thread. Cela signifie que votre routine d'interruption de minuterie doit non seulement enregistrer tous les registres qu'elle voit, mais inspecter la pile pour récupérer les valeurs qui y sont poussées par la logique matérielle d'interruption (la bonne valeur pour le PC est là). Le prologue ISR généré par le compilateur pousse également certaines valeurs sur la pile. L'ordre dans lequel les registres sont restaurés est également d'une importance cruciale. –
@MichaelRoy Comme mentionné, il y a les macros pushRegs() qui poussent tous les registres de la pile et popRegs() qui font apparaître tous les registres de la pile. Ces macros sont utilisées dans d'autres fonctions ... –