Задержка перехода на 1 команду в реализации Verilog и проблема синхронизации

У меня есть 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-битный регистр, в котором хранится счетчик программ

Я не понимаю, почему может быть проблема с этой схемой, но по какой-то причине вся схема задерживается на один такт, пока он не разветвляется (например, если у меня есть инструкция BEQ в 0x16, которая всегда переходит, она выполнится следующая инструкция в 0x18 и затем перейти к относительному смещению, но от 0x20).

Я почти чувствую, что решение прямо передо мной, но я не знаю, чего мне не хватает в семантике. Проблема смещения решается, если я удаляю +2 это всегда неявно, если только нет настоящего "пузыря" или аппаратного отказа, но задержка все еще присутствует.

Может кто-нибудь объяснить мне, что вызывает задержку и почему это происходит?

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;

Изменяя нашу схему в комбинаторную схему, нам больше не нужно сохранять состояние и, таким образом, уменьшать "буфер" в нашем процессе. ПК теперь может обновляться в течение (T) времени вместо (2T).

Другой способ кодирования комбинационной схемы:

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

Комбинационный блок должен иметь значение по умолчанию. Если в условном выражении не определено значение по умолчанию, оно сохранит свое значение и приведет к некорректному поведению. Комбинационный блок не должен содержать значение.

Для получения дополнительной информации о неожиданной защелке см. Это.

Другие вопросы по тегам