dimanche 8 novembre 2026

COSMAC elf+, partie 5

COSMAC ELF+, partie 5

Clavier hexadécimal et programme elf+Mon

Entrer des programmes avec les toggles switches ce n'est vraiment pas pratique, ça use la patience. L'ajout d'un clavier hexadécimal et d'un programme moniteur facilite grandement le travail. J'ai donc construit une carte d'extention sur laquelle j'ai déplacé le haut-parleur et ajouter un clavier hexadécimal.

Le clavier est encodé en utilisant un CI spécialisé le 74C922 spécifiquement conçu pour cette tâche. Un octal D-Lach 74HC373 interface cet encodeur au bus de donnée du elf+.

test du clavier


00  F8 FF       LDI FF      ; initialise R2 comme pointeur de pile
02  A2          PLO R2      ; à la fin de la mémoire RAM
03  B2          PHI R2      ; R2 = $FFFF
04  E2          SEX R2      ; R2 devient le pointeur de pile 
05  3C 05       BN1 05      ; attend pour une touche
07  69          INP KEY 
08  64          OUT DISPLAY
09  22          DEC R2 
0A  34 0A       B1  0A      ; attend le relachement de la touche
0C  30 05       BR  05

Le moniteur

Le clavier hexadécimal contrairement aux toggles switches requière un programme pour être utilisé. Le programme EHOPS écrit par Joseph Weisbecker pour le 3ième article consacré au COSMAC ELF paru dans Popular electronics de mars 1977 m'a servi de modèle.

                        ; elf+ Monitor  
                        ; Version 0.1 
                        ; Adaptation du programme de Joseph Weisbecker
                        ; paru dans le Popular electronics de mars 1977
                        ; 
                        ; R0 registre de travail 
                        ; R1 registre contenant l'adresse
                        ; R2 pointeur de donnée pour GETKEY 
                        ; R3 programme principal 
                        ; R5 GETBYTE 
                        ; R6 GETKEY
                        ; elf+ Monitor reconnaît 3 commandes 
                        ; la commande est sélectionnée par les toggles switches
                        ; 0 aaaa, Exécute le programme à l'adresse $aaaa
                        ; 1 aaaa, Modifie la mémoire débutant à l'adresse $aaaa
                        ; 2 aaaa, Examine la mémoire débutant à l'adresse $aaaa 
                        ; Un programme peut retourner au moniteur 
                        ; en faisant un saut long à l'adresse $0000
                        ; NOTES:
                        ;     1)puisque elf+ a plus que 256 octets de mémoire 
                        ;       le programme est modifié pour accepter des 
                        ;       adresses de 16 bits (4 chiffres hexadécimals)
                        ;     2) La switch IN est utilisé pour la commande 01 
                        ;        pour passé à l'adresse suivante.
                        ;
.ORG 0000
INIT:
00  F8 FF       LDI FF        ; initialise R2 comme pointeur de donnée
02  A2          PLO R2        ; à la fin de la mémoire RAM
03  B2          PHI R2        ; R2 = $FFFF
04  F8 00       LDI  00       ; La partie haute des registres R3,R5,R6 
06  B3          PHI  R3       ; doit-être initialisée à 0. 
07  B5          PHI  R5       ;
08  B6          PHI  R6       ;
09  F8 13       LDI MAIN.0    ; partie basse de la procédure MAIN 
0B  A3          PLO R3        ; R3=MAIN 
0C  F8 2D       LDI GETBYTE.0 ; partie basse de la procédure GETBYTE      
0E  A5          PLO R5        ; R5=GETBYTE
0F  F8 3C       LDI GETKEY.0  ; partie basse de GETKEY 
11  A6          PLO R6        ; R6=GETKEY 
12  D3          SEP R3        ; exécute la routine MAIN 

MAIN:                         ; routine principale
13  D5          SEP GETBYTE   ; appel GETBYTE, obtient adresse high
14  B1          PHI R1        ; R1.1=aa_hi 
15  D5          SEP GETBYTE   ; appel GETBYTE, obtient adresse low 
16  A1          PLO R1        ; R1.0=aa_lo 
17  6C          INP TOGGLES   ; lecture des toggles switches D=op_code 
18  3A 1B       BNZ MOD_EXAM  ; si D <> 0 commande 1 ou 2 
1A  D1          SEP R1        ; code d'opération 00, execute le programme 
                              ; dont l'adresse est dans R1 
MOD_EXAM:                     ; code 01 or 02 ?
1B  F6          SHR D         ; D = D/2 
1C  3B 24       BNF EXAMINE   ; si DF = 0 alors code 02, examine mémoire 
MODIFY:                       ; code d'opération 01 
1E  D5          SEP GETBYTE   ; appel GETBYTE.
1F  E1          SEX R1        ; R1 devient le pointeur de donnée.
20  51          STR M(R1)     ; dépose D à l'adresse M(R1)
21  64          OUT M(R1)     ; affiche M(R1) et R1=R1+1 
22  30 1E       BR MODIFY     ; boucle à MODIFY 
EXAMINE:                      ; code d'opération 02
24  E1          SEX R1        ; R1 devient le pointeur de donnée.         
WAIT_IN_DN:
25  3F 25       BN4 WAIT_IN_DN  ; attend que le bouton IN soit enfoncé
27  64          OUT DISPLAY   ; affiche l'octet en mémoire, R1=R1+1
                              ; Délais anti rebond sur switch IN 
28  37 28       B4 WAIT_IN_UP ; attend que le bouton IN soit relaché 
2A  30 25       BR WAIT_IN_DN ; boucle à EXAMINE 

GB_EXIT:        
2C  D3          SEP MAIN      ; sortie de GETBYTE
GETBYTE:                      ; lecture de 2 touches du clavier
2D  D6          SEP GETKEY    ; appel  GETKEY, 1ière touche  
2E  FE FE       SHL SHL       ; décale D 2 fois à gauche 
30  FE FE       SHL SHL       ; décale D 2 fois à gauche
32  A0          PLO R0.0      ; dépose D dans R0.0   
33  D6          SEP GETKEY    ; appel GETKEY, 2ième touche
34  80          PLO R0.0      ; D=R0.0
35  F1          OR            ; D=D OR M(R2) 
36  52          STR M(RX)     ; M(RX)=D 
37  64          OUT DISPLAY   ; affiche l'octet saisie R2=R2+1
38  22          DEC R2 
39  30 2C       BR GB_EXIT    ; 
                
GK_EXIT:        
3B  D5          SEP GETBYTE   ; retourne à GETBYTE
GETKEY:                       ; lecture du clavier hexadécimal
3C  E2          SEX R2        ; R2 devient le pointeur de donnée.       
WAIT_KD:
3D  3C 3D       BN1 WAIT_KD   ; attend qu'un touche soit enfoncée.
3F  69          INP 1         ; lecture de la valeur
WAIT_KR:
40  34 40       B1  WAIT_KR   ; attend que la touche soit relachée
42  30 3B       BR  GK_EXIT   ; saut vers GK_EXIT 
44

  

Ce programme permet d'utiliser le clavier hexadécimal pour modifier la mémoire, examiner son contenu et exécuter un programme. Il n'utilise que 68 octets de mémoire. Il est sauvergardé dans l'EEPROM AT27C64B et est donc conservé lorsque l'ordinateur est éteint. Il s'exécute automatiquement lorsque la switch RUN est mise à ON. Il y a 3 codes d'opérations:

  • 00, Exécute un programme. Le programme démarre sitôt que son adresse a été entrée au clavier.
  • 01, Modifie le contenu de la mémoire. Après avoir entrée l'adresse de départ tous les octets suivant entré au clavier son mis en mémoire et le pointeur de mémoire est déplacé à l'adresse suivante.
  • 02, Examine le contenu de la mémoire. Une fois l'adresse de départ entrée au clavier, chaque pression sur le bouton IN affiche le contenu de cette adresse et le pointeur passe à l'adresse suivante.
On sélectionne le code sur les toggles switches avant de mettre la switch RUN à ON. Ensuite on entre l'adresse de départ sur le clavier hexadécimal. Il s'agit d'une adresse de 16 bits (2 octets). Chaque fois qu'un octet est entré au clavier sa valeur est affiché.

Démonstration du moniteur elf+Mon version 0.1

vendredi 30 octobre 2026

COSMAC elf+, partie 4

COSMAC ELF+, partie 4

Variation sur un thème

Le programme suivant génère une tonalité dont la fréquence est contrôlée par la valeur des toggles switches.

tone3.asm


                            ; Cette version de TONE lit les toggle switches 
                            ; comme paramètre de délais pour la sous-routine 
                            ; DELAY 
                            ; R0  compteur ordinal routine MAIN 
                            ; R3  compteur ordinal sous-routine DELAY  
                            ; RF  compteur de délais  

INIT:
00  F8 FF       LDI FF      ; initialise R2 comme pointeur de pile
02  A2          PLO R2      ; à la fin de la mémoire RAM
03  B2          PHI R2      ; R2 = $FFFF
04  E2          SEX R2      ; R2 devient le pointeur de pile 
05  F8 00       LDI DELAY.1 ; initialisation de R3 
07  B3          PHI R3      ; à l'adresse de DELAY 
08  F8 13       LDI DELAY.0  
0A  A3          PLO R3      ; R3 <- adresse de DELAY $000D

TONE:                       ; génération d'une tonalité sur Q 
0B  7B 7B       SEQ SEQ     ; Q = 1 
0D  D3          SEP R3      ; appel sous-routine DELAY 
0E  7A          REQ         ; Q = 0 
0F  D3          SEP R3      ; appel sous-routine DELAY
10  30 0B       BR  TONE    ;boucle à TONE 

EXIT:                       ; sortie de la sous-routine 
12  D0          SEP R0      ; retourne au programme MAIN  
DELAY:                      ; entrée sous-routine DELAY 
13  6C          IN  TOGGLES ; initialise le compteur de délais, D=toggles 
14  64          OUT DISPLAY ; par la lectures des toogles switches
15  22          DEC R2      ; R2=R2-1
16  AF          PLO  RF.0   ; RF.0=D
17  F8 00       LDI  0      ; D = 0
19  BF          PHI  RF     ; RF.1 = 0 
LOOP:                       ; décrémente RF tant que RF.1==0 
1A  2F          DEC RF      ; RF = RF-1 
1B  9F          GHI RF      ; D = RF.1 
1C  32 1A       BZ LOOP     ; SI D=0 retourne à LOOP 
1E  30 12       BR EXIT     ; délais terminé
20


lundi 26 octobre 2026

COSMAC elf+, partie 3

COSMAC ELF+, partie 3

Ajout de petite carte avec un haut-parleur pour produire des tonalités en commutant la sortie Q du MCU.

Comme on le voie sur le schéma du côté droit, j'ai ajouté un haut-parleur contrôlé par un transistor MOSFET 2N7000, lui-même étant contrôlé par la sortie Q du MCU. Comme il n'y avait pas d'espace sur la carte du elf+ j'ai fait le montage sur une petite carte qui se branche sur la carte mère du elf+.

démonstration

code du programme


                        ; R0  compteur ordinal routine MAIN 
                        ; R3  compteur ordinal sous-routine DELAY  
                        ; RF  compteur de délais  
MAIN:
0   F8 00   LDI DELAY.1 ; initialisation de R3 
2   B3      PHI R3      ; à l'adresse de DELAY 
3   F8 0D   LDI DELAY.0  
5   A3      PLO R3      ; R3 <- adresse de DELAY $000D

TONE:                   ; génération d'une tonalité sur Q 
6   7B      SEQ         ; Q <- 1 
7   D3      SEP 3       ; appel sous-routine DELAY 
8   7A      REQ         ; Q <- 0 
9   D3      SEP 3       ; appel sous-routine DELAY
A   30 06   BR  06      ;boucle à TONE 

EXIT:                   ; sortie de la sous-routine 
C   D0      SEP 0       ; retourne au programme MAIN  
DELAY:                  ; entrée sous-routine DELAY 
D   F8 4F   LDI  4F     ; initialise le compteur de délais 
F   AF      PLO  RF.0   ; RF.0 <- 4F
10  F8 00   LDI  0      ; D <- 0
12  BF      PHI  RF     ; RF.1 <- 0 
LOOP:                   ; décrémente RF tant que RF.1==0 
13  2F      DEC RF      ; RF <- RF-1 
14  9F      GHI RF      ; D <- RF.1 
15  32 13   BZ LOOP     ; SI D=0 retourne à LOOP 
17  30 0C   BR EXIT     ; délais terminé


Calcul du compteur de DELAY

Pour calculer le délais à mettre dans le registre RF
compte=Freq_osc/(Freq_audio*8*6*2) -1 -16/6

  • compte est la valeur d'initialisation du registre RF
  • Freq_audio est la fréquence audio à générer
  • Freq_osc est la fréquence du cristal utilisé pour le CDP1802
  • 8 parce qu'un cycle machine est 8 périodes de Freq_osc
  • 6 parce que la boucle LOOP s'exécute en 6 cycles machines
  • 2 parce que la sous-routine DELAY est appellée 2 fois par cycle audio.
  • -1 parce que la boucle de délais s'exécute 1 fois même si compte=0
  • -16/6 parce qu'il y a 16 cycles machines qui s'exécutent en dehors de la boucle LOOP par demi-cycle audio et qu'on doit soustraire ces cycles du nombre de répétions de LOOP
Donc pour générer une fréquence audio de 500 hertz avec un cristal de 4Mhz
compte=4e6/(500*8*6*2) -1 -16/6 = 79.6666, tronqué à 79, ce qui correspond à 4F en hexadécimal. La fréquence réelle mesurée à l'oscilloscope est de 502.9 hertz.

vidéo