Architecture Seq

Architecture générale:

Attention, pour que la figure reste relativement lisible, tous les fils ne sont pas montrés. Notamment, icode, ifun, etc. sortant de Instruction memory sont branchés à diverses boîtes grises. Les boîtes grises dstE, dstM, srcA, srcB sont par ailleurs branchées sur Register file.

Général

Les données vont de bas en haut, il faut donc commencer par regarder le bas.

Les boîtes bleues ne seront pas détaillées: elles se comportent tel que l'on a vu en Cours et en TD:

Ce qui nous intéresse plus, ce sont les boîtes grises, qui sont codées en HCL, décrit ci-dessous. Ce sont en fait juste des multiplexeurs un peu évolués: ils prennent des informations en entrée et produisent une valeur en sortie, qui est en général l'une des entrées.

Syntaxe HCL

type nom_sortie = [
	condition1 : valeur_de_sortie_1;
	condition2 : valeur_de_sortie_2;
];

Le comportement est très similaire à un switch C: si la condition1 est vraie, la sortie nom_sortie prend la valeur valeur_de_sortie_1, et sinon, si la condition2 est vraie, elle prend la valeur valeur_de_sortie_2, etc. Bien souvent, une valeur par défaut est ajoutée à la fin en utilisant simplement la condition 1 (toujours vraie), qui "attrape" donc tous les cas qui n'ont pas été traité plus haut.

Dans les conditions, on peut écrire des tests comme en C: valeur == VAL1 || valeur == VAL2. HCL permet cependant une syntaxe additionnelle bien plus agréable: on peut utiliser la syntaxe valeur in { VAL1, VAL2 } qui en est équivalent.

Nota: JXX représente l'ensemble des JMP, JE, JNE, JL, JLE, JG, JGE. C'est Bch qui indique si le branchement doit être pris ou non (il est donc bien sûr toujours égal à 1 dans le cas de JMP).

Nota2: OPL représente l'ensemble des ADDL, SUBL, ANDL, XORL, SALL, SARL, et IOPL représente l'ensemble des IADDL, ISUBL, IANDL, IXORL, ISALL, ISARL. C'est ensuite ifun qui indique quelle opération est demandée dans l'instruction.

Nota3: RESP désigne le registre esp.

Détail des boîtes combinatoires:

PC
int new_pc = [ # Call. Use instruction constant icode == CALL : valC; # Taken branch. Use instruction constant icode == JXX && Bch : valC; # Completion of RET instruction. Use value from stack icode == RET : valM; # Default: Use incremented PC 1 : valP; ];
Memory
## Set read control signal bool mem_read = icode in { MRMOVL, POPL, RET }; ## Set write control signal bool mem_write = icode in { RMMOVL, PUSHL, CALL }; ## Select memory address int mem_addr = [ icode in { RMMOVL, PUSHL, CALL, MRMOVL } : valE; icode in { POPL, RET } : valA; # Other instructions don't need address ]; ## Select memory input data int mem_data = [ # Value from register icode in { RMMOVL, PUSHL } : valA; # Return PC icode == CALL : valP; # Default: Don't write anything ];
Execute
## Select input A to ALU int aluA = [ icode in { RRMOVL, OPL } : valA; icode in { IRMOVL, RMMOVL, MRMOVL, IOPL } : valC; icode in { CALL, PUSHL } : -4; icode in { RET, POPL } : 4; # Other instructions don't need ALU ]; ## Select input B to ALU int aluB = [ icode in { RMMOVL, MRMOVL, OPL, IOPL, CALL, PUSHL, RET, POPL } : valB; icode in { RRMOVL, IRMOVL } : 0; # Other instructions don't need ALU ]; ## Set the ALU function int alufun = [ icode in { OPL, IOPL } : ifun; 1 : ALUADD; ]; ## Should the condition codes be updated? bool set_cc = icode in { OPL, IOPL };
Decode
## What register should be used as the A source? int srcA = [ icode in { RRMOVL, RMMOVL, OPL, PUSHL } : rA; icode in { POPL, RET } : RESP; 1 : RNONE; # Don't need register ]; ## What register should be used as the B source? int srcB = [ icode in { OPL, IOPL, RMMOVL, MRMOVL } : rB; icode in { PUSHL, POPL, CALL, RET } : RESP; 1 : RNONE; # Don't need register ]; ## What register should be used as the E destination? int dstE = [ icode in { RRMOVL, IRMOVL, OPL, IOPL} : rB; icode in { PUSHL, POPL, CALL, RET } : RESP; 1 : RNONE; # Don't need register ]; ## What register should be used as the M destination? int dstM = [ icode in { MRMOVL, POPL } : rA; 1 : RNONE; # Don't need register ];

En résumé, pour le côté A: