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