1 // 2 // Copyright (c) 2010-2025 Antmicro 3 // Copyright (c) 2022-2025 Silicon Labs 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 9 using System; 10 using System.Collections.Generic; 11 using System.Collections.ObjectModel; 12 using System.Linq; 13 using System.Runtime.InteropServices; 14 using Antmicro.Renode.Core; 15 using Antmicro.Renode.Core.Structure.Registers; 16 using Antmicro.Renode.Exceptions; 17 using Antmicro.Renode.Logging; 18 using Antmicro.Renode.Peripherals.Bus; 19 using Antmicro.Renode.Peripherals.Timers; 20 using Antmicro.Renode.Time; 21 using Antmicro.Renode.Utilities.Packets; 22 23 namespace Antmicro.Renode.Peripherals.DMA 24 { 25 public class EFR32xG22_LDMA : IBusPeripheral, IGPIOReceiver, IKnownSize 26 { EFR32xG22_LDMA(Machine machine)27 public EFR32xG22_LDMA(Machine machine) 28 { 29 this.machine = machine; 30 engine = new DmaEngine(machine.GetSystemBus(this)); 31 signals = new HashSet<int>(); 32 IRQ = new GPIO(); 33 channels = new Channel[NumberOfChannels]; 34 for(var i = 0; i < NumberOfChannels; ++i) 35 { 36 channels[i] = new Channel(this, i); 37 } 38 ldmaRegistersCollection = BuildLdmaRegisters(); 39 ldmaXbarRegistersCollection = BuildLdmaXbarRegisters(); 40 } 41 Reset()42 public void Reset() 43 { 44 signals.Clear(); 45 foreach(var channel in channels) 46 { 47 channel.Reset(); 48 } 49 UpdateInterrupts(); 50 } 51 OnGPIO(int number, bool value)52 public void OnGPIO(int number, bool value) 53 { 54 var signal = (SignalSelect)(number & 0xf); 55 var source = (SourceSelect)((number >> 4) & 0x3f); 56 bool single = ((number >> 12) & 1) != 0; 57 58 if(!value) 59 { 60 signals.Remove(number); 61 return; 62 } 63 signals.Add(number); 64 65 for(var i = 0; i < NumberOfChannels; ++i) 66 { 67 if(single && channels[i].IgnoreSingleRequests) 68 { 69 continue; 70 } 71 if(channels[i].Signal == signal && channels[i].Source == source) 72 { 73 channels[i].StartFromSignal(); 74 } 75 } 76 } 77 78 public GPIO IRQ { get; } 79 80 public long Size => 0x400; 81 private readonly DoubleWordRegisterCollection ldmaRegistersCollection; 82 private readonly DoubleWordRegisterCollection ldmaXbarRegistersCollection; 83 private readonly Machine machine; 84 85 private uint Read<T>(DoubleWordRegisterCollection registersCollection, string regionName, long offset, bool internal_read = false) 86 where T : struct, IComparable, IFormattable 87 { 88 var result = 0U; 89 long internal_offset = offset; 90 91 // Set, Clear, Toggle registers should only be used for write operations. But just in case we convert here as well. 92 if (offset >= SetRegisterOffset && offset < ClearRegisterOffset) 93 { 94 // Set register 95 internal_offset = offset - SetRegisterOffset; 96 if(!internal_read) 97 { 98 this.Log(LogLevel.Noisy, "SET Operation on {0}, offset=0x{1:X}, internal_offset=0x{2:X}", Enum.Format(typeof(T), internal_offset, "G"), offset, internal_offset); 99 } 100 } else if (offset >= ClearRegisterOffset && offset < ToggleRegisterOffset) 101 { 102 // Clear register 103 internal_offset = offset - ClearRegisterOffset; 104 if(!internal_read) 105 { 106 this.Log(LogLevel.Noisy, "CLEAR Operation on {0}, offset=0x{1:X}, internal_offset=0x{2:X}", Enum.Format(typeof(T), internal_offset, "G"), offset, internal_offset); 107 } 108 } else if (offset >= ToggleRegisterOffset) 109 { 110 // Toggle register 111 internal_offset = offset - ToggleRegisterOffset; 112 if(!internal_read) 113 { 114 this.Log(LogLevel.Noisy, "TOGGLE Operation on {0}, offset=0x{1:X}, internal_offset=0x{2:X}", Enum.Format(typeof(T), internal_offset, "G"), offset, internal_offset); 115 } 116 } 117 118 if(!registersCollection.TryRead(internal_offset, out result)) 119 { 120 if(!internal_read) 121 { 122 this.Log(LogLevel.Noisy, "Unhandled read from {0} at offset 0x{1:X} ({2}).", regionName, internal_offset, Enum.Format(typeof(T), internal_offset, "G")); 123 } 124 } 125 else 126 { 127 if(!internal_read) 128 { 129 this.Log(LogLevel.Noisy, "{0}: Read from {1} at offset 0x{2:X} ({3}), returned 0x{4:X}", 130 this.GetTime(), regionName, internal_offset, Enum.Format(typeof(T), internal_offset, "G"), result); 131 } 132 } 133 134 return result; 135 } 136 137 private void Write<T>(DoubleWordRegisterCollection registersCollection, string regionName, long offset, uint value) 138 where T : struct, IComparable, IFormattable 139 { machine.ClockSource.ExecuteInLockAntmicro.Renode.Peripherals.DMA.EFR32xG22_LDMA.IFormattable140 machine.ClockSource.ExecuteInLock(delegate { 141 long internal_offset = offset; 142 uint internal_value = value; 143 144 if (offset >= SetRegisterOffset && offset < ClearRegisterOffset) 145 { 146 // Set register 147 internal_offset = offset - SetRegisterOffset; 148 uint old_value = Read<T>(registersCollection, regionName, internal_offset, true); 149 internal_value = old_value | value; 150 this.Log(LogLevel.Noisy, "SET Operation on {0}, offset=0x{1:X}, internal_offset=0x{2:X}, SET_value=0x{3:X}, old_value=0x{4:X}, new_value=0x{5:X}", Enum.Format(typeof(T), internal_offset, "G"), offset, internal_offset, value, old_value, internal_value); 151 } else if (offset >= ClearRegisterOffset && offset < ToggleRegisterOffset) 152 { 153 // Clear register 154 internal_offset = offset - ClearRegisterOffset; 155 uint old_value = Read<T>(registersCollection, regionName, internal_offset, true); 156 internal_value = old_value & ~value; 157 this.Log(LogLevel.Noisy, "CLEAR Operation on {0}, offset=0x{1:X}, internal_offset=0x{2:X}, CLEAR_value=0x{3:X}, old_value=0x{4:X}, new_value=0x{5:X}", Enum.Format(typeof(T), internal_offset, "G"), offset, internal_offset, value, old_value, internal_value); 158 } else if (offset >= ToggleRegisterOffset) 159 { 160 // Toggle register 161 internal_offset = offset - ToggleRegisterOffset; 162 uint old_value = Read<T>(registersCollection, regionName, internal_offset, true); 163 internal_value = old_value ^ value; 164 this.Log(LogLevel.Noisy, "TOGGLE Operation on {0}, offset=0x{1:X}, internal_offset=0x{2:X}, TOGGLE_value=0x{3:X}, old_value=0x{4:X}, new_value=0x{5:X}", Enum.Format(typeof(T), internal_offset, "G"), offset, internal_offset, value, old_value, internal_value); 165 } 166 167 this.Log(LogLevel.Noisy, "{0}: Write to {1} at offset 0x{2:X} ({3}), value 0x{4:X}", 168 this.GetTime(), regionName, internal_offset, Enum.Format(typeof(T), internal_offset, "G"), internal_value); 169 170 if(!registersCollection.TryWrite(internal_offset, internal_value)) 171 { 172 this.Log(LogLevel.Debug, "Unhandled write to {0} at offset 0x{1:X} ({2}), value 0x{3:X}.", regionName, internal_offset, Enum.Format(typeof(T), internal_offset, "G"), internal_value); 173 return; 174 } 175 }); 176 } 177 178 [ConnectionRegionAttribute("ldma")] WriteDoubleWordToLdma(long offset, uint value)179 public void WriteDoubleWordToLdma(long offset, uint value) 180 { 181 Write<LdmaRegisters>(ldmaRegistersCollection, "Ldma", offset, value); 182 } 183 184 [ConnectionRegionAttribute("ldma")] ReadDoubleWordFromLdma(long offset)185 public uint ReadDoubleWordFromLdma(long offset) 186 { 187 return Read<LdmaRegisters>(ldmaRegistersCollection, "Ldma", offset); 188 } 189 190 [ConnectionRegionAttribute("ldmaxbar")] WriteDoubleWordToLdmaXbar(long offset, uint value)191 public void WriteDoubleWordToLdmaXbar(long offset, uint value) 192 { 193 Write<LdmaXbarRegisters>(ldmaXbarRegistersCollection, "LdmaXbar", offset, value); 194 } 195 196 [ConnectionRegionAttribute("ldmaxbar")] ReadDoubleWordFromLdmaXbar(long offset)197 public uint ReadDoubleWordFromLdmaXbar(long offset) 198 { 199 return Read<LdmaXbarRegisters>(ldmaXbarRegistersCollection, "LdmaXbar", offset); 200 } 201 BuildLdmaRegisters()202 private DoubleWordRegisterCollection BuildLdmaRegisters() 203 { 204 DoubleWordRegisterCollection c = new DoubleWordRegisterCollection(this, new Dictionary<long, DoubleWordRegister> 205 { 206 {(long)LdmaRegisters.CTRL, new DoubleWordRegister(this) 207 .WithReservedBits(0, 24) 208 .WithTag("NUMFIXED", 24, 5) 209 .WithReservedBits(29, 2) 210 .WithTaggedFlag("CORERST", 31) 211 }, 212 {(long)LdmaRegisters.STATUS, new DoubleWordRegister(this) 213 .WithTaggedFlag("ANYBUSY", 0) 214 .WithTaggedFlag("ANYREQ", 1) 215 .WithReservedBits(2, 1) 216 .WithTag("CHGRANT", 3, 5) 217 .WithTag("CHERROR", 8, 5) 218 .WithReservedBits(13, 3) 219 .WithTag("FIFOLEVEL", 16, 5) 220 .WithReservedBits(21, 3) 221 .WithTag("CHNUM", 24, 5) 222 .WithReservedBits(29, 3) 223 }, 224 {(long)LdmaRegisters.CHEN, new DoubleWordRegister(this) 225 .WithFlags(0, 8, writeCallback: (i, _, value) => { if (value) channels[i].Enabled = true; }, name: "CHEN") 226 .WithReservedBits(8, 24) 227 }, 228 {(long)LdmaRegisters.CHDIS, new DoubleWordRegister(this) 229 .WithFlags(0, 8, writeCallback: (i, _, value) => { if (value) channels[i].Enabled = false; }, name: "CHDIS") 230 .WithReservedBits(8, 24) 231 }, 232 {(long)LdmaRegisters.CHBUSY, new DoubleWordRegister(this) 233 .WithFlags(0, 8, FieldMode.Read, valueProviderCallback: (i, _) => channels[i].Busy, name: "CHBUSY") 234 .WithReservedBits(8, 24) 235 }, 236 {(long)LdmaRegisters.CHSTATUS, new DoubleWordRegister(this) 237 .WithFlags(0, 8, FieldMode.Read, valueProviderCallback: (i, _) => channels[i].Enabled, name: "CHSTATUS") 238 .WithReservedBits(8, 24) 239 }, 240 {(long)LdmaRegisters.CHDONE, new DoubleWordRegister(this) 241 .WithFlags(0, 8, writeCallback: (i, _, value) => channels[i].Done = value, valueProviderCallback: (i, _) => channels[i].Done, name: "CHDONE") 242 .WithReservedBits(8, 24) 243 }, 244 {(long)LdmaRegisters.DBGHALT, new DoubleWordRegister(this) 245 .WithTag("DBGHALT", 0, 8) 246 .WithReservedBits(8, 24) 247 }, 248 {(long)LdmaRegisters.SWREQ, new DoubleWordRegister(this) 249 .WithFlags(0, 8, FieldMode.Set, writeCallback: (i, _, value) => { if(value) channels[i].StartTransfer(); }, name: "SWREQ") 250 .WithReservedBits(8, 24) 251 }, 252 {(long)LdmaRegisters.REQDIS, new DoubleWordRegister(this) 253 .WithFlags(0, 8, writeCallback: (i, _, value) => channels[i].RequestDisable = value, valueProviderCallback: (i, _) => channels[i].RequestDisable, name: "REQDIS") 254 .WithReservedBits(8, 24) 255 }, 256 {(long)LdmaRegisters.REQPEND, new DoubleWordRegister(this) 257 .WithTag("REQPEND", 0, 8) 258 .WithReservedBits(8, 24) 259 }, 260 {(long)LdmaRegisters.LINKLOAD, new DoubleWordRegister(this) 261 .WithFlags(0, 8, FieldMode.Set, writeCallback: (i, _, value) => { if(value) channels[i].LinkLoad(); }, name: "LINKLOAD") 262 .WithReservedBits(8, 24) 263 }, 264 {(long)LdmaRegisters.REQCLEAR, new DoubleWordRegister(this) 265 .WithTag("REQCLEAR", 0, 8) 266 .WithReservedBits(8, 24) 267 }, 268 {(long)LdmaRegisters.IF, new DoubleWordRegister(this) 269 .WithFlags(0, 8, writeCallback: (i, _, value) => channels[i].DoneInterrupt = value, valueProviderCallback: (i, _) => channels[i].DoneInterrupt, name: "IF") 270 .WithReservedBits(8, 23) 271 .WithTaggedFlag("ERROR", 31) 272 .WithWriteCallback((_, __) => UpdateInterrupts()) 273 }, 274 {(long)LdmaRegisters.IEN, new DoubleWordRegister(this) 275 .WithFlags(0, 8, writeCallback: (i, _, value) => channels[i].DoneInterruptEnable = value, valueProviderCallback: (i, _) => channels[i].DoneInterruptEnable, name: "IEN") 276 .WithReservedBits(8, 23) 277 .WithTaggedFlag("ERROR", 31) 278 .WithWriteCallback((_, __) => UpdateInterrupts()) 279 }, 280 }); 281 282 var channelDelta = (uint)((long)LdmaRegisters.CH1_CFG - (long)LdmaRegisters.CH0_CFG); 283 BindRegisters(LdmaRegisters.CH0_CFG, c, NumberOfChannels, i => channels[i].ConfigurationRegister, channelDelta); 284 BindRegisters(LdmaRegisters.CH0_LOOP, c, NumberOfChannels, i => channels[i].LoopCounterRegister, channelDelta); 285 BindRegisters(LdmaRegisters.CH0_CTRL, c, NumberOfChannels, i => channels[i].DescriptorControlWordRegister, channelDelta); 286 BindRegisters(LdmaRegisters.CH0_SRC, c, NumberOfChannels, i => channels[i].DescriptorSourceDataAddressRegister, channelDelta); 287 BindRegisters(LdmaRegisters.CH0_DST, c, NumberOfChannels, i => channels[i].DescriptorDestinationDataAddressRegister, channelDelta); 288 BindRegisters(LdmaRegisters.CH0_LINK, c, NumberOfChannels, i => channels[i].DescriptorLinkStructureAddressRegister, channelDelta); 289 290 return c; 291 } 292 BuildLdmaXbarRegisters()293 private DoubleWordRegisterCollection BuildLdmaXbarRegisters() 294 { 295 DoubleWordRegisterCollection c = new DoubleWordRegisterCollection(this, new Dictionary<long, DoubleWordRegister>()); 296 297 var channelDelta = (uint)((long)LdmaXbarRegisters.XBAR_CH1_REQSEL - (long)LdmaXbarRegisters.XBAR_CH0_REQSEL); 298 BindRegisters(LdmaXbarRegisters.XBAR_CH0_REQSEL, c, NumberOfChannels, i => channels[i].PeripheralRequestSelectRegister, channelDelta); 299 300 return c; 301 } 302 BindRegisters(IConvertible o, DoubleWordRegisterCollection c, uint count, Func<int, DoubleWordRegister> setup, uint stepInBytes = 4)303 private void BindRegisters(IConvertible o, DoubleWordRegisterCollection c, uint count, Func<int, DoubleWordRegister> setup, uint stepInBytes = 4) 304 { 305 if(!o.GetType().IsEnum) 306 { 307 throw new ArgumentException("This method should be called on enumerated type"); 308 } 309 310 var baseAddress = Convert.ToInt64(o); 311 for(var i = 0; i < count; i++) 312 { 313 var register = setup(i); 314 c.AddRegister(baseAddress + i * stepInBytes, register); 315 } 316 } 317 UpdateInterrupts()318 private void UpdateInterrupts() 319 { 320 this.Log(LogLevel.Debug, "Interrupt set for channels: {0}", String.Join(", ", 321 channels 322 .Where(channel => channel.IRQ) 323 .Select(channel => channel.Index) 324 )); 325 IRQ.Set(channels.Any(channel => channel.IRQ)); 326 } 327 GetTime()328 private TimeInterval GetTime() => machine.LocalTimeSource.ElapsedVirtualTime; 329 330 private readonly DmaEngine engine; 331 private readonly HashSet<int> signals; 332 private readonly Channel[] channels; 333 private const uint SetRegisterOffset = 0x1000; 334 private const uint ClearRegisterOffset = 0x2000; 335 private const uint ToggleRegisterOffset = 0x3000; 336 private const int NumberOfChannels = 8; 337 338 private enum SignalSelect 339 { 340 // if SOURCESEL is LDMAXBAR 341 LDMAXBAR_DMA_PRSREQ0 = 0x0, 342 LDMAXBAR_DMA_PRSREQ1 = 0x1, 343 // if SOURCESEL is TIMER0 344 TIMER0_DMA_CC0 = 0x0, 345 TIMER0_DMA_CC1 = 0x1, 346 TIMER0_DMA_CC2 = 0x2, 347 TIMER0_DMA_UFOF = 0x3, 348 // if SOURCESEL is TIMER1 349 TIMER1_DMA_CC0 = 0x0, 350 TIMER1_DMA_CC1 = 0x1, 351 TIMER1_DMA_CC2 = 0x2, 352 TIMER1_DMA_UFOF = 0x3, 353 // if SOURCESEL is USART0 354 USART0_DMA_RXDATAV = 0x0, 355 USART0_DMA_RXDATAVRIGHT = 0x1, 356 USART0_DMA_TXBL = 0x2, 357 USART0_DMA_TXBLRIGHT = 0x3, 358 USART0_DMA_TXEMPTY = 0x4, 359 // if SOURCESEL is USART1 360 USART1_DMA_RXDATAV = 0x0, 361 USART1_DMA_RXDATAVRIGHT = 0x1, 362 USART1_DMA_TXBL = 0x2, 363 USART1_DMA_TXBLRIGHT = 0x3, 364 USART1_DMA_TXEMPTY = 0x4, 365 // if SOURCESEL is I2C0 366 I2C0_DMA_RXDATAV = 0x0, 367 I2C0_DMA_TXBL = 0x1, 368 // if SOURCESEL is I2C1 369 I2C1_DMA_RXDATAV = 0x0, 370 I2C1_DMA_TXBL = 0x1, 371 // if SOURCESEL is IADC0 372 IADC0_DMA_IADC_SCAN = 0x0, 373 IADC0_DMA_IADC_SINGLE = 0x1, 374 // if SOURCESEL is MSC 375 MSC_DMA_WDATA = 0x0, 376 // if SOURCESEL is TIMER2 377 TIMER2_DMA_CC0 = 0x0, 378 TIMER2_DMA_CC1 = 0x1, 379 TIMER2_DMA_CC2 = 0x2, 380 TIMER2_DMA_UFOF = 0x3, 381 // if SOURCESEL is TIMER3 382 TIMER3_DMA_CC0 = 0x0, 383 TIMER3_DMA_CC1 = 0x1, 384 TIMER3_DMA_CC2 = 0x2, 385 TIMER3_DMA_UFOF = 0x3, 386 // if SOURCESEL is PDM 387 PDM_DMA_RXDATAV = 0x0, 388 // if SOURCESEL is EUART0 389 EUART0_DMA_RXFL = 0x0, 390 EUART0_DMA_TXFL = 0x1, 391 // if SOURCESEL is TIMER4 392 TIMER4_DMA_CC0 = 0x0, 393 TIMER4_DMA_CC1 = 0x1, 394 TIMER4_DMA_CC2 = 0x2, 395 TIMER4_DMA_UFOF = 0x3, 396 } 397 398 private enum SourceSelect 399 { 400 None = 0x0, 401 LDMAXBAR = 0x1, 402 TIMER0 = 0x2, 403 TIMER1 = 0x3, 404 USART0 = 0x4, 405 USART1 = 0x5, 406 I2C0 = 0x6, 407 I2C1 = 0x7, 408 IADC0 = 0xB, 409 MSC = 0xC, 410 TIMER2 = 0xD, 411 TIMER3 = 0xE, 412 PDM = 0xF, 413 EUART0 = 0x10, 414 TIMER4 = 0x11, 415 } 416 417 private enum LdmaRegisters : long 418 { 419 IPVERSION = 0x0000, 420 EN = 0x0004, 421 CTRL = 0x0008, 422 STATUS = 0x000C, 423 SYNCSWSET = 0x0010, 424 SYNCSWCLR = 0x0014, 425 SYNCHWEN = 0x0018, 426 SYNCHWSEL = 0x001C, 427 SYNCSTATUS = 0x0020, 428 CHEN = 0x0024, 429 CHDIS = 0x0028, 430 CHSTATUS = 0x002C, 431 CHBUSY = 0x0030, 432 CHDONE = 0x0034, 433 DBGHALT = 0x0038, 434 SWREQ = 0x003C, 435 REQDIS = 0x0040, 436 REQPEND = 0x0044, 437 LINKLOAD = 0x0048, 438 REQCLEAR = 0x004C, 439 IF = 0x0050, 440 IEN = 0x0054, 441 CH0_CFG = 0x005C, 442 CH0_LOOP = 0x0060, 443 CH0_CTRL = 0x0064, 444 CH0_SRC = 0x0068, 445 CH0_DST = 0x006C, 446 CH0_LINK = 0x0070, 447 CH1_CFG = 0x008C, 448 CH1_LOOP = 0x0090, 449 CH1_CTRL = 0x0094, 450 CH1_SRC = 0x0098, 451 CH1_DST = 0x009C, 452 CH1_LINK = 0x00A0, 453 CH2_CFG = 0x00BC, 454 CH2_LOOP = 0x00C0, 455 CH2_CTRL = 0x00C4, 456 CH2_SRC = 0x00C8, 457 CH2_DST = 0x00CC, 458 CH2_LINK = 0x00D0, 459 CH3_CFG = 0x00EC, 460 CH3_LOOP = 0x00F0, 461 CH3_CTRL = 0x00F4, 462 CH3_SRC = 0x00F8, 463 CH3_DST = 0x00FC, 464 CH3_LINK = 0x0100, 465 CH4_CFG = 0x011C, 466 CH4_LOOP = 0x0120, 467 CH4_CTRL = 0x0124, 468 CH4_SRC = 0x0128, 469 CH4_DST = 0x012C, 470 CH4_LINK = 0x0130, 471 CH5_CFG = 0x014C, 472 CH5_LOOP = 0x0150, 473 CH5_CTRL = 0x0154, 474 CH5_SRC = 0x0158, 475 CH5_DST = 0x015C, 476 CH5_LINK = 0x0160, 477 CH6_CFG = 0x017C, 478 CH6_LOOP = 0x0180, 479 CH6_CTRL = 0x0184, 480 CH6_SRC = 0x0188, 481 CH6_DST = 0x018C, 482 CH6_LINK = 0x0190, 483 CH7_CFG = 0x01AC, 484 CH7_LOOP = 0x01B0, 485 CH7_CTRL = 0x01B4, 486 CH7_SRC = 0x01B8, 487 CH7_DST = 0x01BC, 488 CH7_LINK = 0x01C0, 489 // Set registers 490 IPVERSION_Set = 0x1000, 491 EN_Set = 0x1004, 492 CTRL_Set = 0x1008, 493 STATUS_Set = 0x100C, 494 SYNCSWSET_Set = 0x1010, 495 SYNCSWCLR_Set = 0x1014, 496 SYNCHWEN_Set = 0x1018, 497 SYNCHWSEL_Set = 0x101C, 498 SYNCSTATUS_Set = 0x1020, 499 CHEN_Set = 0x1024, 500 CHDIS_Set = 0x1028, 501 CHSTATUS_Set = 0x102C, 502 CHBUSY_Set = 0x1030, 503 CHDONE_Set = 0x1034, 504 DBGHALT_Set = 0x1038, 505 SWREQ_Set = 0x103C, 506 REQDIS_Set = 0x1040, 507 REQPEND_Set = 0x1044, 508 LINKLOAD_Set = 0x1048, 509 REQCLEAR_Set = 0x104C, 510 IF_Set = 0x1050, 511 IEN_Set = 0x1054, 512 CH0_CFG_Set = 0x105C, 513 CH0_LOOP_Set = 0x1060, 514 CH0_CTRL_Set = 0x1064, 515 CH0_SRC_Set = 0x1068, 516 CH0_DST_Set = 0x106C, 517 CH0_LINK_Set = 0x1070, 518 CH1_CFG_Set = 0x108C, 519 CH1_LOOP_Set = 0x1090, 520 CH1_CTRL_Set = 0x1094, 521 CH1_SRC_Set = 0x1098, 522 CH1_DST_Set = 0x109C, 523 CH1_LINK_Set = 0x10A0, 524 CH2_CFG_Set = 0x10BC, 525 CH2_LOOP_Set = 0x10C0, 526 CH2_CTRL_Set = 0x10C4, 527 CH2_SRC_Set = 0x10C8, 528 CH2_DST_Set = 0x10CC, 529 CH2_LINK_Set = 0x10D0, 530 CH3_CFG_Set = 0x10EC, 531 CH3_LOOP_Set = 0x10F0, 532 CH3_CTRL_Set = 0x10F4, 533 CH3_SRC_Set = 0x10F8, 534 CH3_DST_Set = 0x10FC, 535 CH3_LINK_Set = 0x1100, 536 CH4_CFG_Set = 0x111C, 537 CH4_LOOP_Set = 0x1120, 538 CH4_CTRL_Set = 0x1124, 539 CH4_SRC_Set = 0x1128, 540 CH4_DST_Set = 0x112C, 541 CH4_LINK_Set = 0x1130, 542 CH5_CFG_Set = 0x114C, 543 CH5_LOOP_Set = 0x1150, 544 CH5_CTRL_Set = 0x1154, 545 CH5_SRC_Set = 0x1158, 546 CH5_DST_Set = 0x115C, 547 CH5_LINK_Set = 0x1160, 548 CH6_CFG_Set = 0x117C, 549 CH6_LOOP_Set = 0x1180, 550 CH6_CTRL_Set = 0x1184, 551 CH6_SRC_Set = 0x1188, 552 CH6_DST_Set = 0x118C, 553 CH6_LINK_Set = 0x1190, 554 CH7_CFG_Set = 0x11AC, 555 CH7_LOOP_Set = 0x11B0, 556 CH7_CTRL_Set = 0x11B4, 557 CH7_SRC_Set = 0x11B8, 558 CH7_DST_Set = 0x11BC, 559 CH7_LINK_Set = 0x11C0, 560 // Clear registers 561 IPVERSION_Clr = 0x2000, 562 EN_Clr = 0x2004, 563 CTRL_Clr = 0x2008, 564 STATUS_Clr = 0x200C, 565 SYNCSWSET_Clr = 0x2010, 566 SYNCSWCLR_Clr = 0x2014, 567 SYNCHWEN_Clr = 0x2018, 568 SYNCHWSEL_Clr = 0x201C, 569 SYNCSTATUS_Clr = 0x2020, 570 CHEN_Clr = 0x2024, 571 CHDIS_Clr = 0x2028, 572 CHSTATUS_Clr = 0x202C, 573 CHBUSY_Clr = 0x2030, 574 CHDONE_Clr = 0x2034, 575 DBGHALT_Clr = 0x2038, 576 SWREQ_Clr = 0x203C, 577 REQDIS_Clr = 0x2040, 578 REQPEND_Clr = 0x2044, 579 LINKLOAD_Clr = 0x2048, 580 REQCLEAR_Clr = 0x204C, 581 IF_Clr = 0x2050, 582 IEN_Clr = 0x2054, 583 CH0_CFG_Clr = 0x205C, 584 CH0_LOOP_Clr = 0x2060, 585 CH0_CTRL_Clr = 0x2064, 586 CH0_SRC_Clr = 0x2068, 587 CH0_DST_Clr = 0x206C, 588 CH0_LINK_Clr = 0x2070, 589 CH1_CFG_Clr = 0x208C, 590 CH1_LOOP_Clr = 0x2090, 591 CH1_CTRL_Clr = 0x2094, 592 CH1_SRC_Clr = 0x2098, 593 CH1_DST_Clr = 0x209C, 594 CH1_LINK_Clr = 0x20A0, 595 CH2_CFG_Clr = 0x20BC, 596 CH2_LOOP_Clr = 0x20C0, 597 CH2_CTRL_Clr = 0x20C4, 598 CH2_SRC_Clr = 0x20C8, 599 CH2_DST_Clr = 0x20CC, 600 CH2_LINK_Clr = 0x20D0, 601 CH3_CFG_Clr = 0x20EC, 602 CH3_LOOP_Clr = 0x20F0, 603 CH3_CTRL_Clr = 0x20F4, 604 CH3_SRC_Clr = 0x20F8, 605 CH3_DST_Clr = 0x20FC, 606 CH3_LINK_Clr = 0x2100, 607 CH4_CFG_Clr = 0x211C, 608 CH4_LOOP_Clr = 0x2120, 609 CH4_CTRL_Clr = 0x2124, 610 CH4_SRC_Clr = 0x2128, 611 CH4_DST_Clr = 0x212C, 612 CH4_LINK_Clr = 0x2130, 613 CH5_CFG_Clr = 0x214C, 614 CH5_LOOP_Clr = 0x2150, 615 CH5_CTRL_Clr = 0x2154, 616 CH5_SRC_Clr = 0x2158, 617 CH5_DST_Clr = 0x215C, 618 CH5_LINK_Clr = 0x2160, 619 CH6_CFG_Clr = 0x217C, 620 CH6_LOOP_Clr = 0x2180, 621 CH6_CTRL_Clr = 0x2184, 622 CH6_SRC_Clr = 0x2188, 623 CH6_DST_Clr = 0x218C, 624 CH6_LINK_Clr = 0x2190, 625 CH7_CFG_Clr = 0x21AC, 626 CH7_LOOP_Clr = 0x21B0, 627 CH7_CTRL_Clr = 0x21B4, 628 CH7_SRC_Clr = 0x21B8, 629 CH7_DST_Clr = 0x21BC, 630 CH7_LINK_Clr = 0x21C0, 631 // Toggle registers 632 IPVERSION_Tgl = 0x3000, 633 EN_Tgl = 0x3004, 634 CTRL_Tgl = 0x3008, 635 STATUS_Tgl = 0x300C, 636 SYNCSWSET_Tgl = 0x3010, 637 SYNCSWCLR_Tgl = 0x3014, 638 SYNCHWEN_Tgl = 0x3018, 639 SYNCHWSEL_Tgl = 0x301C, 640 SYNCSTATUS_Tgl = 0x3020, 641 CHEN_Tgl = 0x3024, 642 CHDIS_Tgl = 0x3028, 643 CHSTATUS_Tgl = 0x302C, 644 CHBUSY_Tgl = 0x3030, 645 CHDONE_Tgl = 0x3034, 646 DBGHALT_Tgl = 0x3038, 647 SWREQ_Tgl = 0x303C, 648 REQDIS_Tgl = 0x3040, 649 REQPEND_Tgl = 0x3044, 650 LINKLOAD_Tgl = 0x3048, 651 REQCLEAR_Tgl = 0x304C, 652 IF_Tgl = 0x3050, 653 IEN_Tgl = 0x3054, 654 CH0_CFG_Tgl = 0x305C, 655 CH0_LOOP_Tgl = 0x3060, 656 CH0_CTRL_Tgl = 0x3064, 657 CH0_SRC_Tgl = 0x3068, 658 CH0_DST_Tgl = 0x306C, 659 CH0_LINK_Tgl = 0x3070, 660 CH1_CFG_Tgl = 0x308C, 661 CH1_LOOP_Tgl = 0x3090, 662 CH1_CTRL_Tgl = 0x3094, 663 CH1_SRC_Tgl = 0x3098, 664 CH1_DST_Tgl = 0x309C, 665 CH1_LINK_Tgl = 0x30A0, 666 CH2_CFG_Tgl = 0x30BC, 667 CH2_LOOP_Tgl = 0x30C0, 668 CH2_CTRL_Tgl = 0x30C4, 669 CH2_SRC_Tgl = 0x30C8, 670 CH2_DST_Tgl = 0x30CC, 671 CH2_LINK_Tgl = 0x30D0, 672 CH3_CFG_Tgl = 0x30EC, 673 CH3_LOOP_Tgl = 0x30F0, 674 CH3_CTRL_Tgl = 0x30F4, 675 CH3_SRC_Tgl = 0x30F8, 676 CH3_DST_Tgl = 0x30FC, 677 CH3_LINK_Tgl = 0x3100, 678 CH4_CFG_Tgl = 0x311C, 679 CH4_LOOP_Tgl = 0x3120, 680 CH4_CTRL_Tgl = 0x3124, 681 CH4_SRC_Tgl = 0x3128, 682 CH4_DST_Tgl = 0x312C, 683 CH4_LINK_Tgl = 0x3130, 684 CH5_CFG_Tgl = 0x314C, 685 CH5_LOOP_Tgl = 0x3150, 686 CH5_CTRL_Tgl = 0x3154, 687 CH5_SRC_Tgl = 0x3158, 688 CH5_DST_Tgl = 0x315C, 689 CH5_LINK_Tgl = 0x3160, 690 CH6_CFG_Tgl = 0x317C, 691 CH6_LOOP_Tgl = 0x3180, 692 CH6_CTRL_Tgl = 0x3184, 693 CH6_SRC_Tgl = 0x3188, 694 CH6_DST_Tgl = 0x318C, 695 CH6_LINK_Tgl = 0x3190, 696 CH7_CFG_Tgl = 0x31AC, 697 CH7_LOOP_Tgl = 0x31B0, 698 CH7_CTRL_Tgl = 0x31B4, 699 CH7_SRC_Tgl = 0x31B8, 700 CH7_DST_Tgl = 0x31BC, 701 CH7_LINK_Tgl = 0x31C0, 702 } 703 704 private enum LdmaXbarRegisters : long 705 { 706 XBAR_CH0_REQSEL = 0x0000, 707 XBAR_CH1_REQSEL = 0x0004, 708 XBAR_CH2_REQSEL = 0x0008, 709 XBAR_CH3_REQSEL = 0x000C, 710 XBAR_CH4_REQSEL = 0x0010, 711 XBAR_CH5_REQSEL = 0x0014, 712 XBAR_CH6_REQSEL = 0x0018, 713 XBAR_CH7_REQSEL = 0x001C, 714 // Set registers 715 XBAR_CH0_REQSEL_Set = 0x1000, 716 XBAR_CH1_REQSEL_Set = 0x1004, 717 XBAR_CH2_REQSEL_Set = 0x1008, 718 XBAR_CH3_REQSEL_Set = 0x100C, 719 XBAR_CH4_REQSEL_Set = 0x1010, 720 XBAR_CH5_REQSEL_Set = 0x1014, 721 XBAR_CH6_REQSEL_Set = 0x1018, 722 XBAR_CH7_REQSEL_Set = 0x101C, 723 // Clear registers 724 XBAR_CH0_REQSEL_Clr = 0x2000, 725 XBAR_CH1_REQSEL_Clr = 0x2004, 726 XBAR_CH2_REQSEL_Clr = 0x2008, 727 XBAR_CH3_REQSEL_Clr = 0x200C, 728 XBAR_CH4_REQSEL_Clr = 0x2010, 729 XBAR_CH5_REQSEL_Clr = 0x2014, 730 XBAR_CH6_REQSEL_Clr = 0x2018, 731 XBAR_CH7_REQSEL_Clr = 0x201C, 732 // Toggle registers 733 XBAR_CH0_REQSEL_Tgl = 0x3000, 734 XBAR_CH1_REQSEL_Tgl = 0x3004, 735 XBAR_CH2_REQSEL_Tgl = 0x3008, 736 XBAR_CH3_REQSEL_Tgl = 0x300C, 737 XBAR_CH4_REQSEL_Tgl = 0x3010, 738 XBAR_CH5_REQSEL_Tgl = 0x3014, 739 XBAR_CH6_REQSEL_Tgl = 0x3018, 740 XBAR_CH7_REQSEL_Tgl = 0x301C, 741 } 742 743 744 private class Channel 745 { Channel(EFR32xG22_LDMA parent, int index)746 public Channel(EFR32xG22_LDMA parent, int index) 747 { 748 this.parent = parent; 749 Index = index; 750 descriptor = default(Descriptor); 751 752 PeripheralRequestSelectRegister = new DoubleWordRegister(parent) 753 .WithEnumField<DoubleWordRegister, SignalSelect>(0, 4, out signalSelect, name: "SIGSEL") 754 .WithReservedBits(4, 12) 755 .WithEnumField<DoubleWordRegister, SourceSelect>(16, 6, out sourceSelect, name: "SOURCESEL") 756 .WithReservedBits(22, 10) 757 ; 758 ConfigurationRegister = new DoubleWordRegister(parent) 759 .WithReservedBits(0, 16) 760 .WithEnumField<DoubleWordRegister, ArbitrationSlotNumberMode>(16, 2, out arbitrationSlotNumberSelect, name: "ARBSLOTS") 761 .WithReservedBits(18, 2) 762 .WithEnumField<DoubleWordRegister, Sign>(20, 1, out sourceAddressIncrementSign, name: "SRCINCSIGN") 763 .WithEnumField<DoubleWordRegister, Sign>(21, 1, out destinationAddressIncrementSign, name: "DSTINCSIGN") 764 .WithReservedBits(22, 10) 765 ; 766 LoopCounterRegister = new DoubleWordRegister(parent) 767 .WithValueField(0, 8, out loopCounter, name: "LOOPCNT") 768 .WithReservedBits(8, 24) 769 ; 770 DescriptorControlWordRegister = new DoubleWordRegister(parent) 771 .WithEnumField<DoubleWordRegister, StructureType>(0, 2, FieldMode.Read, 772 valueProviderCallback: _ => descriptor.structureType, 773 name: "STRUCTTYPE") 774 .WithReservedBits(2, 1) 775 .WithFlag(3, FieldMode.Set, 776 writeCallback: (_, value) => descriptor.structureTransferRequest = value, 777 name: "STRUCTREQ") 778 .WithValueField(4, 11, 779 writeCallback: (_, value) => descriptor.transferCount = (ushort)value, 780 valueProviderCallback: _ => descriptor.transferCount, 781 name: "XFERCNT") 782 .WithFlag(15, 783 writeCallback: (_, value) => descriptor.byteSwap = value, 784 valueProviderCallback: _ => descriptor.byteSwap, 785 name: "BYTESWAP") 786 .WithEnumField<DoubleWordRegister, BlockSizeMode>(16, 4, 787 writeCallback: (_, value) => descriptor.blockSize = value, 788 valueProviderCallback: _ => descriptor.blockSize, 789 name: "BLOCKSIZE") 790 .WithFlag(20, 791 writeCallback: (_, value) => descriptor.operationDoneInterruptFlagSetEnable = value, 792 valueProviderCallback: _ => descriptor.operationDoneInterruptFlagSetEnable, 793 name: "DONEIEN") 794 .WithEnumField<DoubleWordRegister, RequestTransferMode>(21, 1, 795 writeCallback: (_, value) => descriptor.requestTransferModeSelect = value, 796 valueProviderCallback: _ => descriptor.requestTransferModeSelect, 797 name: "REQMODE") 798 .WithFlag(22, 799 writeCallback: (_, value) => descriptor.decrementLoopCount = value, 800 valueProviderCallback: _ => descriptor.decrementLoopCount, 801 name: "DECLOOPCNT") 802 .WithFlag(23, 803 writeCallback: (_, value) => descriptor.ignoreSingleRequests = value, 804 valueProviderCallback: _ => descriptor.ignoreSingleRequests, 805 name: "IGNORESREQ") 806 .WithEnumField<DoubleWordRegister, IncrementMode>(24, 2, 807 writeCallback: (_, value) => descriptor.sourceIncrement = value, 808 valueProviderCallback: _ => descriptor.sourceIncrement, 809 name: "SRCINC") 810 .WithEnumField<DoubleWordRegister, SizeMode>(26, 2, 811 writeCallback: (_, value) => descriptor.size = value, 812 valueProviderCallback: _ => descriptor.size, 813 name: "SIZE") 814 .WithEnumField<DoubleWordRegister, IncrementMode>(28, 2, 815 writeCallback: (_, value) => descriptor.destinationIncrement = value, 816 valueProviderCallback: _ => descriptor.destinationIncrement, 817 name: "DSTINC") 818 .WithEnumField<DoubleWordRegister, AddressingMode>(30, 1, FieldMode.Read, 819 valueProviderCallback: _ => descriptor.sourceAddressingMode, 820 name: "SRCMODE") 821 .WithEnumField<DoubleWordRegister, AddressingMode>(31, 1, FieldMode.Read, 822 valueProviderCallback: _ => descriptor.destinationAddressingMode, 823 name: "DSTMODE") 824 .WithChangeCallback((_, __) => { if(descriptor.structureTransferRequest) LinkLoad(); }) 825 ; 826 DescriptorSourceDataAddressRegister = new DoubleWordRegister(parent) 827 .WithValueField(0, 32, 828 writeCallback: (_, value) => descriptor.sourceAddress = (uint)value, 829 valueProviderCallback: _ => descriptor.sourceAddress, 830 name: "SRCADDR") 831 ; 832 DescriptorDestinationDataAddressRegister = new DoubleWordRegister(parent) 833 .WithValueField(0, 32, 834 writeCallback: (_, value) => descriptor.destinationAddress = (uint)value, 835 valueProviderCallback: _ => descriptor.destinationAddress, 836 name: "DSTADDR") 837 ; 838 DescriptorLinkStructureAddressRegister = new DoubleWordRegister(parent) 839 .WithEnumField<DoubleWordRegister, AddressingMode>(0, 1, FieldMode.Read, 840 valueProviderCallback: _ => descriptor.linkMode, 841 name: "LINKMODE") 842 .WithFlag(1, 843 writeCallback: (_, value) => descriptor.link = value, 844 valueProviderCallback: _ => descriptor.link, 845 name: "LINK") 846 .WithValueField(2, 30, 847 writeCallback: (_, value) => descriptor.linkAddress = (uint)value, 848 valueProviderCallback: _ => descriptor.linkAddress, 849 name: "LINKADDR") 850 ; 851 852 pullTimer = new LimitTimer(parent.machine.ClockSource, 1000000, null, $"pullTimer-{Index}", 15, Direction.Ascending, false, WorkMode.Periodic, true, true); 853 pullTimer.LimitReached += delegate 854 { 855 if(!RequestDisable) 856 { 857 StartTransferInner(); 858 } 859 if(!SignalIsOn || !ShouldPullSignal) 860 { 861 pullTimer.Enabled = false; 862 } 863 }; 864 } 865 StartFromSignal()866 public void StartFromSignal() 867 { 868 if(!RequestDisable) 869 { 870 StartTransfer(); 871 } 872 } 873 LinkLoad()874 public void LinkLoad() 875 { 876 LoadDescriptor(); 877 if(!RequestDisable && (descriptor.structureTransferRequest || SignalIsOn)) 878 { 879 StartTransfer(); 880 } 881 } 882 StartTransfer()883 public void StartTransfer() 884 { 885 if(ShouldPullSignal) 886 { 887 pullTimer.Enabled = true; 888 } 889 else 890 { 891 StartTransferInner(); 892 } 893 } 894 Reset()895 public void Reset() 896 { 897 descriptor = default(Descriptor); 898 pullTimer.Reset(); 899 DoneInterrupt = false; 900 DoneInterruptEnable = false; 901 descriptorAddress = null; 902 requestDisable = false; 903 enabled = false; 904 done = false; 905 } 906 907 public int Index { get; } 908 909 public SignalSelect Signal => signalSelect.Value; 910 public SourceSelect Source => sourceSelect.Value; 911 public bool IgnoreSingleRequests => descriptor.ignoreSingleRequests; 912 public bool DoneInterrupt { get; set; } 913 public bool DoneInterruptEnable { get; set; } 914 public bool IRQ => DoneInterrupt && DoneInterruptEnable; 915 916 public DoubleWordRegister PeripheralRequestSelectRegister { get; } 917 public DoubleWordRegister ConfigurationRegister { get; } 918 public DoubleWordRegister LoopCounterRegister { get; } 919 public DoubleWordRegister DescriptorControlWordRegister { get; } 920 public DoubleWordRegister DescriptorSourceDataAddressRegister { get; } 921 public DoubleWordRegister DescriptorDestinationDataAddressRegister { get; } 922 public DoubleWordRegister DescriptorLinkStructureAddressRegister { get; } 923 924 public bool Enabled 925 { 926 get 927 { 928 return enabled; 929 } 930 set 931 { 932 if(enabled == value) 933 { 934 return; 935 } 936 enabled = value; 937 if(enabled) 938 { 939 Done = false; 940 StartTransfer(); 941 } 942 } 943 } 944 945 public bool Done 946 { 947 get 948 { 949 return done; 950 } 951 952 set 953 { 954 if (!done) 955 { 956 DoneInterrupt |= value && descriptor.operationDoneInterruptFlagSetEnable; 957 } 958 done = value; 959 } 960 } 961 962 public bool Busy 963 { 964 get 965 { 966 return isInProgress; 967 } 968 } 969 970 public bool RequestDisable 971 { 972 get 973 { 974 return requestDisable; 975 } 976 977 set 978 { 979 bool oldValue = requestDisable; 980 requestDisable = value; 981 982 if(oldValue && !value) 983 { 984 if(SignalIsOn) 985 { 986 StartTransfer(); 987 } 988 } 989 } 990 } 991 StartTransferInner()992 private void StartTransferInner() 993 { 994 if(isInProgress || Done) 995 { 996 return; 997 } 998 999 isInProgress = true; 1000 var loaded = false; 1001 do 1002 { 1003 loaded = false; 1004 Transfer(); 1005 if(Done && descriptor.link) 1006 { 1007 loaded = true; 1008 LoadDescriptor(); 1009 Done = false; 1010 } 1011 } 1012 while((descriptor.structureTransferRequest && loaded) || (!Done && SignalIsOn)); 1013 1014 isInProgress = false; 1015 if (Done) 1016 { 1017 pullTimer.Enabled = false; 1018 } 1019 } 1020 LoadDescriptor()1021 private void LoadDescriptor() 1022 { 1023 var address = LinkStructureAddress; 1024 if(descriptorAddress.HasValue && descriptor.linkMode == AddressingMode.Relative) 1025 { 1026 address += descriptorAddress.Value; 1027 } 1028 var data = parent.machine.SystemBus.ReadBytes(address, DescriptorSize); 1029 descriptorAddress = address; 1030 descriptor = Packet.Decode<Descriptor>(data); 1031 #if DEBUG 1032 parent.Log(LogLevel.Noisy, "Channel #{0} data {1}", Index, BitConverter.ToString(data)); 1033 parent.Log(LogLevel.Debug, "Channel #{0} Loaded {1}", Index, descriptor.PrettyString); 1034 #endif 1035 } 1036 Transfer()1037 private void Transfer() 1038 { 1039 switch(descriptor.structureType) 1040 { 1041 case StructureType.Transfer: 1042 var request = new Request( 1043 source: new Place(descriptor.sourceAddress), 1044 destination: new Place(descriptor.destinationAddress), 1045 size: Bytes, 1046 readTransferType: SizeAsTransferType, 1047 writeTransferType: SizeAsTransferType, 1048 sourceIncrementStep: SourceIncrement, 1049 destinationIncrementStep: DestinationIncrement 1050 ); 1051 parent.Log(LogLevel.Debug, "Channel #{0} Performing Transfer", Index); 1052 parent.engine.IssueCopy(request); 1053 if(descriptor.requestTransferModeSelect == RequestTransferMode.Block) 1054 { 1055 var blockSizeMultiplier = Math.Min(TransferCount, BlockSizeMultiplier); 1056 parent.Log(LogLevel.Debug, "Channel #{0} TransferCount={1} BlockSizeMultiplier={2}", Index, TransferCount, BlockSizeMultiplier); 1057 if(blockSizeMultiplier == TransferCount) 1058 { 1059 Done = true; 1060 descriptor.transferCount = 0; 1061 } 1062 else 1063 { 1064 descriptor.transferCount -= blockSizeMultiplier; 1065 } 1066 descriptor.sourceAddress += SourceIncrement * blockSizeMultiplier; 1067 descriptor.destinationAddress += DestinationIncrement * blockSizeMultiplier; 1068 } 1069 else 1070 { 1071 Done = true; 1072 } 1073 break; 1074 case StructureType.Synchronize: 1075 parent.Log(LogLevel.Warning, "Channel #{0} Synchronize is not implemented.", Index); 1076 break; 1077 case StructureType.Write: 1078 parent.Log(LogLevel.Warning, "Channel #{0} Write is not implemented.", Index); 1079 break; 1080 default: 1081 parent.Log(LogLevel.Error, "Channel #{0} Invalid structure type value. No action was performed.", Index); 1082 return; 1083 } 1084 parent.UpdateInterrupts(); 1085 } 1086 1087 private bool ShouldPullSignal 1088 { 1089 get 1090 { 1091 // if this returns true for the selected source and signal 1092 // then the signal will be periodically pulled instead of waiting 1093 // for an rising edge 1094 switch(Source) 1095 { 1096 case SourceSelect.None: 1097 return false; 1098 case SourceSelect.LDMAXBAR: 1099 switch(Signal) 1100 { 1101 case SignalSelect.LDMAXBAR_DMA_PRSREQ0: 1102 case SignalSelect.LDMAXBAR_DMA_PRSREQ1: 1103 return false; 1104 default: 1105 goto default; 1106 } 1107 case SourceSelect.IADC0: 1108 switch(Signal) 1109 { 1110 case SignalSelect.IADC0_DMA_IADC_SCAN: 1111 case SignalSelect.IADC0_DMA_IADC_SINGLE: 1112 return false; 1113 default: 1114 goto default; 1115 } 1116 case SourceSelect.USART0: 1117 case SourceSelect.USART1: 1118 switch(Signal) 1119 { 1120 case SignalSelect.USART0_DMA_RXDATAV: 1121 return false; 1122 case SignalSelect.USART0_DMA_TXBL: 1123 case SignalSelect.USART0_DMA_TXEMPTY: 1124 return true; 1125 default: 1126 goto default; 1127 } 1128 case SourceSelect.EUART0: 1129 switch(Signal) 1130 { 1131 case SignalSelect.EUART0_DMA_RXFL: 1132 return false; 1133 case SignalSelect.EUART0_DMA_TXFL: 1134 return true; 1135 default: 1136 goto default; 1137 } 1138 case SourceSelect.I2C0: 1139 case SourceSelect.I2C1: 1140 switch(Signal) 1141 { 1142 case SignalSelect.I2C0_DMA_RXDATAV: 1143 return false; 1144 case SignalSelect.I2C0_DMA_TXBL: 1145 return true; 1146 default: 1147 goto default; 1148 } 1149 case SourceSelect.TIMER0: 1150 case SourceSelect.TIMER1: 1151 case SourceSelect.TIMER2: 1152 case SourceSelect.TIMER3: 1153 case SourceSelect.TIMER4: 1154 switch(Signal) 1155 { 1156 case SignalSelect.TIMER0_DMA_CC0: 1157 case SignalSelect.TIMER0_DMA_CC1: 1158 case SignalSelect.TIMER0_DMA_CC2: 1159 case SignalSelect.TIMER0_DMA_UFOF: 1160 return false; 1161 default: 1162 goto default; 1163 } 1164 case SourceSelect.MSC: 1165 switch(Signal) 1166 { 1167 case SignalSelect.MSC_DMA_WDATA: 1168 return false; 1169 default: 1170 goto default; 1171 } 1172 default: 1173 parent.Log(LogLevel.Error, "Channel #{0} Invalid Source (0x{1:X}) and Signal (0x{2:X}) pair.", Index, Source, Signal); 1174 return false; 1175 } 1176 } 1177 } 1178 1179 private uint BlockSizeMultiplier 1180 { 1181 get 1182 { 1183 switch(descriptor.blockSize) 1184 { 1185 case BlockSizeMode.Unit1: 1186 case BlockSizeMode.Unit2: 1187 return 1u << (byte)descriptor.blockSize; 1188 case BlockSizeMode.Unit3: 1189 return 3; 1190 case BlockSizeMode.Unit4: 1191 return 4; 1192 case BlockSizeMode.Unit6: 1193 return 6; 1194 case BlockSizeMode.Unit8: 1195 return 8; 1196 case BlockSizeMode.Unit16: 1197 return 16; 1198 case BlockSizeMode.Unit32: 1199 case BlockSizeMode.Unit64: 1200 case BlockSizeMode.Unit128: 1201 case BlockSizeMode.Unit256: 1202 case BlockSizeMode.Unit512: 1203 case BlockSizeMode.Unit1024: 1204 return 1u << ((byte)descriptor.blockSize - 4); 1205 case BlockSizeMode.All: 1206 return TransferCount; 1207 default: 1208 parent.Log(LogLevel.Warning, "Channel #{0} Invalid Block Size Mode value.", Index); 1209 return 0; 1210 } 1211 } 1212 } 1213 1214 private bool SignalIsOn 1215 { 1216 get 1217 { 1218 var number = ((int)Source << 4) | (int)Signal; 1219 return parent.signals.Contains(number) || (!IgnoreSingleRequests && parent.signals.Contains(number | 1 << 12)); 1220 } 1221 } 1222 1223 private uint TransferCount => (uint)descriptor.transferCount + 1; 1224 private ulong LinkStructureAddress => (ulong)descriptor.linkAddress << 2; 1225 1226 private uint SourceIncrement => descriptor.sourceIncrement == IncrementMode.None ? 0u : ((1u << (byte)descriptor.size) << (byte)descriptor.sourceIncrement); 1227 private uint DestinationIncrement => descriptor.destinationIncrement == IncrementMode.None ? 0u : ((1u << (byte)descriptor.size) << (byte)descriptor.destinationIncrement); 1228 private TransferType SizeAsTransferType => (TransferType)(1 << (byte)descriptor.size); 1229 private int Bytes => (int)(descriptor.requestTransferModeSelect == RequestTransferMode.All ? TransferCount : Math.Min(TransferCount, BlockSizeMultiplier)) << (byte)descriptor.size; 1230 1231 private Descriptor descriptor; 1232 private ulong? descriptorAddress; 1233 private bool requestDisable; 1234 private bool enabled; 1235 private bool done; 1236 1237 // Accesses to sysubs may cause changes in signals, but we should ignore those during active transaction 1238 private bool isInProgress; 1239 1240 private IEnumRegisterField<SignalSelect> signalSelect; 1241 private IEnumRegisterField<SourceSelect> sourceSelect; 1242 private IEnumRegisterField<ArbitrationSlotNumberMode> arbitrationSlotNumberSelect; 1243 private IEnumRegisterField<Sign> sourceAddressIncrementSign; 1244 private IEnumRegisterField<Sign> destinationAddressIncrementSign; 1245 private IValueRegisterField loopCounter; 1246 1247 private readonly EFR32xG22_LDMA parent; 1248 private readonly LimitTimer pullTimer; 1249 1250 protected readonly int DescriptorSize = Packet.CalculateLength<Descriptor>(); 1251 1252 private enum ArbitrationSlotNumberMode 1253 { 1254 One = 0, 1255 Two = 1, 1256 Four = 2, 1257 Eight = 3, 1258 } 1259 1260 private enum Sign 1261 { 1262 Positive = 0, 1263 Negative = 1, 1264 } 1265 1266 protected enum StructureType : uint 1267 { 1268 Transfer = 0, 1269 Synchronize = 1, 1270 Write = 2, 1271 } 1272 1273 protected enum BlockSizeMode : uint 1274 { 1275 Unit1 = 0, 1276 Unit2 = 1, 1277 Unit3 = 2, 1278 Unit4 = 3, 1279 Unit6 = 4, 1280 Unit8 = 5, 1281 Unit16 = 7, 1282 Unit32 = 9, 1283 Unit64 = 10, 1284 Unit128 = 11, 1285 Unit256 = 12, 1286 Unit512 = 13, 1287 Unit1024 = 14, 1288 All = 15, 1289 } 1290 1291 protected enum RequestTransferMode : uint 1292 { 1293 Block = 0, 1294 All = 1, 1295 } 1296 1297 protected enum IncrementMode : uint 1298 { 1299 One = 0, 1300 Two = 1, 1301 Four = 2, 1302 None = 3, 1303 } 1304 1305 protected enum SizeMode : uint 1306 { 1307 Byte = 0, 1308 HalfWord = 1, 1309 Word = 2, 1310 } 1311 1312 protected enum AddressingMode : uint 1313 { 1314 Absolute = 0, 1315 Relative = 1, 1316 } 1317 1318 [LeastSignificantByteFirst] 1319 private struct Descriptor 1320 { 1321 public string PrettyString => $@"Descriptor {{ 1322 structureType: {structureType}, 1323 structureTransferRequest: {structureTransferRequest}, 1324 transferCount: {transferCount + 1}, 1325 byteSwap: {byteSwap}, 1326 blockSize: {blockSize}, 1327 operationDoneInterruptFlagSetEnable: {operationDoneInterruptFlagSetEnable}, 1328 requestTransferModeSelect: {requestTransferModeSelect}, 1329 decrementLoopCount: {decrementLoopCount}, 1330 ignoreSingleRequests: {ignoreSingleRequests}, 1331 sourceIncrement: {sourceIncrement}, 1332 size: {size}, 1333 destinationIncrement: {destinationIncrement}, 1334 sourceAddressingMode: {sourceAddressingMode}, 1335 destinationAddressingMode: {destinationAddressingMode}, 1336 sourceAddress: 0x{sourceAddress:X}, 1337 destinationAddress: 0x{destinationAddress:X}, 1338 linkMode: {linkMode}, 1339 link: {link}, 1340 linkAddress: 0x{(linkAddress << 2):X} 1341 }}"; 1342 1343 // Some of this fields are read only via sysbus, but can be loaded from memory 1344 #pragma warning disable 649 1345 [PacketField, Offset(bytes: 0 << 2, bits: 0), Width(2)] 1346 public StructureType structureType; 1347 [PacketField, Offset(bytes: 0 << 2, bits: 3), Width(1)] 1348 public bool structureTransferRequest; 1349 [PacketField, Offset(bytes: 0 << 2, bits: 4), Width(11)] 1350 public uint transferCount; 1351 [PacketField, Offset(bytes: 0 << 2, bits: 15), Width(1)] 1352 public bool byteSwap; 1353 [PacketField, Offset(bytes: 0 << 2, bits: 16), Width(4)] 1354 public BlockSizeMode blockSize; 1355 [PacketField, Offset(bytes: 0 << 2, bits: 20), Width(1)] 1356 public bool operationDoneInterruptFlagSetEnable; 1357 [PacketField, Offset(bytes: 0 << 2, bits: 21), Width(1)] 1358 public RequestTransferMode requestTransferModeSelect; 1359 [PacketField, Offset(bytes: 0 << 2, bits: 22), Width(1)] 1360 public bool decrementLoopCount; 1361 [PacketField, Offset(bytes: 0 << 2, bits: 23), Width(1)] 1362 public bool ignoreSingleRequests; 1363 [PacketField, Offset(bytes: 0 << 2, bits: 24), Width(2)] 1364 public IncrementMode sourceIncrement; 1365 [PacketField, Offset(bytes: 0 << 2, bits: 26), Width(2)] 1366 public SizeMode size; 1367 [PacketField, Offset(bytes: 0 << 2, bits: 28), Width(2)] 1368 public IncrementMode destinationIncrement; 1369 [PacketField, Offset(bytes: 0 << 2, bits: 30), Width(1)] 1370 public AddressingMode sourceAddressingMode; 1371 [PacketField, Offset(bytes: 0 << 2, bits: 31), Width(1)] 1372 public AddressingMode destinationAddressingMode; 1373 [PacketField, Offset(bytes: 1 << 2, bits: 0), Width(32)] 1374 public uint sourceAddress; 1375 [PacketField, Offset(bytes: 2 << 2, bits: 0), Width(32)] 1376 public uint destinationAddress; 1377 [PacketField, Offset(bytes: 3 << 2, bits: 0), Width(1)] 1378 public AddressingMode linkMode; 1379 [PacketField, Offset(bytes: 3 << 2, bits: 1), Width(1)] 1380 public bool link; 1381 [PacketField, Offset(bytes: 3 << 2, bits: 2), Width(30)] 1382 public uint linkAddress; 1383 #pragma warning restore 649 1384 } 1385 } 1386 } 1387 }