Les membres ayant 30 points peuvent parler sur les canaux annonces, projets et hs du chat.
La shoutbox n'est pas chargée par défaut pour des raisons de performances. Cliquez pour charger.

Forum Casio - Projets de programmation


Index du Forum » Projets de programmation » addin en 2 parties
Parisse Hors ligne Membre Points: 522 Défis: 0 Message

addin en 2 parties

Posté le 19/12/2021 18:34

J'ai bien avance sur la creation d'un addin en 2 parties.
Voici un fichier testv.cc qui cree un vecteur (avec la uSTL) puis appelle une fonction declaree dans le fichier r8c2.h ci-dessous

#define std ustl
#include <vector>
void r8c2_print_vector(const std::vector<int> & v);

La fonction r8c2_print_vector affiche le vecteur, elle est implementee dans r82c.cc ci-dessous et sera ulterieurement stockee en RAM.

#include <fxcg/keyboard.h>
#include <fxcg/display.h>
#include <fxcg/file.h>
#include <fxcg/keyboard.h>
#include <fxcg/system.h>
#include <fxcg/misc.h>
#include <fxcg/app.h>
#include <fxcg/serial.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define std ustl
#include <vector>
#include <string>
using namespace ustl;

void r8c2_print_vector(const vector<int> & v){
  for (int j=0;j<v.size();++j){
    printf("%d\n",v[j]);
  }
}


Et le fichier testv.cc avec le code de chargement de la fonction en ram et avec les commandes de compilation (a modifier selon installation)

// -*- compile-command: "sh3eb-elf-g++ -g -mb -m4a-nofpu  -mhitachi -std=c++11 -fpermissive -fno-use-cxa-atexit -fno-strict-aliasing -fno-rtti -fno-exceptions  -I. -I/home/parisse/casiolocal/include/ustl  -c r8c2.cc -o r8c2.o && sh3eb-elf-g++ -g -mb -m4a-nofpu  -mhitachi -std=c++11 -fpermissive -fno-use-cxa-atexit -fno-strict-aliasing -fno-rtti -fno-exceptions  -I. -I/home/parisse/casiolocal/include/ustl  -c testv.cc -o testv.o && sh3eb-elf-g++ testv.o r8c2.o -g -static -nostdlib -Taddinram.ld -Wl,--gc-sections,--print-memory-usage -L. -L/home/parisse/casiolocal/lib -Wl,--start-group -ltommath -lustl -lm -lc -lgcc -Wl,--end-group -o testv.elf && sh3eb-elf-objdump -C -t testv.elf | sort > dump && sh3eb-elf-objcopy -R .comment -R .bss -R .rominram -O binary testv.elf testv.bin && sh3eb-elf-objcopy -j .rominram  -O binary testv.elf testv.8c2 && mkg3a -n basic:Testv -n internal:TESTV -V 0.0.0 testv.bin testv.g3a && /bin/cp testv.g3a testv.8c2 ~/.wine/drive_c"  -*-
// debug with sh3eb-elf-gdb -i=mi -ex "target remote localhost:31188" testv.elf

#include <fxcg/keyboard.h>
#include <fxcg/display.h>
#include <fxcg/file.h>
#include <fxcg/keyboard.h>
#include <fxcg/system.h>
#include <fxcg/misc.h>
#include <fxcg/app.h>
#include <fxcg/serial.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define std ustl
#include <vector>
#include <string>
#include "r8c2.h"
using namespace ustl;

unsigned ram2Msize=0;
char ram_filename[]="\\\\fls0\\testv.8c2";

bool chk_ram2M(const char * filename,bool reload){
  unsigned ram2Maddr=0x8c200000, ram2Mendaddr=ram2Maddr+ram2Msize;
  unsigned * ram2M=(unsigned *) ram2Maddr,*ram2Mend=(unsigned *) ram2Mendaddr;
  const unsigned chkinit=0x12345678;
  unsigned chk=chkinit,*ptr;
  const unsigned inc=1;
  if (ram2Msize){
    // if it's too slow, modify incr
    for (ptr=ram2M;ptr<ram2Mend;ptr+=inc){
      chk ^= (*ptr);
    }
    if (chk==*ptr)
      return true; // proba to return true with corruption is tiny, about 1/4e9
    if (!reload)
      return false;
  }
  // load khicas overlay
  int nchar=strlen(filename);
  unsigned short pFile[nchar+1];
  Bfile_StrToName_ncpy(pFile, (const unsigned char *)filename, strlen(filename)+1);
  int hf = Bfile_OpenFile_OS(pFile, READWRITE); // Get handle
  if (hf < 0)
    return false; // nothing to load
  int size=Bfile_GetFileSize_OS(hf);
  if (size>2*1024*1024-4 || Bfile_ReadFile_OS(hf,ram2M,size,0)!=size){
    Bfile_CloseFile_OS(hf);
    return false;
  }
  ram2Msize=size;
  ram2Mendaddr=ram2Maddr+ram2Msize;
  ram2Mend=(unsigned *) ram2Mendaddr;
  Bfile_CloseFile_OS(hf);
  // compute chksum
  chk=chkinit;
  for (ptr=ram2M;ptr<ram2Mend;ptr+=inc){
    chk ^= (*ptr);    
  }
  *ptr=chk; // save chksum
  return true;
}

int main(){
  if (!chk_ram2M(ram_filename,true)){
    printf("%s%s\n","Unable to load ",ram_filename);
    int key;
    for(;;)
      GetKey(&key);
    return 0;
  }
  if (!chk_ram2M(ram_filename,false)){
    printf("%s\n"," ",ram_filename);
    int key;
    for(;;)
      GetKey(&key);
    return 0;
  }
  int i=4321;
  string s("Coucou");
  //int * jptr=new int;
  char * buf=(char *)malloc(256);
  char * buf2=new char[256];
  printf("Hello\n");
  // printf("malloc %d\n new %d\nstack %d",unsigned(buf)-0x88100000,unsigned(buf2)-0x8100000,unsigned(&buf)-0x88100000);
  strcpy(buf,"!!Hello abcdefghijklmnopqrstuvwxyz 123456789");
  strcpy(buf2,"!!Hello2 abcdefghijklmnopqrstuvwxyz 123456789");
  printf("%s\n",buf);
  printf("%s\n",buf2);
  // char buf[]="!!Hello abcdefghijklmnopqrstuvwxyz 123456789";
  if (1){
    std::vector<int> v(3);
    for (int j=0;j<v.size();++j){
      v[j]=j*j;
    }
    r8c2_print_vector(v);
    i=unsigned (&v[2])-0x08100000;
    // v.clear();
  }
  int key;
  for(;;)
    GetKey(&key);
  return 0;
}

Voici le fichier loader addinram.ld pour stocker en RAM le contenu du fichier objet r8c2.o, en creant un fichier elf qu'on divisera ensuite en 2 fichiers, le fichier d'addin g3a et un fichier d'extension 8c2 qui sera charge par l'addin.

OUTPUT_FORMAT(elf32-sh)
OUTPUT_ARCH(sh3)

ENTRY(initialize)
MEMORY
{
        rom  : o = 0x00300000, l = 2M
        ram  : o = 0x08100000, l = 64k  /* pretty safe guess */
        r8c2 (rx) : o = 0x8c200000, l = 3M-4
}

SECTIONS
{
    /* 2nd part of code at 0x8c20000 */
    
        .rominram : {
                r8c2.o(.text)
                r8c2.o (.text.*)
                r8c2.o (.rodata)
                r8c2.o (.rodata.*)
        } > r8c2
           
        /* Code, in ROM */
        .text : {
                *(.pretext)     /* init stuff */
                *(.text)
                *(.text.*)
        } > rom
      
        /* Read-only data, in ROM */
        .rodata : {
                *(.rodata)
                *(.rodata.*)
        } > rom
      
/* RW initialized data, VMA in RAM but LMA in ROM */
.data : ALIGN(4) {
        _datald = LOADADDR(.data) ;
        _sdata = . ;
        *(.data)
        *(.data.*);
        _edata = . ;
} >ram AT>rom

/* Uninitialized data (fill with 0), in RAM */
.bss ALIGN(4) : ALIGN(4) {
        _bbss = . ;
        *(.bss)
        *(.bss*)
        *(COMMON)
        _ebss = . ;

    /* Extra unused static space */
    _sextra = ALIGN(32);
    _eextra = ORIGIN(ram) + LENGTH(ram);
} >ram

}


J'ai fait ce petit test en preparation d'une mise a jour majeure de KhiCAS qui pourrait utiliser beaucoup plus d'espace, pour recueillir l'avis des experts sur le meilleur modele a choisir (ceux qui ont lu jusqu'ici sont probablement des experts...).
Mais d'abord j'ai un gros probleme avec l'emulateur, impossible d'ecrire dans la zone memoire 0x8c20000, est-ce qu'il y a une autre adresse a tester? Ou peut-etre que la zone de RAM n'est pas supportee par l'emulateur, ce qui me compliquerait le travail de mise au point, mais pas que, ca rendrait impossible l'execution a l'emulateur pour une demo dans un but pedagogique,
Ensuite, mon idee serait d'avoir le moteur de calcul de giac en RAM jusqu'a une taille de 3M (ca gagne 1M par rapport aux 2M actuels) et de garder toute l'UI (ainsi bien sur que le chargeur en RAM) dans la partie addin en ROM. On peut meme envisager a moyen terme de rajouter mon implementation de MicroPython avec ma collection de modules pour avoir la meme chose que sur Numworks/Nspire.
J'en profite pour signaler que j'ai mis a jour la section developpement de la doc de KhiCAS avec une description assez detaillee je pense de comment utiliser le debugger mis au point par redoste, (cf. ce fil)


1, 2 Suivante
Yatis En ligne Membre Points: 581 Défis: 0 Message

Citer : Posté le 19/12/2021 18:54 | #


Mais d'abord j'ai un gros probleme avec l'emulateur, impossible d'ecrire dans la zone memoire 0x8c20000, est-ce qu'il y a une autre adresse a tester?

Sur l'émulateur, mon loader ELF perso m'indique que la RAM physique se trouve à 0x08000000, que la RAM utilisateur commence à 0x08160000 et que cette zone a seulement 5 Mo d'espace disponible. Ce qui est sensiblement différent que sur la vraie machine.

Voici le code que j'ai pondu si jamais ça peut vous aider:

#include "vxBoot/hardware.h"

#include <gint/mmu.h>

/* __ram_get_size() : try to determine the RAM size */
static ptrdiff_t __ram_get_size(uintptr_t start_ram)
{
    volatile uint32_t *ptr = (void*)start_ram;
    volatile uint32_t *tst = (void*)start_ram;
    uint32_t backup;

    //TODO: use UTLB page size information to walk through each pages
    while (1) {
        ptr = &ptr[4096];
        backup = ptr[0];
        ptr[0] = 0xdeadbeef;
        if (ptr[0] != 0xdeadbeef || ptr[0] == tst[0]) break;
        ptr[0] = backup;
    }
    ptr[0] = backup;
    return ((ptrdiff_t)((uintptr_t)ptr - (uintptr_t)tst));
}

/* hardware_get_info() : get hardware information */
int hardware_get_info(struct hwinfo * const hwinfo)
{
    if (hwinfo == NULL)
        return (-1);
    uintptr_t uram = mmu_translate(0x08100000, NULL);
    hwinfo->ram.physical.origin_addr = uram & 0xff000000;
    hwinfo->ram.physical.user_addr = uram;
    hwinfo->ram.size = __ram_get_size(uram | 0xa0000000);
    hwinfo->ram.available = hwinfo->ram.size - (uram & 0x00ffffff);
    return (0);
}
Lephenixnoir En ligne Administrateur Points: 24699 Défis: 170 Message

Citer : Posté le 19/12/2021 18:55 | #


J'ai pas encore lu le thread mais je confirme que sur l'émulateur la RAM commence à 0x88000000. Sur la Prizm aussi c'est ça, il n'y a que la Graph 90+E et fx-CG 50 physiques où la RAM commence à 0x8c000000. Parisse, j'avais mentionné ça par mail notamment, en réponse à la question sur la virtualisation.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Parisse Hors ligne Membre Points: 522 Défis: 0 Message

Citer : Posté le 19/12/2021 19:46 | #


Je suis perdu, je dois utiliser quoi comme adresse pour que ca marche sur l'emulateur ET sur les calculatrices physiques? J'ai essaye 88200000 et ac200000 mais ca n'affiche rien a l'emulateur, et le 1er crashe sur la 90.
Yatis En ligne Membre Points: 581 Défis: 0 Message

Citer : Posté le 19/12/2021 19:52 | #


La RAM ne se trouve absolument pas à la même place entre émulateur (0x88000000) et la calculatrice (0x8c000000)
Slyvtt En ligne Maître du Puzzle Points: 2422 Défis: 17 Message

Citer : Posté le 19/12/2021 20:25 | #


Yatis a écrit :
La RAM ne se trouve absolument pas à la même place entre émulateur (0x88000000) et la calculatrice (0x8c000000)

Yatis, Lephé,
y a t il un moyen de savoir depuis un addins si on tourne sur l'émulateur ou la machine physique ? Un code à lire qq part ou un test à effectuer pour discriminer les deux architectures ?
Si oui, Bernard pourrait peut être effectuer ce test afin de choisir la bonne adresse "au vol".
There are only 10 types of people in the world: Those who understand binary, and those who don't ...
Yatis En ligne Membre Points: 581 Défis: 0 Message

Citer : Posté le 19/12/2021 20:34 | #


y a t il un moyen de savoir depuis un addins si on tourne sur l'émulateur ou la machine physique ? Un code à lire qq part ou un test à effectuer pour discriminer les deux architectures ?

Oui et c'est relativement simple, il suffit de lire le registre "Product Version" (0xFF000044), s'il retourne 0, vous êtes dans un émulateur. Voilà un fix que j'ai récemment fait pour un projet qui utilise cette technique :

    /* workaround to disable cursor blink only in FXCG-Manager (emulator) */
    if (*(volatile uint32_t *)0xff000044 != 0x00000000) {
        terminal.private.timer.id = timer_configure(
            TIMER_ANY,
            250000,
            GINT_CALL(terminal_cursor_handler)
        );
        if (terminal.private.timer.id < 0) {
            terminal_close();
            return (-1);
        }
    }
Parisse Hors ligne Membre Points: 522 Défis: 0 Message

Citer : Posté le 19/12/2021 20:34 | #


Non, car les adresses d'appel sont codes en dur, il faudrait 2 versions de l'addin. Mais la je n'arrive pas a le faire marcher l'addin test sur l'emulateur meme avec l'adresse 0x88... Je suis en train d'upgrader l'emulateur au cas ou...
Lephenixnoir En ligne Administrateur Points: 24699 Défis: 170 Message

Citer : Posté le 19/12/2021 20:38 | #


Parisse a écrit :
Je suis perdu, je dois utiliser quoi comme adresse pour que ca marche sur l'emulateur ET sur les calculatrices physiques? J'ai essaye 88200000 et ac200000 mais ca n'affiche rien a l'emulateur, et le 1er crashe sur la 90.

Comme Yatis l'a dit, aucune ! Il faut faire la disjonction de cas émulateur vs. physique à la main. Bienvenue dans le monde des considérations bas-niveau. :3

Slyvtt a écrit :
Yatis, Lephé,
y a t il un moyen de savoir depuis un addins si on tourne sur l'émulateur ou la machine physique ? Un code à lire qq part ou un test à effectuer pour discriminer les deux architectures ?
Si oui, Bernard pourrait peut être effectuer ce test afin de choisir la bonne adresse "au vol".

La version de Yatis est très bien, on peut aussi regarder le numéro de série :

// Version PVR
bool is_emulator = *(volatile uint32_t *)0xff000044 == 0x00000000;
// Version numéro de série
bool is_emulator = !memcmp((void *)0xa001ffd0, "\xff\xff\xff\xff\xff\xff\xff\xff", 8);

Pour information, dans gint :

#include <gint/hardware.h>
gint[HWCALC] == HWCALC_PRIZM;
gint[HWCALC] == HWCALC_FXCG50;
gint[HWCALC] == HWCALC_FXCG_MANAGER;


Ajouté le 19/12/2021 à 20:42 :
         .rominram : {
                r8c2.o(.text)
                r8c2.o (.text.*)
                r8c2.o (.rodata)
                r8c2.o (.rodata.*)
        } > r8c2

Bien joué, c'est pas mal du tout. Ce bloc devrait sans doute être après .text et se terminer par AT>rom >r8c2, juste par souci de faire les choses proprement (même si ça peut marcher sans c'est un peu brutal tel quel).
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Parisse Hors ligne Membre Points: 522 Défis: 0 Message

Citer : Posté le 19/12/2021 20:59 | #


Ok, ca marche sur l'emulateur avec 0x88.... Mais il va falloir compiler 2 versions de la partie ram, en utilisant le test emulateur, on devrait pouvoir charger automatiquement le bon.
Lephenixnoir En ligne Administrateur Points: 24699 Défis: 170 Message

Citer : Posté le 19/12/2021 21:31 | #


Aha oui j'avais pas pensé à ça c'est malin. Là t'as vraiment besoin de l'adresse physique au link donc tu peux pas échapper à la double version x)
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Parisse Hors ligne Membre Points: 522 Défis: 0 Message

Citer : Posté le 20/12/2021 09:18 | #


Bon en fait il faut aussi 2 versions de la partie en ROM, sinon les appels vers la RAM ne se font pas a la bonne adresse. Donc 2 addins et 2 parties RAM. Je vais rajouter emu dans le nom de l'addin pour l'emulateur, et pour les parties ram je vais mettre les extensions .882 et .ac2. Du coup, je cree 2 scripts ld aussi. J'ai fait une archive de l'addin test avec partie en RAM pour ceux qui voudraient faire comme moi (mais ca doit pas etre frequent d'avoir besoin de plus de 2M).
https://www-fourier.univ-grenoble-alpes.fr/~parisse/casio/addinram.tgz

Du coup on a jusque 5M de disponible sur la 90, est-ce vrai aussi sur tous les modeles Prizm?
Il me reste encore a gerer la RAM et le OFF/ON. Actuellement j'ai des problemes de corruption, qui n'ont pas l'air de se produire si on tape sur la touche MENU. Est-ce qu'on sait simuler l'appui sur une touche?

Ajouté le 20/12/2021 à 09:53 :
Ca a l'air possible de reinjecter un code vers GetKey avec int Keyboard_PutKeycode(int x, int y, int keycode), du coup je vais essayer de gerer OFF/ON en remplacant tous les appels actuels a GetKey par une fonction de l'addin, qui gererait shift ON par l'affichage d'un message demandant de confirmer par shift-ON a nouveau, injecter MENU dans le buffer de GetKey et appeler GetKey. A moins qu'il soit possible d'injecter plusieurs code clavier dans le buffer GetKey.
Lephenixnoir En ligne Administrateur Points: 24699 Défis: 170 Message

Citer : Posté le 20/12/2021 09:58 | #


Ton système avec les doubles versions a l'air correct.

Du coup on a jusque 5M de disponible sur la 90, est-ce vrai aussi sur tous les modeles Prizm?

Non, juste la Graph 90+E (fx-CG 50) ! J'espère que tu ne le découvres pas maintenant, je m'en voudrais de pas avoir été clair et de t'avoir fait miroiter du support universel alors que c'est clairement plus difficile. :x

Oui Keyboard_PutKeyCode() est la bonne option. Je crois que tu peux l'appeler plusieurs fois de suite.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Parisse Hors ligne Membre Points: 522 Défis: 0 Message

Citer : Posté le 20/12/2021 10:57 | #


Donc ca veut dire qu'il faut maintenir une version de KhiCAS en anglais proche de l'actuelle, sans partie ram, pour les fxcg10 et 20. Je vais regarder le clavier avant de me lancer dans la version avec ram...

Ajouté le 20/12/2021 à 11:01 :
En fait, il y a peut-etre quand meme de la memoire sur les Prizm? Moins de 3M mais un petit quelque chose?
Lephenixnoir En ligne Administrateur Points: 24699 Défis: 170 Message

Citer : Posté le 20/12/2021 11:13 | #


En fait, il y a peut-etre quand meme de la memoire sur les Prizm? Moins de 3M mais un petit quelque chose?

Ça m'étonnerait la ref hardware de la puce dit 2M.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Parisse Hors ligne Membre Points: 522 Défis: 0 Message

Citer : Posté le 20/12/2021 22:07 | #


Pas de chance
Keyboard_PutKeyCode(-1,-1,KEY_CTRL_MENU); GetKey(keyptr);
n'est pas equivalent a une pression sur la touche MENU.
Le MENU n'est pas affiche, et GetKey renvoie tout de suite le code clavier de la touche MENU.
Lephenixnoir En ligne Administrateur Points: 24699 Défis: 170 Message

Citer : Posté le 20/12/2021 22:12 | #


Oui c'est documenté dans le SimLo, regarde la description de 0x0248 (c'est pour les Graph mono mais ça doit s'appliquer). Pour obtenir les comportements spéciaux type retour au menu il faut injecter directement les codes matriciels, ie. utiliser les deux premiers arguments et pas le troisième.

Il y a aussi toute une histoire avec injecter le code après avoir lancé GetKey(), avec un timer. Tu peux commencer par tester sans le timer, de mémoire ça marche la plupart du temps. Et ensuite tu peux rajouter le timer en prenant son code, qui marche très bien, ou bien t'inspirer de celui de gint pour la méthode.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Parisse Hors ligne Membre Points: 522 Défis: 0 Message

Citer : Posté le 20/12/2021 23:06 | #


Je me mefie de l'utilisation de timer, d'abord c'est un peu plus complexe a mettre en oeuvre et ensuite ca risque de creer des interactions nefastes. Je vais utiliser GetKeyWait OS, en autorisant MENU. Et tester si PowerOff() pose des problemes de corruption memoire, sinon shift-ON affichera un message de taper MENU pour pouvoir eteindre en toute securite.
Lephenixnoir En ligne Administrateur Points: 24699 Défis: 170 Message

Citer : Posté le 20/12/2021 23:15 | #


N'oublie pas que si tu autorises le retour au menu dans GetKeyWait() l'utilisateur peut toujours éteindre la calculatrice dans le menu et revenir ensuite dans l'add-in
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Parisse Hors ligne Membre Points: 522 Défis: 0 Message

Citer : Posté le 21/12/2021 07:32 | #


Oui, c'est ce que je souhaite faire. Il me semble qu'il n'y a pas de corruption memoire dans ce cas la.

Ajouté le 21/12/2021 à 10:22 :
Bon, je vais utiliser le timer pour simuler la touche menu quand il y a un timeout. Ce qui devrait permettre de gerer correctement l'alimentation...
Lephenixnoir En ligne Administrateur Points: 24699 Défis: 170 Message

Citer : Posté le 21/12/2021 10:24 | #


On est d'accord que pour la corruption mémoire on n'a pas encore d'explication solide right? J'ai testé encore de mon côté, la mémoire on-chip (XRAM/YRAM/ILRAM) n'est pas toujours préservée durant une extinction (même dans le menu principal), la RAM utilisateur si. J'aimerais bien creuser encore...
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
1, 2 Suivante

LienAjouter une imageAjouter une vidéoAjouter un lien vers un profilAjouter du codeCiterAjouter un spoiler(texte affichable/masquable par un clic)Ajouter une barre de progressionItaliqueGrasSoulignéAfficher du texte barréCentréJustifiéPlus petitPlus grandPlus de smileys !
Cliquez pour épingler Cliquez pour détacher Cliquez pour fermer
Alignement de l'image: Redimensionnement de l'image (en pixel):
Afficher la liste des membres
:bow: :cool: :good: :love: ^^
:omg: :fusil: :aie: :argh: :mdr:
:boulet2: :thx: :champ: :whistle: :bounce:
valider
 :)  ;)  :D  :p
 :lol:  8)  :(  :@
 0_0  :oops:  :grr:  :E
 :O  :sry:  :mmm:  :waza:
 :'(  :here:  ^^  >:)

Σ π θ ± α β γ δ Δ σ λ
Veuillez donner la réponse en chiffre
Vous devez activer le Javascript dans votre navigateur pour pouvoir valider ce formulaire.

Si vous n'avez pas volontairement désactivé cette fonctionnalité de votre navigateur, il s'agit probablement d'un bug : contactez l'équipe de Planète Casio.

Planète Casio v4.3 © créé par Neuronix et Muelsaco 2004 - 2024 | Il y a 60 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd