[ EXELVISION ] initiation à l'assembleur pour TMS7020

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 : Carl, Papy.G, fneck

Avatar du membre
kikich
Messages : 40
Enregistré le : 24 oct. 2016 23:19
Localisation : Aube

Re: [ EXELVISION ] initiation à l'assembleur pour TMS7020

Message par kikich » 30 janv. 2017 16:49

la théorie c'est bien mais la pratique c'est mieux,
c'est la que l'on va se rendre compte si l'on a vraiment comprit ou pas

jester
Messages : 2217
Enregistré le : 01 janv. 2009 23:16
Localisation : Grenoble

Re: [ EXELVISION ] initiation à l'assembleur pour TMS7020

Message par jester » 31 janv. 2017 11:14

6502man a écrit :Je vais préparer la partie sur le VDP mais en restant très simple pour ne pas perdre tous le monde en route :wink:

Je fais l'impasse sur le 7041 et la synthèse vocale (on pourra l'aborder directement avec du code d'exemple).
La synthèse vocale c'est le plus simple sur cette machine: il y a juste à appeler une fonction pour jouer, pause, arrêter... en renseignant où se trouve les données. Pour le reste tout se fait en interne. Le 7041 on s'en tape un peu 99.5% des fois.

Que la force soit avec toi pour expliquer le VDP... là c'est le double noeud du cerveau à tous les coups !

Avatar du membre
6502man
Messages : 9073
Enregistré le : 12 avr. 2007 22:46
Localisation : VAR
Contact :

Re: [ EXELVISION ] initiation à l'assembleur pour TMS7020

Message par 6502man » 02 févr. 2017 23:22

Suite de la première partie

4) Le VDP
Video Display Processor de son nom complet, est le coprocesseur TMS3556 dédié à tout ce qui concerne l'affichage de l'EXL100.

Ce processeur vidéo dispose de 16 registres spécifiques et de sa propre RAM la VRAM.

3 modes d'affichages possible avec ce VDP : TEXTE, BITMAP, MIXTE.

TEXTE: résolution de 25 X 40 avec 2 couleurs par caractère (fond/forme) en mode alphanumérique ou mosaique, ce mode occupe 2000 octets de VRAM (caractères + attributs).
BITMAP: résolution de 320 X 250 avec 8 couleurs par pixels, ce mode occupe 30500 octets de VRAM (3 bits par pixels).
MIXTE: résolution paramétrable par ligne (TEXTE ou BITMAP) avec les contraintes de couleurs correspondantes, ce mode occupe de 2000 à 30500 octets de VRAM selon la configuration appliquée.



La VRAM installée sur l'EXL100 est de 32Ko, cette mémoire doit être configurée de manière à réserver les zones mémoires nécessaires pour chaque partie.
Cette opération d'initialisation doit être effectuée toujours en premier, dans tout programme assembleur autonome, ou utilisant un mode d'affichage différent du contexte existant.

Schéma de la répartition des différentes zones de la VRAM, l'ordre est totalement arbitraire puisque entièrement redéfinissable :

Code : Tout sélectionner

                 VDP
                  !
  ---------------------------------
  !       !       !       !       !
BAGC0   BAGC1   BAGC2   BAGC3   BAPA

BAGC0 : générateur de caractères N°0 Alphanumérique de 128 caractères
BAGC1 : générateur de caractères N°1 Alphanumérique de 128 caractères
BAGC2 : générateur de caractères N°2 Mosaique de 128 caractères
BAGC3 : générateur de caractères N°3 Alphanumérique ou Mosaique (1*) de 128 caractères
BAPA : début de la zone écran

Donc ces 5 zones doivent être définies en renseignant leurs adresses dans la VRAM, il faut bien entendu faire attention à ce que chaque zone ne se chevauche pas.

Chaque générateur de caractères occupe 1280 octets en VRAM, chaque caractère est défini sur 10 octets et chaque caractère à une résolution de 8 X 10.

Vous allez me dire mais comment on peut caser tout ça dans 32Ko si on utilise le mode BITMAP puisque 30500 + (4 * 1280) = 35620 octets alors que l'on à seulement 32768 octets de VRAM, et bien il faudra simplement définir 1 seul générateur de caractères et appliquer la même adresse aux 4 générateurs de caractères !!!


Définition d'un générateur de caractère:
Chaque caractère occupe 10 octets et sont enregistrés en VRAM de la manière suivante:
chaque dernière ligne des 128 caractères puis avant dernière ligne des 128 caractères, etc pour chaque ligne.
Exemple pour un générateur qui contiendrait les dessins de ABCD..Z, le numéro indique la ligne du caractère:
A9 B9 C9 D9 ... Z9
A8 B8 C8 D8 ... Z8
A7 B7 C7 D7 ... Z7
......................
A2 B2 C2 D2 ... Z2
A1 B1 C1 D1 ... Z1
A0 B0 C0 D0 ... Z0



Organisation des octets dans la zone affichable (2*):
Selon le mode choisi les données ne sont pas organisées de la même manières.
En mode Texte: pour chaque ligne on commence par placer l'attribut du 1er caractère (couleur, générateur,..) puis le code ASCII du 1er caractère, ensuite l'attribut du 2ème caractère puis le code ASCII du 2ème caractère, ainsi de suite sur 40 colonnes plus 2 octets de contrôles en répétant la même chose sur 25 lignes.
En mode BITMAP: 3 octets par bloc de 8 pixels BGR (bleu vert rouge) sur 120 octets + 2 octets de contrôles.
En mode MIXTE: chaque ligne est définie par les 2 octets de fin de la ligne précédente, donc si défini en mode texte 80 octets + 2 octets de contrôles si mode bitmap 120 octets + 2 octets de contrôles.


les 3 octets BGR successifs du mode bitmap sont définis de cette manière:

Code : Tout sélectionner

                                       VRAM
1er octet  :  B B B B B B B B     1 1 1 1 0 0 0 0
2eme octet :  G G G G G G G G     1 0 1 0 1 1 0 0
3eme octet :  R R R R R R R R     1 1 0 0 1 0 1 0
                                  = = = = = = = =
                                  | | | | | | | |
                                  | | | | | | | |-> Noir    0+0+0
                                  | | | | | | |---> Rouge   0+0+1
                                  | | | | | |-----> Vert    0+1+0
                                  | | | | |-------> Jaune   0+1+1
                                  | | | |---------> Bleu    1+0+0
                                  | | |-----------> Cyan    1+1+0
                                  | |-------------> Magenta 1+0+1
                                  |---------------> Blanc   1+1+1


les attributs du mode texte(3*):
Alphanumérique=

Code : Tout sélectionner

                     Détail de l'octet attribut
                  BF GF RF CG1 CG0 INV DH DW
BF+GF+RF > défini la couleur du caractère en respectant le code BGR défini précédemment.
CG1+CG0 > défini le générateur de caractères à utiliser pour le caractère 00:BAGC0, 01:BAGC2, 10:BAGC1, 11:BAGC3.
INV > défini si inversion vidéo ou normal.
DH+DW > défini la taille du caractère 00= normal, 01= double largeur, 10= double hauteur, 11= double taille.
Mosaique=

Code : Tout sélectionner

                     Détail de l'octet attribut
                  BF GF RF CG1 CG0 BB GB RB
BF+GF+RF > défini la couleur du caractère en respectant le code BGR défini précédemment.
CG1+CG0 > défini le générateur de caractères à utiliser pour le caractère.
BB+GB+RB > défini la couleur de fond du caractère en respectant le code BGR défini précédemment.
Cas particulier du caractère 20H (espace), il sert de délimiteur en mode Videotext, pour signaler le début et la fin d'une zone ayant les mêmes attributs.(4*)


Les octets de contrôles:

Code : Tout sélectionner

121eme octet: BM GM RM C/G MR LR IR
BM+GM+RM > défini la couleur de la marge en respectant le code BGR défini précédemment.
C/G > pour le mode mixte permet de définir si la ligne est en mode texte ou bitmap.
MR > MASK permet de cacher l'affichage de la ligne (texte).
LR > active le soulignement (texte).
IR > active l'incrustation (texte).

122eme octet: I output > contrôle l'affichage (voir le datasheet pour plus de détails).



Les registres du VDP:
Il y a 8 registres 8 bits (0 à 7) et 8 registres 16 bits (8 à 15) dans le TMS3556.

Code : Tout sélectionner

 0  Pointeur   Pointeur de registre
 1   COL        Adresse LSB
 2   ROW        Adresse MSB
 3   STATUS     Etat du VDP
 4   CM1        Paramétrage du VDP 
 5   CM2        Paramétrage du VDP
 6   CM3        Paramétrage du VDP
 7   CM4        Paramétrage du VDP
 8   BAMT       Adresse de début du buffer des données VDP
 9   BAMP       Adresse des accès VRAM du VDP (auto-incrémenté)
10  BAPA       Adresse de début de l'écran (début des données affichées)
11  BAGC0      Adresse du générateur de caractères 0
12  BAGC1      Adresse du générateur de caractères 1
13  BAGC2      Adresse du générateur de caractères 2
14  BAGC3      Adresse du générateur de caractères 3
15  BAMTF      Adresse de la fin du buffer des données VDP
Pour écrire dans les registres du VDP il faut envoyer au VDP en premier le numéro du registre puis la donnée, pour ça on utilise le port P45.
Exemple pour écrire dans le registre 7 pour définir la couleur de bord en blanc:

Code : Tout sélectionner

MOVP #$07,P45
MOVP #$E0,P45
Pour les registres 16bits il faut utiliser les registres COL et ROW
Exemple pour écrire dans le registre 10 et définir l’adresse de BAPA à $1000 (attention le VDP incrémente systématiquement l'adresse envoyée au registre par COL/ROW, donc pensez à envoyer l'adresse -1) :

Code : Tout sélectionner

MOVP #$01,P45    ; registre COL
MOVP #$FF,P45
MOVP #$02,P45    ; registre ROW
MOVP #$0F,P45
MOVP #$0A,P45    ; registre BAPA
MOVP #$00,P45    ; phase 1 LSB
MOVP #$00,P45    ; phase 2 MSB
Dans le cas des BAGC0 à BAGC3 il faut soustraire -2 !:!:!:

Le VDP utilise certains registres comme pointeur pour faciliter l'accès à la VRAM, pour cela BAMP devient ACMP et COL + ROW deviennent ACMPxy, et le gros avantage c'est que ces pointeurs sont auto-incrémentés lors de chaque utilisation que ça soit en lecture ou en écriture, c'est très pratique :)


Pour écrire dans la VRAM on peut utilise le port P46, mais le CPU à aussi 2 instructions spécifique pour lire ou écrire dans la VRAM :
LVDP et WVDP.

Exelvision a aussi prévu des routines intégré dans la ROM du TMS7020, ces routines sont appelées par l'instruction TRAP x,ou x correspond au numéro de la routine dans la ROM, certaines de ces routines ont spécialement été crées pour la gestion du VDP, initialiser les générateurs de caractères, définir les adresses des pointeurs ACMP et ACMPxy ... (5*)

Voila pour la partie VDP, je ne pense pas avoir oublié de point important :roll:


Je vois déjà beaucoup de questions, mais j'ai volontairement condensé au maximum, pour que cela reste dans le cadre d'une initiation, je vais pas refaire la datasheet.
Par la suite nous verrons par les codes d'exemples plus en détails les points un peu plus complexe.


N’hésitez pas à consulter les docs sur le site de Daniel:
http://dcexel.free.fr/doc/


-----------------------------------------
(1*) Les générateurs Alphanumériques correspondent aux caractères texte classique.
Les générateurs mosaique correspondent aux caractéres semi graphique type Videotext.
(2*) En mode Texte 2 octets par caractère affiché soit (40*2) + 2 octets par ligne.
En mode Bitmap 3 octets par 8 pixels affichés soit (40*3) + 2 octets par ligne.
(3*) l'octet contenant le code ASCII à afficher est sur 7 bits le 8éme bit sert à definir si le caractère doit clignoter ou non.
(4*) Pour plus de détails sur les délimiteurs et leurs fonctionnement avec le TMS3556 voir le DATASHEET.
(5*) Pour la liste complète et détaillé voir page 46 à 57 du livre "Programmer en assembleur sur Exelvision".



8) L'adressage

C'est la manière dont le CPU va adresser la RAM, la VRAM ou les PORTS.
Le TMS7020 a plusieurs modes d'adressages, implicite, direct, immédiat, absolue, indexée, indirecte et relatif.

Lorsque l'on programme en assembleur nous allons préciser des adresses ou des registres, même des adresses contenues dans des registres, et le CPU va interpréter les différents modes d'adressages pour pouvoir accéder à ces adresses.

Implicite

Code : Tout sélectionner

pour toutes les instructions dont l'adressage n'est pas précisé car il est sous entendu.
Par exemple CLRC qui met à zéro la retenue, on ne précise pas ST.
Direct

Code : Tout sélectionner

pour toutes les instructions entre registres et ou les PORTS.
Par exemple ADD R10,R12 ou MOVP A,P46. 
Immédiat

Code : Tout sélectionner

pour toutes les instructions ayant une donnée en source et un registre en destination et ou les PORTS.
Par exemple MOVP #$FF,P46 ou SUB #$10,R12 ou encore MOVD #$2536,R32.
ABSOLU

Code : Tout sélectionner

pour toutes les instructions indiquant une adresse mémoire.
Par exemple LDA @$1000 ou STA @$2000 ou BR @C600.
INDEXE

Code : Tout sélectionner

pour toutes les instructions utilisant le registre B comme index d'adresse.
Par exemple LDA @$2000(B) [l'accumulateur seras chargé avec l'octet présent en ($2000+B)].
Indirect

Code : Tout sélectionner

pour toutes les instructions utilisant 2 registres comme adresse.
Par exemple LDA *R12 (l'accumulateur seras chargé avec l'octet présent à l'adresse composé par la valeur en R11 et R12, si R11=$10 et R12=$00 l'adresse lu seras donc $1000).
Relatif [/b]

Code : Tout sélectionner

pour toutes les instructions de saut conditionnel.
Par exemple JEQ,JNE, l'adresse de saut est calculé par rapport à l'adresse courante de PC dans la limite d'un déplacement de -128 par rapport à l'adresse courante et +127 par rapport à l'adresse courante.
LA SUITE ICI
Modifié en dernier par 6502man le 12 févr. 2017 23:39, modifié 2 fois.
Phil.

www.6502man.com

To bit or not to bit.
1 or 0.

Avatar du membre
kikich
Messages : 40
Enregistré le : 24 oct. 2016 23:19
Localisation : Aube

Re: [ EXELVISION ] initiation à l'assembleur pour TMS7020

Message par kikich » 03 févr. 2017 00:20

oula la , je commence a décrocher :roll:
Il va falloir que je relise tout. Je dois être un peu fatiguer pour ingurgiter le VDP a cette heure ci :?

j'ai aperçu une petit faute. :wink:
6502man a écrit : Exelvision à aussi prévu des routines intégré dans la ROM du TMS7020, ces routines sont appelées par l'instruction TRAP x,ou x correspond au numéro de la routine dans la ROM, certaines de ces routines ont spécialement étaient (été) crées pour la gestion du VDP, initialiser les générateurs de caractères, définir les adresses des pointeurs ACMP et ACMPxy ... (5*)

jester
Messages : 2217
Enregistré le : 01 janv. 2009 23:16
Localisation : Grenoble

Re: [ EXELVISION ] initiation à l'assembleur pour TMS7020

Message par jester » 03 févr. 2017 13:03

Il faut attendre les exemples... en pratique c'est pas très compliqué, il faut juste être méthodique pour programmer le VDP.
Malheureusement la logique fonctionnelle du VDP, la structuration des pixels en mémoire, et le mode de communication avec le CPU réduise beaucoup l'utilisabilité du mode graphique: si on veut avoir un affichage un peu rapide (animation) il faut des astuces qui prennent pas mal de mémoire, et ça reste impossible de faire un jeu d'action/arcade, même un jeu d'aventure animé.

Le mode texte par contre est très sympa... à utiliser en priorité pour un jeu/démo rapide.

Avatar du membre
6502man
Messages : 9073
Enregistré le : 12 avr. 2007 22:46
Localisation : VAR
Contact :

Re: [ EXELVISION ] initiation à l'assembleur pour TMS7020

Message par 6502man » 04 févr. 2017 00:21

Je viens de rajouter la partie sur l'Adressage :wink:

Patience les premiers codes d'exemples arrivent :lol:
Phil.

www.6502man.com

To bit or not to bit.
1 or 0.

Avatar du membre
6502man
Messages : 9073
Enregistré le : 12 avr. 2007 22:46
Localisation : VAR
Contact :

Re: [ EXELVISION ] initiation à l'assembleur pour TMS7020

Message par 6502man » 12 févr. 2017 23:38

la pratique :

Affectation, addition, soustraction et muliplication.

Nous allons commencer par la base en programmation assembleur c'est à dires la manipulation des Accumulateurs ainsi que l'arithmétique de base.

A) L'affectation des Accumulateurs (A ou B) et/ou des registres (Rxx):

Code : Tout sélectionner

    LDA @$C600    permet de charger la valeur présente en $C600 dans A.
    MOV #$2F,B    permet de charger la valeur $2F dans B.
    MOV #$7C,R12  permet de charger la valeur $7F dans le registre R12.
    MOV R12,A     permet de copier la valeur présente dans le registre R12 vers  A.
    MOV A,B       permet de copier la valeur de A dans B.
Comme nous venons de le voir il y a plusieurs manières d'affecter une valeur à l'Accumulateur ou aux registres.
On peut aussi utiliser le mode d'adressage indirect:

Code : Tout sélectionner

    MOV #$C6,R11   renseigne l'adresse de la case mémoire à lire
    MOV #$00,R12   dans R11-R12.
    LDA *R12       permet de charger la valeur présente en $C600 dans A.
De même avec le mode d'adressage indéxé par B:

Code : Tout sélectionner

    CLR B          met à zéro B
    LDA @$2000(B)  charge la valeur présente en ($2000+0) dans A.

B) Calculons avec les Accumulateurs et les registres.

Code : Tout sélectionner

    ADD #$05,A    addition $05 à A, le résultat est stocké dans A.
    SUB #$4D,A    soustrait $4D à A, le résultat est stocké dans A.
    ADD A,R12     additionne la valeur contenu dans A et R12, le résultat
                  est stocké dans R12.
    ADC #$11,A    addition $11 à A et rajoute la retenue si positionnée à 1,
                  le resultat est stocké dans A.
    SBB #$7F,R11  soustrait $7F à R11 et prend en compte la retenue si
                  positionné à 1, le resultat est stocké dans R11.
    MPY R11,R12   multiplie R11 avec R12, le resultat est toujours dans A et B.
Les codes d'exemples:
Nous implanterons nos programmes assembleur en $C700 et les donnèes en $C600.
Dans un premier temps les programmes seront utilisables avec le BASIC pour
appréhender plus facilement l'assembleur ;)

a) l'addition 8bits:
Pour commencer nous allons écrire un programme d'addition 8bits et voir le résultat en RAM.
En $C600 et $C601 les 2 nombres à additionner, le résultat seras placé en $C602.

Code : Tout sélectionner

.ORG $C700
    PUSH A          ;on sauvegarde dans la pile l'état de A
    PUSH B          ;on sauvegarde dans la pile l'état de B
    LDA @$C600       ;on charge l'octet présent en $C600 dans A
    MOV A,B         ;on copie A dans B
    LDA @$C601       ;on charge l'octet présent en $C601 dans A
    ADD B,A         ;on addition B et A (le résultat est stocké dans A)
    STA @$C602       ;on ecrit la valeur de A en $C602
    POP B           ;on restitue l'état de B
    POP A           ;on restitue l'état de A
    RETS             ;le programme est fini on laisse la main au système.

Code : Tout sélectionner

0003   C700             .ORG $C700
0004   C700 B8              PUSH A          ;on sauvegarde dans la pile l'état de A
0005   C701 C8              PUSH B          ;on sauvegarde dans la pile l'état de B
0006   C702 8A C6 00        LDA @$C600       ;on charge l'octet présent en $C600 dans A
0007   C705 C0              MOV A,B         ;on copie A dans B
0008   C706 8A C6 01        LDA @$C601       ;on charge l'octet présent en $C601 dans A
0009   C709 68              ADD B,A         ;on addition B et A (le résultat est stocké dans A)
0010   C70A 8B C6 02        STA @$C602       ;on ecrit la valeur de A en $C602
0011   C70D C9              POP B           ;on restitue l'état de B
0012   C70E B9              POP A           ;on restitue l'état de A
0013   C70F 0A              RETS             ;le programme est fini on laisse la main au système.


b) l'addition 16bits:
Cette fois nous allons faire une addition sur 16 bits, et vérifier le résultat en RAM.
En $C600 et $C601 le premier nombre 16 bits à additionner avec le deuxième nombre 16 bits présent en $C602 et $C603, le
résultat seras stocké en $C604 et $C605.

Code : Tout sélectionner

.ORG $C700
    PUSH A          ;on sauvegarde dans la pile l'état de A
    PUSH B          ;on sauvegarde dans la pile l'état de B
    PUSH R30        ;on sauvegarde dans la pile l'état de R30
    PUSH R31        ;on sauvegarde dans la pile l'état de R31
    LDA @$c600      ;on charge l'octet présent en $C600 dans A
    MOV A,R30       ;on copie A dans R30
    LDA @$C601      ;on charge l'octet présent en $C601 dans A
    MOV A,R31       ;on copie A dans R31
    LDA @$C603      ;on charge l'octet présent en $C602 dans A
    MOV A,B         ;on copie A dans B
    LDA @$C602      ;on charge l'octet présent en $C603 dans A
    ADD R1,R31      ;on additionne A (R0) à R31 le résultat dans R31
    ADC R0,R30      ;on additionne B (R1) à R30 en tenant compte de la retenue
                    ;  le résultat dans R30    
    MOV R30,A       ;on copie R30 dans A
    STA @$C604      ;on ecrit la valeur de A en $C604
    MOV R31,A       ;on copie R31 dans A
    STA @$C605      ;on ecrit la valeur de A en $C605
    POP R31         ;on restitue l'état de R31
    POP R30         ;on restitue l'état de R30
    POP B           ;on restitue l'état de B
    POP A           ;on restitue l'état de A
    RETS            ;le programme est fini on laisse la main au système.
* on pourrait utiliser aussi l'instruction MOVD pour charger les 2 valeurs
16 bits, mais cela ne permet pas de lire une valeur en mémoire mais uniquement des valeurs de registres.

Code : Tout sélectionner

0003   C700             .ORG $C700
0004   C700 B8              PUSH A          ;on sauvegarde dans la pile l'état de A
0005   C701 C8              PUSH B          ;on sauvegarde dans la pile l'état de B
0006   C702 D8 1E           PUSH R30        ;on sauvegarde dans la pile l'état de R30
0007   C704 D8 1F           PUSH R31        ;on sauvegarde dans la pile l'état de R31
0008   C706 8A C6 00        LDA @$c600      ;on charge l'octet présent en $C600 dans A
0009   C709 D0 1E           MOV A,R30       ;on copie A dans R30
0010   C70B 8A C6 01        LDA @$C601      ;on charge l'octet présent en $C601 dans A
0011   C70E D0 1F           MOV A,R31       ;on copie A dans R31
0012   C710 8A C6 03        LDA @$C603      ;on charge l'octet présent en $C603 dans A
0013   C713 C0              MOV A,B			;on copie A dans B
0014   C714 8A C6 02        LDA @$C602      ;on charge l'octet présent en $C602 dans A
0015   C717 48 01 1F        ADD R1,R31      ;on additionne A (R0) à R31 le résultat dans R31
0016   C71A 49 00 1E        ADC R0,R30      ;on additionne B (R1) à R30 en tenant compte de la retenue
0017   C71D                                 ;  le résultat dans R30    
0018   C71D 12 1E           MOV R30,A       ;on copie R30 dans A
0019   C71F 8B C6 04        STA @$C604      ;on ecrit la valeur de A en $C604
0020   C722 12 1F           MOV R31,A       ;on copie R31 dans A
0021   C724 8B C6 05        STA @$C605      ;on ecrit la valeur de A en $C605
0022   C727 D9 1F           POP R31         ;on restitue l'état de R31
0023   C729 D9 1E           POP R30         ;on restitue l'état de R30
0024   C72B C9              POP B           ;on restitue l'état de B
0025   C72C B9              POP A           ;on restitue l'état de A
0026   C72D 0A              RETS            ;le programme est fini on laisse la main au système.

Technique utilisé pour le calcul sur 16bits:
Nous utiliserons la notation hexadécimal pour bien décomposer les opérations et bien comprendre la manière dont le CPU utilise
les donnèes, par exemple $2185 + $1791 est enregistré dans la mémoire sur 4 octets, le CPU calcul en 8 bits donc nous utilisons la retenue pour pouvoir

Code : Tout sélectionner

 $21    $85
  +         +
 $17    $91
Pour bien calculer il faut commencer par les octets de poids faibles $85 + $91 = $116 soit la retenue et $16, donc l'indicateur de retenue à était positionné par le CPU après l'execution de ADD, ensuite nous passons aux octets de poids forts $21 + $17, comme nous utilisons ADC la retenue est additionné si elle est positionné, ce qui est le cas dans l'exemple présent, donc cela fait $21 +$17 +$01 soit au total $39 $16.
Vous aurez compris que l'on pouvait aussi grâce à la retenue avoir un résultat sur 3 octets dans le cas ou le total des 2 nombres dépasserais $FFFF.
Cela s'applique aussi pour les autres exemples de calculs 8 ou 16bits.



c) la soustraction 8bits:
Nous allons écrire un programme de soustraction 8bits et voir le résultat en RAM.
En $C600 et $C601 les 2 nombres à additionner, le résultat seras placé en $C602.

Code : Tout sélectionner

.ORG $C700
    PUSH A          ;on sauvegarde dans la pile l'état de A
    PUSH B          ;on sauvegarde dans la pile l'état de B
    LDA @$c601      ;on charge l'octet présent en $C600 dans A
    MOV A,B         ;on copie A dans B
    LDA @$C600      ;on charge l'octet présent en $C601 dans A
    SUB B,A         ;on soustrait B et A (le résultat est stocké dans A)
    STA @$C602      ;on ecrit la valeur de A en $C602
    POP B           ;on restitue l'état de B
    POP A           ;on restitue l'état de A
    RETS            ;le programme est fini on laisse la main au système.

Code : Tout sélectionner

0003   C700             .ORG $C700
0004   C700 B8              PUSH A          ;on sauvegarde dans la pile l'état de A
0005   C701 C8              PUSH B          ;on sauvegarde dans la pile l'état de B
0006   C702 8A C6 01        LDA @$c601      ;on charge l'octet présent en $C600 dans A
0007   C705 C0              MOV A,B         ;on copie A dans B
0008   C706 8A C6 00        LDA @$C600      ;on charge l'octet présent en $C601 dans A
0009   C709 6A              SUB B,A         ;on soustrait B et A (le résultat est stocké dans A)
0010   C70A 8B C6 02        STA @$C602      ;on ecrit la valeur de A en $C602
0011   C70D C9              POP B           ;on restitue l'état de B
0012   C70E B9              POP A           ;on restitue l'état de A
0013   C70F 0A              RETS            ;le programme est fini on laisse la main au système.


d) la soustraction 16bits:
Nous allons faire une soustraction sur 16 bits, et vérifier le résultat en RAM.
En $C600 et $C601 le premier nombre 16 bits à soustraire avec le deuxième nombre 16 bits présent en $C602 et $C603,
le résultat seras stocké en $C604 et $C605.

Code : Tout sélectionner

.ORG $C700
    PUSH A          ;on sauvegarde dans la pile l'état de A
    PUSH B          ;on sauvegarde dans la pile l'état de B
    PUSH R30        ;on sauvegarde dans la pile l'état de R30
    PUSH R31        ;on sauvegarde dans la pile l'état de R31
    LDA @$c600      ;on charge l'octet présent en $C600 dans A
    MOV A,R30       ;on copie A dans R30
    LDA @$C601      ;on charge l'octet présent en $C601 dans A
    MOV A,R31       ;on copie A dans R31
    LDA @$C603      ;on charge l'octet présent en $C602 dans A
    MOV A,B         ;on copie A dans B
    LDA @$C602      ;on charge l'octet présent en $C603 dans A
    SUB R1,R31      ;on soustrait A à R31 le résultat dans R31
    SBB R0,R30      ;on soustrait B à R30 en prenant en compte
                    ; la retenue, le résultat est en R30
    MOV R30,A       ;on copie R30 dans A 
    STA @$C604      ;on ecrit la valeur de A en $C604
    MOV R31,A       ;on copie R31 dans A
    STA @$C605      ;on ecrit la valeur de A en $C605
    POP R31         ;on restitue l'état de R31
    POP R30         ;on restitue l'état de R30
    POP B           ;on restitue l'état de B
    POP A           ;on restitue l'état de A
    RETS             ;le programme est fini on laisse la main au système.

Code : Tout sélectionner

0003   C700             .ORG $C700
0004   C700 B8              PUSH A          ;on sauvegarde dans la pile l'état de A
0005   C701 C8              PUSH B          ;on sauvegarde dans la pile l'état de B
0006   C702 D8 1E           PUSH R30        ;on sauvegarde dans la pile l'état de R30
0007   C704 D8 1F           PUSH R31        ;on sauvegarde dans la pile l'état de R31
0008   C706 8A C6 00        LDA @$c600      ;on charge l'octet présent en $C600 dans A
0009   C709 D0 1E           MOV A,R30       ;on copie A dans R30
0010   C70B 8A C6 01        LDA @$C601      ;on charge l'octet présent en $C601 dans A
0011   C70E D0 1F           MOV A,R31       ;on copie A dans R31
0012   C710 8A C6 03        LDA @$C603      ;on charge l'octet présent en $C602 dans A
0013   C713 C0              MOV A,B         ;on copie A dans B
0014   C714 8A C6 02        LDA @$C602      ;on charge l'octet présent en $C603 dans A
0015   C717 4A 01 1F        SUB R1,R31      ;on soustrait A à R31 le résultat dans R31
0016   C71A 4B 00 1E        SBB R0,R30      ;on soustrait B à R30 en prenant en compte
0017   C71D                                 ; la retenue, le résultat est en R30
0018   C71D 12 1E           MOV R30,A       ;on copie R30 dans A 
0019   C71F 8B C6 04        STA @$C604      ;on ecrit la valeur de A en $C604
0020   C722 12 1F           MOV R31,A       ;on copie R31 dans A
0021   C724 8B C6 05        STA @$C605      ;on ecrit la valeur de A en $C605
0022   C727 D9 1F           POP R31         ;on restitue l'état de R31
0023   C729 D9 1E           POP R30         ;on restitue l'état de R30
0024   C72B C9              POP B           ;on restitue l'état de B
0025   C72C B9              POP A           ;on restitue l'état de A
0026   C72D 0A              RETS             ;le programme est fini on laisse la main au système.


e) la multiplication
Nous allons cette fois ci faire une multiplication 8 bits, et vérifier le résultat en RAM.
En $C600 et $C601 les deux nombres 8 bits à multiplier, le résultat seras stocké en $C604 et $C605.

Code : Tout sélectionner

.ORG $C700
    PUSH A          ;on sauvegarde dans la pile l'état de A
    PUSH B          ;on sauvegarde dans la pile l'état de B
    PUSH R30        ;on sauvegarde dans la pile l'état de R30
    PUSH R31        ;on sauvegarde dans la pile l'état de R31
    LDA @$c600      ;on charge l'octet présent en $C600 dans A
    MOV A,R30       ;on copie A dans R30
    LDA @$C601      ;on charge l'octet présent en $C601 dans A
    MOV A,R31       ;on copie A dans R31
    MPY R30,R31     ;on multiplie les 2 nombres (le CPU met toujours le 
                      résultat dans A et B)
    STA @$C604      ;on ecrit la valeur de A en $C604
    MOV B,A         ;on copie B dans A
    STA @$C605      ;on ecrit la valeur de A en $C605
    POP R31         ;on restitue l'état de R31
    POP R30         ;on restitue l'état de R30
    POP B           ;on restitue l'état de B
    POP A           ;on restitue l'état de A
    RETS            ;le programme est fini on laisse la main au système.

Code : Tout sélectionner

0003   C700             .ORG $C700
0004   C700 B8              PUSH A          ;on sauvegarde dans la pile l'état de A
0005   C701 C8              PUSH B          ;on sauvegarde dans la pile l'état de B
0006   C702 D8 1E           PUSH R30        ;on sauvegarde dans la pile l'état de R30
0007   C704 D8 1F           PUSH R31        ;on sauvegarde dans la pile l'état de R31
0008   C706 8A C6 00        LDA @$c600      ;on charge l'octet présent en $C600 dans A
0009   C709 D0 1E           MOV A,R30       ;on copie A dans R30
0010   C70B 8A C6 01        LDA @$C601      ;on charge l'octet présent en $C601 dans A
0011   C70E D0 1F           MOV A,R31       ;on copie A dans R31
0012   C710 4C 1E 1F        MPY R30,R31		;on multiplie les 2 nombres (le CPU met toujours le résultat dans A et B)
0013   C713 8B C6 04        STA @$C604      ;on ecrit la valeur de A en $C604
0014   C716 62              MOV B,A         ;on copie B dans A
0015   C717 8B C6 05        STA @$C605      ;on ecrit la valeur de A en $C605
0016   C71A D9 1F           POP R31         ;on restitue l'état de R31
0017   C71C D9 1E           POP R30         ;on restitue l'état de R30
0018   C71E C9              POP B           ;on restitue l'état de B
0019   C71F B9              POP A           ;on restitue l'état de A
0020   C720 0A              RETS            ;le programme est fini on laisse la main au système.


Voila c'est fini pour la première leçon ;)

Pour ceux qui suivent et qui ont compris, proposez moi un code pour une addition de 2 nombres de 32 bits,
( $1547FF15 + $EF971456 ) le résultat seras sur 5 octets ;)



Les programmes ci dessus sont inclus dans l'archive LESSON1.ZIP


------------------------------------------------------------------------------------------------------------------------------------------------------------


Qu'est ce qui vous faut pour programmer en assembleur pour EXL100 sous windows :
- DCexel version développeur (à demander à Daniel)
- TASM
- Le fichier de correspondance des mnémoniques TMS7020 pour TASM
- l'include spécifique pour le 7020 (merci Jester)
1: configurer DCexel en mode EXL100 sans lecteur de disquette et avec la cartouche Basic.
2: dans le fichier LESSON1.ZIP importer en mode "simulation de clavier" le fichier basic correspondant à l'exercice que vous voulez.
3: executer le programme Basic
4: Le mode mise au point dans DCexel : saisir l'adresse C700 dans la case adresse pour visualiser le code désassemblé ou C600 pour vérifier les donnèes utiliser par les programmes.
dcexel.jpg
dcexel.jpg (264.94 Kio) Vu 1234 fois
5: l'assemblage d'un fichier source en assembleur: allez dans le répertoire ASM et prenez un des fichier .ASM et faites le glisser sur "_goasm.bat", vous obtiendrez 2 nouveaux fichiers .LST et .BIN, sauf si il y a une erreur dans ce cas le .BIN ne seras pas crée.
le fichier .LST correspond au listing désassemblé avec les codes hexa des instructions, le .BIN est le binaire assemblé prêt à être utiliser dans l'EXL100.
6: Convertir des données binaires pour le BASIC: utiliser l'outil de Jester BIN2EXL, qui vous permettra de convertir vers une multitude de format, à télécharger ICI.

Je pense que je n'ai rien oublié et pas fait d'erreur :roll:

Amusez vous bien, la prochaine leçon seras sur les opérations logiques, et après on pourras passer à la partie la plus fun l'affichage :lol:





J'éditerais le post au fur et à mesure, donc à visiter régulièrement ;)
Phil.

www.6502man.com

To bit or not to bit.
1 or 0.

Avatar du membre
Dominique
Messages : 481
Enregistré le : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: [ EXELVISION ] initiation à l'assembleur pour TMS7020

Message par Dominique » 13 févr. 2017 01:02

Super ton cours d'Assembleur !!!!

C'est clair et ça donne rudement envie.

Avatar du membre
kikich
Messages : 40
Enregistré le : 24 oct. 2016 23:19
Localisation : Aube

Re: [ EXELVISION ] initiation à l'assembleur pour TMS7020

Message par kikich » 14 févr. 2017 22:44

magnifique, cette semaine est un peu charger, mais la semaine prochaine je me penche sérieusement sur le sujet

Avatar du membre
kikich
Messages : 40
Enregistré le : 24 oct. 2016 23:19
Localisation : Aube

Re: [ EXELVISION ] initiation à l'assembleur pour TMS7020

Message par kikich » 24 févr. 2017 12:43

Voici mon code asm. :mrgreen:
par contre je ne sais pas comment le transformer en DATA pour le listing BASIC :?

Code : Tout sélectionner

.ORG $C700
    PUSH A          ;on sauvegarde dans la pile l'état de A
    PUSH B          ;on sauvegarde dans la pile l'état de B
    PUSH R30        ;on sauvegarde dans la pile l'état de R30
    PUSH R31        ;on sauvegarde dans la pile l'état de R31
    PUSH R32        ;on sauvegarde dans la pile l'état de R32
    PUSH R33        ;on sauvegarde dans la pile l'état de R33
    PUSH R34        ;on sauvegarde dans la pile l'état de R34
    PUSH R35        ;on sauvegarde dans la pile l'état de R35
    LDA @$c600      ;on charge l'octet présent en $C600 dans A
    MOV A,R30       ;on copie A dans R30
    LDA @$C601      ;on charge l'octet présent en $C601 dans A
    MOV A,R31       ;on copie A dans R31
    LDA @$C602      ;on charge l'octet présent en $C602 dans A
    MOV A,R32       ;on copie A dans R32
    LDA @$C603      ;on charge l'octet présent en $C603 dans A
    MOV A,R33       ;on copie A dans R33
    LDA @$C604     ;on charge l'octet présent en $C604 dans A
    MOV A,R34       ;on copie A dans R34
    LDA @$C605      ;on charge l'octet présent en $C605 dans A
    MOV A,R35       ;on copie A dans R35
    LDA @$C606      ;on charge l'octet présent en $C606 dans A
    MOV A,B			;on copie A dans B
    LDA @$C607      ;on charge l'octet présent en $C607 dans A
    ADD R0,R33      ;on additionne A (R0) à R33 le résultat dans R33
    ADD R1,R32      ;on additionne B (R1) à R32 le résultat dans R32
    ADD R35,R31    ;on additionne R35 à R31 le résultat dans R31
    ADC R34,R30      ;on additionne R34 à R30 en tenant compte de la retenue
                    ;  le résultat dans R30    
    MOV R30,A       ;on copie R30 dans A
    STA @$C608      ;on ecrit la valeur de A en $C608
    MOV R31,A       ;on copie R31 dans A
    STA @$C609      ;on ecrit la valeur de A en $C609
    MOV R32,A       ;on copie R32 dans A
    STA @$C60A      ;on ecrit la valeur de A en $C60A
    MOV R33,A       ;on copie R33 dans A
    STA @$C60B      ;on ecrit la valeur de A en $C60B
    POP R35         ;on restitue l'état de R35
    POP R34         ;on restitue l'état de R34
    POP R33         ;on restitue l'état de R33
    POP R32         ;on restitue l'état de R32
    POP R31         ;on restitue l'état de R31
    POP R30         ;on restitue l'état de R30
    POP B           ;on restitue l'état de B
    POP A           ;on restitue l'état de A
    RETS            ;le programme est fini on laisse la main au système.

Si j'ai bien compris A=R0 et B=R1. si c'est le cas tu a fait une inversion dans tes exemples

Code : Tout sélectionner

    ADD R1,R31      ;on additionne A (R0) à R31 le résultat dans R31
    ADC R0,R30      ;on additionne B (R1) à R30 en tenant compte de la retenue

Avatar du membre
6502man
Messages : 9073
Enregistré le : 12 avr. 2007 22:46
Localisation : VAR
Contact :

Re: [ EXELVISION ] initiation à l'assembleur pour TMS7020

Message par 6502man » 25 févr. 2017 23:58

@Dominique: merci du compliment :D

@kikich: Je vois que tu as suivi la première leçon :wink:

Pour ton premier code il y a 2 choses importantes à rectifier (à première vue) :
-dans la partie addition le premier ADD est correcte, par contre à partir du deuxième il faut impérativement utiliser ADC jusqu'au dernier octet, la retenue doit se reporter si il y lieu d'octet en octet.
Exemple = $BCEFF7FC + $DACEF4FE = $197BEECFA décomposé en opération 8 bits: (1) représente la retenue qui est prise en compte pour l'addition suivante
$FC + $FE = (1) $FA
$F7 + $F4 = (1) $EB >>> si tu n'utilises pas ADC le résultat seras faux $EB au lie de $EC
$EF + $CE = (1) $BD >>> si tu n'utilises pas ADC le résultat seras faux $BD au lieu de $BE
$BC+ $DA = (1) $96

Ensuite on arrive au deuxième point.
-Je demandais "le résultat seras sur 5 octets", bon d'accord c'était un peu vache car je n'ai pas donné d'exemple pour ça.
Donc il te faut en plus rajouter une ligne d'addition comme ceci:
ADC #00,R36 (va permettre de reporter la retenu si le résultat dépasse les 32bits) ;)
et bien entendu penser à l’écrire en RAM ;)

Et ne pas oublier de rajouter l'include nécessaire en début de fichier et le .END en fin de fichier pour l'assembler avec TASM ;)

Pour l'importer dans Dcexel tu utilises soit la solution que j'ai indiqué dans le post ou directement dans l'émulateur avec la fonction "charger un fichier binaire" dans la mise au pont.

Et tu pourras tester ton programme et vérifier par toi même si il fonctionne (c'est la meilleur solution pour apprendre), bien entendu si tu n'y arrives pas demande et je t'aiderai :wink:

La semaine prochaine je prépare la partie opération logique ...

Pour te faciliter la tache voici le code asm en DATA pour le Basic:

Code : Tout sélectionner

10000 DATA 184,200,216,30,216,31,216,32,216,33,216,34,216,35,138,198
10010 DATA 0,208,30,138,198,1,208,31,138,198,2,208,32,138,198,3
10020 DATA 208,33,138,198,4,208,34,138,198,5,208,35,138,198,6,192
10030 DATA 138,198,7,72,0,33,72,1,32,72,35,31,73,34,30,18
10040 DATA 30,139,198,8,18,31,139,198,9,18,32,139,198,10,18,33
10050 DATA 139,198,11,217,35,217,34,217,33,217,32,217,31,217,30,201
10060 DATA 185,10
Phil.

www.6502man.com

To bit or not to bit.
1 or 0.

Avatar du membre
6502man
Messages : 9073
Enregistré le : 12 avr. 2007 22:46
Localisation : VAR
Contact :

Re: [ EXELVISION ] initiation à l'assembleur pour TMS7020

Message par 6502man » 30 mars 2017 00:41

Voici enfin la suite de cette initiation à l'assembleur pour EXL100.

Arithmétique logique, décalage et comparaisons
Cette deuxième partie va aborder tout ce qui concerne les opérations d’arithmétiques logiques, qui est une partie très importante de la programmation en assembleur.
Dans la foulée nous verrons aussi les décalages binaires très utiles.
Et pour finir cette partie nous aborderons les comparaisons aussi essentiel en assembleur.

1) AND, OR, XOR, INV
OU EST XOR ???
(oui c'est un jeu de mot facile)

Code : Tout sélectionner

    AND permet de faire un ET binaire.
      AND #$21,A 
    OR permet de faire un OU binaire.
	  OR #$37,B
    XOR permet de faire un OU eXclusif binaire.
	  XOR #$14,A
    INV permet de faire une inversion binaire.
	  INV A
	  
Explications:
    10101101   
AND 11111111
    10101101  résultat
OR  11110101
    11111101  résultat
XOR 01010101
    10101000  résultat
INV
    01010111  résultat
	
	A noter qu'il existe aussi ANDP, ORP et XORP qui permettent de faire la même chose mais vers
    les ports au lieu des registres.

2) RL, RLC, RR, RRC

Code : Tout sélectionner

    RL effectue un décalage de tous les bits vers la gauche, le bit 7 est copié dans la retenue
    et dans le bit 0.
    RLC effectue un décalage de tous les bits vers la gauche, la retenue est copié dans le bit 0
	et le bit 7 est copié dans la retenue.
	RR effectue un décalage de tous les bits vers la droite,le bit 0 est copié dans la retenue
    et dans le bit 7.
	RRC effectue un décalage de tous les bits vers la droite,la retenue est copié dans le bit 7
	et le bit 0 est copié dans la retenue.
	
Explications:
    10101101
RL  01011011  résultat
RLC 10110111  résultat
RR  11011011  résultat
RRC 11101101  résultat


3) CMP, CMPA

Code : Tout sélectionner

    CMP permet de comparer deux registres, ou une valeur et un registre.
	CMPA permet de comparer l'accumulateur et l'octet présent à l'adresse indiquée en adressage
    immédiat,indirect ou indéxé.
	CMP A,B compare A et B  ( B-A ) le STATUS (ST) du CPU est positionné en fonction du résultat de cette
    comparaison, les registres ne sont pas modifiés.
	CMPA *R20 compare l'accumulateur A avec l'octet présent à l'adresse indiqué par R19-R20



Les codes d'exemples:
Comme précédemment le programme en $C700 les données en $C600.

a) Convertir une valeur hexadécimal en 2 caractères ASCII.
En $C600 la valeur hexadécimal à convertir, $C602 et $C603 les 2 caractères ASCII correspondant.

Code : Tout sélectionner

    PUSH A               ;on sauvegarde dans la pile l'état de A
    PUSH B               ;on sauvegarde dans la pile l'état de B
    PUSH R30             ;on sauvegarde dans la pile l'état de R30
    PUSH R31             ;on sauvegarde dans la pile l'état de R31
    LDA @$c600           ;on charge l'octet présent en $C600 dans A
    MOV A,B              ;on copie A dans B
	AND #$F0,A           ;on applique un ET pour ne conserver que la partie gauche 
                         ; de la valeur hexadécimal dans A.
    CLRC		         ;on met le bit de retenue à zéro.
    RR A                 ;on applique un décalage binaire à droite.
	RR A                 ;on applique un décalage binaire à droite.
	RR A                 ;on applique un décalage binaire à droite.
	RR A                 ;on applique un décalage binaire à droite.
	AND #$0F,B           ;on applique un ET pour ne conserver que la partie droite 
                         ; de la valeur hexadécimal dans B.
    MOVD #HexaAscii,R31  ;on met l'adresse de la chaîne ASCII dans R30/R31.
    ADD R0,R31           ;on additionne la valeur hexa à l'adresse.
    ADC #0,R30           ;on additionne avec retenue 0 à la partie basse de l'adresse.
    LDA *R31             ;on charge le code ASCII dans A.
    STA @$C602           ;on écrit le résultat à l'adresse $C602
    MOVD #HexaAscii,R31  ;on met l'adresse de la chaîne ASCII dans R30/R31.
    ADD R1,R31           ;on additionne la valeur hexa à l'adresse.
    ADC #0,R30           ;on additionne avec retenue 0 à la partie basse de l'adresse.
    LDA *R31             ;on charge le code ASCII dans A.	
    STA @$C603           ;on écrit le résultat à l'adresse $C603
    POP R31              ;on restitue l'état de R31
    POP R30              ;on restitue l'état de R30
    POP B                ;on restitue l'état de B
    POP A                ;on restitue l'état de A
    RETS                 ;le programme est fini on laisse la main au système.
	
HexaAscii	.TEXT "0123456789ABCDEF"

Code : Tout sélectionner

0003   C700             .ORG $C700
0004   C700 B8              PUSH A               ;on sauvegarde dans la pile l'état de A
0005   C701 C8              PUSH B               ;on sauvegarde dans la pile l'état de B
0006   C702 D8 1E           PUSH R30             ;on sauvegarde dans la pile l'état de R30
0007   C704 D8 1F           PUSH R31             ;on sauvegarde dans la pile l'état de R31
0008   C706 8A C6 00        LDA @$c600           ;on charge l'octet présent en $C600 dans A
0009   C709 C0              MOV A,B              ;on copie A dans B
0010   C70A 23 F0       	AND #$F0,A           ;on applique un ET pour ne conserver que la partie gauche 
0011   C70C                                      ; de la valeur hexadecimal dans A.
0012   C70C B0              CLRC		         ;on met le bit de retenue à zéro.
0013   C70D BC              RR A                 ;on applique un décalage binaire à droite.
0014   C70E BC          	RR A                 ;on applique un décalage binaire à droite.
0015   C70F BC          	RR A                 ;on applique un décalage binaire à droite.
0016   C710 BC          	RR A                 ;on applique un décalage binaire à droite.
0017   C711 53 0F       	AND #$0F,B           ;on applique un ET pour ne conserver que la partie droite 
0018   C713                                      ; de la valeur hexadecimal dans B.
0019   C713 88 C7 38 1F     MOVD #HexaAscii,R31  ;on met l'adresse de la chaine ASCII dans R30/R31.
0020   C717 48 00 1F        ADD R0,R31           ;on additionne la valeur hexa à l'adresse.
0021   C71A 79 00 1E        ADC #0,R30           ;on additionne avec retenue 0 à la partie basse de l'adresse.
0022   C71D 9A 1F           LDA *R31             ;on charge le code ASCII dans A.
0023   C71F 8B C6 02        STA @$C602           ;on ecrit le résultat à l'adresse $C602
0024   C722 88 C7 38 1F     MOVD #HexaAscii,R31  ;on met l'adresse de la chaine ASCII dans R30/R31.
0025   C726 48 01 1F        ADD R1,R31           ;on additionne la valeur hexa à l'adresse.
0026   C729 79 00 1E        ADC #0,R30           ;on additionne avec retenue 0 à la partie basse de l'adresse.
0027   C72C 9A 1F           LDA *R31             ;on charge le code ASCII dans A.	
0028   C72E 8B C6 03        STA @$C603           ;on ecrit le résultat à l'adresse $C603
0029   C731 D9 1F           POP R31              ;on restitue l'état de R31
0030   C733 D9 1E           POP R30              ;on restitue l'état de R30
0031   C735 C9              POP B                ;on restitue l'état de B
0032   C736 B9              POP A                ;on restitue l'état de A
0033   C737 0A              RETS                 ;le programme est fini on laisse la main au système.
0034   C738             
0035   C738             	
0036   C738 30 31 32 33 HexaAscii	.TEXT "0123456789ABCDEF"
0036   C73C 34 35 36 37 
0036   C740 38 39 41 42 
0036   C744 43 44 45 46 
b) Détecter l'appui d'une touche.
Attend l'appui d'une touche parmi 4 possibles.
le code ASCII de la touche est écrit en $C600.
pour réaliser cela nous allons simplement scruter l'adresse R3 (VALUE0)
cette adresse est mise à jour dès qu'une touche du clavier est enfoncée
ou dès que le joystick 0 est actionné.

Code : Tout sélectionner

    PUSH A               ;on sauvegarde dans la pile l'état de A.
attkey
	MOV VALUE0,a         ;on récupère la valeur de la touche saisie ou pas.
	MOV #04,VALUE0       ;pour éviter une répétition de touches nous réinitialisons
                         ;  VALUE0 à $04 qui correspond à aucune action. 
	CMP #$31,a           ;on compare A avec $31 (le code ASCII de la touche '1').
	JNE NOT_1            ;si ce n'est pas égal alors on va à NOT_1.
	JMP @Key             ;si c'est égal on va à KEY.
NOT_1
	CMP #$32,a           ;on compare A avec $32 (code de la touche '2').
	JNE NOT_2            ;si ce n'est pas égal alors on va à NOT_2.
	JMP @Key             ;si c'est égal on va à KEY.
NOT_2
	CMP #$33,a           ;idem avec la touche '3'.
	JNE NOT_3
	JMP @Key
NOT_3
	CMP #$34,a           ;idem avec la touche '4'.
	JNE NotKey
	JMP @Key
NotKey
	JMP attkey           ;si cela ne correspond à aucune des touches prévus on reboucle.
Key
    STA @$c600
    POP A                ;on restitue l'état de A
    RETS

Code : Tout sélectionner

0003   C700             .ORG $C700
0004   C700 B8              PUSH A               ;on sauvegarde dans la pile l'état de A.
0005   C701             attkey
0006   C701 12 03       	MOV VALUE0,a         ;on récupére la valeur de la touche saisie ou pas.
0007   C703 72 04 03    	MOV #04,VALUE0       ;pour éviter une répétition de touches nous réinitialisons
0008   C706                                      ;  VALUE0 à $04 qui correspond à aucune action. 
0009   C706 2D 31       	CMP #$31,a           ;on compare A avec $31 (le code ASCII de la touche '1').
0010   C708 E6 02       	JNE NOT_1            ;si ce n'est pas égal alors on va à NOT_1.
0011   C70A E0 14       	JMP @Key             ;si c'est égal on va à KEY.
0012   C70C             NOT_1
0013   C70C 2D 32       	CMP #$32,a           ;on compare A avec $32 (code de la touche '2').
0014   C70E E6 02       	JNE NOT_2            ;si ce n'est pas égal alors on va à NOT_2.
0015   C710 E0 0E       	JMP @Key             ;si c'est égal on va à KEY.
0016   C712             NOT_2
0017   C712 2D 33       	CMP #$33,a           ;idem avec la touche '3'.
0018   C714 E6 02       	JNE NOT_3
0019   C716 E0 08       	JMP @Key
0020   C718             NOT_3
0021   C718 2D 34       	CMP #$34,a           ;idem avec la touche '4'.
0022   C71A E6 02       	JNE NotKey
0023   C71C E0 02       	JMP @Key
0024   C71E             NotKey
0025   C71E E0 E1       	JMP attkey           ;si cela ne correspond à aucune des touches prévus on reboucle.
0026   C720             Key
0027   C720 8B C6 00        STA @$c600
0028   C723 B9              POP A                ;on restitue l'état de A
0029   C724 0A              RETS
Ces code n'ont pas pour but d'être optimisés, mais dans un but d'apprentissage pour un débutant en assembleur

Les programmes ci dessus sont inclus dans l'archive LESSON2.ZIP
Je ne vous fourni pas de programme Basic, vous aurez vite adapter les précédents pour ceux la qui sont très simple ;)
Dans l'archive les sources et les binaires directement importable en $C700 dans l'émulateur ;)

Amusez vous bien :D

Je vais essayer d'être plus rapide pour la suite :roll:
Phil.

www.6502man.com

To bit or not to bit.
1 or 0.

Avatar du membre
kikich
Messages : 40
Enregistré le : 24 oct. 2016 23:19
Localisation : Aube

Re: [ EXELVISION ] initiation à l'assembleur pour TMS7020

Message par kikich » 26 avr. 2017 13:46

merci encore pour ce cour, je suis un peu occuper en ce moment pour me bien suivre et bien assimiler, mais dans quelque semaine j'y replonge .

Avatar du membre
6502man
Messages : 9073
Enregistré le : 12 avr. 2007 22:46
Localisation : VAR
Contact :

Re: [ EXELVISION ] initiation à l'assembleur pour TMS7020

Message par 6502man » 29 avr. 2017 16:01

Je me suis un peu dispersé avec le VG5000, mais je vais continuer ce cours d'ici peu ...
Phil.

www.6502man.com

To bit or not to bit.
1 or 0.

jasz
Messages : 455
Enregistré le : 05 oct. 2016 20:05
Localisation : Quelque part dans le 31

Re: [ EXELVISION ] initiation à l'assembleur pour TMS7020

Message par jasz » 30 avr. 2017 11:07

Très bonne idée ce cours d'asm sur Exel. Ca nous offre une vision sur cette machine très méconnue loin de celles (les machines) que nous fréquentons d'ordinaire.

On peut également se rendre compte que de simples opérations sur 16 bits (addition et soustraction) semblent très compliquées à faire (de prim abord). Je n'ose même pas imaginer la longueur du programme pour une division :?

J'ai cependant une question. Peut-on modifier l'adresse de la pile?

A ce propos
__sam__ a écrit :C'est marrant cette pile qui monte quand on push des trucs.. chez motorola (6809, 680x0) la pile descend quand on push (au niveau des adresses mémoire).
Tout dépend si l'on prend la partie haute ou la partie basse de la zone d'empilage. Sur 680x0, on utilise traditionnellement le registre d'adresse A7 comme pile qui se situe par le système à l'extrémité haute de la ram [d'ou -(A7) pour empiler]. Mais si on définie une zone quelconque dans la ram (LEA $1000.W,A7 par exemple) on peut empiler en incrémentant l'adresse ;)

Répondre