1 // 2 // Copyright (c) 2010-2023 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System.Collections.Generic; 8 using System.Collections.ObjectModel; 9 using Antmicro.Renode.Core; 10 using Antmicro.Renode.Core.Structure.Registers; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Peripherals.Bus; 13 14 namespace Antmicro.Renode.Peripherals.DMA 15 { 16 [AllowedTranslations(AllowedTranslation.QuadWordToDoubleWord)] 17 public class MPFS_PDMA : IKnownSize, IDoubleWordPeripheral, INumberedGPIOOutput 18 { MPFS_PDMA(IMachine machine)19 public MPFS_PDMA(IMachine machine) 20 { 21 this.machine = machine; 22 dmaEngine = new DmaEngine(this.machine.GetSystemBus(this)); 23 channels = new Channel[ChannelCount]; 24 25 var irqCounter = 0; 26 var innerConnections = new Dictionary<int, IGPIO>(); 27 for(var i = 0; i < ChannelCount; ++i) 28 { 29 channels[i] = new Channel(this, i); 30 innerConnections[irqCounter++] = channels[i].DoneInterrupt; 31 innerConnections[irqCounter++] = channels[i].ErrorInterrupt; 32 } 33 Connections = new ReadOnlyDictionary<int, IGPIO>(innerConnections); 34 Reset(); 35 } 36 Reset()37 public void Reset() 38 { 39 for(var i = 0; i < ChannelCount; ++i) 40 { 41 channels[i].Reset(); 42 } 43 } 44 ReadDoubleWord(long offset)45 public uint ReadDoubleWord(long offset) 46 { 47 var channelNumber = offset / ShiftBetweenChannels; 48 if(channelNumber >= ChannelCount) 49 { 50 this.Log(LogLevel.Error, "Trying to read from nonexistent channel"); 51 return 0; 52 } 53 return channels[channelNumber].ReadDoubleWord(offset); 54 } 55 WriteDoubleWord(long offset, uint value)56 public void WriteDoubleWord(long offset, uint value) 57 { 58 var channelNumber = offset / ShiftBetweenChannels; 59 if(channelNumber >= ChannelCount) 60 { 61 this.Log(LogLevel.Error, "Trying to write to nonexistent channel"); 62 return; 63 } 64 channels[channelNumber].WriteDoubleWord(offset, value); 65 } 66 67 public IReadOnlyDictionary<int, IGPIO> Connections { get; } 68 public long Size => 0x4000; 69 70 private readonly IMachine machine; 71 private readonly DmaEngine dmaEngine; 72 private readonly Channel[] channels; 73 74 private const int ChannelCount = 4; 75 private const int ShiftBetweenChannels = 0x1000; 76 77 private class Channel : IDoubleWordPeripheral 78 { Channel(MPFS_PDMA parent, int number)79 public Channel(MPFS_PDMA parent, int number) 80 { 81 this.parent = parent; 82 channelNumber = number; 83 DoneInterrupt = new GPIO(); 84 ErrorInterrupt = new GPIO(); 85 86 var registersMap = new Dictionary<long, DoubleWordRegister>(); 87 registersMap.Add( 88 (long)ChannelRegisters.Control + ShiftBetweenChannels * channelNumber, 89 new DoubleWordRegister(this) 90 .WithFlag(0, 91 writeCallback: (_, val) => 92 { 93 if(!val && !isRun) 94 { 95 isClaimed = false; 96 } 97 if(val && !isRun) 98 { 99 if(!isClaimed) 100 { 101 nextBytesLow.Value = 0; 102 nextBytesHigh.Value = 0; 103 nextSourceLow.Value = 0; 104 nextSourceHigh.Value = 0; 105 nextDestinationLow.Value = 0; 106 nextDestinationHigh.Value = 0; 107 } 108 isClaimed = true; 109 } 110 }, 111 valueProviderCallback: _ => 112 { 113 return isClaimed; 114 }, name: "claim") 115 .WithFlag(1, 116 writeCallback: (_, val) => 117 { 118 if(val) 119 { 120 isRun = true; 121 do 122 { 123 InitTransfer(); 124 } while(repeat.Value); 125 } 126 }, 127 valueProviderCallback: _ => 128 { 129 return isRun; 130 }, name: "run") 131 .WithReservedBits(2, 12) 132 .WithFlag(14, out doneInterruptEnabled, 133 writeCallback: (_, val) => 134 { 135 if(!val) 136 { 137 DoneInterrupt.Unset(); 138 } 139 }, name: "doneIE") 140 .WithTag("errorIE", 15, 1) 141 .WithReservedBits(16, 14) 142 .WithFlag(30, out isDone, name: "done") 143 .WithTag("error", 31, 1) 144 ); 145 146 // NEXT registers 147 nextConfigRegister = new DoubleWordRegister(this) 148 .WithReservedBits(0, 1) 149 .WithFlag(2, out repeat, name: "repeat") 150 .WithTag("order", 3, 1) 151 .WithReservedBits(4, 20) 152 .WithValueField(24, 4, out wsize, name: "wsize") 153 .WithValueField(28, 4, out rsize, name: "rsize"); 154 registersMap.Add( 155 (long)ChannelRegisters.NextConfig + ShiftBetweenChannels * channelNumber, 156 nextConfigRegister 157 ); 158 registersMap.Add( 159 (long)ChannelRegisters.NextBytesLow + ShiftBetweenChannels * channelNumber, 160 new DoubleWordRegister(this) 161 .WithValueField(0, 32, out nextBytesLow) 162 ); 163 registersMap.Add( 164 (long)ChannelRegisters.NextBytesHigh + ShiftBetweenChannels * channelNumber, 165 new DoubleWordRegister(this) 166 .WithValueField(0, 32, out nextBytesHigh) 167 ); 168 registersMap.Add( 169 (long)ChannelRegisters.NextDestinationLow + ShiftBetweenChannels * channelNumber, 170 new DoubleWordRegister(this) 171 .WithValueField(0, 32, out nextDestinationLow) 172 ); 173 registersMap.Add( 174 (long)ChannelRegisters.NextDestinationHigh + ShiftBetweenChannels * channelNumber, 175 new DoubleWordRegister(this) 176 .WithValueField(0, 32, out nextDestinationHigh) 177 ); 178 registersMap.Add( 179 (long)ChannelRegisters.NextSourceLow + ShiftBetweenChannels * channelNumber, 180 new DoubleWordRegister(this) 181 .WithValueField(0, 32, out nextSourceLow) 182 ); 183 registersMap.Add( 184 (long)ChannelRegisters.NextSourceHigh + ShiftBetweenChannels * channelNumber, 185 new DoubleWordRegister(this) 186 .WithValueField(0, 32, out nextSourceHigh) 187 ); 188 189 // EXEC registers 190 execConfig = new DoubleWordRegister(this).WithValueField(0, 32, FieldMode.Read); 191 registersMap.Add( 192 (long)ChannelRegisters.ExecConfig + ShiftBetweenChannels * channelNumber, 193 execConfig 194 ); 195 execBytesLow = new DoubleWordRegister(this).WithValueField(0, 32, FieldMode.Read); 196 registersMap.Add( 197 (long)ChannelRegisters.ExecBytesLow + ShiftBetweenChannels * channelNumber, 198 execBytesLow 199 ); 200 execBytesHigh = new DoubleWordRegister(this).WithValueField(0, 32, FieldMode.Read); 201 registersMap.Add( 202 (long)ChannelRegisters.ExecBytesHigh + ShiftBetweenChannels * channelNumber, 203 execBytesHigh 204 ); 205 execDestinationLow = new DoubleWordRegister(this).WithValueField(0, 32, FieldMode.Read); 206 registersMap.Add( 207 (long)ChannelRegisters.ExecDestinationLow + ShiftBetweenChannels * channelNumber, 208 execDestinationLow 209 ); 210 execDestinationHigh = new DoubleWordRegister(this).WithValueField(0, 32, FieldMode.Read); 211 registersMap.Add( 212 (long)ChannelRegisters.ExecDestinationHigh + ShiftBetweenChannels * channelNumber, 213 execDestinationHigh 214 ); 215 execSourceLow = new DoubleWordRegister(this).WithValueField(0, 32, FieldMode.Read); 216 registersMap.Add( 217 (long)ChannelRegisters.ExecSourceLow + ShiftBetweenChannels * channelNumber, 218 execSourceLow 219 ); 220 execSourceHigh = new DoubleWordRegister(this).WithValueField(0, 32, FieldMode.Read); 221 registersMap.Add( 222 (long)ChannelRegisters.ExecSourceHigh + ShiftBetweenChannels * channelNumber, 223 execSourceHigh 224 ); 225 registers = new DoubleWordRegisterCollection(this, registersMap); 226 } 227 ReadDoubleWord(long offset)228 public uint ReadDoubleWord(long offset) 229 { 230 return registers.Read(offset); 231 } 232 WriteDoubleWord(long offset, uint value)233 public void WriteDoubleWord(long offset, uint value) 234 { 235 registers.Write(offset, value); 236 } 237 Reset()238 public void Reset() 239 { 240 registers.Reset(); 241 DoneInterrupt.Unset(); 242 ErrorInterrupt.Unset(); 243 isClaimed = false; 244 isRun = false; 245 } 246 247 public GPIO DoneInterrupt { get; private set; } 248 public GPIO ErrorInterrupt { get; private set; } 249 InitTransfer()250 private void InitTransfer() 251 { 252 execConfig.Write(0, nextConfigRegister.Value); 253 execBytesLow.Write(0, (uint)nextBytesLow.Value); 254 execBytesHigh.Write(0, (uint)nextBytesHigh.Value); 255 execSourceLow.Write(0, (uint)nextSourceLow.Value); 256 execSourceHigh.Write(0, (uint)nextSourceHigh.Value); 257 execDestinationLow.Write(0, (uint)nextDestinationLow.Value); 258 execDestinationHigh.Write(0, (uint)nextDestinationHigh.Value); 259 260 ulong sourceAddress = nextSourceHigh.Value; 261 sourceAddress = sourceAddress << 32; 262 sourceAddress = sourceAddress + nextSourceLow.Value; 263 264 ulong destinationAddress = nextDestinationHigh.Value; 265 destinationAddress = destinationAddress << 32; 266 destinationAddress = destinationAddress + nextDestinationLow.Value; 267 268 ulong size = nextBytesHigh.Value; 269 size = size << 32; 270 size = size + nextBytesLow.Value; 271 272 parent.machine.LocalTimeSource.ExecuteInNearestSyncedState(_ => 273 { 274 IssueCopy(sourceAddress, destinationAddress, size); 275 FinishTransfer(sourceAddress, destinationAddress, size); 276 }); 277 } 278 IssueCopy(ulong sourceAddress, ulong destinationAddress, ulong size)279 private void IssueCopy(ulong sourceAddress, ulong destinationAddress, ulong size) 280 { 281 var dataLeft = size; 282 while(dataLeft > 0) 283 { 284 var partSize = int.MaxValue; 285 if(dataLeft <= int.MaxValue) 286 { 287 partSize = (int)dataLeft; 288 } 289 290 var request = new Request( 291 sourceAddress, 292 destinationAddress, 293 partSize, 294 GetTransactionSize(TransactionDirection.Read, rsize.Value), 295 GetTransactionSize(TransactionDirection.Write, wsize.Value) 296 ); 297 parent.dmaEngine.IssueCopy(request); 298 sourceAddress += (ulong)partSize; 299 destinationAddress += (ulong)partSize; 300 dataLeft -= (ulong)partSize; 301 } 302 } 303 FinishTransfer(ulong sourceAddress, ulong destinationAddress, ulong size)304 private void FinishTransfer(ulong sourceAddress, ulong destinationAddress, ulong size) 305 { 306 execBytesLow.Write(0, 0); 307 execBytesHigh.Write(0, 0); 308 var execSource = sourceAddress + size; 309 execSourceLow.Write(0, (uint)execSource); 310 execSourceHigh.Write(0, (uint)(execSource >> 32)); 311 var execDestination = destinationAddress + size; 312 execDestinationLow.Write(0, (uint)execDestination); 313 execDestinationHigh.Write(0, (uint)(execDestination >> 32)); 314 315 isClaimed = false; 316 isDone.Value = true; 317 isRun = false; 318 if(doneInterruptEnabled.Value) 319 { 320 DoneInterrupt.Set(); 321 } 322 } 323 GetTransactionSize(TransactionDirection direction, ulong val)324 private TransferType GetTransactionSize(TransactionDirection direction, ulong val) 325 { 326 TransferType type; 327 switch(val) 328 { 329 case 0: 330 type = TransferType.Byte; 331 break; 332 case 1: 333 type = TransferType.Word; 334 break; 335 case 2: 336 type = TransferType.DoubleWord; 337 break; 338 default: 339 type = TransferType.DoubleWord; 340 this.Log(LogLevel.Warning, "{0} transaction size has been truncated to 4 bytes.", direction); 341 break; 342 } 343 return type; 344 } 345 346 private DoubleWordRegister nextConfigRegister; 347 private DoubleWordRegister execConfig; 348 private DoubleWordRegister execBytesLow; 349 private DoubleWordRegister execBytesHigh; 350 private DoubleWordRegister execDestinationLow; 351 private DoubleWordRegister execDestinationHigh; 352 private DoubleWordRegister execSourceLow; 353 private DoubleWordRegister execSourceHigh; 354 private bool isClaimed; 355 private bool isRun; 356 private IFlagRegisterField isDone; 357 private IValueRegisterField wsize; 358 private IValueRegisterField rsize; 359 private IFlagRegisterField repeat; 360 private IValueRegisterField nextBytesLow; 361 private IValueRegisterField nextBytesHigh; 362 private IValueRegisterField nextDestinationLow; 363 private IValueRegisterField nextDestinationHigh; 364 private IValueRegisterField nextSourceLow; 365 private IValueRegisterField nextSourceHigh; 366 367 private readonly IFlagRegisterField doneInterruptEnabled; 368 private readonly DoubleWordRegisterCollection registers; 369 private readonly MPFS_PDMA parent; 370 private readonly int channelNumber; 371 372 private enum TransactionDirection 373 { 374 Read, 375 Write 376 } 377 378 private enum ChannelRegisters 379 { 380 Control = 0x000, 381 NextConfig = 0x004, 382 NextBytesLow = 0x008, 383 NextBytesHigh = 0x00C, 384 NextDestinationLow = 0x010, 385 NextDestinationHigh = 0x014, 386 NextSourceLow = 0x018, 387 NextSourceHigh = 0x01C, 388 ExecConfig = 0x104, 389 ExecBytesLow = 0x108, 390 ExecBytesHigh = 0x10C, 391 ExecDestinationLow = 0x110, 392 ExecDestinationHigh = 0x114, 393 ExecSourceLow = 0x118, 394 ExecSourceHigh = 0x11C, 395 } 396 } 397 } 398 }