1 //
2 // Copyright (c) 2010-2023 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.Collections.Generic;
8 using System.Linq;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Core.Structure.Registers;
11 using Antmicro.Renode.Peripherals.Bus;
12 using Antmicro.Renode.Utilities;
13 using Antmicro.Renode.Time;
14 using Antmicro.Renode.Peripherals.Timers;
15 using Antmicro.Renode.Peripherals.GPIOPort;
16 
17 namespace Antmicro.Renode.Peripherals.X86
18 {
19     public class Quark_PWM : BaseGPIOPort, IDoubleWordPeripheral, IKnownSize, INumberedGPIOOutput
20     {
Quark_PWM(IMachine machine)21         public Quark_PWM(IMachine machine) : base(machine, NumberOfInternalTimers)
22         {
23             IRQ = new GPIO();
24             internalLock = new object();
25             interruptStatus = new bool[NumberOfInternalTimers];
26             timers = new LimitTimer[NumberOfInternalTimers];
27             interruptMask = new bool[NumberOfInternalTimers];
28             alternativeLoadCount = new uint[NumberOfInternalTimers];
29             operationMode = new OperationMode[NumberOfInternalTimers];
30             runningMode = new RunningMode[NumberOfInternalTimers];
31             for(int i = 0; i < timers.Length; i++)
32             {
33                 timers[i] = new LimitTimer(machine.ClockSource, 32000000, this, i.ToString(), eventEnabled: true);
34                 var j = i;
35                 timers[i].LimitReached += () => HandleLimitReached(j);
36             }
37             PrepareRegisters();
38         }
39 
Reset()40         public override void Reset()
41         {
42             base.Reset();
43             for(int i = 0; i < NumberOfInternalTimers; i++)
44             {
45                 alternativeLoadCount[i] = 0;
46                 operationMode[i] = OperationMode.Timer;
47                 runningMode[i] = RunningMode.Free;
48                 interruptMask[i] = false;
49                 interruptStatus[i] = false;
50                 timers[i].Reset();
51             }
52             registers.Reset();
53             IRQ.Unset();
54         }
55 
ReadDoubleWord(long offset)56         public uint ReadDoubleWord(long offset)
57         {
58             return registers.Read(offset);
59         }
60 
WriteDoubleWord(long offset, uint value)61         public void WriteDoubleWord(long offset, uint value)
62         {
63             registers.Write(offset, value);
64         }
65 
66         public GPIO IRQ { get; private set; }
67 
68         public long Size { get { return 0xC0;} }
69 
PrepareRegisters()70         private void PrepareRegisters()
71         {
72             var dict = new Dictionary<long, DoubleWordRegister>
73             {
74                 {(long)Registers.TimersInterruptStatus, new DoubleWordRegister(this)
75                                 // we have to reverse it as: Bit position corresponds to PWM/Timer number
76                                 .WithValueField(0, 4, FieldMode.Read, valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(interruptStatus.Zip(interruptMask, (isSet, isMasked) => isSet && !isMasked).Reverse()))
77                 },
78                 {(long)Registers.TimersRawInterruptStatus, new DoubleWordRegister(this)
79                                 // we have to reverse it as: Bit position corresponds to PWM/Timer number
80                                 .WithValueField(0, 4, FieldMode.Read, valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(interruptStatus.Reverse()))
81                 },
82                 {(long)Registers.TimersEndOfInterrupt, new DoubleWordRegister(this)
83                                 .WithValueField(0, 4, FieldMode.Read, readCallback: (_, __) => HandleEndOfInterrupt())
84                 }
85             };
86 
87             for(int i = 0; i < timers.Length; i++)
88             {
89                 var j = i;
90                 var offset = 0x14 * i;
91                 dict[(long)Registers.Timer1LoadCount + offset] = new DoubleWordRegister(this)
92                     .WithValueField(0, 32, writeCallback: (_, val) => {
93                         timers[j].Limit = val;
94                         timers[j].ResetValue();
95                     });
96 
97                 dict[(long)Registers.Timer1CurrentValue + offset] = new DoubleWordRegister(this)
98                     .WithValueField(0, 32, FieldMode.Read, valueProviderCallback: _ => (uint)timers[j].Value);
99 
100                 dict[(long)Registers.Timer1Control + offset] = new DoubleWordRegister(this)
101                     .WithFlag(0, name: "Enable", writeCallback: (_, val) => timers[j].Enabled = val)
102                     .WithFlag(1, name: "Timer Mode", writeCallback: (_, val) => runningMode[j] = val ? RunningMode.UserDefinedCount : RunningMode.Free)
103                     .WithFlag(2, name: "Interrupt Mask", writeCallback: (_, val) => interruptMask[j] = val)
104                     .WithFlag(3, name: "PWM/Timer Mode", writeCallback: (_, val) => operationMode[j] = val ? OperationMode.PWM : OperationMode.Timer);
105 
106                 dict[(long)Registers.Timer1EndOfInterrupt + offset] = new DoubleWordRegister(this)
107                     .WithValueField(0, 1, FieldMode.Read, readCallback: (_, __) => HandleEndOfInterrupt(j));
108 
109                 dict[(long)Registers.Timer1InterruptStatus + offset] = new DoubleWordRegister(this)
110                     .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => interruptStatus[j]);
111 
112                 // here we have a different registers offset!
113                 dict[(long)Registers.Timer1LoadCount2 + 0x4 * i] = new DoubleWordRegister(this)
114                     .WithValueField(0, 32, writeCallback: (_, val) => alternativeLoadCount[j] = (uint)val);
115             }
116 
117             registers = new DoubleWordRegisterCollection(this, dict);
118         }
119 
HandleLimitReached(int timerId)120         private void HandleLimitReached(int timerId)
121         {
122             lock(internalLock)
123             {
124                 interruptStatus[timerId] = true;
125                 if(!interruptMask[timerId])
126                 {
127                     IRQ.Set();
128                 }
129 
130                 if(operationMode[timerId] == OperationMode.Timer)
131                 {
132                     if(runningMode[timerId] == RunningMode.Free)
133                     {
134                         // i'm not sure if it is correct as the documentation is quite confusing
135                         timers[timerId].Limit = uint.MaxValue;
136                         timers[timerId].ResetValue();
137                     }
138                 }
139                 else
140                 {
141                     var currentLimit = (uint)timers[timerId].Limit;
142                     timers[timerId].Limit = alternativeLoadCount[timerId];
143                     timers[timerId].ResetValue();
144                     alternativeLoadCount[timerId] = currentLimit;
145                     Connections[timerId].Toggle();
146                 }
147             }
148         }
149 
HandleEndOfInterrupt(int? timerId = null)150         private void HandleEndOfInterrupt(int? timerId = null)
151         {
152             lock(internalLock)
153             {
154                 if(timerId.HasValue)
155                 {
156                     interruptStatus[timerId.Value] = false;
157                     if(interruptStatus.All(x => !x))
158                     {
159                         IRQ.Unset();
160                     }
161                 }
162                 else
163                 {
164                     for(int i = 0; i < interruptStatus.Length; i++)
165                     {
166                         interruptStatus[i] = false;
167                     }
168                     IRQ.Unset();
169                 }
170             }
171         }
172 
173         private DoubleWordRegisterCollection registers;
174         private LimitTimer[] timers;
175         private bool[] interruptStatus;
176         private bool[] interruptMask;
177         private uint[] alternativeLoadCount;
178         private OperationMode[] operationMode;
179         private RunningMode[] runningMode;
180         private readonly object internalLock;
181 
182         private const int NumberOfInternalTimers = 4;
183 
184         public enum OperationMode
185         {
186             PWM,
187             Timer
188         }
189 
190         public enum RunningMode
191         {
192             Free,
193             UserDefinedCount
194         }
195 
196         private enum Registers : long
197         {
198             Timer1LoadCount = 0x0,
199             Timer1CurrentValue = 0x4,
200             Timer1Control = 0x8,
201             Timer1EndOfInterrupt = 0xC,
202             Timer1InterruptStatus = 0x10,
203             Timer2LoadCount = 0x14,
204             Timer2CurrentValue = 0x18,
205             Timer2Control = 0x1C,
206             Timer2EndOfInterrupt = 0x20,
207             Timer2InterruptStatus = 0x24,
208             Timer3LoadCount = 0x28,
209             Timer3CurrentValue = 0x2C,
210             Timer3Control = 0x30,
211             Timer3EndOfInterrupt = 0x34,
212             Timer3InterruptStatus = 0x38,
213             Timer4LoadCount = 0x3C,
214             Timer4CurrentValue = 0x40,
215             Timer4Control = 0x44,
216             Timer4EndOfInterrupt = 0x48,
217             Timer4InterruptStatus = 0x4C,
218             TimersInterruptStatus = 0xA0,
219             TimersEndOfInterrupt = 0xA4,
220             TimersRawInterruptStatus = 0xA8,
221             Timer1LoadCount2 = 0xB0,
222             Timer2LoadCount2 = 0xB4,
223             Timer3LoadCount2 = 0xB8,
224             Timer4LoadCount2 = 0xBC,
225         }
226     }
227 }
228 
229