Derniers sujets
Qui est en ligne ?
Il y a en tout 1 utilisateur en ligne :: 0 Enregistré, 0 Invisible et 1 Invité Aucun
Le record du nombre d'utilisateurs en ligne est de 29 le Mer 25 Fév 2015 - 14:01
Connexion
Statistiques
Nous avons 243 membres enregistrésL'utilisateur enregistré le plus récent est paul225l
Nos membres ont posté un total de 8922 messages dans 811 sujets
basic & lib ASM___[RESOLU]
5 participants
Forum Oric :: Forums :: Forum Public :: Assembleur
Page 1 sur 1
basic & lib ASM___[RESOLU]
Petit question afin de me confirmer une hypothèse...
j'ai développé un petit driver pour une interface pour l'oric. Il y a 14 fonctions en tout écrites en asm. Cela compile (ça veut pas dire que ça marche, hein )
par example j'implante cette lib en $8000
Si je souhaite appeller ces fonctions depuis le basic, cela peut seulement se faire au travers d'un CALL #, non?
Et du coup la première sera facilement appelable et pour les autres faudra que je fasse une extraction de l'adresse car les longueurs de chacune des fonctions n'est pas constante.
j'ai bon?!
j'ai développé un petit driver pour une interface pour l'oric. Il y a 14 fonctions en tout écrites en asm. Cela compile (ça veut pas dire que ça marche, hein )
par example j'implante cette lib en $8000
Si je souhaite appeller ces fonctions depuis le basic, cela peut seulement se faire au travers d'un CALL #
Et du coup la première sera facilement appelable et pour les autres faudra que je fasse une extraction de l'adresse car les longueurs de chacune des fonctions n'est pas constante.
j'ai bon?!
Dernière édition par ]0[v] le Jeu 5 Sep 2019 - 10:24, édité 1 fois
]0[v]- Messages : 60
Date d'inscription : 25/07/2019
Re: basic & lib ASM___[RESOLU]
Tu peux les appeler avec un CALL #xxxx oui.
Après il y a plusieurs façon de faire pour les autres.
Le plus simple est de mettre l'adresse des différentes fonctions dans une table au début en #8000. De cette façon, l'adresse de la 1ère fonction est en #8000, l'adresse de la seconde en #8002, etc.
Tu peux simplifier l'appel en modififant la table pour mettre un JMP devant chaque adresse de fonction:
Une autre solution est de modifier le vecteur de la fonction &() ou USR() du BASIC pour la faire pointer faire une petite routine qui va récupérer la valeur qui sera fournie à la fonction.
Pour uiliser &(), il faut mettre l'adresse de la fonction en $02FC.
Pour récupérer la valeur passée en paramètre, il faut faire JSR $D922, ensuite on dans dans le registre A le poids fort de la valeur et dans Y le poids faible.
Il suffit alors de se servir de la valeur de Y comme index dans la table des adresses des fonctions.
Mettre l'adresse de entry en $02FC.
(On peut aussi utiliser la pile et un RTS à la place du JMP.)
Il y a d'autres solutions possibles avec la commande "!" ou pour passer des paramètres.
Après il y a plusieurs façon de faire pour les autres.
Le plus simple est de mettre l'adresse des différentes fonctions dans une table au début en #8000. De cette façon, l'adresse de la 1ère fonction est en #8000, l'adresse de la seconde en #8002, etc.
- Code:
adresse_fonction1
adresse_fonction2
...
Tu peux simplifier l'appel en modififant la table pour mettre un JMP devant chaque adresse de fonction:
- Code:
JMP fonction1
JMP fonction2
...
Une autre solution est de modifier le vecteur de la fonction &() ou USR() du BASIC pour la faire pointer faire une petite routine qui va récupérer la valeur qui sera fournie à la fonction.
Pour uiliser &(), il faut mettre l'adresse de la fonction en $02FC.
Pour récupérer la valeur passée en paramètre, il faut faire JSR $D922, ensuite on dans dans le registre A le poids fort de la valeur et dans Y le poids faible.
Il suffit alors de se servir de la valeur de Y comme index dans la table des adresses des fonctions.
- Code:
enrty:
jsr $d922 ; Conversion Flotttant -> entier
tya ; Poids faible de la valeur
asl ; Multiplie par 2
tax ; Index dans la table
lda table,x
sta saut+1 ; saut+11 -> octet xx du jmp plus bas
inx
lda table,x
sta saut+2 ; saut+2 -> octet yy du jmp
saut:
jmp xxyy
table:
.word fonction0 ; &(0)
.word fonction1 ; &(1)
Mettre l'adresse de entry en $02FC.
(On peut aussi utiliser la pile et un RTS à la place du JMP.)
Il y a d'autres solutions possibles avec la commande "!" ou pour passer des paramètres.
assinie- Messages : 271
Date d'inscription : 09/02/2014
Re: basic & lib ASM___[RESOLU]
merci @assinie, pour cette réponse rapide et très développée
L'idée des CALL est d'accéder rapidement aux diverses fonctions, comme c'est fait par le linker en C au final
Ensuite je souhaite utiliser le basic au minimun, c'est malheureusement le language choisit pour cette machine... toutes n'ont pas eut la chance d'être des jupiter ace ou Hector
Merci quand même d'avoir détaillé le fonctionnement
Oui après il y a la solution de faire une table ce qui apporte l'énorme avantage de savoir exactement qu'elle adresse appeler pour chaque fonctions au détriments d'une petite perte de temps, mais c'est très pratique aussi, dans mon cas je sais pas à tester en tout cas!
Si tu passes l'addresse via la pile ensuite tu recomposes l'adresse pour l'utiliser avec un JSR donc on gagne taille de code mais on perd en temps de d'execution, non? Et cela revient au même que d'utiliser un CALL, non?
L'idée des CALL est d'accéder rapidement aux diverses fonctions, comme c'est fait par le linker en C au final
Ensuite je souhaite utiliser le basic au minimun, c'est malheureusement le language choisit pour cette machine... toutes n'ont pas eut la chance d'être des jupiter ace ou Hector
Merci quand même d'avoir détaillé le fonctionnement
Oui après il y a la solution de faire une table ce qui apporte l'énorme avantage de savoir exactement qu'elle adresse appeler pour chaque fonctions au détriments d'une petite perte de temps, mais c'est très pratique aussi, dans mon cas je sais pas à tester en tout cas!
Si tu passes l'addresse via la pile ensuite tu recomposes l'adresse pour l'utiliser avec un JSR donc on gagne taille de code mais on perd en temps de d'execution, non? Et cela revient au même que d'utiliser un CALL, non?
]0[v]- Messages : 60
Date d'inscription : 25/07/2019
Re: basic & lib ASM___[RESOLU]
Le coup de la pile et du RTS permet d'avoir un code plus compact pour la routine d'appel et évite de modifier dynamiquement le porgramme comme c'est fait dans les exemples que j'ai donnés (le JMP est modifié à la volée).
Le principe est le suivant, on empile l'adresse de la routine -1, ensuite le RTS utilise cette adresse comme adresse de retour.
Le RTS ajoute 1 à l'adresse empilée par un JSR d'où le -1 dans la table:
D'un point de vue temps d'exécution, le RTS prend 6 cycles et un JMP n'en prend que 3, mais c'est en partie compensé par le PHA qui prend 3 cycles contre 4 pour un STA.
On peut encore gagner en taille et en vitesse, en utilsant 2 tables au lien d'une. La première contient les poids faibles des adersses et la seconde les poids forts, comme ça on évite la multiplication par 2 de l'index, le INX et on peut avoir deux fois plus de fonctions (de 0 à 255 contre 0 à 127 avec une seule table).
Le code complet du post précédent devient:
et la version avec un RTS
En fonction de l'assembleur utilisé, l'écriture des tables peut être simplifié.
La version sans le RTS utilise 21 cycles, celle avec le RTS utilise 20 cycles (hors JSR $D922).
La taiile totale de la version sans le RTS est de 18, celle de la version avec le RTS n'est que de 12 octets (hors tables).
Globalement tu gagnes donc 1 cycle et 6 octets, les gains par rapport à la version du post précédent sont encore plus importants.
Le principe est le suivant, on empile l'adresse de la routine -1, ensuite le RTS utilise cette adresse comme adresse de retour.
Le RTS ajoute 1 à l'adresse empilée par un JSR d'où le -1 dans la table:
- Code:
lda table,x
pha ; empile le poids fort
inx
lda table,x
pha ; empile le poids faible
rts ; <=> JMP
table:
.byte (fonction0 -1) >>8, (fonction0 -1) & $FF : ATTENTION: poids fort en premier (contrairement à la norme pour le 6502)
.byte (fonction1 -1) >>8, (fonction1 -1) & $FF
D'un point de vue temps d'exécution, le RTS prend 6 cycles et un JMP n'en prend que 3, mais c'est en partie compensé par le PHA qui prend 3 cycles contre 4 pour un STA.
On peut encore gagner en taille et en vitesse, en utilsant 2 tables au lien d'une. La première contient les poids faibles des adersses et la seconde les poids forts, comme ça on évite la multiplication par 2 de l'index, le INX et on peut avoir deux fois plus de fonctions (de 0 à 255 contre 0 à 127 avec une seule table).
Le code complet du post précédent devient:
- Code:
enrty:
jsr $d922 ; Conversion Flotttant -> entier
lda table_l,y
sta saut+1 ; saut+11 -> octet xx du jmp plus bas
lda table_h,y
sta saut+2 ; saut+2 -> octet yy du jmp
saut:
jmp xxyy
table_l:
.byte fonction0 & $ff ; &(0)
.byte fonction1 & $ff ; &(1)
table_h:
.byte fonction0 >> 8 ; &(0)
.byte fonction1 >> 8 ; &(1)
et la version avec un RTS
- Code:
enrty:
jsr $d922 ; Conversion Flotttant -> entier
lda table_h,y ; Empile le poids fort
pha
lda table_l,y ; Empile le poids faible
pha
saut:
rts
table_l:
.byte fonction0 & $ff ; &(0)
.byte fonction1 & $ff ; &(1)
table_h:
.byte fonction0 >> 8 ; &(0)
.byte fonction1 >> 8 ; &(1)
En fonction de l'assembleur utilisé, l'écriture des tables peut être simplifié.
La version sans le RTS utilise 21 cycles, celle avec le RTS utilise 20 cycles (hors JSR $D922).
La taiile totale de la version sans le RTS est de 18, celle de la version avec le RTS n'est que de 12 octets (hors tables).
Globalement tu gagnes donc 1 cycle et 6 octets, les gains par rapport à la version du post précédent sont encore plus importants.
assinie- Messages : 271
Date d'inscription : 09/02/2014
Re: basic & lib ASM___[RESOLU]
- Code:
table_l:
.byte fonction0 & $ff ; &(0)
.byte fonction1 & $ff ; &(1)
table_h:
.byte fonction0 >> 8 ; &(0)
.byte fonction1 >> 8 ; &(1)
Dbug- Messages : 248
Date d'inscription : 06/01/2013
Re: basic & lib ASM___[RESOLU]
Merci @assinie, j'avais vu ça dans une demo présente dans le sdk 4KKong (premiere version de Mario, me semble-t-il )
C'est plus élégant que ma méthode des CALL pour lequel je dois fournir l'adresse d'implantation de la fonction. Là il suffit de connaître l'index de la fonction dans la table! Jusque là ça me dérangeais pas trop car j'avais fait un petit script bash qui automatisait le build et qui me récupérait les addresses pour chacune des fonctions depuis le fichier "map" et modifier le fichier ASM pour implanter la table des JMP, ça fait le job mais ça reste moins propre que la solution que tu as exposé
Le coup des doubles tables me paraît parfait, de plus 1 cycle & 6 octets sur ces vieilles machines c'est énorme comme gain!!!
Du coup j'adopte cette solution!!!
C'est plus élégant que ma méthode des CALL pour lequel je dois fournir l'adresse d'implantation de la fonction. Là il suffit de connaître l'index de la fonction dans la table! Jusque là ça me dérangeais pas trop car j'avais fait un petit script bash qui automatisait le build et qui me récupérait les addresses pour chacune des fonctions depuis le fichier "map" et modifier le fichier ASM pour implanter la table des JMP, ça fait le job mais ça reste moins propre que la solution que tu as exposé
Le coup des doubles tables me paraît parfait, de plus 1 cycle & 6 octets sur ces vieilles machines c'est énorme comme gain!!!
Du coup j'adopte cette solution!!!
]0[v]- Messages : 60
Date d'inscription : 25/07/2019
basic & lib ASM
@Dbug: cela fonctionne aussi en tout cas avec XA, et il y a surtout encore mieux en terme de lisibilité. J'ai vu ça dans un code je me souviens plus lequel par contre mais en gros il suffit de définir
finalement il n'y a que l'embarras du choix
- Code:
#define LO(x) <(x)
#define HI(x) <(x)
finalement il n'y a que l'embarras du choix
]0[v]- Messages : 60
Date d'inscription : 25/07/2019
Re: basic & lib ASM___[RESOLU]
Pour l'écriture des tables, c'est ce que je disais, en fonction de l'assembleur utilisé c'est plus ou moins lisible ou simple, on peut aussi avoir un script externe qui génère ces tables.
Je n'ai pas voulu donner une syntaxe spécifique mais plutôt simplement indiquer le principe.
Sinon, avec ca65 c'est encore plus simple avec les instructions .lobytes et .hibytes:
Je n'ai pas voulu donner une syntaxe spécifique mais plutôt simplement indiquer le principe.
Sinon, avec ca65 c'est encore plus simple avec les instructions .lobytes et .hibytes:
- Code:
table_l:
.lobytes fonction0, fonction1, fonction2
table_h:
.hibytes fonction0,fonction1, fonction2
assinie- Messages : 271
Date d'inscription : 09/02/2014
Re: basic & lib ASM___[RESOLU]
Hello,
Concernant ce qu'on appelle en fait le "RTS trick" pour l'implémentation de tables de saut, je m'étais intéressé au sujet il y a qq mois et j'avais trouvé un article très bien fait à ce sujet dans le Wiki consacré à la NES: NESdev wiki - RTS trick.
[EDIT: le site NESdev wiki était temporairement offline, mais est de nouveau accessible.]
Autre chose, j'avais noté à l'époque que cette astuce était en fait apparemment utilisée dans la ROM de l'Oric, car il y a des tables de saut prévues pour être utilisées avec un RTS (donc avec les adresses "moins un" des routines) pour toutes les commandes BASIC, les opérateurs et les fonctions arithmétiques: cf. le bouquin "L'Oric A Nu", pp. 68-71.
De mon côté, le sujet m'intéresse pour l'OSDK, j'avais commencé à creuser l'idée de faire une version des libs graphique et son qui puissent être compatibles Oric1/Atmos (actuellement les libs OSDK appelant la ROM fonctionnent uniquement sur Atmos) en utilisant des tables de saut qui pourraient être configurées au lancement du programme après détection de la machine, ou en utilisant les tables de saut déjà dans la ROM quand c'est possible.
Concernant ce qu'on appelle en fait le "RTS trick" pour l'implémentation de tables de saut, je m'étais intéressé au sujet il y a qq mois et j'avais trouvé un article très bien fait à ce sujet dans le Wiki consacré à la NES: NESdev wiki - RTS trick.
[EDIT: le site NESdev wiki était temporairement offline, mais est de nouveau accessible.]
Autre chose, j'avais noté à l'époque que cette astuce était en fait apparemment utilisée dans la ROM de l'Oric, car il y a des tables de saut prévues pour être utilisées avec un RTS (donc avec les adresses "moins un" des routines) pour toutes les commandes BASIC, les opérateurs et les fonctions arithmétiques: cf. le bouquin "L'Oric A Nu", pp. 68-71.
De mon côté, le sujet m'intéresse pour l'OSDK, j'avais commencé à creuser l'idée de faire une version des libs graphique et son qui puissent être compatibles Oric1/Atmos (actuellement les libs OSDK appelant la ROM fonctionnent uniquement sur Atmos) en utilisant des tables de saut qui pourraient être configurées au lancement du programme après détection de la machine, ou en utilisant les tables de saut déjà dans la ROM quand c'est possible.
Dernière édition par retroric le Jeu 5 Sep 2019 - 22:54, édité 2 fois
Re: basic & lib ASM___[RESOLU]
@assinie, ce n'est pas en $9D2C la conversion Float -> Int?
]0[v]- Messages : 60
Date d'inscription : 25/07/2019
Re: basic & lib ASM___[RESOLU]
Je pense ue tu veux dire $D92C
En fait, en $D922, la routine vérife que la valeur n'est pas négative avant de faire la conversion et renvoie une erreur "ILLEGAL QUANTITY ERROR" dans ce cas.
Si tu utilises $D2FC, cette verification n'est pas faite ce qui peux te poser problème ensuite, dans ce cas tu peux aussi directement aller en $DF8C et récupérer le poids faible en $D4.
Note: les adresses sont celles de la version 1.1 de la ROM (Atmos)
En fait, en $D922, la routine vérife que la valeur n'est pas négative avant de faire la conversion et renvoie une erreur "ILLEGAL QUANTITY ERROR" dans ce cas.
Si tu utilises $D2FC, cette verification n'est pas faite ce qui peux te poser problème ensuite, dans ce cas tu peux aussi directement aller en $DF8C et récupérer le poids faible en $D4.
Note: les adresses sont celles de la version 1.1 de la ROM (Atmos)
assinie- Messages : 271
Date d'inscription : 09/02/2014
Re: basic & lib ASM___[RESOLU]
Pour vraiment limiter les problèmes, il faudrait même ajouter un test au retour de $D922 pour vérifier que le programme ne demande pas à exécuter une fonction qui n'existe pas.
Pour ça, il faut vérifier que le registre A est bien nul et que Y contienne une valeur qui n'est pas supérieure ou égale au nombre de fonctions de ta librairie et renvoyer une erreur le cas échéant (un JMP $D336 affiche "ILLEGAL QUANTITY ERROR" par exemple)
Pour ça, il faut vérifier que le registre A est bien nul et que Y contienne une valeur qui n'est pas supérieure ou égale au nombre de fonctions de ta librairie et renvoyer une erreur le cas échéant (un JMP $D336 affiche "ILLEGAL QUANTITY ERROR" par exemple)
assinie- Messages : 271
Date d'inscription : 09/02/2014
Re: basic & lib ASM___[RESOLU]
@assinie: oui c'est bien de faire de la gestion d'erreur si ça ne me prend pas trop de place car mon driver fait déjà 920 octets. Bon là ça doit rajouter 5 ou 6 octets de plus...
Pour l'instant c'est pas ma priorité.
Et oui c'est bien de cette adresse là, $D922, dont je parlais
Pour l'instant c'est pas ma priorité.
Et oui c'est bien de cette adresse là, $D922, dont je parlais
]0[v]- Messages : 60
Date d'inscription : 25/07/2019
Re: basic & lib ASM___[RESOLU]
Bonjour à vous,
J'ai une question pratique concernant l'usage mix de ASM et BASIC:
Comment fait-on pour charger des routines assembleur ET un script basic qui exploite ces routines ?
avec OSDK, j'arrive à faire un TAP ou un DSK pour charger un prog mixant C et ASM, j'arrive aussi à faire un TAP ou un DSK pour charger un prog BASIC.
Mais je ne trouve pas de méthode pour faire un TAP qui contient des routines assembleur ET un script BASIC qui les appelle.
La seule technique que je vois, c'est en mettant le code machine des routines assembleur dans des DATA que je charge en début de script basic ..
Mais alors comment puis-je générer facilement ces DATA depuis le code ASM ?
Si vous avez des tuyaux là-dessus, ça m'intéresse bien ..
J'ai une question pratique concernant l'usage mix de ASM et BASIC:
Comment fait-on pour charger des routines assembleur ET un script basic qui exploite ces routines ?
avec OSDK, j'arrive à faire un TAP ou un DSK pour charger un prog mixant C et ASM, j'arrive aussi à faire un TAP ou un DSK pour charger un prog BASIC.
Mais je ne trouve pas de méthode pour faire un TAP qui contient des routines assembleur ET un script BASIC qui les appelle.
La seule technique que je vois, c'est en mettant le code machine des routines assembleur dans des DATA que je charge en début de script basic ..
Mais alors comment puis-je générer facilement ces DATA depuis le code ASM ?
Si vous avez des tuyaux là-dessus, ça m'intéresse bien ..
jbperin- Messages : 132
Date d'inscription : 05/11/2019
Localisation : Drôme
Re: basic & lib ASM___[RESOLU]
Ca ne marcherais pas bêtement en mettant tes routines assembleur dans un fichier binaire après le programme BASIC et avoir un CLOAD"" pour charger les données binaires quand le programme BASIC se lance?
Dbug- Messages : 248
Date d'inscription : 06/01/2013
Sujets similaires
» Calcul en langage machine [RESOLU]
» Euphoric et Windows 8 [Résolu]
» [résolu]Utilitaire Hex2Oric
» Branchement alimentation péritel [Résolu]
» Problème sur mix BASIC / ASM
» Euphoric et Windows 8 [Résolu]
» [résolu]Utilitaire Hex2Oric
» Branchement alimentation péritel [Résolu]
» Problème sur mix BASIC / ASM
Forum Oric :: Forums :: Forum Public :: Assembleur
Page 1 sur 1
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum
|
|
Dim 31 Mar 2024 - 14:35 par kenneth
» Bla Bla général du Jury
Jeu 21 Mar 2024 - 8:51 par Dom50
» carte mère Oric (re)tracée
Mar 5 Mar 2024 - 18:54 par kenneth
» Meurtre à Grande Vitesse
Dim 25 Fév 2024 - 5:09 par Iurius
» ORIC-1 sur LE BON COIN
Ven 23 Fév 2024 - 23:01 par Mcar
» ORIC ATMOS sur LE BON COIN
Dim 4 Fév 2024 - 12:06 par kiwilevrai
» Problème d'affichage des couleurs avec un Oric Atmos
Sam 27 Jan 2024 - 1:26 par pierbail
» Bienvenue dans le Forum des Oriciens
Mar 9 Jan 2024 - 12:33 par Dom50
» Rencontre avec Laurant Weill, co-fondateur de Loriciel, et mon garçon de 12 ans
Ven 29 Déc 2023 - 14:13 par Arcade-des-Monts
» Bonnes fêtes
Mar 26 Déc 2023 - 10:21 par Dom50
» Murders in Venice / Meutres à Venise
Sam 18 Nov 2023 - 22:44 par retroric
» Un clavier PS/2 pour tester un ORIC
Dim 27 Aoû 2023 - 9:49 par Voyageur
» Disquette 3" Sedoric
Mar 1 Aoû 2023 - 14:22 par AtomeX
» faire un 6502 avec des phototransistor
Dim 16 Juil 2023 - 17:26 par Voyageur
» Oricutron linux et DSK
Jeu 29 Juin 2023 - 18:34 par Voyageur