(Forth) BOIDS et la gestion des objets

Cette catégorie traite de développements récents pour nos vieilles machines, applications, jeux ou démos... Amis programmeurs, c'est ici que vous pourrez enfin devenir célèbres!

Modérateurs : Papy.G, fneck, Carl

Avatar de l’utilisateur
Dominique
Messages : 828
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: (Forth) BOIDS et la gestion des objets

Message par Dominique »

Un grand merci à Daniel, Mokona et Carl pour les encouragements.
Après avoir divisé par 2 la vitesse de séparation, les BOIDS sont devenus plus sages.
J'ai une question pour les pros du 6809.
Je dois faire en ASM une multiplication par A0h.
Bien que mon multiplicande soit au pire =< 110001 (31h)
je ne peux pas me servir de MULT à cause de LDA #A0 !!!!!!

1 - Y a-t-il une meilleure solution que

Code : Tout sélectionner

8602                    LDA #2
3D                      MUL
8632                    LDA #50
3D                      MUL
2 - ou est il possible de demander à D de faire une somme sur lui même
genre :

Code : Tout sélectionner

ADDR D,D
Merci
__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: (Forth) BOIDS et la gestion des objets

Message par __sam__ »

La multiplication est non signée, donc il n'y a pas de problème à mettre A0h dans A puis faire MUL. C'est de loin la meilleure solution.

Maintenant pour faie "ADDD D" tu a plusieurs options de la plus lente à la plus rapide:Sinon bravo pour les optims. Comme toujours pour aller vite il faut éviter de faire 2 fois (presque) la même chose. Là tu as vu que le calcul de la moyenne de vitesse vu par UN boid peut être déduite de la vitesse moyenne de TOUS le boids, qui peut dès lors n'être que calculée qu'une fois. C'est carrément super :D Tu es ainsi passé d'un algorithme quadratique (le temps passé est proportionnel au carré du nombre de BOIDs) à un algortihme linéaire (il est proportionnel au nombre de BOIDs et pas de son carré). Et le passage de O(n^2) à O(n) change carrément la vitesse d'execution bien mieux que ce que ne saurait faire un codage en asm (qui n'impacte que le multiplicateur constant planqué dans l'expression en "grand-O").
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Avatar de l’utilisateur
Dominique
Messages : 828
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: (Forth) BOIDS et la gestion des objets

Message par Dominique »

Merci _sam_ !
J'avais la tête ailleurs ! et je comptais mentalement 9 bits pour A0h :oops:
Avatar de l’utilisateur
Dominique
Messages : 828
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: (Forth) BOIDS et la gestion des objets

Message par Dominique »

Bonsoir tous,
I° Rien de bien neuf, si ce n'est que je considère maintenant comme terminée la partie FORTH du programme.

Je la donne à suivre avec des notes explicatives :

Vocabulaire:

Code : Tout sélectionner

(index ... adresse paramètres)
<index> BOID(N)  : Met dans la pile de données l'adresse paramètres de l'index-ième BOID

(adresse paramètres ... X, Y)
<adresse paramètres> GETNNN     :  Met dans la pile de données les valeurs X et Y du champs NNNN  de l'objet 
<adresse paramètres> GETPOS     :  Champs position 
<adresse paramètres> GETVELOCTY :  Champs Velocity 
<adresse paramètres> GETV1      :  Champs V1
<adresse paramètres> GETV2      :  Champs V2
<adresse paramètres> GETV3      :  Champs V3

(X, Y, adresse paramètres...)
X Y <adresse paramètres> SETNNN     :  Sauvegarde dans le champs NNN les valeurs X et Y de l'objet 
X Y <adresse paramètres> SETPOS     :  Champs position
X Y <adresse paramètres> SETVELOCTY :  Champs Velocity 
X Y <adresse paramètres> SETV1      :  Champs V1
X Y <adresse paramètres> SETV2      :  Champs V2
X Y <adresse paramètres> SETV3      :  Champs V3

(X, Y, adresse paramètres...)
X Y <adresse paramètres> ADDVNN     :  Somme dans le champs NNN les valeurs X et Y de l'objet
X Y <adresse paramètres> ADDPOS     :  Champs position
X Y <adresse paramètres> ADDVELOCTY :  Champs Velocity 
X Y <adresse paramètres> ADDV1      :  Champs V1
X Y <adresse paramètres> ADDV2      :  Champs V2
X Y <adresse paramètres> ADDV3      :  Champs V3

(a, b, c, d ... a-c, b-d) 
SUBV				    :fait la différence de 2 vecteurs

(a, b, n ... a/n, b/n)
DIVV				    : Divise un vecteur a b  par un scalaire n

(a, b, c, d ... flag'a<c' AND 'b<d')
V<V				    : Retourne flag 1 si a<c et b<d - sinon 0

(/Valeur absolue vecteur)
(a, b ... |a|, |b|)
ABSV				    : Fournit la valeur absolue d'un vecteur a b

les procédures principales :

Code : Tout sélectionner

: RULES123 
	18 1 DO 			; Du Boid 1 à 18 (1° lecture)
		I BOID(N) 		; Adresse paramètre du Boid
		DUP MAIN.OBJ ! 		; Copie et sauvegarde dans variable MAIN.OBJ
		CLEAR.VFIELD 		; Mise à zéro de son V1 , V2 et V3
		RULE.SEPARATION 	; Applique loi 1
		RULE.COHESION 		; Applique Loi 2
		RULE.ALIGNEMENT 	; Applique Loi 3
	LOOP 				; Boid suivant
CLEAR.SIGMA ;  				; Mise à zéro des deux SIGMA

(adressParam 1° lecture .....)
: RULE.ALIGNEMENT 
		>R 			; Adresse objet dans pile R
		SIGMA.V3 2@ 		; Lit vecteur SIGMA V3 = Somme des 17 V3 des Boids
		I GETVELCTY.M 		; Lit vecteur Velocity de l'objet (de 1° lecture)
		SUBV 			; SIGMAV3 - VELOCTY de l'objet = somme des V3 des 16 voisins 
		V/16 			; (SIGMAV3 - VELOCTY)/16 -> moyenne des V3 des 16 voisins
		I GETVELCTY.M 		; Lit vecteur Velocity de l'objet (de 1° lecture)
		SUBV 			; (SIGMAV3 - VELOCTY)/16 - VELOCTY
		ALIGNEMENT @ 		; Lit facteur Alignement
		DIVV 			; ((SIGMAV3 - VELOCTY)/16 - VELOCTY)/FacteurAlignement
		R> 			; dés-empile Adresse objet
		SETV3.M ;  		; Sauvegarde ((SIGMAV3 - VELOCTY)/16 - VELOCTY)/FacteurAlignement dans V3 de l'objet

(adressParam 1° lecture .....adressParam 1° lecture)
: RULE.COHESION 
		>R 			; Adresse objet dans pile R
		SIGMA.V1 2@ 		; Lit vecteur SIGMA V1 = Somme des 17 V1 des Boids
		I GETPOS.M 		; Lit vecteur Position de l'objet (de 1° lecture)
		SUBV 			; SIGMAV2 - Position de l'objet = somme des positions des 16 voisins
		V/16 			; (SIGMAV2 - Position de l'objet)/16 -> moyenne des V3 des 16 voisins
		LEADER 2@ 		; Vecteur Position d'un LEADER manœuvré par utilisateur
		ADDV 			; moyenne des Positions des 16 voisins + position Leader
		2 DIVV 			; divisé par 2 -> Centre de gravité perçu par le Boid
		I GETPOS.M 		; Lit position du Boid (de 1° lecture)
		SUBV 			; Calcule sa distance au centre de gravité
		COHESION @ 		; Lit facteur cohésion
		DIVV 			; Distance au Centre Gravité / facteur cohésion
		I SETV1.M 		; dans V1 de l'objet
		R> ;			; dés-empile Adresse objet

(adressParam 1° lecture .....adressParam 1° lecture)
: RULE.SEPARATION 
		18 1 DO 		; Relit tous les BOIDS (2° lecture)
		I BOID(N) 		; Adresse paramètre du BOID (2° lecture)
		DUP >R 			; Copie dans pile R
		MAIN.OBJ @ - 		; Son adresse paramètre = Adr param BOID (1° lecture) ?
			IF 		; non 0 donc BOID différent
			MAIN.OBJ @ GETPOS.M ; Lit position BOID (1° lecture)
			I GETPOS.M     ; Lit position BOID (2° lecture)
			SUBV 		; Distance entre eux
			DDUP ABSV 	; Fait copie et donne Valeur ABS
			SEPARATION 2@ 	; Lit distance SEPARATION mini pré-définie
			V<V 		; Compare |distance| avec distance séparation
				IF 	; si <
				SCALE   ; divise valeur relative distance par 2
				MAIN.OBJ @ ADDV2.M ; et somme dans V2 du BOID (1° lecture)
				ELSE    ; Si distance >=
				DROP DROP ; Retire distance de la pile données
				ENDIF   ; fin si
			ENDIF           ; fin si
		R> DROP 		; Retire sommet Pile R l'adressParam 2° lecture et jette
		LOOP ;  		; Prochain Boid (2° lecture)

(adressParam  .....adressParam)
: UPDATE.VLCTY 
		>R  			; Copie adresse paramètres dans pile R
		I GETV1.M  		; lit champs V1
		I GETV2.M   		; lit champs V2
		ADDV   		        ; V1 + V2
		I GETV3.M   		; lit champs V3
		ADDV    		; V1 + V2 + V3
		I ADDVELCTY.M           ; somme (V1 + V2 + V3) au champs Velocity 
		R> ; 		        ; Retire sommet Pile R
et enfin le listing complet. Ce programme se trouve dans la K7
>>>
Boids_Full_Forth.zip
(2.36 Kio) Téléchargé 154 fois
<<<

Code : Tout sélectionner

1 9 CLOAD BOIDS
compiler par

Code : Tout sélectionner

1 LOAD
lancer par

Code : Tout sélectionner

BOIDS
(Touche "Q" pour saisir les données)

LISTING COMPLET

Code : Tout sélectionner

( /Listing )

: TASK ; 
HEX

( /Disable et Enable Interrupts)
CREATE DI 1A50 , 0EB6 , SMUDGE  
CREATE EI 1CAF , 0EB6 , SMUDGE 

( /Divise vecteur par 8)
( a, b, 8 ... a/8, b/8)
: V/8 8 DUP >R / SWAP R> / SWAP ; 

( /Divise vecteur par 16)
( a, b, 16 ... a/16, b/16)
: V/16 16 DUP >R / SWAP R> / SWAP ; 

( /Lit une variable double) 
(adr ....a, b)
: 2@ DUP @ SWAP 2+ @ ;  

( /Sauvegarde variable double)
( a, b, adr ...)
: 2! DUP >R 2+ ! R> ! ;

( /Additionne variable double)
( a, b , adr...)  
: 2+! DUP >R 2+ +! R> +! ; 

( /duplique TOS et DOS)
( a, b ...a, b, a, b) 
: DDUP OVER OVER ; 

( /Saisie au clavier de n 0<n<1000)
( ...n)
: #IN 0 0 PAD DUP 3 EXPECT 1- (NUMBER) DROP DROP ;  
: /8 8 / ; 

( /Valeur absolue vecteur)
( a, b ... |a|, |b|)
: ABSV >R ABS R> ABS ;

( /Lit le champs 'position')
( adrObjet ... a, b) 
: GETPOS.M 2@ ; 

( /Somme dans le champs 'position')
( a, b, adrObjet ...)
: ADDPOS.M 2+! ; 

( /compare 2 vecteurs)
( a, b, c, d ... flag'a<c' AND 'b<d')
: V<V SWAP >R < SWAP R> < AND ; 

( /Enregistre dans le champs 'position')
( a, b, adrObjet ...)
: SETPOS.M 2! ;

( a, b, c, d ... a-c, b-d) 
: SUBV SWAP >R - SWAP R> - SWAP ;

( a, b, c, d ... a+c, b+d) 
: ADDV SWAP >R + SWAP R> + SWAP ; 

( Xpos, Ypos ... adresse-écran, Flag coté Gauche/Droit)
: TR-CELL >R 8 / DUP 1 AND SWAP 2 / R> 8 / A0 * + SWAP ; 

( /Choix écran Forme du MO5)
( .....)
: FORME A7C0 DUP C@ 1 OR SWAP C! ; 

( / AND n avec valeur adresse adr et sauvegarde dans adr)
( n, adr ...)
: AND.C! DUP C@ SWAP >R AND R> FORME C! ; 

( / OR n avec valeur adresse adr et sauvegarde dans adr)
( n, adr ...)
: OR.C! DUP C@ SWAP >R OR R> FORME C! ; 

( /Déclare variable double)
( .....)
: 2VARIABLE <BUILDS SWAP , , DOES> ;  

( /Limite ordonnées écran)
18E CONSTANT YMAX  

( /Limite absices écran)
27E CONSTANT XMAX 

( /Variable et constante pour random)
65E8 CONSTANT RMULT  
3 1 2VARIABLE RLOC 

( /Variable adresse paramètres objet analysé)
0 VARIABLE MAIN.OBJ 

( /Variable paramètre Cohésion) 
2B VARIABLE COHESION  

( /Variable paramètre Alignement)
2 VARIABLE ALIGNEMENT  

(/Variable double paramètre Séparation)
14 14 2VARIABLE SEPARATION 

( /Variable double coordonnées Leader) 
15E D2 2VARIABLE LEADER  

( /Variable double somme vecteur V1) 
0 0 2VARIABLE SIGMA.V1  

( /Variable double somme vecteur V2)
0 0 2VARIABLE SIGMA.V3  

( /constructeur de Sprites 4 octets)
: PIC.BOID <BUILDS C, C, C, C, DOES> ; 

( /constructeur de Boids _ 10 champs de 2 octets) 
: BOIDS.OBJ <BUILDS , , , , , , , , , , DOES> ;  

( /Table indexée adresse de Sprites - 8 sprites + 3 répétés - Index de 1 à 11)
: TABLE.PIC.BD <BUILDS , , , , , , , , , , , DOES> SWAP 1- 2 * + @ ;  

( /Table indexée adresse de 17 Boids)
: TABLE.OBJ <BUILDS , , , , , , , , , , , , , , , , , DOES> SWAP 1- 2 * + @ ;  

( /définition Sprites 'Gauche' et 'Droit')
60 60 F0 F0 PIC.BOID PIC.BD.GCH1  
60 60 F0 F0 PIC.BOID PIC.BD.GCH2  
F0 F0 60 60 PIC.BOID PIC.BD.GCH3  
F0 F0 60 60 PIC.BOID PIC.BD.GCH4  
30 F0 F0 30 PIC.BOID PIC.BD.GCH5  
D0 F0 60 C0 PIC.BOID PIC.BD.GCH6  
C0 60 F0 D0 PIC.BOID PIC.BD.GCH7  
C0 60 F0 D0 PIC.BOID PIC.BD.GCH8  
C0 F0 F0 C0 PIC.BOID PIC.BD.GCH9  
B0 F0 60 30 PIC.BOID PIC.BD.GCH10  
30 60 F0 B0 PIC.BOID PIC.BD.GCH11  
6 6 F F PIC.BOID PIC.BD.DRT1  
6 6 F F PIC.BOID PIC.BD.DRT2  
F F 6 6 PIC.BOID PIC.BD.DRT3  
F F 6 6 PIC.BOID PIC.BD.DRT4  
3 F F 3 PIC.BOID PIC.BD.DRT5  
D F 6 C PIC.BOID PIC.BD.DRT6  
C 6 F D PIC.BOID PIC.BD.DRT7  
C 6 F D PIC.BOID PIC.BD.DRT8  
C F F C PIC.BOID PIC.BD.DRT9  
B F 6 3 PIC.BOID PIC.BD.DRT10  
3 6 F B PIC.BOID PIC.BD.DRT11 
 
( a, b ... b)
: NIP SWAP DROP ;

( n ... r) 
: RNDM RLOC 2@ RMULT U* ROT 0 D+ OVER RLOC 2! ;  

( / 0<random<n)
( n ... r) 
: RANDOM RNDM U* NIP ;  

( /Crée tous les Boids)
0 0 0 0 0 0 0 0 YMAX RANDOM XMAX RANDOM BOIDS.OBJ BD1  
0 0 0 0 0 0 0 0 YMAX RANDOM XMAX RANDOM BOIDS.OBJ BD2  
0 0 0 0 0 0 0 0 YMAX RANDOM XMAX RANDOM BOIDS.OBJ BD3  
0 0 0 0 0 0 0 0 YMAX RANDOM XMAX RANDOM BOIDS.OBJ BD4  
0 0 0 0 0 0 0 0 YMAX RANDOM XMAX RANDOM BOIDS.OBJ BD5  
0 0 0 0 0 0 0 0 YMAX RANDOM XMAX RANDOM BOIDS.OBJ BD6  
0 0 0 0 0 0 0 0 YMAX RANDOM XMAX RANDOM BOIDS.OBJ BD7  
0 0 0 0 0 0 0 0 YMAX RANDOM XMAX RANDOM BOIDS.OBJ BD8  
0 0 0 0 0 0 0 0 YMAX RANDOM XMAX RANDOM BOIDS.OBJ BD9  
0 0 0 0 0 0 0 0 YMAX RANDOM XMAX RANDOM BOIDS.OBJ BD10  
0 0 0 0 0 0 0 0 YMAX RANDOM XMAX RANDOM BOIDS.OBJ BD11  
0 0 0 0 0 0 0 0 YMAX RANDOM XMAX RANDOM BOIDS.OBJ BD12  
0 0 0 0 0 0 0 0 YMAX RANDOM XMAX RANDOM BOIDS.OBJ BD13  
0 0 0 0 0 0 0 0 YMAX RANDOM XMAX RANDOM BOIDS.OBJ BD14  
0 0 0 0 0 0 0 0 YMAX RANDOM XMAX RANDOM BOIDS.OBJ BD15  
0 0 0 0 0 0 0 0 YMAX RANDOM XMAX RANDOM BOIDS.OBJ BD16  
0 0 0 0 0 0 0 0 YMAX RANDOM XMAX RANDOM BOIDS.OBJ BD17  

( /Construction tables des Sprites gauche et droite)
( /adresse-écran, Index-Sprite + 1)
( /Sprites gauche)
PIC.BD.GCH11 PIC.BD.GCH10 PIC.BD.GCH9 PIC.BD.GCH8 PIC.BD.GCH7 PIC.BD.GCH6 PIC.BD.GCH5 PIC.BD.GCH4 PIC.BD.GCH3 PIC.BD.GCH2 PIC.BD.GCH1 TABLE.PIC.BD PIC.BOID.GAUCHE  
( /Sprites droite)
PIC.BD.DRT11 PIC.BD.DRT10 PIC.BD.DRT9 PIC.BD.DRT8 PIC.BD.DRT7 PIC.BD.DRT6 PIC.BD.DRT5 PIC.BD.DRT4 PIC.BD.DRT3 PIC.BD.DRT2 PIC.BD.DRT1 TABLE.PIC.BD PIC.BOID.DROIT  

( /Crée la table indexée des Boids)
BD17 BD16 BD15 BD14 BD13 BD12 BD11 BD10 BD9 BD8 BD7 BD6 BD5 BD4 BD3 BD2 BD1 TABLE.OBJ BOID(N)   

( /Lit le champs 'Velocity')
( adrObjet ... a, b)
: GETVELCTY.M 4 + GETPOS.M ;  

( adresse-écran,  Masque... )
: (UNPL.PIC) SWAP DDUP AND.C! DDUP 28 + AND.C! DDUP 50 + AND.C! 78 + AND.C! ;  

( Xpos, Ypos .......)
: UNPLOT.PIC.C TR-CELL 0= IF F ELSE F0 ENDIF (UNPL.PIC) ;  

( adrObjet...)
: UNPLOT.PIC.M GETPOS.M UNPLOT.PIC.C ;  

( /Calcule Masque sprite pour X Velocity)
( adrObjet, Xvelocity...adrObjet, Xindex)
: XINDEXOR DUP -3 < IF DROP 4 ELSE 3 > IF 8 ELSE 0 ENDIF ENDIF ;  

( adrObjet, Yvelocity...adrObjet, Yindex)
: YINDEXOR DUP -3 < IF DROP 2 ELSE 3 > IF 1 ELSE 0 ENDIF ENDIF ;  

( adrObjet... adrObjet, Index-Sprite + 1)
: CALCULE-INDEXOR DUP GETVELCTY.M >R XINDEXOR R> YINDEXOR + 1+ ;  

( adresse-écran,  adr'Pic.Boid'... )
: (PLOT.PIC) DDUP C@ SWAP OR.C! DDUP 1+ C@ SWAP 28 + OR.C! DDUP 2+ C@ SWAP 50 + OR.C! 3 + C@ SWAP 78 + OR.C! ;  

( adrObjet...adresse-écran, Index-Sprite + 1)
: PLOT.PIC.C CALCULE-INDEXOR >R GETPOS.M TR-CELL R> SWAP 0= IF PIC.BOID.GAUCHE ELSE PIC.BOID.DROIT ENDIF ;  

( adrObjet...)
: PLOT.PIC.M PLOT.PIC.C (PLOT.PIC) ;  
DECIMAL 

( /Lit le champs 'V1')
(adrObjet ... a, b) 
: GETV1.M 8 + GETPOS.M ;  

( /Lit le champs 'V2')
( adrObjet ... a, b)
: GETV2.M 12 + GETPOS.M ;  

( /Lit le champs 'V3')
( adrObjet ... a, b)
: GETV3.M 16 + GETPOS.M ;  

( /Sauvegarde dans le champs 'Velocity')
( a, b, adrObjet ...)
: SETVELCTY.M 4 + SETPOS.M ;  

( /Sauvegarde dans le champs 'V1')
( a, b, adrObjet ...)
: SETV1.M 8 + SETPOS.M ;  

( /Sauvegarde dans le champs 'V2')
( a, b, adrObjet ...)
: SETV2.M 12 + SETPOS.M ;  

( /Sauvegarde dans le champs 'V3')
( a, b, adrObjet ...)
: SETV3.M 16 + SETPOS.M ;  

( /Somme dans le champs 'velocity')
( a, b, adrObjet ...)
: ADDVELCTY.M 4 + ADDPOS.M ;  

( /Somme dans le champs 'V1')
( a, b, adrObjet ...)
: ADDV1.M 8 + ADDPOS.M ;  

( /Somme dans le champs 'V2')
( a, b, adrObjet ...)
: ADDV2.M 12 + ADDPOS.M ;  

( /Somme dans le champs 'V3')
( a, b, adrObjet ...)
: ADDV3.M 16 + ADDPOS.M ; 

( /Divise un vecteur par 2)
( a, b ...a/2, b/2)
: SCALE >R 2 / R> 2 / ;  

( /Remet X et Y dans les limites écran)
( X, Y ... 0<X<XMAX, 0<Y<YMAX)
: LIMITPOS >R DUP 0< IF XMAX + ELSE DUP XMAX 2- > IF XMAX 2- - ENDIF ENDIF R> DUP 0< IF YMAX + ELSE DUP YMAX 2- > IF YMAX 2- - ENDIF ENDIF ;  

( /Divise vecteur par scalaire)
( a, b, n ... a/n, b/n)
: DIVV DUP >R / SWAP R> / SWAP ;  

( /Velocity=Velocity+ V1 + V2 + V3)
( adrObjet....adrObjet)
: UPDATE.VLCTY >R I GETV1.M I GETV2.M ADDV I GETV3.M ADDV I ADDVELCTY.M R> ;  

( /Vecteur Position = Vecteur Position + Vecteur Velocity. Au passage fait la sommatoire des Velocity dans SIGMA.V3)
( adrObjet....adrObjet)
: UPDATE.POS >R I GETVELCTY.M DDUP SIGMA.V3 2+! I ADDPOS.M R> ;  

( / Verifie que les coordonnées du BOID soient compatibles avec l'écran et fait la sommatoire des Positions dans SIGMA.V1)
( adrObjet....adrObjet)
: CHECK.POS >R I GETPOS.M LIMITPOS DDUP SIGMA.V1 2+! I SETPOS.M R> ;  

( adrObjet....adrObjet)
: MOVE.M UPDATE.VLCTY UPDATE.POS CHECK.POS ;  

( /Déplacement des Leaders)
(keyf...keyf)
: RIGHT DUP 32 = IF LEADER 2@ >R 20 + DUP XMAX < IF R> ELSE XMAX R> ENDIF LEADER 2! ENDIF ;  
( keyf...keyf)
: LEFT DUP 16 = IF LEADER 2@ >R 20 - DUP -1 > IF R> LEADER 2! ELSE R> DROP DROP ENDIF ENDIF ;  
( keyf...keyf)
: DOWN DUP 24 = IF LEADER 2@ 20 + DUP YMAX < IF LEADER 2! ELSE DROP DROP ENDIF ENDIF ;  
( keyf...keyf)
: UP DUP 8 = IF LEADER 2@ 20 - DUP -1 > IF LEADER 2! ELSE DROP DROP ENDIF ENDIF ;  

( /Lecture et affichage Boids )
: AFFI.BOID 18 1 DO I BOID(N) PLOT.PIC.M LOOP ;  

( /Efface, effectue les calculs et affiche tous les Boids)
: DRAW.BOIDS 18 1 DO I BOID(N) DUP UNPLOT.PIC.M MOVE.M PLOT.PIC.M LOOP ;  

( keyf...keyf)
: PARAM.LEADER CR LEADER 2@ SWAP ." VALEUR DU LEADER ...." CR ." X =" . CR ." Y =" . CR ." NLLE VALEUR X " #IN CR ." NLLE VALEUR Y " #IN LEADER 2! ;  

( keyf...keyf)
: PARAM.SEPAR CR SEPARATION 2@ ." PARAMETRE SEPARATION ...." CR ." Y =" . CR ." X =" . CR ." NLLE VALEUR X SEPARATION " #IN CR ." NLLE VALEUR Y SEPARATION " #IN SEPARATION 2! ;  

( keyf...keyf)
: PARAM.COHESION CR COHESION @ ." PARAMETRE COHESION ...." CR . CR ." NLLE VALEUR COHESION " #IN COHESION ! ;  

( keyf...keyf)
: PARAM.ALIGN CR ALIGNEMENT @ ." PARAMETRE ALIGNEMENT ...." CR . CR ." NLLE VALEUR ALIGNEMENT " #IN ALIGNEMENT ! ;  

( keyf...keyf)
: ?END CR ." Z POUR QUITTER" KEY 90 = IF EI QUIT ENDIF ;  

( keyf...keyf)
: PARAM CLS PARAM.LEADER PARAM.SEPAR PARAM.COHESION PARAM.ALIGN ?END CLS AFFI.BOID ;  

( /Saisie des touches flèches ou Q et appel des procedures)
( ...)
: ?INPUT KEYF DUP 58 < IF UP DOWN LEFT RIGHT 14 = IF PARAM ENDIF ELSE DROP ENDIF ;  

( /Mise à zéro des champs V1 V2 et V3)
( adrObjet....adrObjet)
: CLEAR.VFIELD >R 0 0 DDUP DDUP I SETV2.M I SETV3.M I SETV1.M R> ;  


( /Mise à zéro des Sigma)
( adrObjet....adrObjet)
: CLEAR.SIGMA 0 DUP DUP DUP SIGMA.V1 2! SIGMA.V3 2! ;  

( /Applique loi séparation)
( Adresse objet ...Adresse objet )
: RULE.SEPARATION 18 1 DO I BOID(N) DUP >R MAIN.OBJ @ - IF MAIN.OBJ @ GETPOS.M I GETPOS.M SUBV DDUP ABSV SEPARATION 2@ V<V IF SCALE MAIN.OBJ @ ADDV2.M ELSE DROP DROP ENDIF ENDIF R> DROP LOOP ;  

( /Applique loi cohésion)
( Adresse objet ...Adresse objet )
: RULE.COHESION >R SIGMA.V1 2@ I GETPOS.M SUBV V/16 LEADER 2@ ADDV 2 DIVV I GETPOS.M SUBV COHESION @ DIVV I SETV1.M R> ;  

( /Applique loi alignement)
( Adresse objet ... )
: RULE.ALIGNEMENT >R SIGMA.V3 2@ I GETVELCTY.M SUBV V/16 I GETVELCTY.M SUBV ALIGNEMENT @ DIVV R> SETV3.M ;  

( /Applique les 3 lois)
: RULES123 18 1 DO I BOID(N) DUP MAIN.OBJ ! CLEAR.VFIELD RULE.SEPARATION RULE.COHESION RULE.ALIGNEMENT LOOP CLEAR.SIGMA ;  

( /Remise à zero des Boids)
: INIT 40 COHESION ! 2 ALIGNEMENT ! 20 20 SEPARATION 2! 290 130 LEADER 2! CLEAR.SIGMA 18 1 DO I BOID(N) DUP >R XMAX RANDOM YMAX RANDOM I SETPOS.M 0 0 DDUP DDUP DDUP I SETVELCTY.M I SETV1.M I SETV2.M R> SETV3.M DROP LOOP ;  

( /Lance le programme)
: BOIDS DI CLS AFFI.BOID CLEAR.SIGMA BEGIN RULES123 DRAW.BOIDS ?INPUT AGAIN ;  
QUIT QUIT 

( FIN LISTING)

( // Lancement du programme : BOIDS )

Ce programme est presque 100 % Forth (presque à cause des DI et EI que je n'ai pu mettre en Forth)
Je ne le met que pour ceux qui voudraient l'adapter sur un micro ayant un Fig-Forth.
Il faudra bien entendu adapter la partie affichage, mais c'est tout à fait faisable.

II ASM

Je vais maintenant me concentrer sur la partie ASM.
Depuis longtemps je rêve de pouvoir faire cette transition du Forth -> ASM.
_sam_ l'a dit une fois :
__sam__ a écrit :C'est vraiment pratique qu'on puisse écraser le registre X. Franchement le forth sur thomson m'aurait super plu à l'époque car il permet de faire un mix très bien fichu entre le langage de haut niveau et l'assembleur.
et je suis tout à fait d'accord.
Forth possède tout pour passer progressivement du langage Haut niveau vers ASM si l'on utilise quelques trucs :
que je donne dans un autre message + tard dans la soirée.
Avatar de l’utilisateur
Dominique
Messages : 828
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: (Forth) BOIDS et la gestion des objets

Message par Dominique »

L'interface Forth -> ASM
( suivre par la doc fournie avec la K7 du 'FORTH MO5' sur le site de Daniel http://dcmoto.free.fr -> Programmes Software )
L'interface est extrêmement pratique et permet d'inclure progressivement des procédures (routines ) en ASM à l'intérieur de notre listing Forth.
Pour cela le vocabulaire à notre disposition est le suivant :

HEX : ce mot passe le compilateur base hexadécimale.
CREATE (page 16). ce mot va inclure un mot dans le dictionnaire du Forth.
, et c, (page 23) : Aussi étrange que cela paraisse, ce sont des mots. Ils servent à mettre dans la première adresse RAM disponible le sommet de la pile de données.
, mettra un 16 bits dans la RAM et C, mettra un octet.
HERE (page 20, 22, 24) : est justement l'adresse du pointeur de cette adresse RAM disponible. Forth gère lui même HERE à chaque fois que nous ferons , ou C,.
' (page 22) : On l'appelle tick (shift 7 du MO5) suivi d'un mot du dictionnaire il donne l'adresse PFA du mot. Si le mot est écrit en ASM tick donne la première adresse ASM de ce mot (p20).
SMUDGE (page 22) : Marque définitivement le mot pour l'inclure dans le dictionnaire - Lire page 22
0EB6 (page 16): codification ASM d'un JMP /$B6 - appel de la routine ASM $45B6 appelée NEXT qui redonne la main au Forth pour exécuter le prochain mot Forth.
0EB4 0EAC 0EB0 (page 16): codification ASM d'un JMP /$B4 /$AC /$B0 qui font différentes actions avant de passer à NEXT. Voir les détails page 16

Voyons maintenant par l'exemple :
I - J'ai en Forth le mot

Code : Tout sélectionner

(a, b ... a, b, a, b)

: DDUP OVER OVER ;
Comme on voit dans le descriptif de la pile, il duplique 2 étages de la pile.
Passons le en ASM

Code : Tout sélectionner

CREATE DDUP EC42 , AEC4 , 3606 , 3610 , 0EB6 , SMUDGE
65CE EC42       LDD    $02,U              
65D0 AEC4       LDX    ,U                 
65D2 3606       PSHU   B,A                
65D4 3610       PSHU   X                
65D6 0EB6       JMP    /$B6 
Sauf que je ne peux pas utiliser DDUP comme une routine dans un programme ASM.
Mais je peux faire :

Code : Tout sélectionner

CREATE DDUP 8D02 , 0EB6 , EC42 , AEC4 , 3606 , 3610 , 39 C, SMUDGE

65CE 8D02                    BSR ddup
65D0 0EB6                    JMP NEXT
 
                      ddup
65D2 EC42                    LDD 2,U
65D4 AEC4                    LDX ,U
65D6 3606                    PSHU D
65D8 3610                    PSHU X
65DA 39                      RTS
Je peux maintenant créer un mot :

Code : Tout sélectionner

CREATE TEST BD C, ' DDUP 4 + , 0EB6 , SMUDGE

6000 BD65D2                  JSR ddup
6002 0EB6                    JMP NEXT
II Supposons que pour une raison particulière je ne veuille pas faire BSR $02 mais un JSR, nous pourrions alors faire

Code : Tout sélectionner

CREATE DDUP BD C, HERE 4 + , 0EB6 , EC42 , AEC4 , 3606 , 3610 , 39 C, SMUDGE
6518 BD651D     JSR    $651D              
651B 0EB6       JMP    /$B6               
651D EC42       LDD    $02,U              
651F AEC4       LDX    ,U                 
6521 3606       PSHU   B,A                
6523 3610       PSHU   X                  
6525 39         RTS                       
Bien sur aujourd'hui nous avons des outils autrement plus performants, mais c'est ainsi qu'on faisait dans les années 80
__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: (Forth) BOIDS et la gestion des objets

Message par __sam__ »

J'ai plusieurs questions:

Code : Tout sélectionner

CREATE DDUP EC42 , AEC4 , 3606 , 3610 , 0EB6 , SMUDGE
65CE EC42       LDD    $02,U              
65D0 AEC4       LDX    ,U                 
65D2 3606       PSHU   B,A                
65D4 3610       PSHU   X                
65D6 0EB6       JMP    /$B6 
Ici je fusionnerais les 2 pushs ensembles ce qui fait gagner 6 cycle (et 2 octets):

Code : Tout sélectionner

65CE EC42       LDX    $02,U              <== attention l'ordre X/D est inversé, mais c'est pas grave
65D0 AEC4       LDD    ,U                 
65D2 3606       PSHU   B,A,X                
65D6 0EB6       JMP    /$B6 
Sauf que je ne peux pas utiliser DDUP comme une routine dans un programme ASM.
Par rapport à ca je ne comprends pas trop le sens des instructions [COMPILE] et COMPILE. J'ai l'impression (sans doute fausse) que ca fait une sorte d'INLINE, cad recopie tous les octets qui suivent le CFA en place. Du coup si tu utilises ca dans un create exterieur, ca va ajouter "8D02 , 0EB6 , EC42 , AEC4 , 3606 , 3610 , 39 C," tout seul ?

Ca ne doit pas être ca, mais du coup peux tu expliquer ce que ces instructions [COMPILE] et COMPILE font ?

Code : Tout sélectionner

CREATE TEST BD C, ' DDUP 4 + , 0EB6 , SMUDGE[code][/quote]
Est-ce qu'on ne pourrait pas faire appel à EXECUTE en quittant temporairement le mode assembleur durant la définition?
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Avatar de l’utilisateur
Mokona
Messages : 1040
Inscription : 17 déc. 2016 22:01
Localisation : Nord Est des Yvelines
Contact :

Re: (Forth) BOIDS et la gestion des objets

Message par Mokona »

Ma question à moi est : pourquoi faire un branchement à une sous routine qui est juste derrière, plutôt que d'exécuter ce code directement ?
Avatar de l’utilisateur
Dominique
Messages : 828
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: (Forth) BOIDS et la gestion des objets

Message par Dominique »

1° réponse .

[COMPILE] rend non-immédiat un mot immédiat. Il met son <edit> oops j'ai dit PFA :oops: <fin edit> CFA dans la définition du mot.

[ Faire CNT A ] CNT Z

Code : Tout sélectionner

: TASK ;

: ALO ." ALO" ; IMMEDIATE

: TEST1 ALO ; <CR> ALO ok

: TEST2 [COMPILE] ALO ; ok
TEST2 <cr> alo


COMPILE s'utilise dans les mots immédiats pour demander de compiler un mot dans une définition, alors qu'il s'exécute

Code : Tout sélectionner

: TASK ;

: ALO ." ALO" ;

: TEST1 COMPILE ALO ; IMMEDIATE

: TEST2 TEST1 ; <cr> ok
TEST2 <cr> ALO ok
COMPILE.jpg
COMPILE.jpg (40.88 Kio) Consulté 7045 fois
Dernière modification par Dominique le 17 févr. 2017 16:49, modifié 1 fois.
Avatar de l’utilisateur
Dominique
Messages : 828
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: (Forth) BOIDS et la gestion des objets

Message par Dominique »

Je vais prendre à la suite les qutres questions pour y répondre plus tard.

Il a été soulevé une question très intéressante : Créer un mot qui donne une suite d'instructions ASM que l'on peut inclure dans une procédure CREATE.
C'est tout à fait possible et simple
On pourra remplacer 0EB6 par un mot : NEXT par exemple. Ou toute autre.
Posez vos questions. Je ne prétend pas tout savoir.

Si @ yo_fr veut participer au réponses, il est le bien venu.
D'autres aussi
Avatar de l’utilisateur
Dominique
Messages : 828
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: (Forth) BOIDS et la gestion des objets

Message par Dominique »

Pour répondre à _sam_

A) Sans vouloir être taquin (tout en l'étant) et dit avec un large sourire amical:

Chouette, tu te corriges à toi même :D :) car mon DDUP venait d'un de tes messages

Code : Tout sélectionner

    (5) LDX ,U
    (7) PUSHU D
    (7) PUSHU X
Trêve de plaisanterie tu sais combien je suis friand de tes optimisations !

B) On a parfois l'impression que par CREATE on se trouve à l'intérieur d'une procédure qui dirige la création d'un code ASM.

Or ce n'est pas le cas. CREATE ne sert qu'à créer une entête qui sera incorporée dans le dico.
Après avoir calculé la longueur du mot, avoir mis le lien vers le mot précédent du dictionnaire (link field)
mis comme CFA (Code Field Adresse) l'adresse qui suit, elle passe la main au Forth qui lui se trouve en mode exécution normal.

En gros
CREATE DDUP <cr> fais ça

Code : Tout sélectionner

650F A4  <- longeur pas encore SMUDGEE
6510 44 44 55 D0  <- ASCII D D U 'P'+$80
6514 64 E1 <- lien vers le dernier mot du dico (Link Field Adress)
6516 64 18 <- Lien vers les codes (Code Field Adress)
6418       <- adresse libre pour y mettre les codes.
Imaginons maintenant des macros : un mot DDUP.ASM ainsi écrit :

Code : Tout sélectionner

: DDUP.ASM  AE42 , ECC4 , 3616 , 39 C, ;
un mot BSR+NEXT ainsi écrit :

Code : Tout sélectionner

: BSR+NEXT 8D02 , 0EB6 , ;
je peux faire

Code : Tout sélectionner

CREATE DDUP BSR+NEXT DDUP.ASM SMUDGE

6565 8D02       BSR    $6569              
6567 0EB6       JMP    /$B6               
6569 AE42       LDX    $02,U              
656B ECC4       LDD    ,U                 
656D 3616       PSHU   X,B,A              
656F 39         RTS                       
Create.jpg
Create.jpg (36.93 Kio) Consulté 7035 fois
Je crois que c'est comme ça que tu pensais

@ Mokona

L'idée maintenant est de passer du Forth en total ASM en respectant, si possible, la structure Forth; Sauf que
les mots sont maintenant des routines.

1) Si j'ai une routine pour DUP une pour @ une pour SWAP etc.

je transforme mon programme avec des

BSR (ou JSR)

Code : Tout sélectionner

MOT1
	BSR C_mot1
	JMP NEXT
C_mot1
	JSR c_dup
	JSR c_@
	JSR C_SWAP
	RTS
Mais aussi

Code : Tout sélectionner

MOT2
	BSR C_mot2
	JMP NEXT
c_mot2
	JSR C_mot1
	.....
	RTS

Tant que ce sont des DUP des @ etc. bien entendu il n'y a aucun intérêt, mais pour des procédures longues et complexes c'est plus pratique.

2) un autre avantage est d'introduire progressivement de l'ASM dans son Forth.

MOT1 est accessible en ASM par MOT2 (écrit en ASM ) mais est aussi accessible par d'autres définitions
encore écrites en Forth qui d'aventure auraient aussi besoin de MOT1

Je continue don avec mon Forth mais il sera progressivement remplacé par de l'ASM
__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: (Forth) BOIDS et la gestion des objets

Message par __sam__ »

Tout ca est une approche très intéressante je trouve. Je pense qu'on peut complètement programmer en ASM avec une structuration à la forth: utilisation de la pile "U", plein de petite méthodes toutes courtes qui ne sont que succession de JSR vers d'autres petites méthodes.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Avatar de l’utilisateur
Dominique
Messages : 828
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: (Forth) BOIDS et la gestion des objets

Message par Dominique »

Je me souviens avoir jeté un coup d'oeil sur le fameux Graforth qui tournait sur Apple.
C'est très exactement comme ça que ça se passait : la compilation donnait directement des JSR adresse_du_mot.
J'ai essayé de comprendre plus à fond, mais, bon, c'était trop pour moi.
__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: (Forth) BOIDS et la gestion des objets

Message par __sam__ »

Tous ces JSR rendent le code plus rapide mais moins compact en mémoire que la succession des adresses utilisées par DO_COLON. Je pense que DO_COLON est un code qui lit et execute la suite de CFA jusqu'au ";S" final. Je crois que l'usage du "DO_COLON" est le "Direct threading" et que utilisation des JSR le "Subroutine threading".

Plus d'info sur ces histoires de style de threading >>ici<< (en anglais)
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Avatar de l’utilisateur
Dominique
Messages : 828
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: (Forth) BOIDS et la gestion des objets

Message par Dominique »

Le projet BOIDS avance malheureusement trop lentement ces derniers temps.
Je dois pouvoir m'y remettre dans quelques jours.
3 axes majeurs :
1 - Terminer la mise en ASM des procédures les plus critiques pour gagner en rapidité. J'en ai fait quelques unes à temps perdu.
2 - Mais ça ne règle pas l'impression de saccadé que vous voyez dans la vidéo de la semaine dernière. J'y vois quelques raisons évidentes :
a) Même si les coordonnées du BOIDS sont de X=0->640 Y=0->400 l'affichage, lui, se fait sur 80 colonnes * 50 lignes.
b) Si je passe à 160 colonnes * 100 lignes, ce que je vais gagner en fluidité, je vais le perdre en vitesse. Pire si je repasse
à la définition 320 * 200.
c) donc, quelque soit le choix il faudra refaire les procédures d'affichage.
3 - Enfin je n'ai pas oublié le projet de réécrire le programme en une suite de JSR.
__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: (Forth) BOIDS et la gestion des objets

Message par __sam__ »

Ne t'inquiètes pas, les bonnes choses prennent du temps. Qui va piano, va sano comme on dit quelque part :P
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Répondre