1

yop,

J'aimerais savoir comment faire une lib dynamique en C. Dans la doc, il ya ça :
You can produce an external library file by defining the global symbol _library, i.e. by putting int _library in your program.

Ca veut dire que je mets "int _library;" quelque part et c'est bon ? C'est tout ?!?

2

Oui. (Enfin, il faut aussi définir USE_KERNEL évidemment, cf. options du projet si tu utilises l'EDI.)
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

3

Ok, merci. happy

4

Genre tu fais du C.
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

5

Ouais grin

6

On s'endort presque à utiliser genlib en C, tout est déjà fait. grin
truc
void gl_main()
{
	while( 1 )
	{
		// Manage non-graphical part
		switch( Task )
		{
		}

		// Wait for real screen swapping
		glaux_ready();
		
		// Manage graphical part
		switch( Task )
		{
		}

		// Wait for synchro
		glaux_synchro( 1 );
		glaux_swap();
	}
	
}

7

Tiens ben pendant que j'y suis, une question.

Si j'ai deux fonctions, A et B, sans "return", mais dans lesquelles elles s'appellent mutuellement, est-ce que le programme va empiler des adresses de retour sur la pile ?
ie en assembleur, j'aurais fait des bra entre les fonctions, pas des bsr.
Ca se gère comment en C ? tout seul j'espère ?

8

Ça va générer le bordel sur la pile effectivement, sauf dans les cas où une optimisation tailcall est possible.

Il vaut mieux travailler avec des boucles ou des goto dans ce cas.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

9

Si l'optimiseur de flot de contrôle de GCC 1) sait faire cette optimisation sur les fonctions qui s'appellement mutuellement (attention à la terminaison de la récursivité grin) et 2) arrive dans ton cas à déterminer qu'il peut faire cette optimisation, alors il la fera.
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

10

(cross, réponse à martial)

non. ça va s'appeler récursivement et remplir la pile.

ce que tu veux faire ça s'appelle des threads/couroutines/tâches, faut deux piles différentes et utiliser un truc de taskswitch préemptif style je-sais-plus-le-nm-du-truc-de-ximoon

alternativement ça peut se faire assez simplement (sisi trioui) avec setjmp

https://www.unsads.com/scm/svn/squalyl/asi/systeme/P3S/test/switcher-ti68k/
user guest
pass guest

(je sais plus si c'est complet, je sais plus si ça marche, mais le principe y est. Dommage j'avais un truc encore plus simple que ça, je le retrouve plus sad )

edit: ah le voila

#include <stdio.h>
#include <setjmp.h>

/*
| context switch presque portable avec setjmp, longjmp
| pour comprendre setjmp et longjmp voir la doc :
| http://www-ensimag.imag.fr/cours/Systeme/setjmp.longjmp
|
*/

#define K              1024
#define TAILLE_PILE     4*K

int mem [TAILLE_PILE]; /* memoire pour la pile du processus 1 */
int * deb_mem;
int proc_actif = 0;
jmp_buf buf_processus[2];

/*----------------------------------------------------------------------------*/
void ctxsw(actif,  elu) {
	if (setjmp(buf_processus[actif]) == 0)   {
		proc_actif = elu;
		longjmp(buf_processus[elu], 1);
	}
}
/*----------------------------------------------------------------------------*/
int choix_elu() {
	if (proc_actif == 0)  return 1; else return 0;
}
/*----------------------------------------------------------------------------*/
void resched() {
	int proc_elu;
	proc_elu = choix_elu();
	ctxsw(proc_actif, proc_elu);
}
/*----------------------------------------------------------------------------*/
/*
 | code execute par les 2 processus
 |
*/
void code_processus(char * mess) {
	int i;
	while(1) {
		printf ("%s", mess);
		resched();  /* changement de processus */
	}
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int main() {
	deb_mem = mem;         /* on pourrait faire un malloc a la place */
/*
| ici c'est le processus 0 qui s'exécute avec la pile allouée au lancement du programme C
*/
	if (setjmp(buf_processus[1]) == 0) {
#ifdef LINUX
/*
 | Initialisation de la pile pour le processus 1 (petit bricolage specifique pour linux/i386)
 */
		buf_processus[1][0].__jmpbuf[JB_SP] =  deb_mem + TAILLE_PILE;
#else
#ifdef SOLARIS
  /*
   | Initialisation de la pile pour le processus 1
   | (petit bricolage specifique pour Solaris/Sparc)
   */
		buf_processus[1][1] = (int) deb_mem + TAILLE_PILE - 16;
#else
#error "use -DLINUX or -DSOLARIS"
#endif
#endif
	printf ("Je suis le processus 0 et je pars dans la boucle\n");
	code_processus("je pense\n");
	}  else  {
		printf ("Je suis le processus 1 et je pars dans la boucle\n");
		code_processus("         donc tu es\n");
	}
}

11

Pour la TI, le code spécifique à la plateforme, c'est:
buf_processus[1]->A7 = (unsigned long) deb_mem + TAILLE_PILE;
Mais ce hack est vraiment sick! (Enfin, mon Task Switcher contient pire que ça, hein.)
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

12

oui ce hack est mégamoche mais franchement tu connais d'autres moyens? c'est toujours la même histoire non? allocation de l'espace mémoire du nouveau processus, et changement de SP/PC plus autres registres (bien entendu sur pc c'est carrément plus compliqué avec les mmu et etc). SetJmp n'est qu'un outil userspace pratique pour les besoins de la démo.

d'ailleurs pour avoir testé ça marche très bien sur 68k.

13

Kevin Kofler (./8) :
Ça va générer le bordel sur la pile effectivement, sauf dans les cas où une optimisation tailcall est possible.
Il vaut mieux travailler avec des boucles ou des goto dans ce cas.

Ok, je vais m'organiser autrement.
squalyl (./10) :
ce que tu veux faire ça s'appelle des threads/couroutines/tâches, faut deux piles différentes et utiliser un truc de taskswitch préemptif style je-sais-plus-le-nm-du-truc-de-ximoon

alternativement ça peut se faire assez simplement (sisi trioui.gif ) avec setjmp

Hmm t'as vraiment pas plus simple trilove

Regarde à quel point j'en suis techniquement :
	char * Buffer[10] ;

	sprintf( Buffer , "unmap%u" , Level );

J'aurais voulu savoir si c'est valide. Il va bien y avoir un 0 à la fin de "unmap%u" ? cheeky Ou dois-je écrire "unamp%u\0" ?

PS -> Ca fait bien deux octets un int sur TI ?

edit :
	sprintf( Buffer , "unmap%hu" , Level );
	MapDesc = LibsBegin( Buffer , 0 );

Faut inclure quoi pour avoir les ramcalls ? J'ai inclus tigcclib.h, j'ai fait un #define USE_KERNEL, mais il veut pas de mon LibsBegin cry

14

squalyl (./12) :
oui ce hack est mégamoche mais franchement tu connais d'autres moyens?

L'autre moyen, c'est de faire une seule fonction avec des goto, voire une simple boucle si le fonctionnement est suffisamment régulier.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

15

Folco (./13) :
Regarde à quel point j'en suis techniquement :
	char * Buffer[10] ;

	sprintf( Buffer , "unmap%u" , Level );
J'aurais voulu savoir si c'est valide.

Non. Un %u peut faire jusqu'à 5 caractères ("65535"), plus les 5 du "unmap" plus le \0, ça fait 11, donc ton buffer est trop petit.
Il va bien y avoir un 0 à la fin de "unmap%u" ? cheeky

Oui. Mais il faut le compter dans ta taille du buffer aussi!
Ou dois-je écrire "unamp%u\0" ?

Non.
PS -> Ca fait bien deux octets un int sur TI ?

Oui.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

16

Merci pour tout. smile
En fait, mon argument "Level" ne peut dépasser 3 caractères, donc ça ira. C'est pour construire un nom de fichier.


Par contre, j'ai un problème qui me gave bien, ça fait patrie des trucs du C qui ressemblent pour moi à une machinerie assez obscure :
J'inclus "genlib.h". Dans la doc de genlib, c'est écrit ça :
And you don’t need to include tigcclib since genlib.h do it for you.

Et apparemment, tigcclib ne connait pas LibsBegin.

Je vais donc pour inclure kernel.h de PreOS, header kernel pour le C. Mais dans le header, je trouve ça :
#if defined(NOSTUB) || defined(KERNEL) || defined(DOORS)
# error "kernel.h" must not be included with tigcclib.h #endif

Et c'est con, parce que dedans, il y a les définitions des romcalls. sad

Comment faire alors ? PpHd, c'est quoi les règles de l'art en la matière ?

17

./7 Euh je ne comprends pas pourquoi squalyl te parle de tout ça… trifus
Si effectivement tes fonctions s’appellent de façon croisée et non conditionnelle (à l’extérieur d’un if) ton programme ne terminera pas (enfin au moment du stack overflow seulement grin ).
Pour résoudre ça le mieux est de faire des boucles, et le moins mieux est d’utiliser goto.

[edit] : un dernier truc : teste ton code toutes les 10 lignes. Évite d’écrire des pages et des pages sans même voir si ça compile ou sans même tester si la fonctionnalité ajoutée fonctionne comme prévu.
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

18

Merci pour les tips. Pour ce qui est de la compilation, t'inquiète pas, je suis tellement skillé que je suis obligé de tester à chaque ligne. trioui
C'est vrai qu'en assembleur, je peux écrire beaucoup sans relire ou tester, mais là c'est pas la peine. grin

19

Un "int" fait 2 octets sur TI-68k (sauf si tu actives une option à la con du compilo, auquel cas les fonctions de la famille *printf ne vont plus fonctionner correctement, parce qu'elles supposent qu'un int fait 2 octets grin), mais 4 sur la plupart des plate-formes actuelles. Utiliser "int" n'a pas que des avantages.
Tu peux utiliser "short", "unsigned short", "int16_t" ou "uint16_t" (les deux derniers sont dans le header <stdint.h>, qui est inclus par <inttypes.h>) si tu veux une variable 16 bits (.w), et "long", "unsigned long", "int32_t" ou "uint32_t" si tu veux une variable 32 bits.
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

20

Bon, j'ai résoudru le problème de la pile : main est un scheduler qui appelle la fonction qui va bien :
schedule
void gl_main()
{
	while(1)
	{
		// Schedule tasks
		switch( NextTask )
		{
			case TASK_EXIT:
				return;
			case TASK_INTRO:
				LoadIntro();
				break;
			case TASK_GAME:
				LoadGame();
				break;
		}
		CurTask = NextTask ;
		InfiniteLoop();
	}
}

Et dans InfiniteLoop(), on fait un return si CurTask a été mis à 0 par la tâche en cours.

C'est bien. smile
Enfin presque, faut que je trouve un moyen de faire passer une valeur d'une fonction à une autre maintenant...

21

Tiens, j'avais pas vu ce warning, j'en reste confus, bien que je fasse sûrement une erreur :
Le proto de sprintf :
short sprintf (char *buffer, const char *format, ...);
Mon code :
	char * Buffer[ 10 ] ;
	const char * Filename = "unmap%u" ;

	sprintf( Buffer , Filename , Level );

Level est un int. J'ai ce ouarningue :
game.c:17: warning: passing argument 1 of '(<U9e70> = &_ROM_CALL_53)' from incompatible pointer type
Pourquoi ?

22

Parceque ton buffer, tel que déclaré, est un tableau de pointeurs vers des "char". Ce que sprintf attend c'est juste un tableau de char (donc au choix "char Buffer[10]" ou "char* Buffer" selon que tu veux du statique ou du dynamique).
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

23

Ah, parce que un tableau est un pointeur, donc "char Buffer[10 ] est un pointeur. Merci ! smile

24

e, après la déclaration :char buffer[10];Disons plutôt qu
char »
On a :« buffer » est un « char * »
« buffer[n] » est un « 
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

25

Ok, merci pour ça. happy

26

Folco (./16) :
Merci pour tout. smile
En fait, mon argument "Level" ne peut dépasser 3 caractères, donc ça ira. C'est pour construire un nom de fichier.


Par contre, j'ai un problème qui me gave bien, ça fait patrie des trucs du C qui ressemblent pour moi à une machinerie assez obscure :
J'inclus "genlib.h". Dans la doc de genlib, c'est écrit ça :
And you don’t need to include tigcclib since genlib.h do it for you.

Et apparemment, tigcclib ne connait pas LibsBegin.

Je vais donc pour inclure kernel.h de PreOS, header kernel pour le C. Mais dans le header, je trouve ça :
#if defined(NOSTUB) || defined(KERNEL) || defined(DOORS)
# error "kernel.h" must not be included with tigcclib.h#endif

Et c'est con, parce que dedans, il y a les définitions des romcalls. sad

Comment faire alors ? PpHd, c'est quoi les règles de l'art en la matière ?


#include "kernel.h"
#include "genlib.h"

doit marcher.

27

Folco (./6) :
On s'endort presque à utiliser genlib en C, tout est déjà fait. grin
truc
void gl_main()
{
	while( 1 )
	{
		// Manage non-graphical part
		switch( Task )
		{
		}

		// Wait for real screen swapping
		glaux_ready();
		
		// Manage graphical part
		switch( Task )
		{
		}

		// Wait for synchro
		glaux_synchro( 1 );
		glaux_swap();
	}
	
}


C'est fait pour!

28

Merci ! Mais j'ai fait un testcase minimal qui ressemble à ./27, et j'obtiens ça :
/opt/gcc4ti/lib/tigcc.a: Error: Unresolved reference to `__main'.
C'est vrai que les headers C, c'est compliqué avec cette manière de pouvoir dé-définir des symboles...

En plus, quand je compile avec "-Wa,-l", il me dit
1. Que j'ai encore de l'espace à gagner avec le switch -l de GAS !!
2. Que les ramcalls peuvent pas être relatifs (sans blague) et qu'il les passe en absolu.

29

Ajoute #define _main __main tout en haut avant le premier include.

30

Miracle, ça marche, bien joué. smile

Pour faire propre, ce #define doit aller où ?

edit -> je veux dire, dans quel header grin