forum

Navigation du forum
Vous devez vous identifier pour créer des messages et des sujets.

Débuter de 0 en programmation par l'assembleur pour Z80

Bonjour,

Je n'ai aucun notion de programmation (même pas en basic) et je me décide à débuter en assembleur.
Je sais que c'est un langage moins accessible que le Basic, et qu'il est plus facile de passer du Basic à l'assembleur que de démarrer de rien mais... c'est mon choix ^^

J'aime l'idée de "langage machine" et de toute façon. c'est un défi personnel et un passe-temps donc...

Les sites que l'on m'a conseillé sont ASMtrad (https://sites.google.com/site/asmtradcpc/ ) et QUASAR (http://quasar.cpcscene.net/doku.php?id=sommaire)

J'ai aussi trouvé Dr Watson AMSTRAD, autoformation à l'assembleur (https://cpcrulez.fr/codingBOOK_watson_intro.htm) que je n'ai pas encore commencé à lire.

Je suis bloqué sur ASMtrad au 1.5 : Affichage de Sprite. Impossible de sortir quelque chose (pour cela que je lance ce sujet car l'approche pour un total débutant est surement différente.

Je me demande si le défi que je me suis donné n'est pas trop ardu, j'en suis autour de 10h à cette étape sans avancer d'un iota. C'est pas mal frustrant...

Dr. Watson est-elle une bonne source ? Avez-vous des conseils à donner ?

Merci 🙂

Est-ce que je peux poser mes questions niaiseuses ici ??
Je sature d'ASMtrad et de son affichage de sprite qui me saoule à un point... J'ai passé les 10h sur ce problème.

Alors ce soir je fais Quazar "Initiation au Z80".
Dès le premier programme d'illustration j'ai quelques questions... Il faut dire que les comparatifs avec le BASIC sont surement très éclairant pour ceux qui connaissent ce langage mais comme je ne le connais pas plus (^_^)

Voici le texte, avec le code que j'ai annoté avec ce que j'ai compris, mes remarques et mes questions.

Les boucles

Commençons donc par les boucles. On utilise l'instruction JP (JumP) pour faire un saut dans un programme. Je m'explique : si, par exemple, on veut qu'un programme recommence au début quand son exécution est terminée, on place l'instruction JP DEBUT en fin de programme ; DEBUT étant un label placé au début du prog' dans notre exemple (DEBUT ayant été pris au harsard).

Mais j'y pense, on ne vous a pas parlé des labels ! Bon, je vais vous expliquer. Un label est un mot (ou une lettre) quelconque qui est placé en face d'une commande donnée, il sert à ne pas avoir à préciser l'adresse mémoire où se trouve l'instruction, mais seulement préciser le nom donné au label concerné. Pour mieux vous illustrer cela, vous n'avez qu'à regarder le programme ci-dessous :

       ORG &5000;Le code sera stocké à partir de cette adresse dans la RAM
       LD HL,TEXTE;on charge le label dans HL
BOUCLE LD A,(HL);On charge l'adresse contenu dans HL dans A (donc le label?
;Pourquoi le l'adresse et pas la valeur ?!
CP 0;On compare A avec 0 (donc on compare 'DB "Bonjour !",0' avec 0 ?) RET Z; Si on A-0=0, retour au BASIC CALL &BB5A; ??? Pourquoi on est pas retourné au BASIC au premier passage
;car pourtant il y a de base le 0 après Bonjour !? INC HL;??? JP BOUCLE ; TEXTE DB "Bonjour !",0

En observant le programme, vous avez pu voir l'instruction RET Z (eh oui !). Vous devez connaître RET mais pas Z (qu'est-ce qu'il va encore nous sortir !?). Ce fameux Z signifie “si le flag Z est positionné tu fais l'instruction”. Le flag Z est modifié par certaines commandes dont CP (qui signifie “ComPare” au registre A), ce qui veut dire en simplifiant (dans notre prog') : ComPare A à 0, si A=0 alors RETourne au BASIC, sinon continue.

Nous aborderons plus en détail la question des flags dans la section suivante.

Les data

Il me reste donc à vous parler des data. C'est le même principe qu'en BASIC, on réserve une zone mémoire pour y stocker des données, sauf que DATA est remplacé par DB7) (ou DW8) pour les tableaux d'adresses) et que la commande READ du BASIC est remplacée par des LDLD HL,TEXTE fait pointer HL sur les données (ici le texte), on lit celles-ci grâce à LD A,(HL) et on incrémente le pointeur (ici INC HL) pour pointer sur la donnée suivante. Vous pouvez déduire que le texte doit être terminé par un 0 et que ce programme correspond au PRINT du BASIC (zai failli oublier de le dire !).

Merci de votre patience, si vous me répondez vous mettez le doigt dans l'engrenage, je ne vous lâcherai pas et vous allez le regretter irez au paradis.

(erreur)

Hello,
Il n'y a pas de questions niaiseuses, et commencer directement en assembleur, rend les choses plus difficiles à expliquer mais on peut t'aider si tu poses des questions précisent.
Pour les livres sur l'assembleur comme "Dr. Watson" ou  "Langage machine sur l'Amstrad",  ou tous les livres disponibles sur ce site: "https://amstrad.eu/genre/z80-coding/". Tous te seront utiles mais demandent un minimum de connaissance.

De plus, je ne connais pas ton niveau d'expérience. Connais tu les instructions suivantes ?
- VARIABLES
- REGISTRES
- LABELS 
Ces 3 instructions sont un minimum à connaitre dans un programme en assembleur et il y en a beaucoup d'autres.

Dis moi en plus sur tes connaissances afin de savoir par quoi commencer ?

Les registres ce sont des endroits pour stocker des adresses ou des nombre et y faire des choses (genre A est l'accumulateur 8 bits). Il y a des registres 16 bits aussi comme BC HL DE qui peuvent contenir jusque &FFFF contre &FF (255) pour un registre 8 bits.

Les labels ce sont des mots choisi comme on veut et mis en début de ligne qui permettront de faire une boucle en démarrant par là.

Les variables c'est ce qu'on met dans les registres ??

Merci pour ta réponse, je n'en connais pas beaucoup plus.

Salut !

Courageux de te lancer dans l'inconnu sur l'assembleur ;P

       ORG &5000;Le code sera stocké à partir de cette adresse dans la RAM
       LD HL,TEXTE;on charge le label dans HL

En fait le label est juste pour indiquer au compilateur l'adresse où est stocké le texte en mémoire, HL contiendra cette adresse

BOUCLE LD A,(HL);On charge l'adresse contenu dans HL dans A (donc le label?
;Pourquoi le l'adresse et pas la valeur ?!

En fait tu charges dans l'accumulateur le contenu de la case mémoire pointée par HL (valeur 8 bits) parce qu'il y a les parenthèses. Sans les parenthèses, ça serait juste la valeur du registe (une adresse mémoire) ce qui ne serait pas possible puisque HL est 16 bits et A 8 bits

       CP 0;On compare A avec 0 (donc on compare 'DB "Bonjour !",0' avec 0 ?)

Non A contient (au premier passage) la valeur de la première lettre du texte en mémoire (le premier octet), pas la totalité. En fait, il faut savoir comment DB fonctionne : cela annonce une plage de données codées sur un octet (Byte). Or ici on trouve une chaîne, donc cela place en mémoire le code ASCII de chaque caractère à la suite, et ajoute un 0 à la fin (la virgule sépare les données)
       RET Z; Si on A-0=0, retour au BASIC
       CALL &BB5A; ??? Pourquoi on est pas retourné au BASIC au premier passage

RET Z passe à l'instruction suivante sans rien faire si le résultat de l'opération précédente est NZ

;car pourtant il y a de base le 0 après Bonjour !?

Le test n'est effectué que sur une valeur à la fois, donc oui une fois que le programme aura balayé B o n j o u r ' ' et '!' il verra le 0 et le RET Z sera exécuté

       INC HL;???

on incrémente le registre HL de 1 en 1, pour pointer sur l'adresse correspondant à la lettre suivante et balayer l'ensemble de la chaîne
       JP BOUCLE
;
TEXTE  DB "Bonjour !",0

 

pour les cours d'ASMtrad, tu as les vidéos sur la chaîne d'Amstariga qui a suivi les cours en partant de zéro (série des Chiant pour Chiant), ça pourrait servir d'illustration avec les passages où il a du mal !

 

La "case mémoire" c'est quoi ? J'ai du mal avec ce passage "En fait tu charges dans l'accumulateur le contenu de la case mémoire pointée par HL (valeur 8 bits) parce qu'il y a les parenthèses. Sans les parenthèses, ça serait juste la valeur du registre (une adresse mémoire) ce qui ne serait pas possible puisque HL est 16 bits et A 8 bits." (je ne différencie pas en fait la case mémoire et l'adresse mémoire)

Donc avec 

LD A,(HL)
On charge dans l'accumulateur DB "Bonjour !",0 ? Et cela à cause des parenthèses, si la syntaxe avait été LD A,HL on aurait chargé l'adresse "physique" où l'instruction était inscrite dans la RAM ?
(Je reformule pour être sur de bien comprendre)

Avec CP 0, le Z80 compare à chaque passage de la boucle le caractère à l'adresse avec 0. La virgule entre "Bonjour !" et 0 indique qu'il y a deux chaines de caractères ; "Bonjour !" et "0". Bon.

Chaque lettre de "Bonjour !" a une adresse différente en mémoire et l'INC HL permet de passer à la suivante à chaque boucle, jusqu'à croiser le 0. La virgule est-elle utile ? Si cela avait été "Bonjour !0", le programme aurait fonctionné pareil ?

Il y a encore une commande que je ne comprend pas c'est le CALL &BB5A . A quoi sert-il celui-ci ?

Merci, ça m'est vraiment très utile et je comprend mieux certaines choses!

J'ai commencé effectivement a écouter les Chiant pour Chiant, c'est vrai que ca tient la promesse du titre ^^ mais c'est vraiment bon et complémentaire avec les autres approches (Je n'en suis qu'à la 2eme)

Hello, Je vais t'expliquer la différence entre une adresse et une case mémoire...

LD HL, TEXTE ; On charge dans 'HL' la valeur de 'TEXTE' (#500E) ça c'est une adresse.
- #500E c'est la que le LABEL TEXTE pointera une fois le programme compilé. Voir plus bas

LD A, (HL) ; On charge dans le registre 'A' la valeur que le registre 'HL' pointe - ça c'est la case mémoire
- Le registre 'A' contiendra la valeur de la case mémoire pointé en #500E
----------------
Mieux en détails:
A la  fin du programme, tu déclare le label TEXTE avec l'instruction TEXTE DB "Bonjour !", 0
Comme le programme finira à l'adresse #500D, ta déclaration du label TEXTE commencera à #500E
- On ne sait pas à l'avance la longueur d'un programme, c'est pour ça que la déclaration des LABELS est très utile, car ça permet de faire pointer un registre à une adresse que l'on ne connait pas à l'avance.

Donc voila ce que l'on obtient après ta déclaration 'TEXTE' une fois que le programme a été compilé:

#500E TEXTE DB "Bonjour !", 0
Le Label 'TEXTE' pointe à l'adresse #500E

Regardons les cases mémoires au niveau de ton label 'TEXTE':
#500E #42 ; 'B'
#500F #6F ; 'o'
#5010 #6E ; 'n'
#5011 #6A ; 'j'
#5012 #6F ; 'o'
#5013 #75 ; 'u'
#5014 #72 ; 'r'
#5015 #20 ; ' '
#5016 #21 ; '!'
#5017 #00

La case #500E contient la valeur #42 soit le code ascii du caractère 'B' 
La case #500F contient la valeur #6F soit le code ascii du caractère 'o'
ETC... 
- Pour y accéder, le registre 'HL' est utilisé comme pointeur d'adresse et on utilise le registre 'A' pour obtenir son contenu  (sa case mémoire) 
Non on ne peux pas utiliser un registre 16bits avec un registre 8bits sauf quand le registre 16bits est utilisé comme pointeur, alors le registre 'A' 8bits peut avoir accès à sa case mémoire de 8bits.

Je ne sais pas si tu connais le système (hexadécimal) ?, et si c'est pas le cas, alors il faudrait commencer par la, car ce que je viens d'expliquer, ne doit pas avoir un grand sens.
 
 

Les vecteurs sont des routines(programmes) qui sont déjà définies pour accomplir certaines tâches comme l'affichage d'un caractère par exemple ou bien pour effacer l'écran ou changer de couleur d'encre... etc etc ...
 
Pour afficher un caractère sur l'écran, on utilise le VECTEUR #BB5A, celui ci est chargé d'afficher un caractère dont le code ascii est contenu dans le registre 'A'
Pour un petit programme simplifié de celui de dessus on pourrait écrire:
ORG #5000
LD A, 'B"
CALL #BB5A
LD A, "o"
CALL #BB5A
LD A, "n"
CALL #BB5A
LD A, "j"
CALL #BB5A
LD A, "o"
CALL #BB5A
LD A, "u"
CALL #BB5A
LD A, "r"
CALL #BB5A
LD A, " "
CALL #BB5A
LD A, "!"
CALL #BB5A
 RET

Le vecteur écrit le caractère contenu dans 'A'  à l'endroit du curseur et il déplace le curseur d'un caractère sur la droite.

L'instruction 'RET' permet de dire que le programme est terminé (Très important car sinon le programme continuera sur des instructions non programmées)= plantage à 100% des cas.