interp: Add c.fld compressed instruction.

Bug: 265372622

Test: berberis_host_tests/berberis_host_tests

Change-Id: I8b8002527401c26206869ba841d233138a155430
diff --git a/decoder/include/berberis/decoder/riscv64/decoder.h b/decoder/include/berberis/decoder/riscv64/decoder.h
index de0b9d4..677e715 100644
--- a/decoder/include/berberis/decoder/riscv64/decoder.h
+++ b/decoder/include/berberis/decoder/riscv64/decoder.h
@@ -394,12 +394,30 @@
       case CompressedOpcode::kAddi:
         DecodeCAddi();
         break;
+      case CompressedOpcode::kFld:
+        DecodeCFld();
+        break;
       default:
         insn_consumer_->Unimplemented();
     }
     return 2;
   }
 
+  void DecodeCFld() {
+    uint8_t low_imm = GetBits<uint8_t, 5, 2>();
+    uint8_t high_imm = GetBits<uint8_t, 10, 3>();
+    uint8_t imm = (low_imm << 6 | high_imm << 3);
+    uint8_t rd = GetBits<uint8_t, 2, 3>();
+    uint8_t rs = GetBits<uint8_t, 7, 3>();
+    const LoadFpArgs args = {
+        .opcode = LoadFpOpcode::kFld,
+        .dst = uint8_t(8 + rd),
+        .src = uint8_t(8 + rs),
+        .offset = imm,
+    };
+    insn_consumer_->Load(args);
+  }
+
   void DecodeCAddi() {
     uint8_t low_imm = GetBits<uint8_t, 2, 5>();
     uint8_t high_imm = GetBits<uint8_t, 12, 1>();
diff --git a/interpreter/riscv64/interpreter_test.cc b/interpreter/riscv64/interpreter_test.cc
index b82a2df..299b6e4 100644
--- a/interpreter/riscv64/interpreter_test.cc
+++ b/interpreter/riscv64/interpreter_test.cc
@@ -34,6 +34,14 @@
 
 class Riscv64InterpreterTest : public ::testing::Test {
  public:
+  void InterpretCFld(uint16_t insn_bytes, uint64_t offset) {
+    auto code_start = ToGuestAddr(&insn_bytes);
+    state_.cpu.insn_addr = code_start;
+    SetXReg<8>(state_.cpu, ToGuestAddr(bit_cast<uint8_t*>(&kDataToLoad) - offset));
+    InterpretInsn(&state_);
+    EXPECT_EQ(GetFReg<8>(state_.cpu), kDataToLoad);
+  }
+
   void InterpretCAddi4spn(uint16_t insn_bytes, uint64_t expected_offset) {
     auto code_start = ToGuestAddr(&insn_bytes);
     state_.cpu.insn_addr = code_start;
@@ -190,6 +198,38 @@
   ThreadState state_;
 };
 
+TEST_F(Riscv64InterpreterTest, CFld) {
+  union {
+    uint16_t offset;
+    struct {
+      uint8_t : 3;
+      uint8_t i3_i5 : 3;
+      uint8_t i6_i7 : 2;
+    } i_bits;
+  };
+  for (offset = int16_t{0}; offset < int16_t{256}; offset += 8) {
+    union {
+      int16_t parcel;
+      struct {
+        uint8_t low_opcode : 2;
+        uint8_t rd : 3;
+        uint8_t i6_i7 : 2;
+        uint8_t rs : 3;
+        uint8_t i3_i5 : 3;
+        uint8_t high_opcode : 3;
+      } __attribute__((__packed__));
+    } o_bits = {
+        .low_opcode = 0b00,
+        .rd = 0,
+        .i6_i7 = i_bits.i6_i7,
+        .rs = 0,
+        .i3_i5 = i_bits.i3_i5,
+        .high_opcode = 0b001,
+    };
+    InterpretCFld(o_bits.parcel, offset);
+  }
+}
+
 TEST_F(Riscv64InterpreterTest, CAddi) {
   union {
     int8_t offset;