CVE-2021-40507: Improper Authentication (CWE-287)
value: An issue was discovered in the ALU unit of the OR1200 (aka OpenRISC 1200) processor 2011-09-10 through 2015-11-11. The overflow flag is not being updated correctly for the subtract instruction, which results in an incorrect value in the overflow flag. Any software that relies on this flag may experience corruption in execution.
CWE description: When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct.
CVSS v3 base score: 9.8
Published: 2023-04-18T12:15Z
Repository: https://github.com/openrisc/or1200
Language: Other
Files changed: rtl/verilog/or1200_alu.v, rtl/verilog/or1200_cpu.v, rtl/verilog/or1200_defines.v, rtl/verilog/or1200_except.v, rtl/verilog/or1200_mult_mac.v, rtl/verilog/or1200_sprs.v
Commit date: 2011-09-01 18:49:24 +0000
Commit message: or1200: add carry, overflow bits, and range exception

Diff: diff --git a/rtl/verilog/or1200_alu.v b/rtl/verilog/or1200_alu.v
index 53c2698..a922078 100644
--- a/rtl/verilog/or1200_alu.v
+++ b/rtl/verilog/or1200_alu.v
@@ -54,10 +54,11 @@
 module or1200_alu(
 	a, b, mult_mac_result, macrc_op,
 	alu_op, alu_op2, comp_op,
 	cust5_op, cust5_limm,
 	result, flagforw, flag_we,
+	ovforw, ov_we,
 	cyforw, cy_we, carry, flag
 );
 
 parameter width = `OR1200_OPERAND_WIDTH;
 
@@ -76,10 +77,12 @@ input	[5:0]			cust5_limm;
 output	[width-1:0]		result;
 output				flagforw;
 output				flag_we;
 output				cyforw;
 output				cy_we;
+output				ovforw;
+output				ov_we;
 input				carry;
 input         flag;
 
 //
 // Internal wires and regs
@@ -89,28 +92,32 @@ reg	[width-1:0]		shifted_rotated;
 reg	[width-1:0]		extended;   
 reg	[width-1:0]		result_cust5;
 reg				flagforw;
 reg				flagcomp;
 reg				flag_we;
+reg				cyforw;
 reg				cy_we;
+reg				ovforw;
+reg				ov_we;   
 wire	[width-1:0]		comp_a;
 wire	[width-1:0]		comp_b;
 `ifdef OR1200_IMPL_ALU_COMP1
 wire				a_eq_b;
 wire				a_lt_b;
 `endif
 wire	[width-1:0]		result_sum;
-`ifdef OR1200_IMPL_ADDC
-wire	[width-1:0]		result_csum;
-wire				cy_csum;
-`endif
 wire	[width-1:0]		result_and;
 wire				cy_sum;
 `ifdef OR1200_IMPL_SUB
 wire				cy_sub;
 `endif
-reg				cyforw;
+wire    			ov_sum;
+wire    [width-1:0] 		carry_in;
+
+wire    [width-1:0]		b_mux;
+   
+   
 
 //
 // Combinatorial logic
 //
 assign comp_a = {a[width-1] ^ comp_op[3] , a[width-2:0]};
@@ -118,16 +125,28 @@ assign comp_b = {b[width-1] ^ comp_op[3] , b[width-2:0]};
 `ifdef OR1200_IMPL_ALU_COMP1
 assign a_eq_b = (comp_a == comp_b);
 assign a_lt_b = (comp_a < comp_b);
 `endif
 `ifdef OR1200_IMPL_SUB
-assign cy_sub = a < b;
+assign cy_sub = (comp_a < comp_b);
 `endif
-assign {cy_sum, result_sum} = a + b;
-`ifdef OR1200_IMPL_ADDC
-assign {cy_csum, result_csum} = a + b + {`OR1200_OPERAND_WIDTH'd0, carry};
+`ifdef OR1200_IMPL_ADDC   
+assign carry_in = (alu_op==`OR1200_ALUOP_ADDC) ? 
+		  {{width-1{1'b0}},carry} : {width{1'b0}};
+`else
+assign carry_in = {width-1{1'b0}};
 `endif
+`ifdef OR1200_IMPL_SUB
+assign b_mux = (alu_op==`OR1200_ALUOP_SUB) ? (~b)+1 : b;
+`else
+assign b_mux = b;
+`endif   
+assign {cy_sum, result_sum} = (a + b_mux) + carry_in;
+// Numbers either both +ve and bit 31 of result set
+assign ov_sum = ((!a[width-1] & !b_mux[width-1]) & result_sum[width-1]) |
+// or both -ve and bit 31 of result clear
+		((a[width-1] & b_mux[width-1]) & !result_sum[width-1]);  
 assign result_and = a & b;
 
 //
 // Simulation check for bad ALU behavior
 //
@@ -143,13 +162,10 @@ end
 //
 // Central part of the ALU
 //
 always @(alu_op or alu_op2 or a or b or result_sum or result_and or macrc_op
 	 or shifted_rotated or mult_mac_result or flag or result_cust5 or carry
-`ifdef OR1200_IMPL_ADDC
-         or result_csum
-`endif
 `ifdef OR1200_IMPL_ALU_EXT
          or extended
 `endif	 
 ) begin
 `ifdef OR1200_CASE_DEFAULT
@@ -180,23 +196,19 @@ always @(alu_op or alu_op2 or a or b or result_sum or result_and or macrc_op
 		end
 `endif		     
 		`OR1200_ALUOP_SHROT : begin 
 				result = shifted_rotated;
 		end
-		`OR1200_ALUOP_ADD : begin
-				result = result_sum;
-		end
 `ifdef OR1200_IMPL_ADDC
-		`OR1200_ALUOP_ADDC : begin
-				result = result_csum;
-		end
+		`OR1200_ALUOP_ADDC,
 `endif
 `ifdef OR1200_IMPL_SUB
-		`OR1200_ALUOP_SUB : begin
-				result = a - b;
+		`OR1200_ALUOP_SUB,
+`endif	 
+		`OR1200_ALUOP_ADD : begin
+				result = result_sum;
 		end
-`endif
 		`OR1200_ALUOP_XOR : begin
 				result = a ^ b;
 		end
 		`OR1200_ALUOP_OR  : begin
 				result = a | b;
@@ -243,26 +255,20 @@ end
 
 //
 // Generate flag and flag write enable
 //
 always @(alu_op or result_sum or result_and or flagcomp
-`ifdef OR1200_IMPL_ADDC
-         or result_csum
-`endif
 ) begin
 	casez (alu_op)		// synopsys parallel_case
 `ifdef OR1200_ADDITIONAL_FLAG_MODIFIERS
+`ifdef OR1200_IMPL_ADDC
+		`OR1200_ALUOP_ADDC,
+`endif	 
 		`OR1200_ALUOP_ADD : begin
 			flagforw = (result_sum == 32'h0000_0000);
 			flag_we = 1'b1;
 		end
-`ifdef OR1200_IMPL_ADDC
-		`OR1200_ALUOP_ADDC : begin
-			flagforw = (result_csum == 32'h0000_0000);
-			flag_we = 1'b1;
-		end
-`endif
 		`OR1200_ALUOP_AND: begin
 			flagforw = (result_and == 32'h0000_0000);
 			flag_we = 1'b1;
 		end
 `endif
@@ -280,30 +286,24 @@ end
 //
 // Generate SR[CY] write enable
 //
 always @(alu_op or cy_sum
 `ifdef OR1200_IMPL_CY
-`ifdef OR1200_IMPL_ADDC
-	or cy_csum
-`endif
 `ifdef OR1200_IMPL_SUB
 	or cy_sub
 `endif
 `endif
 ) begin
 	casez (alu_op)		// synopsys parallel_case
 `ifdef OR1200_IMPL_CY
+`ifdef OR1200_IMPL_ADDC
+		`OR1200_ALUOP_ADDC,
+`endif	  
 		`OR1200_ALUOP_ADD : begin
 			cyforw = cy_sum;
 			cy_we = 1'b1;
 		end
-`ifdef OR1200_IMPL_ADDC
-		`OR1200_ALUOP_ADDC: begin
-			cyforw = cy_csum;
-			cy_we = 1'b1;
-		end
-`endif
 `ifdef OR1200_IMPL_SUB
 		`OR1200_ALUOP_SUB: begin
 			cyforw = cy_sub;
 			cy_we = 1'b1;
 		end
@@ -314,10 +314,35 @@ always @(alu_op or cy_sum
 			cy_we = 1'b0;
 		end
 	endcase
 end
 
+
+//
+// Generate SR[OV] write enable
+//
+always @(alu_op or ov_sum) begin
+	casez (alu_op)		// synopsys parallel_case
+`ifdef OR1200_IMPL_OV
+`ifdef OR1200_IMPL_ADDC
+		`OR1200_ALUOP_ADDC,
+`endif
+`ifdef OR1200_IMPL_SUB
+		`OR1200_ALUOP_SUB,
+`endif	 
+		`OR1200_ALUOP_ADD : begin
+			ovforw = ov_sum;
+			ov_we = 1'b1;
+		end
+`endif	  
+		default: begin
+			ovforw = 1'b0;
+			ov_we = 1'b0;
+		end
+	endcase
+end
+   
 //
 // Shifts and rotation
 //
 always @(alu_op2 or a or b) begin
 	case (alu_op2)		// synopsys parallel_case
diff --git a/rtl/verilog/or1200_cpu.v b/rtl/verilog/or1200_cpu.v
index 2b6ccf7..69405e4 100644
--- a/rtl/verilog/or1200_cpu.v
+++ b/rtl/verilog/or1200_cpu.v
@@ -269,10 +269,14 @@ wire				flag_we_alu;
 wire				flagforw_fpu;
 wire				flag_we_fpu;
 wire				carry;
 wire				cyforw;
 wire				cy_we_alu;
+wire				ovforw;
+wire				ov_we_alu;
+wire				ovforw_mult_mac;
+wire				ov_we_mult_mac;   
 wire				cy_we_rf;
 wire				lsu_stall;
 wire				epcr_we;
 wire				eear_we;
 wire				esr_we;
@@ -290,10 +294,11 @@ wire				except_start;
 wire				except_started;
 wire    			fpu_except_started;   
 wire	[31:0]			wb_insn;
 wire				sig_syscall;
 wire				sig_trap;
+wire    			sig_range;
 wire				sig_fp;
 wire	[31:0]			spr_dat_cfgr;
 wire	[31:0]			spr_dat_rf;
 wire    [31:0]                  spr_dat_npc;
 wire	[31:0]			spr_dat_ppc;
@@ -391,13 +396,19 @@ assign supv = sr[`OR1200_SR_SM];
 //
 assign flagforw = (flag_we_alu & flagforw_alu) | (flagforw_fpu & flag_we_fpu);
 assign flag_we = (flag_we_alu | flag_we_fpu) & ~abort_mvspr;
 
 //
-//  Flag for any MTSPR instructions, that must block execution, to indicate done
+// Flag for any MTSPR instructions, that must block execution, to indicate done
 //
 assign mtspr_done = mtspr_dc_done;
+
+//
+// Range exception
+//
+assign sig_range = sr[`OR1200_SR_OV];
+   
    
    
 //
 // Instantiation of instruction fetch block
 //
@@ -589,10 +600,12 @@ or1200_alu or1200_alu(
 	.result(alu_dataout),
 	.flagforw(flagforw_alu),
 	.flag_we(flag_we_alu),
 	.cyforw(cyforw),
 	.cy_we(cy_we_alu),
+	.ovforw(ovforw),
+	.ov_we(ov_we_alu),		      
 	.flag(flag),
 	.carry(carry)
 );
 
    
@@ -639,10 +652,12 @@ or1200_mult_mac or1200_mult_mac(
 	.a(operand_a),
 	.b(operand_b),
 	.mac_op(mac_op),
 	.alu_op(alu_op),
 	.result(mult_mac_result),
+	.ovforw(ovforw_mult_mac), 
+	.ov_we(ov_we_mult_mac),
 	.mult_mac_stall(mult_mac_stall),
 	.spr_cs(spr_cs[`OR1200_SPR_GROUP_MAC]),
 	.spr_write(spr_we),
 	.spr_addr(spr_addr),
 	.spr_dat_i(spr_dat_cpu),
@@ -664,10 +679,12 @@ or1200_sprs or1200_sprs(
 	.flag_we(flag_we),
 	.flag(flag),
 	.cyforw(cyforw),
 	.cy_we(cy_we_rf),
 	.carry(carry),
+	.ovforw(ovforw | ovforw_mult_mac),
+	.ov_we(ov_we_alu | ov_we_mult_mac),
 	.to_wbmux(sprs_dataout),
 
 	.du_addr(du_addr),
 	.du_dat_du(du_dat_du),
 	.du_read(du_read),
@@ -801,11 +818,11 @@ or1200_except or1200_except(
 	.rst(rst),
 	.sig_ibuserr(except_ibuserr),
 	.sig_dbuserr(except_dbuserr),
 	.sig_illegal(except_illegal),
 	.sig_align(except_align),
-	.sig_range(1'b0),
+	.sig_range(sig_range),
 	.sig_dtlbmiss(except_dtlbmiss),
 	.sig_dmmufault(except_dmmufault),
 	.sig_int(sig_int),
 	.sig_syscall(sig_syscall),
 	.sig_trap(sig_trap),
diff --git a/rtl/verilog/or1200_defines.v b/rtl/verilog/or1200_defines.v
index 5584210..d2baf97 100644
--- a/rtl/verilog/or1200_defines.v
+++ b/rtl/verilog/or1200_defines.v
@@ -297,11 +297,11 @@
 // By default implementation of l.addc/l.addic
 // instructions is enabled in case you need them.
 // If you don't use them, then disable implementation
 // to save area.
 //
-//`define OR1200_IMPL_ADDC
+`define OR1200_IMPL_ADDC
 
 //
 // Implement l.sub instruction
 //
 // By default implementation of l.sub instructions
@@ -319,11 +319,28 @@
 // to be compliant with the simulator. However SR[CY]
 // is explicitly only used by l.addc/l.addic/l.sub
 // instructions and if these three insns are not
 // implemented there is not much point having SR[CY].
 //
-//`define OR1200_IMPL_CY
+`define OR1200_IMPL_CY
+
+//
+// Implement carry bit SR[OV]
+//
+// Compiler doesn't use this, but other code may like
+// to.
+//
+`define OR1200_IMPL_OV
+
+//
+// Implement carry bit SR[OVE]
+//
+// Overflow interrupt indicator. When enabled, SR[OV] flag
+// does not remain asserted after exception.
+//
+`define OR1200_IMPL_OVE
+
 
 //
 // Implement rotate in the ALU
 //
 // At the time of writing this, or32
@@ -823,13 +840,13 @@
 `define OR1200_SR_DME  5
 `define OR1200_SR_IME  6
 `define OR1200_SR_LEE  7
 `define OR1200_SR_CE   8
 `define OR1200_SR_F    9
-`define OR1200_SR_CY   10	// Unused
-`define OR1200_SR_OV   11	// Unused
-`define OR1200_SR_OVE  12	// Unused
+`define OR1200_SR_CY   10	// Optional
+`define OR1200_SR_OV   11	// Optional
+`define OR1200_SR_OVE  12	// Optional
 `define OR1200_SR_DSX  13	// Unused
 `define OR1200_SR_EPH  14
 `define OR1200_SR_FO   15
 `define OR1200_SR_TED  16
 `define OR1200_SR_CID  31:28	// Unimplemented
diff --git a/rtl/verilog/or1200_except.v b/rtl/verilog/or1200_except.v
index 5a2e43b..e42424a 100644
--- a/rtl/verilog/or1200_except.v
+++ b/rtl/verilog/or1200_except.v
@@ -174,11 +174,12 @@ wire				except_flushpipe /* verilator public */;
 reg	[2:0]			delayed_iee;
 reg	[2:0]			delayed_tee;
 wire				int_pending;
 wire				tick_pending;
 wire    			fp_pending;
-   
+wire    			range_pending;
+			
 reg trace_trap      ;
 reg ex_freeze_prev;
 reg sr_ted_prev;
 reg dsr_te_prev;
 reg dmr1_st_prev    ;
@@ -205,10 +206,17 @@ assign tick_pending = sig_tick & (sr[`OR1200_SR_TEE] |
 		      & delayed_tee[2] & ~ex_freeze & ~ex_branch_taken 
 		      & ~ex_dslot & ~(sr_we & ~to_sr[`OR1200_SR_TEE]);
 
 assign fp_pending = sig_fp & fpcsr_fpee & ~ex_freeze & ~ex_branch_taken 
 		    & ~ex_dslot;
+
+`ifdef OR1200_IMPL_OVE   
+assign range_pending =  sig_range & sr[`OR1200_SR_OVE] & ~ex_freeze & 
+		       ~ex_branch_taken & ~ex_dslot;
+`else
+assign range_pending = 0;
+`endif   
    
 // Abort write into RF by load & other instructions   
 assign abort_ex = sig_dbuserr | sig_dmmufault | sig_dtlbmiss | sig_align | 
 		  sig_illegal | ((du_hwbkpt | trace_trap) & ex_pc_val 
 				 & !sr_ted & !dsr_te);
@@ -232,11 +240,11 @@ assign except_trig = {
 		      sig_dtlbmiss	& ~du_dsr[`OR1200_DU_DSR_DME],
 		      sig_trap		& ~du_dsr[`OR1200_DU_DSR_TE],
 		      sig_syscall       & ~du_dsr[`OR1200_DU_DSR_SCE] & ~ex_freeze,
 		      sig_dmmufault	& ~du_dsr[`OR1200_DU_DSR_DPFE],
 		      sig_dbuserr	& ~du_dsr[`OR1200_DU_DSR_BUSEE],
-		      sig_range		& ~du_dsr[`OR1200_DU_DSR_RE],
+		      range_pending	& ~du_dsr[`OR1200_DU_DSR_RE],
 		      fp_pending	& ~du_dsr[`OR1200_DU_DSR_FPE],
 		      int_pending 	& ~du_dsr[`OR1200_DU_DSR_IE],
 		      tick_pending	& ~du_dsr[`OR1200_DU_DSR_TTE]
 		      };
 
@@ -258,11 +266,11 @@ assign except_stop = {
 			sig_illegal		& du_dsr[`OR1200_DU_DSR_IIE],
 			sig_align		& du_dsr[`OR1200_DU_DSR_AE],
 			sig_dtlbmiss		& du_dsr[`OR1200_DU_DSR_DME],
 			sig_dmmufault		& du_dsr[`OR1200_DU_DSR_DPFE],
 			sig_dbuserr		& du_dsr[`OR1200_DU_DSR_BUSEE],
-			sig_range		& du_dsr[`OR1200_DU_DSR_RE],
+			range_pending		& du_dsr[`OR1200_DU_DSR_RE],
 			sig_trap		& du_dsr[`OR1200_DU_DSR_TE],
 		        fp_pending  		& du_dsr[`OR1200_DU_DSR_FPE],
 			sig_syscall		& du_dsr[`OR1200_DU_DSR_SCE] & ~ex_freeze
 		};
 
diff --git a/rtl/verilog/or1200_mult_mac.v b/rtl/verilog/or1200_mult_mac.v
index 646608e..73f26b4 100644
--- a/rtl/verilog/or1200_mult_mac.v
+++ b/rtl/verilog/or1200_mult_mac.v
@@ -63,10 +63,13 @@ module or1200_mult_mac(
 
 		       // Multiplier/MAC interface
 		       ex_freeze, id_macrc_op, macrc_op, a, b, mac_op, alu_op, 
 		       result, mult_mac_stall,
 
+		       // Overflow
+		       ovforw, ov_we,
+		       
 		       // SPR interface
 		       spr_cs, spr_write, spr_addr, spr_dat_i, spr_dat_o
 		       );
 
    parameter width = `OR1200_OPERAND_WIDTH;
@@ -91,11 +94,12 @@ module or1200_mult_mac(
    input [width-1:0] 			b;
    input [`OR1200_MACOP_WIDTH-1:0] 	mac_op;
    input [`OR1200_ALUOP_WIDTH-1:0] 	alu_op;
    output [width-1:0] 			result;
    output				mult_mac_stall;
-
+   output 				ovforw, ov_we;
+   
    //
    // SPR interface
    //
    input				spr_cs;
    input				spr_write;
@@ -152,13 +156,15 @@ module or1200_mult_mac(
    wire [width-1:0] 			div_tmp;
    reg [5:0] 				div_cntr;
  `else
    reg [width-1:0] 			div_quot_r;      
    reg [width-1:0] 			div_quot_generic;   
- `endif   
+ `endif
+   wire 				div_by_zero;
 `endif
-
+   reg 					ovforw, ov_we;
+   
    //
    // Combinatorial logic
    //
 `ifdef OR1200_MULT_IMPLEMENTED
    assign alu_op_smul = (alu_op == `OR1200_ALUOP_MUL);
@@ -187,10 +193,13 @@ module or1200_mult_mac(
    assign x = (alu_op_sdiv | alu_op_smul) & a[31] ? ~a + 32'b1 : 
 	      alu_op_div | alu_op_mul | (|mac_op) ? a : 32'd0;
    assign y = (alu_op_sdiv | alu_op_smul) & b[31] ? ~b + 32'b1 : 
 	      alu_op_div | alu_op_mul | (|mac_op) ? b : 32'd0;
 
+   assign div_by_zero = !(|b) & alu_op_div;
+   
+
    // Used to indicate when we should check for new multiply or MAC ops
    always @(posedge clk or `OR1200_RST_EVENT rst)
      if (rst == `OR1200_RST_VALUE)
        ex_freeze_r <= 1'b1;
      else
@@ -226,11 +235,47 @@ module or1200_mult_mac(
        result = mac_r[31:0];
  `endif
 `else
        result = {width{1'b0}};    
 `endif    
-     endcase
+     endcase // casez (alu_op)
+
+
+   //
+   // Overflow generation
+   //
+   always @*
+     casez(alu_op)	// synopsys parallel_case
+`ifdef OR1200_IMPL_OV       
+ `ifdef OR1200_MULT_IMPLEMENTED
+       `OR1200_ALUOP_MUL: begin
+	  // Actually doing unsigned multiply internally, and then negate on
+	  // output as appropriate, so if sign bit is set, then is overflow
+	  ovforw = mul_prod_r[31];
+	  ov_we = 1;
+       end
+       `OR1200_ALUOP_MULU : begin
+	  // Overflow on unsigned multiply is simpler.
+	  ovforw = mul_prod_r[32];
+	  ov_we = 1;
+       end
+ `endif //  `ifdef OR1200_MULT_IMPLEMENTED
+ `ifdef OR1200_DIV_IMPLEMENTED
+       `OR1200_ALUOP_DIVU,
+       `OR1200_ALUOP_DIV: begin
+	  // Overflow on divide by zero
+	  ovforw = div_by_zero;
+	  ov_we = 1;
+       end
+ `endif
+`endif //  `ifdef OR1200_IMPL_OV
+       default: begin
+	  ovforw = 0;
+	  ov_we = 0;
+       end
+     endcase // casez (alu_op)
+   
 
 `ifdef OR1200_MULT_IMPLEMENTED
  `ifdef OR1200_MULT_SERIAL
 
    always @(`OR1200_RST_EVENT rst or posedge clk)
@@ -396,10 +441,15 @@ module or1200_mult_mac(
      if (rst == `OR1200_RST_VALUE) begin
 	div_quot_r <=  64'h0000_0000_0000_0000;
 	div_free <=  1'b1;
 	div_cntr <=  6'b00_0000;
      end
+     else if (div_by_zero) begin
+	div_quot_r <=  64'h0000_0000_0000_0000;
+	div_free <=  1'b1;
+	div_cntr <=  6'b00_0000;
+     end
      else if (|div_cntr) begin
 	if (div_tmp[31])
 	  div_quot_r <=  {div_quot_r[62:0], 1'b0};
 	else
 	  div_quot_r <=  {div_tmp[30:0], div_quot_r[31:0], 1'b1};
diff --git a/rtl/verilog/or1200_sprs.v b/rtl/verilog/or1200_sprs.v
index 451db92..8285e31 100644
--- a/rtl/verilog/or1200_sprs.v
+++ b/rtl/verilog/or1200_sprs.v
@@ -55,10 +55,11 @@ module or1200_sprs(
 		   // Clk & Rst
 		   clk, rst,
 
 		   // Internal CPU interface
 		   flagforw, flag_we, flag, cyforw, cy_we, carry,
+		   ovforw, ov_we,
 		   addrbase, addrofs, dat_i, branch_op, ex_spr_read, 
 		   ex_spr_write, 
 		   epcr, eear, esr, except_started,
 		   to_wbmux, epcr_we, eear_we, esr_we, pc_we, sr_we, to_sr, sr,
 		   spr_dat_cfgr, spr_dat_rf, spr_dat_npc, spr_dat_ppc, 
@@ -94,10 +95,12 @@ module or1200_sprs(
    input 				flag_we;	// From ALU
    output 				flag;		// SR[F]
    input 				cyforw;		// From ALU
    input 				cy_we;		// From ALU
    output 				carry;		// SR[CY]
+   input 				ovforw;		// From ALU
+   input 				ov_we;		// From ALU
    input [width-1:0] 			addrbase;	// SPR base address
    input [15:0] 			addrofs;	// SPR offset
    input [width-1:0] 			dat_i;		// SPR write data
    input 				ex_spr_read;	// l.mfspr in EX
    input 				ex_spr_write;	// l.mtspr in EX
@@ -283,22 +286,27 @@ module or1200_sprs(
    //
 
    //
    // What to write into SR
    //
-   assign to_sr[`OR1200_SR_FO:`OR1200_SR_OV] 
-	    = (except_started) ? sr[`OR1200_SR_FO:`OR1200_SR_OV] :
+   assign to_sr[`OR1200_SR_FO:`OR1200_SR_OVE] 
+	    = (except_started) ? {sr[`OR1200_SR_FO:`OR1200_SR_DSX],1'b0} :
 	      (branch_op == `OR1200_BRANCHOP_RFE) ? 
-	      esr[`OR1200_SR_FO:`OR1200_SR_OV] : (spr_we && sr_sel) ? 
-	      {1'b1, spr_dat_o[`OR1200_SR_FO-1:`OR1200_SR_OV]} :
-	      sr[`OR1200_SR_FO:`OR1200_SR_OV];
+	      esr[`OR1200_SR_FO:`OR1200_SR_OVE] : (spr_we && sr_sel) ? 
+	      {1'b1, spr_dat_o[`OR1200_SR_FO-1:`OR1200_SR_OVE]} :
+	      sr[`OR1200_SR_FO:`OR1200_SR_OVE];
    assign to_sr[`OR1200_SR_TED] 
 	    = (except_started) ? 1'b1 :
 	      (branch_op == `OR1200_BRANCHOP_RFE) ? esr[`OR1200_SR_TED] :
 	      (spr_we && sr_sel) ? spr_dat_o[`OR1200_SR_TED] :
 	      sr[`OR1200_SR_TED];
-   
+   assign to_sr[`OR1200_SR_OV] 
+	    = (except_started) ? sr[`OR1200_SR_OV] :
+	      (branch_op == `OR1200_BRANCHOP_RFE) ? esr[`OR1200_SR_OV] :
+	      ov_we ? ovforw :
+	      (spr_we && sr_sel) ? spr_dat_o[`OR1200_SR_OV] :
+	      sr[`OR1200_SR_OV];
    assign to_sr[`OR1200_SR_CY] 
 	    = (except_started) ? sr[`OR1200_SR_CY] :
 	      (branch_op == `OR1200_BRANCHOP_RFE) ? esr[`OR1200_SR_CY] :
 	      cy_we ? cyforw :
 	      (spr_we && sr_sel) ? spr_dat_o[`OR1200_SR_CY] :
@@ -343,11 +351,11 @@ module or1200_sprs(
 
    //
    // Write enables for system SPRs
    //
    assign sr_we = (spr_we && sr_sel) | (branch_op == `OR1200_BRANCHOP_RFE) | 
-		  flag_we | cy_we;
+		  flag_we | cy_we | ov_we;
    assign pc_we = (du_write && (npc_sel | ppc_sel));
    assign epcr_we = (spr_we && epcr_sel);
    assign eear_we = (spr_we && eear_sel);
    assign esr_we = (spr_we && esr_sel);
    assign fpcsr_we = (spr_we && fpcsr_sel);
@@ -373,11 +381,11 @@ module or1200_sprs(
 
    //
    // Carry alias
    //
    assign carry = sr[`OR1200_SR_CY];
-
+   
    //
    // Supervision register
    //
    always @(posedge clk or `OR1200_RST_EVENT rst)
      if (rst == `OR1200_RST_VALUE)

Vulnerable code: `ifdef OR1200_IMPL_ADDC
wire	[width-1:0]		result_csum;
wire				cy_csum;
`endif
reg				cyforw;
assign cy_sub = a < b;
assign {cy_sum, result_sum} = a + b;
`ifdef OR1200_IMPL_ADDC
assign {cy_csum, result_csum} = a + b + {`OR1200_OPERAND_WIDTH'd0, carry};
`ifdef OR1200_IMPL_ADDC
         or result_csum
`endif
		`OR1200_ALUOP_ADD : begin
				result = result_sum;
		end
		`OR1200_ALUOP_ADDC : begin
				result = result_csum;
		end
		`OR1200_ALUOP_SUB : begin
				result = a - b;
`endif
`ifdef OR1200_IMPL_ADDC
         or result_csum
`endif
`ifdef OR1200_IMPL_ADDC
		`OR1200_ALUOP_ADDC : begin
			flagforw = (result_csum == 32'h0000_0000);
			flag_we = 1'b1;
		end
`endif
`ifdef OR1200_IMPL_ADDC
	or cy_csum
`endif
`ifdef OR1200_IMPL_ADDC
		`OR1200_ALUOP_ADDC: begin
			cyforw = cy_csum;
			cy_we = 1'b1;
		end
`endif
//  Flag for any MTSPR instructions, that must block execution, to indicate done
	.sig_range(1'b0),
//`define OR1200_IMPL_ADDC
//`define OR1200_IMPL_CY
`define OR1200_SR_CY   10	// Unused
`define OR1200_SR_OV   11	// Unused
`define OR1200_SR_OVE  12	// Unused
   
		      sig_range		& ~du_dsr[`OR1200_DU_DSR_RE],
			sig_range		& du_dsr[`OR1200_DU_DSR_RE],

 `endif   

     endcase
   assign to_sr[`OR1200_SR_FO:`OR1200_SR_OV] 
	    = (except_started) ? sr[`OR1200_SR_FO:`OR1200_SR_OV] :
	      esr[`OR1200_SR_FO:`OR1200_SR_OV] : (spr_we && sr_sel) ? 
	      {1'b1, spr_dat_o[`OR1200_SR_FO-1:`OR1200_SR_OV]} :
	      sr[`OR1200_SR_FO:`OR1200_SR_OV];
   
		  flag_we | cy_we;

Fixed code: 	ovforw, ov_we,
output				ovforw;
output				ov_we;
reg				cyforw;
reg				ovforw;
reg				ov_we;   
wire    			ov_sum;
wire    [width-1:0] 		carry_in;

wire    [width-1:0]		b_mux;
   
   
assign cy_sub = (comp_a < comp_b);
`ifdef OR1200_IMPL_ADDC   
assign carry_in = (alu_op==`OR1200_ALUOP_ADDC) ? 
		  {{width-1{1'b0}},carry} : {width{1'b0}};
`else
assign carry_in = {width-1{1'b0}};
`ifdef OR1200_IMPL_SUB
assign b_mux = (alu_op==`OR1200_ALUOP_SUB) ? (~b)+1 : b;
`else
assign b_mux = b;
`endif   
assign {cy_sum, result_sum} = (a + b_mux) + carry_in;
// Numbers either both +ve and bit 31 of result set
assign ov_sum = ((!a[width-1] & !b_mux[width-1]) & result_sum[width-1]) |
// or both -ve and bit 31 of result clear
		((a[width-1] & b_mux[width-1]) & !result_sum[width-1]);  
		`OR1200_ALUOP_ADDC,
		`OR1200_ALUOP_SUB,
`endif	 
		`OR1200_ALUOP_ADD : begin
				result = result_sum;
`ifdef OR1200_IMPL_ADDC
		`OR1200_ALUOP_ADDC,
`endif	 
`ifdef OR1200_IMPL_ADDC
		`OR1200_ALUOP_ADDC,
`endif	  

//
// Generate SR[OV] write enable
//
always @(alu_op or ov_sum) begin
	casez (alu_op)		// synopsys parallel_case
`ifdef OR1200_IMPL_OV
`ifdef OR1200_IMPL_ADDC
		`OR1200_ALUOP_ADDC,
`endif
`ifdef OR1200_IMPL_SUB
		`OR1200_ALUOP_SUB,
`endif	 
		`OR1200_ALUOP_ADD : begin
			ovforw = ov_sum;
			ov_we = 1'b1;
		end
`endif	  
		default: begin
			ovforw = 1'b0;
			ov_we = 1'b0;
		end
	endcase
end
   
wire				ovforw;
wire				ov_we_alu;
wire				ovforw_mult_mac;
wire				ov_we_mult_mac;   
wire    			sig_range;
// Flag for any MTSPR instructions, that must block execution, to indicate done

//
// Range exception
//
assign sig_range = sr[`OR1200_SR_OV];
   
	.ovforw(ovforw),
	.ov_we(ov_we_alu),		      
	.ovforw(ovforw_mult_mac), 
	.ov_we(ov_we_mult_mac),
	.ovforw(ovforw | ovforw_mult_mac),
	.ov_we(ov_we_alu | ov_we_mult_mac),
	.sig_range(sig_range),
`define OR1200_IMPL_ADDC
`define OR1200_IMPL_CY

//
// Implement carry bit SR[OV]
//
// Compiler doesn't use this, but other code may like
// to.
//
`define OR1200_IMPL_OV

//
// Implement carry bit SR[OVE]
//
// Overflow interrupt indicator. When enabled, SR[OV] flag
// does not remain asserted after exception.
//
`define OR1200_IMPL_OVE

`define OR1200_SR_CY   10	// Optional
`define OR1200_SR_OV   11	// Optional
`define OR1200_SR_OVE  12	// Optional
wire    			range_pending;
			

`ifdef OR1200_IMPL_OVE   
assign range_pending =  sig_range & sr[`OR1200_SR_OVE] & ~ex_freeze & 
		       ~ex_branch_taken & ~ex_dslot;
`else
assign range_pending = 0;
`endif   
		      range_pending	& ~du_dsr[`OR1200_DU_DSR_RE],
			range_pending		& du_dsr[`OR1200_DU_DSR_RE],
		       // Overflow
		       ovforw, ov_we,
		       
   output 				ovforw, ov_we;
   
 `endif
   wire 				div_by_zero;
   reg 					ovforw, ov_we;
   
   assign div_by_zero = !(|b) & alu_op_div;
   

     endcase // casez (alu_op)


   //
   // Overflow generation
   //
   always @*
     casez(alu_op)	// synopsys parallel_case
`ifdef OR1200_IMPL_OV       
 `ifdef OR1200_MULT_IMPLEMENTED
       `OR1200_ALUOP_MUL: begin
	  // Actually doing unsigned multiply internally, and then negate on
	  // output as appropriate, so if sign bit is set, then is overflow
	  ovforw = mul_prod_r[31];
	  ov_we = 1;
       end
       `OR1200_ALUOP_MULU : begin
	  // Overflow on unsigned multiply is simpler.
	  ovforw = mul_prod_r[32];
	  ov_we = 1;
       end
 `endif //  `ifdef OR1200_MULT_IMPLEMENTED
 `ifdef OR1200_DIV_IMPLEMENTED
       `OR1200_ALUOP_DIVU,
       `OR1200_ALUOP_DIV: begin
	  // Overflow on divide by zero
	  ovforw = div_by_zero;
	  ov_we = 1;
       end
 `endif
`endif //  `ifdef OR1200_IMPL_OV
       default: begin
	  ovforw = 0;
	  ov_we = 0;
       end
     endcase // casez (alu_op)
   
     else if (div_by_zero) begin
	div_quot_r <=  64'h0000_0000_0000_0000;
	div_free <=  1'b1;
	div_cntr <=  6'b00_0000;
     end
		   ovforw, ov_we,
   input 				ovforw;		// From ALU
   input 				ov_we;		// From ALU
   assign to_sr[`OR1200_SR_FO:`OR1200_SR_OVE] 
	    = (except_started) ? {sr[`OR1200_SR_FO:`OR1200_SR_DSX],1'b0} :
	      esr[`OR1200_SR_FO:`OR1200_SR_OVE] : (spr_we && sr_sel) ? 
	      {1'b1, spr_dat_o[`OR1200_SR_FO-1:`OR1200_SR_OVE]} :
	      sr[`OR1200_SR_FO:`OR1200_SR_OVE];
   assign to_sr[`OR1200_SR_OV] 
	    = (except_started) ? sr[`OR1200_SR_OV] :
	      (branch_op == `OR1200_BRANCHOP_RFE) ? esr[`OR1200_SR_OV] :
	      ov_we ? ovforw :
	      (spr_we && sr_sel) ? spr_dat_o[`OR1200_SR_OV] :
	      sr[`OR1200_SR_OV];
		  flag_we | cy_we | ov_we;