[FORTH] Le mécanisme Forth

Tout ce qui concerne le logiciel original et sa sauvegarde avec entre autre la régénération des disquettes ou autres supports physiques.

Modérateurs : Papy.G, fneck, Carl

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

[FORTH] Le mécanisme Forth

Message par Dominique »

LE MÉCANISME FORTH PARTIE 1

Salut à Tous,
Je vous prie de m'excuser si le message est un peu long mais il m'a semblé utile de mettre un exemple
qui permette de comprendre un peu mieux la mécanique Forth et surtout parler de sa fameuse Machine Virtuelle.
On va partir d'un exemple, mais je vais être obligé de forcer le trait pour en arriver où je veux.

Nous sommes dans les années 70 et supposons que nous ayons à écrire un programme ASM pour le 6809 qui calcule la fonction f(x)=8x + 7
La technique ici est ce que les Américains appellent "Threaded code" https://en.wikipedia.org/wiki/Threaded_code
Je n'ai jamais vraiment trouvé de traduction française.
Je me souviens avoir lu une fois "Programmation filaire" et moi ça me convient.
Arrivant à la conclusion qu'il me suffit de prendre un registre et de savoir y ajouter 1, y retrancher 1 et le multiplier par deux je fais :

Code : Tout sélectionner

   ORG $4550
                              SETDP $45
                                            ;****************
                                            ;* 8D+7
                                            ;****************
 
                      Entree_Forth
 4550 8645                    LDA    #$45
 4552 1F8B                    TFR    A,DP
 4554 CC0010                  LDD   #$0010	; Calcul pour la valeur D=$0010

;**********************************************************

; Calcul de la fonction F(D) = 8*D+7 = 2*2*2(D+1)-1

; MAIN PROGRAM
                      Code_8Dplus7
 
 4557 BD4566                  JSR Code_plusun
 455A BD456E                  JSR Code_deuxfois
 455D BD456E                  JSR Code_deuxfois
 4560 BD456E                  JSR Code_deuxfois
 4563 BD456A                  JSR Code_moinsun

; END OF MAIN PROGRAM- Résultat dans D

;********************************************************** 

 ; D+1
                      Code_plusun
 4566 C30001                  ADDD   #$0001
 4569 39                      RTS
 
; D-1
                      Code_moinsun
 456A 830001                  SUBD   #$0001
 456D 39                      RTS

; 2*D
 
                      Code_deuxfois
 456E 58                      LSLB
 456F 49                      ROLA
 4570 39                      RTS
Il faut se souvenir qu'au tout début de l'informatique le problème n'était pas la vitesse d'exécution, on passait du manuel à la vitesse de
la lumière; c'était la mémoire. Chaque Ko était fait à la main et coûtait une fortune.
Très tôt on a cherché à économiser cette mémoire ROM ou RAM et on a vite remarqué que des adresses $4557 à $4563 on répétait l'instruction BD (JSR)
Naturellement l'idée est venue très tôt de faire un "Interpréteur d'adresse" qui ne lirait que les adresses et simulerait les JSR.
En fin de routine, au lieu de faire un RST il suffisait de retourner à l'interpréteur.
OBS : l'interpréteur d'adresse a existé avant le Forth.
Je modifie mon programme et j'appelle cet interpréteur d'adresses directes PseudoNext :

Code : Tout sélectionner


                              ORG $4550
                              SETDP $45
 ; DEBUT
 
 4550 7E4555                  JMP Entree_Forth
                      Adresse_Code    
 4553 4564                    FDB Code_8Dplus7		; Début du programme

; (COLD)
                      Entree_Forth  
 4555 8645                    LDA    #$45
 4557 1F8B                    TFR    A,DP
 4559 CC0010                  LDD   #$0010		; Calcul de la fonction pour D = $0010
 455C 108E4553                LDY   #Code_8Dplus7	; Ecriture adresse du début du programme dans le pointeur d'adresse Y
 
 ; INTERPRETEUR D ADRESSES DIRECTES

                      Code_PseudoNext
 4560 AEA1                    LDX    ,Y++          	; Ecriture de l'adresse dans X et avancement du pointeur vers l'adresse suivante                
 4562 6E84                    JMP    ,X			; Saut vers l'adresse de la sous-routine
 

 ;***************************************************************
; Programme principal
; Calcul de la fonction F(D) = 8*D+1 = 2*2*2(D+1)-1

                      Code_8Dplus7
 
 4564 456E                    FDB Code_plusun
 4566 4578                    FDB Code_deuxfois
 4568 4578                    FDB Code_deuxfois
 456A 4578                    FDB Code_deuxfois
 456C 4573                    FDB Code_moinsun
 
  ; END - Résultat dans D
;*****************************************************************

; MOTS DU VOCABULAIRE

                      Code_plusun
 456E C30001                  ADDD   #$0001
 4571 0E60                    JMP Code_PseudoNext	; Retour à l'interpréteur d'adresse
 
                      Code_moinsun
 4573 830001                  SUBD   #$0001
 4576 0E60                    JMP Code_PseudoNext	; Retour à l'interpréteur d'adresse
 
 
                      Code_deuxfois
 4578 58                      LSLB
 4579 49                      ROLA
 457A 0E60                    JMP Code_PseudoNext	; Retour à l'interpréteur d'adresse

Version Z80 de l'interpréteur d'adresse direct

Code : Tout sélectionner

0001   0000              ;tasm -80 listing2.asm –g3
0002   4550                     .ORG $4550
0003   4550              ; DEBUT
0004   4550 C3 55 45     				JP Entree_Forth
0005   4553             Adresse_Code:    
0006   4553 62 45       				.DW Code_8Dplus7		; Début du programme (Sans utilité)
0007   4555             ; (COLD)
0008   4555             Entree_Forth:  
0009   4555 11 10 00    				LD DE,	$0010			; Calcul pour la valeur DE=$0010
0010   4558 01 62 45    				LD BC,	Code_8Dplus7		; Ecriture adresse du début du programme dans le pointeur d'adresse Y
0011   455B               
0012   455B              ; INTERPRETEUR D ADRESSES DIRECTES
0013   455B             Code_PseudoNext:
0014   455B 0A          				LD A,(BC)
0015   455C 6F           				LD L,A
0016   455D 03          				INC BC
0017   455E 0A          				LD A,(BC)
0018   455F 67          				LD H,A
0019   4560 03          				INC BC
0020   4561 E9          				JP (HL)
0021   4562             
0022   4562              ;***************************************************************
0023   4562             ; Programme principal
0024   4562             ; Calcul de la fonction F(D) = 8*DE+1 = 2*2*2(DE+1)-1
0025   4562             Code_8Dplus7:
0026   4562              
0027   4562 6C 45       				.DW Code_plusun
0028   4564 74 45        				.DW Code_deuxfois
0029   4566 74 45       				.DW Code_deuxfois
0030   4568 74 45       				.DW Code_deuxfois
0031   456A 70 45       				.DW Code_moinsun
0032   456C              
0033   456C               ; END - Résultat dans DE
0034   456C             ;*****************************************************************
0035   456C             
0036   456C             ; MOTS DU VOCABULAIRE
0037   456C             
0038   456C              ; DE+1
0039   456C             Code_plusun:
0040   456C 13          				INC DE
0041   456D C3 5B 45    				JP Code_PseudoNext
0042   4570              
0043   4570             ; DE-1
0044   4570             Code_moinsun:
0045   4570 1B          				DEC DE
0046   4571 C3 5B 45    				JP Code_PseudoNext
0047   4574             
0048   4574             ; 2*DE
0049   4574              
0050   4574             Code_deuxfois:
0051   4574 AF          				XOR A
0052   4575 CB 13       				RL E
0053   4577 CB 12       				RL D
0054   4579 C3 5B 45    				JP Code_PseudoNext
A suivre partie II

Nota : Voulant faire très vite je n'ai pas vérifié mes codes sur émulateur, merci de me signaler toutes coquilles

EDIT du 15-10: Ajouté version Z80 de l'interpréteur d'adresse direct
Dernière modification par Dominique le 15 oct. 2020 11:15, modifié 2 fois.
Avatar de l’utilisateur
Dominique
Messages : 828
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: [FORTH] Le mécanisme Forth

Message par Dominique »

LE MÉCANISME FORTH PARTIE 2

Pour des raisons tout d'abord historiques, l'ordinateur de l'époque de Charles Moore ne possédant que l'indirection
(c'est du moins ce que j'ai lu) et ensuite pour des questions de flexibilité dans le développement de son langage,
le créateur du Forth écrivit son interpréteur d'adresses indirectes.

C'est à dire que les lignes de programmes ne pointent plus sur les adresses, mais sur les adresses contenant les adresses.
Il les a nommées CFA Code Field Address.

Pour le 6809, miracle, la seule modification de NEXT est JMP [,X] au lieu de JMP ,X en plus de la création des Code Field.

Code : Tout sélectionner


                              ORG $4550
                              SETDP $45
 
                       ; DEBUT
 
 4550 7E4555                  JMP Entree_Forth
                      Adresse_Code    
 4553 4564                    FDB Code_8Dplus7
 
                      ; (COLD)
                      Entree_Forth
 4555 8645                    LDA    #$45
 4557 1F8B                    TFR    A,DP
 4559 CC0010                  LDD   #$0010            ; Calcul de la fonction pour D = $0010
 455C 108E4553                LDY    #Adresse_Code    ; Ecriture adresse du début du programme dans le pointeur d'adresse Y

 
                       ; INTERPRETEUR D ADRESSES INDIRECTES
 
                      Next
 4560 AEA1                    LDX    ,Y++             ; Ecriture de l'adresse dans X et avancement du pointeur vers l'adresse suivante                
 4562 6E94                    JMP    [,X]             ; Saut par INDIRECTION vers l'adresse de la sous-routine

 
 
                       ;***************************************************************

                      ; Programme principal
                      ; Calcul de la fonction F(D) = 8*D+1 = 2*2*2(D+1)-1
 
 
                      Code_8Dplus7
 
 4564 456E                    FDB cf_plusun
 4566 457C                    FDB cf_deuxfois
 4568 457C                    FDB cf_deuxfois
 456A 457C                    FDB cf_deuxfois
 456C 4575                    FDB cf_moinsun
 
                        ; END - Résultat dans D
                      ;*****************************************************************

 
                      ; MOTS DU VOCABULAIRE
 
                      cf_plusun
 456E 4570                    FDB Code_plusun 		; Code Field pointant vers le code

                      Code_plusun
 4570 C30001                  ADDD   #$0001
 4573 0E60                    JMP Next
 
                      cf_moinsun
 4575 4577                    FDB Code_moinsun        ; Code Field pointant vers le code

                      Code_moinsun
 4577 830001                  SUBD   #$0001
 457A 0E60                    JMP Next
 
                      cf_deuxfois
 457C 457E                    FDB Code_deuxfois       ; Code Field pointant vers le code

                      Code_deuxfois
 457E 58                      LSLB
 457F 49                      ROLA
 4580 0E60                    JMP Next
  

Il est bien entendu embêtant de monopoliser le registre D. Comme la pile U est disponible, mettons les calculs intermédiaires dans cette pile U.

notre programme deviendra :

Code : Tout sélectionner

 
                              ORG $4550
                              SETDP $45
 
                       ; DEBUT
 
 4550 7E4555                  JMP Entree_Forth
                      Adresse_Code    
 4553 4566                    FDB Code_8Dplus7
 
                      ; (COLD)
                      Entree_Forth
 4555 8645                    LDA    #$45
 4557 1F8B                    TFR    A,DP
 4559 CC0010                  LDD   #$0010            ; Calcul de la fonction pour D = $0010
 455C 3606                    PSHU   B,A              ; Dans la pile U
 455E 108E4566                LDY    #Code_8Dplus7    ; Ecriture adresse du début du programme dans le pointeur d'adresse Y

 
                       ; INTERPRETEUR D ADRESSES INDIRECTES
 
                      Next
 4562 AEA1                    LDX    ,Y++             ; Ecriture de l'adresse dans X et avancement du pointeur vers l'adresse suivante                
 4564 6E94                    JMP    [,X]             ; Saut par INDIRECTION vers l'adresse de la sous-routine

 
 
                       ;***************************************************************

                      ; Programme principal
                      ; Calcul de la fonction F(D) = 8*D+1 = 2*2*2(D+1)-1
 
 
                      Code_8Dplus7
 
 4566 4570                    FDB cf_plusun
 4568 4586                    FDB cf_deuxfois
 456A 4586                    FDB cf_deuxfois
 456C 4586                    FDB cf_deuxfois
 456E 457B                    FDB cf_moinsun
 
                        ; END - Résultat dans le Top of Stack de la pile
                      ;*****************************************************************

 
                      ; MOTS DU VOCABULAIRE
 
                      cf_plusun
 4570 4572                    FDB Code_plusun		; Code Field pointant vers le code
                      Code_plusun
 4572 ECC4                    LDD    ,U                  	; Lecture du TOS Top Of Stack                
 4574 C30001                  ADDD   #$0001    
 4577 EDC4                    STD    ,U                		; Ecriture dans le TOS Top Of Stack
 4579 0E62                    JMP Next         
 
                      cf_moinsun
 457B 457D                    FDB Code_moinsun		; Code Field pointant vers le code
                      Code_moinsun
 457D ECC4                    LDD    ,U                   	; Lecture du TOS Top Of Stack
 457F 830001                  SUBD   #$0001
 4582 EDC4                    STD    ,U                		; Ecriture dans le TOS Top Of Stack
 4584 0E62                    JMP Next
 
                      cf_deuxfois
 4586 4588                    FDB Code_deuxfois		; Code Field pointant vers le code
                      Code_deuxfois
 4588 ECC4                    LDD    ,U                   	; Lecture du TOS Top Of Stack
 458A 58                      LSLB
 458B 49                      ROLA
 458C EDC4                    STD    ,U                		; Ecriture dans le TOS Top Of Stack
 458E 0E62                    JMP Next
Bien entendu on peut optimiser à commencer par le fait que nous pouvons créer une entrée juste avant NEXT que nous appellerons PUT avec l'instruction STD ,U et nous remplacerons
STD ,U JMP NEXT par JMP PUT

Partie 3 (finale) à suivre demain soir
Dernière modification par Dominique le 13 nov. 2020 13:32, modifié 4 fois.
__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [FORTH] Le mécanisme Forth

Message par __sam__ »

Ah noter au passage un autre optimisation possible trouvée dans CamelForth 6809 (qui est récent: 1995) à savoir garder le sommet de la pile dans le registre D, ce qui réduit les accès mémoire pour la plupart des opérations (on a typiquement une lecture et une écriture en moins par opération).

Ce forth a d'autres particularités qui intéresseront spécifiquement Dominique: la pile de donnée est dans S, celle de retour dans U (l'inverse des trucs habituels sur ce CPU), son code source est lui-même décrit en Forth avec de l'ASM 6809 aussi écrit symboliquement en forth (trop fort ce forth!).
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
6502man
Messages : 12286
Inscription : 12 avr. 2007 22:46
Localisation : VAR
Contact :

Re: [FORTH] Le mécanisme Forth

Message par 6502man »

Très intéressant le désassemblage du Forth, on voit que le 6809 est très bien utiliser.
les saut par indirections sont très pratique ont peut le faire aussi en Z80 ;)
Phil.

www.6502man.com

To bit or not to bit.
1 or 0.
__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [FORTH] Le mécanisme Forth

Message par __sam__ »

Oui oui c'est passionnant, surtout les histoires de "VM" (machine virtuelle) concue pour garder une bonne vitesse et compacité du code en mémoire (des trucs plus du tout d'actualité sur les PC modernes, hélas).

Quand on combine ca avec la Z-machine qui est capable de charger du code et des données depuis le disk plus que la mémoire disponible (principe de Mémoire Virtuelle: VM aussi là encore), le tout combiné à des support de masse gigantesques comme les cartes SD, on se prends à rêver de trucs totalement déraisonnables... Mais je m'égare... Revenons sur terre et finissons ce qui est en cours.
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
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [FORTH] Le mécanisme Forth

Message par hlide »

__sam__ a écrit : 14 oct. 2020 02:59 Ce forth a d'autres particularités qui intéresseront spécifiquement Dominique: la pile de donnée est dans S, celle de retour dans U (l'inverse des trucs habituels sur ce CPU), son code source est lui-même décrit en Forth avec de l'ASM 6809 aussi écrit symboliquement en forth (trop fort ce forth!).
N'est-ce pas le principe d'un Forth-kernel ?
Avatar de l’utilisateur
Dominique
Messages : 828
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: [FORTH] Le mécanisme Forth

Message par Dominique »

LE MÉCANISME FORTH PARTIE 3

Avançons dans notre programme et imaginons que nous voulions faire une variante du programme que nous avons écrit.
On nous demande de multiplier par deux le résultat f(x) que j'ai au sommet de la pile.
En quelque sorte calculer 16x+14

L'idée est donc d'écrire un programme (appelons le double_fx qui fasse appel à Code_8Dplus7 puis fasse appel à cf_deuxfois.

La tentation est grande d'écrire :

Code : Tout sélectionner

.......

	LDY    #double_fx
....
                      ; INTERPRETEUR D ADRESSES INDIRECTES
 
                      Next
	LDX    ,Y++             ; Ecriture de l'adresse dans X et avancement du pointeur vers l'adresse suivante                
	JMP    [,X]             ; Saut par INDIRECTION vers l'adresse de la sous-routine

**********************
; Calcul de (8D+7)*2
**********************

double_f(x)

	FDB Code_8Dplus7
	FDB cf_deuxfois
.....
                     Code_8Dplus7
 
	FDB cf_plusun
	FDB cf_deuxfois
	FDB cf_deuxfois
	FDB cf_deuxfois
	FDB cf_moinsun
	
....

etc..
Mais on sent bien que ça ne va pas marcher :
Le pointeur d'adresse Y pointe sur double_fx (adresse FDB Code_8Dplus7) à l'entrée de l'interpréteur d'adresse et par Y++ il pointera sur adresse FDB cf_deuxfois à la sortie.
Il sera donc bien incapable d’enchaîner Code_8Dplus7 pour l’exécuter
.
Seule solution, sauvegarder provisoirement Y qui gère le programme double_fx et demander aussitôt après à Y de gérer le programme Code_8Dplus7.

Pour sauvegarder Y pas de problèmes, nous avons la pile S du 6809 que nous appellerons Pile Retour, et comme par chance X pointe sur le début de Code_8Dplus7, nous nous en servirons pour actualiser Y.

On va donc créer un petit ASM que nous appelons c_docol et qui s'écrira :

Code : Tout sélectionner

 c_docol              
	PSHS   Y  		; Y dans la pile retour S               
	LEAY   $02,X  		; Load Y effective Address (X)+2 ; c_docol étant au début de Code_8Dplus7 il faut bien le passer             
	JMP    NEXT   		; Y pointant sur FDB cf_plusun de Code_8Dplus7 on peut interpréter l'adresse.
	
IMPORTANT :

c_docol est obligatoirement un code ASM et pas un Code Field cf_ . Suivez bien l'interpréteur d'adresse pour vous en convaincre.

Pour sortir de Code_8Dplus7 et récupérer Y écrivons le mot SEMIS, cette fois ci c'est en Forth, avec Code Field cf_

Code : Tout sélectionner

                     cf_semis
	FDB c_semis		; Code Field de semis
                      c_semis
	PULS   Y                ; Mise à jour du pointeur d'adresse Y
 	JMP    NEXT   		; Retour vers l'interpréteur.
 	

Notre programme s'écrira donc maintenant :

Code : Tout sélectionner

                              ORG $4550
                              SETDP $45
 
                       ; DEBUT
 
 4550 7E4555                  JMP Entree_Forth
                      Adresse_Code    
 4553 4566                    FDB double_fx	; Sans effet pour le moment
 
                      ; (COLD)
                      Entree_Forth
 4555 8645                    LDA    #$45
 4557 1F8B                    TFR    A,DP
 4559 CC0010                  LDD   #$0010            ; Calcul de la fonction pour D = $0010
 455C 3606                    PSHU   B,A              ; Dans la pile U
 455E 108E4566                LDY    #double_fx       ; Ecriture adresse du début du programme dans le pointeur d'adresse Y

 
                       ; INTERPRETEUR D ADRESSES INDIRECTES
 
                      Next
 4562 AEA1                    LDX    ,Y++             ; Ecriture de l'adresse dans X et avancement du pointeur vers l'adresse suivante               
 4564 6E94                    JMP    [,X]             ; Saut par INDIRECTION vers l'adresse de la sous-routine

 
 
                      ;*********************************************************
******
                      ; Programme principal
                      ;Calcul de la fonction F(D) = (2*2*2(D+1)-1) * 2
 
                      double_fx
 
 4566 4576                    FDB cf_Code_8Dplus7
 4568 459A                    FDB cf_deuxfois
 
                      ; END - Résultat dans le Top of Stack de la pile
                      ;*********************************************************
********
 
                      ; MOTS DU VOCABULAIRE
 
                      c_docol
                                                      
 456A 3420                    PSHS   Y                ; Y dans la pile retour  
              
 456C 3102                    LEAY   $02,X            ; Load Y effective Address (X)+2 
 						      ;c_docol étant au début de Code_8Dplus7 il faut bien le passer						             
 456E 0E62                    JMP    NEXT             ; Y pointant sur FDB cf_plusun de Code_8Dplus7
				                      ; on peut interpréter l'adresse.
                       
                      cf_semis
 4570 4572                    FDB c_semis             ; Code Field de semis
                      c_semis
 4572 3520                    PULS   Y                ; Mise à jour du pointeur d'adresse Y
 4574 0E62                    JMP    NEXT             ; Retour vers l'interpréteur.

 
                      ; Calcul de la fonction F(D) = 8*D+1 = 2*2*2(D+1)-1
                      cf_code_8Dplus7
 4576 456A                    FDB c_docol
 4578 4584                    FDB cf_plusun
 457A 459A                    FDB cf_deuxfois
 457C 459A                    FDB cf_deuxfois
 457E 459A                    FDB cf_deuxfois
 4580 458F                    FDB cf_moinsun
 4582 4570                    FDB cf_semis
 
                      cf_plusun
 4584 4586                    FDB Code_plusun
                      Code_plusun
 4586 ECC4                    LDD    ,U                 
 4588 C30001                  ADDD   #$0001    
 458B EDC4                    STD    ,U
 458D 0E62                    JMP Next         
 
                      cf_moinsun
 458F 4591                    FDB Code_moinsun
                      Code_moinsun
 4591 ECC4                    LDD    ,U  
 4593 830001                  SUBD   #$0001
 4596 EDC4                    STD    ,U
 4598 0E62                    JMP Next
 
                      cf_deuxfois
 459A 459C                    FDB Code_deuxfois
                      Code_deuxfois
 459C ECC4                    LDD    ,U  
 459E 58                      LSLB
 459F 49                      ROLA
 45A0 EDC4                    STD    ,U
 45A2 0E62                    JMP Next
 
Vous trouverez ici le fichier bin du programme ci dessus.
MachineVirtForth.zip
(222 octets) Téléchargé 186 fois
Sur le DCMOTO de Daniel (dernière version 2020.04.29) dans Outils - Mise au point (2) faire un Load du fichier adresse $4550.
Bien s'assurer que les piles U et S pointent vers une adresse de la RAM (perso j'ai mis S=$9F00 et U=$7F00)
en mettant le registre PC à $4550 on peut faire le pas à pas.

Ces 3 routines : NEXT , c_docol et cf_semis constituent la Machine virtuelle FORTH.

A SUIVRE CE SOIR
Avatar de l’utilisateur
6502man
Messages : 12286
Inscription : 12 avr. 2007 22:46
Localisation : VAR
Contact :

Re: [FORTH] Le mécanisme Forth

Message par 6502man »

Merci pour ce petit cours Forth / ASM :D
Phil.

www.6502man.com

To bit or not to bit.
1 or 0.
Avatar de l’utilisateur
Dominique
Messages : 828
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: [FORTH] Le mécanisme Forth

Message par Dominique »

Merci Phil

Avant de voir des exemples de sauts conditionnels en Forth et un exemple de récursivité, voici la traduction de la machine virtuelle pour le Z80.

Comme nous n'avons qu'une pile nous la réservons pour les données, la pile retour (RPP) étant gérée par le soft.
Le pointeur d'adresse Y du 6809 est traditionnellement le BC du Z80 et le X est le DE.

Code : Tout sélectionner


0001   0000              ;tasm -80 machinevirtz80.asm –g3
0002   4550                     .ORG $4550
0003   4550             				; DEBUT
0004   4550              
0005   4550 C3 57 45    	JP Entree_Forth
0006   4553             Adresse_Code:    
0007   4553 6C 45       	.DW double_fx		; Sans effet pour le moment
0008   4555                                   		; (COLD)
0009   4555             RPP:
0010   4555 BE 7F       	.DW $7FBE		; Definition de l'adresse de la Pile Retour
0011   4557             Entree_Forth:
0012   4557 31 1E 7F    	LD SP,$7F1E		; Definition TOS de la pile de données
0013   455A 21 10 00    	LD HL,$0010		; Variable de la fonction à $10
0014   455D E5          	PUSH HL			; Dans le TOS de la pile de données
0015   455E 01 6C 45    	LD BC,double_fx			
0016   4561             
0017   4561                                    		; INTERPRETEUR D ADRESSES INDIRECTES
0018   4561             NEXT:   
0019   4561 0A          	LD      A,(BC)  	;(W) <- ((IP))
0020   4562 03                  INC     BC      	;avancement du pointeur vers l'adresse suivante (IP) <- (IP)+2
0021   4563 6F                  LD      L,A
0022   4564 0A          NEXT3:  LD      A,(BC)  	;LABEL ADDED BY DLW
0023   4565 03                  INC     BC		;avancement du pointeur vers l'adresse suivante
0024   4566 67                  LD      H,A     	;(HL) <- CF
0025   4567 5E          NEXT1:  LD      E,(HL)  	;(PC) <- ((W)) début INDIRECTION
0026   4568 23                  INC     HL
0027   4569 56                  LD      D,(HL)
0028   456A EB                  EX      DE,HL
0029   456B E9                  JP      (HL)    	;Saut par INDIRECTION vers l'adresse de la sous-routine NOTE : (DE) = CF +1
0030   456C             
0031   456C             	;*********************************************************
0032   456C                                   		; Programme principal
0033   456C                                   		;Calcul de la fonction F(D) = (2*2*2(D+1)-1) * 2
0034   456C             double_fx:
0035   456C             
0036   456C 8F 45       	.DW cf_Code_8Dplus7
0037   456E AD 45        	.DW cf_deuxfois
0038   4570                                   		; END - Fin du programme principal Résultat dans le Top of Stack de la pile
0039   4570                     ;*********************************************************
0040   4570                                   ; MOTS DU VOCABULAIRE
0041   4570             c_docol:  
0042   4570 2A 55 45    	LD      HL,(RPP)	; Lecture du pointeur Pile Retour
0043   4573 2B                  DEC     HL		; Mise à jour du pointeur
0044   4574 70                  LD      (HL),B		; BC dans la pile retour
0045   4575 2B                  DEC     HL		; Mise à jour du pointeur
0046   4576 71                  LD      (HL),C		; BC dans la pile retour
0047   4577 22 55 45            LD      (RPP),HL	; Sauvegarde du pointeur
0048   457A 13                  INC     DE		; Ajustement de l'adresse
0049   457B 4B                  LD      C,E		; Transfert vers le pointeur d'adresse BC
0050   457C 42                  LD      B,D
0051   457D C3 61 45            JP      NEXT          	; BC pointant sur FDB cf_plusun de Code_8Dplus7           
0052   4580             
0053   4580             cf_semis:
0054   4580 82 45        	.DW    c_semis     	;(IP) <- (R1)	Code Field de semis
0055   4582             c_semis:      
0056   4582 2A 55 45    	LD      HL,(RPP)	; Lecture du pointeur Pile Retour
0057   4585 4E                  LD      C,(HL)  	;(BC) <- (R1)  Lecture du TOS de la Pile Retour
0058   4586 23                  INC     HL		; Mise à jour du pointeur
0059   4587 46          	LD      B,(HL)
0060   4588 23                  INC     HL		; Mise à jour du pointeur
0061   4589 22 55 45            LD      (RPP),HL        ;(RP) <- (RP)+2 Sauvegarde du pointeur
0062   458C C3 61 45            JP      NEXT            ; Retour vers l'interpréteur.
0063   458F             
0064   458F                                   		; Calcul de la fonction F(D) = 8*D+1 = 2*2*2(D+1)-1
0065   458F             cf_Code_8Dplus7:
0066   458F 70 45       	.DW c_docol
0067   4591 9D 45       	.DW cf_plusun
0068   4593 AD 45       	.DW cf_deuxfois
0069   4595 AD 45       	.DW cf_deuxfois
0070   4597 AD 45       	.DW cf_deuxfois
0071   4599 A5 45       	.DW cf_moinsun
0072   459B 80 45       	.DW cf_semis
0073   459D             
0074   459D             cf_plusun:
0075   459D 9F 45       	.DW Code_plusun
0076   459F             Code_plusun:
0077   459F E1          	POP	HL		; Lecture du TOS
0078   45A0 23          	INC	HL		; +1
0079   45A1 E5          	PUSH	HL		; Ecriture dans le TOS
0080   45A2 C3 61 45    	JP NEXT			; Retour interpréteur d'adresse
0081   45A5             
0082   45A5             cf_moinsun:
0083   45A5 A7 45       	.DW Code_moinsun
0084   45A7             Code_moinsun:
0085   45A7 E1          	POP	HL		; Lecture du TOS
0086   45A8 2B          	DEC	HL		; -1
0087   45A9 E5          	PUSH	HL		; Ecriture dans le TOS
0088   45AA C3 61 45    	JP NEXT			; Retour interpréteur d'adresse
0089   45AD             
0090   45AD             cf_deuxfois:
0091   45AD AF 45       	.DW Code_deuxfois
0092   45AF             Code_deuxfois:
0093   45AF E1          	POP	HL		; Lecture du TOS
0094   45B0 29          	ADD	HL,HL		; HL+HL
0095   45B1 E5          	PUSH	HL		; Ecriture dans le TOS
0096   45B2 C3 61 45    	JP NEXT			; Retour interpréteur d'adresse
0097   45B5             
0098   45B5             	;**********************
0099   45B5             	.END
J'ai testé le fichier ci dessous sur le DCVG5K de Daniel cette fois ci en lançant CALL &"4550" avec un point d’arrêt (Il semble qu'on ne puisse pas modifier le PC comme sur le DCMOTO :wink: )
machinevirtz80.zip
(261 octets) Téléchargé 194 fois
Avatar de l’utilisateur
Mokona
Messages : 1040
Inscription : 17 déc. 2016 22:01
Localisation : Nord Est des Yvelines
Contact :

Re: [FORTH] Le mécanisme Forth

Message par Mokona »

Merci pour la version Z80, c'est beaucoup plus clair pour moi qui ne maîtrise pas le 6809.
Avatar de l’utilisateur
Dominique
Messages : 828
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: [FORTH] Le mécanisme Forth

Message par Dominique »

Content de le savoir Mokona.

Pour cette raison je viens de rajouter la version Z80 de programme d'interprétation directe (PARTIE 1 de mes messages) et corrigé une coquille dans le listing du même programme version 6809
Ah, je ne l'ai pas vérifié (Z80) mais je pense qu'il est bon. Je termine ce que je faisais et je le corrige s'il y a lieu.
Dernière modification par Dominique le 16 oct. 2020 09:10, modifié 1 fois.
__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [FORTH] Le mécanisme Forth

Message par __sam__ »

On voit que l'utilisation d'une pile de retour soft (RPP est une variable en mémoire et pas un registre) ralenti pas mal les méthodes de type ":" qui sont les plus fréquentes car il faut 2 instructions sur 6809 et pas loin de 8 pour Z80 avant d'aller dans le "NEXT". Cependant comme le Z80 tourne à 4Mhz, peut-être qu'au final les méthodes "c_docol" sur Z80@4mhz et 6809@1mhz prennent sensiblement le même temps physique.
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] Le mécanisme Forth

Message par Dominique »

LE MÉCANISME FORTH PARTIE 4

Une des choses intéressantes au niveau du Forth est que grâce à l'interpréteur d'adresses nous avons la main sur l'adresse d'exécution - le fameux registre Y (BC du Z80)
Et cela ouvre des perspectives fascinantes:
Tout micro processeur, quel qu'il soit, possède aussi son pointeur d'adresses et en joue dans son immense panoplie d'instructions.
Par exemple on comprend intuitivement comment il opère avec les sauts relatifs, conditionnels ou pas.

Pour l'instruction BEQ nn (JRZ NN du Z80) par exemple on imagine qu'il teste son registre Flag - S'il est égal à zéro il avance son pointeur d'adresse, lit la valeur qui s'y trouve et la rajoute à son adresse pour se trouver où on lui avait demandé. S'il n'est pas égal à zéro il avance à nouveau son pointeur pour trouver la prochaine instruction
Ayant le moyen de tester le sommet de notre pile de données et ayant la main sur l'adresse, nous pouvons imiter l'instruction BEQ

Code : Tout sélectionner

; Supposons que Y était en $5004 et dans NEXT par LDX    ,Y++  il vient d'envoyer X à c_zerobran tout en pointant maintenant vers $5006

5000   FDB cf_XXXXXX
5002   FDB cf_XXXXXX
5004   FDB $4777	;cf_zerobran
5006   FDB $0004	; valeur du saut relatif
5008   FDB cf_XXXXXX

.....

                     cf_zerobran
 4777 4779                    FDB c_zerobran
                      c_zerobran
 4779 ECC1                    LDD    ,U++  	;Lecture du TOS en D et destruction du TOS             
 477B 2606                    BNE    zerobran1	; si non égal 0 avance son adresse de 2 pas (ignore le saut)
                      zerobran2              
 477D ECA4                    LDD    ,Y    	; Lecture de la valeur du saut relatif             
 477F 31AB                    LEAY   D,Y        ; Ecriture en Y de l'adresse + valeur du saut relatif       
 4781 0EB6                    JMP    NEXT
                      zerobran1               
 4783 3122                    LEAY   $02,Y  	; Ajoute deux pas à l'adresse pour se positionner après la valeur relative            
 4785 0EB6                    JMP    NEXT  	; retour à l'interpréteur

Version Z80 (Un petit peu plus confuse car ils reprennent en $4AE6 la définition d'un mot précédent

Code : Tout sélectionner

; Supposons que BC était en $5004 et par NEXT  il  vient d'envoyer HL à c_zerobran tout en pointant maintenant vers $5006
5000   .DW cf_XXXXXX
5002   .DW cf_XXXXXX
5004   .DW $4AFB	;cf_zerobran
5006   .DW $0004	; valeur du saut relatif
5008   .DW cf_XXXXXX


4AE6 60          BRAN1:  LD	H,B		;(HL) <- (IP) Ecriture de l'adresse en HL
4AE7 69          	LD	L,C
4AE8 5E          	LD	E,(HL)	;(DE) <- ((IP)) = BRANCH OFFSET
4AE9 23          	INC	HL
4AEA 56          	LD	D,(HL)		; Lecture de la valeur du saut relatif
4AEB 2B          	DEC	HL
4AEC 19          	ADD	HL,DE	 ;(HL) <- (HL) +((IP)) Calcul de la nouvelle adresse
4AED 4D          	LD	C,L		;(IP) <- (HL) Ecriture en BC
4AEE 44          	LD	B,H
4AEF 18 C0       	JR	NEXT	; Vers l'interpréteur
....

		cf_zerobran:
4AFB FD 4A       	.DW c_zerobran
		c_zerobran:
4AFD E1          	POP	HL	; Lit le TOS et le détruit
4AFE 7D          	LD	A,L
4AFF B4          	OR	H	; test si zero
4B00 28 E4       	JR	Z,BRAN1	;IF (S1)=0 THEN BRANCH
4B02 03          	INC	BC		;ELSE SKIP BRANCH OFFSET
4B03 03          	INC	BC
4B04 18 AB       	JR	NEXT	; Vers l'interpréteur
NOTA : je crois qu'en fait c'est l'inverse Ils imitent BNE - Non ? NON C'est bien BEQ : Comme en Forth on fait - IF <instruction exécutée si pile <>0 > endif - ça prête à confusion
Avatar de l’utilisateur
Dominique
Messages : 828
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: [FORTH] Le mécanisme Forth

Message par Dominique »

LE MÉCANISME FORTH PARTIE 5
*************FIN*******************

Ceci est la dernière partie de la présentation puisque l'idée n'était pas de faire un cours, mais d'expliquer la machine virtuelle.
On est très fier, en Forth, de montrer les constructions récursives. Généralement on montre les factorielles.
Comme je n'ai pas trop envie de mettre un algorithme de multiplication, on va utiliser l'addition pour calculer de manière récursive la somme des N premiers entiers naturels.

La formule va utiliser le test cf_zerobran que je viens de montrer. Vous l'avez certainement noté, le test détruit le sommet de la pile. Comme nous désirons le conserver, la solution est de le dupliquer avant le test pour qu'il se conserve.
Dup est l'un des premiers mots que l'on apprend en Forth et sa construction est enfantine

Version 6809

Code : Tout sélectionner

                     cf_dup
		                   FDB c_dup
                      c_dup
	                   	LDD    ,U  	; Ecriture du sommet de la pile de données dans D
				PSHU   B,A      ; Remet à nouveau D dans la pile de données        
	                  	JMP    NEXT
Version Z80

Code : Tout sélectionner

cf_dup:
		                   .DW c_dup
c_dup:
	                   	POP HL  	; Retire le sommet de la pile de données dans HL
				PUSH HL   	; Remet HL dans la pile de données        
				PUSH HL   	; Remet HL une seconde fois dans la pile de données					                  	
				JP NEXT
Le mot + qui fait la somme de deux valeurs dans la pile de données est encore plus simple.

Version 6809

Code : Tout sélectionner

                     cf_plus
	                    	FDB c_plus
                     c_plus
	                    	PULU   A,B       ; Retire D du sommet de la pile        
				ADDD   ,U 	 ; Somme D avec le sommet de la pile (2° élément)
			      	STD    ,U        ; Remplace le sommet par la somme       
				JMP    NEXT
Version Z80

Code : Tout sélectionner

cf_plus:
	                    	.DW c_plus
c_plus:
				POP DE  	; Retire le sommet de la pile de données dans DE
				POP HL  	; Retire le sommet de la pile de données dans HL
				ADD HL,DE	; Somme dans HL
				PUSH HL		; Remet HL dans le sommet de la pile de données
				JP NEXT

Voici donc, d'abord en 6809 le programme somme_recurse qui calcule de façon récursive la somme des N entiers naturels (N est adresse $4569)

Code : Tout sélectionner

                              ORG $4550
                              SETDP $45
                       ; DEBUT
 
 4550 7E4565                  JMP Entree_Forth
                      debut_programme_recurse
 4553 4574                    FDB cf_somme_recurse
 
                      ;*****************************************
                      ; MACHINE VIRTUELLE FORTH
                      ;*****************************************
 
                      NEXT
 4555 AEA1                    LDX    ,Y++             ; Ecriture de l'adresse dans X et avancement du pointeur vers l'adresse suivante                 
 4557 6E94                    JMP    [,X]             ; Saut par INDIRECTION vers l'adresse de la sous-routine
 
                      c_docol
                                                      
 4559 3420                    PSHS   Y                ; Y dans la pile retour               
 455B 3102                    LEAY   $02,X            ; Load Y effective Address (X)+2 ; c_docol étant au début de Code_8Dplus7 il faut bien le passer             
 455D 0E55                    JMP    NEXT             ; Y pointant sur FDB cf_plusun de Code_8Dplus7 on peut interpréter l'adresse.
                       
 
                      cf_semis
 455F 4561                    FDB c_semis             ; Code Field de semis
                      c_semis
 4561 3520                    PULS   Y                ; Mise à jour du pointeur d'adresse Y
 4563 0E55                    JMP    NEXT             ; Retour vers l'interpréteur.
 
                      ;*****************************************
                      ; FIN DE LA MV FORTH
                      ;*****************************************
 
                      ; (COLD)
                      Entree_Forth
 4565 8645                    LDA    #$45
 4567 1F8B                    TFR    A,DP
 4569 CC0010                  LDD   #$0010                    ; Calcul de la somme pour D = $0010
 456C 3606                    PSHU   B,A                      ; Dans la pile U
 456E 108E4553                LDY    #debut_programme_recurse ; Ecriture adresse du début du programme dans le pointeur d'adresse Y
 4572 0E55                    JMP    NEXT 
 
 
                      ; Programme principal
                      ; Somme des entiers naturels
 
                      cf_somme_recurse
 4574 4559                    FDB c_docol		; c_docol à chaque passage mettra dans la pile Retour S l'adresse $4582 qui pointe sur le mot +
 4576 4590                    FDB cf_dup		; Le TOS de la pile de données est dupliqué pour conserver l'ancienne valeur avant de faire 1- à la nouvelle
 4578 45A8                    FDB cf_moinsun		; - 1 sur une des valeur - la pile U vaudra 10 puis 10 9 puis 10 9 8 puis etc...
 457A 4590                    FDB cf_dup		; Dupliquée car cf_zerobran détruit le sommet
 457C 4598                    FDB cf_zerobran		; Tant que le sommet ne vaut pas zero zerobranche ne fait pas le saut $0004
 457E 0004                    FDB $0004			; Quant il le fera Y sera amené à $4582 pour faire le +
 4580 4574                    FDB cf_somme_recurse	; sinon Y retourne à $4574 où c_docol empilera son adresse $4582 dans S
 4582 4586                    FDB cf_plus		; Au premier passage le TOS vaut 0 il sera sommé à 1 puis la somme à 2 puis la somme à 3 et....
 4584 455F                    FDB cf_semis		; Retire de la pile S les valeurs laissés par Y ($4582) autant de fois que c_docol les a empilées.
 
                      ; *********FIN DU PROGRAMME - SOMME DANS LE TOS DE LA PILE**********
 
 
                      ; MOTS DU VOCABULAIRE
 
                      ;************************
                      ;* LE MOT +
                      ;************************
                      cf_plus
 4586 4588                    FDB c_plus
                      c_plus
 4588 3706                    PULU   A,B       ; Retire D du sommet de la pile      
 458A E3C4                    ADDD   ,U        ; Somme D avec le sommet de la pile (2° élément)
 458C EDC4                    STD    ,U        ; Remplace le sommet par la somme       
 458E 0E55                    JMP    NEXT
 
                      ;************************
                      ;* LE MOT DUP
                      ;************************
 
                      cf_dup
 4590 4592                    FDB c_dup
                      c_dup
 4592 ECC4                    LDD    ,U       ; Ecriture du sommet de la pile de données dans D
 4594 3606                    PSHU   B,A      ; Remet à nouveau D dans la pile de données        
 4596 0E55                    JMP    NEXT
 
                      ;************************
                      ;* LE MOT 0BRANCH
                      ;************************
                      cf_zerobran
 4598 459A                    FDB c_zerobran
                      c_zerobran
 459A ECC1                    LDD    ,U++     ;Lecture du TOS en D et destruction du TOS             
 459C 2606                    BNE    zerobran1        ; si non égal 0 avance son adresse de 2 pas (ignore le saut)
                      zerobran2              
 459E ECA4                    LDD    ,Y       ; Lecture de la valeur du saut relatif             
 45A0 31AB                    LEAY   D,Y        ; Ecriture en Y de l'adresse + valeur du saut relatif       
 45A2 0E55                    JMP    NEXT
                      zerobran1               
 45A4 3122                    LEAY   $02,Y    ; Ajoute deux pas à l'adresse pour se positionner après la valeur relative            
 45A6 0E55                    JMP    NEXT     ; retour à l'interpréteur
 
                      ;************************
                      ;* LE MOT 1-
                      ;************************
                       
                      cf_moinsun
 45A8 45AA                    FDB Code_moinsun
                      Code_moinsun
 45AA ECC4                    LDD    ,U  
 45AC 830001                  SUBD   #$0001
 45AF EDC4                    STD    ,U
 45B1 0E55                    JMP     NEXT
Fichier BIN pour le tester sur DCMOTO
recurse6809.zip
(259 octets) Téléchargé 187 fois
La version Z80 vient ensuite

Voici la version Z80 même si je ne l'ai pas testée jusqu'au bout
RECURSEZ80.zip
(279 octets) Téléchargé 191 fois

Code : Tout sélectionner

0001   0000              ;tasm -80 machinevirtz80.asm –g3
0002   0000             
0003   4550                    .ORG $4550
0004   4550              ; DEBUT
0005   4550 C3 81 45     				JP Entree_Forth
0006   4553             debut_programme_recurse:    
0007   4553 8E 45       				.DW cf_somme_recurse		; Début du programme 
0008   4555             RPP:
0009   4555 BE 7F       	.DW $7FBE		; Definition de l'adresse de la Pile Retour
0010   4557             
0011   4557             			;*****************************************
0012   4557                                   	; MACHINE VIRTUELLE FORTH
0013   4557                                   	;*****************************************
0014   4557             
0015   4557             NEXT:   
0016   4557 0A          	LD      A,(BC)  	;(W) <- ((IP))
0017   4558 03                  INC     BC      	;avancement du pointeur vers l'adresse suivante (IP) <- (IP)+2
0018   4559 6F                  LD      L,A
0019   455A 0A          NEXT3:  LD      A,(BC)  	;LABEL ADDED BY DLW
0020   455B 03                  INC     BC		;avancement du pointeur vers l'adresse suivante
0021   455C 67                  LD      H,A     	;(HL) <- CF
0022   455D 5E          NEXT1:  LD      E,(HL)  	;(PC) <- ((W)) début INDIRECTION
0023   455E 23                  INC     HL
0024   455F 56                  LD      D,(HL)
0025   4560 EB                  EX      DE,HL
0026   4561 E9                  JP      (HL)    	;Saut par INDIRECTION vers l'adresse de la sous-routine NOTE : (DE) = CF +1
0027   4562             
0028   4562             c_docol:  
0029   4562 2A 55 45    	LD      HL,(RPP)	; Lecture du pointeur Pile Retour
0030   4565 2B                  DEC     HL		; Mise à jour du pointeur
0031   4566 70                  LD      (HL),B		; BC dans la pile retour
0032   4567 2B                  DEC     HL		; Mise à jour du pointeur
0033   4568 71                  LD      (HL),C		; BC dans la pile retour
0034   4569 22 55 45            LD      (RPP),HL	; Sauvegarde du pointeur
0035   456C 13                  INC     DE		; Ajustement de l'adresse
0036   456D 4B                  LD      C,E		; Transfert vers le pointeur d'adresse BC
0037   456E 42                  LD      B,D
0038   456F C3 57 45            JP      NEXT          	; BC pointant sur FDB 
0039   4572             
0040   4572             cf_semis:
0041   4572 74 45        	.DW    c_semis     	;(IP) <- (R1)	Code Field de semis
0042   4574             c_semis:      
0043   4574 2A 55 45    	LD      HL,(RPP)	; Lecture du pointeur Pile Retour
0044   4577 4E                  LD      C,(HL)  	;(BC) <- (R1)  Lecture du TOS de la Pile Retour
0045   4578 23                  INC     HL		; Mise à jour du pointeur
0046   4579 46          	LD      B,(HL)
0047   457A 23                  INC     HL		; Mise à jour du pointeur
0048   457B 22 55 45            LD      (RPP),HL        ;(RP) <- (RP)+2 Sauvegarde du pointeur
0049   457E C3 57 45            JP      NEXT            ; Retour vers l'interpréteur.
0050   4581             
0051   4581             ;*****************************************
0052   4581             ; FIN DE LA MV FORTH
0053   4581             ;*****************************************
0054   4581             
0055   4581             ; (COLD)
0056   4581             Entree_Forth:
0057   4581 31 1E 7F    	LD SP,$7F1E		; Definition TOS de la pile de données
0058   4584 21 10 00    	LD HL,$0010		; Variable de la fonction à $10
0059   4587 E5          	PUSH HL			; Dans le TOS de la pile de données
0060   4588 01 53 45    	LD BC,debut_programme_recurse		
0061   458B C3 57 45      	JP    NEXT
0062   458E             
0063   458E             ; Programme principal
0064   458E             ; Somme des entiers naturels
0065   458E             
0066   458E             cf_somme_recurse:
0067   458E 62 45       	.DW c_docol
0068   4590 A9 45       	.DW cf_dup
0069   4592 C9 45       	.DW cf_moinsun
0070   4594 A9 45       	.DW cf_dup
0071   4596 B1 45       	.DW cf_zerobran
0072   4598 04 00       	.DW $0004
0073   459A 8E 45       	.DW cf_somme_recurse
0074   459C A0 45       	.DW cf_plus
0075   459E 72 45       	.DW cf_semis
0076   45A0             
0077   45A0             ; *********FIN DU PROGRAMME - SOMME DANS LE TOS DE LA PILE**********
0078   45A0             
0079   45A0             
0080   45A0             ; MOTS DU VOCABULAIRE
0081   45A0             
0082   45A0             ;************************
0083   45A0             ;* LE MOT +
0084   45A0             ;************************
0085   45A0             cf_plus:
0086   45A0 A2 45       	                    	.DW c_plus
0087   45A2             c_plus:
0088   45A2 D1          				POP DE  	; Retire le sommet de la pile de données dans DE
0089   45A3 E1          				POP HL  	; Retire le sommet de la pile de données dans HL
0090   45A4 19          				ADD HL,DE	; Somme dans HL
0091   45A5 E5          				PUSH HL		; Remet HL dans le sommet de la pile de données
0092   45A6 C3 57 45    				JP NEXT
0093   45A9             ;************************
0094   45A9             ;* LE MOT DUP
0095   45A9             ;************************
0096   45A9             
0097   45A9             cf_dup:
0098   45A9 AB 45       		                   .DW c_dup
0099   45AB             c_dup:
0100   45AB E1          	                   	POP HL  	; Retire le sommet de la pile de données dans HL
0101   45AC E5          				PUSH HL   	; Remet HL dans la pile de données        
0102   45AD E5          				PUSH HL   	; Remet HL une seconde fois dans la pile de données					                  	
0103   45AE C3 57 45    				JP NEXT
0104   45B1             ;************************
0105   45B1             ;* LE MOT 0BRANCH
0106   45B1             ;************************
0107   45B1             
0108   45B1             cf_zerobran:
0109   45B1 B3 45       			.DW c_zerobran
0110   45B3             c_zerobran:
0111   45B3 E1          			POP HL	; Lit le TOS et le détruit
0112   45B4 7D          			LD A,L
0113   45B5 B4          			OR H	; test si zero
0114   45B6 28 05       			JR Z,BRAN1	;IF (S1)=0 THEN BRANCH
0115   45B8 03          			INC BC		;ELSE SKIP BRANCH OFFSET
0116   45B9 03          			INC BC
0117   45BA C3 57 45    			JP NEXT	; Vers l'interpréteur
0118   45BD 60          BRAN1:  		LD H,B		;(HL) <- (IP) Ecriture de l'adresse en HL
0119   45BE 69          			LD L,C
0120   45BF 5E          			LD E,(HL)	;(DE) <- ((IP)) = BRANCH OFFSET
0121   45C0 23          			INC HL
0122   45C1 56          			LD D,(HL)		; Lecture de la valeur du saut relatif
0123   45C2 2B          			DEC HL
0124   45C3 19          			ADD HL,DE	 ;(HL) <- (HL) +((IP)) Calcul de la nouvelle adresse
0125   45C4 4D          			LD C,L		;(IP) <- (HL) Ecriture en BC
0126   45C5 44          			LD B,H
0127   45C6 C3 57 45    			JP NEXT	; Vers l'interpréteur
0128   45C9             
0129   45C9             ;************************
0130   45C9             ;* LE MOT 1-
0131   45C9             ;************************
0132   45C9             
0133   45C9             
0134   45C9             cf_moinsun:
0135   45C9 CB 45       			.DW Code_moinsun
0136   45CB             Code_moinsun:
0137   45CB E1          			POP HL		; Lecture du TOS
0138   45CC 2B          			DEC HL		; -1
0139   45CD E5          			PUSH HL		; Ecriture dans le TOS
0140   45CE C3 57 45    			JP NEXT			; Retour interpréteur d'adresse
0141   45D1             
0142   45D1             	.ENDtasm: Number of errors = 0
Avatar de l’utilisateur
jice
Messages : 213
Inscription : 21 avr. 2014 15:08
Localisation : Madrid

Re: [FORTH] Le mécanisme Forth

Message par jice »

merci Dominique, très intéressant de voir comment fonctionne le Forth, et de réviser un peu d'ASM 6809 aussi :)
MO5 - MO5 Platini - TO7 - TO7/70 - TO8 - TO9+
Répondre