; SMILENGHEADER ; COMMENT This is the Smile NG file header, do not modify! ; VERSION 1.0 ; PROC CALM ;---------------------------------------------------+ ; | ; Petit programme qui écrit sur le LCD graphique | ; | ;---------------------------------------------------+ ;========================================================================= ; NOTE ; POUR PASSER DES CARACTÈRES ASCII À T6963, IL SUFFIT DE SOUSTRAIRE ; 20h AU CODE ASCII ;========================================================================= .PROC z80 .BASE 10'16 jump start ; on va au début du programme ; Définition des constantes ; Constantes LCD graphique ; Ecran 240x128 pixels ; mode 8x8 ; 30 colonnes x 16 lignes THA = 40 ; text home address set TA = 41 ; text area set GHA = 42 ; graphic home address set GA = 43 ; graphic area set OFFSET = 22 ; offset register set ADPSET = 24 ; address pointer set AWRON = 0B0 ; Autowrite ON AWROFF = 0B2 ; Autowrite OFF ; Constantes LCD texte .BASE 10'2 ; ========================================= ; CONSTANTES LCD (instructions) ZERO = 0 FINIT = 00110000 ; Valeur d'initialisation FSET = 00111000 ; Function SET (8 bits, char 5x8 px) DISP = 00001100 ; Display ON, Cusror OFF, Blink OFF ; Pour avoir le curseur : DISP+1 CLRDSP = 00000001 ; Efface l'écran, remet à la position initiale EMSET = 00000110 ; Entry Mode Set (fin de l'initialisation) PAHAUT = 10000000 ; Page/rangée supérieure de l'écran PABAS = 11000000 ; Page/rangée inférieure de l'écran BUSY = 10000000 ; Masque pour vérifier l'état du flag busy (qui est sur D7) ; ========================================= .BASE 10'16 ; ========================================= ; Adresses de l'écran graphique SCRDAT = 0C0 SCRCMD = 0C1 ; Adresses de l'écran texte LCDWRI = 40 LCDWRD = 41 LCDRDI = 42 LCDRDD = 43 ; Adresse MUBUS MUBWR = 0 ; Adresse du sommet de la pile du soft RAMTOP = 7FFF ; Variables CU = 4100 CD = 4110 SU = 4120 SD = 4130 MU = 4140 MD = 4150 ;========================================= ; initialisation start: ;création de la pile au sommet de la RAM (évite des bugs avec l'utilisation de zones réservées dans la RAM) ioff ; désactive les interruptions move #RAMTOP,SP ; place le pointeur de pile au sommet de la ram im1 ; met le mode d'interruptions 1 call initlcd ; initialise l'écran texte debut: move #LONG3,B ; longueur du message move #msg3,HL call wrstr ; on passe à la ligne call carret move #LONG4,B ; longueur du message move #msg4,HL call wrstr ; Fixe les adresses de départ pour le texte et les graphiques move #0000,HL ; text home address = 0h call dt2 move #THA,A call cmd move #0200,HL ; graphic home address = 500h call dt2 move #GHA,A call cmd ; Défini la largeur d'écran move #001E,HL ; zone texte de 30 colonnes call dt2 move #TA,A call cmd move #001E,HL ; zone graphique de 30 colonnes call dt2 move #GA,A call cmd ; Défini le mode d'affichage move #80,A ; mode OR call cmd ; Set OFFSET register move #0002,HL call dt2 move #OFFSET,A call cmd ; Mode d'affichage (texte ON, Graphics OFF, Curseur OFF) move #94,A call cmd call cls ; on efface l'écran ; On écrit un petit texte quand même :) move #0040,HL ; Pointeur sur la 3è ligne 5è colonne call dt2 move #ADPSET,A call cmd move #AWRON,A call cmd ; Autowrite ON move #LONGG1,B ; 22 caractères move #msgg1,DE call lcdstr ; Même chose avec le deuxième message move #007F,HL ; Pointeur sur la 5è ligne 8è colonne call dt2 move #ADPSET,A call cmd move #AWRON,A call cmd ; Autowrite ON move #LONGG2,B ; 16 caractères move #msgg2,DE call lcdstr call tempo_lcd call tempo_lcd call tempo_lcd ; On laisse le temps de lire le message call cls ; on efface l'écran ; Mode d'affichage (texte OFF, Graphics ON, Curseur OFF) move #98,A call cmd move #0200,HL ; Pointeur au départ call dt2 move #ADPSET,A call cmd move #AWRON,A call cmd move #0F00,BC ; 30 colonnes x 128 pixels = 3840 = 0F00h move #pict1,DE ; Adresse de base de l'image call lcdgraph call tempo_lcd ; On affiche le dessin call tempo_lcd call tempo_lcd ; On laisse le temps de lire le message move #0A7,A call cmd ; Cusreur 1 ligne ; On affiche l'horloge ; Mode d'affichage (texte ON, Graphics OFF, Curseur ON, Blink ON) move #97,A call cmd move #97,A call cmd call cls move #0A0,A call cmd ; Cusreur 1 ligne move #0000,HL ; Pointeur sur la 1ère ligne 1ère colonne call dt2 move #ADPSET,A call cmd move #AWRON,A call cmd ; Autowrite ON move #LONGG3,B move #msgg3,DE call lcdstr move #0A7,A call cmd ; Cusreur 1 ligne call tempo_lcd call tempo_lcd call tempo_lcd ; On affiche TIME lentement!!! =) move #34,A ; T move #0C0,B ; Incrémente le pointeur call lcdchr call tempo_lcd move #29,A ; I move #0C0,B ; Incrémente le pointeur call lcdchr call tempo_lcd move #2D,A ; M move #0C0,B ; Incrémente le pointeur call lcdchr call tempo_lcd move #25,A ; E move #0C0,B ; Incrémente le pointeur call lcdchr call tempo_lcd call tempo_lcd ; Affiche sur la console le soft aussi call clrscr move #LONG5,B ; longueur du message move #msg5,HL call wrstr call carret move #LONG6,B ; longueur du message move #msg6,HL call wrstr ; Mode d'affichage (texte ON, Graphics OFF, Curseur OFF) move #94,A call cmd ; On affiche le "programme" :p move #003C,HL ; Pointeur sur la 3è ligne 1ère colonne call dt2 move #ADPSET,A call cmd move #AWRON,A call cmd ; Autowrite ON move #LONGG4,B ; 16 caractères move #msgg4,DE call lcdstr move #00A0,HL ; Pointeur sur la 6è ligne 12ème colonne call dt2 move #ADPSET,A call cmd ; Programme d'horloge ici move #10,A move A,CU move A,CD move A,SU move A,SD move A,MU move A,MD move CU,A ; 0 move #0C0,B ; Incrémente le pointeur call lcdchr move CD,A ; 0 move #0C0,B ; Incrémente le pointeur call lcdchr move #1A,A ; : move #0C0,B ; Incrémente le pointeur call lcdchr move SU,A ; 0 move #0C0,B ; Incrémente le pointeur call lcdchr move SD,A ; 0 move #0C0,B ; Incrémente le pointeur call lcdchr move #1A,A ; : move #0C0,B ; Incrémente le pointeur call lcdchr move MU,A ; 0 move #0C0,B ; Incrémente le pointeur call lcdchr move MD,A ; 0 move #0C0,B ; Incrémente le pointeur call lcdchr move #11,A move A,CU move A,CD move A,SU move A,SD move A,MU move A,MD jump centu1 centu: move #00A0,HL ; Place le pointeur call dt2 move #ADPSET,A call cmd move #10,A move A,MD ; remet les dizaines à 0 move #0C4,B ; n'incrémente pas le pointeur call lcdchr move MD,A inc A move A,MD centu1: move #00A7,HL ; Place le pointeur call dt2 move #ADPSET,A call cmd cent1: move CU,A comp #1A,A ; >9 ? jump,EQ centd ; oui on fait les dizaine move #0C4,B ; n'incrémente pas le pointeur move CU,A call lcdchr ; Affiche le chifffre move CU,A inc A ; incrémente move A,CU ; sauve en mémoire push AF move #7,A batt: call attente2 dec A jump,NE batt pop AF jump cent1 ; boucle centd: move #00A7,HL ; Place le pointeur call dt2 move #ADPSET,A call cmd move #10,A move A,CU ; remet les unités à 0 move #0C4,B ; n'incrémente pas le pointeur call lcdchr ; Affiche le chifffre move CU,A inc A move A,CU move #00A6,HL ; Place le pointeur call dt2 move #ADPSET,A call cmd centd1: move CD,A comp #1A,A ; >9 ? jump,EQ secu ; oui on fait les secondes unité move #0C4,B ; n'incrémente pas le pointeur move CD,A call lcdchr move CD,A inc A move A,CD jump centu1 ; boucle secu: move #00A6,HL ; Place le pointeur call dt2 move #ADPSET,A call cmd move #10,A move A,CD ; remet les unités à 0 move #0C4,B ; n'incrémente pas le pointeur call lcdchr ; Affiche le chifffre move CD,A inc A move A,CD move #00A4,HL ; Place le pointeur call dt2 move #ADPSET,A call cmd secu1: move SU,A comp #1A,A ; >9 ? jump,EQ secd ; oui on fait les secondes dizaine move #0C4,B ; n'incrémente pas le pointeur move SU,A call lcdchr move SU,A inc A move A,SU jump centu1 ; boucle secd: move #00A4,HL ; Place le pointeur call dt2 move #ADPSET,A call cmd move #10,A move A,SU ; remet les unités à 0 move #0C4,B ; n'incrémente pas le pointeur call lcdchr ; Affiche le chifffre move SU,A inc A move A,SU move #00A3,HL ; Place le pointeur call dt2 move #ADPSET,A call cmd secd1: move SD,A comp #16,A ; >5 ? jump,EQ minu ; oui on fait les minutes unités move #0C4,B ; n'incrémente pas le pointeur move SD,A call lcdchr move SD,A inc A move A,SD jump centu1 ; boucle minu: move #00A3,HL ; Place le pointeur call dt2 move #ADPSET,A call cmd move #10,A move A,SD ; remet les unités à 0 move #0C4,B ; n'incrémente pas le pointeur call lcdchr ; Affiche le chifffre move SD,A inc A move A,SD move #00A1,HL ; Place le pointeur call dt2 move #ADPSET,A call cmd minu1: move MU,A comp #1A,A ; >9 ? jump,EQ mind ; oui on fait les minutes dizaine move #0C4,B ; n'incrémente pas le pointeur move MU,A call lcdchr move MU,A inc A move A,MU jump centu1 ; boucle mind: move #00A1,HL ; Place le pointeur call dt2 move #ADPSET,A call cmd move #10,A move A,MU ; remet les unités à 0 move #0C4,B ; n'incrémente pas le pointeur call lcdchr ; Affiche le chifffre move MU,A inc A move A,MU move #00A0,HL ; Place le pointeur call dt2 move #ADPSET,A call cmd mind1: move MD,A comp #16,A ; >5 ? jump,EQ centu ; oui on fait les centièmes unité move #0C4,B ; n'incrémente pas le pointeur move MD,A call lcdchr move MD,A inc A move A,MD jump centu1 ; boucle fin: nop jump fin ;========================================= ; Sous routines ;========================================= ; Routines du LCD graphique ; Routine d'écriture de commande ; Entrée : commande en A ; Sortie : rien ; Modifie : rien cmd: push AF cmd1: move $SCRCMD,A and #3,A comp #3,A ; vérifie les bits de status jump,NE cmd1 pop AF move A,$SCRCMD ; écrit la commande ret ; Routine d'écriture avec un octet de donnée ; Entrée : data en A ; Sortie : rien ; Modifie : rien dt1: push AF dt11: move $SCRCMD,A and #3,A comp #3,A ; vérifie les bits de status jump,NE dt11 pop AF move A,$SCRDAT ; écrit la donnée ret ; Routine c'écriture avec deux octets de donnée ; Entrée : data en HL ; Sortie : rien ; Modifie : A dt2: move $SCRCMD,A and #3,A comp #3,A ; vérifie les bits de status jump,NE dt2 move L,A move A,$SCRDAT ; écrit la donnée de poids faible dt21: move $SCRCMD,A and #3,A comp #3,A ; vérifie les bits de status jump,NE dt21 move H,A move A,$SCRDAT ; écrit la donnée de poids fort ret ; Routine du mode écriture automatique ; Entrée : data en A ; Sortie : rien ; Modifie : rien adt: push AF adt1: move $SCRCMD,A and #8,A comp #8,A ; vérifie les bits de status jump,NE adt1 pop AF move A,$SCRDAT ; écrit la donnée ret ; Routine qui efface l'écran ; Entrée : rien ; Sortie : rien ; Modifie :A cls: ; On rempli l'écran de texte blanc (autrement dit, on l'efface!) push HL move #0000,HL ; Pointeur au départ call dt2 move #ADPSET,A call cmd move #AWRON,A call cmd move #01E0,BC ; 30 colonnes x 16 lignes = 480 = 1E0h txcr: move #0,A call adt dec BC move B,A comp #0,A jump,NE txcr move C,A comp #0,A jump,NE txcr move #AWROFF,A ; fin de l'autowrite call cmd pop HL ret ; Routine qui affiche une chaîne de caractères sur l'écran graphique ; Requiert d'être en mode texte !!! ; Entrée : - longueur de la chaîne en B, adresse de la chaîne en DE ; - Avoir activé le mode autowrite avec ce code : ; move #AWRON,A ; call cmd ; Autowrite ON ; Sortie : - rien ; modifie : - A,B,DE lcdstr: move {DE},A ; écrit le texte sub #20,A ; conversion code T6963 call adt inc DE DJ,NE B,lcdstr move #AWROFF,A call cmd ret ; Routine qui affiche un caractère sur l'écran graphique et incrémente/décrémente/ne bouge pas le pointeur ; Requiert d'être en mode texte !!! ; Entrée : - caractère en A, commande en B ; Sortie : - rien ; modifie : - A,B lcdchr: push AF lchr1: move $SCRCMD,A and #3,A comp #3,A ; vérifie les bits de status jump,NE lchr1 pop AF move A,$SCRDAT ; écrit le caractère lchr2: move $SCRCMD,A and #3,A comp #3,A ; vérifie les bits de status jump,NE lchr2 move B,A move A,$SCRCMD ; écrit la commande (incrément/écrément/ne bouge pas) ret ; Routine qui dessine sur l'écran graphique ; Requiert d'être en mode graphique !!! ; Entrée : - longueur du graphe en BC, adresse du dessin en DE ; - avoir activé le mode autowrite avec ce code : ; move #AWRON,A ; call cmd ; Autowrite ON ; Sortie : - rien ; Modifie : - A,BC,DE lcdgraph: move {DE},A call adt inc DE dec BC move B,A comp #0,A jump,NE lcdgraph move C,A comp #0,A jump,NE lcdgraph move #AWROFF,A ; fin de l'autowrite call cmd ret ;========================================= ; Routines du LCD texte ;Initialisation de l'écran LCD initlcd: move #ZERO,A move A,$LCDWRI move #FSET,A move A,$LCDWRI call attente call attente call attente call attente call attente call attente call attente call attente call attente call attente move #FSET,A move A,$LCDWRI call attente call attente ;---------------------------------------------- move #FSET,A move A,$LCDWRI call attente call attente ;---------------------------------------------- move #FSET,A move A,$LCDWRI call attente call attente ;---------------------------------------------- move #DISP,A move A,$LCDWRI call attente call attente ;---------------------------------------------- move #CLRDSP,A move A,$LCDWRI call attente call attente ;---------------------------------------------- move #EMSET,A move A,$LCDWRI call attente call attente ;---------------------------------------------- move #PAHAUT,A move A,$LCDWRI call attente call attente ;---------------------------------------------- ; message de fin, le périphérique est correctement initialisé move #LONG1,B ; longueur du message move #msg1,HL call wrstr ; on passe à la ligne call carret ; on écrit la 2è ligne du message d'accueil move #LONG2,B ; longueur du message move #msg2,HL call wrstr ; tempo pour lire le message call tempo_lcd call clrscr ret ;========================================= ;========================================= ; Lecture du bit busy ; ATTENTION ROUTINE BUGUEE !!!! ; Tant qu'il est à 1, le LCD n'est pas prêt, dès qu'il passe à 0, on peut continuer ; méthode la plus rapide pour perdre le moins de temps possible lors d'écriture waitlcd: push AF wlcd: move $LCDRDI,A and #BUSY,A ; si le BF est à 0, on peut écrire sinon on ne peut pas. jump,zc wlcd ; jump Zero Clear / si c'est à 0 c'est fini sinon on boucle pop AF ret ;========================================= ;========================================= ; écriture d'une chaîne de caractère sur le LCD ; entrée ; - Longueur de la chaine de caractères en B ; - Adresse du début de la chaine en HL ; sortie : - rien ; modifie: - A, B, HL wrstr: move {HL},A ; acquérir le byte move A,$LCDWRD ; sortie du caractère sur l'écran call attente call attente inc HL ; pointage sur le caractère suivant dec B jump,ne wrstr ; boucle jusqu'à ce que tous les caractères soient affichés ret ;========================================= ;========================================= ; écriture d'un caractère sur le LCD ; entrée ; - adresse où se trouve le caractère dans HL ; sortie : - rien ; modifie: - A, HL wrchr: call attente call attente move {HL},A move A,$LCDWRD ret ;========================================= ;========================================= ; lecture d'un caractère sur le LCD ; entrée ; - adresse où sera copié le caractère en HL ; - adresse écran où se trouve le chr dans B ; sortie : - le caractère est copié où pointe HL ; modifie: - A, HL rdchr: call attente call attente ; on pointe où on va lire sur l'écran push AF move B,A move A,$LCDWRI pop AF call attente call attente ; on lit et on copie move $LCDRDD,A move A,{HL} ret ;========================================= ;========================================= ; lecture d'une chaîne de caractères sur le LCD ; entrée ; - adresse où sera copié le caractère en HL ; - adresse écran où se trouve le début de la chaîne dans B ; - longueur de la chaîne de caractères dans C ; sortie : - la chaine est copiée à partir d'où pointe HL ; modifie: - A, C, HL rdstr: call attente call attente ; on pointe où on va lire sur l'écran push AF move B,A move A,$LCDWRI pop AF rdstr1$: call attente call attente ; on lit et on copie move $LCDRDD,A move A,{HL} inc HL dec C move C,A comp #1,A jump,ne rdstr1$ ret ;========================================= ;========================================= ;carriage return ; entrée ; - rien ; sortie : - rien ; modifie - rien carret: push AF move #PABAS,A move A,$LCDWRI pop AF call attente call attente ret ;========================================= ;========================================= ;Clrear Screen : efface l'écran et repositionne au départ ; entrée : - rien ; sortie : - rien ; modifie : - rien clrscr: push AF move #CLRDSP,A move A,$LCDWRI pop AF call attente call attente ret ;========================================= ;========================================= ; Routines de temporisation ;Boucle d'attente ; Nombre de cycles ; call : 17 ; push AF : 11 ; move I,A : 7 ; pop : 10 ; ret : 10 ; 55 ; Boucle (256x) ; dec A : 4 ; jump, cc,I : 10 ; 3584 ; Total : 3639 ; Temps : à 2.5 MHz : 1.4556 ms ; à 5 MHz : 727.8 us attente: push AF move #0FF,A a$: dec A jump,ne a$ pop AF ret ; Temporisation de précision attente2: push AF move #0F0,A b$: dec A jump,ne b$ pop AF ret ; Temporisation longue, pour avoir le temps de lire le message sur l'écran LCD tempo_lcd: push AF move #0FF,A lect1: call attente dec A jump,ne lect1 move #0FF,A lect2: call attente dec A jump,ne lect2 move #0FF,A lect3: call attente dec A jump,ne lect3 pop AF ret ; Fin des sous routines ;========================================= ;========================================= ; Messages ; Lcd texte msg1: .ascii "LCD display" msg1fin: nop LONG1 = msg1fin-msg1 msg2: .ascii "ready!" msg2fin: nop LONG2 = msg2fin-msg2 msg3: .ascii "LCD console" msg3fin: nop LONG3 = msg3fin-msg3 msg4: .ascii "Version 2.22b" msg4fin: nop LONG4 = msg4fin-msg4 msg5: .ascii "TIME version 1.1" msg5fin: nop LONG5 = msg5fin-msg5 msg6: .ascii "FS22-647 pOS 0.1" msg6fin: nop LONG6 = msg6fin-msg6 ; Lcd graphique msgg1: .ascii "- FS22-647 zCOMPUTER -" msgg1f: nop LONGG1 = msgg1f-msgg1 msgg2: .ascii "Zilog inside z80" msgg2f: nop LONGG2 = msgg2f-msgg2 msgg3: .ascii "A:\>" msgg3f: nop LONGG3 = msgg3f-msgg3 msgg4: .ascii "Real time clock by Gilbert =)" msgg4f: nop LONGG4 = msgg4f-msgg4 ;Avant de programmer l'EPROM, ajouter ici le code de l'image bitmap qui sera affichée au boot. pict1: .data.8.8 55,0AA