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 System;
9 using System.Linq;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Peripherals.Bus;
12 using Antmicro.Renode.Utilities.Binding;
13 using System.Collections.Generic;
14 using Antmicro.Renode.Time;
15 using Antmicro.Renode.Logging;
16 using Antmicro.Renode.Peripherals.IRQControllers;
17 using Endianess = ELFSharp.ELF.Endianess;
18 
19 namespace Antmicro.Renode.Peripherals.CPU
20 {
21     // Changing CPU slot after start is not supported because of InitCPUId call and
22     // because it is hardly ever needed.
23     [GPIO(NumberOfInputs = 3)]
24     public partial class Sparc : TranslationCPU
25     {
Sparc(string cpuType, IMachine machine, Endianess endianness = Endianess.BigEndian)26         public Sparc(string cpuType, IMachine machine, Endianess endianness = Endianess.BigEndian): base(cpuType, machine, endianness)
27         {
28             Init();
29         }
30 
31         public override string Architecture { get { return "sparc"; } }
32 
33         public override string GDBArchitecture { get { return Architecture; } }
34 
35         public override List<GDBFeatureDescriptor> GDBFeatures { get { return new List<GDBFeatureDescriptor>(); } }
36 
37         public bool ShutdownAsNop
38         {
39             get => neverWaitForInterrupt;
40             set
41             {
42                 neverWaitForInterrupt = value;
43             }
44         }
45 
Init()46         private void Init()
47         {
48 
49         }
50 
Start()51         public override void Start()
52         {
53             InitCPUId();
54             base.Start();
55         }
56 
OnGPIO(int number, bool value)57         public override void OnGPIO(int number, bool value)
58         {
59             switch(number)
60             {
61             case 0:
62                 // Interrupt GPIO set from GaislerIRQMP controller
63                 if(isPowerDown)
64                 {
65                     // Clear state when CPU has been issued a power-down (ASR19)
66                     isPowerDown = false;
67                 }
68                 base.OnGPIO(number, value);
69                 break;
70             case 1:
71                 // Reset GPIO set from GaislerIRQMP controller
72                 this.Log(LogLevel.Noisy, "Sparc Reset IRQ {0}, value {1}", number, value);
73                 Reset();
74                 this.Log(LogLevel.Info, "Setting Entry Point value to 0x{0:X}", this.EntryPoint);
75                 TlibSetEntryPoint(this.EntryPoint);
76                 break;
77             case 2:
78                 // Run GPIO set from GaislerIRQMP controller
79                 this.Log(LogLevel.Noisy, "Sparc Run IRQ {0}, value {1}", number, value);
80                 // Undo halted CPU
81                 TlibClearWfi();
82                 if(IsHalted)
83                 {
84                     IsHalted = false;
85                 }
86                 if(this.IsStarted)
87                 {
88                     this.Start();
89                 }
90                 break;
91             default:
92                 this.Log(LogLevel.Warning, "GPIO index out of range");
93                 break;
94             }
95         }
96 
97         private GaislerMIC connectedMIC;
98 
99         public GaislerMIC ConnectedMIC
100         {
101             get
102             {
103                 if (connectedMIC == null)
104                 {
105                     var gaislerMics = machine.GetPeripheralsOfType<GaislerMIC>();
106                     foreach (var mic in gaislerMics)
107                     {
108                         for(var micIndex=0; micIndex < mic.GetNumberOfProcessors(); micIndex++)
109                         {
110                             var endpoints = mic.GetCurrentCpuIrq(micIndex).Endpoints;
111                             for(var i = 0; i < endpoints.Count; ++i)
112                             {
113                                 if(endpoints[i].Receiver == this)
114                                 {
115                                     connectedMIC = mic;
116                                     return connectedMIC;
117                                 }
118                             }
119                         }
120                     }
121                 }
122                 return connectedMIC;
123             }
124         }
125 
DecodeInterrupt(int number)126         protected override Interrupt DecodeInterrupt(int number)
127         {
128             switch(number)
129             {
130             case 0:
131                 return Interrupt.Hard;
132             case 1:
133                 return Interrupt.TargetExternal0;
134             case 2:
135                 return Interrupt.TargetExternal1;
136             default:
137                 throw InvalidInterruptNumberException;
138             }
139         }
140 
GetExceptionDescription(ulong exceptionIndex)141         protected override string GetExceptionDescription(ulong exceptionIndex)
142         {
143             return ExceptionDescriptionsMap.TryGetValue(exceptionIndex, out var result)
144                 ? result
145                 : base.GetExceptionDescription(exceptionIndex);
146         }
147 
148         public uint EntryPoint { get; private set; }
149 
150         [Export]
FindBestInterrupt()151         private int FindBestInterrupt()
152         {
153             if( ConnectedMIC != null )
154             {
155                 if(machine.SystemBus.TryGetCurrentCPU(out var cpu))
156                 {
157                     return ConnectedMIC.CPUGetInterrupt((int)cpu.MultiprocessingId);
158                 }
159                 else
160                 {
161                     this.Log(LogLevel.Warning, "Find best interrupt - Could not get CPUId.");
162                 }
163             }
164             return 0;
165         }
166 
167         [Export]
AcknowledgeInterrupt(int interruptNumber)168         private void AcknowledgeInterrupt(int interruptNumber)
169         {
170             if( ConnectedMIC != null )
171             {
172                 if(machine.SystemBus.TryGetCurrentCPU(out var cpu))
173                 {
174                     ConnectedMIC.CPUAckInterrupt((int)cpu.MultiprocessingId, interruptNumber);
175                 }
176                 else
177                 {
178                     this.Log(LogLevel.Warning, "Acknowledge interrupt - Could not get CPUId.");
179                 }
180             }
181         }
182 
183         [Export]
OnCpuHalted()184         private void OnCpuHalted()
185         {
186             IsHalted = true;
187         }
188 
189         [Export]
OnCpuPowerDown()190         private void OnCpuPowerDown()
191         {
192             isPowerDown = true;
193             this.NoisyLog("CPU has been powered down");
194         }
195 
InitCPUId()196         private void InitCPUId()
197         {
198             if(!cpuIdinitialized)
199             {
200                 int cpuid = machine.SystemBus.GetCPUSlot(this);
201                 // Only update ASR17 for slave cores 1-15
202                 if(cpuid > 0 && cpuid < 16)
203                 {
204                     TlibSetSlot(cpuid);
205                     this.NoisyLog("Current CPUId is {0:X}.", cpuid);
206                 }
207                 else
208                 {
209                     this.NoisyLog("Could not set CPUId - value {0:X} is outside of allowed range", cpuid);
210                 }
211                 // Halt the slave cores, only core 0 starts automatically
212                 if(cpuid > 0 && cpuid < 16)
213                 {
214                     TlibSetWfi();
215                     this.NoisyLog("Halting current CPU - core number {0:X}.", cpuid);
216                 }
217                 cpuIdinitialized = true;
218             }
219         }
220 
AfterPCSet(uint value)221         private void AfterPCSet(uint value)
222         {
223             SetRegisterValue32((int)SparcRegisters.NPC, value + 4);
224             if(!entryPointInitialized)
225             {
226                 EntryPoint = value;
227                 entryPointInitialized = true;
228                 this.Log(LogLevel.Info, "Using PC value as Entry Point value : 0x{0:X}", EntryPoint);
229             }
230         }
231 
232         private bool cpuIdinitialized = false;
233         private bool entryPointInitialized;
234         private bool isPowerDown;
235 
236         // 649:  Field '...' is never assigned to, and will always have its default value null
237         #pragma warning disable 649
238 
239         [Import]
240         private Action<int> TlibSetSlot;
241 
242         [Import]
243         private Action<uint> TlibSetEntryPoint;
244 
245         [Import]
246         private Action TlibClearWfi;
247 
248         [Import]
249         private Action TlibSetWfi;
250 
251         #pragma warning restore 649
252 
253         private readonly Dictionary<ulong, string> ExceptionDescriptionsMap = new Dictionary<ulong, string>
254         {
255             {0x01, "Instruction access exception"},
256             {0x02, "Illegal instruction"},
257             {0x03, "Privileged instruction"},
258             {0x04, "FP disabled"},
259             {0x05, "Window overflow"},
260             {0x06, "Window underflow"},
261             {0x07, "Memory address not aligned"},
262             {0x08, "FP exception"},
263             {0x09, "Data access exception"},
264             {0x0A, "Tag overflow"},
265             {0x0B, "Watchpoint detected"},
266             {0x20, "R register access error"},
267             {0x21, "Instruction access error"},
268             {0x24, "CP disabled"},
269             {0x25, "Unimplemented FLUSH"},
270             {0x28, "CP Exception"},
271             {0x29, "Data access error"},
272             {0x2A, "Division by zero"},
273             {0x2B, "Data store error"},
274             {0x2C, "Data access MMU miss"},
275             {0x3C, "Instruction access MMU miss"}
276         };
277     }
278 }
279 
280