Idée de projet - add-in pour debug
Posté le 28/05/2018 20:01
salut;
Je sais pas si vous programmez sur Casio mais si c’est le cas vous devez savoir à quel point programmer dessus c’est pratique: on programme un jeu, on le compile, on vérifie sur l’Émulateur si tout fonctionne, si tout fonctionne on le transfère sur la calto puis on peut transporter son jeu de partout.
Problématique
Si vous programmez un gros jeu il est possible que des petits bugs apparaissent APRÈS avoir compilé qui font planter la Casio.
Et pourtant le jeu fonctionnait sur l’Émulateur sauf que l’Émulateur ne sera jamais comme la console.
Et c’est là que ça devient méga chiant parce que, modifier un octet, compiler, connecter la calto et voir que ça ne fonctionne pas...on vient de perdre 5 minutes de notre vie à brasser de l’aire.
De plus si vos faites des jeux en multijoueur on ne peut pas vérifier via l’Émulateur, il faut donc tout se taper et c’est...long, trop long.
Idée
C’est pourquoi une idée m’est venue alors que j’écrivais la librairie “mySerail.h”.
Pourquoi ne pas créer un add-in qui récupère les données via le port USB puis exécute le jeu à la fin du transfère ?
Pour résumer éviter d’aller dans “LINK”, et attendre que la calto se connecte à l’ordi, attendre que l’add-in soit transféré.
En gros avoir un add-in de debug qui nous permet de ne pas avoir à toucher à la console pour tester ses programmes.
Théorie
Pour ça il nous faut une connexion directe entre la Casio et le PC...bon ya un port USB donc c’est rapide.
L’add-in se met directement en ‘Receive’ (elle attend un fichier).
Ensuite on vérifie s'il y a assez de place dans la RAM.
Si ya assez de place, on met tout le programme dans la RAM, puis on l’exécute.
(c’est tellement simple à dire^^)
Pourquoi la RAM ?
C’est un add-in de debug je vous rappelle donc on s’en fout que le programme soit stocké dans la ROM.
De plus la RAM est rapide à écrire, bien plus rapide que le ROM.
Possible ?
Oui MAIS seulement des petits programmes car la ‘vrai’ RAM disponible sur SH4 est de 12 ko (d’après
la doc de
Lephenixoir) OU 64 ko (d’après le
wiki).
Donc bon...
Oublions 2 secondes la taille de la RAM et le fait qu’il y en est pas autant sur les SH3 que sur le SH4.
1.On sait communiquer via le port USB (exemple :
P7 de
Cakeisalie5), du moins on sait communiquer PC->Casio par contre il me semble pas avoir entendu parler de syscall permettant de jouer avec le port USB (j’ai chercher mais je n'ai rien comprit
).
2.On sait exécuter du code Assembleur depuis la RAM (#sysCall) (
gint fait ça merveilleusement bien aussi <3).
3.On sait faire des interfaces par dégueux.
Donc oui c’est possible !
Es-ce que j’ai commencer a faire un truc ?
Non, déjà parce que j'ai pas beaucoup de temps en ce moment et j’ai déjà plusieurs projets à finir.
C’est juste pour signaler que c’est théoriquement possible donc s'il y a des personnes intéressées par ce projet...bah allez-y ça pourrait être sympa et il y a sûrement beaucoup de choses à apprendre
.
Citer : Posté le 14/12/2018 22:49 | #
Attention à ne pas mettre des ABSOLUTE() partout, tous les symboles b* et e* doivent en être exempts sinon tu ne sauras pas où copier dans la RAM !
Pas besoin de volatile durant ta copie, les données ne vont pas changer dans ton dos.
Pour caricaturer, on peut dire que c'est la section où on met tout ce qui est initialisé à 0. Il est absolument indispensable de la mentionner dans le linker script car c'est ce qui permet aux symboles dedans d'avoir des adresses assignées. Cependant, les valeurs à proprement parler ne sont que des 0, donc on ne garde pas cette section dans l'ELF. On la vire et on génère les zéros à la main au début de l'exécution.
Ah oui mais c'est le kernel de FiXos là, contrairement à ton add-in il ne rend pas la main au système à la fin de l'exécution. Tu ne peux pas te permettre autant de largesses si tu veux revoir un jour le menu principal...
Citer : Posté le 24/12/2018 22:59 | #
Ah oui mais c'est le kernel de FiXos là, contrairement à ton add-in il ne rend pas la main au système à la fin de l'exécution. Tu ne peux pas te permettre autant de largesses si tu veux revoir un jour le menu principal...
Effectivement ça peut être problématique en effet
J'ai continué mon linker script, contrairement à avant, là j'arrive à compiler mais seulement j'ai un problème de taille. À la sortie mon .bin fait 132120097 octets, ce qui est légèrement beaucoup trop mon gout (je sais très bien qu'il y a un problème, surtout que pour l'instant l'add-in ne dépassent pas les 16 ko).
Je suppose que cela vient sois des ABSOLUTES() ou des AT() ou d'une section qui se multiplie, seulement, je ne suis absolument pas sur de moi.
Tu as une idée d'où ça peut venir ? (le.pretext je pense (?)).
voila le linker script.
OUTPUT_ARCH(sh3)
ENTRY(_bootstrap)
MEMORY
{
rom : o = 0x00300200, l = 512k
ram : o = 0x08100000, l = 8k
my_ram : o = 0x8800d000, l = 12k
}
SECTIONS
{
.text : {
*(.pretext)
*(.pretext.*)
*(.text)
*(.text.*)
_etext = . ;
} > rom
.rodata : AT(_etext) {
*(.rodata)
*(.rodata.*)
_erodata = . ;
} > rom
.bss : AT(_erodata) {
_bbss_rom = ABSOLUTE (.) ;
_bbss_ram = . ;
*(.bss)
*(.bss.*)
_bss_size = SIZEOF(.bss) ;
_ebss = ABSOLUTE (.) ;
} > ram
.data : AT(_ebss) {
_bdata_rom = ABSOLUTE (.) ;
_bdata_ram = . ;
*(.data)
*(.data.*)
_data_size = SIZEOF(.data) ;
_edata = ABSOLUTE (.) ;
} > ram
/*
* RAM section witch set my interupt handler.
* vbr + 0x100 -> exeption interupt.
* vbr + 0x400 -> tlb miss.
* vbr + 0x600 -> other interupt.
*/
.glados : AT(_edata) ALIGN(4) {
. = ALIGN(0x100) ;
_glados_vbr = . ;
_bglados_rom = ABSOLUTE (.) ;
_bglados_ram = . ;
. = _glados_vbr + 0x100 ;
*(.glados.exept)
. = _glados_vbr + 0x400 ;
*(.glados.tlb)
. = _glados_vbr + 0x600 ;
*(.glados.interupt)
. = ALIGN(4) ;
_glados_size = SIZEOF(.glados) ;
} > my_ram
}
voila le crt0.c:
#include "../../include/stream.h"
extern int main(void);
extern void __save_stuff(void);
extern void __restore_stuff(void);
extern uint32_t bbss_ram;
extern uint32_t bbss_rom;
extern uint32_t bss_size;
extern uint32_t bdata_ram;
extern uint32_t bdata_rom;
extern uint32_t data_size;
extern uint32_t bglados_ram;
extern uint32_t bglados_rom;
extern uint32_t glados_size;
extern uint32_t glados_vbr;
__attribute__((section(".pretext"))) static void section_dump(void *bsection_ram,
void *bsection_rom, int section_size_dump)
{
uint32_t *ram_section = (uint32_t*)bsection_ram;
uint32_t *rom_section = (uint32_t*)bsection_rom;
int i;
i = -1;
while (++i < section_size_dump)
*ram_section++ = *rom_section++;
}
__attribute__((section(".pretext"))) int bootstrap(void)
{
int exit;
section_dump(&bbss_ram, &bbss_rom, bss_size);
section_dump(&bdata_ram, &bdata_rom, data_size);
section_dump(&bglados_ram, &bglados_rom, glados_size);
init_stream();
__save_stuff();
exit = main();
__restore_stuff();
quit_stream();
return (exit);
}
Ce que je trouve bizarre c'est que mon .elf fait 47 ko donc je comprends pas pourquoi le .bin est aussi volumineux >_<
Citer : Posté le 24/12/2018 23:11 | #
Ça, c'est faux je pense. Utilise -Wl,-M pour voir la valeur du symbole : il est dans la RAM. .data : AT(_erodata + sizeof(.bss)) devrait marcher mieux.
L'ELF donne une liste de section/adresses. Le binaire n'a pas ce format-là, il doit reproduire tel quel la structure de la mémoire. Donc si tu as des données chargées de façon pas continue, il doit reproduire les trous.
Citer : Posté le 26/12/2018 22:29 | #
Ça, c'est faux je pense. Utilise -Wl,-M pour voir la valeur du symbole : il est dans la RAM. .data : AT(_erodata + sizeof(.bss)) devrait marcher mieux.
Effectivement ça fonctionne, seulement maintenant j'ai une erreur.
Une erreur de copy (TARGET=00000001 PC=880023f94), avec les flags que tu m'as donné je trouvé rien à l'address PC (normal) mais surtout le TARGET signifie que le linkage n'a pas fonctionné (du moins je pense) mais je n'ai aucune idée d'où ça peut venir. Les sections sont aux bonnes address et bien alignées...
Mon crt0.c ne contient rien à part un return (0)... bref je sais absolument par où chercher ni quoi faire, dans le doute je mets mon linker car l'erreur viens forcement de lui.
OUTPUT_ARCH(sh3)
ENTRY(_bootstrap)
MEMORY
{
rom : o = 0x00300200, l = 512k
ram : o = 0x08100000, l = 8k
my_ram : o = 0x8800d000, l = 12k
}
SECTIONS
{
.text : {
*(.pretext)
*(.pretext.*)
*(.text)
*(.text.*)
} > rom
.rodata : {
*(.rodata)
*(.rodata.*)
_erodata = ABSOLUTE (.) ;
} > rom
.bss : AT(_erodata) {
_bbss_rom = ABSOLUTE (.) ;
_bbss_ram = . ;
*(.bss)
*(.bss.*)
_bss_size = SIZEOF(.bss) ;
} > ram
.data : AT(_erodata + SIZEOF(.bss)) {
_bdata_rom = ABSOLUTE (.) ;
_bdata_ram = . ;
*(.data)
*(.data.*)
_data_size = SIZEOF(.data) ;
} > ram
/*
* RAM section witch set my interupt handler.
* vbr + 0x100 -> exeption interupt.
* vbr + 0x400 -> tlb miss.
* vbr + 0x600 -> other interupt.
*/
.glados : AT(_erodata + SIZEOF(.bss) + SIZEOF(.data)) ALIGN(4) {
. = ALIGN(0x100) ;
_glados_vbr = . ;
_bglados_rom = ABSOLUTE (.) ;
_bglados_ram = . ;
. = _glados_vbr + 0x100 ;
*(.glados.exept)
. = _glados_vbr + 0x400 ;
*(.glados.tlb)
. = _glados_vbr + 0x600 ;
*(.glados.interupt)
. = ALIGN(4) ;
_glados_size = SIZEOF(.glados) ;
} > my_ram
}
Citer : Posté le 26/12/2018 22:39 | #
J'insiste, encore et toujours, utilise -Wl,-M. Ça t'affiche une carte de la mémoire après linkage, la valeur de tous les symboles que tu as créés, et ça te permet de voir les erreurs d'alignement. Si tu n'y arrives pas, montre-moi l'erreur, mais sans ça tu ne t'en sortiras pas (et moi non plus) !
Alternativement tu peux utiliser readelf ou objdump mais tu aurais moins d'infos.
Citer : Posté le 27/12/2018 21:19 | # | Fichier joint
J'insiste, encore et toujours, utilise -Wl,-M. Ça t'affiche une carte de la mémoire après linkage, la valeur de tous les symboles que tu as créés, et ça te permet de voir les erreurs d'alignement. Si tu n'y arrives pas, montre-moi l'erreur, mais sans ça tu ne t'en sortiras pas (et moi non plus) !
Après quelques heures de tests et débuggage je n'arrive définitivement pas à trouver la source du problème.
Surement un alignement qui foire, mais même en forçant l'alignement de chaque section je n'arrive à rien, toujours la même erreur.J'ai réduit mon add in le plus possible et voila la carte mémoire (en fichier joint).
EDIT: en mettant le fichier joint je suis re-tomber sur la ligne 79 et 183:
OUTPUT(test.elf elf32-sh)
.comment 0x0000000000000000 0x11
.comment 0x0000000000000000 0x11 src/core/bootstrap.o
0x12 (size before relaxing)
Aurais-je oublié la section .comment ? quel est le rôle de cette section ?
Citer : Posté le 27/12/2018 23:18 | #
La section .comment est inutile, elle ne contient que des petits commentaires genre "généré par GCC".
Clairement, ça c'est faux, ça devrait être égal à... _erodata. Ça n'explique pas le crash, mais c'est quelque chose. Pareil pour tous les autres symboles *_rom. D'ailleurs j'ai dis il y a pas longtemps...
Attention à ne pas mettre des ABSOLUTE() partout, tous les symboles b* et e* doivent en être exempts sinon tu ne sauras pas où copier dans la RAM !
Sinon, regarde mieux ce que t'a donné -Wl,-M. Le code d'entrée qui est exécuté n'est pas celui que tu crois. L'ordre compte
Citer : Posté le 29/12/2018 20:07 | # | Fichier joint
Clairement, ça c'est faux, ça devrait être égal à... _erodata. Ça n'explique pas le crash, mais c'est quelque chose. Pareil pour tous les autres symboles *_rom. D'ailleurs j'ai dis il y a pas longtemps...
Mmmmm...après un début de relecture de info ld (qui m'a appris beaucoup de choses) j'utilise LOADADDR() au lieu de ABSOLUTE() car qui me donne l'addresse de dépars d'une section. (la LMA et non la VMA) (ce qui m'a fait réaliser que j'ai incroyablement rien compris de l'utilité de ABSOLUTE()... >_< ).
Du coup j'ai réécrit mon linker, ce qui donne ça;
OUTPUT_ARCH(sh3)
ENTRY(_bootstrap)
MEMORY
{
rom : o = 0x00300200, l = 512k
ram : o = 0x08100000, l = 8k
my_ram : o = 0x8800d000, l = 12k
}
SECTIONS
{
.text : ALIGN(4) {
*(.pretext)
*(.pretext.*)
*(.text)
*(.text.*)
} > rom
.rodata : ALIGN(4) {
*(.rodata)
*(.rodata.*)
_erodata = . ;
} > rom
.bss : AT(_erodata){
_bbss_ram = . ;
*(.bss)
*(.bss.*)
*(COMMON)
_bss_size = SIZEOF(.bss) ;
_bbss_rom = LOADADDR(.bss) ;
} > ram
.data : AT(_erodata + SIZEOF(.bss)) ALIGN (4){
*(.data)
*(.data.*)
_data_size = SIZEOF(.data) ;
_bdata_rom = LOADADDR(.data) ;
} > ram
/*
* RAM section witch set my interupt handler.
* vbr + 0x100 -> exeption interupt.
* vbr + 0x400 -> tlb miss.
* vbr + 0x600 -> other interupt.
*/
.glados : AT(_erodata + SIZEOF(.bss) + SIZEOF(.data)) ALIGN(4) {
. = ALIGN(0x100) ;
_glados_vbr = . ;
_bglados_ram = . ;
. = _glados_vbr + 0x100 ;
*(.glados.exept)
. = _glados_vbr + 0x400 ;
*(.glados.tlb)
. = _glados_vbr + 0x600 ;
*(.glados.interupt)
. = ALIGN(4) ;
_glados_size = SIZEOF(.glados) ;
_bglados_rom = LOADADDR(.glados) ;
} > my_ram
}
Le problème se trouve au niveau du dump de .data et de la mise à 0 de la section .bss, je plante toujours au même endroit, pour l'instant j'aimerait juste mettre .bss a 0 mais j'ai ce plantage (TARGET=00304000 ; PC =08100004).
Autant 08100004 ça correspond à la fin de la section .bss (ou au début de .data vu qu'elles se suivent) mais 00304000 correspond... à la fin de l'add-in visiblement.
Après plusieurs tests je me rend compte que c'est SIZEOF() qui foire >_< . Pourtant d'après la mémory map (fichier joint) le _bss_size me semble correcte (4o car il n'y a qu'une seule et même addresse dans .bss).
D'un autre côté j'ai essayé plusieurs façons d'avoir _bss_size:
(int32_t)&bss_size ------> plante à 00304000
(int32_t)bss_size --------> plante à 55555555
Et d'après info ld il faut bien faire la première façon, donc je ne sais pas pourquoi ça marche pô
Attention à ne pas mettre des ABSOLUTE() partout, tous les symboles b* et e* doivent en être exempts sinon tu ne sauras pas où copier dans la RAM !
Sinon, regarde mieux ce que t'a donné -Wl,-M. Le code d'entrée qui est exécuté n'est pas celui que tu crois. L'ordre compte
Merci ! <3 Effectivement, je n'avais pas fait gaffe mais section_dump() était placée avant bootstrap() (d'ailleurs je ne suis pas sur que crt0.s soit véritablement un bootstap xD )
Ce que je ne comprends pas c'est pourquoi il le linkait comme ça alors que j'avais mis ENTRY(_bootstrap) >_< m'enfin bon, l'important c'est que c'est réglé
Du coup si tu peux m'expliquer à quoi sert ABSOLUTE() parce que, pour le coup, je pensais que ça donnait la valeur de la LMA et non la VMA mais visiblement ce n'est pas le cas (je n'ai pas encore fini de lire info ld ).
Citer : Posté le 29/12/2018 21:55 | #
De base quand tu définis un symbole à l'intérieur d'une section, sa valeur est prise relativement à l'adresse de la section. ABSOLUTE() change ça. C'est encore un peu obscur pour moi, par contre je peux te dire que quand tu fais objdump -t (affiche la liste des symboles), les symboles sont soit liés à une section (auquel cas le nom de la section s'affiche), soit absolus (auquel cas *ABS* est affiché). La différence me paraît subtile...
C'est bien la première façon qu'il faut faire, sache que la deuxième correspond à lire la mémoire à l'adresse bss_size.
Ah, oui, alors en fait ENTRY() ça marche pour les ELF, mais en binaire pur c'est vraiment le début du code qui est exécuté en premier. D'où l'intérêt d'avoir .pretext. Si tu as ENTRY() alors .pretext n'est pas nécessaire, tu peux tout mettre dans .text.
Tu as juste pour LOADADDR(), si tu as trop de doutes jette un oeil aux scripts de gint, qui... marchent (normalement, ça fait un moment que je les ai pas testés).
---
Je reviens sur le point principal, ton linker script. Actuellement tu peux simplifier par mal la chose : la section .bss n'a en effet pas besoin de résider dans la ROM (il n'y a que des zéros). Donc, par exemple, tu as des simplifications dans ce genre :
Du reste la façon dont tu calcules tes adresses est juste, d'ailleurs le résultat de -Wl,-M le montre bien. Je vois deux problèmes potentiels :
Ceci n'est pas un multiple de 4.
Ceci n'est pas chargé à une adresse multiple de 4.
Tu peux régler tout ça avec les bons paramètres d'alignment, que je ne connais pas par coeur (c'est un peu compliqué parce que tu as des alignments internes et externes et j'ai parfois besoin de deux), là aussi les scripts de gint contiennent la solution.
Ajouté le 29/12/2018 à 21:57 :
Aussi : info ld est exactement la doc qu'il faut utiliser ici, bien joué.
Citer : Posté le 06/01/2019 20:14 | # | Fichier joint
C'est bon j'ai réussi à lancer mon add in (Le problème venait de SIZEOF() et des quelques fonctions mal alignées ).
Maintenant j'aimerait mettre ma VBR à la place de celle de Casio (sans la perdre, pour pouvoir la restaurer avant de quitter l'add in). Au début j'ai simplement fait un ldc r4, VBR mais la calto plantait, puis je me suis dit "Ha, mais si ça se trouve, quand je mets ma VBR et qu'il y a une interruption pile à ce moment-là, la calto doit planter". Donc j'ai opté pour ce code:
sts.l PR, @-r15
mov.l SR_pause, r0
stc SR, r3
or r0, r3
ldc r3, SR
ldc r4, VBR
mov.l SR_pause, r0
not r0, r0
and r0, r3
ldc r3, SR
lds.l @r15+, PR
rts
nop
.align 4
SR_pause .long 0x10000000
Et Bingo ça a marché, plus de plantage. (EDIT: cela venait d'une fonction ma aligner ).
Je voulais être sûr que les interruptions fonctionnaient encore, donc je voulais mettre un compteur qui m'aurait donné une idée du nombre d'interruption par seconde .
Le problème c'est que le compteur s'incrémente jamais, et quand j'essaie de toucher au clavier (car je sais que se génère masse d'interruption) la calto plante >_< .
J'ai donc forcé le truc en mettant:
rts
ldc r4, VBR
et le compteur s'incrémente toujours pas pourtant je ne bloque pas les interruptions... je suis un peu à court d'idées je dois avouer
je suis sur qu'il me manque un truc tout bête pour ça fonctionne...
(j'ai mis en fichier le .c qui fonctionne pas ainsi que la memory map)
Désoler de demander autant d'aide
Citer : Posté le 06/01/2019 20:18 | #
Pas mal ta fonction, c'est propre. Il y a sans doute quelques autres flags que tu veux mettre dans SR (je n'ai plus les détails mais gint en active d'autres). Bien en tous cas
Ben c'est pas compliqué, quand tu appuies sur une touche ça lance ton gestionnaire d'interruptions, idem après un certain délai à cause de la RTC. L'interruption sera générée en continue tant que tu ne l'auras pas validée en mettant un bit de registre spécifique à 0. Quel bit et quel registre dépend de l'interruption en question.
Tu as donc deux choix :
1. Tu coupes l'interruption entre le moment où tu changes la VBR et le moment où tu remets les interruptions (et tu restaures en revenant au système)
2. Tu gères l'interruption.
Citer : Posté le 25/01/2019 20:14 | # | Fichier joint
Bon après une petite pause, j'ai repris le projet et le nettoyant un peu.
Et j'ai toujours le problème du plantage.
Je pense que ça viens de mon crt0.c ou de mon interrupt handler mais je n'en suis pas sûr, car d'après la memory map tout est à sa place et alignés.
Cette fois-ci j'utilise les Interrupt Request Register (IRR*) et je les mets tous a 0.
Ensuite je mets ma VBR (tout son passe bien et je peux afficher un compteur a l'écran par exemple ou brancher un câble USB).
Mais dès que je touche au clavier, la calto plante en affichant des lignes horizontales (quelques frames).
Donc je me suis dit que cela venait de mon interrupt handler qui n'est pas là où pointe ma VBR, mais ça me semble peu probable car il n'y a pas que le clavier qui génère des interruptions donc elle devrait planter avant non ?
Ou alors mes addresses des registres IRR* ne sont pas bonnes:
#ifndef __7705_H__
# define __7705_H__
#define __TRA 0xffffffd0
#define __EXPEVT 0xffffffd4
#define __INTEVT 0xffffffd8
#define __INTEVT2 0xa4000000
#define __TEA 0xfffffffc
#define __IRR0 0xa4000004
#define __IRR1 0xa4000006
#define __IRR2 0xa4000008
#endif
Je te mets en fichier joint mon crt0.c, mon interrupt handler ('fin le truc qui plante) et mon linker. (ou essaie ce repo (comme il est en priver je sais pas si tu peux lire ce qu'il y a dessus )).
Citer : Posté le 25/01/2019 21:20 | #
Juste quelques remarques.
Quel est l'idée derrière tout ça ? stddef.h est fourni par le compilateur, et ça ne me paraît pas une bonne idée de ne pas utiliser ce qu'il te donne quand c'est lui qui compile.
{
interrupt_counter++;
}
Les interruptions ne marchent pas comme ça, il y a des conventions d'appels particulières, une autre banque de registres et l'instruction de clôture est rte au lieu de rts. Actuellement, je peux te garantir que tu crashes à la première interruption. Si tu ne veux pas écrire tes gestionnaire en assembleur, il faut au moins spécifier à GCC d'utiliser les bonnes conventions d'appel :
void exeption_handler(void)
{
interrupt_counter++;
}
Quoi d'autre...
*irr1 = 0;
*irr2 = 0;
Les IRR sont en lecture seule, si tu espères accuser réception des interruptions il faut aller chercher les bits dans les registres des modules qui émettent les interruptions, individuellement (sauf pour les IRQ qui sont bel et bien dans IRR0, mais on n'en utilise pas).
Tu travailles sur SH3 ?
Pour désactiver les interruptions il faut toucher aux IPR*, essentiellement il faut tous les mettre à 0x0000, excepté bien sûr pour les interruptions que tu gères, et n'oublie pas de restaurer leur valeur quand tu as fini, sinon le système ne va pas aimer.
Citer : Posté le 25/01/2019 23:06 | #
Quel est l'idée derrière tout ça ? stddef.h est fourni par le compilateur, et ça ne me paraît pas une bonne idée de ne pas utiliser ce qu'il te donne quand c'est lui qui compile.
Comme on mettais --nostdlib je me suis dit qu'on ne devait pas avoir stddef.h xD
Les interruptions ne marchent pas comme ça, il y a des conventions d'appels particulières, une autre banque de registres et l'instruction de clôture est rte au lieu de rts. Actuellement, je peux te garantir que tu crashes à la première interruption. Si tu ne veux pas écrire tes gestionnaire en assembleur, il faut au moins spécifier à GCC d'utiliser les bonnes conventions d'appel :
J'avais totalement oublié rte, j'etais tellement focalisé sur le compteur que j'ai tout fait de travers >_<
Et je savais pas qu'il était possible de le préciser à GCC, merci
Ce qu'on a spécifié à GCC ne fait qu'un rte au lieu d'un rts ? (ceci-dit je vais être vite fixé avec objdump... ).
Du coup est-ce qu'il faut que je remette SSR dans SR et SPC dans PC avant de quitter mes handlers ?
Les IRR sont en lecture seule, si tu espères accuser réception des interruptions il faut aller chercher les bits dans les registres des modules qui émettent les interruptions, individuellement (sauf pour les IRQ qui sont bel et bien dans IRR0, mais on n'en utilise pas).
mais je suis débile, en plus je l'ai marqué dans mes notes >___<
Tu travailles sur SH3 ?
Non... du coup je suppose que les addresses sont absolument fausses x)
Juste pour être sûr: 7705 -> SH3 && 7305 -> SH4
(J'ai encore une fois...tout confondu )
Pour désactiver les interruptions il faut toucher aux IPR*, essentiellement il faut tous les mettre à 0x0000, excepté bien sûr pour les interruptions que tu gères, et n'oublie pas de restaurer leur valeur quand tu as fini, sinon le système ne va pas aimer.
J'ai inversé IRR* avec IPR* on dirait... (Il faut que j'arrête de vouloir aller trop vite >_< ).
Citer : Posté le 25/01/2019 23:38 | #
Comme on mettais --nostdlib je me suis dit qu'on ne devait pas avoir stddef.h xD
λ ls opt/sh4eb-nofpu-elf-2.31.1-8.2.0/lib/gcc/sh4eb-nofpu-elf/8.2.0/include*
opt/sh4eb-nofpu-elf-2.31.1-8.2.0/lib/gcc/sh4eb-nofpu-elf/8.2.0/include:
gint gcov.h stdalign.h stdatomic.h stddef.h stdint-gcc.h stdnoreturn.h unwind.h
float.h iso646.h stdarg.h stdbool.h stdfix.h stdint.h tgmath.h varargs.h
opt/sh4eb-nofpu-elf-2.31.1-8.2.0/lib/gcc/sh4eb-nofpu-elf/8.2.0/include-fixed:
limits.h README syslimits.h
Non, il y a d'autres différences, que tu peux trouver en te baladant dans le chapitre de gestion des exceptions de la doc du MPU.
Non, car c'est exactement ce que rte fait.
Juste pour être sûr: 7705 -> SH3 && 7305 -> SH4
(J'ai encore une fois...tout confondu )
Tu n'as pas confondu, mais les IRR n'existent que sur SH3.
Citer : Posté le 28/01/2019 19:42 | # | Fichier joint
Bon après quelques tests je plante toujours au même endroit.
Effectivement c'est bel est bien un problème d'interruption.
Maintenant je fais comme ça pour mettre ma VBR:
Je bloque toutes les interruptions.
Je récupère les infos des IPR*.
Je mets tous les IPR* à 0.
Je récupère l'ancienne VBR.
Je mets ma VBR à la place.
Je débloque les interruptions.
Du coup j'ai pu voir que la calto utilisait:
IPRA: 0x00000800
IPRB: 0x00000000
IPRC: 0x00000000
IPRD: 0x00000000
IPRE: 0x00000000
IPRF: 0x00008d00
IPRG: 0x00000000
IPRH: 0x00000000
Donc elle utilise le TMU1 (IPRA), et ce qui est utilisé dans le registre IPRF m'est obscure pour l'instant. (mais je suppose qu'il doit y avoir le clavier (KEYSC ?)).
Est-il possible que l'address utiliser pour IPR* ne sois pas bonne (0xa4080000) ?
Pour l'instant je veux juste boucler à l'infini dans mes handlers quand une interruption se produit.
Je sais plus trop quoi faire / essayer... car même en désactivant toutes les interruptions je plante toujours ... ou alors je suis encore passé devant une info capitale que j'ai oubliée (ou confondu avec une autre)
Citer : Posté le 28/01/2019 20:24 | #
Ces registres ne font que 16 bits, donc les quatre premiers chiffres hexadécimaux ne servent à rien. As-tu bien pensé à y accéder avec des uint16_t * ?
La première interruption dans IPRA est TMU0_0 ; tu peux l'appeler TMU_0 car il n'y a en fait qu'un TMU (avec 3 timers) sur la puce, et non pas 3 TMUs (de chacun 3 timers) comme sur le SH7724.
Les deux interruptions dans IPRF sont le clavier et le DMA.
L'adresse que tu as utilisée est la bonne, mais attention il y a deux octets de trous entre chaque registre (mais vu que tu arrives à les lire, je pense que tu es bon).
Je pense que tu as oublié que la SH4 va jusqu'à IPRL (12 registres), notamment la RTC est cachée dans IPRK ; il y aussi quelques ETMU qui traînent par ici.
Ton approche est juste, seuls les détails sont à peaufiner ! Tu es sur le bon chemin, courage !
Citer : Posté le 29/01/2019 19:41 | # | Fichier joint
Ces registres ne font que 16 bits, donc les quatre premiers chiffres hexadécimaux ne servent à rien.
As-tu bien pensé à y accéder avec des uint16_t * ?
Oui mais ma fonction prend seulement des uint32_t*
Je pense que tu as oublié que la SH4 va jusqu'à IPRL (12 registres), notamment la RTC est cachée dans IPRK ;
il y aussi quelques ETMU qui traînent par ici.
Même en mettant IPRA ~ IPRL à 0 je plante toujours... je me dis que c'est mon crt0.c qui ne dump pas les sections qu'il faut
mais pourtant memeory_map.txt me dit que si et objdump aussi >_<.
Je n'ai plus d'idée, a part me pencher sur les NMI mais tu m'as dit qu'ils n'étaient pas utilisés.
Donc je pense tout reprendre de 0 au risque de me retrouver bloquer au même endroit
Sinon il faudrait que je me tourne vers quel doc ? Car visiblement 7705 est trop éloigné du 7305... (donc la doc du 7724 ?)
Je te mets toutes les sources en fichier joint (normalement il y a pile assez pour compiler).
Merci de prendre du temps pour mes problèmes, sans toi je n'aurais jamais réussi a arrivé jusqu'ici <3
EDIT: le fichier joint est un .tar.gz.
Citer : Posté le 29/01/2019 21:22 | #
Oui mais ma fonction prend seulement des uint32_t*
La mienne aussi, la question est plutôt de mettre un paramètre pour le nombre de digits à afficher.
mais pourtant memeory_map.txt me dit que si et objdump aussi >_<.
Je n'ai plus d'idée, a part me pencher sur les NMI mais tu m'as dit qu'ils n'étaient pas utilisés.
Donc je pense tout reprendre de 0 au risque de me retrouver bloquer au même endroit
D'abord, la chose suivante : coupe toutes les interruptions dans sr ; il te suffit d'avoir sr.bl = 1, et si tu y tiens tu peux ajouter icr0.nmib = 1 pour bloquer aussi la NMI. Est-ce que ça plante dans cette situation ?
Attends, il faut que le choses soient absolument claires sur ce point, sinon tu vas foncer dans le mur.
Les calculatrices SH3 ont des SH7355 et des SH7337 qui sont très proches du SH7705.
Les calculatrices SH4 ont un SH7305 qui ressemble au SH7724.
Les docs que tu consultent donc celle du SH7724 et la documentation populaire que l'on rassemble sur https://bible.planet-casio.com/ . La doc de SimLo traite peu des aspects bas niveau de ce type mais est pertinente quand elle le fait. J'ai aussi quelques notes sur ce point. Dans le doute, demande car beaucoup de choses diffèrent (TMU, KEYSC pour ne citer que les plus communes).
J'ai regardé tes sources. Qu'est-ce que tu penses que __restore_stuff() fait ?
Ton objet de type glados_t... il n'y en a qu'un, right? Pourquoi est-ce que tu l'alloues dynamiquement plutôt que de le placer dans la RAM statique (qui semble plus naturel) ?
Oh ! C'est pas terrible. Au mieux c'est bancal, surtout que les OS 02.02 existent dans les deux je crois. De mémoire le dernier chiffre vaut 1 (02.02⋅2201 vs 02.02.2200) si le proco est SH4, mais c'est vraiment bof. Utilise la méthode de SimLo qui utilise des vraies différences sur certains registres.
Ta configuration des interruptions l'air juste, mais... c'est difficile de s'y retrouver, avec tous les logs. Pourquoi la VBR est-elle changée dans une fonction show_...() ? Pourquoi le programme principal est dans shell/ ?
Citer : Posté le 30/01/2019 09:20 | #
D'abord, la chose suivante : coupe toutes les interruptions dans sr ; il te suffit d'avoir sr.bl = 1, et si tu y tiens tu peux ajouter icr0.nmib = 1 pour bloquer aussi la NMI. Est-ce que ça plante dans cette situation ?
Non absolument pas, c'est pour ça que je me dis qu'il n'est pas impossible que le crash vienne de mon crt0.c.
Ta configuration des interruptions l'air juste, mais... c'est difficile de s'y retrouver, avec tous les logs. Pourquoi la VBR est-elle changée dans une fonction show_...() ? Pourquoi le programme principal est dans shell/ ?
show__...() montre juste l'addres actuel de la VBR (et la mienne) mais n'est pas changée a ce moment la. Ell est changer dans __set_vbr().
Le programme principal est dans le dossier Shell/ car j'aimerais coder un Shell (juste histoire d'apprendre comment fonctionne un Shell ). Mais c'est vrai que ce qu'il y a dans le main.c n'est pas du tout au bon endroit et devrait se trouver dans crt0.c (je pense) :/
Oh ! C'est pas terrible. Au mieux c'est bancal, surtout que les OS 02.02 existent dans les deux je crois. De mémoire le dernier chiffre vaut 1 (02.02⋅2201 vs 02.02.2200) si le proco est SH4, mais c'est vraiment bof. Utilise la méthode de SimLo qui utilise des vraies différences sur certains registres.
Je sais que c'est vraiment bof, seulement pour l'instant je me focalise plus sur mes handlers cassés x)
Mais merci pour l'info il me semblait bien que cette tèchnique était bancal, je regarderais la méthode de SimLo je suis curieux de savoir comment il fait
Ton objet de type glados_t... il n'y en a qu'un, right? Pourquoi est-ce que tu l'alloues dynamiquement plutôt que de le placer dans la RAM statique (qui semble plus naturel) ?
Je comptais le faire quand j'ai nettoyé mon code (mais encore une fois j'étais focalisé sur mon plantage)
J'ai regardé tes sources. Qu'est-ce que tu penses que __restore_stuff() fait ?
Elle restaure certains registres, notamment la VBR, c'est pour ça qu'elle plante quand je l'utilise (j'ai oublié de bloquer les interruptions avant de tout restaurer :/ ).
Merci de m'avoir expliqué pour les docs, je me basais sur le 7705, du coup j'ai zyeuté rapidement la doc du 7724 et effectivement j'ai pu trouver des infos qu'il me manquait (notamment les 12 registres IPR*)
Citer : Posté le 30/01/2019 14:24 | #
Non absolument pas, c'est pour ça que je me dis qu'il n'est pas impossible que le crash vienne de mon crt0.c.
Ben au contraire ; ton crt0.c est toujours exécuté dans les premiers dizièmes de seconde au démarrage de ton application. Si couper les interruptions suffit pour garder ton programme en vie plusieurs secondes, alors ton problème ne vient définitivement pas de l'exécution de ton crt0.c.
show__...() montre juste l'addres actuel de la VBR (et la mienne) mais n'est pas changée a ce moment la. Ell est changer dans __set_vbr().
Faudrait voir à pas me prendre pour un vieux con non plus.
{
puts("stop interrupt...");
__block_interrupt();
puts("DONE\nDump INTC:\n");
dump_intc();
puts("reset interrupt...");
stop_interrupt();
puts("DONE\n");
interrupt_counter = 0;
puts("set new VBR...");
__set_vbr((void*)&glados_vbr);
/* ... */
}
À la limite tu le mets où tu veux, mais pas dans crt0.c. En principe, crt0.c fait partie de la lib standard. Je déroge personnellement à cette règle pour éviter d'avoir à utiliser des constructeurs pour initialiser gint et ses drivers, et parce que c'est plus pratique, mais en aucun cas ça ne peut être ton programme principal. Est-il nécessaire, pour écrire un add-in avec Glados, d'écrire soit-même le crt0.c dans son fichier principal ?
Mais merci pour l'info il me semblait bien que cette tèchnique était bancal, je regarderais la méthode de SimLo je suis curieux de savoir comment il fait
Certes, mais je sens déjà que pour toi il n'est pas toujours clair (ou du moins clair et juste) quels registres sont SH3 et quels registres sont SH4 ; ça me paraît être une priorité. La détection n'est peut-être pas fondamentale mais je crois que cette méthode est fausse dans certains cas donc ça ne va pas t'arranger.
SimLo a juste localisé un registre (le registre de contrôle du port L, si je me souviens bien) qui est au même endroit sur les deux MPU mais qui a certains bits réservés sous SH3 qui sont utilisés sous SH4. Il écrit donc des 1 dedans, puis relit le registre pour voir si les 1 sont restés (auquel cas c'est un SH4), ou s'ils ont été remplacés par des 0, comme il est de coutume avec les bits réservés (auquel cas c'est un SH3). Il y a une autre différence de ce type pour distinguer les deux types de SH3 -SH7355 et SH7337- et à partir des SH4 il existe des registres de versions (PRR et PVR) pour avoir les détails de façon propre.
Un peu hacky comme tu peux le voir, mais toujours plus fiable que la version de l'OS, si tu veux mon avis.
Il n'y a pas de mauvaise façon de faire, personnellement ça me paraît plus facile de l'allouer statiquement pour éviter les erreurs sur les pointeurs, les appels de syscall et le tas mais c'est un peu de la paranoïa.
Elle restaure certains registres, notamment la VBR, c'est pour ça qu'elle plante quand je l'utilise (j'ai oublié de bloquer les interruptions avant de tout restaurer :/ ).
Non. C'est une implémentation de longjmp(). Ça restaure l'état des registres tel qu'il était au moment où __save_stuff() (aussi dite setjmp()) a été appelée, et ça reprend l'exécution à cet endroit. Autrement dit, quand tu appelles _restore_stuff(), ça remonte dans le temps (en termes d'état des registres et de la pile seulement) et ça recommence l'exécution juste après le moment où tu as appelé __save_stuff().
Bon courage !