summaryrefslogtreecommitdiff
path: root/rtl/core/psr.sv
blob: ee672e148c3145878bfc18bd1cdf429269771833 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
`include "core/uarch.sv"

module core_psr
(
	input  logic     clk,
	                 update_flags,
	                 alu_v_valid,
	input  psr_flags alu_flags,

	output psr_flags 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
		next_flags = flags;

		if(update_flags) begin
			next_flags = alu_flags;
			if(~alu_v_valid)
				next_flags.v = flags.v;
		end
	end

	always_ff @(posedge clk) begin
		wr_flags <= next_flags;
		if(pending_update)
			cpsr_flags <= flags;

		pending_update <= update_flags;
	end

	initial begin
		flags = 4'b0000;
		cpsr_flags = 4'b0000;
		pending_update = 0;
	end

endmodule