2016-06-05 21 views
0

Ich versuche, einen einfachen Multicycle-Prozessor zu implementieren, und ich stieß auf einige Probleme, die ich nicht durchkommen werde. Der Code ist unten. Ich experimentiere gerade jetzt, um das fließen zu lassen. Wenn ich fertig bin, beginne ich mit der Implementierung von Anweisungen und ALU. Allerdings stecke ich an diesem Punkt fest. In dem Code unten ist mir bewusst, dass data_memory nie verwendet wird (Ich werde zu da, wenn ich das lösen kann), einige Eingänge und Ausgänge werden auch nicht verwendet, x1 und x2 sind nur Variablen, die ich erstellt habe, um zu sehen, was ist wirklich los. Was ist in Datei ist selbstverständlich.Iterationsgrenze bei der Implementierung eines Multicycled-Prozessors

Ich verwende Altera Quartus 15.1 mit Verilog2001. Dieser Code kompiliert genau einige Warnungen wegen unbenutztem Zeug aus, aber wenn ich versuche, es mit einer Taktperiode von 20ns zu simulieren, gibt es einen Fehler, der sagt "Error (suppressible): (vsim-3601) Iterationslimit 5000 erreicht zum Zeitpunkt 100 ns" . Es sagt auch, dass dies unterdrückbar ist, aber ich weiß auch nicht, wie ich es unterdrücken soll.

Ich habe nach diesem Fehler gesucht und ich habe gelernt, dass dies passiert, weil der Code irgendwann in eine Endlosschleife geht. Ich habe versucht, dies zu lösen, indem ich eine andere Variable ok erstelle. Ein Zyklus beginnt mit dem Setzen von ok auf 0 und nachdem die Mikrooperationen für diesen Zyklus abgeschlossen sind, setze ich ok auf 1. Der Zyklus wird sich also nicht zu einer unpassenden Zeit ändern (es ist wie das Sperren des Zyklus). Dies führte leider zu demselben Fehler.

Ich versuchte auch einen anderen Fluss. Anstelle von cycle und next_cycle habe ich eine Variable für den Zyklus erstellt. Bei jeder steigenden Flanke der Uhr überprüfte ich den aktuellen Zustand und tat die Dinge entsprechend, dann stellte ich den Zyklus für den nächsten Schritt ein. Beispiel:

Dies kompiliert auch gut, und kann ohne Fehler simuliert werden! Funktioniert jedoch nicht korrekt und gibt seltsame (oder unerwartete) Ergebnisse. Ich finde einen anderen Ansatz intuitiver. Also werde ich versuchen, es zum Laufen zu bringen.

Wie kann ich dies beheben/implementieren?

`include "definitions.v" 

module controller(
    input       clk, 
    input       nres, 
    output reg      ire, 
    output reg      dwe, 
    output reg      dre, 
    output reg [1:0]    x2, 
    output reg [`IADR_WIDTH-1:0] i_address, 
    output reg [`DADR_WIDTH-1:0] d_address, 
    output reg [`DATA_WIDTH-1:0] data_out); 

    reg [2:0] cycle = 3'b000; 
    reg [2:0] next_cycle; 

    reg [`IADR_WIDTH-1:0] PC = 6'b000000; 
    reg [`INST_WIDTH-1:0] IR = 12'b00000_0000000; 
    reg [`DADR_WIDTH-1:0] MAR = 6'b000000;   
    reg [4:0]    OPC = 5'b00000; 

    wire [`DATA_WIDTH-1:0] data_in; 
    wire [`INST_WIDTH-1:0] instruction; 

    reg [1:0] x1; 

    data_memory dmem  ( .clk  (clk), 
           .dwe  (dwe), 
           .dre  (dre), 
           .nres  (nres), 
           .d_address (d_address), 
           .d_data  (data_out), 
           .d_q  (data_in)); 

    instruction_memory imem ( .clk  (clk), 
           .ire  (ire), 
           .i_address (i_address), 
           .i_q  (instruction)); 

    reg ok = 1; 

    always @ (posedge clk) begin 
     cycle = (ok) ? next_cycle : cycle; 
    end 

    always @ (cycle) begin 
     case (cycle) 
      3'b000: begin 
       ok = 0; 
       MAR = PC; 
       next_cycle = 3'b001; 
       ire = 1'b1; 
       x2 = 2'b00; 
       ok = 1; 
      end 
      3'b001: begin 
       ok = 0; 
       i_address = MAR; 
       IR = instruction; 
       ire = 1'b0; 
       next_cycle = 3'b010; 
       x2 = 2'b01; 
       ok = 1; 
      end 
      3'b010: begin 
       ok = 0; 
       OPC = IR; 
       next_cycle = 3'b011; 
       x2 = 2'b10; 
       ok = 1; 
      end 
      3'b011: begin 
       ok = 0; 
       if (OPC==5'b01011) x1 = 2'b11; 
       PC = PC + 1; 
       next_cycle = 3'b000; 
       x2 = 2'b11; 
       ok = 1; 
      end 
     endcase  
    end 

endmodule 
+0

Einige Vorschläge: 1) Verwenden Sie 'immer @ (*)' anstelle von 'immer @ (Zyklus)' - es wird nichts reparieren, aber es ist eine gute Angewohnheit; 2) Fügen Sie einen 'Default'-Fall hinzu, um das Sperrverhalten zu verhindern - andernfalls wird Quartus auf einen Latch (statt auf einen Draht) schließen; 3) Verwenden Sie nicht-blockierende Zuordnungen ('<=') innerhalb flankengetriggerter 'always' Blöcke; 4) Veröffentlichen Sie Ihren Testbench-Code, falls darin die Fehlerquelle enthalten ist. – wilcroft

+0

Sie haben 'PC = PC + 1;' in einem kombinatorischen Block. Dies sollte wahrscheinlich auf einer Taktflanke vorgerückt werden. – Morgan

+0

@Morgan Aber es wird von einem Zustand (Zyklus) gesteuert, und dieser Zustand wird durch positive Flanke der Uhr gesteuert. Glaubst du, dass das das Problem verursacht? – Motun

Antwort

1

Wenn wir always @(signal) in Verilog zu schreiben, eine festgelegte Empfindlichkeit Liste ist die Logik auf eine Änderung dieses Signal ausgelöst. Dies kann zu Missverständnissen führen, wie Hardware tatsächlich funktioniert. Die einzige Hardware, die wir an einer Kante ändern, ist ein Flip-Flop, und Sie müssen dafür das Keyword pagegege oder negedge angeben. Wenn always @(signal) synthetisiert wird, erhalten Sie tatsächlich einen kombinatorischen Block, der sich wie always @(*) verhalten wird. Dies ist eine automatische Empfindlichkeitsliste.

So aus den Kommentaren in diesem kleinen Abschnitt von Code, den wir aussehen: Diese

always @ (*) begin 
    case (cycle) 
     3'b011: begin 
     ok = 0; 
     if (OPC==5'b01011) x1 = 2'b11; 
     PC = PC + 1; 
     next_cycle = 3'b000; 
     x2 = 2'b11; 
     ok = 1; 

ein kombinatorischen Block, ausgelöst im Simulator, wenn etwas, das er Ausgangsänderungen bewirken kann. Die meisten Signale sind statischen Signalen oder anderen bekannten Werten mit Out-Schleifen zugeordnet.

PC = PC +1; 

Die obige Linie obwohl Updates der Wert von PC, wird dieser neue Wert von PC den kombinatorischen Block auslösen soll neu bewertet werden, was wiederum die PC-Erhöhungs Schlagen, etc. Dies alles des Delta-Zyklus geschieht im Innern des Simulators.

Mit Hardware-Beschreibungssprachen (HDLs) wie Verilog müssen wir uns daran erinnern, dass wir parallele Anweisungen, nicht seriell ausgeführte Codezeilen beschreiben.