Partage
  • Partager sur Facebook
  • Partager sur Twitter

langage C et assembleur pour Z80 avec SDCC

programmer en C pour Amstrad CPC464

    16 février 2021 à 18:31:57

    Bonjour j'aimerai me créer une librairie personnelle en C pour mon amstrad (vieux ordi des années 80, processeur Z80)

    Suis donc obliger de faire des routines en langage machine pour utiliser les routines rom de ma machine.

    J'ai un soucis sur ma fonction plot qui doit me dessiner un point aux coordonnées x,y

    seulement LD DE,x et LD HL,y ecrit comme je l'ai fait suis pas bon  . Quel est la bonne syntaxe sachant que je dois mettre 

    DE <-- x

    HL <-- y

    merci pour vos reponses

    #include <stdio.h>
    #include <stdlib.h>
    
    
    void mode2(void)
    {
      __asm
        ld  a, #2
        call  #0xBC0E
      __endasm;
    	
    }
    
    
    void wait_char(void)
    {  
      __asm
        call #0xBB06
      __endasm;
    }
    
    void plot (unsigned int x, unsigned int y)
    {
    	__asm
    	  LD DE,x
    	  LD HL,y
    	  call #0xBBEA
    	 __endasm;
    }
    
    void main(void)
    {
    	mode2();
    	plot (100,100);
    	plot(200,200);
    	wait_char();
    }


    unsigned int x car 0<x<600

    unsigned int y car 0<y<400

    mes messages erreurs apres compilation avec SDCC



    -
    Edité par Dark-linux 16 février 2021 à 18:40:27

    • Partager sur Facebook
    • Partager sur Twitter
    http://sinclair.recreatedzxspectrum.com/index.php
      16 février 2021 à 18:42:41

      c'est pas un problème de jeux d'instructions, mais plutôt de syntaxe avec SDCC, merci quand même

      White Crow a écrit:

      Hello 

      tu as essayé une recherche google ???

      genre → https://fr.wikibooks.org/wiki/Programmation_Assembleur_Z80/Jeu_d_instructions#LD 



      • Partager sur Facebook
      • Partager sur Twitter
      http://sinclair.recreatedzxspectrum.com/index.php
        16 février 2021 à 18:52:34

        As-tu seulement un compilateur décent sur ton Z80? A-t-il une option pour montrer le code généré?
        En soi, les instructions me semblent correctes, mais ça dépend de l'environnement ou du contexte.
        Ça fait trop longtemps que je n'ai pas codé en assembleur Z80.
        Avec une RAM de 64Kb, ça ne doit pas êttre évident.
        • Partager sur Facebook
        • Partager sur Twitter

        Le Tout est souvent plus grand que la somme de ses parties.

          16 février 2021 à 18:53:48

          Avec un recherche google  sdcc z80 asm on trouve ça

          https://gist.github.com/Konamiman/af5645b9998c802753023cf1be8a2970

          Avec des exemples

          Getting function parameters

          Parameters for the function are pushed to the stack before the function is called. They are pushed from right to left, so the leftmost parameter is the first one found when going up in the stack:

          char SumTwoChars(char x, char y) __naked 
          {
           __asm
           ld iy,#2 add iy,sp ;Bypass the return address of the function ld l,(iy) ;x ld a,1(iy) ;y add l ld l,a ;return value ret __endasm; }

          -
          Edité par michelbillaud 16 février 2021 à 18:58:46

          • Partager sur Facebook
          • Partager sur Twitter
            16 février 2021 à 19:30:19

            Merci Michel pour la précision. Je me doutais que c'était ça.
            Mais je ne savais pas dans quel ordre les paramêtre seraient empilés.
            • Partager sur Facebook
            • Partager sur Twitter

            Le Tout est souvent plus grand que la somme de ses parties.

              16 février 2021 à 19:55:03

              C'est le genre de truc où on ne peut pas éviter de lire la doc, si on veut s'en servir.
              • Partager sur Facebook
              • Partager sur Twitter
                16 février 2021 à 20:02:42

                Merci pour vos réponses éclairées, sauf que la lumière ne s'est pas allumée dans mes  vieux neurones. 

                J'ai pas compris la manipulation pour pouvoir affecté dans mes registres mes variables x et y. 

                Si je pense a Ld  DE, x autrement dit DE prend la valeur contenue dans x

                et pour LD HL, y.... 

                La syntaxe serait : LD DE, iy et LD HL, 1(iy)

                Mon but est d'utiliser les vecteurs de la rom du cpc464 d'amstrad pour m'affranchir justement de coder en langage machine

                Ensuite pour vous répondre PierrotLeFou je compile à la main avec. Bat sous Windows. J'ai pas réussi à régler code::bloc. Je suis un tuto sur cpcmania sur le sujet. 

                Merci pour vos retours

                • Partager sur Facebook
                • Partager sur Twitter
                http://sinclair.recreatedzxspectrum.com/index.php
                  16 février 2021 à 20:31:58

                  Parmi ces trois propositions pour résoudre un problème, laquelle est la moins efficace ?

                  1. lire la doc

                  2. essayer soi-même

                  3. demander sur un forum à des gens qui n'y connaissent rien.

                  • Partager sur Facebook
                  • Partager sur Twitter
                    16 février 2021 à 20:53:47

                    michelbillaud a écrit:

                    Parmi ces trois propositions pour résoudre un problème, laquelle est la moins efficace ?

                    1. lire la doc

                    2. essayer soi-même

                    3. demander sur un forum à des gens qui n'y connaissent rien.


                    La moins efficace s'est certainement répondre à une question par une énigme. Si vous savez pas  je me passe de votre verbiage. Ou alors expliquez moi la sémantique de votre code postée. Merci
                    • Partager sur Facebook
                    • Partager sur Twitter
                    http://sinclair.recreatedzxspectrum.com/index.php
                      16 février 2021 à 20:58:47

                      michelbillaud a écrit:

                      Parmi ces trois propositions pour résoudre un problème, laquelle est la moins efficace ?

                      1. lire la doc

                      2. essayer soi-même

                      3. demander sur un forum à des gens qui n'y connaissent rien.


                      🤔demander à des gens qui n'y connaissent rien d'essayer après avoir lu la doc ? 🤪😅

                      Sinon sur le site susmentionné, il y a un bout de code :

                      ; FILE: putchar.s
                      ;; Modified to suit execution on the Amstrad CPC
                      ;; by H. Hansen 2003
                      ;; Original lines has been marked out!
                      
                        .area _CODE
                      _putchar::       
                      _putchar_rr_s:: 
                                ld      hl,#2
                                add     hl,sp
                              
                                ld      a,(hl)
                                call    0xBB5A
                                ret
                                 
                      _putchar_rr_dbs::
                      
                                ld      a,e
                                call    0xBB5A
                                ret

                      Et comme ça à vue de nez je dirais bien que :

                      • ld        hl,#2 : charge la valeur 2 dans le registre hl
                      • add     hl,sp : ajoute l'adresse de base de la pile (où doit se trouver le paramètre)
                      • ld        a,(hl) : charge le registre a avec la valeur pointée par hl, donc la valeur qui a été empilée sur la pile, donc le paramètre

                      → http://www.cpcmania.com/Docs/Programming/Introduction_to_programming_in_SDCC_Compiling_and_testing_a_Hello_World.htm 

                      • Partager sur Facebook
                      • Partager sur Twitter
                        16 février 2021 à 21:44:35

                        Oui mais non, ça c'est du langage d'assemblage, et le monsieur il veut intégrer des instructions dans du C compilé par sdcc. Pas forcément une bonne idée, mais bon.

                        Il y a des chances que les syntaxes des instructions différent dans les deux cas. Si le monsieur voulait bien se donner la peine de regarder les liens qu'on lui donne (et qu'on s'emmerde a chercher pour lui...) au lieu de rochonner, il trouverait certainement  des exemples.

                        Spoiler : on y trouve des "ld hl,..."

                        Ps : un call suivi d'un ret, ça se remplace avantageusement  par un jmp, dans mes lointains souvenirs (Le JRST hack du pdp 11 !)

                        -
                        Edité par michelbillaud 16 février 2021 à 21:52:51

                        • Partager sur Facebook
                        • Partager sur Twitter
                          17 février 2021 à 2:05:01

                          michelbillaud a écrit:

                          Ps : un call suivi d'un ret, ça se remplace avantageusement  par un jmp, dans mes lointains souvenirs (Le JRST hack du pdp 11 !)

                          Je ne te suis pas trop dans ton raisonnement: le call va exécuter un sous programme, puis le ret va sortir du sous-programme courant. En quoi un jmp pourrait-il remplacer cette séquence?

                          • Partager sur Facebook
                          • Partager sur Twitter
                            17 février 2021 à 2:13:20

                            Je pense que la syntaxe de la plupart des assembleurs Z80 doit êttre pratiquement identique.
                            Je suis peut-être lemt à comprendre, mais que vient faire un script .bat et Code::Block sur Windows?
                            À moins d'avoir un cross-compiler pour le Z80, on est dans le champs.
                            J'ai déjà vu des compilateurs Fortran sur un Z80, mais pas de C.
                            Moi, j'utilisais un cross-assembler et il y avait un loader dans le résident du Z80.
                            Il faut absolument passer par la pile quand on appelle une fonction. Il n'y a pas de symbole généré pour les variables X et Y parce que ce sont des paramètres.
                            • Partager sur Facebook
                            • Partager sur Twitter

                            Le Tout est souvent plus grand que la somme de ses parties.

                              17 février 2021 à 5:02:59

                              Je code malheuresement en Z80 (oui je n'aime pas cet assembleur)

                              Effectivement LD DE,x et LD HL,y n'existe pas , c'est simple dans ton cas x et y sont des variables , donc il faudrait écrire :
                              LD DE,(x) et LD HL,(y)

                              C'est simple :
                              sans parenthèse => valeur immédiate
                              avec parenthèse => valeur indirect (adresse)

                              Mais les variable sstocké en argument de fonction ne sont pas forcément stocké en RAM avec une mémoire fixe , mais sur la pile ,il faut sûrement regardé les call conventions de ton compilo (soit il push les arguments , soit certain registres sont dédié).

                              PS: avant de faire de l'asm du z80 faudrait effectivement lire une doc dessus :p

                              -
                              Edité par HelbaSama 17 février 2021 à 5:08:58

                              • Partager sur Facebook
                              • Partager sur Twitter
                                17 février 2021 à 6:54:31

                                @HelbaSama:
                                Utilises-tu un compilateur C sur un Z80?
                                Si on pouvait voir le code généré, on aurait la réponse.
                                Mais je pens que c'est comme michelbillaud l'a expliqué.
                                • Partager sur Facebook
                                • Partager sur Twitter

                                Le Tout est souvent plus grand que la somme de ses parties.

                                  17 février 2021 à 12:49:22

                                  zoup a écrit:

                                  michelbillaud a écrit:

                                  Ps : un call suivi d'un ret, ça se remplace avantageusement  par un jmp, dans mes lointains souvenirs (Le JRST hack du pdp 11 !)

                                  Je ne te suis pas trop dans ton raisonnement: le call va exécuter un sous programme, puis le ret va sortir du sous-programme courant. En quoi un jmp pourrait-il remplacer cette séquence?


                                  Bon, imaginons que la fonction foo ci-dessous soit appelée quelque part dans le code

                                  foo:
                                       ... 
                                       call bar          ; 1
                                       ret               ; 2
                                  
                                  • au moment de faire le call, dans la pile on a l'adresse à laquelle foo devra retourner.
                                  • le  "call bar" empile l'adresse de l'instruction ret (2)
                                  • la fonction bar contient normalement une instruction ret qui depilera et fera retourner à cette adresse
                                  • puis le ret de foo dépilera l'adresse de retour et fera revenir à l'appelant de foo.
                                  Maintenant si on fait
                                  foo:
                                      ...
                                      jmp bar
                                  • le jmp n'empile rien
                                  • on va exécuter le code de bar
                                  • le ret de bar dépile l'adresse de retour et s'y branche.
                                  Economies
                                  • code plus court (call + ret / jmp), prend moins de place
                                  • plus rapide
                                  • ne prend pas de place dans la pile.

                                  -
                                  Edité par michelbillaud 17 février 2021 à 12:50:34

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    17 février 2021 à 13:51:30

                                    michelbillaud a écrit:


                                    Bon, imaginons que la fonction foo ci-dessous soit appelée quelque part dans le code

                                    foo:
                                         ... 
                                         call bar          ; 1
                                         ret               ; 2
                                    
                                    • au moment de faire le call, dans la pile on a l'adresse à laquelle foo devra retourner.
                                    • le  "call bar" empile l'adresse de l'instruction ret (2)
                                    • la fonction bar contient normalement une instruction ret qui depilera et fera retourner à cette adresse
                                    • puis le ret de foo dépilera l'adresse de retour et fera revenir à l'appelant de foo.
                                    Maintenant si on fait
                                    foo:
                                        ...
                                        jmp bar
                                    • le jmp n'empile rien
                                    • on va exécuter le code de bar
                                    • le ret de bar dépile l'adresse de retour et s'y branche.
                                    Economies
                                    • code plus court (call + ret / jmp), prend moins de place
                                    • plus rapide
                                    • ne prend pas de place dans la pile.

                                    -
                                    Edité par michelbillaud il y a environ 1 heure

                                    Merci pour cet éclairage. Je n'y avais jamais pensé.

                                    PierrotLeFou a écrit:

                                    Je pense que la syntaxe de la plupart des assembleurs Z80 doit être pratiquement identique.

                                    Celle du langage d'assemblage oui, celle propre à l'assembleur (les directives par exemple), c'est pas sûr.

                                    PierrotLeFou a écrit:

                                    J'ai déjà vu des compilateurs Fortran sur un Z80, mais pas de C.

                                    Si tu retrouves un vieil APPLE II avec sa carte Z80 ainsi que TURBO C, ça peut le faire ;) (nostalgie)

                                    -
                                    Edité par zoup 17 février 2021 à 13:52:20

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      17 février 2021 à 13:57:39

                                      PierrotLeFou a écrit:

                                      @HelbaSama:
                                      Utilises-tu un compilateur C sur un Z80?
                                      Si on pouvait voir le code généré, on aurait la réponse.
                                      Mais je pens que c'est comme michelbillaud l'a expliqué.


                                      Non je code en full asm pour le Z80 , donc aucune idée de ce que fait le compilo (et puis ça dépend des compilo aussi , pas tous respecte les mêmes conventions).
                                      Le Z80 et le 6502 sont les rares processeurs où les compilateurs C sont assez mauvais et que programmer à la main est bien plus rapide , mais c'est un peu normal , à l'époque on pensait pas forcément faciliter les langages de haut niveau :)

                                      Pour l'optimisation du call/ret / jmp  , cet opti marche que sur des cas particulier (faut qu'il y'a pas de code après le jmp)  , en général , si on y va en asm ce cas là il arrive rarement :D
                                      En général quand on fait une boucle , on fait comme les compilo C , on inline et on déplie la boucle :D

                                      Techniquement sur le Z80 faut éviter l'utilisation de ix/iy (qui va souvent à plus de 20 cycles ) ,c'est les plus gourmand en cycle et privilégier hl (7-10 cycles)
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        17 février 2021 à 14:12:52

                                        HelbaSama a écrit:


                                        Pour l'optimisation du call/ret / jmp  , cet opti marche que sur des cas particulier (faut qu'il y'a pas de code après le jmp)  , en général , si on y va en asm ce cas là il arrive rarement :D

                                        En effet, ça marche pour un appel _terminal_ seulement, quand un call est suivi d'un ret (c'est bien indiqué !)

                                        Mais de là à dire que c'est rare : c'est le cas pour les 3 fonctions présentées dans le message d'origine. Et probablement pour quasiment toutes les fonctions qu'il veut écrire qui sont des "wrappers" compatibles avec C pour les fonctions de la ROM.

                                        Dans le cas où la fonction C ne contient qu'un call

                                        void wait_char(void)
                                        { 
                                          __asm
                                            call #0xBB06
                                          __endasm;
                                        }

                                        il y a probablement mieux à faire : déclarer wait_char comme un symbole dont la valeur est 0xBB06. En assembleur probablement, ne me demandez pas comment. Comme ça l'appel de wait_char ira directement au bon endroit.




                                        -
                                        Edité par michelbillaud 17 février 2021 à 14:13:34

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          17 février 2021 à 18:07:13

                                          merci les enfants pour vos conseils, papy n'a rien compris a vos gesticulations intellectuelles. Bon sinon , si quelqu'un a une idée simple à mon problème cité au dessus, suis preneur......

                                          Effectivement faire du C sur des bécanes avec 64 K de mémoire - 16 Ko de rom , il y a mieux.

                                          Ceci dit SDCC est un des mieux optimisé pour la circonstance. Mon code posté au dessus je note , n'est pas académique, j'ai juste fait une transcription avec ce que je connais en langage machine sur le bestiau.

                                          Après avoir lu le R.T.F.M. 130 pages sur SDCC , un paquet de tuto sur le sujet pour compiler à la main et avoir une disquette exécutable pour mon cpc464,

                                          je coince sur mon problème. qui est de pouvoir me creer une fonction avec des parametres en entrée et les utiliser dans mon code machine

                                          Merci de votre patience

                                          -
                                          Edité par Dark-linux 17 février 2021 à 18:11:31

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                          http://sinclair.recreatedzxspectrum.com/index.php
                                            17 février 2021 à 21:16:08

                                            Dark-linux a écrit:

                                            merci les enfants pour vos conseils, papy n'a rien compris a vos gesticulations intellectuelles. Bon sinon , si quelqu'un a une idée simple à mon problème cité au dessus, suis preneur......

                                            Ouaw ça donne pas envie de t'aidersi tu ne lis pas les réponses , mais je répète pour ma part :
                                            1) ce n 'est pas comme ça qu'on lit en RAM
                                            2) il faut respecter les calls conventions
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              18 février 2021 à 8:04:01

                                              Dark-linux a écrit:

                                              Après avoir lu le R.T.F.M. 130 pages sur SDCC , un paquet de tuto sur le sujet pour compiler à la main et avoir une disquette exécutable pour mon cpc464,

                                              je coince sur mon problème. qui est de pouvoir me creer une fonction avec des parametres en entrée et les utiliser dans mon code machine

                                              Merci de votre patience

                                              -
                                              Edité par Dark-linux il y a environ 13 heures

                                              Tu coinceras  sans doute moins en partant des exemples qui ont été indiqués. Il suffit pas de prétendre avoir lu la doc, il faut l'appliquer 

                                              Fais nous voir tout ce que tu as essayé, avec les messages d'erreur. On pourra peut être voir ce qui ne va pas dans ce que tu as ecrit. Et ce que tu as oublié d'essayer.

                                              De notre côté, on n'a pas forcément d'amstrad pour jouer avec, donc la motivation pour installer tout le bordel et apprendre à sans servir juste pour dépanner quelqu'un en lui donnant des solutions verifiées, c'est assez limité.

                                              @pierrot les compilateurs C qui tournent sur z80, y en a plein    google c compiler cp/m

                                              ---

                                              Bon

                                              1. Installé sdcc sous linux (debian)

                                              2. copié le source dans un fichier a.c

                                              3. trouvé comment on compile pour z80. Rédaction d'un Makefile

                                              all : a.ihx
                                              
                                              %.ihx : %.c
                                              	sdcc -mz80 $^
                                              

                                              4. Coup d'oeil a la doc. Annotation "__naked" indique de générer du code sans prelude ni postlude (le ret). Je préfère déclarer au compilateur que c'est moi qui prends les manettes de A à Z dans la fonction. Je mettrai un "ret" SI J'EN AI ENVIE, c'est pas ses oignons.

                                              void mode2(void) __naked
                                              {
                                                __asm
                                                  ld  a, #2
                                                  call  #0xBC0E
                                                  ret
                                                __endasm;
                                                   
                                              }
                                               


                                              5. Lecture des exemples : ils indiquent précisément comment récupérer les paramètres sur la pile. Ils sont stockés successivement dans la pile, 2 octets pour un int, à partir de l'offset 0. Utilisation de iy pour les récupérer

                                              Correction des deux LD

                                              	;    LD DE,x
                                              	ld d,0(iy)  ;x (low)
                                              	ld e,1(iy)  ;x (high)
                                              
                                              	; LD HL,y
                                              	ld h,2(iy)  ;y (low)
                                              	ld l,3(iy)  ;y (high)



                                              sous réserve que je ne sois pas planté dans l'ordre des registres (big endian etc).


                                              6.  Remplacement de l'appel (call) par un saut.

                                              Vu que je ne connais pas le Z80, et que mes souvenirs de 8085 remontent aux années 80, un coup d'oeil pour trouver que c'est l'instruction JP (pas jump)

                                              Apparemment, il faut enlever le  # devant l'adresse numérique

                                              void wait_char(void)  __naked
                                              { 
                                                __asm
                                                  jp 0xBB06
                                                __endasm;
                                              }

                                              7 Code final

                                              #include <stdio.h>
                                               
                                              void mode2(void) __naked
                                              {
                                                __asm
                                                  ld  a, #2
                                                  jp  0xBC0E
                                                __endasm;
                                              }
                                                
                                              void wait_char(void)  __naked
                                              { 
                                                __asm
                                                  jp 0xBB06
                                                __endasm;
                                              }
                                               
                                              void plot (unsigned int x , unsigned int y) __naked
                                              {
                                              	(void) x;   // pour éviter les messages
                                              	(void) y;   // sur les paramètres non utilisés
                                                  __asm
                                              		ld d,0(iy)  ;x (low)
                                              		ld e,1(iy)  ;x (high)
                                              
                                              		ld h,2(iy)  ;y (low)
                                              		ld l,3(iy)  ;y (high)
                                               
                                              		jp 0xBBEA
                                                   __endasm;
                                              }
                                               
                                              void main(void)
                                              {
                                                  mode2();
                                                  plot(100,100);
                                                  plot(200,200);
                                                  wait_char();
                                              }
                                              

                                              8. Le fichier lst généré, pour vérifier (par exemple que le (void) x ne fabrique pas d'instructions).

                                                                            1 ;--------------------------------------------------------
                                                                            2 ; File Created by SDCC : free open source ANSI-C Compiler
                                                                            3 ; Version 3.8.0 #10562 (Linux)
                                                                            4 ;--------------------------------------------------------
                                                                            5 	.module a
                                                                            6 	.optsdcc -mz80
                                                                            7 	
                                                                            8 ;--------------------------------------------------------
                                                                            9 ; Public variables in this module
                                                                           10 ;--------------------------------------------------------
                                                                           11 	.globl _main
                                                                           12 	.globl _plot
                                                                           13 	.globl _wait_char
                                                                           14 	.globl _mode2
                                                                           15 ;--------------------------------------------------------
                                                                           16 ; special function registers
                                                                           17 ;--------------------------------------------------------
                                                                           18 ;--------------------------------------------------------
                                                                           19 ; ram data
                                                                           20 ;--------------------------------------------------------
                                                                           21 	.area _DATA
                                                                           22 ;--------------------------------------------------------
                                                                           23 ; ram data
                                                                           24 ;--------------------------------------------------------
                                                                           25 	.area _INITIALIZED
                                                                           26 ;--------------------------------------------------------
                                                                           27 ; absolute external ram data
                                                                           28 ;--------------------------------------------------------
                                                                           29 	.area _DABS (ABS)
                                                                           30 ;--------------------------------------------------------
                                                                           31 ; global & static initialisations
                                                                           32 ;--------------------------------------------------------
                                                                           33 	.area _HOME
                                                                           34 	.area _GSINIT
                                                                           35 	.area _GSFINAL
                                                                           36 	.area _GSINIT
                                                                           37 ;--------------------------------------------------------
                                                                           38 ; Home
                                                                           39 ;--------------------------------------------------------
                                                                           40 	.area _HOME
                                                                           41 	.area _HOME
                                                                           42 ;--------------------------------------------------------
                                                                           43 ; code
                                                                           44 ;--------------------------------------------------------
                                                                           45 	.area _CODE
                                                                           46 ;a.c:3: void mode2(void) __naked
                                                                           47 ;	---------------------------------
                                                                           48 ; Function mode2
                                                                           49 ; ---------------------------------
                                                 0000                      50 _mode2::
                                                                           51 ;a.c:8: __endasm;
                                                 0000 3E 02         [ 7]   52 	ld	a, #2
                                                 0002 C3 0E BC      [10]   53 	jp	0xBC0E
                                                                           54 ;a.c:9: }
                                                                           55 ;a.c:11: void wait_char(void)  __naked
                                                                           56 ;	---------------------------------
                                                                           57 ; Function wait_char
                                                                           58 ; ---------------------------------
                                                 0005                      59 _wait_char::
                                                                           60 ;a.c:15: __endasm;
                                                 0005 C3 06 BB      [10]   61 	jp	0xBB06
                                                                           62 ;a.c:16: }
                                                                           63 ;a.c:18: void plot (unsigned int x , unsigned int y) __naked
                                                                           64 ;	---------------------------------
                                                                           65 ; Function plot
                                                                           66 ; ---------------------------------
                                                 0008                      67 _plot::
                                                                           68 ;a.c:30: __endasm;
                                                 0008 FD 56 00      [19]   69 	ld	d,0(iy) ;x (low)
                                                 000B FD 5E 01      [19]   70 	ld	e,1(iy) ;x (high)
                                                 000E FD 66 02      [19]   71 	ld	h,2(iy) ;y (low)
                                                 0011 FD 6E 03      [19]   72 	ld	l,3(iy) ;y (high)
                                                 0014 C3 EA BB      [10]   73 	jp	0xBBEA
                                                                           74 ;a.c:31: }
                                                                           75 ;a.c:33: void main(void)
                                                                           76 ;	---------------------------------
                                                                           77 ; Function main
                                                                           78 ; ---------------------------------
                                                 0017                      79 _main::
                                                                           80 ;a.c:35: mode2();
                                                 0017 CDr00r00      [17]   81 	call	_mode2
                                                                           82 ;a.c:36: plot(100,100);
                                                 001A 21 64 00      [10]   83 	ld	hl, #0x0064
                                                 001D E5            [11]   84 	push	hl
                                                 001E 2E 64         [ 7]   85 	ld	l, #0x64
                                                 0020 E5            [11]   86 	push	hl
                                                 0021 CDr08r00      [17]   87 	call	_plot
                                                 0024 F1            [10]   88 	pop	af
                                                 0025 F1            [10]   89 	pop	af
                                                                           90 ;a.c:37: plot(200,200);
                                                 0026 21 C8 00      [10]   91 	ld	hl, #0x00c8
                                                 0029 E5            [11]   92 	push	hl
                                                 002A 2E C8         [ 7]   93 	ld	l, #0xc8
                                                 002C E5            [11]   94 	push	hl
                                                 002D CDr08r00      [17]   95 	call	_plot
                                                 0030 F1            [10]   96 	pop	af
                                                 0031 F1            [10]   97 	pop	af
                                                                           98 ;a.c:38: wait_char();
                                                                           99 ;a.c:39: }
                                                 0032 C3r05r00      [10]  100 	jp  _wait_char
                                                                          101 	.area _CODE
                                                                          102 	.area _INITIALIZER
                                                                          103 	.area _CABS (ABS)
                                              


                                              9. Remarque la ligne 10 : le compilateur a lui aussi remplacé   call _wait_char + ret  par jp_wait_char.

                                              10 verif : ligne 73  l'instruction de saut "jp 0xBBEA" a bien l'air d'avoir été traduite correctement en  C3 EA BB.

                                              http://map.grauw.nl/resources/z80instr.php


                                              Total, 1h de boulot, dont rédaction. 

                                              Reste un problème, à quel nom je fais la facture de 150 € HT ?

                                              PS: pour un modeste supplément, si on définit wait_char sous forme de macro

                                              #define wait_char ((void (*)(void)) 0xBB06)


                                              l'appel terminal  wait_char();   génère un simple   jp 0xBB06.


                                              J'aurais préféré un truc du genre

                                              void mafonction ()  =  0x1234;
                                              

                                              mais j'ai pas eu le courage de chercher dans la doc si ça existait.




                                              -
                                              Edité par michelbillaud 18 février 2021 à 12:56:19

                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                18 février 2021 à 14:44:11

                                                Eh ben bravo :)

                                                "Apparemment, il faut enlever le  # devant l'adresse numérique"
                                                effectivement les valeurs immediate sans sans parenthèse (donc pas de #)
                                                le # est pour le 6502 ou le M68000 , mais je pensais que c'était son compilo qui demandais ce '#' , au moins tu confirme que ce n'est pas le cas ;)
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  18 février 2021 à 15:16:11

                                                  Ce que je confirme, c'est que ca passe à la compilation si on l'enlève, et pas si on le laisse, contrairement à call. Après, faut essayer pour valider.

                                                  J'ai pas envie de chercher une confirmation dans les docs pour un truc qui ne me servira probablement jamais.

                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    18 février 2021 à 16:46:15

                                                    Bonjour les jeunes,

                                                    désolé si j'ai froissé c'était pas le but ! Je part du fond de l'abîme de la méconnaissance et je fais avec les neurones qui me restent et suis pas programmeur de métier....bon je rentre du boulot et voulait vous poster ou j'en étais avec mes turlupetudes intellectuelles....

                                                    d'abord mon fichier compil.bat qui me sert a compiler et linker sur mon z80 avec les specificités de l'amstrad.... lignes 3 et 4 

                                                    ligne5 ma compilation pour faire démarrer mon code à 138 hexa sinon ca crache à l'éxecution...

                                                    et le linkage ligne suivante

                                                    la derniere ligne pour creer une disquette virtuelle pour essayer sur mon émulateur Caprice.

                                                    @echo off
                                                    set path=%path%;\sdcc\bin
                                                    sdasz80 -o crt0_cpc.s
                                                    sdasz80 -o putchar_cpc.s
                                                    sdcc -mz80 --code-loc 0x0138 --data-loc 0 --no-std-crt0 crt0_cpc.rel putchar_cpc.rel projet.c
                                                    hex2bin projet.ihx
                                                    CPCDiskXP -File projet.bin -AddAmsdosHeader 100 -AddToNewDsk result.dsk
                                                    pause

                                                    j'ai corrigé un peu mon code car j'ai compris que mes x et y en fait sont stockés sur la pile et qu'il faut les récuperer sur la pile dans le bon ordre

                                                    et pour faire cela j'ai modifié comme suit sans forcement bien comprendre dans les détails, rajouté __naked à ma déclaration de fonction pour éviter un "retour intempestif ?"

                                                    bref :

                                                    #include <stdio.h>
                                                    #include <stdlib.h>
                                                    
                                                    #define KM_WAIT_CHAR_s \
                                                    	__asm \
                                                    	call #0xBB06 \
                                                    	__endasm
                                                    
                                                    #define  SCR_SET_MODE1_s \
                                                    	__asm	ld a,#1 \
                                                    	call #0xBC0E \
                                                    	__endasm;
                                                    
                                                    void mode2(void)
                                                    {
                                                      __asm
                                                        ld  a, #2
                                                        call  #0xBC0E
                                                      __endasm;
                                                    	
                                                    }
                                                    
                                                    
                                                    void wait_char(void)
                                                    {  
                                                      __asm
                                                        call #0xBB06
                                                      __endasm;
                                                    }
                                                    
                                                    void plot (unsigned int x, unsigned int y)__naked
                                                    {
                                                    	__asm
                                                    	  LD DE,iy
                                                    	  LD HL,1(iy)
                                                    	  call #0xBBEA
                                                    	 __endasm;
                                                    }
                                                    
                                                    void main(void)
                                                    {
                                                    	mode2();
                                                    	plot (100,100);
                                                    	plot(200,200);
                                                    	wait_char();
                                                    }

                                                    la compilation et bien sûr les erreurs .....

                                                    bon maintenent je vais regarder tous vos commentaires essayer de comprendre mes erreurs, refaire des tests , et je reviendrai vers vous pour faire le point......

                                                    Mais il me faut du temps , suis long à la détente et pour moi c'est un passe temps

                                                    Merci pour toutes vos remarques constructives @+

                                                    nota bene : celui qui a passé 1h à chercher sur son temps libre (michelbillaud) , laissez moi votre adresse en PV, dans le sud ouest on fabrique du foie gras ...

                                                    -
                                                    Edité par Dark-linux 18 février 2021 à 16:51:21

                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                    http://sinclair.recreatedzxspectrum.com/index.php
                                                      18 février 2021 à 17:17:17

                                                      Si tu mets __naked à la fonction plot qui se termine par un call, , c'est à toi de mettre un ret à la fin.

                                                      Pour les erreurs sur LD, je t'ai donné la solution. Si tu ne veux pas la lire, pourquoi tu poses des questions ?

                                                      -
                                                      Edité par michelbillaud 18 février 2021 à 17:21:01

                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        23 février 2021 à 17:28:22

                                                        bonjour,

                                                        Merci pour vos réponses , bon pour l'instant j'ai pas de question subsidiaire sur le sujet, je vous mets un exemple de code que j'ai réalise (sauf la fonction de traçage de ligne et de cercle que j'ai honteusement copié sur le net). Histoire de remercier ceux qui m'ont aider.....

                                                        Si vous avez des remarques je prends, histoire de m'améliorer  . Merci

                                                        A l'exécution sur mon CPC j'ai un traçage de rectangle et de cercle comme je le souhaitais.

                                                        #include <stdio.h>
                                                        
                                                        
                                                        #define WAIT_CHAR \
                                                        	__asm \
                                                        	call #0xBB06 \
                                                        	__endasm;
                                                        	
                                                        #define CLS \
                                                        	__asm \
                                                        	call #0xBBDB\
                                                        	__endasm;
                                                        	
                                                        #define  SET_MODE1 \
                                                        	__asm	ld a,#1 \
                                                        	call #0xBC0E \
                                                        	__endasm;
                                                        
                                                        #define  SET_MODE2 \
                                                        	__asm	ld a,#2 \
                                                        	call #0xBC0E \
                                                        	__endasm;
                                                        
                                                        typedef unsigned int mot;
                                                        typedef unsigned char octet;
                                                        
                                                        void PutPixelMode1(mot nX, mot nY, octet nColor)
                                                        {
                                                          mot nPixel = nX % 4;
                                                          unsigned char *pAddress = (octet *)((mot)(0xC000 + ((nY / 8) * 80) + ((nY % 8) * 2048) + (nX / 4)));
                                                          switch (nPixel)
                                                          {
                                                        	  case 0 :
                                                        	  {	
                                                        	    *pAddress &= 119;
                                                        		if(nColor & 1)  *pAddress |= 128;
                                                        		if(nColor & 2)  *pAddress |= 8;
                                                        	  break;
                                                        	  }
                                                        	  
                                                        	  case 1:
                                                        	  {
                                                        		*pAddress &= 187;
                                                        		if(nColor & 1)  *pAddress |= 64;
                                                        		if(nColor & 2)  *pAddress |= 4;
                                                        		break;
                                                        	  }
                                                        	  
                                                        	  case 2:
                                                        	  {
                                                        		*pAddress &= 221;
                                                        		if(nColor & 1)  *pAddress |= 32;
                                                        		if(nColor & 2)  *pAddress |= 2;
                                                        		break;
                                                        	  }
                                                        	  
                                                        	  case 3:
                                                        	  {
                                                        		*pAddress &= 238;
                                                        		if(nColor & 1)  *pAddress |= 16;
                                                        		if(nColor & 2)  *pAddress |= 1;
                                                        		break;
                                                        	  }
                                                          }
                                                           
                                                        }
                                                        
                                                        void lineBresenham(mot x1,mot y1,mot x2,mot y2, octet nColor)
                                                        {
                                                            int cx, cy,
                                                                ix, iy,
                                                                dx, dy, 
                                                                ddx= x2-x1, ddy= y2-y1;
                                                             
                                                            if (!ddx) { //vertical line special case
                                                                if (ddy > 0) {
                                                                    cy= y1;  
                                                                    do PutPixelMode1(x1, cy++, nColor);
                                                                    while (cy <= y2);
                                                                    return;
                                                                } else {
                                                                    cy= y2;
                                                                    do PutPixelMode1(x1, cy++, nColor);
                                                                    while (cy <= y1);
                                                                    return;
                                                                }
                                                            }
                                                            if (!ddy) { //horizontal line special case
                                                                if (ddx > 0) {
                                                                    cx= x1;
                                                                    do PutPixelMode1(cx, y1, nColor);
                                                                    while (++cx <= x2);
                                                                    return;
                                                                } else {
                                                                    cx= x2; 
                                                                    do PutPixelMode1(cx, y1, nColor);
                                                                    while (++cx <= x1);
                                                                    return;
                                                                }
                                                            }
                                                            if (ddy < 0) { iy= -1; ddy= -ddy; }//pointing up
                                                                    else iy= 1;
                                                            if (ddx < 0) { ix= -1; ddx= -ddx; }//pointing left
                                                                    else ix= 1;
                                                            dx= dy= ddx*ddy;
                                                            cy= y1, cx= x1; 
                                                            if (ddx < ddy) { // < 45 degrees, a tall line    
                                                                do {
                                                                    dx-=ddy;
                                                                    do {
                                                                        PutPixelMode1(cx, cy, nColor);
                                                                        cy+=iy, dy-=ddx;
                                                                    } while (dy >=dx);
                                                                    cx+=ix;
                                                                } while (dx > 0);
                                                            } else { // >= 45 degrees, a wide line
                                                                do {
                                                                    dy-=ddx;
                                                                    do {
                                                                        PutPixelMode1(cx, cy, nColor);
                                                                        cx+=ix, dx-=ddy;
                                                                    } while (dx >=dy);
                                                                    cy+=iy;
                                                                } while (dy > 0);
                                                            }
                                                        }
                                                        
                                                        void Cercle(mot rayon, mot x_centre, mot y_centre, octet nColor)
                                                        {
                                                        	int x =0;
                                                        	unsigned char y = rayon;
                                                        	int d = rayon - 1;
                                                        	while ( y >= x )
                                                        	{
                                                        		PutPixelMode1( x+x_centre, y+y_centre, nColor );
                                                        		PutPixelMode1( y+x_centre, x+y_centre, nColor );
                                                        		PutPixelMode1( -x+x_centre, y+y_centre, nColor );
                                                        		PutPixelMode1( -y+x_centre, x+y_centre, nColor );
                                                        		PutPixelMode1( x+x_centre, -y+y_centre, nColor );
                                                        		PutPixelMode1( y+x_centre, -x+y_centre, nColor );
                                                        		PutPixelMode1( -x+x_centre, -y+y_centre, nColor );
                                                        		PutPixelMode1( -y+x_centre, -x+y_centre, nColor );
                                                        		if ( d >= 2*(x-1) )
                                                        		{
                                                        			d = d - (2*x);
                                                        			x = x + 1;
                                                        		}
                                                        		else if ( d <= 2*(x-y) )
                                                        		{
                                                        			d = d + (2*y) - 1;
                                                        			y = y-1;
                                                        		}
                                                        		else
                                                        		{
                                                        			d = d + 2*(y-x-1);
                                                        			y = y-1;
                                                        			x = x+1;
                                                        		}
                                                        	}
                                                        
                                                        }
                                                        
                                                        
                                                        void main(void)
                                                        {
                                                            int i;
                                                        	SET_MODE1;
                                                            
                                                            for(i=0; i<25; i++)
                                                            {
                                                                lineBresenham(108+i,48+i, 211+i,48+i,i%4);
                                                                lineBresenham(211+i,48+i, 211+i,151+i,i%4);
                                                                lineBresenham(211+i,151+i, 108+i,151+i,i%4);
                                                                lineBresenham(108+i,151+i, 108+i,48+i,i%4);
                                                               
                                                                // trace ligne oblique
                                                                lineBresenham(108+i,48+i, 211+i,151+i,i%4);
                                                                lineBresenham(211+i,151+i, 108+i,48+i,i%4);
                                                            }
                                                        	WAIT_CHAR;
                                                        	CLS;
                                                        	
                                                        	for (i=0; i< 50; i++)
                                                        	{
                                                        		Cercle(30+i, 160, 100, i%4);
                                                        	}
                                                        	WAIT_CHAR;
                                                        		
                                                        }
                                                        

                                                        -
                                                        Edité par Dark-linux 23 février 2021 à 17:31:08

                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                        http://sinclair.recreatedzxspectrum.com/index.php
                                                          24 février 2021 à 21:00:23

                                                          Salut,

                                                          Moi j'aime beaucoup les anciens codages sur les anciennes machines, et je suis en train d'éplucher ta fonction PutPixelMode1 avec attention.

                                                          Je suis allé me documenter, et j'ai vu qu'effectivement l'adresse de l'écran commence a 0xC000

                                                          Je suis d'ailleurs surpris de voir, dans ta formule ligne 30 que les lignes de pixels ne se suivent pas en mémoire !

                                                          Chaque ligne fait 80 octets et se suit, ok.

                                                          ligne 0 commence a 0 ( a partir de 0xC000), ligne 1 a 2048, ligne 2 a 4096 .... ligne 8 commence a 80, ligne 9 a 80 +2048, tout est entrelacé.

                                                          Ensuite j'ai vu aussi en ligne qu'effectivement les 2 bits utilisés par la couleur ne se suivent pas, d'ou les &= et les | dans ton code.

                                                          Après, je trouve ta fonction putpixel très calculatoire, pour un seul pixel. Tes algos de Bresenham ne seront pas très rapides sur un Amstrad, car pour chaque pixel, tu recalcules tout, et pire, tu switch (un branchement est souvent plus lent qu'un autre calcul direct). Mais ça doit marcher, et l'optimisation viendra après.

                                                          J'aime beaucoup les vieux modes graphiques. J'ai bossé pas mal sur le mode 13h sous DOS à l'époque : pareil on écrivrait directement en mémoire (adresse virtuelle 0xA000000). J'adore l'encodage graphique de la NES, la façon maline de faire des couleurs sous le ZXSpectrum, tout ça.

                                                          Et j'ai fait une lib légère (que Windows par contre) qui permet aussi d'afficher des pixels via un tableau, pour ceux qui aiment le "from scatch" (même si dans les fait, c'est une surcouche a la Winapi)

                                                          En tout cas, merci pour ton code qui m'a bien instruit sur la façon de coder le graphisme sur l'Amstrad !

                                                          EDIT, je mets cet excellent lien qui montre un remplissage, dans quel sens c'est rempli :

                                                          http://www.cpcmania.com/Docs/Programming/Painting_pixels_introduction_to_video_memory.htm

                                                          Sur cette page, il y a un GIF animé qui montre le remplissage progressif

                                                          -
                                                          Edité par Fvirtman 24 février 2021 à 21:40:46

                                                          • Partager sur Facebook
                                                          • Partager sur Twitter

                                                          Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                                                          langage C et assembleur pour Z80 avec SDCC

                                                          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                          • Editeur
                                                          • Markdown