1

Je fais un saut d'un programme à une lib.

Le programme :
_main:	clr.l	-(%sp)			|push function & version
	bsr.s	Push			|push &libname on the stack, shorter than using lea
	.asciz	"pxclb"			|name of the lib
Push:	jsr	kernel__LibsExec	|exec the main part which has it's own routine to quit properly
	.long	kernel__Exec		|data needed, its adress is on the stack

Et la lib :
pxclb__0000:
	movea.l	(%sp)+,%a0				|&Data of the loader
	movea.l	(%sp)+,%a1				|return adress of the loader
	move.w	(%sp)+,%d3				|ARGC
	movea.l	(%sp),%a2				|ARGV

D'après moi, une fois arrivé à pxclb__0000, je devrais avoir :

(sp) == adresse du .long kernel__Exec
donc ((sp)) == kernel::exec et (-4(sp)) == kernel::LibsExec

Et pourtant, quand j'arrive à pxclib__0000, j'ai (sp) == $21AF9C, 4(sp) == $21B1E0.
Ca pointe donc dans la ROM, quelque part dans le linker probablement, vu que kernel::exec == $21B1A4 et kernel::LibsExec == $21AF3A

Alors que si je comprends bien la doc, c'est l'adresse de kernel::exec que je devrais trouver !
RamCalls.txt, PreOS.

35-kernel::LibsExec(char *lib_name, WORD function, BYTE version, ...) (Preos only)

The parameters are pushed on the stack.
It calls the function without modifying the registers, and it pops its argument
during the call (LIB_DESCRIPTOR, function, and version)
.


Où est-ce que je déconne ?

2

kernel::LibsExec effectue une modification de l'addresse de retour de la fonction, de telle facon qu'il puisse gérer la suite de kernell:LibsExec (ie. de rélocation de la lib, libération de la mémoire, ...)
Donc ton système ne peut pas marcher puisque l'adresse de la lib appelante disparait le temps d'execution de la fonction appelée.

Utiliser un appel direct sans passer par kernell::Exec.

3

A noter que kernel::Exec a un coût caché en RAM de 12 octets.

4

Ok, c'est ce que je me suis dit cette nuit, dans un demi-sommeil. J'avais utilisé ça parce que je viens de (re^n)-lire ProgFormatV4, et ça me permettait de virer le seul relogement de lib qu'il y avait au profit d'un autre relogement de ramcall, sachant que j'utilisais nécessairement kernel::exec. D'où un gain de place qui me descendait le loader à 117 bytes (+ les 6 octets que tu signales, une table de 3 pointeurs si j'ai bien compris, c'est pas ça qu'on appelle une liste chainée ? Les éléments font référence au suivant et/ou au précédent ?).

Bon ben c'est pas grave, ça :
_main:	jsr	pxclb__0000
	.long	kernel__Exec,kernel__LibsExec

Ca prend 129 octets, on fera avec.
Qui plus est, ça évite d'avoir un appel non protégé à LibsExec en cas d'échec.

5

Folco (./4) :
c'est ce que je me suis dit cette nuit, dans un demi-sommeil
Faut vraiment que tu fasses un break, là tongue
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

6

...un break point, à la rigueur embarrassed

7

./5 -> nan j'aime ça tongue

./6 -> voilà \o/ grin

8

./6: Non je le fais pour lui là.

9

Avant d'attaquer les ramcalls en f-line ? love grin

10

Tout çà pour économiser quelques octets.... Tsss tongue

11

Ca me permettrait d'avoir pexec en un seul fichier 68kP et 0 octet de RAM consommée, mis à part le binaire à exécuter. gni

Putain oui je cours après les octets, j'ai réduit la taille du loader et de la lib de moitié déjà (129 + 1205 octets) ^^

Et puis PExec se remet à tourner dans son nouvel habit depuis cet après-midi, ça va cartonner. tongue

12

Avant d'attaquer les ramcalls en f-line ?

Bon, PpHd, on s'y prend comment ? Comme certains ramcalls sont des pseudo-constantes (KEY_*), d'autres des pointeurs vers des variables de 1 octet (CALCULATOR), d'autres des routines (kernel::*), ça parait pas simple de proposer une interface qui corresponde à tout ça.

Bien que le design de tes softs m'épate toujours et que ce soit vraiment pas mon fort, j'ai pensé à ça :

dc.w $F000 + #ramcall
ou encore :
dc.w $F000 + #ramcall x 2

Et ça renvoie dans a0 le pointeur vers le ramcall dans la table du kernel. Suffit d'avoir une table d'offsets de deux bytes à ajouter à l'adresse du premier ramcall. Le fait d'utiliser la seconde solution gagne en temps de calcul (mais c'est pas vraiment ce qu'on cherche quand on utilise ce vecteur), tandis que la première solution permet de ne pas trop empiéter sur la plage disponible du vecteur.

Après, l'utilisateur n'a qu'à faire un jsr (a0), tst.b (a0), cmp.w (a0),d0 etc... De toute façon, c'est bien à lui de savoir comment utiliser le ramcall dont il a besoin. Qui plus est, ça permet une implémentation très légère en taille.

Qu'en pensez-vous tous ?

13

J'attends le retour des autres.

14

Comme tu l'écris, les RAM_CALLs en F-Line ne sont vraiment pas top pour la vitesse d'exécution, mais sont effectivement sympa pour l'optimisation taille smile

A propos du fait d'écrire F000 + ramcall, F000 + ramcall*2 ou F000 + ramcall*4: je pense que ça dépend surtout de l'utilisation de la plage F000-FFFF. Presque toute la plage F800-FFFF est utilisée pour les ROM_CALLs, mais la plage F000-F7FF est libre. Au pire, s'il faut un jour ajouter d'autres F-Line, on pourra prendre F080 ou F100 comme base.

L'interface qui consiste à retourner dans a0 le pointeur sur le RAM_CALL (si c'est une donnée immédiate, comme KEY_LEFT) ou l'adresse (si c'est l'adresse d'une fonction ou d'une donnée comme font_small, par exemple) n'est pas plus bête qu'une autre.
Une autre possibilité est de retourner les valeurs immédiates dans d0 ou les adresses dans a0. Peut-être est elle plus optimisée dans certains cas que celle que tu proposes, mais en revanche, elle est moins optimisée pour le test des touches. Avec ta méthode, on peut faire
F851 (ROM_CALL ngetchx en F-Line)
F??? (RAM_CALL KEY_LEFT)
cmp.w (a0),d0

alors qu'avec l'interface que je décris, il faut faire

F851 (ROM_CALL ngetchx en F-Line)
move.w d0,<ea != d0> (par exemple)
F??? (RAM_CALL KEY_LEFT)
cmp.w <ea>,d0


(Ah, au fait... c'est clair qu'il n'y aurait pas tout le fun pour toi d'optimiser une lib externe consommant zéro RAM, et que le fun, c'est important pour nous passionnés - mais à moyen terme, peut-être que le meilleur endroit pour pexec serait built-in PedroM, non ?)
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

15

Une partie du code de pexec serait à réécrire si PpHd voulait l'implanter. A moins de dégager violemment les options et de ne garder qu'une fonction pure AMS-like, mais l'intérêt est moindre.
A voir, je suis prêt à écrire une version built-in avec des specs différentes.

A noter que ta proposition, si elle pouvait se révéler plus pratique pour le programmeur, prendrait plus de place à implanter. J'avais commencé un patch comme ça, mais c'est chiant, il faut savoir ce que fais chaque ramcall. C'est pour ça que j'avais abandonné, c'était trop lourd. Qui plus est, l'OS devrait regarder à quoi sert ce ramcall, et agir en fonction. Le programmeur, lui, sait ce qu'il a à faire de (a0). M'enfin, c'est mon avis.

16

--- Vectors.asm.old	2009-07-16 20:41:31.000000000 +0200
+++ Vectors.asm	2009-07-21 12:02:48.619049088 +0200
@@ -150,8 +150,9 @@
 	move.w	(sp)+,d1		; Get Old SR
 	move.l	(sp)+,a0		; Get Address of the 'crash'
 	move.w	(a0)+,d0		; We get the instruction and a0 ->next instruction
-	subi.w	#$F800,d0		; Is it > $F800 ? 
+	cmpi.w	#$F800,d0
 	bls.s	\no			; No, so it is a crash (First_Window isn't a ROM_CALL)
+		subi.w	#$F800,d0
 		move.l	a0,a1		; Jsr/Jmp with a 32 bits offset	
 		cmp.w	#$FFF0-$F800,d0
 		bne.s	\NoRelJsr
@@ -175,7 +176,18 @@
 \Jump			move.w	d1,SR		; Restore SR
 			pea	(a0)		; Push return address
 			jmp	(a1)		; Jump to Rom_call function
-\no:	lea	Line1111_str(Pc),a0
+\no:	subi.w	#$F000,d0
+	cmpi.w	#MAX_RAMCALL,d0
+	bcc.s	\error
+		move.w	d1,SR			; Restore SR
+		pea	(a0)			; Push return adress
+		add.w	d0,d0			; Offset *2
+		add.w	d0,d0			; *4 (table of longwords)
+		lea.l	RAM_TABLE(pc),a0	; Get ramcalls table ptr (Kernel.asm)
+		adda.w	d0,a0			; Set pointer to the right ramcall
+		rts				; Come back
+
+\error:	lea	Line1111_str(Pc),a0
 	bra	FATAL_ERROR

tromb Fichier joint : patch.diff smile

C'est optimisable au niveau du nettoyage du f-line. Mais faut changer les bcc et j'ai pas voulu me faire chier. Mais ça marche.

17

J'aime pas cette interface. Je veux que si c'est une fonction ca appelle la fonction, et sinon ca retourne la valeur gni
Sinon ca prend de la place dans le code utilisateur.

18

Ok, je fais ça dès que je peux. Le truc, c'est que c'est l'OS qui va s'embarquer le code pour tous les ramcalls. Remarque, une table de saut pc-relatif sur un byte par ramcall + les quelques routines kivonbien pour les différents types de ramcalls (yen a pas tant que ça) et c'est marre. smile

19

Qu'est ce que c'est que ces deux valeurs ? Elles sont inversées sur 89 et 92 :
dc.l KEY_LEFT,KEY_RIGHT,KEY_UP,KEY_DOWN,342,345
,$2000,3840,$4000

20

342 et 345 sont le OR logique de certaines paires de valeurs parmi KEY_LEFT, KEY_RIGHT, KEY_UP et KEY_DOWN.
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

21

C'est 2 des 4 diagonales parmi la crois Haut, Bas, Gauche, Droit. Je ne sais pas d'où çà sort, mais c'est comme çà...

22

Ok. Alors je tiens compte de quoi ? Visiblement, PedroM n'utilise pas cette table, sauf si j'ai raté un truc. Alors :
- à quoi sert-elle en ce moment ? (mais elle va servir ^^)
- de quelle liste de ramcall dois-je tenir compte ? Celle-ci, ou celle documentée dans ramcalls.txt ? Il n'y en a pas le même nombre.

De plus, est-il impératif que l'interface adopte une numérotation de ramcalls identique à celle existante ?
Par exemple, si l'interface utilisateur est :
.macro RAM_THROW ramcall
.word 0xF000 + \ramcall
.endm
Puis-je partir mettons avec FLINE_LibsBegin equ 0, FLINE_LibsCall equ 1 etc... ?
Je suppose que c'est pas gênant ? En tout cas, ça permettrait d'avoir un code plus petit et surtout plus simple dans le kernel (regroupement des fonctions à appeler, des adresses à retourner, et des valeurs sur deux octets à renvoyer).

Dernière chose, c'est PedroM-only ?

23

PpHd (./17) :
J'aime pas cette interface. Je veux que si c'est une fonction ca appelle la fonction, et sinon ca retourne la valeur gni

Et aussi de la magie noire tant que tu y es? gni
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é

24

Kevin Kofler (./23) :
PpHd (./17) :
J'aime pas cette interface. Je veux que si c'est une fonction ca appelle la fonction, et sinon ca retourne la valeur gni

Et aussi de la magie noire tant que tu y es? gni

Tant qu'à faire.

grin
Folco (./22) :
PedroM n'utilise pas cette table, sauf si j'ai raté un truc.

Tu as raté un truc.
Folco (./22) :
- de quelle liste de ramcall dois-je tenir compte ? Celle-ci, ou celle documentée dans ramcalls.txt ? Il n'y en a pas le même nombre.

Ben si normalement oui. C'est dans Kernel.asm
Folco (./22) :
Je suppose que c'est pas gênant ? En tout cas, ça permettrait d'avoir un code plus petit et surtout plus simple dans le kernel (regroupement des fonctions à appeler, des adresses à retourner, et des valeurs sur deux octets à renvoyer).

??? Tu as juste 2 zones de données qui correspondent à des fonctions. 4 comparaison et c'est réglé.
Je ne comprends pas ce que tu veux faire.

Folco (./22) :
Dernière chose, c'est PedroM-only ?

Bien sûr. gni

25

Ok, je verrai ça demain à tête reposée.

26

mais... MAIS ... ON VA POUVOIR FAIRE DES PROGRAMMES NOSTUB AVEC APPEL DE DLL (*) trilove encore un bonne tranche de bricolage en perspective. trilove

(*) je parle naturellement de vraies dll embarrassed

Tu as raté un truc.

Exact, fallair chercher dans PreodroM aussi embarrassed
??? Tu as juste 2 zones de données qui correspondent à des fonctions. 4 comparaison et c'est réglé.Je ne comprends pas ce que tu veux faire.

Exact, exact, j'avais encore une table de saut en tête :

Je vois donc trois choses possibles à traiter :
- renvoi d'une adresse dans a0 (LCD_MEM etc)
- renvoi d'une donée dans d0 (KEY_* etc)
- exécution de routine (kernel::*)

Si les zones de fonctions sont claires en effet, les pointeurs et les données sont très mélangées : c'est pas dur d'identifier ce qu'il faut, mais c'est 40 tests qu'il faudra, pas 4.
D'où mon idée d'une table de saut vers trois routines de deux lignes :
- le renvoi d'adresse dans a0
- le renvoi de donnée dans d0
- l'exécution d'une routine.

Une table de saut codée sur 1 octet par entrée prendra pas plus de place que s'il faut désembrouiller les éléments de la table, et sera bien plus rapide. Je te propose ça ce soir.
A moins que ton idée soit de renvoyer tout ce qui est valeurs et adresses dans d0. J'attends les avis de tous et ton ordre. grin

27

Je veux que si c'est une fonction ca appelle la fonction, et sinon ca retourne la valeur gniSinon ca prend de la place dans le code utilisateur.

Ben, cette interface-là pour les RAM_CALLs peut elle aussi prendre plus de place dans le code utilisateur: j'ai donné un exemple en ./14 wink

Pour sauter entre trois morceaux de code différent, une table de sauts est plus lente qu'un double test. Mais sinon, je pense aussi que l'utilisation d'un tableau indiquant, pour chaque RAM_CALL, si c'est un type adresse, un type donnée ou un type routine, est inévitable, pour des raisons d'efficacité:

; table qui définit le type du RAM_CALL
ram_call_type_table:
dc.b -1, 0, 0, 1, -1, 1, ...

move.b d(pc,dn.w),dn
beq.s type0
blt.s type_minus1
; ici on traite le type1
...
rte

type0:
...
rte

type_minus1:
...
rte

Pour les RAM_CALLs de type adresse et données, on doit pouvoir s'en sortir en ne détruisant que d0 et a0. Spécifier que les RAM_CALLs en F-Line, même pour les types adresse et données, paraît excessif.
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

28

Lionel Debroux (./27) :
Pour sauter entre trois morceaux de code différent, une table de sauts est plus lente qu'un double test

hmmm bien vu, bon à retiendre dans mes notes ça top

29

Voilà ce que ça donnerait :
--- Vectors.asm.old	2009-07-16 20:41:31.000000000 +0200
+++ Vectors.asm	2009-07-22 18:59:17.512566027 +0200
@@ -150,8 +150,9 @@
 	move.w	(sp)+,d1		; Get Old SR
 	move.l	(sp)+,a0		; Get Address of the 'crash'
 	move.w	(a0)+,d0		; We get the instruction and a0 ->next instruction
-	subi.w	#$F800,d0		; Is it > $F800 ? 
+	cmpi.w	#$F800,d0
 	bls.s	\no			; No, so it is a crash (First_Window isn't a ROM_CALL)
+		subi.w	#$F800,d0
 		move.l	a0,a1		; Jsr/Jmp with a 32 bits offset	
 		cmp.w	#$FFF0-$F800,d0
 		bne.s	\NoRelJsr
@@ -175,10 +176,30 @@
 \Jump			move.w	d1,SR		; Restore SR
 			pea	(a0)		; Push return address
 			jmp	(a1)		; Jump to Rom_call function
-\no:	lea	Line1111_str(Pc),a0
+\no:	subi.w	#$F000,d0				; Clear data of exception
+	cmpi.w	#MAX_RAMCALL,d0				; Valid ramcall ?
+	bcc.s	\error					; No, throw an error
+		move.w	d1,SR				; Restore previous SR
+		pea	(a0)				; Push return adress
+		move.b	RAM_TABLE_TYPE(pc,d0.w),d1	; Red type of ramcall (table of bytes)
+		add.w	d0,d0				; Table of longwords
+		add.w	d0,d0
+		lea.l	RAM_TABLE(pc),a0		; Read the ramcall table ptr
+		adda.w	d0,a0				; Add offset : a0 now points to the ramcall
+		movea.l	(a0),a0				; Read it
+		tst.b	d1				; Read its type
+		bmi.s	\ReturnPtr			; -1 : return a ptr in a0
+		beq.s	\ReturnData			; 0  : return data in d0
+			jmp	(a0)			; 1  : else jump to the function
+\ReturnData:	move.l	a0,d0				; Data must be in a0
+\ReturnPtr:	rts					; Else it's already set
+\error:	lea	Line1111_str(Pc),a0
 	bra	FATAL_ERROR
 
-	
+RAM_TABLE_TYPE					; -1 : ptr. 0 : data. +1 : routine
+	dc.b	-1,0,0,-1,0,0,0,0,0,0,0,0,0,-1,-1,0,-1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,-1,-1,-1,1,0,0,0,0,0,1,1,1,1,-1,-1,-1
+
+
 Trap_7:
 Trap_8:
 Trap_10:		; Enter self test

A vérifier si c'est intégré : la table des types. Ca compile, mais j'ai pas encore essayé, j'attends d'abord le verdict. grin

30

hmmm ... une table de saut n'aurait pas été plus courte ?

moveq.l #0,d1
move.b RAM_TABLE_JUMP(pc,d0.w),d1
.....
jmp jump(pc,d1.w)
jump:
label_offset_fonction: jmp a0
label_offset_data: move.l a0,d0
label_offset_ptr: rts

Qu'en pensez-vous ?