Site logo

Triceraprog
La programmation depuis le Crétacé

  • VG5000µ, une Cartographie de la Mémoire BASIC ()

    Quand j'ai commencé à étudier les documentations sur le VG5000µ, des incohérences sur certains points me sont apparues. Les différentes sources ne donnaient pas les même renseignements. Ou alors je lisais mal. Mais un truc ne collait pas.

    En étudiant la ROM, là encore, ça ne collait pas avec les documentations. Mais le code ne ment pas, j'ai donc débuté une quête de la vérité : que se passe-t-il vraiment ?

    ... ce n'était peut-être pas si épique, mais bon...

    L'anomalie qui m'intéresse aujourd'hui est celle de la gestion de la mémoire par le BASIC. Et voici les pièces qui ont provoqué mon étonnement.

    Première pièce

    La manuel de l'utilisateur, page 46, indique que le premier paramètre de la commande définit la totalité de l'espace occupé par les chaînes de caractères et doit être compris entre -32768 et 32767. Spécifier une mémoire à réserver négative est un peu étrange, et un test rapide montre que passer une valeur négative est rejetée par le BASIC.

    Au passage, un coup d'œil dans la ROM montre que l'instruction CLEAR utilise une routine qui ne décode que des entiers positifs...

    Plus étonnant, le second paramètre, qui indique la plus haute adresse possible atteignable par le BASIC doit être inférieur à 32767 pour le VG5000 standard, et 42864 pour l'extension mémoire 16ko. Et ne mentionne pas 32ko d'extension.

    42864... Ça ne correspond pas à grand chose. Avec l'extension 16ko, je vois plutôt une adresse maximale à 49151. En effet, la ROM prend les 16 premiers ko, et les 16+16 ko de RAM sont à la suite. 48 * 1024 donne 49152 octets.

    Bref, louche. De plus, un essai direct d'un CLEAR 50, 42864 ne fonctionne pas, un paramètre invalide est indiqué. La routine pour décoder le second paramètre étant une routine qui prend des entiers entre -32768 et 32767.

    Une cartographie de la mémoire page 86 indique que la mémoire peut bien aller jusqu'à 49151, qu'il faut spécifier cette valeur en complément à 2 sous une forme négative. C'est incohérent avec la description de CLEAR mais l'expérience montre que la cartographie a raison. Elle indique aussi des valeur de pointeur (stktop), (fretop), (arytab) et (txttab), mais n'indique pas où les trouver.

    Deuxième pièce

    La deuxième source est « Clefs pour VG5000 », un livre des éditions du P.S.I.

    Page 15, la description de CLEAR est globalement reprise avec les mêmes renseignements erronés.

    Page 69, une cartographie de la mémoire est disponible et indique des noms de variables pointeurs sur des zones mémoire. Plus loin, ces variables systèmes sont décrites, avec leurs adresses. C'est par ici que j'avais commencé à regarder le fonctionnement.

    Deux choses me paraissaient bizarre. Une flèche entre arytab et fretop sans nom. Soit. Mais aussi une variable fretop qui est sous la pile. C'est bizarre car le bas de la pile, c'est déjà le registre SP, quel intérêt de garder une information comme ça ? Pour protéger la pile ?

    C'est cependant cohérent avec le manuel d'utilisateur et donne une information en plus sur le fait que (memsiz) n'est pas initialisé tout en haut de la RAM disponible mais trois octets avant. Il ajoute une variable de système : (vartab).

    C'est à ce moment là que j'ai commencé à étudier la ROM et voir que (fretop) était initialisé avec la valeur (memsiz), et que lors d'allocation de chaînes de caractères, l'algorithme partait du principe que (fretop) était toujours supérieur à (stktop).

    En fait, l'erreur d'allocation de chaîne était lancée, si je ne me trompais pas (mais le doute est permis quand on regarde des pages de code assembleur), lorsque (fretop) atteignant (stktop) par le haut. Autrement dit, tant que (fretop)-(stktop) était positif, il y avait de la place. Je détaille ça plus loin.

    Et donc, ça ne collait pas avec le schéma.

    Les descriptions des variables sont les suivantes :

    • $488E : adresse de début du programme Basic (txttab)
    • $4895 : Adresse du haut de la pile (stktop)
    • $49C3 : adresse du haut de la zone "chaînes" (fretop)
    • $49D8 : adresse de début de la zone "variables" (vartab)
    • $49DA : adresse de début de la zone "chaînes" (arytab) (c'est incohérent d'après le schéma, mais on se doute bien que ary signifie array est qu'il s'agit en fait de la zone pour les tableaux DIM)
    • $49DC : adresse de fin du stockage en cours, n'est pas nommé. Je ne le savais pas à ce moment-là, mais il s'agit de (strend) et c'est le nom qu'il manque entre (arytab) et (fretop)... il faut dire que la description n'est pas hyper parlante. Quel stockage ? En cours de quoi ?

    Troisième pièce

    Le troisième document dans lequel je me suis plongé est celui du manuel technique, en anglais. Page 6, on trouve le tableau source des deux précédents documents., mais là encore, (fretop) est sous la pile...

    Plus loin, page 9, la liste des variables systèmes, là encore probablement la source du livre P.S.I, est donné. On y trouve (txttab), (stktop), (fretop), (vartab), (arytab) avec sa description correcte mentionnant des tableaux, et (fretop), et (strend) indiquant « end of storage in use ».

    La description de (strend) est un peu plus éclairante que sa traduction dans le livre P.S.I, même si ça manque de détail. Il n’apparaît pas dans la cartographie de la mémoire.

    Il n'y a pas d'autres mentions du fonctionnement des allocations mémoire dans ce document, à part un peu à propos de manipulation de (txttab) et (vartab) quand on veut lancer un programme BASIC depuis un ROM d'extension.

    Quatrième pièce

    De tous les documents sur le VG5000µ, les plus dignes de confiances, ceux qui vont un peu plus dans le détail et dans lesquels je n'ai jamais trouvé d'erreur jusqu'à maintenant, ce sont les « Technical Bulletin** ». Sur celui du 14 juin 1984, à propos de « BASIC Text Relocation » il est mentionné que (strend) sera bougé, avec (vartab), (arytab) et (temp), si (txttab) est modifié et que le BASIC exécute une des routines qui replace tout ça.

    Pas tellement plus d'information cependant.

    Dans le bulletin du 11 septembre 1984, une mention de (stktop) et (memsiz) est fait, qui donne les bonnes adresses en fonction des différentes configuration de mémoire.

    Au final...

    Au final... et bien le mieux est d'aller voir dans la ROM ce qu'il se passe. Et pour chercher, je pars sur deux pistes : où donc est-ce que (fretop) est utilisé, et qu'est-ce que (strend) ?

    (fretop) est utilisé a de nombreux endroits, mais quelques-uns de ses usages sont suffisant pour comprendre.

    L’initialisation

    La fonction suivante est appelé lorsqu'il s'agit de réinitialiser la mémoire. Au lancement de la machine, par un appel à NEW, mais aussi directement en reset_vars lors d'un RUN ou en init_vars lors d'un CLEAR.

    reset_mem:   ld       hl,(txttab)          ; $2ed9
    reset_mem_2: xor      a,a
                 jp       reset_mem_3
    
    reset_mem_4: inc      hl
                 ld       (vartab),hl
    reset_vars:  ld       hl,(txttab)
                 dec      hl
    init_vars:   ld       (temp),hl
                 ld       hl,(memsiz)
                 ld       (fretop),hl
                 xor      a,a
                 call     inst_restore
                 ld       hl,(vartab)
                 ld       (arytab),hl
                 ld       (strend),hl
    

    Tout commence avec comme point de repère (txttab), qui est le début du programme BASIC en cours.

    Le jp reset_mem_3 renvoie en reset_mem_4 après avoir coupé le lien sur la première ligne de BASIC, effaçant par la même occasion l'accès au programme (qui est toujours là...).

    Cette gymnastique avec reset_mem_3, qui n'est jamais appelé par ailleurs, vient à mon avis du patch de la ROM 1.1, qui fait tout pour rester stable dans les adresses de routines. Je vérifierai cette théorie plus tard.

    (vartab) est placé deux octets plus loin que (txttab) (HL est aussi incrémenté par le code de reset_mem_3)

    (temp) est placé un octet avec (txttab)

    (fretop) est initialisé à la même adresse que (memsiz), ce qui montre bien que, au moins là, les cartographie mémoire sont fausses.

    L'appel à inst_restore est l'exécution de l'instruction RESTORE du BASIC, qui va chercher et stocker la première ligne contenant des DATA.

    Puis enfin, (arytab) et (strend) prennent la valeur de (vartab).

    Un peu plus loin, les lignes suivantes remettent le registre SP à l'adresse en haut de sa zone, stockée dans (stktop).

                 ld       hl,(stktop)          ; $2eff
                 ld       sp,hl
    

    La conclusion sur l’initialisation de la mémoire est que les adresses de références sont (txttab), (memsiz) et (stktop). Les autres pointeurs sont placés en fonction de ces adresses.

    Vérification mémoire de chaînes

    Lorsqu'une chaîne de caractère est sur le point d'être créé, la routine suivante est appelée en premier lieu :

                 ld       hl,(stktop)          ; $36bf
                 ex       de,hl
                 ld       hl,(fretop)
                 cpl
                 ld       c,a
                 ld       b,$ff
                 add      hl,bc
                 inc      hl
                 rst      de_compare
                 jr       c,out_str_mem
    

    À l'entrée de cette routine, A contient le nombre de caractères de la chaîne à créer.

    Après les trois premières lignes, on se retrouve avec (stktop) dans DE et (fretop) dans HL. Les trois lignes suivantes mettent dans BC l'inverse de A (en complément à 2).

    Via le add, HL contient donc (fretop) moins le nombre de caractères dont on a besoin, (le inc qui suit est la correction de la soustraction en complément à 2).

    rst de_compare est une routine qui compare les valeurs de HL et DE, si HL est inférieur à DE, alors le flag Carry est levé, ce qui provoque le saut qui suit vers l'erreur indiquant qu'il n'y a pas assez de mémoire dans l'espace réservé aux chaînes de caractères.

    Ce qui est important ici, c'est que ce calcul montre que (fretop) doit être supérieur à (stktop). Ce qui montre encore que les schémas sont faux.

    FRE(" ")

    Dernière vérification, histoire d'être vraiment certain, en analysant la fonction FRE(" "). Cette commande avec une chaîne en paramètre n'est pas documentée dans le manuel d'instruction, mais on la trouve dans les « bulletins ».

    Lorsque FRE a un paramètre numérique (peu importe lequel), la fonction renvoie la place restante en mémoire BASIC... pour tout ce qui n'est pas stockage des caractères de chaînes.

    Avec un paramètre alphanumérique, FRE renvoie l'espace restant dans la mémoire réservée aux caractères.

    Et en voici le code :

    inst_fre:    ld       hl,(strend)          ; $38b1
                 ex       de,hl
                 ld       hl,$0000
                 add      hl,sp
                 ld       a,(valtyp)
                 or       a,a
                 jp       z,inst_fre_2
                 call     gstrcu
                 call     call36e3
                 ld       de,(stktop)
                 ld       hl,(fretop)
                 jp       inst_fre_2
    
    inst_fre_2:  ld       a,l
                 sub      a,e
                 ld       c,a
                 ld       a,h
                 sbc      a,d
    

    Tout commence en plaçant (strend) dans DE (via HL). Puis en mettant SP dans HL (via le add).

    (valtyp) contient le type de l'expression qui vient d'être évaluée. À l'appel d'une fonction, il s'agit de la valeur du paramètre. Si cette valeur est numérique (= 0), la suite se passe en inst_fre_2 où le résultat de l'opération HL - DE est mis dans le couple de registres A et C.

    Au passage, notons que la mémoire restante est calculée comme la différence entre le pointeur de pile courant et (strend), ce qui permet de situer correctement la fonction de (strend) comme marquant la fin (adresse haute) du stockage BASIC « listing + variables + tableaux ».

    Si l'expression était alphanumérique, alors il y a deux appels (dont un auquel je n'ai pas encore donné de nom) qui permettent d'appeler le ramasse miettes (Garbage Collection) sur les chaînes de caractères. Passons.

    Puis (stktop) est placé dans DE et (fretop) dans HL, avant d'effectuer le même calcul que précédemment HL - DE.

    Ce qui montre à nouveau que (fretop) doit être supérieur à (stktop) et qui indique même que cet espace correspond à la zone de mémoire libre pour les chaînes. Autrement dit, (fretop) présente l'adresse la plus basse des chaînes de caractères, toutes stockées au-dessus. Le nom a probablement provoqué la confusion de sa description comme étant l'adresse du haut, mais c'est en fait une zone qui croît vers le bas.

    En donc ?

    (fretop) est un pointeur qui est valide entre (memsiz) et (stktop). L'espace entre (memsiz) et (stktop) est déterminé par le premier paramètre de CLEAR et (memsiz) est déterminé par le second paramètre de CLEAR.

    Et grâce à ces informations, nous pouvons cartographier, la mémoire avec ses pointeurs de manière correcte et complète, du moins je l'espère.

    Cartographie Mémoire VG5000µ


  • Récréation 3D, Z80 du VG5000µ ()

    Deux ans déjà que j'avais créé quelques modèles 3D... Le temps passe vite. Et l'envie m'a repris.

    Voici donc une petite recréation du Z80 présent dans le VG5000µ. Fait depuis des images et je ne suis donc pas complètement certains des mesures. J'irai vérifier la prochaine fois que j'en démonte un, si j'y pense.

    Z80 présent dans le VG5000µ

    Update: nouvelle version, corrigée avec des dimensions DIP plus correctes (mais le boitier du SGS est plat... ça fait donc un mélange)

    Z80 présent dans le VG5000µ


  • Bonne Année 2019 ! ()

    Bonjour à tous. Cette année, j'espère pouvoir faire aboutir un projet autour du VG5000µ que j'ai commencé il y a longtemps et que j'avance petit pas par petit pas.

    En attendant, je vous souhaite :

    10 B$="AAHGGGGGCB00A@GGGGCBCB00998898=<10"
    20 LB=LEN(B$)
    30 FOR I=1 TO LB STEP 2
    40 A=ASC(MID$(B$,I,1))+ASC(MID$(B$,I+1,1))-64
    50 PRINT CHR$(A);
    60 NEXT I
    

    À essayer sur votre ancienne machine sous BASIC préférée. Ça devrait être portable sur à peu près toutes les machines avec interpréteur BASIC et des capactités par trop limitées sur les chaînes de caractères (adieu ZX81...). Sur certains, il faudra ajouter LET aux lignes 10, 20 et 40 pour les assignations de variable.


  • VG5000µ, ajouter des instructions au BASIC ? ()

    Il y a quelques temps, un message sur le forum Config.cfg demandait s'il était simple ou même possible d'ajouter des instructions supplémentaires à la ROM d'un VG5000µ. C'est une question que je me posais aussi, avec dans l'idée d'ajouter des instructions graphiques utilisant l'implémentation des articles précédents].

    J'ai donc continué à étudier la ROM (que je commence à bien connaître maintenant) à la recherche d'une méthode. Et on va voir que ça n'est pas gagné.

    Le parseur

    Lorsque la touche RET du clavier est appuyée, il se passe plusieurs choses. Tout d'abord, un caractère NUL (valeur 0) est placé dans le buffer d'entrée à l'emplacement du dernier caractère qui n'est pas un espace (adresses $3c4a à $3c56). Le RET à la fin de cette fonction ramène hors de la boucle principal du traitement interactif.

    Après un traitement de la protection de programmes qui n'est pas le sujet ici, une fonction cherche si la ligne commence par un numéro de ligne puis débute la transcription de la ligne vers une ligne « tokenisée ». La procédure de tokénisation, en bref, va repérer toutes les instructions, fonctions et opérations connues et les transformer en « tokens » : un octet dont le bit de poids fort est à 1.

    Un token permet de prendre moins de place en mémoire et facilite le travail de l'évaluateur.

    La procédure saute bien entendu les chaînes de caractères en repérant les paires de guillemets.

    Je laisse de côté le traitement de caractères à significations particulières (le ? qui remplace PRINT comme dans la plupart des BASIC par exemple) pour arriver à la recherche principale. Cette routine, qui commence globalement en $23a5, va comparer le contenu des caractères à décoder (en les passant en majuscules si nécessaire) avec une liste de noms et symboles dans une table située en $23a7.

    Premier problème, cette liste est figée. Si aucune correspondance n'est trouvée, la routine ne dispose pas de hook pour passer la main à une éventuelle liste gérée par l'utilisateur. Les caractères sans correspondance sont laissés tels quels dans le buffer. Si plus tard, à l'évaluation, ces caractères n'ont pas de sens (ne désignent pas une variable par exemple), une erreur sera émise.

    On pourrait alors imaginer se servir d'un autre hook, celui qui est appelé à chaque affichage de caractère ($47e2) ou celui qui est appelé lors d'un retour à la ligne (\$47e5), afin d'ajouter un parsing à la main. Mais pour cela, il faudrait choisir des tokens libres pour les nouvelles instructions ; ce qui amène à étudier les tokens.

    Les tokens

    Voici la liste des tokens avec leurs valeurs.

    Commandes Support - Opérateurs Fonctions
    128:END 178:TAB( 185:+ 195:SGN
    129:FOR 179:TO 186:- 196:INT
    130:NEXT 180:FN 187:* 197:ABS
    131:DATA 181:SPC( 188:/ 198:USR
    132:INPUT 182:THEN 189:^ 199:FRE
    133:DIM 183:NOT 190:AND 200:LPOS
    134:READ 184:STEP 191:OR 201:POS
    135:LET 192:> 202:SQR
    136:GOTO 193:= 203:RND
    137:RUN 194:< 204:LOG
    138:IF 205:EXP
    139:RESTORE 206:COS
    140:GOSUB 207:SIN
    141:RETURN 208:TAN
    142:REM 209:ATN
    143:STOP 210:PEEK
    144:ON 211:LEN
    145:LPRINT 212:STR$
    146:DEF 213:VAL
    147:POKE 214:ASC
    148:PRINT 215:STICKX
    149:CONT 216:STICKY
    150:LIST 217:ACTION
    151:LLIST 218:KEY
    152:CLEAR 219:LPEN
    153:RENUM 220:CHR$
    154:AUTO 221:LEFT$
    155:LOAD 222:RIGHT$
    156:SAVE 223:MID$
    157:CLOAD
    158:CSAVE
    159:CALL
    160:INIT
    161:SOUND
    162:PLAY
    163:TX
    164:GR
    165:SCREEN
    166:DISPLAY
    167:STORE
    168:SCROLL
    169:PAGE
    170:DELIM
    171:SETE
    172:ET
    173:EG
    174:CURSOR
    175:DISK
    176:MODEM
    177:NEW

    On peut remarquer que cette liste comporte plusieurs parties. La première, de 128 à 177, contient des instructions, c'est-à-dire des commandes impératives, sans valeur de retour.

    De 178 à 184, il s'agit de commandes de support, qui ne peuvent être trouvées qu'en conjonction de commandes maîtresses. Par exemple THEN avec IF ; TO et STEP avec FOR,...

    De 185 à 194, il s'agit d'opérateurs logiques et arithmétiques. Enfin, à partir de 195 jusqu'à la fin, 223, il s'agit de fonctions, qui retournent des valeurs, et qui apparaîtrons donc, au côté des opérateurs, dans des expressions.

    On commence à sentir que s'il fallait ajouter des mot-clés, en fonction de leur nature, il faudrait les placer dans le bon groupe. Sauf que cette liste est compacte. On peut imaginer ajouter des fonctions après MID$, mais ajouter une instruction ou un opérateur décalerait toute la table, ce qui poserait un problème de compatibilité au moins avec les programmes enregistrés (les programmes BASIC enregistrés le sont sous forme tokenisée).

    L'évaluateur

    C'est donc vers l'évaluateur qu'il faut se tourner et se demander comment sont traitées les lignes en BASIC. Et c'est là que vient se planter le dernier clou dans le cercueil de l'ajout de commandes utilisateurs... du moins sans modifier la ROM.

    Tout d'abord, examinons le décodage des tokens en $250f.

                 sub      a,$80
                 jp       c,inst_let           ; Comme tous les tokens sont supérieurs ou égaux
                                               ; à $80, si le caractère est inférieur, c'est le début du nom d'une variable.
                                               ; C'est un LET implicite.
    
                 cp       a,$32
                 jp       nc,stx_err_prt       ; Les 50 ($32) premiers tokens seulement sont des instructions
                                               ; Si le token est après, alors c'est une Erreur de syntaxe.
    

    Voilà... la ROM contient en dur les bornes des instructions pouvant être décodées.

    Et ce n'est pas fini. Lorsque l'on regarde l'évaluation d'expression en $28d8 :

                 xor      a,a
                 ld       (valtyp),a           ; Type numérique par défaut
                 rst      chget
                 jp       z,missing_op         ; Cas où le caractère est NUL
                 jp       c,str_to_num         ; Cas où le caractère est un chiffre.
                 cp       a,$26
                 jp       z,str_hex_dec        ; Saut si sur le point de parser un nombre en hexa (caractère '&')
                 call     a_to_z_2
                 jr       nc,str_to_var        ; Saut si la valeur est entre A et Z
                 cp       a,$b9                ; Token pour '+'
                 jr       z,parse_value
                 cp       a,$2e                ; Caractère '.'
                 jp       z,str_to_num
                 cp       a,$ba                ; Token pour '-'
                 jr       z,str_to_min
                 cp       a,$22                ; Caractère '"'
                 jp       z,str_to_str
                 cp       a,$b7                ; Token pour 'NOT'
                 jp       z,str_to_not
                 cp       a,$b4                ; Token pour 'FN'
                 jp       z,str_to_fn
                 sub      a,$c3                ; Token pour 'SGN', la première des fonctions
                 jr       nc,str_to_func
    

    Afin de déterminer le type de valeur à décoder, un certain nombre de tokens est là aussi en dur.

    Et donc ?

    Et donc tel quel, la ROM ne fourni pas de mécanisme d’extension pour écrire de nouvelles instructions. D'autre part, même s'il reste une trentaine de tokens libres à la fin de la liste, les constantes dans le parseur et dans l'évaluateur exigent que les tailles des groupes du tableau soient respectés.

    Reste la possibilité de modifier la ROM pour ajouter les nouvelles instructions, ce qui n'est pas très compliqué, mais qui nécessitera de la conversion au chargement pour être compatible avec des programmes en BASIC enregistrés sur K7.


  • VG5000µ, Schémas de principe ()

    Le schéma de principe scanné depuis la documentation de maintenance trouvée sur le site My VG5000 et reconstitué du VG5000µ m'a souvent aidé à comprendre le fonctionnement de cette machine. Et je remercie l'auteur de ce travail !

    Pour contribuer à mon tour à la documentation VG5000µ, j'ai refait les schémas de la platine principale et de la platine k7 au propre, afin d'en augmenter la lisibilité.

    Quelques commentaires :

    • j'ai ajouté en précision les broches non branchées du Z80 et de l'EF9345. Cela montre rapidement les choix hardware du VG5000µ qui ne seront pas contournables sans modification du matériel.

    • j'ai utilisé les nomenclatures des datasheets des composants, ce qui change un peu la nomenclature originale.

    • j'ai gardé la disposition générale du schéma, pour ne pas perdre les habitués, mais il peut y avoir quelques changements dans le détail, lorsque je pensais pouvoir améliorer la lisibilité.

    • j'ai modifié les marquages des portes logiques vers une nomenclature en toute lettre ; par contre, je n'ai aucune idée de la nomenclature officiel pour un Buffer, j'ai mis BUF en attendant.

    • une porte AND, en sortie des deux portes NAND du 7812 n'avait pas de marquage sur le schéma originel, j'ai retrouvé le composant en suivant le schéma d'implantation (ce n'était pas trop compliqué, puisque qu'il n'y a qu'un seul composant qui fourni des portes AND, mais au moins, c'est vérifié)

    • le schéma original comporte la plupart des signaux en anglais, sauf quelques-uns (genre RVB), j'ai gardé RVB sur les sorties mais changé en RGB sur la nomenclature EF9345, comme sur la datasheet.

    • De même il y a un mélange COMMUT.RAPIDE mais SOUND sur la sortie vidéo, j'ai tout unifié en français.

    • Mais du coup, j'ai des signaux en anglais sur la sortie SON/K7...

    Merci à tous les commentateurs du fil de discussion sur System.cfg qui m'ont permis d'améliorer les schémas.

    La platine principale

    Image cliquable pour une version en haute définition. (mise à jour 29 avril 2021)

    Platine principale

    La platine K7/Son

    Image cliquable pour une version en haute définition. (mise à jour 9 sept. 2018)

    Platine K7/Son

    Note

    Le schéma a été mis à jour dans un nouvel article.


« (précédent) Page 16 / 26 (suivant) »

Tous les tags

3d (15), 6502 (10), 6809 (1), 8bits (1), Affichage (24), AgonLight (2), Altaïr (1), Amstrad CPC (1), Apple (1), Aquarius (2), ASM (30), Atari (1), Atari 800 (1), Atari ST (2), Automatisation (4), BASIC (31), BASIC-80 (4), C (3), Calculs (1), CDC (1), Clion (1), cmake (1), Commodore (1), Commodore PET (1), Compression (4), CPU (1), Debug (5), Dithering (2), Divers (1), EF9345 (1), Émulation (7), Famicom (7), Forth (13), Game Jam (1), Hector (3), Histoire (1), Hooks (4), Huffman (1), i8008 (1), Image (17), Jeu (15), Jeu Vidéo (4), Livre (1), Logo (2), LZ (1), Machine virtuelle (2), Magazine (1), MAME (1), Matra Alice (3), MDLC (7), Micral (2), Motorola (1), MSX (1), Musée (2), Nintendo Switch (1), Nombres (3), Optimisation (1), Outils (3), Pascaline (1), Peertube (1), PHC-25 (2), Photo (2), Programmation (15), Python (1), RLE (1), ROM (15), RPUfOS (6), Salon (1), SC-3000 (1), Schéma (5), Synthèse (15), Tortue (1), Triceraprog (1), VG5000 (62), VIC-20 (1), Vidéo (1), Z80 (21), z88dk (1), ZX0 (1)

Les derniers articles

Forth sur 6502, épisode 10
Forth sur 6502, épisode 9
Forth sur 6502, épisode 8
Forth sur 6502, épisode 7
Forth sur 6502, épisode 6
Forth sur 6502, épisode 5
Forth sur 6502, épisode 4
Forth sur 6502, épisode 3
Forth sur 6502, épisode 2
Forth sur 6502, épisode 1

Atom Feed

Réseaux