IAGentic

Journal de veille sur l'usage appliqué de l'IA, chez soi et en entreprise : ce qu'on lui fait faire, ce qu'il faut pour commencer, ce que ça coûte et où ça casse.

outil

nesformer exécute un CPU NES dans les poids de Qwen 3.5

Drew Breunig met en ligne le 30 octobre 2026 nesformer, un dépôt qui loge le processeur 6502 de la NES, ses 2 Ko de mémoire vive et les 32 Ko de ROM d'une cartouche dans un point de contrôle Qwen3.5 de 466,6 millions de paramètrespoids du modèleNombre de valeurs apprises par un modèle. À quantification égale, plus de paramètres veut dire plus de mémoire occupée, et en général de meilleures réponses.Fiche du lexique. Aucun poids n'a été entraîné : un compilateur les calcule, et le modèle prédit le journal d'exécution du processeur un tokenPlus petite unité de texte qu'un modèle manipule. Un mot courant tient souvent en un seul, un mot rare se découpe en plusieurs morceaux. Les prix, les limites et les débits s'expriment en tokens, pas en mots.Fiche du lexique à la fois. Les trois jeux de test libres sortent identiques à un émulateur de référence, image pour image, à 150 à 290 fois la lenteur de la console d'origine.

par Gyom 31 octobre 2026 à 07:21 5 min de lecture rubrique : Code

etiquettes : Local · Coût

Une manette de jeu filaire vue de face, croix directionnelle à gauche et quatre boutons colorés à droite, dessinée au trait d'encre sur fond crème.

L'idée vient de Qwenputer, de Divyansh Agrawal, qui avait compilé un processeur CHIP-8 puis un cœur RISC-V dans un Qwen3.5-4B. nesformer reprend son compilateur, chipformer, et change de machine : le 6502 de la NES compte 151 opcodes officiels, un registre de statut à sept indicateurs, une pile, et il doit tenir une cadence que lui impose une puce graphique que le modèle ne simule pas. Le dépôt est publié sous licence MIT, et le compilateur comme deux fichiers du projet restent couverts par la licence MIT de Qwenputer.

151 opcodes dans sept couches à état DeltaNet

Le point de contrôle est un Qwen3_5ForCausalLM ordinaire, qui se charge par from_pretrained et ne demande aucun code maison : sept couches Gated DeltaNet portent le circuit, plus une couche d'attention entièrement nulle que le cache de Hugging Face exige. La taille cachée est de 768, le vocabulaire de 263 808 tokens. Le fichier totalise 466,6 millions de paramètres en bf16, soit 933 Mo, dont 9,3 millions seulement sont non nuls, ce qui ramène l'archive des poids à 3,3 Mo.

La mémoire tient dans l'état récurrent. Chaque tête DeltaNet garde une matrice de 128 sur 128 que la règle delta met à jour à chaque token. Avec la porte ouverte et une clé en un seul point, une mise à jour écrase exactement une ligne de cette matrice, et une requête en un seul point relit cette ligne. Chaque ligne devient donc une cellule de mémoire, et la cartouche, la mémoire vive et les registres logent dans ces lignes. Le fichier nesformer.json note quelle couche et quelle tête portent quelle partie de la machine.

Ce que l'hôte garde, et ce que le modèle ne voit jamais

Le processeur graphique, la puce audio et la manette restent dans un programme hôte. Il dessine une ligne d'image à la fois, lit la manette, et injecte dans le flux ce que le processeur attend de l'extérieur : un token NMI à chaque retour de trame, un token IN pour chaque lecture d'entrée-sortie, et les 256 octets d'un transfert DMA d'attributs sous forme de tokens DM. L'hôte ne voit ni les registres ni la mémoire vive du processeur autrement que par le journal d'exécution.

1,1 à 1,3 token par instruction

Chaque instruction produit un enregistrement, et le dernier token de l'enregistrement le valide. Le compteur ordinal n'est pas écrit : chaque token final porte la longueur de son instruction, trois compteurs DeltaNet totalisent les instructions de chaque longueur depuis le dernier saut, et le compteur ordinal se reconstitue en ajoutant ce total à la cible du saut. Un JSR pousse son adresse de retour dans le circuit, un STA indexé indirect lit ses deux octets de pointeur avant d'écrire. La plupart des instructions tiennent en un token, et le code de jeu réel tourne entre 1,1 et 1,3 token par instruction.

1 650 tokens par seconde sur un cœur, pour 700 000 nécessaires

Le moteur par défaut calcule la passe avant de Qwen3.5 depuis le fichier safetensors, compilé avec numba et en sautant les blocs nuls : environ 1 650 débittokens par secondeNombre de tokens produits par seconde en génération. Avec le temps d'attente du premier token, c'est le chiffre qui dit si un modèle est utilisable au quotidien sur une machine donnée.Fiche du lexique sur un cœur de processeur, contre 210 pour le moteur numpy et une dizaine pour transformers standard. Une vraie NES demanderait environ 700 000 tokens par seconde. Les jeux passent l'essentiel de chaque image dans une boucle qui attend le retour de trame ; quand l'hôte voit le corps de cette boucle se répéter sans écrire en mémoire ni en entrée-sortie, il avance l'horloge jusqu'au prochain événement d'affichage, ce qui divise le nombre de tokens par 2,6 à 4,2. Il en sort une console simulée 150 à 290 fois plus lente que l'originale, une image toutes les une à six secondes, et environ vingt-cinq minutes pour dix secondes de jeu.

Trois jeux de test identiques à un 6502 de référence

La vérification se fait en quatre étages. Le processeur de référence, écrit en Python, suit le journal de référence de nestest sur 3 348 instructions et l'émulateur py65 sur 5,7 millions d'instructions de code de jeu. Le circuit, exécuté dans l'évaluateur de Qwenputer avec ses contrôles d'exactitude en bf16, prédit chaque token de référence sur nestest et sur 283 610 positions des séquences de démarrage de deux jeux. Le point de contrôle chargé dans transformers standard, en bf16 sur processeur, prédit 2 651 positions sans écart.

Puis les poids tournent librement : 1 916 527 tokens pour 600 images de Thwaite, soit dix secondes de temps NES, et 2 645 885 tokens pour 420 images de Full Game. Les journaux sont identiques à ceux du processeur de référence, et les 300 images sauvegardées de Thwaite comme les 210 de Full Game aussi. Le saut de boucle d'attente, ajouté pour la vitesse, ne change rien de visible : images et écritures d'entrée-sortie se comparent à l'identique, horodatages de cycles compris.

Pas de mappeur, pas d'IRQ, pas de son

Les cartouches NROM seulement, c'est-à-dire le mappeur 0 d'iNES : le processeur n'adresse que 32 Ko de ROM à la fois, et un jeu plus gros porte une puce de commutation de bancs que le modèle ne sait pas suivre, parce que ses lectures de ROM se font dans une table fixe. Les opcodes non officiels et les sauts dans la mémoire vive émettent un token HALT. Les IRQ de la puce audio et du DMC manquent, BRK et NMI fonctionnent. Le rendu ligne par ligne ne reproduit pas les effets en cours de ligne, la collision du sprite zéro et le débordement de sprites restent approximatifs, et aucun son n'est produit. Supporter un mappeur demanderait de loger toute la ROM dans l'état, d'y garder les registres de banque, et d'ajouter une étape qui traduit chaque adresse du processeur en adresse de ROM.

Le dépôt ouvre la voie à autre chose qu'un jeu : le 6502 est un processeur documenté jusqu'à l'opcode, avec un journal de référence public, ce qui donne un banc de mesure rare pour l'exécution de code dans des poids. Une machine dont on ne connaît pas le comportement exact ne se vérifie pas de cette manière, image pour image et instruction pour instruction.

Source primaire dbreunig/nesformer, « An NES CPU compiled into the weights of a stock Qwen3.5 model », dépôt GitHub, 30 octobre 2026

Retour au journal