Forums Casio - Autres questions

Index du Forum > Autres questions > Problème avec le SDK : système error
Shadow15510
Hors ligne
Rédacteur
Points: 1191
Défis: 15
Message
Posté le 10/08/2018 20:17

Problème avec le SDK : système error :

Bonjour !
Je sais qu'il existe plusieurs système error je vais donc essayé d'être le plus concis possible...
Lorsque je fait "Trace into" j'obtient un pop-up qui me dit : « Exécution has stopped due to an error ! Nonexisting memory by data read access at FFFFFE4»
Ensuite, la system error m'indique les infos suivantes :
-Address(W)
-Target = 08100689
-Pc = 08100689
Lors de la fin de l'émulation (bouton stop) la fenêtre "Trace" me met sur MonochromeLib.c l'endroit en PJ.
Merci d'avance


Fichier joint




Dark storm
En ligne
Administrateur
Points: 10388
Défis: 174
Message
Citer : Posté le 10/08/2018 21:54 | #
T'essaie d'accéder à une zone de mémoire non-valide. Sûrement un pointeur qui foire. N'hésite pas à mettre des breakpoints pour voir où ça merdoie. C'est peut-être le seul avantage du SDK par rapport au fxsdk
----------------------------------
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Páranÿe quetë Quendya
Lephenixnoir
Hors ligne
Administrateur
Points: 11853
Défis: 136
Message
Citer : Posté le 11/08/2018 11:43 | #
J'adore la contradiction complète entre le SDK qui dit « c'est ffff'ffe4 » et la SysERROR qui dit « c'est 0810'0689 ». Bon, tiens-toi bien Shadow, je vais tenter d'expliquer en contournant les contradictions partout...

L'erreur est ADDRESS (W), ce qui signifie que tu (ou une fonction de ML que tu as appelée) as tenté d'écrire à un endroit de la mémoire, mais que ça n'a pas marché parce que l'adresse n'est pas bonne. Alors où et pourquoi ?

Le SDK te dit que l'adresse que tu as tenté d'utiliser est ffff'ffe4 (tu as oublié un f). Pour des raisons que je vais pas expliquer, il est super peu probable qu'une écriture à cet endroit échoue.

La SysERROR dit que l'adresse en question est 0810'0689. Cette adresse se situe dans la zone de RAM qui est utilisée pour stocker les variables statiques et globales, c'est donc un endroit où tu as normalement le droit d'écrire.

Si on regarde ce qui se passe dans ML, il y a effectivement des écritures dans la mémoire à l'endroit indiqué : mais c'est dans la VRAM, et la VRAM ne devrait jamais recouvrir l'adresse 0810'0689.

Je sais de plus que si l'adresse n'existait pas, tu aurais eu une TLB ERROR et non une ADDRESS (W).

Cette erreur ADDRESS (W) est plutôt typique des accès mal alignés : quand tu écris dans la mémoire, tu écris soit 1, soit 2, soit 4 octets d'un coup. Mais quand tu écris 2 octets, tu dois le faire à une adresse multiple de 2, sinon la mémoire ne sait pas faire. Pour écrire 4 octets, il faut être sur une adresse multiple de 4. Or l'adresse 0810'0689 est impaire donc on ne peut y accéder qu'octet par octet.

Mon hypothèse est donc que tu as tenté de modifier une variable globale mais que sans faire exprès tu as causé un accès mal aligné.

-

Bon. Maintenant, il y a plusieurs choses incohérentes dans ce rapport de SysERROR : d'abord le SDK et l'OS ne sont pas d'accord sur l'adresse fautive, ensuite la valeur de PC annoncée est du bullshit.

Quitte à supposer qu'ils se sont également plantés sur l'erreur exacte, on peut penser que c'est la ligne line = bmp[i] << shift qui a planté. (Ce qui aurait dû être signalé sous la forme ADDRESS (R).)

Pourquoi ? Parce que bmp est un tableau de unsigned short autrement dit des éléments qui font tous 2 octets. On ne peut donc lire les éléments que si leur adresse est multiple de 2 : et justement, là on a un problème avec un accès à une adresse impaire.

Ma seconde hypothèse est donc : tu as déclaré ton bmp avec const unsigned char bmp[] = { ... }, ce qui signifie "un tableau dont les éléments font un octet chacun". Le compilateur a alors choisi de mettre le tableau sur une adresse impaire, ce qui est entièrement légitime mais empêche d'y accéder 2 octets par 2 octets comme le veut ML.
----------------------------------
Rise.
Shadow15510
Hors ligne
Rédacteur
Points: 1191
Défis: 15
Message
Citer : Posté le 11/08/2018 14:08 | #
... Nan, mais le BASIC Casio, c'est pas si mal en fait...

Dans le code j'utilise la fonction ML_bmp_or_cl(piece,x,y,128,64);
Où pièce est un tableau déclaré en : char pièce[ ]={0x...}; Je ne déclare par le "const unsigned" c'est de ce côté qu'il faut fouiller ?
x et y sont les coordonnées (des entiers)... Je n'y connais pas grand-choses merci de vos aides
Le coup des variables globales... Vous allez encore m'envoyer ch*** mais je met toutes mes variables en global je sais, c'est pas bien mais je le fait quand même...
----------------------------------
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Dark storm
En ligne
Administrateur
Points: 10388
Défis: 174
Message
Citer : Posté le 11/08/2018 14:15 | #
Le compilateur a alors choisi de mettre le tableau sur une adresse impaire, ce qui est entièrement légitime mais empêche d'y accéder 2 octets par 2 octets comme le veut ML.

Justement, ML_bmp_or attends bien un char* (source)
----------------------------------
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Páranÿe quetë Quendya
Shadow15510
Hors ligne
Rédacteur
Points: 1191
Défis: 15
Message
Citer : Posté le 11/08/2018 14:20 | #
Plus ça va moins ça va...
Je ne comprends pas trop comment je peux faire pour contourner l'erreur...
Par contre avant que cela plante j'avais des ML_bmp_16_or_cl(bmp,x,y);
avec "bmp" déclaré en "char"
----------------------------------
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Lephenixnoir
Hors ligne
Administrateur
Points: 11853
Défis: 136
Message
Citer : Posté le 11/08/2018 14:42 | #
... Nan, mais le BASIC Casio, c'est pas si mal en fait...

Pas d'inquiétude. Il y a peut-être 5 personnes sur ce forum qui arriveraient à suivre ce que je raconte, alors pas de panique.

Où pièce est un tableau déclaré en : char pièce[ ]={0x...}; Je ne déclare par le "const unsigned" c'est de ce côté qu'il faut fouiller ?

char signifie « un nombre sur un octet ». Avec un octet de stockage, on peut représenter 256 séquences de 0 et de 1 différentes. D'après la convention qui nous dit comment on représente des entiers avec des bits, ça fait des nombres qui peuvent aller de -128 à 127. Voilà ce qu'est un char.

unsigned signifie que les nombres négatifs ne nous intéressent pas. Dans ce cas on change la convention utilisée pour représenter les nombres ; les nombres non signés sur un char peuvent aller de 0 à 255. Ça c'est un unsigned char.

const signifie que l'on n'a pas l'intention ou le droit de modifier la variable. Cela incite le compilateur à stocker le tableau dans une zone de mémoire où on ne peut pas écrire, comme la ROM, au lieu de le mettre dans la RAM, qui est très petite et très convoitée !

Jusque-là, ça va ?

Pour une image pour MonochromeLib, ce qu'on veut, c'est juste avoir une séquence de bits (un bit par pixel avec 1=noir et 0=blanc) bien précise dans la mémoire. Mais bon, en C, on ne peut pas dire comme ça « je veux avoir la séquence 100010100101 dans la mémoire ».

Le Sprite Coder (ou outil équivalent) que tu as utilisé a généré à la place un tableau de char. Et il a mis dedans des nombres entiers bien choisis : des nombres qui, une fois représentés en binaire, donnent exactement la séquence de bits qu'il lui faut pour l'image.

Toujours bon ?

Quand MonochromeLib veut afficher l'image, elle va lire les bits de l'image dans la mémoire. Les programmes peuvent lire 1 octet, 2 octets ou 4 octets d'un coup dans la mémoire. (Soit 8 pixels, 16 pixels ou 32 pixels d'un coup.)

Pour des raisons que je n'explique pas, ML_bmp_or() lit toujours 1 seul octet (8 pixels) à la fois. Mais ML_bmp_16_or() est une fonction optimisée spécialement pour les images de 16×16. PierrotLL (l'auteur de ML) a bien compris que pouvoir lire toute une ligne en une seule opération, c'est avantageux ! Et donc ML_bmp_16_or() lit toujours 2 octets (16 pixels) à chaque étape, comme ça elle traite une ligne entière d'un coup !

Tu respires encore ? Mettons une checkpoint là, je n'ai pas tout à fait fini, mais mieux vaut que j'explique ça d'abord. Si tu as des questions, lâche-toi !

L'explication et la solution au prochain post. T'inquiète ça va être très simple à résoudre. :3

Le coup des variables globales... Vous allez encore m'envoyer ch*** mais je met toutes mes variables en global je sais, c'est pas bien mais je le fait quand même...

C'est pas si grave, mais n'oublie pas d'apprendre un jour pourquoi tu dois aussi utiliser des locales...

Dark Storm a écrit :
Justement, ML_bmp_or attends bien un char*

On parle de ML_bmp_16_or_cl() là ;D
----------------------------------
Rise.
Shadow15510
Hors ligne
Rédacteur
Points: 1191
Défis: 15
Message
Citer : Posté le 11/08/2018 14:46 | #
J'ai plutôt bien compris je pense... En tout cas ça me rassure d'entendre (de lire) que le problème est simple à résoudre.
----------------------------------
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Lephenixnoir
Hors ligne
Administrateur
Points: 11853
Défis: 136
Message
Citer : Posté le 11/08/2018 15:43 | #
En fait, j'ai déjà expliqué tout ce qu'il faut. Voilà la fin.

Je rappelle qu'une adresse dans la mémoire correspond à un octet. En face de chaque adresse, un octet. Une variable qui prend deux octets prend deux places consécutives aux adresses n et n + 1.

Alright?

Quand tu fais un tableau de char, tu annonces au compilateur que tu vas accéder à un élément à la fois, soit 1 octet à la fois... et comme je l'ai dit précédemment, tu peux lire un octet à n'importe quelle adresse, donc le compilateur est libre de mettre ton tableau où il veut dans la mémoire, sur n'importe quelle adresse.

Quand tu fais un tableau de short, tu annonces au compilateur que tu vas accéder à un élément à la fois, soit 2 octets à la fois... et tu ne peux lire 2 octets d'un coup que sur des adresses paires. Donc le compilateur va faire attention à mettre ton tableau sur une adresse paire. Comme ça, chaque short du tableau occupe deux adresses consécutives n et n + 1, où n est pair. Car on ne peut lire 2 octets d'un coup que si on commence à une adresse paire.

Quand tu fais un tableau de int, tu annonces au compilateur que tu vas accéder à un élément à la fois, soit 4 octets à la fois... et tu ne peux lire 4 octets d'un coup que sur des adresses multiples de 4. Donc le compilateur va faire attention à mettre ton tableau sur une adresse multiple de 4, car on ne peut lire les 4 octets aux adresses n, n + 1, n + 2 et n + 3 d'un coup que si n est multiple de 4.

Toujours bon ?

ML_bmp_16_or() prend en paramètre un tableau de short, donc aligné sur une adresse paire. Or tu lui as donné un tableau de char... qui peut être n'importe où, et ici pas de bol, il est sur une adresse impaire ! Diantre !

Quand ML_bmp_16_or() veut lire le premier élément, il fait bmp[0], et ça veut dire « lis-moi deux octets consécutifs au début du tableau ». Ça veut dire les deux octets aux adresses bmp et bmp + 1. Et ça tu ne peux le faire que si bmp est une adresse paire, or elle est impaire... vraiment pas de bol !

Il est temps de conclure.

La "vraie" solution serait de faire en sorte que ton tableau commence à une adresse paire. Mais sans toucher au code, ben, c'est un peu difficile.

La solution rapide c'est d'utiliser ML_bmp_or() à la place, car cette fonction-là n'essaie jamais de lire 2 octets d'un coup dans ton tableau. Tant pis si c'est moins optimisé
----------------------------------
Rise.
Shadow15510
Hors ligne
Rédacteur
Points: 1191
Défis: 15
Message
Citer : Posté le 11/08/2018 15:53 | #
j'essaye ça tout de suite

C'est bon : ça marche
----------------------------------
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Ninestars
Hors ligne
Membre
Points: 1984
Défis: 22
Message
Citer : Posté le 12/08/2018 00:43 | #
Merci pour toutes ces précisions ! Ça va m'aider à interpréter des erreurs.
Du coup quand on cast un char en int, si le char n'est pas aligné sur un multiple de 4 ça plante aussi ? Je pense pas sinon ça arriverait bien plus souvent je suppose.
Tu es un vrai romancier quand il s'agit d'expliquer en plus toi, c'est très clair
----------------------------------
Dark storm
En ligne
Administrateur
Points: 10388
Défis: 174
Message
Citer : Posté le 12/08/2018 12:03 | #
Non, je pense justement que le cast permet de réaligner la donnée. À l'inverse, ceci devrait planter.

char c = 42;
char *ptrc = &c;
int *ptri = ptrc;
*ptri = 43;


(Avec confirmation de Lephe, je suis pas sûr de ce que j'avance)
----------------------------------
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Páranÿe quetë Quendya
Lephenixnoir
Hors ligne
Administrateur
Points: 11853
Défis: 136
Message
Citer : Posté le 12/08/2018 14:39 | #
Ninestars a écrit :
Merci pour toutes ces précisions ! Ça va m'aider à interpréter des erreurs.

Je savais que je ne perdais pas mon temps

Du coup quand on cast un char en int, si le char n'est pas aligné sur un multiple de 4 ça plante aussi ? Je pense pas sinon ça arriverait bien plus souvent je suppose.

Non, caster un char en int, ça ne se fait pas dans la mémoire. Ça revient à charger le char dans un registre et ensuite faire une extension de signe pour obtenir une représentation de la même valeur numérique, mais sur 32 bits. Ça ne plantera jamais.

Dark storm a écrit :
Non, je pense justement que le cast permet de réaligner la donnée. À l'inverse, ceci devrait planter.

char c = 42;
char *ptrc = &c;
int *ptri = ptrc;
*ptri = 43;

Voilà, tu as compris le principe. Après il est possible que c soit placé sur une adresse multiple de 4. Et en l'occurrence c est une variable locale, donc placée sur la pile, donc elle très probablement sur une adresse multiple de 4. Ce code risquerait donc bien de marcher.

Sous GCC on peut forcer l'alignement d'une variable à n (si n est une puissance de 2) avec l'attribut :

__attribute__((aligned(n)))
----------------------------------
Rise.


Index du Forum > Autres questions > Problème avec le SDK : système error

Planète Casio v42 © créé par Neuronix et Muelsaco 2004 - 2018 | Il y a 36 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire indépendant, géré bénévolement et n'est donc pas affilié à Casio | Toute reproduction de Planète Casio, même partielle, est interdite
Les fichiers, programmes et autres publications présents sur Planète Casio restent la propriété de leurs auteurs respectifs et peuvent être soumis à des licences ou des copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd