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_CSR32 : NullRegistrationPointPeripheralContainer<SDCard>, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IDoubleWordPeripheral, IKnownSize 23 { LiteSDCard_CSR32(IMachine machine)24 public LiteSDCard_CSR32(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 readerAddress = 0; 45 writerAddress = 0; 46 47 Array.Clear(responseBuffer, 0, responseBuffer.Length); 48 } 49 ReadDoubleWord(long offset)50 public uint ReadDoubleWord(long offset) 51 { 52 return phyRegistersCollection.Read(offset); 53 } 54 WriteDoubleWord(long offset, uint value)55 public void WriteDoubleWord(long offset, uint value) 56 { 57 phyRegistersCollection.Write(offset, value); 58 } 59 60 [ConnectionRegionAttribute("core")] ReadDoubleWordFromCore(long offset)61 public uint ReadDoubleWordFromCore(long offset) 62 { 63 return coreRegistersCollection.Read(offset); 64 } 65 66 [ConnectionRegionAttribute("core")] WriteDoubleWordToCore(long offset, uint value)67 public void WriteDoubleWordToCore(long offset, uint value) 68 { 69 coreRegistersCollection.Write(offset, value); 70 } 71 72 [ConnectionRegionAttribute("reader")] ReadDoubleWordFromReader(long offset)73 public uint ReadDoubleWordFromReader(long offset) 74 { 75 return readerRegistersCollection.Read(offset); 76 } 77 78 [ConnectionRegionAttribute("reader")] WriteDoubleWordToReader(long offset, uint value)79 public void WriteDoubleWordToReader(long offset, uint value) 80 { 81 readerRegistersCollection.Write(offset, value); 82 } 83 84 [ConnectionRegionAttribute("writer")] ReadDoubleWordFromWriter(long offset)85 public uint ReadDoubleWordFromWriter(long offset) 86 { 87 return writerRegistersCollection.Read(offset); 88 } 89 90 [ConnectionRegionAttribute("writer")] WriteDoubleWordToWriter(long offset, uint value)91 public void WriteDoubleWordToWriter(long offset, uint value) 92 { 93 writerRegistersCollection.Write(offset, value); 94 } 95 96 public long Size => 0x200; 97 98 public DoubleWordRegisterCollection RegistersCollection => phyRegistersCollection; 99 DefineRegisters()100 private void DefineRegisters() 101 { 102 PhyRegisters.CardDetect.Define(this) 103 // note: `true` means *no* card 104 .WithFlag(0, FieldMode.Read, name: "card_detect", valueProviderCallback: _ => RegisteredPeripheral == null) 105 .WithReservedBits(1, 31); 106 107 CoreRegisters.Argument.Define(coreRegistersCollection) 108 .WithValueField(0, 32, out argumentValue, name: "argument"); 109 110 CoreRegisters.Command.Define(coreRegistersCollection) 111 .WithEnumField<DoubleWordRegister, ResponseType>(0, 2, out responseTypeField, name: "respone_type") 112 .WithReservedBits(2, 3) 113 .WithEnumField<DoubleWordRegister, TransferType>(5, 2, out transferTypeField, name: "transfer_type") 114 .WithReservedBits(7, 1) 115 .WithValueField(8, 6, out commandIndexField, name: "command_index") 116 .WithReservedBits(14, 18); 117 118 CoreRegisters.IssueCommand.Define(coreRegistersCollection) 119 .WithFlag(0, FieldMode.WriteOneToClear, name: "issue_command", writeCallback: (_, val) => 120 { 121 if(!val) 122 { 123 // we are only interested in `true` 124 return; 125 } 126 127 if(RegisteredPeripheral == null) 128 { 129 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.Value); 130 return; 131 } 132 133 this.Log(LogLevel.Noisy, "Issuing command #{0}, transfer type is {1}, response type is {2}", commandIndexField.Value, transferTypeField.Value, responseTypeField.Value); 134 135 var resp = RegisteredPeripheral.HandleCommand((uint)commandIndexField.Value, (uint)argumentValue.Value).AsByteArray(); 136 137 this.Log(LogLevel.Noisy, "Received response of size {0}", resp.Length); 138 #if DEBUG_PACKETS 139 this.Log(LogLevel.Noisy, Misc.PrettyPrintCollectionHex(resp)); 140 #endif 141 142 var expectedResponseLength = 0; 143 144 switch(responseTypeField.Value) 145 { 146 case ResponseType.Short: 147 case ResponseType.ShortBusy: 148 expectedResponseLength = 4; 149 break; 150 151 case ResponseType.Long: 152 expectedResponseLength = 16; 153 break; 154 } 155 156 if(resp.Length != expectedResponseLength) 157 { 158 this.Log(LogLevel.Warning, "Expected response of length {0} bytes, but received {1} bytes", expectedResponseLength, resp.Length); 159 return; 160 } 161 162 for(var i = 0; i < resp.Length; i++) 163 { 164 responseBuffer[ResponseBufferLength - 1 - i] = resp[i]; 165 //responseBuffer[i] = resp[i]; 166 } 167 168 switch(transferTypeField.Value) 169 { 170 case TransferType.Read: 171 if(dmaReaderEnabled.Value) 172 { 173 ReadData(); 174 } 175 break; 176 177 case TransferType.Write: 178 if(dmaWriterEnabled.Value) 179 { 180 WriteData(); 181 } 182 break; 183 } 184 }) 185 .WithReservedBits(1, 7) 186 .WithReservedBits(8, 24); 187 188 CoreRegisters.Response.DefineMany(coreRegistersCollection, ResponseBufferLength / 4, (register, idx) => 189 { 190 register 191 .WithValueField(0, 8, FieldMode.Read, name: $"Response{(4 * idx + 0)}", valueProviderCallback: _ => responseBuffer[4 * idx + 3]) 192 .WithValueField(8, 8, FieldMode.Read, name: $"Response{(4 * idx + 1)}", valueProviderCallback: _ => responseBuffer[4 * idx + 2]) 193 .WithValueField(16, 8, FieldMode.Read, name: $"Response{(4 * idx + 2)}", valueProviderCallback: _ => responseBuffer[4 * idx + 1]) 194 .WithValueField(24, 8, FieldMode.Read, name: $"Response{(4 * idx + 3)}", valueProviderCallback: _ => responseBuffer[4 * idx + 0]); 195 }); 196 197 CoreRegisters.CommandEvent.Define(coreRegistersCollection) 198 .WithFlag(0, FieldMode.Read, name: "cmddone", valueProviderCallback: _ => true) 199 .WithTag("cerrwrite", 1, 1) 200 .WithTag("cerrtimeout", 2, 1) 201 .WithTag("cerrcrc", 3, 1) 202 .WithReservedBits(4, 28); 203 204 CoreRegisters.DataEvent.Define(coreRegistersCollection) 205 .WithFlag(0, FieldMode.Read, name: "datadone", valueProviderCallback: _ => true) 206 .WithTag("derrwrite", 1, 1) 207 .WithTag("derrtimeout", 2, 1) 208 .WithTag("derrcrc", 3, 1) 209 .WithReservedBits(4, 28); 210 211 CoreRegisters.BlockSize.Define(coreRegistersCollection) 212 .WithValueField(0, 10, out blockSize, name: "BlockSize") 213 .WithReservedBits(10, 22); 214 215 CoreRegisters.BlockCount.Define(coreRegistersCollection) 216 .WithValueField(0, 32, out blockCount, name: "BlockSize"); 217 218 ReaderRegisters.DmaBase.DefineMany(readerRegistersCollection, 2, (register, idx) => 219 { 220 register 221 .WithValueField(0, 32, name: $"ReaderAddress{idx}", 222 writeCallback: (_, val) => BitHelper.ReplaceBits(ref readerAddress, val, width: 32, destinationPosition: 32 - idx * 32), 223 valueProviderCallback: _ => (uint)BitHelper.GetValue(readerAddress, offset: 32 - idx * 32, size: 32)); 224 }); 225 226 ReaderRegisters.DmaLength.Define(readerRegistersCollection) 227 .WithValueField(0, 32, out readerLength, name: "ReaderLength"); 228 229 ReaderRegisters.DmaEnable.Define(readerRegistersCollection) 230 .WithFlag(0, out dmaReaderEnabled, name: "enable") 231 .WithReservedBits(1, 31); 232 233 ReaderRegisters.DmaDone.Define(readerRegistersCollection) 234 .WithFlag(0, name: "done", valueProviderCallback: _ => true) 235 .WithReservedBits(1, 31); 236 237 ReaderRegisters.DmaLoop.Define(readerRegistersCollection) 238 .WithTag("loop", 0, 1) 239 .WithReservedBits(1, 31); 240 241 WriterRegisters.DmaBase.DefineMany(writerRegistersCollection, 2, (register, idx) => 242 { 243 register 244 .WithValueField(0, 32, name: $"WriterAddress{idx}", 245 writeCallback: (_, val) => BitHelper.ReplaceBits(ref writerAddress, val, width: 32, destinationPosition: 32 - idx * 32), 246 valueProviderCallback: _ => (uint)BitHelper.GetValue(writerAddress, offset: 32 - idx * 32, size: 32)); 247 }); 248 249 WriterRegisters.DmaLength.Define(writerRegistersCollection) 250 .WithValueField(0, 32, out writerLength, name: "WriterLength"); 251 252 WriterRegisters.DmaEnable.Define(writerRegistersCollection) 253 .WithFlag(0, out dmaWriterEnabled, name: "enable") 254 .WithReservedBits(1, 31); 255 256 WriterRegisters.DmaDone.Define(writerRegistersCollection) 257 .WithFlag(0, name: "done", valueProviderCallback: _ => true) 258 .WithReservedBits(1, 31); 259 260 WriterRegisters.DmaLoop.Define(writerRegistersCollection) 261 .WithTag("loop", 0, 1) 262 .WithReservedBits(1, 31); 263 } 264 ReadData()265 private void ReadData() 266 { 267 readerAddress &= 0xffffffff; 268 269 var data = RegisteredPeripheral.ReadData((uint)readerLength.Value); 270 #if DEBUG_PACKETS 271 this.Log(LogLevel.Noisy, "Reading {0} bytes of data from device: {1}. Writing it to 0x{2:X}", data.Length, Misc.PrettyPrintCollectionHex(data), readerAddress); 272 #endif 273 274 sysbus.WriteBytes(data, readerAddress); 275 } 276 WriteData()277 private void WriteData() 278 { 279 writerAddress &= 0xffffffff; 280 281 var data = sysbus.ReadBytes(writerAddress, (int)writerLength.Value); 282 #if DEBUG_PACKETS 283 this.Log(LogLevel.Noisy, "Writing {0} bytes of data read from 0x{1:X} to the device: {2}", data.Length, writerAddress, Misc.PrettyPrintCollectionHex(data)); 284 #endif 285 286 RegisteredPeripheral.WriteData(data); 287 } 288 289 private ulong readerAddress; 290 private ulong writerAddress; 291 private IValueRegisterField readerLength; 292 private IValueRegisterField writerLength; 293 294 private IValueRegisterField blockSize; 295 private IValueRegisterField blockCount; 296 private IValueRegisterField commandIndexField; 297 private IEnumRegisterField<ResponseType> responseTypeField; 298 private IEnumRegisterField<TransferType> transferTypeField; 299 private IFlagRegisterField dmaWriterEnabled; 300 private IFlagRegisterField dmaReaderEnabled; 301 private IValueRegisterField argumentValue; 302 303 private byte[] responseBuffer; 304 305 private readonly IBusController sysbus; 306 private readonly DoubleWordRegisterCollection phyRegistersCollection; 307 private readonly DoubleWordRegisterCollection coreRegistersCollection; 308 private readonly DoubleWordRegisterCollection readerRegistersCollection; 309 private readonly DoubleWordRegisterCollection writerRegistersCollection; 310 311 private const int ResponseBufferLength = 16; 312 313 private enum TransferType 314 { 315 None, 316 Read, 317 Write 318 } 319 320 private enum ResponseType 321 { 322 None, 323 Short, 324 Long, 325 ShortBusy, 326 } 327 328 private enum PhyRegisters 329 { 330 CardDetect = 0x0, 331 ClockDivider = 0x4, 332 InitInitialize = 0x8, 333 DataWStatus = 0xC, 334 } 335 336 private enum CoreRegisters 337 { 338 Argument = 0x0, 339 Command = 0x4, 340 IssueCommand = 0x8, 341 Response = 0xC, 342 CommandEvent = 0x1C, 343 DataEvent = 0x20, 344 BlockSize = 0x24, 345 BlockCount = 0x28 346 } 347 348 private enum ReaderRegisters 349 { 350 // 64-bits long, spread accross 2 registers 351 DmaBase = 0x0, 352 // 32-bits long, spread accross 1 register 353 DmaLength = 0x8, 354 // 1-bit long, spread accross 1 register 355 DmaEnable = 0xC, 356 // 1-bit long, spread accross 1 register 357 DmaDone = 0x10, 358 // 1-bit long, spread accross 1 register 359 DmaLoop = 0x14, 360 // 32-bits long, spread accross 1 register 361 DmaOffset = 0x18 362 } 363 364 private enum WriterRegisters 365 { 366 // 64-bits long, spread accross 2 registers 367 DmaBase = 0x0, 368 // 32-bits long, spread accross 1 register 369 DmaLength = 0x8, 370 // 1-bit long, spread accross 1 registers 371 DmaEnable = 0xC, 372 // 1-bit long, spread accross 1 registers 373 DmaDone = 0x10, 374 // 1-bit long, spread accross 1 registers 375 DmaLoop = 0x14, 376 // 32-bits long, spread accross 1 register 377 DmaOffset = 0x18 378 } 379 } 380 } 381