diff options
Diffstat (limited to 'rtl/core/psr.sv')
| -rw-r--r-- | rtl/core/psr.sv | 38 |
1 files changed, 31 insertions, 7 deletions
diff --git a/rtl/core/psr.sv b/rtl/core/psr.sv index 30bb320..ee672e1 100644 --- a/rtl/core/psr.sv +++ b/rtl/core/psr.sv @@ -10,21 +10,45 @@ module core_psr output psr_flags flags ); - psr_flags cpsr_flags; + /* Este diseño de doble búfer es importante por rendimiento. Reducirlo + * a uno más "sencillo" tiene un costo de casi 40MHz menos en Fmax. + * Esto se debe a que el CPSR es el mayor mercado del core, se encuentra + * conectado a cycles, regs, alu y decode. La dependencia con decode en + * particular es crítica debido a que el condition code se especifica en + * términos de banderas de CPSR. Una ruta combinacional que atraviese flags + * iniciaría en cycles, tomaría valores de regs, llegaría a ALU, caería + * en flags y, debido al operand forwarding que se necesita por hazards de + * pipeline, esa misma señal seguiría combinacionalmente hacia decode para + * finalmente registrar en cycles nuevamente. Tal cosa es impermisible. + */ + + psr_flags cpsr_flags, next_flags, wr_flags; + logic pending_update; + + assign flags = pending_update ? wr_flags : cpsr_flags; always_comb begin - flags = cpsr_flags; + next_flags = flags; if(update_flags) begin - flags = alu_flags; + next_flags = alu_flags; if(~alu_v_valid) - flags.v = cpsr_flags.v; + next_flags.v = flags.v; end end - always_ff @(posedge clk) - cpsr_flags <= flags; + always_ff @(posedge clk) begin + wr_flags <= next_flags; + if(pending_update) + cpsr_flags <= flags; - initial cpsr_flags = 4'b0000; + pending_update <= update_flags; + end + + initial begin + flags = 4'b0000; + cpsr_flags = 4'b0000; + pending_update = 0; + end endmodule |
