PROCESSEUR 16bits ~100Hz + outils de programmation - 1.14

Discussion dans 'Redstone et Command blocks' créé par Régis Laspalès, 15 Avril 2019.

  1. Régis Laspalès

    Inscrit:
    16 Février 2014
    Messages:
    1 916
    J'aime reçus:
    375
    Salut, quand je suis en vacances je perds toujours mon temps à jouer à factorio ou à construire des ordinateurs dans minecraft, cette fois c'était les ordinateurs.

    100Hz ???? Mais dans minecraft la plus petite durée est le tick, et il y en a 20 par seconde et ça fait 20Hz au max !!! Comment c'est possible ??!!

    Une chaîne de command blocks s’exécute en un tick, peu importe sa longueur. Mais un command block ne peut être exécuté qu'une seule fois par tick, sauf si on le débride en modifiant le tag "UpdateLastExecution". On peut alors faire autant de choses qu'on veut (enfin presque) dans le même tick avec un peu de magie et une utilisation abusive de la commande /clone.

    En gros, à chaque tick l'unité de contrôle charge l'instruction qu'il faut exécuter mais aussi les 4 ou 5 suivantes (ou autant qu'on veut c'est juste qu'à partir de 4 mon jeu commence à ramer). Elles sont alors toutes exécutées dans le même tick mais quand il y a un saut les instructions chargées ne sont plus les bonnes, on passe au tick suivant pour recharger les bonnes (ça a les mêmes limitations qu'une pipeline pour ceux qui connaissent). Donc si on fait exécuter les instructions 5 par 5 et qu'il n'y a pas de sauts dans le programme, on arrive à 100Hz ! J'ai des pistes pour un système plus efficace, je suis en train d’expérimenter, faire de la branch prediction dans minecraft ce serait classe quand même...

    Bref ça va très vite, ça prend que quelques secondes pour overflow 16bits avec la suite de fibonacci.

    [​IMG]
    [​IMG]
    [​IMG]

    La mémoire du programme est séparée de la mémoire principale pour permettre de stocker des instructions déjà décodées, ce qui accélère beaucoup les choses, mais cela empêche la modification du programme par l'ordinateur lui-même. J'ai écrit un petit script pour compiler de l'assembleur et d'exporter dans la mémoire.
    Il y a 256 lignes pour le programme et 1K de RAM, mais on peut monter à 64K pour chaque, après c'est un problème de place. Les 128 dernières adresses de la RAM sont réservées à l'écran.

    Il y a une vingtaine d'instructions, grâce au stack le processeur supporte l'appel de fonctions et les interruptions.


    Les 8 registres 16bits qui peuvent tous être utilisés de la même manières dans des opérations arithmétiques ou logiques :
    • 3 registres de données (A, B, C)
    • registre d'adresse
    • registre de segment
    • compteur ordinal
    • stack pointer
    • registre des flags (zéro, négatif et overflow, + statut)

    Les interfaces (c'est pas compliqué d'en brancher d'autres sur les ports I/O) :
    • écran 16*8 caractères (qui supporte un genre d'ASCII du pauvre)
    • entrée/sortie hexadécimale
    • entrée/sortie binaire


    Documentation (disponible dans le téléchargement) :

    Code:
    Schéma d'une instruction :
        Code de fonction  ||  op1  ||  op2  ||  op3
    
    ou bien :
        Code de saut  ||  op1
    
    ou bien :
        Code de saut  ||  Code de fonction  ||  op1  ||  op2  ||  op3
    
        Ici le résultat de la fonction sert d'adresse pour le saut.
        -> surtout pratique pour gagner une ligne avec IRET, sinon c'est gadget.
    
    
    
    Opérandes possibles dans les instructions ('op') :
    
      registres (A,B,C,ADR,CS,SP,PC,FLAGS)
      nombre immédiat ('x') qui peut être décimal, binaire ('0bXXX') ou hexadécimale ('0xXXX')
      adresse ram indirecte (via ADR)
      adresse ram immédiate ('[x]')
      port I/O indirect (via ADR)
      port I/O immédiat ('{x}')
      PUSH et POP (offset possible avec POP)
      'VOID' si l'on ne veut pas garder le résultat d'une opération (ou alors pour générer un zéro)
      adresse immédiate relative au stack pointer ('(x)') :
          (0) est l'adresse pointée par le stack (qui est normalement vide)
          (1) est l'adresse qui précède celle pointée par le stack
          (2) est celle encore avant etc...
              -> on ne peut accéder qu'à des adresses "dans le passé"
    
      note : On peut donner autant de valeurs immédiates que l'on veut par instruction,
        on peut donc faire des opérations sur la mémoire sans passer par les registres.
        -> les valeurs immédiates prennent beaucoup de mémoire
    
    
    
    Registre des flags :
    
      0-8   non utilisés
      9     overflow
      10    négatif
      11    zéro
      12    halt
      13    ne pas incrémenter PC (utilisé par les sauts)
      14    interruption
      15    flush de la pipeline
    
          'FL' peut être placé à la fin de n'importe quelle instruction
            pour mettre à jour les flags zéro, overflow et négatif
    
    
    
    codes de saut :
    
      IRET    (pas d'opérande) retour d'interruption restaure les registres
      INT     appel d'interruption, sauvegarde tous les registres, saut vers un autre segment (via CS)
      JS      saut sans condition vers un autre segment (via CS)
      CALL    appel de fonction (push l'adresse du compteur programme)
      JMP     saut sans condition
      JNZ     saut si flag zéro = 0
      JNO     saut si flag retenue = 0
      JNN     saut si flag négatif = 0
      JZ      saut si flag zéro = 1
      JO      saut si flag retenue = 1
      JN      saut si flag négatif = 1
        op1 :
        saute à l'adresse indiquée par op1
    
    
    
    Codes de fonction :
    
      MOV     copie / f(x) = x
      NOT     fonction NOT
      SHL     décalage logique vers la gauche
      RTL     rotatation vers la gauche
      SHR     décalage logique vers la droite
      RTR     rotation vers la droite
      NEG     opposé
      INC     incrémentation
      DEC     décrémentation
        op1,op2 :
        stocke le résultat de f(op2) dans op1
    
      AND     ET logique
      XOR     OU exclusif logique
      OR      OU logique
      ADD     addition
      SUB     soustration
        op1,op2,op3 :
        stocke f(op2,op3) dans op1
    
    
    

    Code:
    Assemblage :
      Il faut d'abord lancer l'exe ou glisser-déposer dessus le fichier qui contient le code.
      On indique ensuite le segment : l'adresse à laquelle le programme commence.
     
      Deux fichiers sont créés : "log_bin.txt" avec le programme en langage machine et "import.mcfunction" qui sert pour
      importer le programme dans minecraft.
    
    
    Importation :
      Le fichier "import_*programme*.mcfunction" doit être placé dans le datapack de la map :
          donc dans C:\Users\Utilisateur\AppData\Roaming\.minecraft\saves\CB 1642\datapacks\import\data\import\functions
    
      Il faut ensuite recharger le datapack avec "/reload", puis importer avec "/function import:import.mcfunction"
    
      Il n'est pas nécessaire de reset la RAM, on peut bien sûr importer plusieurs programmes, mais il faut leur donner des adresses bien différentes :
      la gestion de la mémoire est manuelle.
    
    
    
    Fonctions de l'assembleur :
    
      Ce ne sont pas des instructions qui seront exécutées par le processeur.
      Elles aident à la programmation et commencent par un point.
    
      .const NOM VALEUR
        Défini une constante
    
    
      .data NOM VALEUR
        La valeur peut être un nombre, un string (avec des "") -> les caractères doivent être dans la table
        (attention aux majuscules et aux espaces), ou un array de nombres (avec des {} et des virgules pour séparer)
    
        Des constantes sont alors définies :
          *NOM qui renvoie la valeur de la variable oar adressage ram immédiat,
              ex : 'MOV *NOM 10' change la valeur de NOM
          &NOM qui donne l'adresse de NOM en tant que nombre immédiat
          NOM.LEN qui donne la longueur si la valeur est un string ou un array
    
    
      .label NOM
        Crée une constante qui renvoie vers une adresse relative à l'origine du programme,
        -> intéressant pour les sauts
    
    
      .labelabs NOM
        Idem .label mais l'adresse est absolue (par rapport à toute la ram)
        -> intéressant pour le saut JS.
    
    
      .segment ADRESSE
        Permet de dire où se trouve le programme dans la mémoire, demandé toute façon par le complilateur.
        -> intéressant quand on a deux programmes dans le même fichier et que l'on veut les importer en même temps (risqué quand même)
    
    
      .offset ADRESSE
        Permet de définir où se trouve le code par rapport à l'origine du programme
        -> intéressant pour gérer les adresses quand on a beaucoup de fonctions dans le programme
    

    Code:
    ;affiche "HELLO WORLD !"
    ;nécessite CBCOS
    
    MOV {3} 2    ;on efface l'écran
    MOV A 896    ;on met l'adresse du début de la ram vidéo dans A
    MOV B &TEXT_HELLO    ;on met l'adresse du début du text dans B
    MOV C TEXT_HELLO.LEN    ;la longueur du text dans C
    INT 20        ;interruption vers une fonction de CBCOS, copie de mémoire (paramètres dans A, B et C)
    MOV {3} 1    ;on rafraichit l'écran
    INT 8
    
    ;définition de la variable "TEXT_HELLO"
    .data TEXT_HELLO "HELLO WORLD !"
    

    Code:
    Ecran 16*8 caractères :
    
    Pour rafraichir l'écran : écrire un 1 au port 3
    Pour effacer l'écran    : écrire un 2 au port 3
    
    
    Adresses de l'écran : 896 à 1023 (0x380 à 0x3FF)
    
    
    Table des caractères:
    
        0   : SPACE ('_' dans les déclarations de strings)
        1   : BLANK
        2   : 0
        3   : 1
        4   : 2
        5   : 3
        6   : 4
        7   : 5
        8   : 6
        9   : 7
        10  : 8
        11  : 9
        12  : A
        13  : B
        14  : C
        15  : D
        16  : E
        17  : F
        18  : G
        19  : H
        20  : I
        21  : J
        22  : K
        23  : L
        24  : M
        25  : N
        26  : O
        27  : P
        28  : Q
        29  : R
        30  : S
        31  : T
        32  : U
        33  : V
        34  : W
        35  : X
        36  : Y
        37  : Z
        38  : +
        39  : -
        40  : *
        41  : /
        42  : ^
        43  : =
        44  : >
        45  : <
        46  : .
        47  : ,
        48  : :
        49  : ;
        50  : !
        51  : ?
        52  : '
        53  : "
        54  : (
        55  : )
    
    

    Code:
    Adresse 0x0   à 0x6F  : CBCOS --> au démarrage il affiche un message à l'écran et demande le programme qu'il faut executer via l'entrée hexadécimale.
    
    Adresses 0x100 à 0x111 : fibonacci
    Adresses 0x140 à 0x15A : hello world
    Adresses 0x180 à 0x19C : test de l'écran
    
    Adresses 0x200 à ---   : mémoire stack, allouée par CBCOS, attention à ne pas mettre des programmes trop près après 0x200
    Adresses 0x380 à 0x3FF : mémoire vidéo, peut être utilisée normalement si l'écran n'est pas utilisé
    



    Je publierai une vidéo.. un jour.
    [​IMG]
    Nan c'est juste pour montrer qu'on peut afficher des couleurs sur l'écran. J'aurais pu faire un arc-en-ciel avec les 16 couleurs mais bon.

    Je n'ai pas encore remis le système de overclock magique, ça va me prendre un peu de temps. x)
    Pour l'instant c'est limité à 20Hz. La doc, l'assembleur et d'autres exemples de programmes sont inclus dans le téléchargement.
     

    Fichiers attachés:

    #1 Régis Laspalès, 15 Avril 2019
    Dernière édition: 4 Mai 2019
    Wistaro et Kaeios aiment ça.
  2. Eglaios

    Eglaios Crétin de la commu

    Inscrit:
    14 Avril 2018
    Messages:
    181
    J'aime reçus:
    29
    Ah oui, ça ressemble vraiment à l'atari 2600 de Sethbling, sauf que pour lui, un jeu s'exécute 10 fois plus lentement que sur la vraie console, lol. C'est cool!
     
  3. [GISED] Link

    [GISED] Link Torches, poudre et repeaters. What else ?

    Inscrit:
    4 Mars 2012
    Messages:
    333
    J'aime reçus:
    74
    Yop,

    J'ai passé ma vie à sniffer de la poudre ... et me voilà face à un processeur qui n'en contient même pas ...
    [​IMG]

    Sinon ça a l'air d'être assez conséquent et complet. Peux-tu ajouter des informations supplémentaires :
    • Jeu d'instruction
    • Une vidéo / plus d'images sur l'exécution, comment ça marche
    • Description d'une ligne de la ROM (apparemment ya pas mal de bit par instructions ...)
    • Une ...... map ? afin qu'on puisse... euh ... ESSAYER :bave:
    • Autres infos techniques croustillantes sur ce petit bijou

    En tout cas c'est du joli
     
  4. Régis Laspalès

    Inscrit:
    16 Février 2014
    Messages:
    1 916
    J'aime reçus:
    375
    Je le sien fonctionne avec un datapack et sa première version date un peu, je ne sais pas si c'est vraiment comparable.
    Un jour j'essayerai de reproduire un 6502 pour voir, faudrait que je mette le nez dans les datapacks aussi.



    J'ai posté en faisant le pari que personne aller répondre donc j'ajouterai tout ça. ;)
    Si t'as des propositions de programmes que je pourrais mettre en démo hésite pas.
    Faudra aussi que je mette à disposition le compilateur mais il est pas vraiment présentable, je suis pas fier de mon code... x)

    Et t'inquiète c'est le premier ordinateur que je fais avec des commands blocks, d'habitude j'utilise exclusivement la redstone.
    Les command blocks c'est en fait beaucoup plus rapide et ça fait beaucoup moins ramer.
     
    #4 Régis Laspalès, 16 Avril 2019
    Dernière édition: 16 Avril 2019
  5. Régis Laspalès

    Inscrit:
    16 Février 2014
    Messages:
    1 916
    J'aime reçus:
    375
    Salut petite mise à jour, j'ai mis une liste des instructions, je peux fournir plus de détails dans l'hypothèse où des gens voudrait programmer pour cette machine (je suis en train de rédiger plus de doc). Je ne mets pas la map à disposition tout de suite, je suis en train de travailler les programmes installés "d'usine", notamment un système d'exploitation primitif. Sinon je laisserai mes programmes de test comme hello world ou fibonnaci.

    Je vais aussi améliorer la communication entre le CPU et le "GPU", on pourra lui envoyer des instructions via les ports I/O car pour
    l'instant tout ce qu'il fait c'est scanner la mémoire pour des caractères à afficher.

    Ensuite je modifierai l'assembleur pour qu'il soit utilisable par tout le monde, c'est un peu compliqué au niveau de la syntaxe (même pour moi).
    Ce sera plus propre quand on pourra donner des valeurs hexadécimales.

    [​IMG]
    En gros :
    • les 3 première lignes définissent des constantes utiles un peu partout,
    • "segment" précise où dans la mémoire commence le programme
    • "lab" crée un label (ici il sert à rien mais c'est pratique pour les boucles)
    • "data" permet de définir une constante avec l'adresse de certaines données qui vont être mises dans la ram

    ensuite le code qui va être exécuté pour de vrai :
    • Je push 3 adresses pour ensuite appeler une fonction qui copie un bout de la ram à un autre endroit ("hello world" -> mémorie vidéo)
    • J'appelle une fonction qui rappelle "l'OS" pour terminer le programme


    Enfin je finaliserai le projet en construisant un décodeur d'instructions pour le processeur, ce qui permettra de tout stocker dans la même mémoire,
    un des trucs chiant quand on importe un programme c'est qu'il faut gérer la ROM et la RAM séparément. J'ai déjà les premières briques posées avec
    le registre de segment, le défi ce sera de concevoir un langage machine adapté à un décodeur instantané.

    Je suis pas un expert, ce que je connais je l'ai surtout appris en construisant des processeurs en redstone et non en programmant en assembleur.
    Du coup il y a sûrement des grosses incohérences. Par exemple PUSH et POP qui sont traités comme des opérandes et non comme des instructions,
    ça permet par exemple de les utiliser directement sans passer par un registre, par exemple c'est possible de faire quelque chose comme "JUMP POP",
    mais on est obligé de dire "MOV PUSH *** " dans les cas où on veut juste push une valeur comme dans l'exemple d'haut dessus.
    C'est pas trop tard pour changer tout ça.

    A la fin ce truc sera compatible x86 mdr...
     
    #5 Régis Laspalès, 20 Avril 2019
    Dernière édition: 21 Avril 2019
  6. Wistaro

    Wistaro Étudiant ingénieur

    Inscrit:
    5 Février 2014
    Messages:
    1 102
    J'aime reçus:
    158
    Wow, très beau travail. En particulier l'ajout du pipeline et de l'architecture de Harvard modifié ;)

    J'ai hâte de voir ce que ça peut donner par la suite
     
  7. Régis Laspalès

    Inscrit:
    16 Février 2014
    Messages:
    1 916
    J'aime reçus:
    375
    Le Harvard il va pas rester longtemps, j'ai trouvé un décodeur, j'ai de la place dans le code machine pour rajouter des fonctions et des registres si je veux.
    Ça fait plus propre sans le gros rectangle de rom. :^)

    [​IMG]
     
    #7 Régis Laspalès, 22 Avril 2019
    Dernière édition: 22 Avril 2019
  8. Régis Laspalès

    Inscrit:
    16 Février 2014
    Messages:
    1 916
    J'aime reçus:
    375
    Salut je mets <enfin> à disposition la map avec un petit kit de développement.
    Il y a encore du boulot, j'ai pas pu remettre le système de pseudo pipeline mais c'est pas un truc compliqué.
    J'aimerai ajouter une horloge sur un port I/O pour avec plus de possibilités en terme de système "d'exploitation", et ça manquerait presque un deuxième K de ram.
    L'executable de l'assembleur n'est compatible qu'avec windows je pense.
    Et non ça peut pas faire tourner doom.
     
  9. Régis Laspalès

    Inscrit:
    16 Février 2014
    Messages:
    1 916
    J'aime reçus:
    375
    Bon... j'ai laissé le projet de côté mais j'ai encore des visions de processeurs dans mes rêves.




    Il est encore temps de se ruer sur ce bijou de technologie de la mort qui tue tant que tout n'est pas obsolète.
     
    #9 Régis Laspalès, 20 Juin 2019
    Dernière édition: 20 Juin 2019

Partager cette page