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;
8 using System.Collections.Generic;
9 using System.Collections.ObjectModel;
10 using System.Linq;
11 using System.Runtime.InteropServices;
12 using Antmicro.Renode.Core;
13 using Antmicro.Renode.Core.Structure.Registers;
14 using Antmicro.Renode.Exceptions;
15 using Antmicro.Renode.Logging;
16 using Antmicro.Renode.Peripherals.Bus;
17 using Antmicro.Renode.Peripherals.Timers;
18 using Antmicro.Renode.Time;
19 using Antmicro.Renode.Utilities.Packets;
20 
21 namespace Antmicro.Renode.Peripherals.DMA
22 {
23     public class EFR32MG12_LDMA : BasicDoubleWordPeripheral, IGPIOReceiver, IKnownSize
24     {
EFR32MG12_LDMA(IMachine machine)25         public EFR32MG12_LDMA(IMachine machine) : base(machine)
26         {
27             engine = new DmaEngine(sysbus);
28             signals = new HashSet<int>();
29             IRQ = new GPIO();
30             channels = new Channel[NumberOfChannels];
31             for(var i = 0; i < NumberOfChannels; ++i)
32             {
33                 channels[i] = new Channel(this, i);
34             }
35             BuildRegisters();
36         }
37 
Reset()38         public override void Reset()
39         {
40             signals.Clear();
41             foreach(var channel in channels)
42             {
43                 channel.Reset();
44             }
45             base.Reset();
46             UpdateInterrupts();
47         }
48 
OnGPIO(int number, bool value)49         public void OnGPIO(int number, bool value)
50         {
51             var signal = (SignalSelect)(number & 0xf);
52             var source = (SourceSelect)((number >> 4) & 0x3f);
53             bool single = ((number >> 12) & 1) != 0;
54             if(!value)
55             {
56                 signals.Remove(number);
57                 return;
58             }
59             signals.Add(number);
60             for(var i = 0; i < NumberOfChannels; ++i)
61             {
62                 if(single && channels[i].IgnoreSingleRequests)
63                 {
64                     continue;
65                 }
66                 if(channels[i].Signal == signal && channels[i].Source == source)
67                 {
68                     channels[i].StartFromSignal();
69                 }
70             }
71         }
72 
73         public GPIO IRQ { get; }
74 
75         public long Size => 0x400;
76 
BuildRegisters()77         private void BuildRegisters()
78         {
79             Registers.Control.Define(this)
80                 .WithTag("SYNCPRSSETEN", 0, 8)
81                 .WithTag("SYNCPRSCLREN", 8, 8)
82                 .WithReservedBits(16, 8)
83                 .WithTag("NUMFIXED", 24, 3)
84                 .WithReservedBits(27, 4)
85                 .WithTaggedFlag("RESET", 31)
86             ;
87             Registers.Status.Define(this)
88                 .WithTaggedFlag("ANYBUSY", 0)
89                 .WithTaggedFlag("ANYREQ", 1)
90                 .WithReservedBits(2, 1)
91                 .WithTag("CHGRANT", 3, 3)
92                 .WithReservedBits(6, 2)
93                 .WithTag("CHERROR", 8, 3)
94                 .WithReservedBits(11, 5)
95                 .WithTag("FIFOLEVEL", 16, 5)
96                 .WithReservedBits(21, 3)
97                 .WithTag("CHNUM", 24, 5)
98                 .WithReservedBits(29, 3)
99             ;
100             Registers.SynchronizationTrigger.Define(this)
101                 .WithTag("SYNCTRIG", 0, 8)
102                 .WithReservedBits(8, 24)
103             ;
104             Registers.ChannelEnable.Define(this)
105                 .WithFlags(0, 8, writeCallback: (i, _, value) => channels[i].Enabled = value, valueProviderCallback: (i, _) => channels[i].Enabled, name: "CHEN")
106                 .WithReservedBits(8, 24)
107             ;
108             Registers.ChannelBusy.Define(this)
109                 .WithTag("BUSY", 0, 8)
110                 .WithReservedBits(8, 24)
111             ;
112             Registers.ChannelDone.Define(this)
113                 .WithFlags(0, 8, writeCallback: (i, _, value) => channels[i].Done = value, valueProviderCallback: (i, _) => channels[i].Done, name: "CHDONE")
114                 .WithReservedBits(8, 24)
115             ;
116             Registers.ChannelDebugHalt.Define(this)
117                 .WithTag("DBGHALT", 0, 8)
118                 .WithReservedBits(8, 24)
119             ;
120             Registers.ChannelSoftwareTransferRequest.Define(this)
121                 .WithFlags(0, 8, FieldMode.Set, writeCallback: (i, _, value) => { if(value) channels[i].StartTransfer(); }, name: "SWREQ")
122                 .WithReservedBits(8, 24)
123             ;
124             Registers.ChannelRequestDisable.Define(this)
125                 .WithFlags(0, 8, writeCallback: (i, _, value) => channels[i].RequestDisable = value, valueProviderCallback: (i, _) => channels[i].RequestDisable, name: "REQDIS")
126                 .WithReservedBits(8, 24)
127             ;
128             Registers.ChannelRequestsPending.Define(this)
129                 .WithTag("REQPEND", 0, 8)
130                 .WithReservedBits(8, 24)
131             ;
132             Registers.ChannelLinkLoad.Define(this)
133                 .WithFlags(0, 8, FieldMode.Set, writeCallback: (i, _, value) => { if(value) channels[i].LinkLoad(); }, name: "LINKLOAD")
134                 .WithReservedBits(8, 24)
135             ;
136             Registers.ChannelRequestClear.Define(this)
137                 .WithTag("REQCLEAR", 0, 8)
138                 .WithReservedBits(8, 24)
139             ;
140             Registers.InterruptFlag.Define(this)
141                 .WithFlags(0, 8, FieldMode.Read, valueProviderCallback: (i, _) => channels[i].DoneInterrupt, name: "DONE")
142                 .WithReservedBits(8, 23)
143                 .WithTaggedFlag("ERROR", 31)
144                 .WithWriteCallback((_, __) => UpdateInterrupts())
145             ;
146             Registers.InterruptFlagSet.Define(this)
147                 .WithFlags(0, 8, FieldMode.Set, writeCallback: (i, _, value) => channels[i].DoneInterrupt |= value, name: "DONE")
148                 .WithReservedBits(8, 23)
149                 .WithTaggedFlag("ERROR", 31)
150                 .WithWriteCallback((_, __) => UpdateInterrupts())
151             ;
152             Registers.InterruptFlagClear.Define(this)
153                 .WithFlags(0, 8, FieldMode.WriteOneToClear, writeCallback: (i, _, value) => channels[i].DoneInterrupt &= !value, name: "DONE")
154                 .WithReservedBits(8, 23)
155                 .WithTaggedFlag("ERROR", 31)
156                 .WithWriteCallback((_, __) => UpdateInterrupts())
157             ;
158             Registers.InterruptEnable.Define(this)
159                 .WithFlags(0, 8, writeCallback: (i, _, value) => channels[i].DoneInterruptEnable = value, valueProviderCallback: (i, _) => channels[i].DoneInterruptEnable, name: "DONE")
160                 .WithReservedBits(8, 23)
161                 .WithTaggedFlag("ERROR", 31)
162                 .WithWriteCallback((_, __) => UpdateInterrupts())
163             ;
164 
165             var channelDelta = (uint)((long)Registers.Channel1PeripheralRequestSelect - (long)Registers.Channel0PeripheralRequestSelect);
166             Registers.Channel0PeripheralRequestSelect.BindMany(this, NumberOfChannels, i => channels[i].PeripheralRequestSelectRegister, channelDelta);
167             Registers.Channel0Configuration.BindMany(this, NumberOfChannels, i => channels[i].ConfigurationRegister, channelDelta);
168             Registers.Channel0LoopCounter.BindMany(this, NumberOfChannels, i => channels[i].LoopCounterRegister, channelDelta);
169             Registers.Channel0DescriptorControlWord.BindMany(this, NumberOfChannels, i => channels[i].DescriptorControlWordRegister, channelDelta);
170             Registers.Channel0DescriptorSourceDataAddress.BindMany(this, NumberOfChannels, i => channels[i].DescriptorSourceDataAddressRegister, channelDelta);
171             Registers.Channel0DescriptorDestinationDataAddress.BindMany(this, NumberOfChannels, i => channels[i].DescriptorDestinationDataAddressRegister, channelDelta);
172             Registers.Channel0DescriptorLinkStructureAddress.BindMany(this, NumberOfChannels, i => channels[i].DescriptorLinkStructureAddressRegister, channelDelta);
173         }
174 
UpdateInterrupts()175         private void UpdateInterrupts()
176         {
177             this.Log(LogLevel.Debug, "Interrupt set for channels: {0}", String.Join(", ",
178                 channels
179                     .Where(channel => channel.IRQ)
180                     .Select(channel => channel.Index)
181                 ));
182             IRQ.Set(channels.Any(channel => channel.IRQ));
183         }
184 
185         private readonly DmaEngine engine;
186         private readonly HashSet<int> signals;
187         private readonly Channel[] channels;
188 
189         private const int NumberOfChannels = 8;
190 
191         private enum SignalSelect
192         {
193             // if SOURCESEL is None
194             // Off = 0bxxxx,
195             // if SOURCESEL is PRS
196             PRSRequest0                         = 0b0000,
197             PRSRequest1                         = 0b0001,
198             // if SOURCESEL is ADC0
199             ADC0Single                          = 0b0000,
200             ADC0Scan                            = 0b0001,
201             // if SOURCESEL is VDAC0
202             VDAC0CH0                            = 0b0000,
203             VDAC0CH1                            = 0b0001,
204             // if SOURCESEL is USART0
205             USART0RxDataAvailable               = 0b0000,
206             USART0TxBufferLow                   = 0b0001,
207             USART0TxEmpty                       = 0b0010,
208             // if SOURCESEL is USART1
209             USART1RxDataAvailable               = 0b0000,
210             USART1TxBufferLow                   = 0b0001,
211             USART1TxEmpty                       = 0b0010,
212             USART1RxDataAvailableRight          = 0b0011,
213             USART1TxBufferLowRight              = 0b0100,
214             // if SOURCESEL is USART2
215             USART2RxDataAvailable               = 0b0000,
216             USART2TxBufferLow                   = 0b0001,
217             USART2TxEmpty                       = 0b0010,
218             // if SOURCESEL is USART3
219             USART3RxDataAvailable               = 0b0000,
220             USART3TxBufferLow                   = 0b0001,
221             USART3TxEmpty                       = 0b0010,
222             USART3RxDataAvailableRight          = 0b0011,
223             USART3TxBufferLowRight              = 0b0100,
224             // if SOURCESEL is LEUART0
225             LEUART0RxDataAvailable              = 0b0000,
226             LEUART0TxBufferLow                  = 0b0001,
227             LEUART0TxEmpty                      = 0b0010,
228             // if SOURCESEL is I2C0
229             I2C0RxDataAvailable                 = 0b0000,
230             I2C0TxBufferLow                     = 0b0001,
231             // if SOURCESEL is I2C1
232             I2C1RxDataAvailable                 = 0b0000,
233             I2C1TxBufferLow                     = 0b0001,
234             // if SOURCESEL is TIMER0
235             TIMER0UnderflowOverflow             = 0b0000,
236             TIMER0CaptureCompare0               = 0b0001,
237             TIMER0CaptureCompare1               = 0b0010,
238             TIMER0CaptureCompare2               = 0b0011,
239             // if SOURCESEL is TIMER1
240             TIMER1UnderflowOverflow             = 0b0000,
241             TIMER1CaptureCompare0               = 0b0001,
242             TIMER1CaptureCompare1               = 0b0010,
243             TIMER1CaptureCompare2               = 0b0011,
244             TIMER1CaptureCompare3               = 0b0100,
245             // if SOURCESEL is WTIMER0
246             WTIMER0UnderflowOverflow            = 0b0000,
247             WTIMER0CaptureCompare0              = 0b0001,
248             WTIMER0CaptureCompare1              = 0b0010,
249             WTIMER0CaptureCompare2              = 0b0011,
250             // if SOURCESEL is WTIMER1
251             WTIMER1UnderflowOverflow            = 0b0000,
252             WTIMER1CaptureCompare0              = 0b0001,
253             WTIMER1CaptureCompare1              = 0b0010,
254             WTIMER1CaptureCompare2              = 0b0011,
255             WTIMER1CaptureCompare3              = 0b0100,
256             // if SOURCESEL is PROTIMER
257             PROTIMERPreCounterOverflow          = 0b0000,
258             PROTIMERBaseCounterOverflow         = 0b0001,
259             PROTIMERWrapCounterOverflow         = 0b0010,
260             PROTIMERCaptureCompare0             = 0b0011,
261             PROTIMERCaptureCompare1             = 0b0100,
262             PROTIMERCaptureCompare2             = 0b0101,
263             PROTIMERCaptureCompare3             = 0b0110,
264             PROTIMERCaptureCompare4             = 0b0111,
265             // if SOURCESEL is MODEM
266             MODEMDebug                          = 0b0000,
267             // if SOURCESEL is AGC
268             AGCReceivedSignalStrengthIndicator  = 0b0000,
269             // if SOURCESEL is MSC
270             MSCWriteDataReady                   = 0b0000,
271             // if SOURCESEL is CRYPTO0
272             CRYPTO0Data0Write                   = 0b0000,
273             CRYPTO0Data0XorWrite                = 0b0001,
274             CRYPTO0Data0Read                    = 0b0010,
275             CRYPTO0Data1Write                   = 0b0011,
276             CRYPTO0Data1Read                    = 0b0100,
277             // if SOURCESEL is CSEN
278             CSENData                            = 0b0000,
279             CSENBaseline                        = 0b0001,
280             // if SOURCESEL is LESENSE
281             LESENSEBufferDataAvailable          = 0b0000,
282             // if SOURCESEL is CRYPTO1
283             CRYPTO1Data0Write                   = 0b0000,
284             CRYPTO1Data0XorWrite                = 0b0001,
285             CRYPTO1Data0Read                    = 0b0010,
286             CRYPTO1Data1Write                   = 0b0011,
287             CRYPTO1Data1Read                    = 0b0100,
288         }
289 
290         private enum SourceSelect
291         {
292             None     = 0b000000,
293             PRS      = 0b000001,
294             ADC0     = 0b001000,
295             VDAC0    = 0b001010,
296             USART0   = 0b001100,
297             USART1   = 0b001101,
298             USART2   = 0b001110,
299             USART3   = 0b001111,
300             LEUART0  = 0b010000,
301             I2C0     = 0b010100,
302             I2C1     = 0b010101,
303             TIMER0   = 0b011000,
304             TIMER1   = 0b011001,
305             WTIMER0  = 0b011010,
306             WTIMER1  = 0b011011,
307             PROTIMER = 0b100100,
308             MODEM    = 0b100110,
309             AGC      = 0b100111,
310             MSC      = 0b110000,
311             CRYPTO0  = 0b110001,
312             CSEN     = 0b110010,
313             LESENSE  = 0b110011,
314             CRYPTO1  = 0b110100,
315         }
316 
317         private enum Registers
318         {
319             Control                                     = 0x000,
320             Status                                      = 0x004,
321             SynchronizationTrigger                      = 0x008,
322             ChannelEnable                               = 0x020,
323             ChannelBusy                                 = 0x024,
324             ChannelDone                                 = 0x028,
325             ChannelDebugHalt                            = 0x02C,
326             ChannelSoftwareTransferRequest              = 0x030,
327             ChannelRequestDisable                       = 0x034,
328             ChannelRequestsPending                      = 0x038,
329             ChannelLinkLoad                             = 0x03C,
330             ChannelRequestClear                         = 0x040,
331             InterruptFlag                               = 0x060,
332             InterruptFlagSet                            = 0x064,
333             InterruptFlagClear                          = 0x068,
334             InterruptEnable                             = 0x06C,
335             Channel0PeripheralRequestSelect             = 0x080,
336             Channel0Configuration                       = 0x084,
337             Channel0LoopCounter                         = 0x088,
338             Channel0DescriptorControlWord               = 0x08C,
339             Channel0DescriptorSourceDataAddress         = 0x090,
340             Channel0DescriptorDestinationDataAddress    = 0x094,
341             Channel0DescriptorLinkStructureAddress      = 0x098,
342             Channel1PeripheralRequestSelect             = 0x0B0,
343             Channel1Configuration                       = 0x0B4,
344             Channel1LoopCounter                         = 0x0B8,
345             Channel1DescriptorControlWord               = 0x0BC,
346             Channel1DescriptorSourceDataAddress         = 0x0C0,
347             Channel1DescriptorDestinationDataAddress    = 0x0C4,
348             Channel1DescriptorLinkStructureAddress      = 0x0C8,
349             Channel2PeripheralRequestSelect             = 0x0E0,
350             Channel2Configuration                       = 0x0E4,
351             Channel2LoopCounter                         = 0x0E8,
352             Channel2DescriptorControlWord               = 0x0EC,
353             Channel2DescriptorSourceDataAddress         = 0x0F0,
354             Channel2DescriptorDestinationDataAddress    = 0x0F4,
355             Channel2DescriptorLinkStructureAddress      = 0x0F8,
356             Channel3PeripheralRequestSelect             = 0x110,
357             Channel3Configuration                       = 0x114,
358             Channel3LoopCounter                         = 0x118,
359             Channel3DescriptorControlWord               = 0x11C,
360             Channel3DescriptorSourceDataAddress         = 0x120,
361             Channel3DescriptorDestinationDataAddress    = 0x124,
362             Channel3DescriptorLinkStructureAddress      = 0x128,
363             Channel4PeripheralRequestSelect             = 0x140,
364             Channel4Configuration                       = 0x144,
365             Channel4LoopCounter                         = 0x148,
366             Channel4DescriptorControlWord               = 0x14C,
367             Channel4DescriptorSourceDataAddress         = 0x150,
368             Channel4DescriptorDestinationDataAddress    = 0x154,
369             Channel4DescriptorLinkStructureAddress      = 0x158,
370             Channel5PeripheralRequestSelect             = 0x170,
371             Channel5Configuration                       = 0x174,
372             Channel5LoopCounter                         = 0x178,
373             Channel5DescriptorControlWord               = 0x17C,
374             Channel5DescriptorSourceDataAddress         = 0x180,
375             Channel5DescriptorDestinationDataAddress    = 0x184,
376             Channel5DescriptorLinkStructureAddress      = 0x188,
377             Channel6PeripheralRequestSelect             = 0x1A0,
378             Channel6Configuration                       = 0x1A4,
379             Channel6LoopCounter                         = 0x1A8,
380             Channel6DescriptorControlWord               = 0x1AC,
381             Channel6DescriptorSourceDataAddress         = 0x1B0,
382             Channel6DescriptorDestinationDataAddress    = 0x1B4,
383             Channel6DescriptorLinkStructureAddress      = 0x1B8,
384             Channel7PeripheralRequestSelect             = 0x1D0,
385             Channel7Configuration                       = 0x1D4,
386             Channel7LoopCounter                         = 0x1D8,
387             Channel7DescriptorControlWord               = 0x1DC,
388             Channel7DescriptorSourceDataAddress         = 0x1E0,
389             Channel7DescriptorDestinationDataAddress    = 0x1E4,
390             Channel7DescriptorLinkStructureAddress      = 0x1E8,
391         }
392 
393         private class Channel
394         {
Channel(EFR32MG12_LDMA parent, int index)395             public Channel(EFR32MG12_LDMA parent, int index)
396             {
397                 this.parent = parent;
398                 Index = index;
399                 descriptor = default(Descriptor);
400 
401                 PeripheralRequestSelectRegister = new DoubleWordRegister(parent)
402                     .WithEnumField<DoubleWordRegister, SignalSelect>(0, 4, out signalSelect, name: "SIGSEL")
403                     .WithReservedBits(4, 12)
404                     .WithEnumField<DoubleWordRegister, SourceSelect>(16, 6, out sourceSelect, name: "SOURCESEL")
405                     .WithReservedBits(22, 10)
406                     .WithWriteCallback((_, __) =>
407                     {
408                         if(ShouldPullSignal)
409                         {
410                             pullTimer.Enabled = true;
411                         }
412                     })
413                 ;
414                 ConfigurationRegister = new DoubleWordRegister(parent)
415                     .WithReservedBits(0, 16)
416                     .WithEnumField<DoubleWordRegister, ArbitrationSlotNumberMode>(16, 2, out arbitrationSlotNumberSelect, name: "ARBSLOTS")
417                     .WithReservedBits(18, 2)
418                     .WithEnumField<DoubleWordRegister, Sign>(20, 1, out sourceAddressIncrementSign, name: "SRCINCSIGN")
419                     .WithEnumField<DoubleWordRegister, Sign>(21, 1, out destinationAddressIncrementSign, name: "DSTINCSIGN")
420                     .WithReservedBits(22, 10)
421                 ;
422                 LoopCounterRegister = new DoubleWordRegister(parent)
423                     .WithValueField(0, 8, out loopCounter, name: "LOOPCNT")
424                     .WithReservedBits(8, 24)
425                 ;
426                 DescriptorControlWordRegister = new DoubleWordRegister(parent)
427                     .WithEnumField<DoubleWordRegister, StructureType>(0, 2, FieldMode.Read,
428                         valueProviderCallback: _ => descriptor.structureType,
429                         name: "STRUCTTYPE")
430                     .WithReservedBits(2, 1)
431                     .WithFlag(3, FieldMode.Set,
432                         writeCallback: (_, value) => descriptor.structureTransferRequest = value,
433                         name: "STRUCTREQ")
434                     .WithValueField(4, 11,
435                         writeCallback: (_, value) => descriptor.transferCount = (ushort)value,
436                         valueProviderCallback: _ => descriptor.transferCount,
437                         name: "XFERCNT")
438                     .WithFlag(15,
439                         writeCallback: (_, value) => descriptor.byteSwap = value,
440                         valueProviderCallback: _ => descriptor.byteSwap,
441                         name: "BYTESWAP")
442                     .WithEnumField<DoubleWordRegister, BlockSizeMode>(16, 4,
443                         writeCallback: (_, value) => descriptor.blockSize = value,
444                         valueProviderCallback: _ => descriptor.blockSize,
445                         name: "BLOCKSIZE")
446                     .WithFlag(20,
447                         writeCallback: (_, value) => descriptor.operationDoneInterruptFlagSetEnable = value,
448                         valueProviderCallback: _ => descriptor.operationDoneInterruptFlagSetEnable,
449                         name: "DONEIFSEN")
450                     .WithEnumField<DoubleWordRegister, RequestTransferMode>(21, 1,
451                         writeCallback: (_, value) => descriptor.requestTransferModeSelect = value,
452                         valueProviderCallback: _ => descriptor.requestTransferModeSelect,
453                         name: "REQMODE")
454                     .WithFlag(22,
455                         writeCallback: (_, value) => descriptor.decrementLoopCount = value,
456                         valueProviderCallback: _ => descriptor.decrementLoopCount,
457                         name: "DECLOOPCNT")
458                     .WithFlag(23,
459                         writeCallback: (_, value) => descriptor.ignoreSingleRequests = value,
460                         valueProviderCallback: _ => descriptor.ignoreSingleRequests,
461                         name: "IGNORESREQ")
462                     .WithEnumField<DoubleWordRegister, IncrementMode>(24, 2,
463                         writeCallback: (_, value) => descriptor.sourceIncrement = value,
464                         valueProviderCallback: _ => descriptor.sourceIncrement,
465                         name: "SRCINC")
466                     .WithEnumField<DoubleWordRegister, SizeMode>(26, 2,
467                         writeCallback: (_, value) => descriptor.size = value,
468                         valueProviderCallback: _ => descriptor.size,
469                         name: "SIZE")
470                     .WithEnumField<DoubleWordRegister, IncrementMode>(28, 2,
471                         writeCallback: (_, value) => descriptor.destinationIncrement = value,
472                         valueProviderCallback: _ => descriptor.destinationIncrement,
473                         name: "DSTINC")
474                     .WithEnumField<DoubleWordRegister, AddressingMode>(30, 1, FieldMode.Read,
475                         valueProviderCallback: _ => descriptor.sourceAddressingMode,
476                         name: "SRCMODE")
477                     .WithEnumField<DoubleWordRegister, AddressingMode>(31, 1, FieldMode.Read,
478                         valueProviderCallback: _ => descriptor.destinationAddressingMode,
479                         name: "DSTMODE")
480                     .WithChangeCallback((_, __) => { if(descriptor.structureTransferRequest) LinkLoad(); })
481                 ;
482                 DescriptorSourceDataAddressRegister = new DoubleWordRegister(parent)
483                     .WithValueField(0, 32,
484                         writeCallback: (_, value) => descriptor.sourceAddress = (uint)value,
485                         valueProviderCallback: _ => descriptor.sourceAddress,
486                         name: "SRCADDR")
487                 ;
488                 DescriptorDestinationDataAddressRegister = new DoubleWordRegister(parent)
489                     .WithValueField(0, 32,
490                         writeCallback: (_, value) => descriptor.destinationAddress = (uint)value,
491                         valueProviderCallback: _ => descriptor.destinationAddress,
492                         name: "DSTADDR")
493                 ;
494                 DescriptorLinkStructureAddressRegister = new DoubleWordRegister(parent)
495                     .WithEnumField<DoubleWordRegister, AddressingMode>(0, 1, FieldMode.Read,
496                         valueProviderCallback: _ => descriptor.linkMode,
497                         name: "LINKMODE")
498                     .WithFlag(1,
499                         writeCallback: (_, value) => descriptor.link = value,
500                         valueProviderCallback: _ => descriptor.link,
501                         name: "LINK")
502                     .WithValueField(2, 30,
503                         writeCallback: (_, value) => descriptor.linkAddress = (uint)value,
504                         valueProviderCallback: _ => descriptor.linkAddress,
505                         name: "LINKADDR")
506                 ;
507 
508                 pullTimer = new LimitTimer(parent.machine.ClockSource, 1000000, null, $"pullTimer-{Index}", 15, Direction.Ascending, false, WorkMode.Periodic, true, true);
509                 pullTimer.LimitReached += delegate
510                 {
511                     if(!RequestDisable)
512                     {
513                         StartTransferInner();
514                     }
515                     if(!SignalIsOn || !ShouldPullSignal)
516                     {
517                         pullTimer.Enabled = false;
518                     }
519                 };
520             }
521 
StartFromSignal()522             public void StartFromSignal()
523             {
524                 if(!RequestDisable)
525                 {
526                     StartTransfer();
527                 }
528             }
529 
LinkLoad()530             public void LinkLoad()
531             {
532                 LoadDescriptor();
533                 if(descriptor.structureTransferRequest || SignalIsOn)
534                 {
535                     StartTransfer();
536                 }
537             }
538 
StartTransfer()539             public void StartTransfer()
540             {
541                 if(ShouldPullSignal)
542                 {
543                     pullTimer.Enabled = true;
544                 }
545                 else
546                 {
547                     StartTransferInner();
548                 }
549             }
550 
Reset()551             public void Reset()
552             {
553                 descriptor = default(Descriptor);
554                 pullTimer.Reset();
555                 DoneInterrupt = false;
556                 DoneInterruptEnable = false;
557                 descriptorAddress = null;
558                 requestDisable = false;
559                 enabled = false;
560                 done = false;
561             }
562 
563             public int Index { get; }
564 
565             public SignalSelect Signal => signalSelect.Value;
566             public SourceSelect Source => sourceSelect.Value;
567             public bool IgnoreSingleRequests => descriptor.ignoreSingleRequests;
568 
569             public bool DoneInterrupt { get; set; }
570             public bool DoneInterruptEnable { get; set; }
571             public bool IRQ => DoneInterrupt && DoneInterruptEnable;
572 
573             public DoubleWordRegister PeripheralRequestSelectRegister { get; }
574             public DoubleWordRegister ConfigurationRegister { get; }
575             public DoubleWordRegister LoopCounterRegister { get; }
576             public DoubleWordRegister DescriptorControlWordRegister { get; }
577             public DoubleWordRegister DescriptorSourceDataAddressRegister { get; }
578             public DoubleWordRegister DescriptorDestinationDataAddressRegister { get; }
579             public DoubleWordRegister DescriptorLinkStructureAddressRegister { get; }
580 
581             public bool Enabled
582             {
583                 get
584                 {
585                     return enabled;
586                 }
587                 set
588                 {
589                     if(enabled == value)
590                     {
591                         return;
592                     }
593                     enabled = value;
594                     if(enabled)
595                     {
596                         Done = false;
597                         StartTransfer();
598                     }
599                 }
600             }
601 
602             public bool Done
603             {
604                 get
605                 {
606                     return done;
607                 }
608 
609                 set
610                 {
611                     done = value;
612                     DoneInterrupt |= done && descriptor.operationDoneInterruptFlagSetEnable;
613                 }
614             }
615 
616             public bool RequestDisable
617             {
618                 get
619                 {
620                     return requestDisable;
621                 }
622 
623                 set
624                 {
625                     if(requestDisable && !value)
626                     {
627                         requestDisable = value;
628                         if(SignalIsOn)
629                         {
630                             StartTransfer();
631                         }
632                     }
633                     requestDisable = value;
634                 }
635             }
636 
StartTransferInner()637             private void StartTransferInner()
638             {
639                 if(isInProgress || Done)
640                 {
641                     return;
642                 }
643 
644                 isInProgress = true;
645                 var loaded = false;
646                 do
647                 {
648                     loaded = false;
649                     Transfer();
650                     if(Done && descriptor.link)
651                     {
652                         loaded = true;
653                         LoadDescriptor();
654                     }
655                 }
656                 while((descriptor.structureTransferRequest && loaded) || (!Done && SignalIsOn));
657                 isInProgress = false;
658             }
659 
LoadDescriptor()660             private void LoadDescriptor()
661             {
662                 var address = LinkStructureAddress;
663                 if(descriptorAddress.HasValue && descriptor.linkMode == AddressingMode.Relative)
664                 {
665                     address += descriptorAddress.Value;
666                 }
667                 var data = parent.sysbus.ReadBytes(address, DescriptorSize);
668                 descriptorAddress = address;
669                 descriptor = Packet.Decode<Descriptor>(data);
670 #if DEBUG
671                 parent.Log(LogLevel.Noisy, "Channel #{0} data {1}", Index, BitConverter.ToString(data));
672                 parent.Log(LogLevel.Debug, "Channel #{0} Loaded {1}", Index, descriptor.PrettyString);
673 #endif
674             }
675 
Transfer()676             private void Transfer()
677             {
678                 switch(descriptor.structureType)
679                 {
680                     case StructureType.Transfer:
681                         var request = new Request(
682                             source: new Place(descriptor.sourceAddress),
683                             destination: new Place(descriptor.destinationAddress),
684                             size: Bytes,
685                             readTransferType: SizeAsTransferType,
686                             writeTransferType: SizeAsTransferType,
687                             sourceIncrementStep: SourceIncrement,
688                             destinationIncrementStep: DestinationIncrement
689                         );
690                         parent.Log(LogLevel.Debug, "Channel #{0} Performing Transfer", Index);
691                         parent.engine.IssueCopy(request);
692                         if(descriptor.requestTransferModeSelect == RequestTransferMode.Block)
693                         {
694                             var blockSizeMultiplier = Math.Min(TransferCount, BlockSizeMultiplier);
695                             if(blockSizeMultiplier == TransferCount)
696                             {
697                                 Done = true;
698                                 descriptor.transferCount = 0;
699                             }
700                             else
701                             {
702                                 descriptor.transferCount -= blockSizeMultiplier;
703                             }
704                             descriptor.sourceAddress += SourceIncrement * blockSizeMultiplier;
705                             descriptor.destinationAddress += DestinationIncrement * blockSizeMultiplier;
706                         }
707                         else
708                         {
709                             Done = true;
710                         }
711                         break;
712                     case StructureType.Synchronize:
713                         parent.Log(LogLevel.Warning, "Channel #{0} Synchronize is not implemented.", Index);
714                         break;
715                     case StructureType.Write:
716                         parent.Log(LogLevel.Warning, "Channel #{0} Write is not implemented.", Index);
717                         break;
718                     default:
719                         parent.Log(LogLevel.Error, "Channel #{0} Invalid structure type value. No action was performed.", Index);
720                         return;
721                 }
722                 parent.UpdateInterrupts();
723             }
724 
725             private bool ShouldPullSignal
726             {
727                 get
728                 {
729                     // if this returns true for the selected source and signal
730                     // then the signal will be periodically pulled instead of waiting
731                     // for an rising edge
732                     switch(Source)
733                     {
734                         case SourceSelect.None:
735                             return false;
736                         case SourceSelect.PRS:
737                             switch(Signal)
738                             {
739                                 case SignalSelect.PRSRequest0:
740                                 case SignalSelect.PRSRequest1:
741                                     return false;
742                                 default:
743                                     goto default;
744                             }
745                         case SourceSelect.ADC0:
746                             switch(Signal)
747                             {
748                                 case SignalSelect.ADC0Single:
749                                 case SignalSelect.ADC0Scan:
750                                     return false;
751                                 default:
752                                     goto default;
753                             }
754                         case SourceSelect.VDAC0:
755                             switch(Signal)
756                             {
757                                 case SignalSelect.VDAC0CH0:
758                                 case SignalSelect.VDAC0CH1:
759                                     return false;
760                                 default:
761                                     goto default;
762                             }
763                         case SourceSelect.USART0:
764                         case SourceSelect.USART2:
765                         case SourceSelect.LEUART0:
766                             switch(Signal)
767                             {
768                                 case SignalSelect.USART0RxDataAvailable:
769                                     return false;
770                                 case SignalSelect.USART0TxBufferLow:
771                                 case SignalSelect.USART0TxEmpty:
772                                     return true;
773                                 default:
774                                     goto default;
775                             }
776                         case SourceSelect.USART1:
777                         case SourceSelect.USART3:
778                             switch(Signal)
779                             {
780                                 case SignalSelect.USART1RxDataAvailable:
781                                 case SignalSelect.USART1RxDataAvailableRight:
782                                     return false;
783                                 case SignalSelect.USART1TxBufferLow:
784                                 case SignalSelect.USART1TxEmpty:
785                                 case SignalSelect.USART1TxBufferLowRight:
786                                     return true;
787                                 default:
788                                     goto default;
789                             }
790                         case SourceSelect.I2C0:
791                         case SourceSelect.I2C1:
792                             switch(Signal)
793                             {
794                                 case SignalSelect.I2C0RxDataAvailable:
795                                     return false;
796                                 case SignalSelect.I2C0TxBufferLow:
797                                     return true;
798                                 default:
799                                     goto default;
800                             }
801                         case SourceSelect.TIMER0:
802                         case SourceSelect.WTIMER0:
803                             switch(Signal)
804                             {
805                                 case SignalSelect.TIMER0UnderflowOverflow:
806                                 case SignalSelect.TIMER0CaptureCompare0:
807                                 case SignalSelect.TIMER0CaptureCompare1:
808                                 case SignalSelect.TIMER0CaptureCompare2:
809                                     return false;
810                                 default:
811                                     goto default;
812                             }
813                         case SourceSelect.TIMER1:
814                         case SourceSelect.WTIMER1:
815                             switch(Signal)
816                             {
817                                 case SignalSelect.TIMER1UnderflowOverflow:
818                                 case SignalSelect.TIMER1CaptureCompare0:
819                                 case SignalSelect.TIMER1CaptureCompare1:
820                                 case SignalSelect.TIMER1CaptureCompare2:
821                                 case SignalSelect.TIMER1CaptureCompare3:
822                                     return false;
823                                 default:
824                                     goto default;
825                             }
826                         case SourceSelect.PROTIMER:
827                             switch(Signal)
828                             {
829                                 case SignalSelect.PROTIMERPreCounterOverflow:
830                                 case SignalSelect.PROTIMERBaseCounterOverflow:
831                                 case SignalSelect.PROTIMERWrapCounterOverflow:
832                                 case SignalSelect.PROTIMERCaptureCompare0:
833                                 case SignalSelect.PROTIMERCaptureCompare1:
834                                 case SignalSelect.PROTIMERCaptureCompare2:
835                                 case SignalSelect.PROTIMERCaptureCompare3:
836                                 case SignalSelect.PROTIMERCaptureCompare4:
837                                     return false;
838                                 default:
839                                     goto default;
840                             }
841                         case SourceSelect.MODEM:
842                             switch(Signal)
843                             {
844                                 case SignalSelect.MODEMDebug:
845                                     return false;
846                                 default:
847                                     goto default;
848                             }
849                         case SourceSelect.AGC:
850                             switch(Signal)
851                             {
852                                 case SignalSelect.AGCReceivedSignalStrengthIndicator:
853                                     return false;
854                                 default:
855                                     goto default;
856                             }
857                         case SourceSelect.MSC:
858                             switch(Signal)
859                             {
860                                 case SignalSelect.MSCWriteDataReady:
861                                     return false;
862                                 default:
863                                     goto default;
864                             }
865                         case SourceSelect.CRYPTO0:
866                         case SourceSelect.CRYPTO1:
867                             switch(Signal)
868                             {
869                                 case SignalSelect.CRYPTO0Data0Write:
870                                 case SignalSelect.CRYPTO0Data0XorWrite:
871                                 case SignalSelect.CRYPTO0Data0Read:
872                                 case SignalSelect.CRYPTO0Data1Write:
873                                 case SignalSelect.CRYPTO0Data1Read:
874                                     return false;
875                                 default:
876                                     goto default;
877                             }
878                         case SourceSelect.CSEN:
879                             switch(Signal)
880                             {
881                                 case SignalSelect.CSENData:
882                                 case SignalSelect.CSENBaseline:
883                                     return false;
884                                 default:
885                                     goto default;
886                             }
887                         case SourceSelect.LESENSE:
888                             switch(Signal)
889                             {
890                                 case SignalSelect.LESENSEBufferDataAvailable:
891                                     return false;
892                                 default:
893                                     goto default;
894                             }
895                         default:
896                             parent.Log(LogLevel.Error, "Channel #{0} Invalid Source (0x{1:X}) and Signal (0x{2:X}) pair.", Index, Source, Signal);
897                             return false;
898                     }
899                 }
900             }
901 
902             private uint BlockSizeMultiplier
903             {
904                 get
905                 {
906                     switch(descriptor.blockSize)
907                     {
908                         case BlockSizeMode.Unit1:
909                         case BlockSizeMode.Unit2:
910                             return 1u << (byte)descriptor.blockSize;
911                         case BlockSizeMode.Unit3:
912                             return 3;
913                         case BlockSizeMode.Unit4:
914                             return 4;
915                         case BlockSizeMode.Unit6:
916                             return 6;
917                         case BlockSizeMode.Unit8:
918                             return 8;
919                         case BlockSizeMode.Unit16:
920                             return 16;
921                         case BlockSizeMode.Unit32:
922                         case BlockSizeMode.Unit64:
923                         case BlockSizeMode.Unit128:
924                         case BlockSizeMode.Unit256:
925                         case BlockSizeMode.Unit512:
926                         case BlockSizeMode.Unit1024:
927                             return 1u << ((byte)descriptor.blockSize - 4);
928                         case BlockSizeMode.All:
929                             return TransferCount;
930                         default:
931                             parent.Log(LogLevel.Warning, "Channel #{0} Invalid Block Size Mode value.", Index);
932                             return 0;
933                     }
934                 }
935             }
936 
937             private bool SignalIsOn
938             {
939                 get
940                 {
941                     var number = ((int)Source << 4) | (int)Signal;
942                     return parent.signals.Contains(number) || (!IgnoreSingleRequests && parent.signals.Contains(number | 1 << 12));
943                 }
944             }
945 
946             private uint TransferCount => (uint)descriptor.transferCount + 1;
947             private ulong LinkStructureAddress => (ulong)descriptor.linkAddress << 2;
948 
949             private uint SourceIncrement => descriptor.sourceIncrement == IncrementMode.None ? 0u : ((1u << (byte)descriptor.size) << (byte)descriptor.sourceIncrement);
950             private uint DestinationIncrement => descriptor.destinationIncrement == IncrementMode.None ? 0u : ((1u << (byte)descriptor.size) << (byte)descriptor.destinationIncrement);
951             private TransferType SizeAsTransferType => (TransferType)(1 << (byte)descriptor.size);
952             private int Bytes => (int)(descriptor.requestTransferModeSelect == RequestTransferMode.All ? TransferCount : Math.Min(TransferCount, BlockSizeMultiplier)) << (byte)descriptor.size;
953 
954             private Descriptor descriptor;
955             private ulong? descriptorAddress;
956             private bool requestDisable;
957             private bool enabled;
958             private bool done;
959 
960             // Accesses to sysubs may cause changes in signals, but we should ignore those during active transaction
961             private bool isInProgress;
962 
963             private IEnumRegisterField<SignalSelect> signalSelect;
964             private IEnumRegisterField<SourceSelect> sourceSelect;
965             private IEnumRegisterField<ArbitrationSlotNumberMode> arbitrationSlotNumberSelect;
966             private IEnumRegisterField<Sign> sourceAddressIncrementSign;
967             private IEnumRegisterField<Sign> destinationAddressIncrementSign;
968             private IValueRegisterField loopCounter;
969 
970             private readonly EFR32MG12_LDMA parent;
971             private readonly LimitTimer pullTimer;
972 
973             protected readonly int DescriptorSize = Packet.CalculateLength<Descriptor>();
974 
975             private enum ArbitrationSlotNumberMode
976             {
977                 One   = 0,
978                 Two   = 1,
979                 Four  = 2,
980                 Eight = 3,
981             }
982 
983             private enum Sign
984             {
985                 Positive = 0,
986                 Negative = 1,
987             }
988 
989             protected enum StructureType : uint
990             {
991                 Transfer    = 0,
992                 Synchronize = 1,
993                 Write       = 2,
994             }
995 
996             protected enum BlockSizeMode : uint
997             {
998                 Unit1    = 0,
999                 Unit2    = 1,
1000                 Unit3    = 2,
1001                 Unit4    = 3,
1002                 Unit6    = 4,
1003                 Unit8    = 5,
1004                 Unit16   = 7,
1005                 Unit32   = 9,
1006                 Unit64   = 10,
1007                 Unit128  = 11,
1008                 Unit256  = 12,
1009                 Unit512  = 13,
1010                 Unit1024 = 14,
1011                 All      = 15,
1012             }
1013 
1014             protected enum RequestTransferMode : uint
1015             {
1016                 Block = 0,
1017                 All   = 1,
1018             }
1019 
1020             protected enum IncrementMode : uint
1021             {
1022                 One  = 0,
1023                 Two  = 1,
1024                 Four = 2,
1025                 None = 3,
1026             }
1027 
1028             protected enum SizeMode : uint
1029             {
1030                 Byte     = 0,
1031                 HalfWord = 1,
1032                 Word     = 2,
1033             }
1034 
1035             protected enum AddressingMode : uint
1036             {
1037                 Absolute = 0,
1038                 Relative = 1,
1039             }
1040 
1041             [LeastSignificantByteFirst]
1042             private struct Descriptor
1043             {
1044                 public string PrettyString => $@"Descriptor {{
1045     structureType: {structureType},
1046     structureTransferRequest: {structureTransferRequest},
1047     transferCount: {transferCount + 1},
1048     byteSwap: {byteSwap},
1049     blockSize: {blockSize},
1050     operationDoneInterruptFlagSetEnable: {operationDoneInterruptFlagSetEnable},
1051     requestTransferModeSelect: {requestTransferModeSelect},
1052     decrementLoopCount: {decrementLoopCount},
1053     ignoreSingleRequests: {ignoreSingleRequests},
1054     sourceIncrement: {sourceIncrement},
1055     size: {size},
1056     destinationIncrement: {destinationIncrement},
1057     sourceAddressingMode: {sourceAddressingMode},
1058     destinationAddressingMode: {destinationAddressingMode},
1059     sourceAddress: 0x{sourceAddress:X},
1060     destinationAddress: 0x{destinationAddress:X},
1061     linkMode: {linkMode},
1062     link: {link},
1063     linkAddress: 0x{(linkAddress << 2):X}
1064 }}";
1065 
1066 // Some of this fields are read only via sysbus, but can be loaded from memory
1067 #pragma warning disable 649
1068                 [PacketField, Offset(doubleWords: 0, bits: 0), Width(2)]
1069                 public StructureType structureType;
1070                 [PacketField, Offset(doubleWords: 0, bits: 3), Width(1)]
1071                 public bool structureTransferRequest;
1072                 [PacketField, Offset(doubleWords: 0, bits: 4), Width(11)]
1073                 public uint transferCount;
1074                 [PacketField, Offset(doubleWords: 0, bits: 15), Width(1)]
1075                 public bool byteSwap;
1076                 [PacketField, Offset(doubleWords: 0, bits: 16), Width(4)]
1077                 public BlockSizeMode blockSize;
1078                 [PacketField, Offset(doubleWords: 0, bits: 20), Width(1)]
1079                 public bool operationDoneInterruptFlagSetEnable;
1080                 [PacketField, Offset(doubleWords: 0, bits: 21), Width(1)]
1081                 public RequestTransferMode requestTransferModeSelect;
1082                 [PacketField, Offset(doubleWords: 0, bits: 22), Width(1)]
1083                 public bool decrementLoopCount;
1084                 [PacketField, Offset(doubleWords: 0, bits: 23), Width(1)]
1085                 public bool ignoreSingleRequests;
1086                 [PacketField, Offset(doubleWords: 0, bits: 24), Width(2)]
1087                 public IncrementMode sourceIncrement;
1088                 [PacketField, Offset(doubleWords: 0, bits: 26), Width(2)]
1089                 public SizeMode size;
1090                 [PacketField, Offset(doubleWords: 0, bits: 28), Width(2)]
1091                 public IncrementMode destinationIncrement;
1092                 [PacketField, Offset(doubleWords: 0, bits: 30), Width(1)]
1093                 public AddressingMode sourceAddressingMode;
1094                 [PacketField, Offset(doubleWords: 0, bits: 31), Width(1)]
1095                 public AddressingMode destinationAddressingMode;
1096                 [PacketField, Offset(doubleWords: 1, bits: 0), Width(32)]
1097                 public uint sourceAddress;
1098                 [PacketField, Offset(doubleWords: 2, bits: 0), Width(32)]
1099                 public uint destinationAddress;
1100                 [PacketField, Offset(doubleWords: 3, bits: 0), Width(1)]
1101                 public AddressingMode linkMode;
1102                 [PacketField, Offset(doubleWords: 3, bits: 1), Width(1)]
1103                 public bool link;
1104                 [PacketField, Offset(doubleWords: 3, bits: 2), Width(30)]
1105                 public uint linkAddress;
1106 #pragma warning restore 649
1107             }
1108         }
1109     }
1110 }
1111