2015-12-02 20 views
2

我有一個16位單週期非常稀疏的MIPS實現,我一直在Verilog中進行研究。除了分支延遲了整個時鐘週期的事實之外,一切都可以工作。在Verilog實現和同步問題中的1指令分支延遲

always @(posedge clock) begin 
    // Necessary to add this in order to ensure PC => PC_next 
    iaddr <= pc_next 
end 

上面的代碼被用於更新程序計數器/指令地址,它來自一個模塊,PCLogic:

module PCLogic(
     pc_next, // next value of the pc 
     pc,  // current pc value 
     signext, // from sign extend circuit 
     branch, // beq instruction 
     alu_zero, // zero from ALU, used in cond branch 
     reset  // reset input 
     ); 

output [15:0] pc_next; 
input [15:0] pc; 
input [15:0] signext; // From sign extend circuit 
input branch; 
input alu_zero; 
input reset; 

reg [15:0] pc_next; 

    always @(pc or reset) begin 
     if (reset == 1) 
      pc_next = 0; 
     else if (branch == 1 && alu_zero == 1) 
      pc_next = pc+2+(signext << 1); 
     else 
      pc_next = pc+2; 
    end 

endmodule 

iaddr是存儲程序計數器的簡單的16位寄存器。

我不明白爲什麼這個電路可能有問題,但由於某種原因,整個電路延遲了一個時鐘週期,直到它分支(例如,如果我有一個總是跳轉的0x16 BEQ指令它將在0x18執行下一條指令,然後跳轉到相對偏移量,但從0x20開始)。

我幾乎可以感覺到解決方案就在我的面前,但我不知道我對語義缺少什麼。如果我刪除始終隱含的+2,則會解決偏移問題,除非存在真正的「泡」或硬件導致的空操作,但延遲仍然存在。

有人可以向我解釋是什麼原因導致延遲,爲什麼會發生?

+0

邏輯規定,只要'pc'改變,'alu_zero'的'branch'的*和*爲* zero *,那麼'pc_next'必須加2。從片段中,我猜'alu_zero'或'branch'沒有正確更新。你能分享一些僞測試臺或波形嗎? – sharvil111

+0

@ sharvil111其實我剛剛解決了這個問題!我會回答我自己的問題。 – VermillionAzure

+0

是的,連續分配工作。 – sharvil111

回答

2

答案是,在PCLogic模塊內使用狀態會導致額外的傳播延遲。通過去除在PCLogic寄存器,我們基於聲明表達式移除模塊本身中的隱式狀態的步驟,降低其傳播至可忽略不計0

因此,答案是改變pc_next到由always @(pc)塊計算一個:

wire [15:0] pc_next = (reset == 1)? 0 : (branch == 1 && alu_zero == 1)? pc+2+(signext << 1) : pc+2; 

通過改變我們的電路爲組合學電路,我們不再需要存儲狀態,從而降低了我們的進程「緩衝」。現在PC可以在(T)時間內更新,而不是(2T)。

2

另一種方式來編寫一個組合電路:

reg [15:0] pc_next; 

always @* begin 
    if (reset == 1) 
     pc_next = 0; 
    else if (branch == 1 && alu_zero == 1) 
     pc_next = pc+2+(signext << 1); 
    else 
     pc_next = pc+2; // latch will be inferred without this 
end 

,知道你們需要這時候你的組合電路變得更復雜,因爲分配的語句難以閱讀的時候有很多的嵌套的if-else。

注意這個

pc_next = pc+2; // latch will be inferred without this 

一個組合模塊,應該有一個默認值。如果在條件語句中沒有定義默認值,則它將保留其值並導致不正確的行爲。組合塊不能包含值。

有關意外鎖存器的更多信息,請參閱this

+0

這就是我最初編寫電路的方法。如果這樣做,它不起作用。但是,請等待......總是@(*)'改變了事情嗎?或者這基本上是一樣的?這和我原來的代碼有什麼區別? – VermillionAzure

+0

'always @(*)'對所有輸入信號都很敏感。對於複雜的電路來說,這是相同的,但更易讀,特別是當嵌套的if-else語句很多時。 – e19293001

+1

必須爲組合塊的所有輸入信號指定靈敏度列表。在你的代碼中,靈敏度列表必須是'always @(pc,reset,alu_zero,branch,signext)',因爲這些都是你的組合電路的輸入信號。爲了簡化,只需對所有組合塊使用'always @ *'。 – e19293001