Nous poursuivons la conception de notre processeur simple. Dans cet article, nous abordons l'utilisation du regsitre R7 comme compteur de programme (PC).
L'idée fondamentale est que toute instruction modifiant la valeur de R7 effectue un saut (jump). Dans le cas contraire, le programme s'exécute de manière séquentielle et R7 doit être incrémenté à chaque cycle d'horloge.
Pour implémenter ce comportement, la section d'écriture des registres est modifiée :
always @(posedge clk) begin
if (sel_pc) begin
pc_reg <= alu_result;
end else begin
pc_reg <= pc_reg + 8'd1;
end
// Mise à jour des autres registres
for (int i = 0; i < 7; i++) begin
if (sel[i]) begin
regs[i] <= alu_result;
end
end
end
La synthèse RTL génère alors un additionneur pour l'incrémentation et un multiplexeur contrôlé par le signal de sélection du PC. Cela permet de connecter le registre programme à une ROM contenant les instructions, permettant ainsi leur exécution séquentielle.
Pour améliorer la lisibilité du code, nous passerons du format Verilog (.v) à SystemVerilog (.sv). Cette extension offre des syntaxes plus compactes, notamment pour la déclaration des ensembles de registres :
module processeur_simple(
input logic clk,
input logic [15:0] instruction,
output logic [7:0] registres [8]
);
logic [7:0] operande_a, operande_b, resultat_alu;
logic [2:0] index_destination;
assign index_destination = instruction[10:8];
always_comb begin
operande_a = registres[instruction[10:8]];
operande_b = instruction[11] ? registres[instruction[2:0]] : instruction[7:0];
end
always_comb begin
casez(instruction[15:12])
4'b0000: resultat_alu = operande_b; // Chargement
4'b0001: resultat_alu = operande_a + operande_b; // Addition
4'b0010: resultat_alu = operande_a - operande_b; // Soustraction
4'b0011: resultat_alu = operande_a & operande_b; // ET logique
4'b0100: resultat_alu = operande_a | operande_b; // OU logique
4'b0101: resultat_alu = (operande_a == operande_b); // Comparaison
default: resultat_alu = '0;
endcase
end
logic [7:0] selecteur_ecriture;
decodeur_3vers8 decodeur_inst(
.entree(index_destination),
.sortie(selecteur_ecriture)
);
always_ff @(posedge clk) begin
// Traitement spécial pour le compteur de programme
if (selecteur_ecriture[7]) begin
registres[7] <= resultat_alu;
end else begin
registres[7] <= registres[7] + 1;
end
// Écriture dans les autres registres
for (int i = 0; i < 7; i++) begin
if (selecteur_ecriture[i]) begin
registres[i] <= resultat_alu;
end
end
end
endmodule
Cette réécriture utilise des structures SystemVerilog comme logic, always_comb, always_ff et les opérateurs améliorés. L'architecture générée reste identique, mais le code source est plus concis et plus lisible.