1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef BERBERIS_DECODER_RISCV64_SEMANTICS_PLAYER_H_ 18 #define BERBERIS_DECODER_RISCV64_SEMANTICS_PLAYER_H_ 19 20 #include "berberis/base/overloaded.h" 21 #include "berberis/decoder/riscv64/decoder.h" 22 23 namespace berberis { 24 25 // This class expresses the semantics of instructions by calling a sequence of SemanticsListener 26 // callbacks. 27 template <class SemanticsListener> 28 class SemanticsPlayer { 29 public: 30 using Decoder = Decoder<SemanticsPlayer>; 31 using Register = typename SemanticsListener::Register; 32 using FpRegister = typename SemanticsListener::FpRegister; 33 SemanticsPlayer(SemanticsListener * listener)34 explicit SemanticsPlayer(SemanticsListener* listener) : listener_(listener) {} 35 36 // Decoder's InsnConsumer implementation. 37 Csr(const typename Decoder::CsrArgs & args)38 void Csr(const typename Decoder::CsrArgs& args) { 39 Register result; 40 Register arg = GetRegOrZero(args.src); 41 result = listener_->Csr(args.opcode, arg, args.csr); 42 SetRegOrIgnore(args.dst, result); 43 } 44 Csr(const typename Decoder::CsrImmArgs & args)45 void Csr(const typename Decoder::CsrImmArgs& args) { 46 Register result; 47 result = listener_->Csr(args.opcode, args.imm, args.csr); 48 SetRegOrIgnore(args.dst, result); 49 } 50 Fence(const typename Decoder::FenceArgs & args)51 void Fence(const typename Decoder::FenceArgs& args) { 52 listener_->Fence(args.opcode, 53 args.src, 54 args.sw, 55 args.sr, 56 args.so, 57 args.si, 58 args.pw, 59 args.pr, 60 args.po, 61 args.pi); 62 // The unused fields in the FENCE instructions — args.src and args.dst — are reserved for 63 // finer-grain fences in future extensions. For forward compatibility, base implementations 64 // shall ignore these fields, and standard software shall zero these fields. Likewise, many 65 // args.opcode and predecessor/successor set settings are also reserved for future use. Base 66 // implementations shall treat all such reserved configurations as normal fences with 67 // args.opcode=0000, and standard software shall use only non-reserved configurations. 68 } 69 FenceI(const typename Decoder::FenceIArgs & args)70 void FenceI(const typename Decoder::FenceIArgs& args) { 71 Register arg = GetRegOrZero(args.src); 72 listener_->FenceI(arg, args.imm); 73 // The unused fields in the FENCE.I instruction, imm[11:0], rs1, and rd, are reserved for 74 // finer-grain fences in future extensions. For forward compatibility, base implementations 75 // shall ignore these fields, and standard software shall zero these fields. 76 } 77 78 template <typename OpArgs> Op(OpArgs && args)79 void Op(OpArgs&& args) { 80 Register arg1 = GetRegOrZero(args.src1); 81 Register arg2 = GetRegOrZero(args.src2); 82 Register result = Overloaded{[&](const typename Decoder::OpArgs& args) { 83 return listener_->Op(args.opcode, arg1, arg2); 84 }, 85 [&](const typename Decoder::Op32Args& args) { 86 return listener_->Op32(args.opcode, arg1, arg2); 87 }}(args); 88 SetRegOrIgnore(args.dst, result); 89 }; 90 Amo(const typename Decoder::AmoArgs & args)91 void Amo(const typename Decoder::AmoArgs& args) { 92 Register arg1 = GetRegOrZero(args.src1); 93 Register arg2 = GetRegOrZero(args.src2); 94 Register result = listener_->Amo(args.opcode, arg1, arg2, args.aq, args.rl); 95 SetRegOrIgnore(args.dst, result); 96 }; 97 Lui(const typename Decoder::UpperImmArgs & args)98 void Lui(const typename Decoder::UpperImmArgs& args) { 99 Register result = listener_->Lui(args.imm); 100 SetRegOrIgnore(args.dst, result); 101 } 102 Auipc(const typename Decoder::UpperImmArgs & args)103 void Auipc(const typename Decoder::UpperImmArgs& args) { 104 Register result = listener_->Auipc(args.imm); 105 SetRegOrIgnore(args.dst, result); 106 } 107 Load(const typename Decoder::LoadArgs & args)108 void Load(const typename Decoder::LoadArgs& args) { 109 Register arg = GetRegOrZero(args.src); 110 Register result = listener_->Load(args.opcode, arg, args.offset); 111 SetRegOrIgnore(args.dst, result); 112 }; 113 Load(const typename Decoder::LoadFpArgs & args)114 void Load(const typename Decoder::LoadFpArgs& args) { 115 Register arg = GetRegOrZero(args.src); 116 FpRegister result = listener_->LoadFp(args.opcode, arg, args.offset); 117 SetFpReg(args.dst, result); 118 }; 119 120 template <typename OpImmArgs> OpImm(OpImmArgs && args)121 void OpImm(OpImmArgs&& args) { 122 Register arg = GetRegOrZero(args.src); 123 Register result = Overloaded{[&](const typename Decoder::OpImmArgs& args) { 124 return listener_->OpImm(args.opcode, arg, args.imm); 125 }, 126 [&](const typename Decoder::OpImm32Args& args) { 127 return listener_->OpImm32(args.opcode, arg, args.imm); 128 }, 129 [&](const typename Decoder::ShiftImmArgs& args) { 130 return listener_->ShiftImm(args.opcode, arg, args.imm); 131 }, 132 [&](const typename Decoder::ShiftImm32Args& args) { 133 return listener_->ShiftImm32(args.opcode, arg, args.imm); 134 }}(args); 135 SetRegOrIgnore(args.dst, result); 136 }; 137 OpFp(const typename Decoder::OpFpArgs & args)138 void OpFp(const typename Decoder::OpFpArgs& args) { 139 FpRegister arg1 = GetFpReg(args.src1); 140 FpRegister arg2 = GetFpReg(args.src2); 141 FpRegister result = listener_->OpFp(args.opcode, args.float_size, args.rm, arg1, arg2); 142 SetFpReg(args.dst, result); 143 } 144 Store(const typename Decoder::StoreArgs & args)145 void Store(const typename Decoder::StoreArgs& args) { 146 Register arg = GetRegOrZero(args.src); 147 Register data = GetRegOrZero(args.data); 148 listener_->Store(args.opcode, arg, args.offset, data); 149 }; 150 Store(const typename Decoder::StoreFpArgs & args)151 void Store(const typename Decoder::StoreFpArgs& args) { 152 Register arg = GetRegOrZero(args.src); 153 FpRegister data = GetFpReg(args.data); 154 listener_->StoreFp(args.opcode, arg, args.offset, data); 155 }; 156 Branch(const typename Decoder::BranchArgs & args)157 void Branch(const typename Decoder::BranchArgs& args) { 158 Register arg1 = GetRegOrZero(args.src1); 159 Register arg2 = GetRegOrZero(args.src2); 160 listener_->Branch(args.opcode, arg1, arg2, args.offset); 161 }; 162 JumpAndLink(const typename Decoder::JumpAndLinkArgs & args)163 void JumpAndLink(const typename Decoder::JumpAndLinkArgs& args) { 164 Register result = listener_->JumpAndLink(args.offset, args.insn_len); 165 SetRegOrIgnore(args.dst, result); 166 }; 167 JumpAndLinkRegister(const typename Decoder::JumpAndLinkRegisterArgs & args)168 void JumpAndLinkRegister(const typename Decoder::JumpAndLinkRegisterArgs& args) { 169 Register base = GetRegOrZero(args.base); 170 Register result = listener_->JumpAndLinkRegister(base, args.offset, args.insn_len); 171 SetRegOrIgnore(args.dst, result); 172 }; 173 174 // We may have executed a signal handler just after the syscall. If that handler changed x10, then 175 // overwriting x10 here would be incorrect. On the other hand asynchronous signals are unlikely to 176 // change CPU state, so we don't support this at the moment for simplicity." System(const typename Decoder::SystemArgs & args)177 void System(const typename Decoder::SystemArgs& args) { 178 if (args.opcode != Decoder::SystemOpcode::kEcall) { 179 return Unimplemented(); 180 } 181 Register syscall_nr = GetRegOrZero(17); 182 Register arg0 = GetRegOrZero(10); 183 Register arg1 = GetRegOrZero(11); 184 Register arg2 = GetRegOrZero(12); 185 Register arg3 = GetRegOrZero(13); 186 Register arg4 = GetRegOrZero(14); 187 Register arg5 = GetRegOrZero(15); 188 Register result = listener_->Ecall(syscall_nr, arg0, arg1, arg2, arg3, arg4, arg5); 189 SetRegOrIgnore(10, result); 190 } 191 Nop()192 void Nop() { listener_->Nop(); } 193 Unimplemented()194 void Unimplemented() { listener_->Unimplemented(); }; 195 196 private: GetRegOrZero(uint8_t reg)197 Register GetRegOrZero(uint8_t reg) { 198 return reg == 0 ? listener_->GetImm(0) : listener_->GetReg(reg); 199 } 200 SetRegOrIgnore(uint8_t reg,Register value)201 void SetRegOrIgnore(uint8_t reg, Register value) { 202 if (reg != 0) { 203 listener_->SetReg(reg, value); 204 } 205 } 206 GetFpReg(uint8_t reg)207 FpRegister GetFpReg(uint8_t reg) { return listener_->GetFpReg(reg); } 208 SetFpReg(uint8_t reg,FpRegister value)209 void SetFpReg(uint8_t reg, FpRegister value) { listener_->SetFpReg(reg, value); } 210 211 SemanticsListener* listener_; 212 }; 213 214 } // namespace berberis 215 216 #endif // BERBERIS_DECODER_RISCV64_SEMANTICS_PLAYER_H_ 217