Wie kann ich die Verzögerung zwischen Befehl und Programmzähler beheben?

Ich entwerfe den MIPS-Prozessor, dazu gehören Datenspeicher und Befehlsspeicher zum Testen. Ich hatte ein Problem mit der in dieser Frage behandelten IM-Synthese ( Wie erstelle ich einen synthetisierbaren Befehlsspeicher in SystemVerilog? ) Und nachdem ich ihn wie empfohlen umgeschrieben hatte (ff mit einer caseAnweisung), trat ein weiteres Problem auf.

Das Problem: Der Befehl in der CPU hat eine Zyklusverzögerung vom Programmzähler. Wenn also der Verzweigungsbefehl (Nummer i ) kommt, ist der Programmzähler bereits ( i+1 ) und dann kommt instr ( i+1 ) und PC ist PC_branch . Wie kann ich es reparieren? Verzögerung wird durch dieses ff in IM verursacht. Code und Wellenformen sind unten.

Der Code:

always_ff @(posedge clk) begin
case (addr)      
        32'd0 : rom_ff <= 32'h2408000F; // a = F
        32'd1 : rom_ff <= 32'h240A0000; // res = 0

        32'd2 : rom_ff <= 32'h01485021; // (*) res = res + a
        32'd3 : rom_ff <= 32'h2508FFFF; // a = a - 1

        32'd4 : rom_ff <= 32'h1500FFFD; // if (a != 0) goto (*)
        32'd5 : rom_ff <= 32'hAC0A0ADD; 
        default : rom_ff <= 32'h0;
    endcase
end

Die Wellenform von CPU-Signalen:Geben Sie hier die Bildbeschreibung ein

Antworten (2)

Worauf Sie dort gestoßen sind, sind die Probleme, die mit dem Pipelining von Anweisungen einhergehen . Ich gehe davon aus, dass Sie Ihren Prozessor irgendwann für den Betrieb auf einem FPGA synthetisieren werden, daher ist das Entfernen des Registers zwischen dem Befehlsspeicher und dem Rest der CPU leider keine Option.

Um dies zu beheben, haben Sie drei Möglichkeiten.

  • Ignorieren Sie das Problem. Schließlich verhält sich Ihr Prozessor immer noch deterministisch – das einzige Problem ist, dass er nach einer Verzweigung eine zusätzliche Anweisung ausführt. Dies wird als Verzweigungsverzögerungsschlitz bezeichnet , was bedeutet, dass die Anweisung, die nach einer Verzweigung kommt, so ausgeführt wird, als wäre sie tatsächlich vor der Verzweigung. Viele Prozessoren haben diese Art von Verzögerungsschlitzen und Compiler können damit gut umgehen. Frühe MIPS-Prozessoren hatten auch Verzögerungssteckplätze.
  • Halten Sie die Pipeline bedingungslos an , nachdem eine Verzweigung abgerufen wurde. Dies bedeutet, dass Sie den Programmzähler für einen Zyklus anhalten und ein NOP in die Pipeline einfügen, wenn Sie auf eine Verzweigung stoßen, wodurch der Verzögerungsschlitz effektiv ausgeblendet wird.
  • Spülen Sie die Pipeline, wenn eine Verzweigung genommen wird. Dies bedeutet, dass Ihr Prozessor den Befehlsstrom normal ausführt, bis er erkennt, dass er springen muss. An diesem Punkt wirft es alle Anweisungen nach dem Sprung weg, die es bereits abgerufen hat. In Ihrem Fall gäbe es nur eine einzige Anweisung zum Wegwerfen.

Sie können sich auch ansehen, wie klassische RISC-Pipelines organisiert sind und welche Gefahren in einer Pipeline stecken . Sobald Sie Speicherzugriffe in Ihrem Prozessor implementieren, stoßen Sie möglicherweise auch auf Gefahren, die dadurch verursacht werden, dass aus dem Speicher geladene Daten nicht schnell genug verfügbar sind. Sie können diese Probleme auf ähnliche Weise lösen, indem Sie entweder die Pipeline anhalten oder akzeptieren, dass Sie sogenannte Ladeverzögerungsschlitze haben, was bedeutet, dass die aus dem Speicher geladenen Daten nicht sofort für die Anweisung nach dem Laden verfügbar sind. Einige Prozessoren haben auch diese Art von Delay-Slots, obwohl sie weniger verbreitet sind als Branch-Delay-Slots.

Ist es in Ordnung, wenn ich nach der Verzweigung eine 32'h0 (Blase) Anweisung hinzufüge?
@katzesaal Wenn 32'h0 ein NOP ist, dann ja, das würde wunderbar funktionieren! Dann füllen Sie einfach den Delay-Slot mit einem NOP. Sie könnten auch eine Anweisung von vor der Verzweigung in den Verzögerungsschlitz ziehen (solange die Verzweigung nicht von ihrem Ergebnis abhängt). Dann verschwenden Sie nicht einmal einen Taktzyklus.
Wow, dieser Trick mit einem Instr anstelle von NOP ist cool) Vielen Dank für die Antwort.
  • Eine weitere gute Option ist die Verwendung der Verzweigungsvorhersage . Es gibt viele Verzweigungsvorhersagealgorithmen, die Sie recherchieren können. Viele moderne Prozessoren verwenden die Verzweigungsvorhersage. Wenn also der prognostizierte Abzweig der richtige ist, gewinnen und sparen Sie Zyklen. Wenn der vorhergesagte Zweig der falsche ist, müssen Sie die Daten löschen.

  • Die Ausführung außerhalb der Reihenfolge kann verwendet werden, um die CPU zu beschäftigen. Bei dieser Technik werden viele Leerlauf-/Verschwendungszyklen vermieden. Die Reihenfolge der Ausführung von Instruktionen ist nicht die ursprüngliche Reihenfolge bei der Out-of-Order-Ausführung.

Weiterlesen: