diff options
Diffstat (limited to 'rtl/core')
| -rw-r--r-- | rtl/core/psr.sv | 38 | ||||
| -rw-r--r-- | rtl/core/regs/regs.sv | 2 |
2 files changed, 32 insertions, 8 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 diff --git a/rtl/core/regs/regs.sv b/rtl/core/regs/regs.sv index 6ddf335..9b9ba57 100644 --- a/rtl/core/regs/regs.sv +++ b/rtl/core/regs/regs.sv @@ -29,7 +29,7 @@ module core_regs assign pc_word = {pc_visible, 2'b00}; assign rd_value_a = rd_pc_a ? pc_word : (wr_enable && rd_index_a == wr_index) ? wr_value : file_rd_value_a; - assign rd_value_b = rd_pc_b ? pc_word : (wr_enable && rd_index_a == wr_index) ? wr_value : file_rd_value_b; + assign rd_value_b = rd_pc_b ? pc_word : (wr_enable && rd_index_b == wr_index) ? wr_value : file_rd_value_b; assign file_wr_enable = wr_enable & ~wr_pc; assign branch = wr_enable & wr_pc; |
