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 8 using System; 9 using System.Linq; 10 11 using Antmicro.Renode.Core; 12 using Antmicro.Renode.Core.Structure; 13 using Antmicro.Renode.Core.Structure.Registers; 14 15 using Antmicro.Renode.Peripherals.Bus; 16 17 using Antmicro.Renode.Utilities; 18 using Antmicro.Renode.Logging; 19 20 namespace Antmicro.Renode.Peripherals.SD 21 { 22 public class LiteSDCard : NullRegistrationPointPeripheralContainer<SDCard>, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IDoubleWordPeripheral, IKnownSize 23 { LiteSDCard(IMachine machine)24 public LiteSDCard(IMachine machine) : base(machine) 25 { 26 sysbus = machine.GetSystemBus(this); 27 phyRegistersCollection = new DoubleWordRegisterCollection(this); 28 coreRegistersCollection = new DoubleWordRegisterCollection(this); 29 readerRegistersCollection = new DoubleWordRegisterCollection(this); 30 writerRegistersCollection = new DoubleWordRegisterCollection(this); 31 32 DefineRegisters(); 33 34 responseBuffer = new byte[ResponseBufferLength]; 35 } 36 Reset()37 public override void Reset() 38 { 39 phyRegistersCollection.Reset(); 40 coreRegistersCollection.Reset(); 41 readerRegistersCollection.Reset(); 42 writerRegistersCollection.Reset(); 43 44 argumentValue = 0; 45 blockSize = 0; 46 blockCount = 0; 47 48 readerAddress = 0; 49 writerAddress = 0; 50 51 readerLength = 0; 52 writerLength = 0; 53 54 Array.Clear(responseBuffer, 0, responseBuffer.Length); 55 } 56 ReadDoubleWord(long offset)57 public uint ReadDoubleWord(long offset) 58 { 59 return phyRegistersCollection.Read(offset); 60 } 61 WriteDoubleWord(long offset, uint value)62 public void WriteDoubleWord(long offset, uint value) 63 { 64 phyRegistersCollection.Write(offset, value); 65 } 66 67 [ConnectionRegionAttribute("core")] ReadDoubleWordFromCore(long offset)68 public uint ReadDoubleWordFromCore(long offset) 69 { 70 return coreRegistersCollection.Read(offset); 71 } 72 73 [ConnectionRegionAttribute("core")] WriteDoubleWordToCore(long offset, uint value)74 public void WriteDoubleWordToCore(long offset, uint value) 75 { 76 coreRegistersCollection.Write(offset, value); 77 } 78 79 [ConnectionRegionAttribute("reader")] ReadDoubleWordFromReader(long offset)80 public uint ReadDoubleWordFromReader(long offset) 81 { 82 return readerRegistersCollection.Read(offset); 83 } 84 85 [ConnectionRegionAttribute("reader")] WriteDoubleWordToReader(long offset, uint value)86 public void WriteDoubleWordToReader(long offset, uint value) 87 { 88 readerRegistersCollection.Write(offset, value); 89 } 90 91 [ConnectionRegionAttribute("writer")] ReadDoubleWordFromWriter(long offset)92 public uint ReadDoubleWordFromWriter(long offset) 93 { 94 return writerRegistersCollection.Read(offset); 95 } 96 97 [ConnectionRegionAttribute("writer")] WriteDoubleWordToWriter(long offset, uint value)98 public void WriteDoubleWordToWriter(long offset, uint value) 99 { 100 writerRegistersCollection.Write(offset, value); 101 } 102 103 public long Size => 0x200; 104 105 public DoubleWordRegisterCollection RegistersCollection => phyRegistersCollection; 106 DefineRegisters()107 private void DefineRegisters() 108 { 109 PhyRegisters.CardDetect.Define(this) 110 // note: `true` means *no* card 111 .WithFlag(0, FieldMode.Read, name: "card_detect", valueProviderCallback: _ => RegisteredPeripheral == null) 112 .WithReservedBits(1, 31); 113 114 CoreRegisters.Argument.DefineMany(coreRegistersCollection, 4, (register, idx) => 115 { 116 register 117 .WithValueField(0, 8, name: $"argument{idx}", 118 writeCallback: (_, val) => 119 { 120 BitHelper.ReplaceBits(ref argumentValue, width: 8, source: (uint)val, destinationPosition: 24 - idx * 8); 121 }, 122 valueProviderCallback: _ => BitHelper.GetValue(argumentValue, offset: 24 - idx * 8, size: 8)) 123 .WithIgnoredBits(8, 24); 124 }); 125 126 CoreRegisters.Command0.Define(coreRegistersCollection) 127 .WithIgnoredBits(0, 32); 128 129 CoreRegisters.Command1.Define(coreRegistersCollection) 130 .WithIgnoredBits(0, 32); 131 132 CoreRegisters.Command2.Define(coreRegistersCollection) 133 .WithValueField(0, 7, out commandIndexField, name: "command_index") 134 .WithReservedBits(7, 1) 135 .WithIgnoredBits(8, 24); 136 137 CoreRegisters.Command3.Define(coreRegistersCollection) 138 .WithEnumField<DoubleWordRegister, ResponseType>(0, 3, out responseTypeField, name: "respone_type") 139 .WithReservedBits(3, 2) 140 .WithEnumField<DoubleWordRegister, TransferType>(5, 3, out transferTypeField, name: "transfer_type") 141 .WithIgnoredBits(8, 24); 142 143 CoreRegisters.IssueCommand.Define(coreRegistersCollection) 144 .WithFlag(0, FieldMode.WriteOneToClear, name: "issue_command", writeCallback: (_, val) => 145 { 146 if(!val) 147 { 148 // we are only interested in `true` 149 return; 150 } 151 152 if(RegisteredPeripheral == null) 153 { 154 this.Log(LogLevel.Warning, "Issued a 0x{0:X} command with 0x{1:X} argument, but there is no SD card attached", commandIndexField.Value, argumentValue); 155 return; 156 } 157 158 this.Log(LogLevel.Noisy, "Issuing command #{0} with argument 0x{3:X}, transfer type is {1}, response type is {2}", commandIndexField.Value, transferTypeField.Value, responseTypeField.Value, argumentValue); 159 160 var resp = RegisteredPeripheral.HandleCommand((uint)commandIndexField.Value, argumentValue).AsByteArray(); 161 162 this.Log(LogLevel.Noisy, "Received response of size {0}", resp.Length); 163 #if DEBUG_PACKETS 164 this.Log(LogLevel.Noisy, Misc.PrettyPrintCollectionHex(resp)); 165 #endif 166 167 var expectedResponseLength = 0; 168 169 switch(responseTypeField.Value) 170 { 171 case ResponseType.Short: 172 expectedResponseLength = 4; 173 break; 174 175 case ResponseType.Long: 176 expectedResponseLength = 16; 177 break; 178 } 179 180 if(resp.Length != expectedResponseLength) 181 { 182 this.Log(LogLevel.Warning, "Expected response of length {0} bytes, but received {1} bytes", expectedResponseLength, resp.Length); 183 return; 184 } 185 186 for(var i = 0; i < resp.Length; i++) 187 { 188 responseBuffer[ResponseBufferLength - 1 - i] = resp[i]; 189 } 190 191 switch(transferTypeField.Value) 192 { 193 case TransferType.Read: 194 if(dmaReaderEnabled.Value) 195 { 196 ReadData(); 197 } 198 break; 199 200 case TransferType.Write: 201 if(dmaWriterEnabled.Value) 202 { 203 WriteData(); 204 } 205 break; 206 } 207 }) 208 .WithReservedBits(1, 7) 209 .WithReservedBits(8, 24); 210 211 CoreRegisters.Response.DefineMany(coreRegistersCollection, ResponseBufferLength, (register, idx) => 212 { 213 register 214 .WithValueField(0, 8, FieldMode.Read, name: $"Response{idx}", valueProviderCallback: _ => 215 { 216 return responseBuffer[idx]; 217 }) 218 .WithIgnoredBits(8, 24); 219 }); 220 221 CoreRegisters.CommandEvent.Define(coreRegistersCollection) 222 .WithFlag(0, FieldMode.Read, name: "cmd_done", valueProviderCallback: _ => true) 223 .WithTag("cmd_error", 1, 1) 224 .WithTag("cmd_timeout", 2, 1) 225 .WithReservedBits(3, 5) 226 .WithIgnoredBits(8, 24); 227 228 CoreRegisters.DataEvent.Define(coreRegistersCollection) 229 .WithFlag(0, FieldMode.Read, name: "data_done", valueProviderCallback: _ => true) 230 .WithTag("data_error", 1, 1) 231 .WithTag("data_timeout", 2, 1) 232 .WithReservedBits(3, 5) 233 .WithIgnoredBits(8, 24); 234 ; 235 236 CoreRegisters.BlockSize.DefineMany(coreRegistersCollection, 2, (register, idx) => 237 { 238 register 239 .WithValueField(0, 8, name: $"BlockSize{idx}", 240 writeCallback: (_, val) => BitHelper.ReplaceBits(ref blockSize, width: 8, source: (uint)val, destinationPosition: 8 - idx * 8), 241 valueProviderCallback: _ => BitHelper.GetValue(blockSize, offset: 8 - idx * 8, size: 8)) 242 .WithIgnoredBits(8, 24); 243 }); 244 245 CoreRegisters.BlockCount.DefineMany(coreRegistersCollection, 4, (register, idx) => 246 { 247 register 248 .WithValueField(0, 8, name: $"BlockCount{idx}", 249 writeCallback: (_, val) => BitHelper.ReplaceBits(ref blockCount, width: 8, source: (uint)val, destinationPosition: 24 - idx * 8), 250 valueProviderCallback: _ => BitHelper.GetValue(blockCount, offset: 24 - idx * 8, size: 8)) 251 .WithIgnoredBits(8, 24); 252 }); 253 254 ReaderRegisters.DmaBase.DefineMany(readerRegistersCollection, 8, (register, idx) => 255 { 256 register 257 .WithValueField(0, 8, name: $"ReaderAddress{idx}", 258 writeCallback: (_, val) => BitHelper.ReplaceBits(ref readerAddress, val, width: 8, destinationPosition: 56 - idx * 8), 259 valueProviderCallback: _ => (byte)BitHelper.GetValue(readerAddress, offset: 56 - idx * 8, size: 8)) 260 .WithIgnoredBits(8, 24); 261 }); 262 263 ReaderRegisters.DmaLength.DefineMany(readerRegistersCollection, 4, (register, idx) => 264 { 265 register 266 .WithValueField(0, 8, name: $"ReaderLength{idx}", 267 writeCallback: (_, val) => BitHelper.ReplaceBits(ref readerLength, (uint)val, width: 8, destinationPosition: 24 - idx * 8), 268 valueProviderCallback: _ => BitHelper.GetValue(readerLength, offset: 24 - idx * 8, size: 8)) 269 .WithIgnoredBits(8, 24); 270 }); 271 272 ReaderRegisters.DmaEnable.Define(readerRegistersCollection) 273 .WithFlag(0, out dmaReaderEnabled, name: "enable") 274 .WithIgnoredBits(1, 31); 275 276 ReaderRegisters.DmaDone.Define(readerRegistersCollection) 277 .WithFlag(0, name: "done", valueProviderCallback: _ => true) 278 .WithIgnoredBits(1, 31); 279 280 ReaderRegisters.DmaLoop.Define(readerRegistersCollection) 281 .WithTag("loop", 0, 1) 282 .WithIgnoredBits(1, 31); 283 284 WriterRegisters.DmaBase.DefineMany(writerRegistersCollection, 8, (register, idx) => 285 { 286 register 287 .WithValueField(0, 8, name: $"WriterAddress{idx}", 288 writeCallback: (_, val) => BitHelper.ReplaceBits(ref writerAddress, val, width: 8, destinationPosition: 56 - idx * 8), 289 valueProviderCallback: _ => (byte)BitHelper.GetValue(writerAddress, offset: 56 - idx * 8, size: 8)) 290 .WithIgnoredBits(8, 24); 291 }); 292 293 WriterRegisters.DmaLength.DefineMany(writerRegistersCollection, 4, (register, idx) => 294 { 295 register 296 .WithValueField(0, 8, name: $"WriterLength{idx}", 297 writeCallback: (_, val) => BitHelper.ReplaceBits(ref writerLength, (uint)val, width: 8, destinationPosition: 24 - idx * 8), 298 valueProviderCallback: _ => BitHelper.GetValue(writerLength, offset: 24 - idx * 8, size: 8)) 299 .WithIgnoredBits(8, 24); 300 }); 301 302 WriterRegisters.DmaEnable.Define(writerRegistersCollection) 303 .WithFlag(0, out dmaWriterEnabled, name: "enable") 304 .WithIgnoredBits(1, 31); 305 306 WriterRegisters.DmaDone.Define(writerRegistersCollection) 307 .WithFlag(0, name: "done", valueProviderCallback: _ => true) 308 .WithIgnoredBits(1, 31); 309 310 WriterRegisters.DmaLoop.Define(writerRegistersCollection) 311 .WithTag("loop", 0, 1) 312 .WithIgnoredBits(1, 31); 313 } 314 ReadData()315 private void ReadData() 316 { 317 readerAddress &= 0xffffffff; 318 319 var data = RegisteredPeripheral.ReadData(readerLength); 320 #if DEBUG_PACKETS 321 this.Log(LogLevel.Noisy, "Reading {0} bytes of data from device: {1}. Writing it to 0x{2:X}", data.Length, Misc.PrettyPrintCollectionHex(data), readerAddress); 322 #endif 323 324 sysbus.WriteBytes(data, readerAddress); 325 } 326 WriteData()327 private void WriteData() 328 { 329 writerAddress &= 0xffffffff; 330 331 var data = sysbus.ReadBytes(writerAddress, (int)writerLength); 332 #if DEBUG_PACKETS 333 this.Log(LogLevel.Noisy, "Writing {0} bytes of data read from 0x{1:X} to the device: {2}", data.Length, writerAddress, Misc.PrettyPrintCollectionHex(data)); 334 #endif 335 336 RegisteredPeripheral.WriteData(data); 337 } 338 339 private ulong readerAddress; 340 private ulong writerAddress; 341 private uint readerLength; 342 private uint writerLength; 343 344 private uint blockSize; 345 private uint blockCount; 346 private IValueRegisterField commandIndexField; 347 private IEnumRegisterField<ResponseType> responseTypeField; 348 private IEnumRegisterField<TransferType> transferTypeField; 349 private IFlagRegisterField dmaWriterEnabled; 350 private IFlagRegisterField dmaReaderEnabled; 351 352 private byte[] responseBuffer; 353 354 private uint argumentValue; 355 356 private readonly IBusController sysbus; 357 private readonly DoubleWordRegisterCollection phyRegistersCollection; 358 private readonly DoubleWordRegisterCollection coreRegistersCollection; 359 private readonly DoubleWordRegisterCollection readerRegistersCollection; 360 private readonly DoubleWordRegisterCollection writerRegistersCollection; 361 362 private const int ResponseBufferLength = 16; 363 364 private enum TransferType 365 { 366 None, 367 Read, 368 Write 369 } 370 371 private enum ResponseType 372 { 373 None, 374 Short, 375 Long 376 } 377 378 private enum PhyRegisters 379 { 380 CardDetect = 0x0 381 } 382 383 private enum CoreRegisters 384 { 385 // 32-bits long, spread accorss 4 registers 386 Argument = 0x0, 387 388 // 32-bits long, spread accorss 4 registers 389 Command0 = 0x10, 390 Command1 = 0x10 + 0x4, 391 Command2 = 0x10 + 0x8, 392 Command3 = 0x10 + 0xC, 393 394 // 1-bit long, spread accorss 1 register 395 IssueCommand = 0x20, 396 397 // 128-bits long, spread accross 16 registers 398 Response = 0x24, 399 400 // 4-bits long, spread accorss 1 register 401 CommandEvent = 0x64, 402 // 4-bits long, spread accorss 1 register 403 DataEvent = 0x68, 404 405 // 10-bits long, spread accross 2 registers 406 BlockSize = 0x6C, 407 408 // 32-bits long, spread accorss 4 registers 409 BlockCount = 0x74 410 } 411 412 private enum ReaderRegisters 413 { 414 // 64-bits long, spread accorss 8 registers 415 DmaBase = 0x0, 416 // 32-bits long, spread accorss 4 registers 417 DmaLength = 0x20, 418 // 1-bit long, spread accorss 1 registers 419 DmaEnable = 0x30, 420 // 1-bit long, spread accorss 1 registers 421 DmaDone = 0x34, 422 // 1-bit long, spread accorss 1 registers 423 DmaLoop = 0x38, 424 // 32-bits long, spread accorss 4 registers 425 DmaOffset = 0x3C 426 } 427 428 private enum WriterRegisters 429 { 430 // 64-bits long, spread accorss 8 registers 431 DmaBase = 0x0, 432 // 32-bits long, spread accorss 4 registers 433 DmaLength = 0x20, 434 // 1-bit long, spread accorss 1 registers 435 DmaEnable = 0x30, 436 // 1-bit long, spread accorss 1 registers 437 DmaDone = 0x34, 438 // 1-bit long, spread accorss 1 registers 439 DmaLoop = 0x38, 440 // 32-bits long, spread accorss 4 registers 441 DmaOffset = 0x3C 442 } 443 } 444 } 445