1 // 2 // Copyright (c) 2010-2025 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.Collections.Generic; 9 using System.Runtime.InteropServices; 10 using System.Linq; 11 using Antmicro.Renode.Core; 12 using Antmicro.Renode.Core.Structure; 13 using Antmicro.Renode.Exceptions; 14 using Antmicro.Renode.Debugging; 15 using Antmicro.Renode.Logging; 16 using Antmicro.Renode.Peripherals.Bus; 17 using Antmicro.Renode.Peripherals.IRQControllers; 18 using Antmicro.Renode.Peripherals.Timers; 19 using Antmicro.Renode.Peripherals.CFU; 20 using Antmicro.Renode.Time; 21 using Antmicro.Renode.Utilities; 22 using Antmicro.Renode.Utilities.Binding; 23 using Antmicro.Migrant; 24 using Endianess = ELFSharp.ELF.Endianess; 25 26 namespace Antmicro.Renode.Peripherals.CPU 27 { 28 public abstract class BaseRiscV : TranslationCPU, IPeripheralContainer<ICFU, NumberRegistrationPoint<int>>, IPeripheralContainer<IIndirectCSRPeripheral, BusRangeRegistration>, ICPUWithPostOpcodeExecutionHooks, ICPUWithPostGprAccessHooks, ICPUWithNMI 29 { BaseRiscV( IRiscVTimeProvider timeProvider, uint hartId, string cpuType, IMachine machine, PrivilegedArchitecture privilegedArchitecture, Endianess endianness, CpuBitness bitness, ulong? nmiVectorAddress = null, uint? nmiVectorLength = null, bool allowUnalignedAccesses = false, InterruptMode interruptMode = InterruptMode.Auto, uint minimalPmpNapotInBytes = 8, uint pmpNumberOfAddrBits = 32, PrivilegeLevels privilegeLevels = PrivilegeLevels.MachineSupervisorUser )30 protected BaseRiscV( 31 IRiscVTimeProvider timeProvider, 32 uint hartId, 33 string cpuType, 34 IMachine machine, 35 PrivilegedArchitecture privilegedArchitecture, 36 Endianess endianness, 37 CpuBitness bitness, 38 ulong? nmiVectorAddress = null, 39 uint? nmiVectorLength = null, 40 bool allowUnalignedAccesses = false, 41 InterruptMode interruptMode = InterruptMode.Auto, 42 uint minimalPmpNapotInBytes = 8, 43 uint pmpNumberOfAddrBits = 32, 44 PrivilegeLevels privilegeLevels = PrivilegeLevels.MachineSupervisorUser 45 ) 46 : base(hartId, cpuType, machine, endianness, bitness) 47 { 48 HartId = hartId; 49 this.timeProvider = timeProvider; 50 this.privilegedArchitecture = privilegedArchitecture; 51 shouldEnterDebugMode = true; 52 nonstandardCSR = new Dictionary<ulong, NonstandardCSR>(); 53 customInstructionsMapping = new Dictionary<ulong, Action<UInt64>>(); 54 indirectCsrPeripherals = new Dictionary<BusRangeRegistration, IIndirectCSRPeripheral>(); 55 this.nmiVectorLength = nmiVectorLength; 56 this.nmiVectorAddress = nmiVectorAddress; 57 58 UserState = new Dictionary<string, object>(); 59 60 ChildCollection = new Dictionary<int, ICFU>(); 61 62 customOpcodes = new List<Tuple<string, ulong, ulong>>(); 63 postOpcodeExecutionHooks = new List<Action<ulong>>(); 64 postGprAccessHooks = new Action<bool>[NumberOfGeneralPurposeRegisters]; 65 66 architectureDecoder = new ArchitectureDecoder(machine, this, cpuType, privilegeLevels); 67 EnableArchitectureVariants(); 68 69 UpdateNMIVector(); 70 71 AllowUnalignedAccesses = allowUnalignedAccesses; 72 73 try 74 { 75 this.interruptMode = interruptMode; 76 TlibSetInterruptMode((int)interruptMode); 77 } 78 catch(CpuAbortException) 79 { 80 throw new ConstructionException(string.Format("Unsupported interrupt mode: 0x{0:X}", interruptMode)); 81 } 82 83 TlibSetPmpaddrBits(pmpNumberOfAddrBits); 84 TlibSetNapotGrain(minimalPmpNapotInBytes); 85 86 RegisterCSR((ulong)StandardCSR.Miselect, () => miselectValue, s => miselectValue = (uint)s, "miselect"); 87 for(uint i = 0; i < 6; ++i) 88 { 89 var j = i; 90 RegisterCSR((ulong)StandardCSR.Mireg + i, () => ReadIndirectCSR(miselectValue, j), v => WriteIndirectCSR(miselectValue, j, (uint)v), $"mireg{i + 1}"); 91 } 92 93 RegisterCSR((ulong)StandardCSR.Siselect, () => siselectValue, s => siselectValue = (uint)s, "siselect"); 94 for(uint i = 0; i < 6; ++i) 95 { 96 var j = i; 97 RegisterCSR((ulong)StandardCSR.Sireg + i, () => ReadIndirectCSR(siselectValue, j), v => WriteIndirectCSR(siselectValue, j, (uint)v), $"sireg{i + 1}"); 98 } 99 } 100 Register(ICFU cfu, NumberRegistrationPoint<int> registrationPoint)101 public void Register(ICFU cfu, NumberRegistrationPoint<int> registrationPoint) 102 { 103 var isRegistered = ChildCollection.Where(x => x.Value.Equals(cfu)).Select(x => x.Key).ToList(); 104 if(isRegistered.Count != 0) 105 { 106 throw new RegistrationException("Can't register the same CFU twice."); 107 } 108 else if(ChildCollection.ContainsKey(registrationPoint.Address)) 109 { 110 throw new RegistrationException("The specified registration point is already in use."); 111 } 112 113 ChildCollection.Add(registrationPoint.Address, cfu); 114 machine.RegisterAsAChildOf(this, cfu, registrationPoint); 115 cfu.ConnectedCpu = this; 116 } 117 Unregister(ICFU cfu)118 public void Unregister(ICFU cfu) 119 { 120 var toRemove = ChildCollection.Where(x => x.Value.Equals(cfu)).Select(x => x.Key).ToList(); //ToList required, as we remove from the source 121 foreach(var key in toRemove) 122 { 123 ChildCollection.Remove(key); 124 } 125 126 machine.UnregisterAsAChildOf(this, cfu); 127 } 128 GetRegistrationPoints(ICFU cfu)129 public IEnumerable<NumberRegistrationPoint<int>> GetRegistrationPoints(ICFU cfu) 130 { 131 return ChildCollection.Keys.Select(x => new NumberRegistrationPoint<int>(x)); 132 } 133 134 public IEnumerable<IRegistered<ICFU, NumberRegistrationPoint<int>>> Children 135 { 136 get 137 { 138 return ChildCollection.Select(x => Registered.Create(x.Value, new NumberRegistrationPoint<int>(x.Key))); 139 } 140 } 141 Register(IIndirectCSRPeripheral peripheral, BusRangeRegistration registrationPoint)142 public void Register(IIndirectCSRPeripheral peripheral, BusRangeRegistration registrationPoint) 143 { 144 machine.RegisterAsAChildOf(this, peripheral, registrationPoint); 145 indirectCsrPeripherals.Add(registrationPoint, peripheral); 146 } 147 Unregister(IIndirectCSRPeripheral peripheral)148 public void Unregister(IIndirectCSRPeripheral peripheral) 149 { 150 foreach(var point in GetRegistrationPoints(peripheral).ToList()) 151 { 152 indirectCsrPeripherals.Remove(point); 153 } 154 machine.UnregisterAsAChildOf(this, peripheral); 155 } 156 GetRegistrationPoints(IIndirectCSRPeripheral peripheral)157 public IEnumerable<BusRangeRegistration> GetRegistrationPoints(IIndirectCSRPeripheral peripheral) 158 { 159 return indirectCsrPeripherals.Where(p => p.Value == peripheral).Select(p => p.Key); 160 } 161 162 IEnumerable<IRegistered<IIndirectCSRPeripheral, BusRangeRegistration>> IPeripheralContainer<IIndirectCSRPeripheral, BusRangeRegistration>.Children 163 { 164 get 165 { 166 return indirectCsrPeripherals.Select(x => Registered.Create(x.Value, x.Key)); 167 } 168 } 169 OnNMI(int number, bool value, ulong? mcause = null)170 public virtual void OnNMI(int number, bool value, ulong? mcause = null) 171 { 172 if(this.NMIVectorLength == null || this.NMIVectorAddress == null) 173 { 174 this.Log(LogLevel.Warning, "Non maskable interrupt not supported on this CPU. {0} or {1} not set", 175 nameof(this.NMIVectorAddress), nameof(this.NMIVectorLength)); 176 } 177 else 178 { 179 TlibSetNmi(number, value ? 1 : 0, mcause ?? (ulong)number); 180 } 181 } 182 OnGPIO(int number, bool value)183 public override void OnGPIO(int number, bool value) 184 { 185 186 // we don't log warning when value is false to handle gpio initial reset 187 if(privilegedArchitecture >= PrivilegedArchitecture.Priv1_10 && IsValidInterruptOnlyInV1_09(number) && value) 188 { 189 this.Log(LogLevel.Warning, "Interrupt {0} not supported since Privileged ISA v1.10", (IrqType)number); 190 return; 191 } 192 else if(IsUnimplementedInterrupt(number) && value) 193 { 194 this.Log(LogLevel.Warning, "Interrupt {0} not supported", (IrqType)number); 195 return; 196 } 197 198 TlibSetMipBit((uint)number, value ? 1u : 0u); 199 base.OnGPIO(number, value); 200 } 201 SupportsInstructionSet(InstructionSet set)202 public bool SupportsInstructionSet(InstructionSet set) 203 { 204 return TlibIsFeatureAllowed((uint)set) == 1; 205 } 206 IsInstructionSetEnabled(InstructionSet set)207 public bool IsInstructionSetEnabled(InstructionSet set) 208 { 209 return TlibIsFeatureEnabled((uint)set) == 1; 210 } 211 Reset()212 public override void Reset() 213 { 214 base.Reset(); 215 pcWrittenFlag = false; 216 ShouldEnterDebugMode = true; 217 EnableArchitectureVariants(); 218 foreach(var key in simpleCSRs.Keys.ToArray()) 219 { 220 simpleCSRs[key] = 0; 221 } 222 UserState.Clear(); 223 SetPCFromResetVector(); 224 } 225 RegisterCustomCSR(string name, uint number, PrivilegeLevel mode)226 public void RegisterCustomCSR(string name, uint number, PrivilegeLevel mode) 227 { 228 var customCSR = new SimpleCSR(name, number, mode); 229 if(simpleCSRs.Keys.Any(x => x.Number == customCSR.Number)) 230 { 231 throw new ConstructionException($"Cannot register CSR {customCSR.Name}, because its number 0x{customCSR.Number:X} is already registered"); 232 } 233 simpleCSRs.Add(customCSR, 0); 234 RegisterCSR(customCSR.Number, () => simpleCSRs[customCSR], value => simpleCSRs[customCSR] = value, name); 235 } 236 RegisterCSR(ulong csr, Func<ulong> readOperation, Action<ulong> writeOperation, string name = null)237 public void RegisterCSR(ulong csr, Func<ulong> readOperation, Action<ulong> writeOperation, string name = null) 238 { 239 nonstandardCSR.Add(csr, new NonstandardCSR(readOperation, writeOperation, name)); 240 if(TlibInstallCustomCSR(csr) == -1) 241 { 242 throw new ConstructionException($"CSR limit exceeded. Cannot register CSR 0x{csr:X}"); 243 } 244 } 245 SilenceUnsupportedInstructionSet(InstructionSet set, bool silent = true)246 public void SilenceUnsupportedInstructionSet(InstructionSet set, bool silent = true) 247 { 248 TlibMarkFeatureSilent((uint)set, silent ? 1 : 0u); 249 } 250 InstallCustomInstruction(string pattern, Action<UInt64> handler, string name = null)251 public bool InstallCustomInstruction(string pattern, Action<UInt64> handler, string name = null) 252 { 253 if(pattern == null) 254 { 255 throw new ArgumentException("Pattern cannot be null"); 256 } 257 if(handler == null) 258 { 259 throw new ArgumentException("Handler cannot be null"); 260 } 261 262 if(pattern.Length != 64 && pattern.Length != 32 && pattern.Length != 16) 263 { 264 throw new RecoverableException($"Unsupported custom instruction length: {pattern.Length}. Supported values are: 16, 32, 64 bits"); 265 } 266 267 // we know that the size is correct so the below method will alwyas succeed 268 Misc.TryParseBitPattern(pattern, out var bitPattern, out var bitMask); 269 270 CheckCustomInstructionLengthPattern(bitPattern, pattern.Length); 271 272 var length = (ulong)pattern.Length / 8; 273 var id = TlibInstallCustomInstruction(bitMask, bitPattern, length); 274 if(id == 0) 275 { 276 throw new ConstructionException($"Could not install custom instruction handler for length {length}, mask 0x{bitMask:X} and pattern 0x{bitPattern:X}"); 277 } 278 279 customOpcodes.Add(Tuple.Create(name ?? pattern, bitPattern, bitMask)); 280 customInstructionsMapping[id] = handler; 281 return true; 282 } 283 EnableCustomOpcodesCounting()284 public void EnableCustomOpcodesCounting() 285 { 286 foreach(var opc in customOpcodes) 287 { 288 InstallOpcodeCounterPattern(opc.Item1, opc.Item2, opc.Item3); 289 } 290 291 EnableOpcodesCounting = true; 292 } 293 Vector(uint registerNumber, uint elementIndex, ulong? value = null)294 public ulong Vector(uint registerNumber, uint elementIndex, ulong? value = null) 295 { 296 AssertVectorExtension(); 297 if(value.HasValue) 298 { 299 TlibSetVector(registerNumber, elementIndex, value.Value); 300 } 301 return TlibGetVector(registerNumber, elementIndex); 302 } 303 EnablePostOpcodeExecutionHooks(uint value)304 public void EnablePostOpcodeExecutionHooks(uint value) 305 { 306 TlibEnablePostOpcodeExecutionHooks(value != 0 ? 1u : 0u); 307 } 308 AddPostOpcodeExecutionHook(UInt64 mask, UInt64 value, Action<ulong> action)309 public void AddPostOpcodeExecutionHook(UInt64 mask, UInt64 value, Action<ulong> action) 310 { 311 var index = TlibInstallPostOpcodeExecutionHook(mask, value); 312 if(index == UInt32.MaxValue) 313 { 314 throw new RecoverableException("Unable to register opcode hook. Maximum number of hooks already installed"); 315 } 316 // Assert that the list index will match the one returned from the core 317 if(index != postOpcodeExecutionHooks.Count) 318 { 319 throw new ApplicationException("Mismatch in the post-execution opcode hooks on the C# and C side." + 320 " One of them miss at least one element"); 321 } 322 postOpcodeExecutionHooks.Add(action); 323 } 324 EnablePostGprAccessHooks(uint value)325 public void EnablePostGprAccessHooks(uint value) 326 { 327 TlibEnablePostGprAccessHooks(value != 0 ? 1u : 0u); 328 } 329 InstallPostGprAccessHookOn(uint registerIndex, Action<bool> callback, uint value)330 public void InstallPostGprAccessHookOn(uint registerIndex, Action<bool> callback, uint value) 331 { 332 postGprAccessHooks[registerIndex] = callback; 333 TlibEnablePostGprAccessHookOn(registerIndex, value); 334 } 335 RegisterLocalInterruptController(CoreLocalInterruptController clic)336 public void RegisterLocalInterruptController(CoreLocalInterruptController clic) 337 { 338 if(this.clic != null) 339 { 340 throw new ArgumentException($"{nameof(CoreLocalInterruptController)} is already registered"); 341 } 342 this.clic = clic; 343 } 344 ClicPresentInterrupt(int index, bool vectored, int level, PrivilegeLevel mode)345 public void ClicPresentInterrupt(int index, bool vectored, int level, PrivilegeLevel mode) 346 { 347 TlibSetClicInterruptState(index, vectored ? 1u : 0, (uint)level, (uint)mode); 348 } 349 350 public CSRValidationLevel CSRValidation 351 { 352 get => (CSRValidationLevel)TlibGetCsrValidationLevel(); 353 354 set 355 { 356 TlibSetCsrValidationLevel((uint)value); 357 } 358 } 359 360 public uint HartId 361 { 362 get 363 { 364 return TlibGetHartId(); 365 } 366 367 set 368 { 369 TlibSetHartId(value); 370 } 371 } 372 373 public ulong ResetVector 374 { 375 get => resetVector; 376 set 377 { 378 resetVector = value; 379 SetPCFromResetVector(); 380 } 381 } 382 SetPCFromResetVector()383 private void SetPCFromResetVector() 384 { 385 // Prevents overwriting PC if it's been set already (e.g. by LoadELF). 386 // The pcWrittenFlag is automatically set when setting PC so let's unset it. 387 // Otherwise, only the first ResetVector change would be propagated to PC. 388 if(!pcWrittenFlag) 389 { 390 PC = ResetVector; 391 pcWrittenFlag = false; 392 } 393 } 394 395 public bool WfiAsNop 396 { 397 get => neverWaitForInterrupt; 398 set 399 { 400 neverWaitForInterrupt = value; 401 } 402 } 403 404 public uint VectorRegisterLength 405 { 406 set 407 { 408 if(!SupportsInstructionSet(InstructionSet.V)) 409 { 410 throw new RecoverableException("Attempted to set Vector Register Length (VLEN), but V extention is not enabled"); 411 } 412 if(TlibSetVlen(value) != 0) 413 { 414 throw new RecoverableException($"Attempted to set Vector Register Length (VLEN), but {value} is not a valid value"); 415 } 416 } 417 } 418 419 public uint VectorElementMaxWidth 420 { 421 set 422 { 423 if(!SupportsInstructionSet(InstructionSet.V)) 424 { 425 throw new RecoverableException("Attempted to set Vector Element Max Width (ELEN), but V extention is not enabled"); 426 } 427 if(TlibSetElen(value) != 0) 428 { 429 throw new RecoverableException($"Attempted to set Vector Element Max Width (ELEN), but {value} is not a valid value"); 430 } 431 } 432 } 433 434 public ulong? NMIVectorAddress 435 { 436 get 437 { 438 return nmiVectorAddress; 439 } 440 441 set 442 { 443 nmiVectorAddress = value; 444 UpdateNMIVector(); 445 } 446 } 447 448 public uint? NMIVectorLength 449 { 450 get 451 { 452 return nmiVectorLength; 453 } 454 455 set 456 { 457 nmiVectorLength = value; 458 UpdateNMIVector(); 459 } 460 } 461 462 public event Action<ulong> MipChanged; 463 464 public Dictionary<string, object> UserState { get; } 465 466 public override List<GDBFeatureDescriptor> GDBFeatures 467 { 468 get 469 { 470 if(gdbFeatures.Any()) 471 { 472 return gdbFeatures; 473 } 474 475 var registerWidth = (uint)MostSignificantBit + 1; 476 RiscVRegisterDescription.AddCpuFeature(ref gdbFeatures, registerWidth); 477 RiscVRegisterDescription.AddFpuFeature(ref gdbFeatures, registerWidth, false, SupportsInstructionSet(InstructionSet.F), SupportsInstructionSet(InstructionSet.D), false); 478 RiscVRegisterDescription.AddCSRFeature(ref gdbFeatures, registerWidth, SupportsInstructionSet(InstructionSet.S), SupportsInstructionSet(InstructionSet.U), false, SupportsInstructionSet(InstructionSet.V)); 479 RiscVRegisterDescription.AddVirtualFeature(ref gdbFeatures, registerWidth); 480 RiscVRegisterDescription.AddCustomCSRFeature(ref gdbFeatures, registerWidth, nonstandardCSR); 481 if(SupportsInstructionSet(InstructionSet.V)) 482 { 483 RiscVRegisterDescription.AddVectorFeature(ref gdbFeatures, VLEN); 484 } 485 486 return gdbFeatures; 487 } 488 } 489 490 public IEnumerable<InstructionSet> ArchitectureSets => architectureDecoder.InstructionSets; 491 492 public bool AllowUnalignedAccesses 493 { 494 set => TlibAllowUnalignedAccesses(value ? 1 : 0); 495 } 496 497 public abstract RegisterValue VLEN { get; } 498 DecodeInterrupt(int number)499 protected override Interrupt DecodeInterrupt(int number) 500 { 501 return Interrupt.Hard; 502 } 503 PCWritten()504 protected void PCWritten() 505 { 506 pcWrittenFlag = true; 507 } 508 GetExceptionDescription(ulong exceptionIndex)509 protected override string GetExceptionDescription(ulong exceptionIndex) 510 { 511 var decoded = (exceptionIndex << 1) >> 1; 512 var descriptionMap = IsInterrupt(exceptionIndex) 513 ? InterruptDescriptionsMap 514 : ExceptionDescriptionsMap; 515 516 if(descriptionMap.TryGetValue(decoded, out var result)) 517 { 518 return result; 519 } 520 return base.GetExceptionDescription(exceptionIndex); 521 } 522 TrySetNonMappedRegister(int register, RegisterValue value)523 protected bool TrySetNonMappedRegister(int register, RegisterValue value) 524 { 525 if(SupportsInstructionSet(InstructionSet.V) && IsVectorRegisterNumber(register)) 526 { 527 return TrySetVectorRegister((uint)register - RiscVRegisterDescription.StartOfVRegisters, value); 528 } 529 return TrySetCustomCSR(register, value); 530 } 531 TryGetNonMappedRegister(int register, out RegisterValue value)532 protected bool TryGetNonMappedRegister(int register, out RegisterValue value) 533 { 534 if(SupportsInstructionSet(InstructionSet.V) && IsVectorRegisterNumber(register)) 535 { 536 return TryGetVectorRegister((uint)register - RiscVRegisterDescription.StartOfVRegisters, out value); 537 } 538 return TryGetCustomCSR(register, out value); 539 } 540 TrySetCustomCSR(int register, RegisterValue value)541 protected bool TrySetCustomCSR(int register, RegisterValue value) 542 { 543 if(!nonstandardCSR.ContainsKey((ulong)register)) 544 { 545 return false; 546 } 547 WriteCSR((ulong)register, value); 548 return true; 549 } 550 TryGetCustomCSR(int register, out RegisterValue value)551 protected bool TryGetCustomCSR(int register, out RegisterValue value) 552 { 553 value = default(RegisterValue); 554 if(!nonstandardCSR.ContainsKey((ulong)register)) 555 { 556 return false; 557 } 558 value = ReadCSR((ulong)register); 559 return true; 560 } 561 GetNonMappedRegisters()562 protected IEnumerable<CPURegister> GetNonMappedRegisters() 563 { 564 var registers = GetCustomCSRs(); 565 if(SupportsInstructionSet(InstructionSet.V)) 566 { 567 var vlen = VLEN; 568 registers = registers.Concat(Enumerable.Range((int)RiscVRegisterDescription.StartOfVRegisters, (int)RiscVRegisterDescription.NumberOfVRegisters) 569 .Select(index => new CPURegister(index, vlen, false, false))); 570 } 571 return registers; 572 } 573 GetCustomCSRs()574 protected IEnumerable<CPURegister> GetCustomCSRs() 575 { 576 return nonstandardCSR.Keys.Select(index => new CPURegister((int)index, MostSignificantBit + 1, false, false)); 577 } 578 IsInterrupt(ulong exceptionIndex)579 private bool IsInterrupt(ulong exceptionIndex) 580 { 581 return BitHelper.IsBitSet(exceptionIndex, MostSignificantBit); 582 } 583 584 protected abstract byte MostSignificantBit { get; } 585 ReportInvalidCustomInstructionFormat(ulong pattern, int bitsLength, string format)586 private static void ReportInvalidCustomInstructionFormat(ulong pattern, int bitsLength, string format) 587 { 588 throw new RecoverableException($"Pattern 0x{pattern:X} is invalid for {bitsLength} bits long instruction. Expected instruction in format: {format}"); 589 } 590 591 // These patterns are defined in RISC-V User-Level ISA V2.2, section 1.2 Instruction Length Encoding 592 // there are more, but we support only 16, 32 and 64 bit long custom instructions CheckCustomInstructionLengthPattern(ulong pattern, int bitLength)593 private static void CheckCustomInstructionLengthPattern(ulong pattern, int bitLength) 594 { 595 if(bitLength == 16 && ((pattern & 0b11) == 0b11)) 596 { 597 ReportInvalidCustomInstructionFormat(pattern, bitLength, "AA".PadLeft(bitLength, 'x') + ", AA != 11"); 598 } 599 else if(bitLength == 32 && ( 600 ((pattern & 0b11) != 0b11) || 601 ((pattern & 0b11100) == 0b11100)) 602 ) 603 { 604 ReportInvalidCustomInstructionFormat(pattern, bitLength, "BBB11".PadLeft(bitLength, 'x') + ", BBB != 111"); 605 } 606 else if(bitLength == 64 && ((pattern & 0b1111111) != 0b0111111)) 607 { 608 ReportInvalidCustomInstructionFormat(pattern, bitLength, "0111111".PadLeft(bitLength, 'x')); 609 } 610 } 611 EnableArchitectureVariants()612 private void EnableArchitectureVariants() 613 { 614 foreach(var @set in architectureDecoder.InstructionSets) 615 { 616 if(set == InstructionSet.G) 617 { 618 //G is a wildcard denoting multiple instruction sets 619 foreach(var gSet in new[] { InstructionSet.I, InstructionSet.M, InstructionSet.F, InstructionSet.D, InstructionSet.A }) 620 { 621 TlibAllowFeature((uint)gSet); 622 } 623 TlibAllowAdditionalFeature((uint)StandardInstructionSetExtensions.ICSR); 624 TlibAllowAdditionalFeature((uint)StandardInstructionSetExtensions.IFENCEI); 625 } 626 else if(set == InstructionSet.B) 627 { 628 //B is a wildcard denoting all bit manipulation instruction subsets 629 foreach(var gSet in new[] { StandardInstructionSetExtensions.BA, StandardInstructionSetExtensions.BB, StandardInstructionSetExtensions.BC, StandardInstructionSetExtensions.BS }) 630 { 631 TlibAllowAdditionalFeature((uint)gSet); 632 } 633 } 634 else 635 { 636 TlibAllowFeature((uint)set); 637 } 638 } 639 640 foreach(var @set in architectureDecoder.StandardExtensions) 641 { 642 TlibAllowAdditionalFeature((uint)set); 643 } 644 645 TlibSetPrivilegeArchitecture((int)privilegedArchitecture); 646 } 647 TrySetVectorRegister(uint registerNumber, RegisterValue value)648 private bool TrySetVectorRegister(uint registerNumber, RegisterValue value) 649 { 650 var vlenb = VLEN / 8; 651 var valueArray = value.GetBytes(Endianess.BigEndian); 652 653 if(valueArray.Length != vlenb) 654 { 655 return false; 656 } 657 658 var valuePointer = Marshal.AllocHGlobal(vlenb); 659 Marshal.Copy(valueArray, 0, valuePointer, vlenb); 660 661 var result = true; 662 if(TlibSetWholeVector(registerNumber, valuePointer) != 0) 663 { 664 result = false; 665 } 666 667 Marshal.FreeHGlobal(valuePointer); 668 return result; 669 } 670 TryGetVectorRegister(uint registerNumber, out RegisterValue value)671 private bool TryGetVectorRegister(uint registerNumber, out RegisterValue value) 672 { 673 var vlenb = VLEN / 8; 674 var valuePointer = Marshal.AllocHGlobal(vlenb); 675 if(TlibGetWholeVector(registerNumber, valuePointer) != 0) 676 { 677 Marshal.FreeHGlobal(valuePointer); 678 value = default(RegisterValue); 679 return false; 680 } 681 var bytes = new byte[vlenb]; 682 Marshal.Copy(valuePointer, bytes, 0, vlenb); 683 value = bytes; 684 Marshal.FreeHGlobal(valuePointer); 685 return true; 686 } 687 IsVectorRegisterNumber(int register)688 private bool IsVectorRegisterNumber(int register) 689 { 690 return RiscVRegisterDescription.StartOfVRegisters <= register && register < RiscVRegisterDescription.StartOfVRegisters + RiscVRegisterDescription.NumberOfVRegisters; 691 } 692 UpdateNMIVector()693 private void UpdateNMIVector() 694 { 695 if(NMIVectorAddress.HasValue && NMIVectorLength.HasValue && NMIVectorLength > 0) 696 { 697 this.Log(LogLevel.Noisy, "Non maskable interrupts enabled with parameters: {0} = {1}, {2} = {3}", 698 nameof(NMIVectorAddress), NMIVectorAddress, nameof(NMIVectorLength), NMIVectorLength); 699 TlibSetNmiVector(NMIVectorAddress.Value, NMIVectorLength.Value); 700 } 701 else 702 { 703 this.Log(LogLevel.Noisy, "Non maskable interrupts disabled"); 704 TlibSetNmiVector(0, 0); 705 } 706 } 707 GetIndirectCsrPeripheral(uint iselect)708 private IIndirectCSRPeripheral GetIndirectCsrPeripheral(uint iselect) 709 { 710 return indirectCsrPeripherals.SingleOrDefault(p => p.Key.Range.Contains(iselect)).Value; 711 } 712 ReadIndirectCSR(uint iselect, uint ireg)713 private uint ReadIndirectCSR(uint iselect, uint ireg) 714 { 715 var peripheral = GetIndirectCsrPeripheral(iselect); 716 if(peripheral == null) 717 { 718 this.WarningLog("Unknown indirect CSR 0x{0:x}", iselect); 719 return 0; 720 } 721 return peripheral.ReadIndirectCSR(iselect - (uint)GetRegistrationPoints(peripheral).Single().Range.StartAddress, ireg); 722 } 723 WriteIndirectCSR(uint iselect, uint ireg, uint value)724 private void WriteIndirectCSR(uint iselect, uint ireg, uint value) 725 { 726 var peripheral = GetIndirectCsrPeripheral(iselect); 727 if(peripheral == null) 728 { 729 this.WarningLog("Unknown indirect CSR 0x{0:x}", iselect); 730 return; 731 } 732 peripheral.WriteIndirectCSR(iselect - (uint)GetRegistrationPoints(peripheral).Single().Range.StartAddress, ireg, value); 733 } 734 735 [Export] GetCPUTime()736 private ulong GetCPUTime() 737 { 738 if(timeProvider == null) 739 { 740 this.Log(LogLevel.Warning, "Trying to read time from CPU, but no time provider is registered."); 741 return 0; 742 } 743 744 SyncTime(); 745 return timeProvider.TimerValue; 746 } 747 748 [Export] ReadCSR(ulong csr)749 private ulong ReadCSR(ulong csr) 750 { 751 var readMethod = nonstandardCSR[csr].ReadOperation; 752 if(readMethod == null) 753 { 754 this.Log(LogLevel.Warning, "Read method is not implemented for CSR=0x{0:X}", csr); 755 return 0; 756 } 757 return readMethod(); 758 } 759 760 [Export] WriteCSR(ulong csr, ulong value)761 private void WriteCSR(ulong csr, ulong value) 762 { 763 var writeMethod = nonstandardCSR[csr].WriteOperation; 764 if(writeMethod == null) 765 { 766 this.Log(LogLevel.Warning, "Write method is not implemented for CSR=0x{0:X}", csr); 767 } 768 else 769 { 770 writeMethod(value); 771 } 772 } 773 774 [Export] TlibMipChanged(ulong value)775 private void TlibMipChanged(ulong value) 776 { 777 MipChanged?.Invoke(value); 778 } 779 780 [Export] HandleCustomInstruction(UInt64 id, UInt64 opcode)781 private int HandleCustomInstruction(UInt64 id, UInt64 opcode) 782 { 783 if(!customInstructionsMapping.TryGetValue(id, out var handler)) 784 { 785 throw new CpuAbortException($"Unexpected instruction of id {id} and opcode 0x{opcode:X}"); 786 } 787 788 pcWrittenFlag = false; 789 handler(opcode); 790 return pcWrittenFlag ? 1 : 0; 791 } 792 793 [Export] HandlePostOpcodeExecutionHook(UInt32 id, UInt64 pc)794 private void HandlePostOpcodeExecutionHook(UInt32 id, UInt64 pc) 795 { 796 this.NoisyLog($"Got opcode hook no {id} from PC {pc}"); 797 if(id < (uint)postOpcodeExecutionHooks.Count) 798 { 799 postOpcodeExecutionHooks[(int)id].Invoke(pc); 800 } 801 else 802 { 803 this.Log(LogLevel.Error, "Received opcode hook with non-existing id = {0}", id); 804 } 805 } 806 807 [Export] HandlePostGprAccessHook(UInt32 registerIndex, UInt32 writeOrRead)808 private void HandlePostGprAccessHook(UInt32 registerIndex, UInt32 writeOrRead) 809 { 810 DebugHelper.Assert(registerIndex < 32, $"Index outside of range : {registerIndex}"); 811 if(postGprAccessHooks[(int)registerIndex] == null) 812 { 813 this.Log(LogLevel.Error, "No callback for register #{0} installed", registerIndex); 814 return; 815 } 816 817 var isWrite = (writeOrRead != 0); 818 819 this.NoisyLog("Post-GPR {0} hook for register #{1} triggered", isWrite ? "write" : "read", registerIndex); 820 postGprAccessHooks[(int)registerIndex].Invoke(isWrite); 821 } 822 823 [Export] ClicClearEdgeInterrupt()824 private void ClicClearEdgeInterrupt() 825 { 826 if(clic == null) 827 { 828 this.ErrorLog("Attempting to clear CLIC edge interrupt, but there is no CLIC peripheral connected to this core."); 829 return; 830 } 831 clic.ClearEdgeInterrupt(); 832 } 833 834 [Export] ClicAcknowledgeInterrupt()835 private void ClicAcknowledgeInterrupt() 836 { 837 if(clic == null) 838 { 839 this.ErrorLog("Attempting to acknowledge CLIC interrupt, but there is no CLIC peripheral connected to this core."); 840 return; 841 } 842 clic.AcknowledgeInterrupt(); 843 } 844 845 public readonly Dictionary<int, ICFU> ChildCollection; 846 847 private ulong? nmiVectorAddress; 848 private uint? nmiVectorLength; 849 private uint miselectValue; 850 private uint siselectValue; 851 852 private CoreLocalInterruptController clic; 853 854 private bool pcWrittenFlag; 855 private ulong resetVector = DefaultResetVector; 856 857 private readonly IRiscVTimeProvider timeProvider; 858 859 private readonly PrivilegedArchitecture privilegedArchitecture; 860 861 private readonly Dictionary<ulong, NonstandardCSR> nonstandardCSR; 862 863 private readonly Dictionary<ulong, Action<UInt64>> customInstructionsMapping; 864 865 private readonly Dictionary<SimpleCSR, ulong> simpleCSRs = new Dictionary<SimpleCSR, ulong>(); 866 867 private List<GDBFeatureDescriptor> gdbFeatures = new List<GDBFeatureDescriptor>(); 868 869 private readonly ArchitectureDecoder architectureDecoder; 870 871 private readonly Dictionary<BusRangeRegistration, IIndirectCSRPeripheral> indirectCsrPeripherals; 872 873 [Constructor] 874 private readonly List<Action<ulong>> postOpcodeExecutionHooks; 875 876 [Transient] 877 private readonly Action<bool>[] postGprAccessHooks; 878 879 // 649: Field '...' is never assigned to, and will always have its default value null 880 #pragma warning disable 649 881 [Import] 882 private Action<uint> TlibAllowFeature; 883 884 [Import] 885 private Action<uint> TlibAllowAdditionalFeature; 886 887 [Import] 888 private Func<uint, uint> TlibIsFeatureEnabled; 889 890 [Import] 891 private Func<uint, uint> TlibIsFeatureAllowed; 892 893 [Import(Name="tlib_set_privilege_architecture")] 894 private Action<int> TlibSetPrivilegeArchitecture; 895 896 [Import] 897 private Action<uint, uint> TlibSetMipBit; 898 899 [Import] 900 private Action<uint> TlibSetHartId; 901 902 [Import] 903 private Func<uint> TlibGetHartId; 904 905 [Import] 906 private Action<uint> TlibSetNapotGrain; 907 908 [Import] 909 private Action<uint> TlibSetPmpaddrBits; 910 911 [Import] 912 private Func<ulong, ulong, ulong, ulong> TlibInstallCustomInstruction; 913 914 [Import(Name="tlib_install_custom_csr")] 915 private Func<ulong, int> TlibInstallCustomCSR; 916 917 [Import] 918 private Action<uint, uint> TlibMarkFeatureSilent; 919 920 [Import] 921 private Action<ulong, uint> TlibSetNmiVector; 922 923 [Import] 924 private Action<int, int, ulong> TlibSetNmi; 925 926 [Import] 927 private Action<uint> TlibSetCsrValidationLevel; 928 929 [Import] 930 private Func<uint> TlibGetCsrValidationLevel; 931 932 [Import] 933 private Action<int> TlibAllowUnalignedAccesses; 934 935 [Import] 936 private Action<int> TlibSetInterruptMode; 937 938 [Import] 939 private Func<uint, uint> TlibSetVlen; 940 941 [Import] 942 private Func<uint, uint> TlibSetElen; 943 944 [Import] 945 private Func<uint, uint, ulong> TlibGetVector; 946 947 [Import] 948 private Action<uint, uint, ulong> TlibSetVector; 949 950 [Import] 951 private Func<uint, IntPtr, uint> TlibGetWholeVector; 952 953 [Import] 954 private Func<uint, IntPtr, uint> TlibSetWholeVector; 955 956 [Import] 957 private Action<uint> TlibEnablePostOpcodeExecutionHooks; 958 959 [Import] 960 private Func<ulong, ulong, uint> TlibInstallPostOpcodeExecutionHook; 961 962 [Import] 963 private Action<uint> TlibEnablePostGprAccessHooks; 964 965 [Import] 966 private Action<uint, uint> TlibEnablePostGprAccessHookOn; 967 968 [Import] 969 private Action<int, uint, uint, uint> TlibSetClicInterruptState; 970 971 #pragma warning restore 649 972 973 private readonly Dictionary<ulong, string> InterruptDescriptionsMap = new Dictionary<ulong, string> 974 { 975 {1, "Supervisor software interrupt"}, 976 {3, "Machine software interrupt"}, 977 {5, "Supervisor timer interrupt"}, 978 {7, "Machine timer interrupt"}, 979 {9, "Supervisor external interrupt"}, 980 {11, "Machine external interrupt"} 981 }; 982 983 private readonly Dictionary<ulong, string> ExceptionDescriptionsMap = new Dictionary<ulong, string> 984 { 985 {0, "Instruction address misaligned"}, 986 {1, "Instruction access fault"}, 987 {2, "Illegal instruction"}, 988 {3, "Breakpoint"}, 989 {4, "Load address misaligned"}, 990 {5, "Load access fault"}, 991 {6, "Store address misaligned"}, 992 {7, "Store access fault"}, 993 {8, "Environment call from U-mode"}, 994 {9, "Environment call from S-mode"}, 995 {11, "Environment call from M-mode"}, 996 {12, "Instruction page fault"}, 997 {13, "Load page fault"}, 998 {15, "Store page fault"} 999 }; 1000 1001 [NameAlias("PrivilegeArchitecture")] 1002 public enum PrivilegedArchitecture 1003 { 1004 Priv1_09, 1005 Priv1_10, 1006 Priv1_11, 1007 Priv1_12, 1008 /* Keep last. 1009 * For features that are not yet part of a ratified privileged specification. 1010 * As new specs become ratified, we should substitute uses of Unratified to the new spec value. 1011 */ 1012 PrivUnratified 1013 } 1014 1015 /* The enabled instruction sets are exposed via a register. Each instruction bit is represented 1016 * by a single bit, in alphabetical order. E.g. bit 0 represents set 'A', bit 12 represents set 'M' etc. 1017 */ 1018 public enum InstructionSet 1019 { 1020 I = 'I' - 'A', 1021 E = 'E' - 'A', 1022 M = 'M' - 'A', 1023 A = 'A' - 'A', 1024 F = 'F' - 'A', 1025 D = 'D' - 'A', 1026 C = 'C' - 'A', 1027 S = 'S' - 'A', 1028 U = 'U' - 'A', 1029 V = 'V' - 'A', 1030 B = 'B' - 'A', 1031 G = 'G' - 'A', 1032 } 1033 1034 public enum StandardInstructionSetExtensions 1035 { 1036 BA = 0, 1037 BB = 1, 1038 BC = 2, 1039 BS = 3, 1040 ICSR = 4, 1041 IFENCEI = 5, 1042 ZFH = 6, 1043 ZVFH = 7, 1044 SMEPMP = 8, 1045 ZVE32X = 9, 1046 ZVE32F = 10, 1047 ZVE64X = 11, 1048 ZVE64F = 12, 1049 ZVE64D = 13, 1050 ZACAS = 14, 1051 } 1052 1053 public enum InterruptMode 1054 { 1055 // entries match values 1056 // in tlib, do not change 1057 Auto = 0, 1058 Direct = 1, 1059 Vectored = 2 1060 } 1061 1062 public enum PrivilegeLevels 1063 { 1064 Machine, 1065 MachineUser, 1066 MachineSupervisorUser, 1067 } 1068 BeforeVectorExtensionRegisterRead()1069 protected void BeforeVectorExtensionRegisterRead() 1070 { 1071 AssertVectorExtension(); 1072 } 1073 BeforeVectorExtensionRegisterWrite(RegisterValue value)1074 protected RegisterValue BeforeVectorExtensionRegisterWrite(RegisterValue value) 1075 { 1076 AssertVectorExtension(); 1077 return value; 1078 } 1079 BeforeMTVECWrite(RegisterValue value)1080 protected RegisterValue BeforeMTVECWrite(RegisterValue value) 1081 { 1082 return HandleMTVEC_STVECWrite(value, "MTVEC"); 1083 } 1084 BeforeSTVECWrite(RegisterValue value)1085 protected RegisterValue BeforeSTVECWrite(RegisterValue value) 1086 { 1087 return HandleMTVEC_STVECWrite(value, "STVEC"); 1088 } 1089 1090 private class ArchitectureDecoder 1091 { ArchitectureDecoder(IMachine machine, BaseRiscV parent, string architectureString, PrivilegeLevels privilegeLevels)1092 public ArchitectureDecoder(IMachine machine, BaseRiscV parent, string architectureString, PrivilegeLevels privilegeLevels) 1093 { 1094 this.parent = parent; 1095 this.machine = machine; 1096 instructionSets = new List<InstructionSet>(); 1097 standardExtensions = new List<StandardInstructionSetExtensions>(); 1098 1099 Decode(architectureString); 1100 DecodePrivilegeLevels(privilegeLevels); 1101 } 1102 1103 public IEnumerable<InstructionSet> InstructionSets 1104 { 1105 get => instructionSets; 1106 } 1107 1108 public IEnumerable<StandardInstructionSetExtensions> StandardExtensions 1109 { 1110 get => standardExtensions; 1111 } 1112 Decode(string architectureString)1113 private void Decode(string architectureString) 1114 { 1115 // Example cpuType string we would like to handle here: "rv64gcv_zba_zbb_zbc_zbs_xcustom". 1116 architectureString = architectureString.ToUpper(); 1117 1118 if(!architectureString.StartsWith("RV")) 1119 { 1120 throw new ConstructionException($"Architecture string should start with rv, but is: {architectureString}"); 1121 } 1122 var instructionSetsString = architectureString.Skip(2); 1123 1124 var bits = string.Join("", instructionSetsString.TakeWhile(Char.IsDigit)); 1125 if(bits.Length == 0 || int.Parse(bits) != parent.MostSignificantBit + 1) 1126 { 1127 throw new ConstructionException($"Unexpected architecture width: {bits}"); 1128 } 1129 instructionSetsString = instructionSetsString.Skip(bits.Length); 1130 1131 while(instructionSetsString.Count() != 0) 1132 { 1133 if(instructionSetsString.First() == '_') 1134 { 1135 if(instructionSetsString.Count() == 1) 1136 { 1137 break; 1138 } 1139 instructionSetsString = instructionSetsString.Skip(1); 1140 } 1141 1142 string isaStringPart = ""; 1143 if(TryHandleSingleCharInstructionSetName(instructionSetsString.First())) 1144 { 1145 isaStringPart = instructionSetsString.First().ToString(); 1146 } 1147 else 1148 { 1149 isaStringPart = String.Join("", instructionSetsString.TakeWhile(Char.IsLetterOrDigit)); 1150 HandleLongInstructionSetName(isaStringPart); 1151 } 1152 1153 parent.DebugLog("Matched ISA String :'{0}'", isaStringPart); 1154 // Consume used characters 1155 instructionSetsString = instructionSetsString.Skip(isaStringPart.Length); 1156 } 1157 } 1158 TryHandleSingleCharInstructionSetName(char isaChar)1159 private bool TryHandleSingleCharInstructionSetName(char isaChar) 1160 { 1161 switch(isaChar) 1162 { 1163 case 'I': 1164 if(instructionSets.Contains(InstructionSet.E)) 1165 { 1166 throw new ConstructionException($"ISA string cannot contain both I and E base instruction sets at the same time."); 1167 } 1168 instructionSets.Add(InstructionSet.I); 1169 break; 1170 case 'E': 1171 if(instructionSets.Contains(InstructionSet.I)) 1172 { 1173 throw new ConstructionException($"ISA string cannot contain both I and E base instruction sets at the same time."); 1174 } 1175 instructionSets.Add(InstructionSet.E); 1176 break; 1177 case 'M': 1178 instructionSets.Add(InstructionSet.M); 1179 break; 1180 case 'A': 1181 instructionSets.Add(InstructionSet.A); 1182 break; 1183 case 'F': 1184 instructionSets.Add(InstructionSet.F); 1185 break; 1186 case 'D': 1187 instructionSets.Add(InstructionSet.D); 1188 break; 1189 case 'C': 1190 instructionSets.Add(InstructionSet.C); 1191 break; 1192 case 'V': 1193 instructionSets.Add(InstructionSet.V); 1194 break; 1195 case 'B': 1196 instructionSets.Add(InstructionSet.B); 1197 break; 1198 case 'G': 1199 instructionSets.Add(InstructionSet.G); 1200 break; 1201 case 'U': 1202 parent.WarningLog("Enabling privilege level extension '{0}' using 'cpuType' is not supported. " + 1203 "Privilege levels should be specified using the 'privilegeLevels' constructor parameter. " + 1204 "Extension will not be enabled", isaChar); 1205 break; 1206 default: 1207 return false; 1208 } 1209 ValidateInstructionSetForBaseE(); 1210 return true; 1211 } 1212 HandleLongInstructionSetName(string name)1213 private void HandleLongInstructionSetName(string name) 1214 { 1215 switch(name) 1216 { 1217 case "S": 1218 parent.WarningLog("Enabling privilege level extension '{0}' using 'cpuType' is not supported. " + 1219 "Privilege levels should be specified using the 'privilegeLevels' constructor parameter. " + 1220 "Extension will not be enabled", name); 1221 break; 1222 case "SMEPMP": standardExtensions.Add(StandardInstructionSetExtensions.SMEPMP); break; 1223 case "XANDES": Andes_AndeStarV5Extension.RegisterIn(machine, (RiscV32)parent); break; 1224 case "ZBA": standardExtensions.Add(StandardInstructionSetExtensions.BA); break; 1225 case "ZBB": standardExtensions.Add(StandardInstructionSetExtensions.BB); break; 1226 case "ZBC": standardExtensions.Add(StandardInstructionSetExtensions.BC); break; 1227 case "ZBS": standardExtensions.Add(StandardInstructionSetExtensions.BS); break; 1228 case "ZICSR": standardExtensions.Add(StandardInstructionSetExtensions.ICSR); break; 1229 case "ZIFENCEI": standardExtensions.Add(StandardInstructionSetExtensions.IFENCEI); break; 1230 case "ZFH": standardExtensions.Add(StandardInstructionSetExtensions.ZFH); break; 1231 case "ZVFH": standardExtensions.Add(StandardInstructionSetExtensions.ZVFH); break; 1232 case "ZVE32X": standardExtensions.Add(StandardInstructionSetExtensions.ZVE32X); break; 1233 case "ZVE32F": standardExtensions.Add(StandardInstructionSetExtensions.ZVE32F); break; 1234 case "ZVE64X": standardExtensions.Add(StandardInstructionSetExtensions.ZVE64X); break; 1235 case "ZVE64F": standardExtensions.Add(StandardInstructionSetExtensions.ZVE64F); break; 1236 case "ZVE64D": standardExtensions.Add(StandardInstructionSetExtensions.ZVE64D); break; 1237 case "ZACAS": standardExtensions.Add(StandardInstructionSetExtensions.ZACAS); break; 1238 default: 1239 throw new ConstructionException($"Undefined instructions set extension: '{name}'"); 1240 } 1241 } 1242 DecodePrivilegeLevels(PrivilegeLevels privilegeLevels)1243 private void DecodePrivilegeLevels(PrivilegeLevels privilegeLevels) 1244 { 1245 switch(privilegeLevels) 1246 { 1247 case PrivilegeLevels.Machine: 1248 break; // Nothing to do 1249 case PrivilegeLevels.MachineUser: 1250 instructionSets.Add(InstructionSet.U); 1251 break; 1252 case PrivilegeLevels.MachineSupervisorUser: 1253 instructionSets.Add(InstructionSet.S); 1254 instructionSets.Add(InstructionSet.U); 1255 break; 1256 default: 1257 throw new Exception("Unreachable"); 1258 } 1259 } 1260 ValidateInstructionSetForBaseE()1261 private void ValidateInstructionSetForBaseE() 1262 { 1263 if(instructionSets.Contains(InstructionSet.E) 1264 && (instructionSets.Any(x => (x != InstructionSet.E) 1265 && (x != InstructionSet.M) 1266 && (x != InstructionSet.A) 1267 && (x != InstructionSet.C)))) 1268 { 1269 throw new ConstructionException($"RV32E can only have M, A and C standard extensions"); 1270 } 1271 } 1272 1273 private readonly IList<StandardInstructionSetExtensions> standardExtensions; 1274 private readonly IList<InstructionSet> instructionSets; 1275 private readonly BaseRiscV parent; 1276 private readonly IMachine machine; 1277 } 1278 HandleMTVEC_STVECWrite(RegisterValue value, string registerName)1279 private RegisterValue HandleMTVEC_STVECWrite(RegisterValue value, string registerName) 1280 { 1281 switch(interruptMode) 1282 { 1283 case InterruptMode.Direct: 1284 if((value.RawValue & 0x3) != 0x0) 1285 { 1286 var originalValue = value; 1287 value = RegisterValue.Create(BitHelper.ReplaceBits(value.RawValue, 0x0, width: 2), value.Bits); 1288 this.Log(LogLevel.Warning, "CPU is configured in the Direct interrupt mode, modifying {2} to 0x{0:X} (tried to set 0x{1:X})", value.RawValue, originalValue.RawValue, registerName); 1289 } 1290 break; 1291 1292 case InterruptMode.Vectored: 1293 if((value.RawValue & 0x3) != 0x1) 1294 { 1295 var originalValue = value; 1296 value = RegisterValue.Create(BitHelper.ReplaceBits(value.RawValue, 0x1, width: 2), value.Bits); 1297 this.Log(LogLevel.Warning, "CPU is configured in the Vectored interrupt mode, modifying {2} to 0x{0:X} (tried to set 0x{1:X})", value.RawValue, originalValue.RawValue, registerName); 1298 } 1299 break; 1300 } 1301 1302 return value; 1303 } 1304 AssertVectorExtension()1305 private void AssertVectorExtension() 1306 { 1307 if(!SupportsInstructionSet(InstructionSet.V)) 1308 { 1309 throw new RegisterValueUnavailableException("Vector extention is not supported by this CPU"); 1310 } 1311 } 1312 1313 /* Since Priv 1.10 all hypervisor interrupts descriptions were changed to 'Reserved' 1314 * Current state can be found in Table 3.6 of the specification (pg. 37 in version 1.11) 1315 */ IsValidInterruptOnlyInV1_09(int irq)1316 private static bool IsValidInterruptOnlyInV1_09(int irq) 1317 { 1318 return irq == (int)IrqType.HypervisorExternalInterrupt 1319 || irq == (int)IrqType.HypervisorSoftwareInterrupt 1320 || irq == (int)IrqType.HypervisorTimerInterrupt; 1321 } 1322 1323 /* User-level interrupts support extension (N) is not implemented */ IsUnimplementedInterrupt(int irq)1324 private static bool IsUnimplementedInterrupt(int irq) 1325 { 1326 return irq == (int)IrqType.UserExternalInterrupt 1327 || irq == (int)IrqType.UserSoftwareInterrupt 1328 || irq == (int)IrqType.UserTimerInterrupt; 1329 } 1330 1331 private readonly InterruptMode interruptMode; 1332 1333 private readonly List<Tuple<string, ulong, ulong>> customOpcodes; 1334 1335 // In MISA register the extensions are encoded on bits [25:0] (see: https://five-embeddev.com/riscv-isa-manual/latest/machine.html), 1336 // but because these additional features are not there RISCV_ADDITIONAL_FEATURE_OFFSET allows to show that they are unrelated to MISA. 1337 private const int AdditionalExtensionOffset = 26; 1338 1339 private const ulong DefaultResetVector = 0x1000; 1340 private const int NumberOfGeneralPurposeRegisters = 32; 1341 1342 protected enum IrqType 1343 { 1344 UserSoftwareInterrupt = 0x0, 1345 SupervisorSoftwareInterrupt = 0x1, 1346 HypervisorSoftwareInterrupt = 0x2, 1347 MachineSoftwareInterrupt = 0x3, 1348 UserTimerInterrupt = 0x4, 1349 SupervisorTimerInterrupt = 0x5, 1350 HypervisorTimerInterrupt = 0x6, 1351 MachineTimerInterrupt = 0x7, 1352 UserExternalInterrupt = 0x8, 1353 SupervisorExternalInterrupt = 0x9, 1354 HypervisorExternalInterrupt = 0xa, 1355 MachineExternalInterrupt = 0xb 1356 } 1357 1358 protected enum StandardCSR 1359 { 1360 Siselect = 0x150, 1361 Sireg = 0x151, // sireg, sireg2, ..., sireg6 (0x156) 1362 Miselect = 0x350, 1363 Mireg = 0x351, // mireg, mireg2, ..., mireg6 (0x356) 1364 } 1365 } 1366 } 1367