1 //
2 // Copyright (c) 2010-2024 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 Antmicro.Renode.Core;
9 using Antmicro.Renode.Core.Structure;
10 using Antmicro.Renode.Peripherals.IRQControllers;
11 using Antmicro.Renode.Peripherals.Timers;
12 using Antmicro.Renode.Exceptions;
13 using Antmicro.Renode.Logging;
14 using Endianess = ELFSharp.ELF.Endianess;
15 
16 namespace Antmicro.Renode.Peripherals.CPU
17 {
18     public class ARMv7A : Arm, IARMSingleSecurityStateCPU, IPeripheralRegister<ARM_GenericTimer, NullRegistrationPoint>
19     {
ARMv7A(IMachine machine, string cpuType, uint cpuId = 0, ARM_GenericInterruptController genericInterruptController = null, Endianess endianness = Endianess.LittleEndian)20         public ARMv7A(IMachine machine, string cpuType, uint cpuId = 0, ARM_GenericInterruptController genericInterruptController = null, Endianess endianness = Endianess.LittleEndian)
21             : base(cpuType, machine, cpuId, endianness)
22         {
23             Affinity = new Affinity(cpuId);
24             try
25             {
26                 genericInterruptController?.AttachCPU(this);
27             }
28             catch(Exception e)
29             {
30                 throw new ConstructionException($"Failed to attach CPU to Generic Interrupt Controller: {e.Message}", e);
31             }
32         }
33 
Register(ARM_GenericTimer peripheral, NullRegistrationPoint registrationPoint)34         public void Register(ARM_GenericTimer peripheral, NullRegistrationPoint registrationPoint)
35         {
36             if(genericTimer != null)
37             {
38                 throw new RegistrationException("A generic timer is already registered.");
39             }
40             genericTimer = peripheral;
41             machine.RegisterAsAChildOf(this, peripheral, registrationPoint);
42         }
43 
Unregister(ARM_GenericTimer peripheral)44         public void Unregister(ARM_GenericTimer peripheral)
45         {
46             genericTimer = null;
47             machine.UnregisterAsAChildOf(this, peripheral);
48         }
49 
50         public override MemorySystemArchitectureType MemorySystemArchitecture => MemorySystemArchitectureType.Virtual_VMSA;
51 
52         // Currently unsupported
53         public bool FIQMaskOverride => false;
54         public bool IRQMaskOverride => false;
55 
56         public Affinity Affinity { get; }
57         public SecurityState SecurityState => SecurityState.Secure;
58         public ExceptionLevel ExceptionLevel => ExceptionLevel.EL1_SystemMode;
59 
Write32CP15Inner(Coprocessor32BitMoveInstruction instruction, uint value)60         protected override void Write32CP15Inner(Coprocessor32BitMoveInstruction instruction, uint value)
61         {
62             if(instruction.CRn == GenericTimerCoprocessorRegister)
63             {
64                 if(genericTimer != null)
65                 {
66                     genericTimer.WriteDoubleWordRegisterAArch32(instruction.FieldsOnly, value);
67                     return;
68                 }
69                 this.Log(LogLevel.Error, "Trying to write the register of a generic timer, by the CP15 32-bit write instruction ({0}), but a timer was not found.", instruction);
70                 return;
71             }
72             base.Write32CP15Inner(instruction, value);
73         }
74 
Read32CP15Inner(Coprocessor32BitMoveInstruction instruction)75         protected override uint Read32CP15Inner(Coprocessor32BitMoveInstruction instruction)
76         {
77             if(instruction.CRn == GenericTimerCoprocessorRegister)
78             {
79                 if(genericTimer != null)
80                 {
81                     return genericTimer.ReadDoubleWordRegisterAArch32(instruction.FieldsOnly);
82                 }
83                 this.Log(LogLevel.Error, "Trying to read the register of a generic timer, by the CP15 32-bit read instruction ({0}), but a timer was not found - returning 0x0.", instruction);
84                 return 0;
85             }
86             return base.Read32CP15Inner(instruction);
87         }
88 
Write64CP15Inner(Coprocessor64BitMoveInstruction instruction, ulong value)89         protected override void Write64CP15Inner(Coprocessor64BitMoveInstruction instruction, ulong value)
90         {
91             if(instruction.CRm == GenericTimerCoprocessorRegister)
92             {
93                 if(genericTimer != null)
94                 {
95                     genericTimer.WriteQuadWordRegisterAArch32(instruction.FieldsOnly, value);
96                     return;
97                 }
98                 this.Log(LogLevel.Error, "Trying to write the register of a generic timer, by the CP15 64-bit write instruction ({0}), but a timer was not found.", instruction);
99                 return;
100             }
101             base.Write64CP15Inner(instruction, value);
102         }
103 
Read64CP15Inner(Coprocessor64BitMoveInstruction instruction)104         protected override ulong Read64CP15Inner(Coprocessor64BitMoveInstruction instruction)
105         {
106             if(instruction.CRm == GenericTimerCoprocessorRegister)
107             {
108                 if(genericTimer != null)
109                 {
110                     return genericTimer.ReadQuadWordRegisterAArch32(instruction.FieldsOnly);
111                 }
112                 this.Log(LogLevel.Error, "Trying to read the register of a generic timer, by the CP15 64-bit read instruction ({0}), but a timer was not found - returning 0x0.", instruction);
113                 return 0;
114             }
115             return base.Read64CP15Inner(instruction);
116         }
117 
118         protected ARM_GenericTimer genericTimer;
119 
120         private const uint GenericTimerCoprocessorRegister = 14;
121     }
122 }
123