MSX Village forum

La Place des Développeurs Coder en C avec SDCC

ericb59 Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : compte ++ Groupe : Shoutbox

Inscrit le : 17/04/2012 à 10h25

Messages: 5464

Le 15/12/2020 à 20h02
Topic général sur SDCC...
Questions, problèmes, astuces, codes, routines en tout genre... Ici on prend tout !
A vot' bon coeur m'sieur dames Edité par ericb59 Le 15/12/2020 à 20h36


banniere-ericb59e
Site web    
ericb59 Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : compte ++ Groupe : Shoutbox

Inscrit le : 17/04/2012 à 10h25

Messages: 5464

Le 22/12/2020 à 15h17
@aoineko :
Je vois dans ta lib, que tu ajoute __FASCALL sur tes fonctions C, pourtant elle ne contiennent pas de code ASM pour autant.
- Quel est donc ce maléfice ?
D'autre part, __FASCALL tout seul ne semble plus fans la de SDCC. Quelle version de SDCC utilises tu ?
car moi je connais __z88dk_fastcall , mais pas __fastcall tout seul.


Autre chose... As tu testé --peep-hole ? Edité par ericb59 Le 22/12/2020 à 15h29


banniere-ericb59e
Site web    
aoineko Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 02/01/2011 à 21h17

Messages: 2657

Le 22/12/2020 à 16h32
__FASCALL est un define de __z88dk_fastcall :)
J'ai un historique de programmeur cross-platform donc j'ai pris l'habitude d'encapsuler les directives trop spécifique à un compilo.

TOUTES tes fonctions qui n'ont qu'un seul argument devrait avoir la directive __z88dk_fastcall.
Ca n'a aucun lien avec son contenu, ça change juste la façon dont sont passés les arguments.
J'ai même qq fonctions où je merge plusieurs arguments pour pouvoir utiliser cette directive (ce qui reste bien plus rapide que de passer par la pile).
D'après les discussions que j'ai lu sur le forum SDCC, il est probable qu'on ait un système plus souple dans les futures versions.

Et non, je n'ai pas encore utilisé le peep-hole... tout simplement parce que j'en ai pas encore vu l'utilité.
En tout cas, j'ai pas vu de code assembleur généré ou je me suis dis que le peep-hole serait la solution (c'est souvent plus un problème de C).


On est toujours ignorant avant de savoir.
Github    
ericb59 Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : compte ++ Groupe : Shoutbox

Inscrit le : 17/04/2012 à 10h25

Messages: 5464

Le 22/12/2020 à 16h45
Citation :
Ca n'a aucun lien avec son contenu, ça change juste la façon dont sont passés les arguments.


Ha bon ?
En fait je croyais que ce n'étais utile que dans le cas où la routine était écrite en ASM.
Je n'avais pas compris que c'était valable pour tout type de routine.


banniere-ericb59e
Site web    
aoineko Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 02/01/2011 à 21h17

Messages: 2657

Le 22/12/2020 à 18h20
Le compilo C de SDCC gère très bien le passage par registre :top
(tu y gagnes à l'appel de la fonction et dans le corps de la fonction)

Code C :
 
u8 Acc(u8 a)
{
    u8 ret = g_Counter + a;
    return ret;
}
 


Code ASM :
 
_Acc::
    ld    hl, #2 ; Passage par la pile == caca
    add    hl, sp
    ld    a,(#_g_Counter + 0)
    add    a, (hl)
    ld    l, a
    ret
 


Code C :
 
u8 Acc_FC(u8 a) __FASTCALL
{
    u8 ret = g_Counter + a;
    return ret;
}
 


Code ASM :
 
_Acc_FC::
    ld    a,(#_g_Counter + 0)
    add    a, l ; SDCC cherche bien le paramètre dans le registre L
    ld    l, a
    ret
 


On est toujours ignorant avant de savoir.
Github    
ericb59 Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : compte ++ Groupe : Shoutbox

Inscrit le : 17/04/2012 à 10h25

Messages: 5464

Le 22/12/2020 à 19h14
C'est bon à savoir. Je vais ajouter cela dans Fusion-c :top


banniere-ericb59e
Site web    
aoineko Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 02/01/2011 à 21h17

Messages: 2657

Le 23/12/2020 à 19h14
aoineko :
J'ai un historique de programmeur cross-platform donc j'ai pris l'habitude d'encapsuler les directives trop spécifique à un compilo


Un autre truc que je fais toujours, c'est SURTOUT ne pas utiliser le type int. Le standard AINSI C permet que le int puisse avoir une taille variable en fonction des implémentations. Sur SDCC, c'est du 16-bits, sur un GCC moderne, ça sera du 32-bits. Si tu as besoin de changer de compilo un jour, rien ne t'assures que ça sera des 16-bits.
Il y a donc trois problèmes : 1) on ne sait pas exactement quelle taille il aura, 2) on peut facilement oublier quel est sa taille (ce qui est un gros problème quand on programme pour le Z80), 3) le statut de signé/non-signé n'est pas assuré (ce qui est aussi un gros problème pour le Z80).

Tu pourrais utilisais le short à la place, qui lui est assuré d'être en 16-bits, mais je te conseille très fortement d'utiliser des types explicitant la taille et le statut signé/non-signé des variables.

Perso j'ai pris l'habitude d'utiliser :
- u8 : 8-bits unsigned integer
- u16 : 16-bits unsigned integer
- i8 : 8-bits signed integer
- i16 : 16-bits signed integer
- ...

Mais si tu veux garder des types standards, tu peux utiliser ceux fournis par <stdint.h> : uint8_t, uint16_t, etc.

Ca à l'air de rien, mais ça permet à l'utilisateur d'avoir bien conscience de ce qu'il fait... ce qui a un énorme impact pour le Z80.


On est toujours ignorant avant de savoir.
Github    
ericb59 Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : compte ++ Groupe : Shoutbox

Inscrit le : 17/04/2012 à 10h25

Messages: 5464

Le 23/12/2020 à 20h12
Oui, SHORT et INT sont identiques avec SDCC.
Je ne pense pas passer un code SDCC vers GCC, ni inversement quoi que ... ?
Moi je m'étais contenté d'utiliser les types standard de SDCC, dont j'avais l'habitude quand j'ai appris à coder en C avec GCC.
Je ne me suis pas cassé la tête plus loin.

Mais je comprend bien le problème...
De même je conseille aux autre sde toujours indiquer le "unsigned" alors que je ne le fait pas moi même ! :D


banniere-ericb59e
Site web    
aoineko Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 02/01/2011 à 21h17

Messages: 2657

Le 23/12/2020 à 21h34
Vu les piètres performances de SDCC... je pense qu'on hésiterait pas beaucoup à changer pour un nouveau toolchain qui serait vraiment bien optimisé pour le Z80.
Et on a aucune assurance de ce que cet hypothétique nouveau compilo choisirait pour les int.


On est toujours ignorant avant de savoir.
Github    
ericb59 Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : compte ++ Groupe : Shoutbox

Inscrit le : 17/04/2012 à 10h25

Messages: 5464

Le 06/01/2021 à 11h50
@aoineko

En utilisant ton CRT0, je me suis rendu compte que hex2bin m'indiquait
"Data Record skipped at 0xCxxx"

je pense que cela es dû à la variable g_HeapStartAddress qu'il y a dans ton CRT0.
Est-ce normal ce data skipper ? tu l'as aussi de ton coté ?


banniere-ericb59e
Site web    
aoineko Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 02/01/2011 à 21h17

Messages: 2657

Le 06/01/2021 à 14h25
Tu parles de quel crt0 ? Y en a 6 ^^

EDIT: Et non, l'erreur n'est pas normale. En tout cas, j'ai aucune erreur avec mes ctr0 sur tous les supports.
Ca peut aussi venir des paramètres qu'on utilise pour build le programme binaire.
Ce soir j'archiverai sur GitHub tout ce que j'ai fait ces derniers jours pour clean la gestion multi-support (mais les crt0 ont pas bougé il me semble).


On est toujours ignorant avant de savoir.
Github    
aoineko Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 02/01/2011 à 21h17

Messages: 2657

Le 08/01/2021 à 00h00
J'ai fait une grosse passe sur ma lib pour m'assurer la compatibilité MSX1 (pour les fonctionnalités compatibles évidemment ^^).
J'ai notamment check toutes les questions des temps d'accès en lecture/écriture du VDP.
Je sais pas ou en est Fusion-C à ce sujet, mais si tu veux je peux faire un petit topo.


On est toujours ignorant avant de savoir.
Github    
ericb59 Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : compte ++ Groupe : Shoutbox

Inscrit le : 17/04/2012 à 10h25

Messages: 5464

Le 08/01/2021 à 11h30
@aoineko. Tout il est bon pour le MSX1 dans FUSION-C.
J'ai même refait une routine CopyRam2VRAM spécifique pour MSX2 car on peut aller plus vite sur la VRAM du MSX2 que sur MSX1.

Mais vas y fais ton topo... J'suis certain que j'y apprendrai encore des choses qui vont me servir. :lol :top


banniere-ericb59e
Site web    
aoineko Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 02/01/2011 à 21h17

Messages: 2657

Le 08/01/2021 à 12h58
C’est cadeau :)

Déjà, le plus important à savoir c’est que quand l’affichage est désactivé, il n’y a aucune limitation de vitesse d’écriture/lecture en VRAM quelque-soit le type de MSX (comprendre : le Z80 n’ira jamais plus vite que le VDP). Donc, pour charger un niveau de jeu par ex., le mieux c’est de couper l’affichage et de charger tous ses graphismes en VRAM à pleine vitesse.

Les problèmes de temps d’accès n’interviennent donc que pour les lectures/écritures en VRAM pendant l’affichage. Dans ce cas, il faut croiser d’un côté :
- la version du VDP (= la version du MSX dans la plupart des cas) et le mode d’affichage qu’on souhaite utiliser
- les différentes façons d’écrire en VRAM et leur vitesse (la lecture à exactement les mêmes contraintes donc je vais pas détailler)

On peut essayer de faire de la dentelle en gérant tous les cas de façon optimale, mais une bonne approche c’est de prendre le pire cas (worst-case scenario).

Pour le MSX1 (V9918), l'intervalle minimale entre deux écritures en nombre de cycle Z80 est de :
- 29 cc pour les modes graphiques (Screen 1 & 2)
- 13 cc pour les modes textuels (Screen 0 & 3)

Sur MSX2/2+ (V9938/58) :
- 15 cc pour les modes graphiques (Screen 1-8)
- 20 cc pour les modes textuels (Screen 0 Width 40/80)

Coté Z80, il a plusieurs façons d’envoyer des données au VDP plus ou moins rapide :
- 18 cc pour une succession de outi (c’est ce que le Z80 du MSX peut faire de plus rapide)
- 23 cc pour un otir (ou une série de otir si on a besoin d’envoyer plus de 256 octets)
- 29 cc pour une boucle de outi (ce qui fait pile le worse-case du MSX1 ^^)
Code ASM :
loop: outi
      jp nz, loop


Déjà, on se rend compte qu’avec un otir (23 cc), on est déjà plus lent que le pire cas du MSX2.
Le choix que j’ai fait, c’est donc d’utiliser le otir pour mes fonctions d’écriture en VRAM par défaut. Ça peut être optimisé (cf. plus bas), mais ça suffit à mes besoins, surtout que c’est le genre de fonction qu’on a pas trop de raison d’utiliser pendant le déroulement d’un jeu sur MSX2. Dans ce cas, on utilise plutôt les commandes VDP qui ont le gros avantage d’avoir un nombre d’octets fixe à écrire et donc sont idéals pour utiliser une succession de outi. Je crois qu’il existe une astuce pour pouvoir utiliser les commandes VDP avec les modes textuels ; c’est le seul cas qui pourrait poser problème (18 cc < 20 cc).

La fonction à base de otir est aussi valable pour les modes textes du MSX1 (23 cc >13 cc). Le seul problème restant est donc les modes graphiques du MSX1. Pour eux, j’ai donc fait un set de fonction particulier à base de boucle de outi qui font pile la durée du pire case (29 cc).

Voilà.

Tout ce qui est dis pour l’écriture est aussi valable pour la lecture (avec ini et inir).
Normalement tu devrais avoir aucun nop dans ton programme.

Et en bonus, une solution pour aller encore plus vite qu’avec le otir pour un nombre variable d’octets à copier. Utiliser des paquets de outi ! :)
Par ex., tu peux faire des paquets de 16 outi :
- tu fais d’abord un outir avec "compteur & 0x000F",
- ensuite tu boucles "compteur >> 4" fois sur ton paquet de 16 outi.
C’est valable pour n’importe quelle valeur puissance de 2.
Par ex., pour un programme qui copie des images complètes en VRAM, tu peux même faire des blocs 256 outi !
Ca prend de place en code, mais le gain va être significatif.
Par contre, cette astuce n’a aucun intérêt pour de petites boucles.

PS : Pour la fonction FillVRAM, y aussi la boucle "loop: out (VDP_DATA), a ; djnz loop" qui prends de 21 à 26 cc et qui peut donc être problématique sur les modes graphiques d'un MSX1 (V9918) quand l'affichage est activé.


On est toujours ignorant avant de savoir.
Github    
ericb59 Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : compte ++ Groupe : Shoutbox

Inscrit le : 17/04/2012 à 10h25

Messages: 5464

Le 08/01/2021 à 15h23
OK. Donc tu as 2 jeux d'instructions MSX1 et MSX2.

Citation :
Déjà, le plus important à savoir c’est que quand l’affichage est désactivé, il n’y a aucune limitation de vitesse d’écriture/lecture

Question, comment tu coupes l'affichage sur MSX 1 ? :gne


banniere-ericb59e
Site web    
Répondre
Vous n'êtes pas autorisé à écrire dans cette catégorie