1 // 2 // Copyright (c) 2010-2025 Antmicro 3 // Copyright (c) 2011-2015 Realtime Embedded 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 using Antmicro.Renode.Core; 9 using Antmicro.Renode.Utilities.Binding; 10 using System.Collections.Generic; 11 using System; 12 using Antmicro.Renode.Time; 13 using ELFSharp.ELF; 14 using Machine = Antmicro.Renode.Core.Machine; 15 using ELFSharp.ELF.Sections; 16 using System.Linq; 17 using Antmicro.Renode.Logging; 18 using ELFSharp.UImage; 19 20 namespace Antmicro.Renode.Peripherals.CPU 21 { 22 [GPIO(NumberOfInputs = 1)] 23 public partial class PowerPc : TranslationCPU, ICPUWithHooks 24 { 25 // Note that the reported endianness will be wrong if it is switched at runtime! PowerPc(string cpuType, IMachine machine, Endianess endianness = Endianess.BigEndian)26 public PowerPc(string cpuType, IMachine machine, Endianess endianness = Endianess.BigEndian) : base(cpuType, machine, endianness) 27 { 28 initialEndianess = endianness; 29 irqSync = new object(); 30 machine.ClockSource.AddClockEntry( 31 new ClockEntry(long.MaxValue / 2, 128000000, DecrementerHandler, this, String.Empty, false, Direction.Descending)); 32 TlibSetLittleEndianMode(initialEndianess == Endianess.LittleEndian ? 1u : 0u); 33 } 34 Reset()35 public override void Reset() 36 { 37 base.Reset(); 38 TlibSetLittleEndianMode(initialEndianess == Endianess.LittleEndian ? 1u : 0u); 39 } 40 InitFromUImage(UImage uImage)41 public override void InitFromUImage(UImage uImage) 42 { 43 this.Log(LogLevel.Warning, "PowerPC VLE mode not implemented for uImage loading."); 44 base.InitFromUImage(uImage); 45 } 46 InitFromElf(IELF elf)47 public override void InitFromElf(IELF elf) 48 { 49 base.InitFromElf(elf); 50 51 var bamSection = elf.GetSections<Section<uint>>().FirstOrDefault(x => x.Name == ".__bam_bootarea"); 52 if(bamSection != null) 53 { 54 var bamSectionContents = bamSection.GetContents(); 55 var isValidResetConfigHalfWord = bamSectionContents[1] == 0x5a; 56 if(!isValidResetConfigHalfWord) 57 { 58 this.Log(LogLevel.Warning, "Invalid BAM section, ignoring."); 59 } 60 else 61 { 62 StartInVle = (bamSectionContents[0] & 0x1) == 1; 63 this.Log(LogLevel.Info, "Will {0}start in VLE mode.", StartInVle ? "" : "not "); 64 } 65 } 66 } 67 OnGPIO(int number, bool value)68 public override void OnGPIO(int number, bool value) 69 { 70 InternalSetInterrupt(InterruptType.External, value); 71 } 72 73 public override string Architecture { get { return "ppc"; } } 74 75 public override string GDBArchitecture { get { return "powerpc:common"; } } 76 77 public override List<GDBFeatureDescriptor> GDBFeatures 78 { 79 get 80 { 81 var powerCore = new GDBFeatureDescriptor("org.gnu.gdb.power.core"); 82 for(var index = 0u; index < 32; index++) 83 { 84 powerCore.Registers.Add(new GDBRegisterDescriptor(index, 32, $"r{index}", "uint32", "general")); 85 } 86 87 powerCore.Registers.Add(new GDBRegisterDescriptor(64, 32, "pc", "code_ptr", "general")); 88 powerCore.Registers.Add(new GDBRegisterDescriptor(65, 32, "msr", "uint32", "general")); 89 powerCore.Registers.Add(new GDBRegisterDescriptor(66, 32, "cr", "uint32", "general")); 90 powerCore.Registers.Add(new GDBRegisterDescriptor(67, 32, "lr", "code_ptr", "general")); 91 powerCore.Registers.Add(new GDBRegisterDescriptor(68, 32, "ctr", "uint32", "general")); 92 powerCore.Registers.Add(new GDBRegisterDescriptor(69, 32, "xer", "uint32", "general")); 93 94 return new List<GDBFeatureDescriptor>(new GDBFeatureDescriptor[] { powerCore }); 95 } 96 } 97 98 public bool WaitAsNop 99 { 100 get => neverWaitForInterrupt; 101 set 102 { 103 neverWaitForInterrupt = value; 104 } 105 } 106 DecodeInterrupt(int number)107 protected override Interrupt DecodeInterrupt(int number) 108 { 109 if(number == 0) 110 { 111 return Interrupt.Hard; 112 } 113 throw InvalidInterruptNumberException; 114 } 115 GetExceptionDescription(ulong exceptionIndex)116 protected override string GetExceptionDescription(ulong exceptionIndex) 117 { 118 return ExceptionDescriptionsMap.TryGetValue(exceptionIndex, out var result) 119 ? result 120 : base.GetExceptionDescription(exceptionIndex); 121 } 122 123 [Export] ReadTbl()124 public uint ReadTbl() 125 { 126 tb += 0x100; 127 return tb; 128 } 129 130 [Export] ReadTbu()131 public uint ReadTbu() 132 { 133 return 0; 134 } 135 136 [Export] ReadDecrementer()137 private ulong ReadDecrementer() 138 { 139 return checked((uint)machine.ClockSource.GetClockEntry(DecrementerHandler).Value); 140 } 141 142 public bool StartInVle 143 { 144 get; 145 set; 146 } 147 148 [Export] WriteDecrementer(ulong val)149 private void WriteDecrementer(ulong val) 150 { 151 // The API relies on 64-bit values because of PPC64, but the 32-bit PowerPC uses a 32-bit decrementer. 152 var value = (uint)val; 153 machine.ClockSource.ExchangeClockEntryWith(DecrementerHandler, 154 entry => entry.With(period: value, value: value, enabled: value != 0)); 155 } 156 InternalSetInterrupt(InterruptType interrupt, bool value)157 private void InternalSetInterrupt(InterruptType interrupt, bool value) 158 { 159 lock(irqSync) 160 { 161 if(value) 162 { 163 TlibSetPendingInterrupt((int)interrupt, 1); 164 base.OnGPIO(0, true); 165 return; 166 } 167 if(TlibSetPendingInterrupt((int)interrupt, 0) == 1) 168 { 169 base.OnGPIO(0, false); 170 } 171 } 172 } 173 DecrementerHandler()174 private void DecrementerHandler() 175 { 176 InternalSetInterrupt(InterruptType.Decrementer, true); 177 } 178 179 [Export] IsVleEnabled()180 private uint IsVleEnabled() 181 { 182 //this should present the current state. Now it's a stub only. 183 return StartInVle ? 1u : 0u; 184 } 185 186 // 649: Field '...' is never assigned to, and will always have its default value null 187 #pragma warning disable 649 188 189 [Import] 190 private Func<int, int, int> TlibSetPendingInterrupt; 191 192 [Import] 193 private Action<uint> TlibSetLittleEndianMode; 194 195 #pragma warning restore 649 196 197 private uint tb; 198 private readonly object irqSync; 199 private readonly Endianess initialEndianess; 200 201 private readonly Dictionary<ulong, string> ExceptionDescriptionsMap = new Dictionary<ulong, string> 202 { 203 {0, "Critical input"}, 204 {1, "Machine check exception"}, 205 {2, "Data storage exception"}, 206 {3, "Instruction storage exception"}, 207 {4, "External input"}, 208 {5, "Alignment exception"}, 209 {6, "Program exception"}, 210 {7, "Floating-point unavailable exception"}, 211 {8, "System call exception"}, 212 {9, "Auxiliary processor unavailable"}, 213 {10, "Decrementer exception"}, 214 {11, "Fixed-interval timer interrupt"}, 215 {12, "Watchdog timer interrupt"}, 216 {13, "Data TLB miss"}, 217 {14, "Instruction TLB miss"}, 218 {15, "Debug interrupt"}, 219 {32, "SPE/embedded floating-point unavailable"}, 220 {33, "Embedded floating-point data interrupt"}, 221 {34, "Embedded floating-point round interrupt"}, 222 {35, "Embedded performance monitor interrupt"}, 223 {36, "Embedded doorbell interrupt"}, 224 {37, "Embedded doorbell critical interrupt"}, 225 {64, "System reset exception"}, 226 {65, "Data segment exception"}, 227 {66, "Instruction segment exception"}, 228 {67, "Hypervisor decrementer exception"}, 229 {68, "Trace exception"}, 230 {69, "Hypervisor data storage exception"}, 231 {70, "Hypervisor instruction storage exception"}, 232 {71, "Hypervisor data segment exception"}, 233 {72, "Hypervisor instruction segment exception"}, 234 {73, "Vector unavailable exception"}, 235 {74, "Programmable interval timer interrupt"}, 236 {75, "IO error exception"}, 237 {76, "Run mode exception"}, 238 {77, "Emulation trap exception"}, 239 {78, "Instruction fetch TLB miss"}, 240 {79, "Data load TLB miss"}, 241 {80, "Data store TLB miss"}, 242 {81, "Floating-point assist exception"}, 243 {82, "Data address breakpoint"}, 244 {83, "Instruction address breakpoint"}, 245 {84, "System management interrupt"}, 246 {85, "Embedded performance monitor interrupt"}, 247 {86, "Thermal interrupt"}, 248 {87, "Vector assist exception"}, 249 {88, "Soft patch exception"}, 250 {89, "Maintenance exception"}, 251 {90, "Maskable external breakpoint"}, 252 {91, "Non maskable external breakpoint"}, 253 {92, "Instruction TLB error"}, 254 {93, "Data TLB error"}, 255 {96, "EOL"}, 256 //tlib exceptions: used internally during code translation 257 {512, "Stop translation"}, 258 {513, "Branch instruction"}, 259 //tlib exceptions: special cases we want to stop translation 260 {514, "Context synchronizing instruction"}, 261 {515, "System call in user mode only"}, 262 {516, "Conditional stores in user mode"} 263 }; 264 265 // have to be in sync with translation libs 266 private enum InterruptType 267 { 268 Reset = 0, 269 WakeUp, 270 MachineCheck, 271 External, 272 SMI, 273 CritictalExternal, 274 Debug, 275 Thermal, 276 Decrementer, 277 Hypervisor, 278 PIT, 279 FIT, 280 WDT, 281 CriticalDoorbell, 282 Doorbell, 283 PerformanceMonitor 284 } 285 } 286 } 287