carnaval / jopml

sync. circuit extension to OCaml, simulator, and loosely MIPS compatible 1-cycle CPU

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

= L'assembleur =

Style mips, c'est le plus simple : plein de registres + un registre zero qui contient toujours 0
2 types d'instructions
- [alu rdest r1 r2] pour les operations arith/logiques où alu parcours {add, sub, or, and, ... }
  prends aussi en compte move car : move $rdest $r ~ or rdest $r $zero
  prends aussi en compte les jump avec move $pc $x
- [load dest addr/store orig addr] qui prends ou mets des trucs dans la RAM à l'addresse $addr
De plus, chaque instruction prends un registre supplementaire $c en argument et ne s'execute que si celui ci est nul (sinon elle devient move $zero $zero ~ nop). Cela permet le branching et on met $zero pour faire le mips usuel.

Encodage : chaque instruction sur 4 mots
[op][arg1][arg2][arg3] (quand l'operation a moins d'arguments on pad avec des 0)
où :
op =
   | 00[alu_type] => operation sur l'alu { arg1 = rdest, arg2 = r2, arg3 = r3}, on transmet alu_type
   | 10(0*) => load { dest = arg1, addr = arg2 }
   | 11(0*) => store { orig = arg3, addr = arg2 }

(le 0* c'est qu'on complète par des zeros, on est indépendant de la taille du mot à la compilation)

= La ROM =

Elle va lire les mots 4 par 4 parceque c'est la taille de nos instructions donc c'est plus simple :
- une entrée read_addr[wordsize]
- une sortie instr[4*wordsize]

= La RAM =

- deux entrée read_addr[wordsize], write_addr[wordsize]
- une entrée write_data[wordsize] et une entrée write[1]
- une sortie read_data[wordsize]
si write est à 1 la RAM écrit write_data à l'addresse write_addr etc.

= Architecture =

Un registre spécial $pc est toujours branché sur le read_addr de la ROM. Il s'incrémente de plus tout seul a chaque tick d'horloge.

Tous les sorties registres sont branchés sur 2 gros selecteurs qui prennent en argument arg2 et arg3 resp.
En gros on a 3 mots qui valent a tout moment $arg2 et $arg3 resp.
De même les entrées sont branchées sur un selecteur qui vaut $arg1$.
Donc a chaque instruction, on écrits TOUJOURS le résultat de quelquechose dans $arg1 et on lit TOUJOURS $arg2 et $arg3

r1_read == |                                     |
r2_read == | SELECT (instr[wordsize:2*wordsize]) |
...        |                                     | == arg2
rn_read == |                                     |

pareil pour arg3

Pour alu & load:

                    arg2 =(read_addr)= [RAM]
                                         ||
                                    (read_data)
                 _____                   ||
arg2 =(input1)= | ALU | =(output)= select(op[0:2]) == arg3
arg3 =(input2)= |_____|

Pour brifzero :
                      zero
                        |
arg2 == is_zero -- select(op[0:2]) -- pc_overwrite
 ||
pc_write

= Organisation =

- jop/ : Module camlp4 et runtime pour la compilation ml => netlist.
- circuits/ : Fichiers ml décrivant des netlists.
- netlists/ : Netlists générées et fichiers d'input.
- simulator/ : Simulateur de netlist en java. L'utilisation est expliquée en executant JOP_Simulator.jar sans argument (java -jar JOP_Simulator.jar)


= Comment lancer une demo ? =

Les demos dispos sont (pour l'instant) :

./rundemo.sh full_adder
Teste tout les combinaisons d'entrées sur un full adder décrit dans circuits/full_adder.ml
Sortie espérée : 0 1 1 1 2 2 2 3

./rundemo.sh minus
Fais le moins unaire de l'entrée (ici 100000000...)
Sortie espérée : 11111111111....

./rundemo.sh count <n>
Incrémente un compteur modulo 2^n pendant 32 ticks d'horloge.
Sortie espérée :
- 0 1 2 3 ... ((2^n)-1) 0 1 ... (valeur du compteur)
- 0 0 0 0 ...   1   0 0 ... (bit d'overflow)

./rundemo.sh modn <n>
Même chose que pour count, mais on a ici un compteur modulo n, avec n quelconque.

./rundemo.sh clk2
Effectue une division d'horloge.
Sortie attendue : 110011001100...
(ou la même chose avec un déphasage de 1 pour l'autre sortie)

Le code des circuits n'est pour l'instant pas très beau, ceci étant dût à quelques soucis avec camlp4, work in progress.


= Est-il possible de faire ces démos avec nos propres inputs d'entrée ? =

Bien sûr, il suffit pour cela de modifier le fichier d'extension ".nl.input" correspondant.

Les fichiers input sont concus de telle manière :
Tout d'abord le nombre de cycle d'horloge à simuler,
Puis pour chaque input, le nom de la variable suivie (séparés par des espaces) les valeurs au cours du temps.

Un exemple de fichier pourrait être :

8
a 0 1 0 0 0 1 1 1 
b 0 0 1 0 1 0 1 1
ci 0 0 0 1 1 1 0 1

About

sync. circuit extension to OCaml, simulator, and loosely MIPS compatible 1-cycle CPU


Languages

Language:NewLisp 91.4%Language:Java 6.4%Language:OCaml 1.7%Language:Python 0.4%Language:Shell 0.1%Language:Makefile 0.1%Language:ActionScript 0.0%