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