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 
8 using Antmicro.Renode.Core;
9 using Antmicro.Renode.Core.Structure.Registers;
10 using Antmicro.Renode.Logging;
11 using Antmicro.Renode.Peripherals.CPU;
12 
13 namespace Antmicro.Renode.Peripherals.Miscellaneous
14 {
15     public class SAM4S_RSTC : BasicDoubleWordPeripheral, IGPIOReceiver, IKnownSize
16     {
SAM4S_RSTC(IMachine machine)17         public SAM4S_RSTC(IMachine machine) : base(machine)
18         {
19             DefineRegisters();
20         }
21 
InvokeReset(ResetType reason, bool resetProcessor = false, bool resetPeripherals = false, bool assertPin = false)22         public void InvokeReset(ResetType reason, bool resetProcessor = false, bool resetPeripherals = false, bool assertPin = false)
23         {
24             if(!resetProcessor && !resetPeripherals && assertPin)
25             {
26                 this.Log(LogLevel.Info, "Asserting IRQ pin");
27                 userResetStatus = true;
28                 IRQ.Set();
29                 return;
30             }
31 
32             string resetVector = null;
33             if(resetProcessor && resetPeripherals)
34             {
35                 resetVector = "platform";
36             }
37             else if(resetProcessor)
38             {
39                 resetVector = "CPU";
40             }
41             else if(resetPeripherals)
42             {
43                 resetVector = "peripherals";
44             }
45             else
46             {
47                 return;
48             }
49 
50             this.Log(LogLevel.Info, "Resetting {0}", resetVector);
51             lastResetReason.Value = reason;
52 
53             if(machine.SystemBus.TryGetCurrentCPU(out var cpu) && resetProcessor)
54             {
55                 if(!(cpu is CortexM cortexM))
56                 {
57                     this.Log(LogLevel.Error, "CPU reset has been requested, but the CPU is not cortex-m; is platform configuration correct?");
58                     return;
59                 }
60 
61                 machine.LocalTimeSource.ExecuteInNearestSyncedState(_ =>
62                 {
63                     var currentVectorBase = cortexM.VectorTableOffset;
64                     cpu.Reset();
65                     cortexM.VectorTableOffset = currentVectorBase;
66                     cpu.Resume();
67                 });
68             }
69 
70             if(resetPeripherals)
71             {
72                 machine.RequestResetInSafeState(unresetable: new IPeripheral[] { this, cpu, machine.SystemBus });
73             }
74         }
75 
OnGPIO(int pin, bool state)76         public void OnGPIO(int pin, bool state)
77         {
78             if(pin != 0)
79             {
80                 this.Log(LogLevel.Warning, "Tried to write to pin different than 0, ignoring");
81                 return;
82             }
83 
84             if(!state && userResetEnabled)
85             {
86                 InvokeReset(ResetType.UserReset, resetProcessor: true);
87             }
88             else if(previousPinState && !state)
89             {
90                 InvokeReset(ResetType.UserReset, assertPin: !userResetEnabled && userResetInterrupt);
91             }
92 
93             previousPinState = state;
94         }
95 
Reset()96         public override void Reset()
97         {
98             base.Reset();
99             IRQ.Unset();
100         }
101 
102         public GPIO IRQ { get; } = new GPIO();
103 
104         public long Size => 0x10;
105 
DefineRegisters()106         private void DefineRegisters()
107         {
108             Registers.Control.Define(this)
109                 .WithFlag(0, out var processorReset, name: "PROCRST",
110                     valueProviderCallback: _ => false)
111                 .WithReservedBits(1, 1)
112                 .WithFlag(2, out var peripheralReset, name: "PERRST",
113                     valueProviderCallback: _ => false)
114                 .WithFlag(3, out var externalReset, name: "EXTRST",
115                     valueProviderCallback: _ => false)
116                 .WithReservedBits(4, 20)
117                 .WithValueField(24, 8, out var controlKey, name: "KEY",
118                     valueProviderCallback: _ => 0)
119                 .WithWriteCallback((_, __) =>
120                 {
121                     if(controlKey.Value != ResetPassword)
122                     {
123                         this.Log(LogLevel.Info, "Software tried to invoke software reset, but wrong key has been provided: {0:X} vs {1:X}", controlKey, ResetPassword);
124                         return;
125                     }
126 
127                     InvokeReset(ResetType.SoftwareReset, processorReset.Value, peripheralReset.Value, externalReset.Value);
128                 })
129             ;
130 
131             Registers.Status.Define(this)
132                 .WithFlag(0, FieldMode.Read, name: "URSTS",
133                     valueProviderCallback: _ =>
134                     {
135                         var previousValue = userResetStatus;
136                         if(previousValue && userResetInterrupt)
137                         {
138                             IRQ.Unset();
139                         }
140                         userResetStatus = false;
141                         return previousValue;
142                     })
143                 .WithReservedBits(1, 7)
144                 .WithEnumField(8, 3, out lastResetReason, name: "RSTTYP")
145                 .WithReservedBits(11, 5)
146                 .WithTaggedFlag("NRSTL", 16)
147                 .WithFlag(17, FieldMode.Read, name: "SRCMP",
148                     valueProviderCallback: _ => false)
149                 .WithReservedBits(18, 14)
150             ;
151 
152             Registers.Mode.Define(this, 0x00000001)
153                 .WithFlag(0, out var resetEnabled, FieldMode.Write, name: "URSTEN")
154                 .WithReservedBits(1, 3)
155                 .WithFlag(4, out var interruptEnabled, FieldMode.Write, name: "URSTIEN")
156                 .WithReservedBits(5, 3)
157                 .WithTag("ERSTL", 8, 4)
158                 .WithReservedBits(12, 12)
159                 .WithValueField(24, 8, out var modeKey, FieldMode.Write, name: "KEY")
160                 .WithWriteCallback((_, __) =>
161                 {
162                     if(modeKey.Value != ResetPassword)
163                     {
164                         this.Log(LogLevel.Info, "Software tried to modify configuration, but wrong key has been provided: {0:X} vs {1:X}", modeKey, ResetPassword);
165                         return;
166                     }
167 
168                     userResetEnabled = resetEnabled.Value;
169                     userResetInterrupt = interruptEnabled.Value;
170                 })
171             ;
172         }
173 
174         private IEnumRegisterField<ResetType> lastResetReason;
175 
176         private bool previousPinState;
177         private bool userResetStatus;
178         private bool userResetEnabled;
179         private bool userResetInterrupt;
180 
181         private const int ResetPassword = 0xA5;
182 
183         public enum ResetType
184         {
185             GeneralReset,
186             BackupReset,
187             WatchdogReset,
188             SoftwareReset,
189             UserReset,
190             Reserved0,
191             Reserved1,
192             Reserved2,
193         }
194 
195         public enum Registers
196         {
197             Control = 0x00,
198             Status = 0x04,
199             Mode = 0x08,
200         }
201     }
202 }
203