1 //
2 // Copyright (c) 2010-2023 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 Antmicro.Renode.Peripherals.Bus;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Logging;
12 using Antmicro.Renode.Utilities;
13 using System.Linq;
14 
15 namespace Antmicro.Renode.Peripherals.DMA
16 {
17     public class UDMA : IDoubleWordPeripheral, IKnownSize
18     {
UDMA(IMachine machine, int numberOfChannels = 32)19         public UDMA(IMachine machine, int numberOfChannels = 32)
20         {
21             engine = new DmaEngine(machine.GetSystemBus(this));
22             SystemBus = machine.GetSystemBus(this);
23             channels = new Channel[numberOfChannels];
24             IRQ = new GPIO();
25             Reset();
26         }
27 
Reset()28         public void Reset()
29         {
30             basePointer = 0;
31             busErrorStatus = 0;
32             for(var i = 0; i < channels.Length; ++i)
33             {
34                 channels[i] = new Channel(this, i);
35             }
36         }
37 
38         public long Size
39         {
40             get
41             {
42                 return 0x1000;
43             }
44         }
45 
ReadDoubleWord(long offset)46         public uint ReadDoubleWord(long offset)
47         {
48             switch((Registers)offset)
49             {
50             case Registers.ChannelControlBase:
51                 return basePointer;
52             case Registers.AlternateChannelControlBase:
53                 return basePointer + 0x200; //According to Table 10-3 from cc2538 manual.
54             case Registers.ErrorClear:
55                 return busErrorStatus;
56             case Registers.WaitStatus:
57                 return ReadFromChannels(x => x.WaitingOnRequest);
58             case Registers.SoftwareRequest:
59                 return 0; //although it's write only, contiki drivers read from this. It's safe to read 0.
60             case Registers.UseBurstSet:
61                 return ReadFromChannels(x => x.UseBurst);
62             case Registers.RequestMaskSet:
63                 return ReadFromChannels(x => x.RequestMask);
64             case Registers.EnableSet:
65                 return ReadFromChannels(x => x.ChannelEnabled);
66             case Registers.AlternateSet:
67                 return ReadFromChannels(x => x.UseAlternateControlData);
68             case Registers.PrioritySet:
69                 return ReadFromChannels(x => x.HighPriority);
70             case Registers.InterruptStatus:
71                 return ReadFromChannels(x => x.InterruptStatus);
72             case Registers.PeripheralIdentification4:
73                 return peripheralIdentification[4];
74             case Registers.PeripheralIdentification0:
75             case Registers.PeripheralIdentification1:
76             case Registers.PeripheralIdentification2:
77             case Registers.PeripheralIdentification3:
78                 return peripheralIdentification[offset - (int)Registers.PeripheralIdentification0];
79             case Registers.PrimeCellIdentification0:
80             case Registers.PrimeCellIdentification1:
81             case Registers.PrimeCellIdentification2:
82             case Registers.PrimeCellIdentification3:
83                 return primeCellIdentification[offset - (int)Registers.PrimeCellIdentification0];
84             default:
85                 this.LogUnhandledRead(offset);
86                 break;
87             }
88             return 0;
89         }
90 
WriteDoubleWord(long offset, uint value)91         public void WriteDoubleWord(long offset, uint value)
92         {
93             switch((Registers)offset)
94             {
95             case Registers.Config:
96                 //enable not implemented
97                 break;
98             case Registers.ChannelControlBase:
99                 basePointer = value;
100                 break;
101             case Registers.SoftwareRequest:
102                 ActionOnChannels(x => x.InitTransfer(), value);
103                 break;
104             case Registers.UseBurstSet:
105                 ActionOnChannels(x => x.UseBurst = true, value);
106                 break;
107             case Registers.UseBurstClear:
108                 ActionOnChannels(x => x.UseBurst = false, value);
109                 break;
110             case Registers.RequestMaskSet:
111                 ActionOnChannels(x => x.RequestMask = true, value);
112                 break;
113             case Registers.RequestMaskClear:
114                 ActionOnChannels(x => x.RequestMask = false, value);
115                 break;
116             case Registers.EnableSet:
117                 ActionOnChannels(x => x.ChannelEnabled = true, value);
118                 break;
119             case Registers.EnableClear:
120                 ActionOnChannels(x => x.ChannelEnabled = false, value);
121                 break;
122             case Registers.AlternateSet:
123                 ActionOnChannels(x => x.UseAlternateControlData = true, value);
124                 break;
125             case Registers.AlternateClear:
126                 ActionOnChannels(x => x.UseAlternateControlData = false, value);
127                 break;
128             case Registers.PrioritySet:
129                 ActionOnChannels(x => x.HighPriority = true, value);
130                 break;
131             case Registers.PriorityClear:
132                 ActionOnChannels(x => x.HighPriority = false, value);
133                 break;
134             case Registers.ErrorClear:
135                 if(value > 0)
136                 {
137                     busErrorStatus = 0;
138                 }
139                 break;
140             case Registers.Assignment:
141                 ActionOnChannels((x,y) => x.SecondaryChannelAssignment = y, value);
142                 break;
143             case Registers.InterruptStatus:
144                 ActionOnChannels(x => x.InterruptStatus = false, value);
145                 IRQ.Unset();
146                 break;
147             default:
148                 this.LogUnhandledWrite(offset, value);
149                 break;
150             }
151         }
152 
InitTransfer(int channel, bool isBurst)153         public void InitTransfer(int channel, bool isBurst)
154         {
155             if(channel > channels.Length)
156             {
157                 this.Log(LogLevel.Warning, "Trying to issue a {0} transfer on non-existent channel {1}", isBurst ? "burst" : "single", channel);
158                 return;
159             }
160             channels[channel].UseBurst = isBurst;
161             channels[channel].InitTransfer();
162         }
163 
164         public GPIO IRQ { get; private set; }
165 
ActionOnChannels(Action<Channel, bool> action, uint selector)166         private void ActionOnChannels(Action<Channel, bool> action, uint selector)
167         {
168             var index = 0;
169             foreach(var bit in BitHelper.GetBits(selector))
170             {
171                 action(channels[index], bit);
172                 index++;
173             }
174         }
175 
ActionOnChannels(Action<Channel> action, uint selector)176         private void ActionOnChannels(Action<Channel> action, uint selector)
177         {
178             foreach(var i in BitHelper.GetSetBits(selector))
179             {
180                 action(channels[i]);
181             }
182         }
183 
ReadFromChannels(Func<Channel, bool> reader)184         private uint ReadFromChannels(Func<Channel, bool> reader)
185         {
186             var result = 0u;
187             for(var i = 0; i < channels.Length; ++i)
188             {
189                 if(reader(channels[i]))
190                 {
191                     result |= 1u << i;
192                 }
193             }
194             return result;
195         }
196 
197         private uint basePointer;
198         private uint busErrorStatus;
199         private readonly Channel[] channels;
200         private readonly DmaEngine engine;
201         private readonly IBusController SystemBus;
202 
203         private readonly uint[] peripheralIdentification = new uint[]{ 0x30, 0xB2, 0xB, 0x0, 0x4 };
204         private readonly uint[] primeCellIdentification = new uint[]{ 0xD, 0xF0, 0x5, 0xB1 };
205 
206         private class Channel
207         {
Channel(UDMA parent, int number)208             public Channel(UDMA parent, int number)
209             {
210                 this.parent = parent;
211                 channelNumber = number;
212             }
213 
InitTransfer()214             public void InitTransfer()
215             {
216                 var dataSource = (ulong)((UseAlternateControlData ? parent.basePointer + 0x200 : parent.basePointer) + 0x10 * channelNumber);
217                 var controlStructure = new ControlStructure(parent.SystemBus.ReadBytes(dataSource, 0x10));
218                 var request = new Request(controlStructure.SourcePointer, controlStructure.DestinationPointer, (int)controlStructure.TransferSize,
219                                   (TransferType)controlStructure.SourceSize, (TransferType)controlStructure.DestinationSize,
220                                   controlStructure.SourceIncrement, controlStructure.DestinationIncrement,
221                                   controlStructure.SourceIncrement != 0, controlStructure.DestinationIncrement != 0);
222                 parent.engine.IssueCopy(request);
223 
224                 controlStructure.ControlWord &= ~0x3FF7u; //zero request type and length
225                 parent.SystemBus.WriteBytes(controlStructure.GetBytes(), dataSource, true);
226                 ChannelEnabled = false;
227                 InterruptStatus = true;
228                 parent.IRQ.Set();
229 
230             }
231 
232             public bool WaitingOnRequest{ get; private set; }
233             public bool InterruptStatus{ get; set; }
234             public bool SecondaryChannelAssignment{ get; set; }
235             public bool HighPriority{ get; set; }
236             public bool UseAlternateControlData{ get; set; }
237             public bool ChannelEnabled{ get; set; }
238             public bool UseBurst{ get; set; }
239             public bool RequestMask{ get; set; }
240             public uint ChannelMapping{ get; set; }
241             private readonly UDMA parent;
242             private readonly int channelNumber;
243 
244             private struct ControlStructure
245             {
ControlStructureAntmicro.Renode.Peripherals.DMA.UDMA.Channel.ControlStructure246                 public ControlStructure(byte[] data)
247                 {
248                     ControlWord = BitConverter.ToUInt32(data, 8);
249                     //Source/DestinationPointer point to the LAST byte to tranfser, oddly.
250                     SourceEndPointer = BitConverter.ToUInt32(data, 0);
251                     DestinationEndPointer = BitConverter.ToUInt32(data, 4);
252                     Unused = BitConverter.ToUInt32(data, 0xC);
253                 }
254 
GetBytesAntmicro.Renode.Peripherals.DMA.UDMA.Channel.ControlStructure255                 public byte[] GetBytes()
256                 {
257                     return BitConverter.GetBytes(SourceEndPointer).Concat(BitConverter.GetBytes(DestinationEndPointer))
258                         .Concat(BitConverter.GetBytes(ControlWord)).Concat(BitConverter.GetBytes(Unused)).ToArray();
259                 }
260 
261                 public uint DestinationIncrement { get { return IncrementHelper(ControlWord >> 30); } } //bits 31-30
262                 public uint SourceIncrement { get { return IncrementHelper((ControlWord >> 26) & 0x3); } } //bits 27-26
263                 public uint DestinationSize { get { return (uint)Math.Pow(2, (ControlWord >> 28) & 0x3); } }
264                 public uint SourceSize { get { return (uint)Math.Pow(2, (ControlWord >> 24) & 0x3); } }
265                 public uint TransferSize { get { return ((ControlWord >> 4) & 0x3FF) + 1; } } //Bits 13-4 of control word
266                 public uint SourcePointer { get { return SourceIncrement != 0 ? SourceEndPointer - TransferSize + 1 : SourceEndPointer; } }
267                 public uint DestinationPointer{ get { return DestinationIncrement != 0 ? DestinationEndPointer - TransferSize + 1 : DestinationEndPointer; } }
268 
269                 //burst mode and transfer mode not implemented
270                 public uint SourceEndPointer;
271                 public uint DestinationEndPointer;
272                 public uint ControlWord;
273                 public uint Unused;
274 
275                 //Translate bits to actual increase value.
IncrementHelperAntmicro.Renode.Peripherals.DMA.UDMA.Channel.ControlStructure276                 private static uint IncrementHelper(uint value)
277                 {
278                     switch(value)
279                     {
280                     case 3:
281                         return 0;
282                     case 2:
283                         return 4;
284                     case 1:
285                         return 2;
286                     case 0:
287                         return 1;
288                     default:
289                         throw new ArgumentException("Unhandled increment value {0}.".FormatWith(value));
290                     }
291                 }
292             }
293         }
294 
295         private enum Registers
296         {
297             Status = 0x0, //not used
298             Config = 0x4, //1 - enable, not implemented
299             ChannelControlBase = 0x8, //[31:10]
300             AlternateChannelControlBase = 0xC, //not used
301             WaitStatus = 0x10, //bit per channel, not used
302             SoftwareRequest = 0x14, //bit per channel, cleared when request completed <- action
303             UseBurstSet = 0x18, //bit per channel <- data
304             UseBurstClear = 0x1C, //bit per channel <- data
305             RequestMaskSet = 0x20, //bit per channel <- data
306             RequestMaskClear = 0x24, //bit per channel <- data
307             EnableSet = 0x28, //bit per channel
308             EnableClear = 0x2C, //bit per channel
309             AlternateSet = 0x30, //bit per channel
310             AlternateClear = 0x34, //bit per channel
311             PrioritySet = 0x38, //bit per channel
312             PriorityClear = 0x3C, //bit per channel
313             ErrorClear = 0x4C, //write 1 to clear error, read 1 on error
314             Assignment = 0x500, //bit per channel, not used
315             InterruptStatus = 0x504, //bit per channel, w1c
316             PeripheralIdentification4 = 0xFD0, //sic! it's before PeripheralIdentification0
317             PeripheralIdentification0 = 0xFE0,
318             PeripheralIdentification1 = 0xFE4,
319             PeripheralIdentification2 = 0xFE8,
320             PeripheralIdentification3 = 0xFEC,
321             PrimeCellIdentification0 = 0xFF0,
322             PrimeCellIdentification1 = 0xFF4,
323             PrimeCellIdentification2 = 0xFF8,
324             PrimeCellIdentification3 = 0xFFC
325         }
326     }
327 }
328