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.Threading; 14 using System.Threading.Tasks; 15 16 17 namespace Antmicro.Renode.Peripherals.DMA 18 { 19 public class VybridDma : IDoubleWordPeripheral, IWordPeripheral, IBytePeripheral 20 { VybridDma(Machine mach)21 public VybridDma(Machine mach) 22 { 23 machine = mach; 24 engine = new DmaEngine(machine.GetSystemBus(this)); 25 26 channels = new Channel[32]; 27 for (var i = 0; i < 32; i++) 28 { 29 channels[i] = new Channel(this, i); 30 } 31 32 IRQ = new GPIO(); 33 } 34 ReadWord(long offset)35 public ushort ReadWord(long offset) 36 { 37 this.LogUnhandledRead(offset); 38 return 0; 39 } 40 WriteWord(long offset, ushort value)41 public void WriteWord(long offset, ushort value) 42 { 43 if (offset < 0x1000) { 44 this.LogUnhandledWrite(offset, value); 45 return; 46 } 47 uint channel = (uint)((offset - 0x1000) / 0x20); 48 var operation = (offset - 0x1000) - (channel * 0x20); 49 if (channel > 31) { 50 this.Log(LogLevel.Error, "Channel is greater than 31"); 51 return; 52 } 53 channels[channel].WriteWord(operation, value); 54 UpdateIRQ(); 55 } 56 ReadByte(long offset)57 public byte ReadByte(long offset) 58 { 59 this.LogUnhandledRead(offset); 60 return 0; 61 } 62 WriteByte(long offset, byte value)63 public void WriteByte(long offset, byte value) 64 { 65 switch((Register)offset) 66 { 67 case Register.SetEnableRequest: 68 EnableRequestRegister |= (uint)(1<<value); 69 DoCopy(); 70 break; 71 case Register.ClearInterruptRequest: 72 InterruptRequestRegister &= (uint)~(1<<value); 73 break; 74 case Register.ClearEnableRequest: 75 EnableRequestRegister &= (uint)~(1<<value); 76 break; 77 default: 78 this.LogUnhandledWrite(offset, value); 79 break; 80 } 81 UpdateIRQ(); 82 } 83 ReadDoubleWord(long address)84 public uint ReadDoubleWord(long address) 85 { 86 if (address < 0x1000) { 87 switch ((Register)address) 88 { 89 case Register.InterruptRequest: 90 return InterruptRequestRegister; 91 } 92 } 93 this.LogUnhandledRead(address); 94 return 0; 95 } 96 WriteDoubleWord(long address, uint value)97 public void WriteDoubleWord(long address, uint value) 98 { 99 if (address < 0x1000) { 100 switch ((Register)address) 101 { 102 default: 103 this.LogUnhandledWrite(address, value); 104 break; 105 } 106 return; 107 } 108 109 var channel = (address - 0x1000) / 0x20; 110 var operation = (address - 0x1000) - (channel * 0x20); 111 112 if (channel > 31) { 113 this.Log(LogLevel.Error, "Channel is greater than 31"); 114 return; 115 } 116 117 channels[channel].WriteDoubleWord(operation, value); 118 UpdateIRQ(); 119 } 120 DoCopy()121 public bool DoCopy() 122 { 123 bool res = false; 124 if (EnableRequestRegister == 0) return false; 125 for (int i = 0; i < 32; i++) { 126 if ((EnableRequestRegister & (1 << i)) == 0) continue; 127 var channel = channels[i]; 128 if (!channel.DoCopy()) continue; 129 res = true; 130 131 // TODO: also move those to channel.DoCopy() ? 132 if ((channel.TCD_ControlAndStatus & (1u << 3)) != 0) 133 { 134 EnableRequestRegister &= ~(1u << channel.channelNumber); 135 } 136 137 if ((channel.TCD_ControlAndStatus & (1u << 1)) != 0) 138 { 139 InterruptRequestRegister |= (1u << channel.channelNumber); 140 } 141 } 142 if (res) UpdateIRQ(); 143 return res; 144 } 145 Reset()146 public void Reset() 147 { 148 InterruptRequestRegister = 0; 149 UpdateIRQ(); 150 } 151 UpdateIRQ()152 private void UpdateIRQ() { 153 if (InterruptRequestRegister != 0) { 154 this.NoisyLog("IRQ is on, val = {0:X},enable={1:X}", InterruptRequestRegister, EnableRequestRegister); 155 IRQ.Set(); 156 } else { 157 IRQ.Unset(); 158 } 159 } 160 161 //private uint EnableErrorInterruptRegister; 162 private uint EnableRequestRegister; 163 private uint InterruptRequestRegister; 164 //private uint HardwareRequestStatusRegister; 165 //private uint ControlRegister; 166 //private uint ErrorRegister; 167 168 private readonly IMachine machine; 169 private readonly DmaEngine engine; 170 171 public GPIO IRQ { get; private set; } 172 173 private enum Register : long 174 { 175 Control = 0x00, 176 EnableErrorInterrupt = 0x14, 177 ClearEnableErrorInterupt = 0x18, 178 SetEnableErrorInterrupt = 0x19, 179 ClearEnableRequest = 0x1A, 180 SetEnableRequest = 0x1B, 181 ClearDONEStatusBit = 0x1C, 182 ClearError = 0x1E, 183 ClearInterruptRequest = 0x1F, 184 InterruptRequest = 0x24, 185 Error = 0x2C, 186 HardwareRequestStatus = 0x34, 187 } 188 189 private sealed class Channel 190 { Channel(VybridDma parent, int number)191 public Channel(VybridDma parent, int number) { 192 this.parent = parent; 193 channelNumber = number; 194 } 195 WriteDoubleWord(long offset, uint value)196 public void WriteDoubleWord(long offset, uint value) { 197 switch ((ChannelRegister)offset) { 198 case ChannelRegister.TCD_MinorByteCount: 199 TCD_MinorByteCount = value; 200 break; 201 case ChannelRegister.TCD_SourceAddress: 202 TCD_SourceAddress = value; 203 break; 204 case ChannelRegister.TCD_DestinationAddress: 205 TCD_DestinationAddress = value; 206 break; 207 default: 208 parent.Log(LogLevel.Noisy, "Unhandled DWORD write val=0x{2:X} offset 0x{0:X} on channel {1}",offset,channelNumber,value); 209 break; 210 } 211 } 212 WriteWord(long offset, ushort value)213 public void WriteWord(long offset, ushort value) { 214 switch((ChannelRegister)offset) { 215 case ChannelRegister.TCD_CurrentMajorLoopCount: 216 TCD_CurrentMajorLoopCount = value; 217 break; 218 case ChannelRegister.TCD_ControlAndStatus: 219 TCD_ControlAndStatus = value; 220 break; 221 default: 222 parent.Log(LogLevel.Noisy, "Unhandled WORD write val=0x{2:X} offset 0x{0:X} on channel {1}",offset,channelNumber,value); 223 break; 224 } 225 } 226 DoCopy()227 public bool DoCopy() { 228 if ((TCD_ControlAndStatus & (1u << 7)) > 0) return false; 229 uint size = (uint)(TCD_MinorByteCount * TCD_CurrentMajorLoopCount); 230 parent.Log(LogLevel.Noisy, "Channel {0} : copying data size {1} from 0x{2:X} to 0x{3:X}", channelNumber, size, TCD_SourceAddress, TCD_DestinationAddress); 231 if (size == 0) { 232 parent.Log(LogLevel.Error, "Error: size is 0 - stopping copy request (minor={0},major={1})", TCD_MinorByteCount, TCD_CurrentMajorLoopCount); 233 return false; 234 } 235 var request = new Request(TCD_SourceAddress, TCD_DestinationAddress, (int)size, TransferType.Byte, TransferType.Byte, incrementWriteAddress: false); 236 parent.engine.IssueCopy(request); 237 238 TCD_ControlAndStatus |= (1u << 7); 239 return true; 240 } 241 242 public readonly int channelNumber; 243 private readonly VybridDma parent; 244 245 uint TCD_SourceAddress; 246 //uint TCD_SignedSourceAddressOffset; 247 //uint TCD_TransferAttributes; 248 uint TCD_MinorByteCount; 249 //uint TCD_LastSourceAddressAdjustment; 250 uint TCD_DestinationAddress; 251 //uint TCD_SignedDestinationAddressOffset; 252 uint TCD_CurrentMajorLoopCount; 253 //uint TCD_LastDestinationAddressAdjustment; 254 public uint TCD_ControlAndStatus; 255 256 private enum ChannelRegister : long 257 { 258 TCD_SourceAddress = 0x00, 259 TCD_SignedSourceAddressOffset = 0x04, 260 TCD_TransferAttributes = 0x06, 261 TCD_MinorByteCount = 0x08, 262 TCD_LastSourceAddressAdjustment = 0x0C, 263 TCD_DestinationAddress = 0x10, 264 TCD_SignedDestinationAddressOffset = 0x14, 265 TCD_CurrentMajorLoopCount = 0x16, 266 TCD_LastDestinationAddressAdjustment = 0x18, 267 TCD_ControlAndStatus = 0x1C, 268 } 269 } 270 271 private readonly Channel[] channels; 272 } 273 } 274 275