summaryrefslogtreecommitdiff
path: root/rtl
diff options
context:
space:
mode:
Diffstat (limited to 'rtl')
-rw-r--r--rtl/core/psr.sv38
-rw-r--r--rtl/core/regs/regs.sv2
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;