Verilog实现和同步问题

时间:2015-12-02 03:07:03

标签: synchronization mips verilog hardware-programming

我有一个16位单周期,非常稀疏的MIPS实现,我一直在Verilog工作。除了分支延迟一整个时钟周期之外,一切都有效。

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,除非存在真正的“气泡”或硬件引起的无操作,但延迟仍然存在,否则解决了偏移问题。

有人可以向我解释导致延迟的原因及其发生的原因吗?

2 个答案:

答案 0 :(得分:2)

答案是在PCLogic模块中使用状态会导致额外的传播延迟。通过删除PCLogic中的寄存器,我们删除模块本身中的隐式状态步骤,将其传播降低到可忽略的0。

所以答案是根据声明性表达式将pc_next块由always @(pc)块计算为1:

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

通过将电路更改为组合电路,我们不再需要存储状态,从而减少了我们工艺中的“缓冲区”。 PC现在可以在(T)时间而不是(2T)更新。

答案 1 :(得分: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时,很难读取assign语句。

注意这个

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

组合块应具有默认值。如果条件语句中没有定义默认值,它将保留其值并导致不正确的行为。组合块不能保留值。

有关意外锁定的详细信息,请参阅this