[smc/hw] Always require rvalid for successful SC.W

- Since the ALU is used for writing to rd to indicate the success
  reponse, a dTLB hit is no longer registered and the write is qualified
  directly in ID.

Fix: 293617243
Change-Id: I28a00a14574c25f3d74fe5622e7fd2edc05f3c26
diff --git a/hw/top_matcha/ip/smc/rtl/smc_core.sv b/hw/top_matcha/ip/smc/rtl/smc_core.sv
index 7748ffc..5559088 100644
--- a/hw/top_matcha/ip/smc/rtl/smc_core.sv
+++ b/hw/top_matcha/ip/smc/rtl/smc_core.sv
@@ -777,6 +777,7 @@
     .sfence_rs2_asid_o (sfence_rs2_asid),
 
     // Atomics
+    .data_rvalid_i(data_rvalid_i),
     .amo_rf_success_o(amo_sc_lsu_written)
   );
 
diff --git a/hw/top_matcha/ip/smc/rtl/smc_decoder.sv b/hw/top_matcha/ip/smc/rtl/smc_decoder.sv
index ba1b91e..3add819 100644
--- a/hw/top_matcha/ip/smc/rtl/smc_decoder.sv
+++ b/hw/top_matcha/ip/smc/rtl/smc_decoder.sv
@@ -371,19 +371,22 @@
 
               AMO_SC: begin
                 amo_sc_o       = 1'b1;
+                data_we_cmd_o  = STORE;
 
+                // Address generation
                 if (amo_outstanding_req_i || amo_ptw_finished_i) begin
                   rf_ren_a_o    = 1'b1;
                   rf_ren_b_o    = 1'b1;
                   data_req_o    = 1'b1;
-                  data_we_cmd_o = STORE;
+
+                // Valid reservation
                 end else if (amo_rf_success_i) begin
-                  rf_we              = 1'b1;
+                  rf_we         = 1'b1;
+                  data_req_o    = 1'b1;
+
+                // No reservation
                 end else begin
-                  // We don't qualify here with !amo_sc_success_i in order to
-                  // set rd=1 immediately in case an interrupt disrupts
-                  // an LSU PTW. The downside is rf_we is high throughout the PTW.
-                  rf_we              = 1'b1;
+                  rf_we          = 1'b1;
                 end
               end
 
@@ -947,13 +950,16 @@
             end
 
             AMO_SC: begin
+
+              // Address generation
               if (amo_outstanding_req_i || amo_ptw_finished_i) begin
                 alu_op_a_mux_sel_o  = OP_A_REG_A;
                 alu_op_b_mux_sel_o  = OP_B_IMM;
                 imm_b_mux_sel_o     = IMM_B_ZERO;
                 alu_operator_o      = ALU_ADD;
 
-              // Failure and success both use SLTU. Set success to write 0 instead of 1 by default.
+              // Regardless of reservation, the ALU uses SLTU.
+              // If there is no reservation we write 1 by default.
               end else if (amo_rf_success_i) begin
                 alu_op_a_mux_sel_o  = OP_A_IMM;
                 imm_a_mux_sel_o     = IMM_A_ZERO;
diff --git a/hw/top_matcha/ip/smc/rtl/smc_id_stage.sv b/hw/top_matcha/ip/smc/rtl/smc_id_stage.sv
index 85458d8..a1257bc 100644
--- a/hw/top_matcha/ip/smc/rtl/smc_id_stage.sv
+++ b/hw/top_matcha/ip/smc/rtl/smc_id_stage.sv
@@ -214,7 +214,8 @@
   output logic [ASIDWidth-1:0]       sfence_rs2_asid_o,
 
   // Atomics
-  output logic                       amo_rf_success_o  // one cycle after writing to DMEM
+  input logic                        data_rvalid_i,
+  output logic                       amo_rf_success_o
 );
 
   import smc_pkg::*;
@@ -329,7 +330,7 @@
 
   // Atomics
   logic amo_lr, amo_sc;
-  logic amo_sc_valid;
+  logic amo_sc_valid, amo_sc_invalid;
   logic amo_sc_success_d, amo_sc_success_q;
   logic amo_rf_success_d, amo_rf_success_q;
   logic amo_outstanding_res_q, amo_outstanding_res_d;
@@ -562,7 +563,7 @@
     .amo_lr_o             (amo_lr),
     .amo_outstanding_req_i(amo_outstanding_req),
     .amo_ptw_finished_i   (ptw_finished_q),
-    .amo_rf_success_i     (amo_rf_success_o)
+    .amo_rf_success_i     (amo_rf_success_q)
   );
 
   assign lsu_req_in_dec_o = lsu_req_dec;
@@ -759,17 +760,19 @@
   //      Atomics       //
   ////////////////////////
 
-  assign amo_sc_valid = amo_sc && amo_outstanding_res_q;
-  assign amo_outstanding_req = amo_outstanding_res_q;
-  assign amo_rf_success_o = amo_rf_success_q;
-
-
   // Valid reservation is registered as soon as LR executes, regardless
-  // if the LSU receives a valid response.
+  // if the LSU receives a valid response. amo_sc_invalid masks additional LSU
+  // requests on valid SC after address generation.
+
+  assign amo_sc_valid = amo_sc && amo_outstanding_res_q;
+  assign amo_sc_invalid = amo_sc && ~amo_outstanding_res_q;
+  assign amo_outstanding_req = amo_outstanding_res_q;
+  assign amo_rf_success_o = (amo_rf_success_d == 1'b0) && (amo_rf_success_q == 1'b1);
+
   always_comb begin
     amo_outstanding_res_d = amo_outstanding_res_q;
     amo_sc_success_d = id_ptw_active_i ? amo_sc_success_q : 1'b0;
-    amo_rf_success_d = 1'b0;
+    amo_rf_success_d = data_rvalid_i ? 1'b0 : amo_rf_success_q;
 
     if (lsu_req) begin
       if (amo_lr) begin
@@ -779,7 +782,8 @@
         amo_sc_success_d      = 1'b1;
       end
 
-      // Only write 1 to rd one cycle after valid SC.W (PTW and non-PTW).
+      // Write 0 to rd one cycle after valid SC.W and hold amo_rf_success until
+      // we receive rvalid to prevent default rf write of 1.
       if ((amo_sc_valid && !ptw_spec_walk_i) || (ptw_finished_q && amo_sc_success_q)) begin
         amo_rf_success_d = 1'b1;
       end
@@ -804,7 +808,8 @@
   assign multdiv_en_dec   = mult_en_dec | div_en_dec;
 
   assign lsu_req      = instr_executing ? (data_req_allowed | ptw_finished_q) &
-                                           lsu_req_dec & ~mmu_data_req_fault   : 1'b0;
+                                           lsu_req_dec & ~mmu_data_req_fault & ~amo_sc_invalid
+                                                                               : 1'b0;
   assign mult_en_id   = instr_executing ? mult_en_dec                          : 1'b0;
   assign div_en_id    = instr_executing ? div_en_dec                           : 1'b0;