[Thomson] SDDRIVE Vidéo

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

Répondre
Daniel
Messages : 17312
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

[Thomson] SDDRIVE Vidéo

Message par Daniel »

Le contrôleur SDDRIVE, avec son débit de 20000 octets/seconde, n'est pas aussi rapide que le système SDANIM7 à base d'Arduino, mais permet toutefois de réaliser des vidéos avec son pour tous les ordinateurs 8 bits Thomson : http://dcmoto.free.fr/programmes/sddriv ... index.html

06.png
06.png (2.98 Kio) Consulté 3493 fois

La documentation de cette démo donne les informations pour créer soi-même sa propre vidéo.
Si vous n'êtes pas équipé du contrôleur SDDRIVE, il est possible d'avoir un aperçu de la démonstration dans Windows --> Image
Dernière modification par Daniel le 07 avr. 2023 10:26, modifié 1 fois.
Daniel
L'obstacle augmente mon ardeur.
Avatar de l’utilisateur
6502man
Messages : 12284
Inscription : 12 avr. 2007 22:46
Localisation : VAR
Contact :

Re: [Thomson] SDDRIVE Vidéo

Message par 6502man »

Même si c'est pas aussi rapide que la solution SDANIM7, c'est déjà très très bien, et extraordinaire pour un ordinateur des années 80 :D
Phil.

www.6502man.com

To bit or not to bit.
1 or 0.
capri2800
Messages : 232
Inscription : 19 nov. 2014 16:00
Localisation : Martigny, Suisse
Contact :

Re: [Thomson] SDDRIVE Vidéo

Message par capri2800 »

Sympa la vidéo !

Je l'ai vue version "Windows" ça doit être sympa sur un vrai MO5.
Daniel
Messages : 17312
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] SDDRIVE Vidéo

Message par Daniel »

Elle tourne en boucle sur un MO5 près de moi depuis ce matin. La différence est qu'avec le MO5 on apprécie mieux l'exploit technique qu'avec le PC. Mais le résultat, image et son, est semblable. Avec peut-être sur MO5 un très léger ronflement dans le son. C'est un défaut difficile à éviter car la carte mère du MO5 n'est pas conçue comme une chaîne Hi-Fi.

Pour la vidéo, j'ai un peu amélioré l'algorithme utilisé par SDANIM7 pour obtenir pratiquement la même qualité d'image avec un débit très inférieur. Le son reste le point faible, avec 5162 échantillons/seconde. Pour Simon's Cat ce n'est pas gênant. J'ai fait d'autres essais avec des chanteuses, et ce n'est pas très bon. Brassens, avec sa voix grave, passe un peu mieux.
Daniel
L'obstacle augmente mon ardeur.
Avatar de l’utilisateur
Carl
Modérateur
Messages : 13249
Inscription : 08 avr. 2007 13:21
Localisation : http://www.doledujura.fr
Contact :

Re: [Thomson] SDDRIVE Vidéo

Message par Carl »

Excellent ! 8)

Carl
Avatar de l’utilisateur
jice
Messages : 213
Inscription : 21 avr. 2014 15:08
Localisation : Madrid

Re: [Thomson] SDDRIVE Vidéo

Message par jice »

Génial !
MO5 - MO5 Platini - TO7 - TO7/70 - TO8 - TO9+
__sam__
Messages : 7921
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] SDDRIVE Vidéo

Message par __sam__ »

Je suis en vacances et je reflechis à faire aussi de la video avec SDDRIVE en amméliorant le débit si possible (et en couleur tant qu'on y est).

J'ai regardé le code ASM de ce player et j'ai constaté qu'il n'y a pas de couverture des octets audio manquants pendant l'inter-bloc. Avec l'émulateur cela ne s'entends pas car l'interbloc de la carte SD est pour ainsi nul. Mais en pratique ca peut monter jusqu'à 5ms si j'ai bonne mémoire c'est à dire environ 1/6 du temps de lecture d'un bloc complet de la carte SD.

Du coup je me demande si cette absence de son est audible et si elle produit des craquements comme on en avait avec l'expérience sur la musique avec SD-MOTO. Quelqu'un avec le matériel réel peut-il dire si on entends ou pas les inter-blocs de la carte SD?
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Daniel
Messages : 17312
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] SDDRIVE Vidéo

Message par Daniel »

De mémoire je crois qu'il n'y a pas une compensation parfaite, mais le nombre de cycles entre deux blocs est réduit le plus possible pour minimiser le décalage. Je ne l'entends pas mais je ne suis pas une référence dans ce domaine. Il faudrait que les musiciens donnent leur avis.

Pour la plupart des cartes SD le gap inter-bloc équivaut à la lecture de quatre octets : deux octets de CRC, un octet $FF et un octet $FE.

[Edit 1] Avec Simon's Cat il n'est pas très facile d'entendre les défauts, par contre cette vidéo est peut-être mieux adaptée pour le son (par contre l'image n'est pas bonne, mais c'est un autre problème).

[Edit 2] Dans SDDRIVE Music, au contraire de SDDRIVE Vidéo, la compensation est parfaite car il y a un buffer avec des échantillons en réserve. Ils sont joués pendant le changement de bloc.
Daniel
L'obstacle augmente mon ardeur.
__sam__
Messages : 7921
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] SDDRIVE Vidéo

Message par __sam__ »

justement j'étudie la possibilité d'un buffer inter-bloc collecté dans des bits dispo dans le format.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
jasz
Messages : 1313
Inscription : 05 oct. 2016 20:05
Localisation : Quelque part dans le 31

Re: [Thomson] SDDRIVE Vidéo

Message par jasz »

L'idée du buffer est bonne car on peut travailler entre le physique (celui qui est lu) et le logique (celui qui charge) en swappant entre chaque bloc. La chose est possible sans bouffer trop de cycles. Par contre pour l'écran il faudrait faire de même car des fois on sent le ralentissement lors de l'affichage...
Daniel
Messages : 17312
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] SDDRIVE Vidéo

Message par Daniel »

Le changement de buffer peut être audible, par contre il est totalement imperceptible dans l'image. La fluidité de l'animation est uniquement fonction du débit et de l'algorithme de compression.
Daniel
L'obstacle augmente mon ardeur.
__sam__
Messages : 7921
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] SDDRIVE Vidéo

Message par __sam__ »

@jasz: Le buffer ne sert pas à faire de double buffering. Tout est fait au CPU il n'y a pas de chips qui écrit ou affiche l'un des buffers pendant qu'on travaille sur l'autre. Le buffer sert juste à combler l'attente entre les blocs de la carte SD.

En effet, au sein d'un bloc, la lecture (bit par bit, pour rappel) des octets se fait sans attente et on peu sortir les échantillons à la même fréquence qu'on lit les octets. Mais quand la carte SD doit passer au bloc suivant tous les 512 octets, il faut attendre que ce nouveau bloc soit pret. La spec dit que ca peut prendre jusqu'à 5ms (après quoi la carte SD est supposée s'être endormie). Or 5ms c'est long. Ca représente 25 échantillons sonores à 5khz. Il faut donc un buffer de 25 échantillons sonores en reserve pour combler les données qui n'arrivent pas pendant le changement de bloc. C'est la solution trouvée par Daniel dans les experimentations de son avec SDMOTO et qui est absente du code de SDDrive vidéo ce qui m'étonnait.

Concernant le fait que ca peine. C'est normal lors des changements trop "lourds" de l'image. Avec le player actuel, la bande passante video permet de modifier un octet video tous les 193 cycles environ. Pour mettre à jour tout l'écran il faut donc 8000 * 193 cycles soit sensiblement 1.5 seconde. C'est super long!

Dans mon étude, je regarde comment on peut augmenter la bande passante vidéo tout en gardant un son correct (5.16khz dans le player d'origine). J'ai pas fini tous les calculs, mais le format préliminaire que j'ai trouvé permet d'avoir 5.8khz audio (donc mieux que le player d'origine) et une bande passante plus de deux fois supérieure pour la partie vidéo. Ainsi le changement d'écran complet tombe un peu au dessus de 600ms.

En poussant un peu plus la bande passante video j'arrive théoriquement à 366ms pour mettre à jour tout l'écran, mais l'audio ne bénéficie alors plus que de 2.7khz de bande passante. Ce n'est pas assez je pense. Donc bref tout le truc de mes recherches d'été est de trouver le bon compromis pour avoir la meilleure bande passante audio et video.

Avec un changement complet de la video en ~600ms au lieu de ~1500ms, ca devrait peiner un peu moins lors des changements vidéos massifs, mais ca ne sera jamais instantané: la solution de lecture des octets bit par bit n'offre pas assez de bande passante. Pour aller plus vite il faut pouvoir lire les octets en une fois. C'est ce qui est fait avec le montage à base d'arduino (documenté sur le forum) ou avec une carte CF (pas documenté je crois?). Hélas très peu de personnes ont ces solutions. C'est sans doute dommage, car un max de bande passante permet de faire des trucs encore plus étonnants. Pour info mon amiga500 "vampirisé" lit les CF à 9.5Mo par seconde, de quoi streamer de la video et de l'audio en haute qualité :) (mais la vampire c'est une tuerie de toute façon.)
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Daniel
Messages : 17312
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] SDDRIVE Vidéo

Message par Daniel »

En réalité le changement de buffer est beaucoup plus rapide que la valeur limite indiquée dans la doc. C'est l'équivalent de la lecture de quatre octets.
- Avec SDDRIVE on lit 20000 octets/seconde, je vous laisse faire le calcul :wink:
- Avec le contrôleur CS91-280 on lit 5600 octets/seconde, c'est un peu plus long.
Daniel
L'obstacle augmente mon ardeur.
__sam__
Messages : 7921
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] SDDRIVE Vidéo

Message par __sam__ »

Un truc que je ne m'explique pas: si avec SDMOTO c'était plus lent pour lire les octets, la carte aurait largement le temps de changer de bloc avant qu'on ne lise les octets du bloc suivant. Une fois lu le bloc, on lisait le CRC (opération lente par rapport à SDDRIVE) et on aurait du avoir immédiatement le $FE de début de bloc sans aucune lecture de $FF d'attente. On aurait donc jamais du avoir de crépitements. Pourtant on en avait vraiment beaucoup. Je me souviens d'avoir dumpé à l'écran en temps réel les octets lus et on voyait bien les $FF apparaitre (en diagonale juste au dessus de la double flèche rouge). Etait-ce les cartes SD de l'époque qui avaient besoin de 10 ou 15 elements de buffer intercalaire pendant lesquels on lisait $FF ([EDIT] en fait pour ne plus avoir de craquements tu étais monté à 64 octets de buffer)? Bref je m'explique pas qu'avec une lecture plus lente de la carte il falait attendre plus longtemps qu'à présent. :?:

En apparté, une chose intéressante: le lecteur double densité MFM stream les données lues de la tête de lecture à quelque chose comme 250000bits/sec je crois. A raison de 10bits par octets, ca nous fait 25ko/sec en vitesse de pointe. Le lecteur de floppy pourrait être presque aussi rapide que SDDrive. Sur le papier du moins. :roll: Mais j'ose même pas imaginer le temps de passage d'une piste à la suivante.... une éternité sans doute.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Daniel
Messages : 17312
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] SDDRIVE Vidéo

Message par Daniel »

Je n'ai pas fait d'étude sérieuse sur le temps de changement de bloc, mes estimations sont très subjectives. Mais il me semble que l'octet $FF est toujours envoyé avant $FE, même pour les cartes ultra-rapides lues très lentement. Et il me semble aussi qu'à la vitesse très lente du 6809 il n'y a qu'un octet $FF, mais je peux me tromper. Il est possible que ça dépende aussi du modèle de carte et que certains blocs soient plus longs à trouver que d'autres, en particulier quand il y a des blocs mauvais sur la carte et qu'ils sont remplacés par des blocs de réserve. Mais là encore ce sont des supputations sans preuve.

Il ne faut pas trop se fier aux 64 échantillons de réserve pour SDMOTO. D'abord je suis revenu à 32 dans la dernière version, et ensuite il y avait une autre cause aux craquements (un bug dans le programme). J'avais augmenté le nombre d'échantillons de réserve car je supposais que le problème était là, mais en fait il était ailleurs. Un buffer de 4 ou 8 échantillons devrait suffire. J'ai gardé 32 car ça ne coûte rien vu le nombre de bits disponibles dans le fichier.

Ci-dessous la dernière version de CS91280_MUSIC :

Code : Tout sélectionner

/**************************************************\
*           C S 9 1 2 8 0 _ M U S I C              * 
*           (c) 2018 - Daniel Coulom               *  
*           http://dcmoto.free.fr/                 *
*           http://forum.system-cfg.com/           *
*--------------------------------------------------*
* Ce code est distribue gratuitement dans l'espoir *
* qu'il sera utile, mais sans aucune  garantie  et *
* sans  engager  la  responsabilité  de  l'auteur. *
* Vous  pouvez  l' utiliser,  le  modifier  et  le *
* diffuser librement, en conservant cette  licence *
* et les références de l'auteur dans   toutes  les *
* copies. L'exploitation commerciale est interdite.*
\**************************************************/

* Ce programme utilise l'interface SDMOTO ou SDMO
* associee au controleur CS91-280 ou CS91-282 pour
* jouer de la musique en streaming.
* Il réalise les fonctions suivantes pour TO ou MO:
* - affichage d'une image monochrome (16 blocs)
* - envoi sur le CNA de musique 5586Hz 6 bits
* Le chargement et le lancement du programme sont
* realises grace a un secteur de boot.
*
* Utilisation du 2eme port joystick avec SDMOTO
* Port A $A7CC (pour les MO) ou $E7CC (pour les TO)
* PA5 en sortie --> SD Clock     SCK  DB9 pin 2
* PA6 en sortie --> SD Data IN   MOSI DB9 pin 3
* PA7 en entree <-- SD Data OUT  MISO DB9 pin 4
*
* Utilisation port magnetophone avec SDMO
* Port A $A7C0 pour les donnees 
* PA6 en sortie --> SD Data IN   MOSI DB9 pin 3
* PA7 en entree <-- SD Data OUT  MISO DB9 pin 4
* Port B $A7C2 pour l'horloge
* PA3 en sortie --> SD Clock     SCK  DB9 pin 2

/**************************************************\
*                Version 2018.07.02                *
\**************************************************/
* Historique
* 2018.07.02 deplacement de la zone SD_LB0 en <$51 
* 2018.07.02 deplacement de la zone SD_TYP en <$57 
* 2018.05.30 debut de calcul LBA debut pour CMD18
* 2018.05.29 test appui touche TO8
* 2018.05.28 test touches espace et fleches MO
* 2018.05.28 ajustement precis des cycles
* 2018.05.27 ajout barre de progression
* 2018.03.01 initialisation MO6 differente
* 2018.02.25 premiere version issue de SDPLAY.2017

*------------------------------------------------------
* DEBUT DU PROGRAMME
*------------------------------------------------------
  ORG   $9C00 
  BRA   INIT          initialisations 

*------------------------------------------------------
* FONCTIONS D'ACCES A LA CARTE SD
*------------------------------------------------------
CMD18
  FCB   $52            read multiple block
  FDB   $0000          adresse bloc (poids fort)
  FDB   $0000          adresse bloc (poids faible)
  FCB   $FF            checksum non testee 
  FCB   $00            code retour attendu  
CMD12
  FCB   $4C            stop transmission
  FDB   $0000          dummy parameter
  FDB   $0000          dummy parameter
  FCB   $FF            checksum non testee 
  FCB   $00            code retour attendu  

*------------------------------------------------------
* ZONES DE TRAVAIL 
*------------------------------------------------------
SD_TYP
  FCB   $00            type de carte SD=0 SDHC=1
SD_LB0
  FDB   $0000          LBA debut fichier (poids fort)
  FDB   $0000          LBA debut fichier (poids faible)
EXCMD
  FDB   $A028          adresse fonction EXCMD (MO)
VIDEO
  FDB   $0000          adresse debut memoire video (MO)
PBARA
  FDB   $0000          adresse debut barre progression
PBARS
  FDB   $0000          secteurs/pixel barre progression 
PBARP  
  FDB   $0000          numero pixel barre progression
NSECT
  FDB   $0000          numero de secteur sur 4 octets
  FDB   $0000          (zone de travail)

*------------------------------------------------------
* Detection du type d'ordinateur MO ou TO
*------------------------------------------------------
INIT
  ORCC  #$50           desactive les interruptions
  LDA   >$FFF2         $FFF2: $F0(MO) et $70(TO)
  BPL   INIT3          TO detecte

*------------------------------------------------------
* Initialisations communes MO5-MO6 
*------------------------------------------------------
  LDA   >$2057         type de carte
  STA   >SD_TYP        stockage type de carte
  LDD   >$2051         LB0 poids faible
  STD   >SD_LB0        stockage LB0 poids faible 
  LDD   >$2053         LB0 poids faible
  STD   >SD_LB0+2      stockage LB0 poids faible 
  LDU   #$A7C0         adresse selection banque video
  LDB   #$07           octet couleur
  BSR   COLOR          initialisation couleurs
  LDA   >$FFF0         type d'ordinateur
  BNE   INIT2          MO6   

*------------------------------------------------------
* Initialisations MO5 
* Attention aux differences PIA systeme MO5 et MO6
*------------------------------------------------------
INIT1
  LDA   >$A7C0         port A du PIA systeme
  ANDA  #$E1           raz couleur cadre
  ORA   #$0E           couleur cadre 7 (blanc) 
  STA   >$A7C0         change couleur cadre
  LDA   $A6FF          numero banque CS91-280
  CMPA  #$B0           test banque B0
  BEQ   INIT4          CS91-280 est en mode SDMOTO 
  LBSR  RBSDMO         modification routine RBYTE
  BRA   INIT9          suite des initialisations

*------------------------------------------------------
* Initialisations MO6 
* Attention aux differences PIA systeme MO5 et MO6
*------------------------------------------------------
INIT2
  LDA   #$07           couleur cadre 7 (blanc) 
  STA   >$A7DD         change couleur cadre
  LDA   >$A7C0         PIA systeme 
  ANDA  #$FB           clear mute bit 
  STA   >$A7C0         modification PIA
  BRA   INIT9          suite des initialisations

*------------------------------------------------------
* Initialisations communes TO7-TO8 
*------------------------------------------------------
INIT3
  LDU   #$E7C3         adresse selection banque video
  LDY   #$4000         adresse debut memoire video
  STY   VIDEO          initialisation adresse video
  LDD   #$5F18         adresse barre progression
  STD   PBARA          stockage adresse
  LDB   #$C7           octet couleur
  BSR   COLOR          initialisation couleurs
  LDA   #$E0           valeur adresse EXCMD (poids fort)
  STA   EXCMD          adresse execution EXCMD pour TO
  LDA   >$6057         type de carte
  STA   >SD_TYP        stockage type de carte
  LDD   >$6051         LB0 poids faible
  STD   >SD_LB0        stockage LB0 poids faible 
  LDD   >$6053         LB0 poids faible
  STD   >SD_LB0+2      stockage LB0 poids faible 
  LDA   >$FFF0         type d'ordinateur
  BEQ   INIT4          TO7=0   
  DECA                 retrancher 1
  BEQ   INIT4          TO7/70=1
  BRA   INIT5          TO8=3   

*------------------------------------------------------
* Initialisations TO7 
*------------------------------------------------------
INIT4
  LDA   >$E7C3         port A du PIA systeme
  ORA   #$70           couleur cadre 7 (blanc) 
  STA   >$E7C3         change couleur cadre
  BRA   INIT9          suite des initialisations

*------------------------------------------------------
* Initialisations TO8 
*------------------------------------------------------
INIT5
  LDA   #$07           couleur cadre 7 (blanc) 
  STA   >$E7DD         change couleur cadre TO8
  LBSR  RKEYT8         modification routine KEYTST
  BRA   INIT9          suite des initialisations

*------------------------------------------------------
* Initialisation couleur noir/blanc (Y = debut ecran)
* Adresse du bit de selection banque video dans U
* Adresse octet couleur dans B
*------------------------------------------------------
COLOR   
  LDA   ,U             octet de selection banque video
  ANDA  #$FE           clear bit 0
  STA   ,U             selection video couleur
  LDY   VIDEO          adresse debut memoire video
  LDX   #$1F40         compteur de boucles
  TFR   B,A            code couleur sur deux octets
COLOR1  
  STD   ,Y++           initialise deux octets
  LEAX  -2,X           comptage
  BNE   COLOR1         boucle
  INC   ,U             selection video forme
  RTS

*------------------------------------------------------
* Initialisations communes 
*------------------------------------------------------
INIT9
* Initialisation adresse du fichier .sd pour CMD18
*  LDX   <$8E           octets poids fort adresse
*  STX   CMD18+1        stockage pour commande CMD18
*  LDX   <$90           octets poids faible adresse
*  STX   CMD18+3        stockage pour commande CMD18
  TFR   DP,B           valeur actuelle de DP
  ADDB  #$87           $A7 pour MO et $E7 pour TO
  TFR   B,DP           initialisation DP
* Initialisation PIA pour SDMOTO
  LDA   <$CE           lecture registre de controle A
  ANDA  #$FB           raz bit 2 
  STA   <$CE           selection DDRA
  LDB   #$60           set bits 5 et 6
  STB   <$CC           bits MOSI et CLOCK en sortie
  ORA   #$04           set b2
  STA   <$CE           selection PA
* Initialisation CNA en sortie
  LDA   <$CF           lecture registre de controle B
  ANDA  #$FB           raz bit 2 
  STA   <$CF           selection DDRB
  LDB   #$3F           set bits 0-5 
  STB   <$CD           bits CNA en sortie
  ORA   #$04           set b2
  STA   <$CF           selection PB

*-------------------------------------------------------
* Calcul du secteur de debut de la musique
*-------------------------------------------------------
  LDD   SD_LB0         poids fort LBA debut fichier 
  STD   NSECT          stockage poids fort 
  LDD   SD_LB0+2       poids faible LBA debut fichier 
  STD   NSECT+2        stockage poids faible 
  LBSR  DIV512         division par 512 si type=SD
  LBSR  OFFSET         calcul debut du morceau 
  LBSR  MUL512         multiplication par 512 si type=SD
  LDD   NSECT          poids fort LBA debut fichier
  STD   CMD18+1        stockage poids fort
  LDD   NSECT+2        poids fort LBA debut fichier
  STD   CMD18+3        stockage poids fort
  
*-------------------------------------------------------
* Lancement de la commande CMD18 et saut de cinq blocs
*-------------------------------------------------------
READ
  LDU   #CMD18         adresse commande CMD18
  JSR   [EXCMD]        EXCMD = execution commande
*  LBSR  SAUT           lecture bloc (secteur de boot)
*  LBSR  SAUT           lecture bloc (secteur sdplay)
*  LBSR  SAUT           lecture bloc (secteur sdplay)
*  LBSR  SAUT           lecture bloc (secteur sdplay)
*  LBSR  SAUT           lecture bloc (secteur sdplay)

*------------------------------------------------------
* Affichage de l'image
*------------------------------------------------------
DISPLAY
  LDU   VIDEO          adresse memoire video
  LDY   #$0010         nombre de blocs a lire
DISPL1      
  LBSR  RBYTE          lecture d'un octet
  CMPA  #$FE           test debut de bloc
  BNE   DISPL1         attente debut de bloc
  LDX   #$0200         nombre d'octets a lire
DISPL2
  LBSR  RBYTE          lecture d'un octet
  STA   ,U+            affichage       
  LEAX  -1,X           decrementation compteur 
  BNE   DISPL2         lecture octet suivant
  LBSR  RBYTE          lecture CRC1
  LBSR  RBYTE          lecture CRC2
  LEAY  -1,Y           decrementation compteur
  BNE   DISPL1         lecture bloc suivant
  BSR   PBARI          initialisation barre de progression 
  BRA   PLAY           jouer la musique 

*------------------------------------------------------
* ARRET DE LA LECTURE ET BOUCLE INFINIE
*------------------------------------------------------
FIN
  PULS  B              depilage compteur octets suppl.
  LDU   #CMD12         adresse commande CMD12
  JSR   [EXCMD]        EXCMD = execution commande
  BRA   READ           recommencer la lecture 

*------------------------------------------------------
* Initialisation de la barre de progression
*------------------------------------------------------
PBARI
  LDD   -2,U           nombre secteurs/pixel
  STD   PBARS          stockage en memoire
  LDD   #$0000         raz registre D
  STD   PBARP          raz numero pixel
  LDX   VIDEO          adresse debut ecran
  LEAX  $1F18,X        adresse barre de progression 
  STX   PBARA          stockage adresse  
  LEAX  -40,X          debut ligne precedente
  LDB   #$50           compteur de boucle
  LDA   #$00           segment a blanc
PBARI1
  STA   ,X+            initialise le segment a blanc
  DECB                 decremente le compteur    
  BNE   PBARI1         nouvelle boucle
  RTS                  retour
     
*------------------------------------------------------
* Joue 2 octets et recupere 1 bit dans le premier
* avec test de fin sur le bit 7 de l'echantillon
* periode = 179 microsecondes
* decompte des cycles avec le BSR et le RTS :
* avant le premier echantillon : 7+158=165
* entre les deux echantillons : 4+2+6+6+158+3=179 
* apres le deuxieme echantillon : 4+5+5=14
* 14(apres le deuxieme)+165(avant le prochain)=179 
*------------------------------------------------------
PLAY2
* premier octet        158+4+2+6+6=176  
  LBSR  RBYTE          lecture echantillon       (158)
  STA   <$CD           envoi de l'echantillon      (4)
  ASLA                 b7 dans carry               (2)
  ROL   ,X             stockage b7                 (6)
  NOP                  temporisation               (2)
  NOP                  temporisation               (2)
  NOP                  temporisation               (2)
  
* deuxieme octet       158+3+4+5+5=175 (+7 pour BSR) 
  LBSR  RBYTE          lecture echantillon       (158)
* test de fin
  BPL   PLAY21         pas d'octet fin de fichier  (3)
  LDX   #FIN           adresse routine de FIN
  STX   ,S             pour retour en FIN
PLAY21
  STA   <$CD           envoi de l'echantillon      (4)
  LBRN  $FFFF          temporisation               (5)
  RTS                  retour                      (5)

*------------------------------------------------------
* Lecture de la musique
*------------------------------------------------------
PLAY
  LEAU  $E000,U        adresse ecran = fin - $2000
  LEAX  $23,U          adresse haute buffer ecran
  LDU   #$0000         numero secteur courant 
  LDB   #$20           compteur octets supplementaires
  PSHS  B              empilage compteur
      
*------------------------------------------------------
* Attente debut de bloc
*------------------------------------------------------
PLAY0
  LBSR  RBYTE          lecture d'un octet
  CMPA  #$FE           test debut de bloc
  BNE   PLAY0          attente debut de bloc

*------------------------------------------------------
* Boucle de lecture d'un bloc
*------------------------------------------------------
PLAY1
  BSR   PLAY2          joue 2 octets, stocke 1 bit
  BSR   PLAY2          joue 2 octets, stocke 1 bit
  BSR   PLAY2          joue 2 octets, stocke 1 bit
  BSR   PLAY2          joue 2 octets, stocke 1 bit
  BSR   PLAY2          joue 2 octets, stocke 1 bit
  BSR   PLAY2          joue 2 octets, stocke 1 bit
  BSR   PLAY2          joue 2 octets, stocke 1 bit
* joue 2 octets, complete l'octet supplementaire  
  LBRN  $FFFF          temporisation               (5)
  NOP                  temporisation               (2)
  LBSR  RBYTE          lecture echantillon       (158)
  STA   <$CD           envoi de l'echantillon      (4)
  ASLA                 b7 dans carry               (2)
  ROL   ,X             stockage b7                 (6)
  LEAX  -1,X           modifie pointeur octet sup  (5)
  NOP                  temporisation               (2)
  NOP                  temporisation               (2)
  LBSR  RBYTE          lecture echantillon       (158)
  STA   <$CD           envoi de l'echantillon      (4)
  DEC   ,S             compteur octets supplement. (6)
  BNE   PLAY1          boucle suivante             (3)

*------------------------------------------------------
* Lecture des octets de CRC
*------------------------------------------------------

* premier octet CRC    158+3+5+4+5+2+2=179
  LBSR  RBYTE          lecture octet CRC         (158)
  LDD   #$0000         initialise A pour test $FE  (3) 
  LDB   1,X            chargement echantillon sup. (5)
  STB   <$CD           envoi de l'echantillon 1    (4)
  LEAX  2,X            incremente pointeur oct sup (5)
  NOP                  temporisation               (2) 
  NOP                  temporisation               (2) 

* deuxieme octet CRC  158+2+6+4=170
  LBSR  RBYTE          lecture octet CRC         (158)
  CLRA                 initialise A pour test $FE  (2) 
  LDB   ,X+            chargement echantillon sup. (6)
  STB   <$CD           envoi de l'echantillon 2    (4)

*------------------------------------------------------
* Lecture des octets inter-blocs pendant l'envoi
* des echantillons supplementaires
*------------------------------------------------------

* Echantillon supplementaire n°3 (2+4+161+6+2+4=179)
  LDB   #$20           compteur echantillons sup.  (2) 
  STB   ,S             stocke le compteur          (4) 
  BSR   INTER          lecture octet inter-blocs (161)
  LDB   ,X+            chargement echantillon      (6)
  NOP                  temporisation               (2) 
  STB   <$CD           envoi de l'echantillon 3    (4)

* Echantillons supplementaires 4 a 32 
  LDY   #$001D         compteur pour 29 boucles    (4)
*  NOP                  temporisation               (2) 
*  NOP                  temporisation               (2) 
* comptage des secteurs (1 cycle en trop)
  LEAU  1,U            incremente secteur courant (5) 

* La boucle SUPP s'execute en 161+6+4+5+3=179 cycles
SUPP
  BSR   INTER          lecture octet inter-blocs (161)
  LDB   ,X+            chargement echantillon      (6)
  STB   <$CD           envoi de l'echantillon      (4)
  LEAY  -1,Y           decremente le compteur      (5)
  BNE   SUPP           nouvelle boucle             (3)
  
* Preparation de la lecture du bloc suivant   
  LEAX  -1,X           retablit pointeur           (5)
  CMPA  #$FE           test début de bloc          (2)
  BEQ   PLAY1          traitement du bloc suivant  (3)
  BRA   PLAY0          attente octet $FE           (3) 

*------------------------------------------------------
* LIRE UN OCTET INTER-BLOCS SI NECESSAIRE 
* SINON AFFICHER LA BARRE DE PROGRESSION
* Total avec BSR : 7+2+3+144+5=161 
*------------------------------------------------------
INTER
  CMPA  #$FE           test debut de bloc          (2)
  BNE   RBYTE          lecture octet inter-blocs   (3)

*------------------------------------------------------
* Affichage de la barre de progression (149 cycles)
*------------------------------------------------------
PBAR
  CMPU  PBARS          secteurs/pixel             (8)   8   
  BEQ   PBAR2          affichage de la barre      (3)  11
*******************************************************
* temporisation 75 cycles si la barre n'est pas affichee
  PSHS  Y,X,B,A        empilage registres        (11)  
  LDB   #$0B           compteur de boucles        (2) 
PBAR1      
  DECB                 decremente le compteur     (2)
  BNE   PBAR1          nouvelle boucle            (3)
  NOP                  temporisation              (2) 
  NOP                  temporisation              (2) 
  BRA   PBAR9          test touche et retour      (3) 
*******************************************************
PBAR2
  LDU   #$0000         raz compteur secteurs      (3)  14
  PSHS  Y,X,B,A        empilage registres        (11)  25
  LDD   PBARP          numero pixel courant       (6)  31  
  INCD                 numero pixel suivant       (4)  35
  STD   PBARP          numero pixel courant       (6)  41  
  LSRA                 division                   (2)  43
  RORB                 par huit                   (2)  45
  LSRA                 pour                       (2)  47
  RORB                 obtenir                    (2)  49
  LSRA                 le numero                  (2)  51
  RORB                 du segment                 (2)  53
  ADDD  PBARA          adresse ecran du segment   (7)  60
  TFR   D,Y            stockee dans Y             (6)  66
  LDX   #STABLE        adresse table segments     (3)  69
  LDD   PBARP          numero du pixel            (6)  75
  ANDB  #$07           numero du segment          (2)  77 
  LDA   B,X            chargement segment         (5)  82
  STA   ,Y             affichage                  (4)  86
PBAR9
  BSR   KEYTST         test appui touche         (50) 136
  PULS  A,B,X,Y,PC     depilage et retour        (13) 149 

*------------------------------------------------------
* Table des segments
*------------------------------------------------------
STABLE
  FCB   $80
  FCB   $c0
  FCB   $e0
  FCB   $f0
  FCB   $f8
  FCB   $fc
  FCB   $fe
  FCB   $ff
       
*------------------------------------------------------
* Temporisation 138 cycles
* Plus CMPU(8) et BNE(3) = 149 (equivalent RBYTE + RTS)
* boucle de temporisation : 25x5=125 cycles
* total : 2+125+2+2+2+5=138 cycles
*------------------------------------------------------
*TEMPO
*  LDB   #$19           compteur de boucles     (2) 
*TEMP1      
*  DECB                 decremente le compteur  (2)
*  BNE   TEMP1          nouvelle boucle         (3)
*  NOP                  temporisation           (2) 
*  NOP                  temporisation           (2) 
*  NOP                  temporisation           (2) 
*  RTS                  retour                  (5)

*------------------------------------------------------
* Test appui sur une touche (MO) 51 cycles avec le BSR    
*------------------------------------------------------
KEYTST
* test espace  
  LDA    #$40          touche espace           (2)
  STA    <$C1          selection touche        (4)
  LDA    <$C1          test touche             (4)
  BPL    MO_SP         touche enfoncee         (3)
* test fleche gauche  
  LDA    #$52          touche fleche gauche    (2)
  STA    <$C1          selection touche        (4)
  LDA    <$C1          test touche             (4)
  BPL    MO_FG         touche enfoncee         (3)
* test fleche droite  
  LDA    #$32          touche fleche droite    (2) 
  STA    <$C1          selection touche        (4)
  LDA    <$C1          test touche             (4)
  BPL    MO_FD         touche enfoncee         (3)
  RTS                  retour                  (5)

*------------------------------------------------------
* Saut vers les routines de traitement touches MO
*------------------------------------------------------
MO_SP
  LBRA   PAUSE
MO_FG
  LBRA   BACK
MO_FD
  LBRA   FWD  

*------------------------------------------------------
* Saut de 512 octets 
*------------------------------------------------------
SAUT
  BSR   RBYTE          lecture octet
  CMPA  #$FE           comparaison avec $FE
  BNE   SAUT           attente debut secteur
  LDX   #$0200         initialisation compteur
SAUT1
  BSR   RBYTE          lecture d'un octet
  LEAX  -1,X           decrementation compteur
  BNE   SAUT1          nouvelle lecture
  BSR   RBYTE          lecture CRC1
  BSR   RBYTE          lecture CRC2
  RTS                  retour

*------------------------------------------------------
* LECTURE D'UN OCTET AVEC SDMOTO
* Le registre B n'est pas preserve
* Valeur de l'octet dans le registre A en sortie
*------------------------------------------------------
RBYTE
* premier bit
  LDB   #$5F           clear bit 5                 (2)
  STB   <$CC           clock low, di high          (4)
  LDB   #$7F           Valeur pour test bit 7      (2)
  STB   <$CC           clock high, di high         (4)
  CMPB  <$CC           PA b7 (bit lu) -> carry     (4)
  ROLA                 C (bit lu) -> b0 reg A      (2)
* deuxieme bit
  LDB   #$5F           clear bit 5                 (2)
  STB   <$CC           clock low, di high          (4)
  LDB   #$7F           Valeur pour test bit 7      (2)
  STB   <$CC           clock high, di high         (4)
  CMPB  <$CC           PA b7 (bit lu) -> carry     (4)
  ROLA                 C (bit lu) -> b0 reg A      (2)
* troisieme bit
  LDB   #$5F           clear bit 5                 (2)
  STB   <$CC           clock low, di high          (4)
  LDB   #$7F           Valeur pour test bit 7      (2)
  STB   <$CC           clock high, di high         (4)
  CMPB  <$CC           PA b7 (bit lu) -> carry     (4)
  ROLA                 C (bit lu) -> b0 reg A      (2)
* quatrieme bit
  LDB   #$5F           clear bit 5                 (2)
  STB   <$CC           clock low, di high          (4)
  LDB   #$7F           Valeur pour test bit 7      (2)
  STB   <$CC           clock high, di high         (4)
  CMPB  <$CC           PA b7 (bit lu) -> carry     (4)
  ROLA                 C (bit lu) -> b0 reg A      (2)
* cinquieme bit
  LDB   #$5F           clear bit 5                 (2)
  STB   <$CC           clock low, di high          (4)
  LDB   #$7F           Valeur pour test bit 7      (2)
  STB   <$CC           clock high, di high         (4)
  CMPB  <$CC           PA b7 (bit lu) -> carry     (4)
  ROLA                 C (bit lu) -> b0 reg A      (2)
* sixieme bit
  LDB   #$5F           clear bit 5                 (2)
  STB   <$CC           clock low, di high          (4)
  LDB   #$7F           Valeur pour test bit 7      (2)
  STB   <$CC           clock high, di high         (4)
  CMPB  <$CC           PA b7 (bit lu) -> carry     (4)
  ROLA                 C (bit lu) -> b0 reg A      (2)
* septieme bit
  LDB   #$5F           clear bit 5                 (2)
  STB   <$CC           clock low, di high          (4)
  LDB   #$7F           Valeur pour test bit 7      (2)
  STB   <$CC           clock high, di high         (4)
  CMPB  <$CC           PA b7 (bit lu) -> carry     (4)
  ROLA                 C (bit lu) -> b0 reg A      (2)
* huitieme bit 
  LDB   #$5F           clear bit 5                 (2)
  STB   <$CC           clock low, di high          (4)
  LDB   #$7F           Valeur pour test bit 7      (2)
  STB   <$CC           clock high, di high         (4)
  CMPB  <$CC           PA b7 (bit lu) -> carry     (4)
  ROLA                 C (bit lu) -> b0 reg A      (2)
*
  RTS                  retour (octet dans A)       (5)

* longueur totale avec BSR: 7 + 18*8 + 5 = 156
*                avec LBSR: 9 + 18*8 + 5 = 158

*------------------------------------------------------
* LECTURE D'UN OCTET AVEC SDMO
* Le registre B n'est pas preserve
* Valeur de l'octet dans le registre A en sortie
*------------------------------------------------------
RBYTEMO
* premier bit
  LDB   #$36           clear bit 3               (2)
  STB   <$C2           clock low                 (4) 
  LDB   #$7F           Valeur pour test bit 7    (2)
  STB   <$C2           clock high                (4)
  CMPB  <$C0           PA b7 (bit lu) -> carry   (4)
  ROLA                 C (bit lu) -> b0 reg A    (2)
* deuxieme bit
  LDB   #$36           clear bit 3               (2)
  STB   <$C2           clock low                 (4) 
  LDB   #$7F           Valeur pour test bit 7    (2)
  STB   <$C2           clock high                (4)
  CMPB  <$C0           PA b7 (bit lu) -> carry   (4)
  ROLA                 C (bit lu) -> b0 reg A    (2)
* troisieme bit
  LDB   #$36           clear bit 3               (2)
  STB   <$C2           clock low                 (4) 
  LDB   #$7F           Valeur pour test bit 7    (2)
  STB   <$C2           clock high                (4)
  CMPB  <$C0           PA b7 (bit lu) -> carry   (4)
  ROLA                 C (bit lu) -> b0 reg A    (2)
* quatrieme bit
  LDB   #$36           clear bit 3               (2)
  STB   <$C2           clock low                 (4) 
  LDB   #$7F           Valeur pour test bit 7    (2)
  STB   <$C2           clock high                (4)
  CMPB  <$C0           PA b7 (bit lu) -> carry   (4)
  ROLA                 C (bit lu) -> b0 reg A    (2)
* cinquieme bit
  LDB   #$36           clear bit 3               (2)
  STB   <$C2           clock low                 (4) 
  LDB   #$7F           Valeur pour test bit 7    (2)
  STB   <$C2           clock high                (4)
  CMPB  <$C0           PA b7 (bit lu) -> carry   (4)
  ROLA                 C (bit lu) -> b0 reg A    (2)
* sixieme bit
  LDB   #$36           clear bit 3               (2)
  STB   <$C2           clock low                 (4) 
  LDB   #$7F           Valeur pour test bit 7    (2)
  STB   <$C2           clock high                (4)
  CMPB  <$C0           PA b7 (bit lu) -> carry   (4)
  ROLA                 C (bit lu) -> b0 reg A    (2)
* septieme bit
  LDB   #$36           clear bit 3               (2)
  STB   <$C2           clock low                 (4) 
  LDB   #$7F           Valeur pour test bit 7    (2)
  STB   <$C2           clock high                (4)
  CMPB  <$C0           PA b7 (bit lu) -> carry   (4)
  ROLA                 C (bit lu) -> b0 reg A    (2)
* huitieme bit
  LDB   #$36           clear bit 3               (2)
  STB   <$C2           clock low                 (4) 
  LDB   #$7F           Valeur pour test bit 7    (2)
  STB   <$C2           clock high                (4)
  CMPB  <$C0           PA b7 (bit lu) -> carry   (4)
  ROLA                 C (bit lu) -> b0 reg A    (2)
*
  RTS                  retour (octet dans A)     (5)

* longueur totale avec BSR: 7 + 18*8 + 5 = 156
*                avec LBSR: 9 + 18*8 + 5 = 158

*------------------------------------------------------
* PAUSE (touche ESPACE)    
*------------------------------------------------------
PAUSE
  LDX    #$0000        compteur de boucle      
PAUSE1
  LEAX   -1,X          decrementation compteur
  BNE    PAUSE1        nouvelle boucle
PAUSE2
  LDA    #$40          touche espace
  STA    <$C1          selection touche
  LDA    <$C1          test touche
  BMI    PAUSE2        touche relachee
PAUSE3
  LEAX   -1,X          decrementation compteur
  BNE    PAUSE3        nouvelle boucle
  RTS                  retour 

*------------------------------------------------------
* RETOUR RAPIDE (fleche gauche)    
*------------------------------------------------------
BACK
  LDX    #$0000        compteur de boucle      
BACK1
  LEAX   -1,X          decrementation compteur
  BNE    BACK1         nouvelle boucle
  RTS

*------------------------------------------------------
* AVANCE RAPIDE (fleche droite)    
*------------------------------------------------------
FWD
  LDX    #$0000        compteur de boucle      
FWD1
  LEAX   -1,X          decrementation compteur
  BNE    FWD1          nouvelle boucle
  RTS

*------------------------------------------------------
* Test appui sur une touche (TO8) 50 cycles avec le BSR   
*------------------------------------------------------
KEYT8 
  LDA    <$C8          etat clavier            (4)
  LSRA                 b0 --> carry            (2)
  BCS    KEYT82                                (3)    
  LDB    #$05          compteur de boucles     (2) 
KEYT81      
  DECB                 decremente le compteur  (2)
  BNE    KEYT81        nouvelle boucle         (3)
  NOP                  temporisation           (2) 
  RTS                  retour                  (5)
KEYT82
  JMP    TO8K          traitement de la touche  
KEYT89

*------------------------------------------------------
* Traitement d'une touche TO8
*------------------------------------------------------
TO8K
  ANDCC  #$AF          active les interruptions
TO8K1
  LDA    <$C8          etat clavier
  LSRA                 b0 --> carry
  BCS    TO8K1         attente touche relachee
TO8K2
  LDA    <$C8          etat clavier
  LSRA                 b0 --> carry
  BCC    TO8K2         attente touche enfoncee
TO8K3
  LDA    <$C8          etat clavier
  LSRA                 b0 --> carry
  BCS    TO8K3         attente touche relachee
  ORCC   #$50          masque les interruptions
  RTS                  retour 

*------------------------------------------------------
* DIVISION NSECT PAR 512 POUR LES CARTES SD
*------------------------------------------------------
DIV512
  TST    [SD_TYP]      test du type de carte 
  BNE    DIV999        carte SDHC
* octets de poids faible
  LDD    NSECT+1       octets de poids faible
  LSRA                 division
  RORB                 par deux  
  STD    NSECT+2       decalage d'un octet 
* octets de poids fort
  CLRA                 premier octet de poids fort
  LDB    NSECT         deuxieme octet de poids fort
  LSRB                 division par deux
  STD    NSECT         octets de poids fort
  BCC    DIV999        pas de retenue
* report de la retenue
  LDA    NSECT+2        
  ORA    #$80
  STA    NSECT+2
DIV999   
  RTS 

*------------------------------------------------------
* MULTIPLICATION NSECT PAR 512 POUR LES CARTES SD
*------------------------------------------------------
MUL512
  TST    [SD_TYP]      test du type de carte 
  BNE    MUL999        carte SDHC
* octets de poids fort
  LDD    NSECT+1       octets de poids fort
  LSLB                 multiplication
  ROLA                 par deux
  STD    NSECT         decalage d'un octet 
* octets de poids faible
  CLRB                 deuxieme octet de poids faible
  LDA    NSECT+3       premier octet de poids faible
  LSLA                 multiplication par deux
  STD    NSECT+2       octets de poids faible
  BCC    MUL999
* report de la retenue
  LDA    NSECT+1        
  ORA    #$01
  STA    NSECT+1
MUL999
  RTS

*------------------------------------------------------
* CALCUL DU SECTEUR DE DEBUT DE LA MUSIQUE A JOUER
*------------------------------------------------------
OFFSET
  LDA    NSECT+3       lecture 4e octet
  ADDA   #$05          nombre de secteurs decalage 
  STA    NSECT+3       ecriture 4e octet 
  LDA    NSECT+2       lecture 3e octet
  ADCA   #$00          ajout de la retenue 
  STA    NSECT+2       ecriture 3e octet 
  LDA    NSECT+1       lecture 2e octet
  ADCA   #$00          ajout de la retenue 
  STA    NSECT+1       ecriture 2e octet 
  LDA    NSECT         lecture 1er octet
  ADCA   #$00          ajout de la retenue 
  STA    NSECT         ecriture 1er octet 
  RTS
    
*------------------------------------------------------
* REMPLACEMENT DE LA ROUTINE KEYTST POUR MO
* PAR LA ROUTINE KEYT8 POUR TO8
*------------------------------------------------------
RKEYT8
  LDY   #KEYT8         adresse routine KEYT8   
  LDX   #KEYTST        adresse routine KEYTST
RKEYT1
  LDB   ,Y+            lecture routine KEYT8
  STB   ,X+            ecriture routine KEYTST
  CMPY  #KEYT89        test de fin
  BNE   RKEYT1         nouvelle boucle
  RTS                  retour

*------------------------------------------------------
* REMPLACEMENT DE LA ROUTINE RBYTE POUR SDMOTO
* PAR LA ROUTINE RBYTEMO POUR SDMO
*------------------------------------------------------
RBSDMO
  LDY   #RBYTEMO       adresse routine SDMO   
  LDX   #RBYTE         adresse routine RBYTE
RBSDMO1
  LDB   ,Y+            lecture routine SDMO
  STB   ,X+            ecriture routine RBYTE
  CMPX  #RBYTEMO       test de fin
  BNE   RBSDMO1        nouvelle boucle
  RTS                  retour

  ORG   $9FFF
  FCB   $00            pour remplir 3 secteurs complets  

  END
Daniel
L'obstacle augmente mon ardeur.
Répondre