1 //
2 // Copyright (c) 2010-2024 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;
8 using System.Collections.Generic;
9 using System.Linq;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Core.Extensions;
12 using Antmicro.Renode.Core.Structure;
13 using Antmicro.Renode.Core.Structure.Registers;
14 using Antmicro.Renode.Exceptions;
15 using Antmicro.Renode.Logging;
16 using Antmicro.Renode.Peripherals.Bus;
17 using Antmicro.Renode.Utilities;
18 
19 namespace Antmicro.Renode.Peripherals.SD
20 {
21     public class MPFS_SDController : NullRegistrationPointPeripheralContainer<SDCard>, IPeripheralContainer<IPhysicalLayer<byte>, NullRegistrationPoint>, IKnownSize, IDisposable,
22         IDoubleWordPeripheral, IWordPeripheral, IBytePeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IProvidesRegisterCollection<ByteRegisterCollection>
23     {
MPFS_SDController(IMachine machine)24         public MPFS_SDController(IMachine machine) : base(machine)
25         {
26             IRQ = new GPIO();
27             WakeupIRQ = new GPIO();
28             sysbus = machine.GetSystemBus(this);
29             irqManager = new InterruptManager<Interrupts>(this);
30             internalBuffer = new Queue<byte>();
31 
32             RegistersCollection = new DoubleWordRegisterCollection(this);
33             ByteRegistersCollection = new ByteRegisterCollection(this);
34             InitializeRegisters();
35         }
36 
ReadDoubleWord(long offset)37         public uint ReadDoubleWord(long offset)
38         {
39             if(RegistersCollection.TryRead(offset, out var result))
40             {
41                 return result;
42             }
43 
44             return this.ReadDoubleWordUsingByte(offset);
45         }
46 
WriteDoubleWord(long offset, uint value)47         public void WriteDoubleWord(long offset, uint value)
48         {
49             if(RegistersCollection.TryWrite(offset, value))
50             {
51                 return;
52             }
53 
54             this.WriteDoubleWordUsingByte(offset, value);
55         }
56 
ReadWord(long offset)57         public ushort ReadWord(long offset)
58         {
59             if(ByteRegistersCollection.TryRead(offset, out byte low))
60             {
61                 ushort high =  ByteRegistersCollection.Read(offset + 1);
62                 return (ushort) ((high << 8) + low);
63             };
64 
65             return this.ReadWordUsingDoubleWord(offset);
66         }
67 
WriteWord(long offset, ushort value)68         public void WriteWord(long offset, ushort value)
69         {
70             if(ByteRegistersCollection.TryWrite(offset, (byte) value))
71             {
72                 ByteRegistersCollection.Write(offset+1, (byte) (value >> 8));
73                 return;
74             };
75 
76             this.WriteWordUsingDoubleWord(offset, value);
77         }
78 
ReadByte(long offset)79         public byte ReadByte(long offset)
80         {
81             return ByteRegistersCollection.Read(offset);
82         }
83 
WriteByte(long offset, byte value)84         public void WriteByte(long offset, byte value)
85         {
86             ByteRegistersCollection.Write(offset, value);
87         }
88 
Reset()89         public override void Reset()
90         {
91             RegisteredPeripheral?.Reset();
92             RegistersCollection.Reset();
93             irqManager.Reset();
94             internalBuffer.Clear();
95             bytesRead = 0;
96         }
97 
Dispose()98         public void Dispose()
99         {
100             RegisteredPeripheral?.Dispose();
101         }
102 
GetRegistrationPoints(IPhysicalLayer<byte> peripheral)103         public IEnumerable<NullRegistrationPoint> GetRegistrationPoints(IPhysicalLayer<byte> peripheral)
104         {
105             return (peripheral == phy)
106                 ? new[] { NullRegistrationPoint.Instance }
107                 : new NullRegistrationPoint[0];
108         }
109 
Register(IPhysicalLayer<byte> peripheral, NullRegistrationPoint registrationPoint)110         public void Register(IPhysicalLayer<byte> peripheral, NullRegistrationPoint registrationPoint)
111         {
112             if(phy != null)
113             {
114                 throw new RegistrationException("There is already a PHY registered for this controller");
115             }
116             phy = peripheral;
117         }
118 
Unregister(IPhysicalLayer<byte> peripheral)119         public void Unregister(IPhysicalLayer<byte> peripheral)
120         {
121             if(phy != peripheral)
122             {
123                 throw new RegistrationException("Trying to unregister PHY that is currently not registered in this controller");
124 
125             }
126             phy = null;
127         }
128 
129         [IrqProvider]
130         public GPIO IRQ { get; private set; }
131 
132         public GPIO WakeupIRQ { get; private set; }
133 
134         public long Size => 0x2000;
135 
136         public DoubleWordRegisterCollection RegistersCollection { get; }
137         public ByteRegisterCollection ByteRegistersCollection { get; }
138         DoubleWordRegisterCollection IProvidesRegisterCollection<DoubleWordRegisterCollection>.RegistersCollection => RegistersCollection;
139         ByteRegisterCollection IProvidesRegisterCollection<ByteRegisterCollection>.RegistersCollection => ByteRegistersCollection;
140 
141         IEnumerable<IRegistered<IPhysicalLayer<byte>, NullRegistrationPoint>> IPeripheralContainer<IPhysicalLayer<byte>, NullRegistrationPoint>.Children => phy != null
142             ? new [] { Registered.Create(phy, NullRegistrationPoint.Instance) }
143             : new IRegistered<IPhysicalLayer<byte>, NullRegistrationPoint>[0];
144 
InitializeRegisters()145         private void InitializeRegisters()
146         {
147             var responseFields = new IValueRegisterField[4];
148 
149             Registers.PhySettings_HRS04.Define32(this)
150                 .WithValueField(0, 6, out addressField, name: "UHS-I Delay Address Pointer (USI_ADDR)")
151                 .WithReservedBits(6, 2)
152                 .WithValueField(8, 8, out writeDataField, name: "UHS-I Settings Write Data (UIS_WDATA)")
153                 .WithValueField(16, 5, out readDataField, FieldMode.Read, name: "UHS-I Settings Read Data (UIS_RDATA)")
154                 .WithReservedBits(21, 3)
155                 .WithFlag(24, out var writeRequestFlag, name: "UHS-I Settings Write Request (UIS_WR)")
156                 .WithFlag(25, out var readRequestFlag, name: "UHS-I Settings Read Request (UIS_RD)")
157                 .WithFlag(26, out ackField, FieldMode.Read, name: "UHS-I Settings Acknowledge (UIS_ACK)")
158                 .WithReservedBits(27, 5)
159                 .WithWriteCallback((_, value) =>
160                 {
161                     // here we set ack field even when no PHY is registered
162                     // this is intentional - the uboot test showed that this field
163                     // might be necessary to proceed with booting even when actual
164                     // reads/writes to PHY are ignored
165                     ackField.Value = (writeRequestFlag.Value || readRequestFlag.Value);
166 
167                     if(readRequestFlag.Value)
168                     {
169                         readRequestFlag.Value = false;
170                         if(phy == null)
171                         {
172                             this.Log(LogLevel.Warning, "Trying to read from an unregistered PHY");
173                         }
174                         else
175                         {
176                             readDataField.Value = phy.Read((byte)addressField.Value);
177                         }
178                     }
179 
180                     if(writeRequestFlag.Value)
181                     {
182                         writeRequestFlag.Value = false;
183                         if(phy == null)
184                         {
185                             this.Log(LogLevel.Warning, "Trying to write to an unregistered PHY");
186                         }
187                         else
188                         {
189                             phy.Write((byte)addressField.Value, (byte)writeDataField.Value);
190                         }
191                     }
192                 })
193             ;
194 
195             Registers.BlockSizeBlockCount_SRS01.Define32(this)
196                 .WithValueField(0, 12, out blockSizeField, name: "Transfer Block Size (TBS)")
197                 .WithValueField(16, 16, out blockCountField, name: "Block Count For Current Transfer (BCCT)")
198             ;
199 
200             Registers.Argument1_SRS02.Define32(this)
201                 .WithValueField(0, 32, out var commandArgument1Field, name: "Command Argument 1 (ARG1)")
202             ;
203 
204             ByteRegisters.CommandTransferMode_SRS03_3.Define8(this)
205                 .WithEnumField(0, 6, out commandIndex, name: "Command Index (CI)")
206                 .WithReservedBits(6, 2)
207                 .WithWriteCallback((_, val) =>
208                 {
209                     var sdCard = RegisteredPeripheral;
210                     if(sdCard == null)
211                     {
212                         this.Log(LogLevel.Warning, "Tried to send a command, but no SD card is currently attached");
213                         return;
214                     }
215 
216                     var commandResult = sdCard.HandleCommand((uint)commandIndex.Value, (uint)commandArgument1Field.Value);
217                     var responseType = responseTypeSelectField.Value;
218                     switch(responseType)
219                     {
220                         case ResponseType.NoResponse:
221                             if(commandResult.Length != 0)
222                             {
223                                 this.Log(LogLevel.Warning, "Expected no response, but {0} bits received", commandResult.Length);
224                                 return;
225                             }
226                             break;
227                         case ResponseType.Response136Bits:
228                             // our response does not contain 8 bits:
229                             // * start bit
230                             // * transmission bit
231                             // * command index / reserved bits (6 bits)
232                             if(commandResult.Length != 128)
233                             {
234                                 this.Log(LogLevel.Warning, "Unexpected a response of length 128 bits (excluding control bits), but {0} received", commandResult.Length);
235                                 return;
236                             }
237                             // the following bits are considered a part of returned register, but are not included in the response buffer:
238                             // * CRC7 (7 bits)
239                             // * end bit
240                             // that's why we are skipping the initial 8-bits
241                             responseFields[0].Value = commandResult.AsUInt32(8);
242                             responseFields[1].Value = commandResult.AsUInt32(40);
243                             responseFields[2].Value = commandResult.AsUInt32(72);
244                             responseFields[3].Value = commandResult.AsUInt32(104, 24);
245                             break;
246                         case ResponseType.Response48Bits:
247                         case ResponseType.Response48BitsWithBusy:
248                             // our response does not contain 16 bits:
249                             // * start bit
250                             // * transmission bit
251                             // * command index / reserved bits (6 bits)
252                             // * CRC7 (7 bits)
253                             // * end bit
254                             if(commandResult.Length != 32)
255                             {
256                                 this.Log(LogLevel.Warning, "Expected a response of length {0} bits (excluding control bits and CRC), but {1} received", 32, commandResult.Length);
257                                 return;
258                             }
259                             responseFields[0].Value = commandResult.AsUInt32();
260                             break;
261                         default:
262                             this.Log(LogLevel.Warning, "Unexpected response type selected: {0}. Ignoring the command response.", responseTypeSelectField.Value);
263                             return;
264                     }
265 
266                     ProcessCommand(sdCard, commandIndex.Value);
267 
268                     irqManager.SetInterrupt(Interrupts.BufferWriteReady, irqManager.IsEnabled(Interrupts.BufferWriteReady));
269                     irqManager.SetInterrupt(Interrupts.BufferReadReady, irqManager.IsEnabled(Interrupts.BufferReadReady));
270                     irqManager.SetInterrupt(Interrupts.CommandComplete, irqManager.IsEnabled(Interrupts.CommandComplete));
271                     if(responseType == ResponseType.Response48BitsWithBusy)
272                     {
273                         irqManager.SetInterrupt(Interrupts.TransferComplete, irqManager.IsEnabled(Interrupts.TransferComplete));
274                     }
275                 })
276             ;
277 
278             ByteRegisters.CommandTransferMode_SRS03_2.Define8(this)
279                 .WithEnumField(0, 2, out responseTypeSelectField, name: "Response Type Select (RTS)")
280                 .WithReservedBits(2, 1)
281                 .WithTag("Command CRC Check Enable (CRCCE)", 3, 1)
282                 .WithTag("Command Index Check Enable (CICE)", 4, 1)
283                 .WithEnumField(5, 1, out dataPresentSelect, name: "Data Present Select (DPS)")
284                 .WithTag("Command Type (CT)", 6, 2)
285             ;
286 
287             ByteRegisters.CommandTransferMode_SRS03_1.Define8(this)
288                 .WithTag("Response Interrupt Disable (RID)", 0, 1)
289                 .WithReservedBits(1, 7)
290             ;
291 
292             ByteRegisters.CommandTransferMode_SRS03_0.Define8(this)
293                 .WithFlag(0, out isDmaEnabled, name: "DMA Enable")
294                 .WithTag("Block Count Enable (BCE)", 1, 1)
295                 .WithTag("Auto CMD Enable (ACE)", 2, 2)
296                 .WithEnumField(4, 1, out dataTransferDirectionSelect, name: "Data Transfer Direction Select (DTDS)")
297                 .WithTag("Multi/Single Block Select (MSBS)", 5, 1)
298                 .WithTag("Response Type R1/R5 (RECT)", 6, 1)
299                 .WithTag("Response Error Check Enable (RECE)", 7, 1)
300             ;
301 
302             Registers.Response1_SRS04.Define32(this)
303                 .WithValueField(0, 32, out responseFields[0], FieldMode.Read, name: "Response Register #1 (RESP1)")
304             ;
305 
306             Registers.Response2_SRS05.Define32(this)
307                 .WithValueField(0, 32, out responseFields[1], FieldMode.Read, name: "Response Register #2 (RESP2)")
308             ;
309 
310             Registers.Response3_SRS06.Define32(this)
311                 .WithValueField(0, 32, out responseFields[2], FieldMode.Read, name: "Response Register #3 (RESP3)")
312             ;
313 
314             Registers.Response4_SRS07.Define32(this)
315                 .WithValueField(0, 32, out responseFields[3], FieldMode.Read, name: "Response Register #4 (RESP4)")
316             ;
317 
318             Registers.DataBuffer_SRS08.Define32(this).WithValueField(0, 32, name: "Buffer Data Port (BDP)",
319                 valueProviderCallback: _ =>
320                 {
321                     var sdCard = RegisteredPeripheral;
322                     if(sdCard == null)
323                     {
324                         this.Log(LogLevel.Warning, "Tried to read data, but no SD card is currently attached");
325                         return 0;
326                     }
327                     if(isDmaEnabled.Value)
328                     {
329                         this.Log(LogLevel.Debug, "Reading data in DMA mode from register that does not support it");
330                     }
331                     if(!internalBuffer.Any())
332                     {
333                         return 0;
334                     }
335                     return ReadBuffer();
336                 },
337                 writeCallback: (_, value) =>
338                 {
339                     var sdCard = RegisteredPeripheral;
340                     if(sdCard == null)
341                     {
342                         this.Log(LogLevel.Warning, "Tried to write data, but no SD card is currently attached");
343                         return;
344                     }
345                     if(isDmaEnabled.Value)
346                     {
347                         this.Log(LogLevel.Warning, "Tried to write data in DMA mode to register that does not support it");
348                         return;
349                     }
350                     WriteBuffer(sdCard, BitConverter.GetBytes((uint)value));
351                 })
352             ;
353 
354             Registers.PresentState_SRS09.Define32(this)
355                 .WithFlag(0, FieldMode.Read, name: "Command Inhibit CMD (CICMD)")
356                 .WithFlag(1, FieldMode.Read, name: "Command Inhibit DAT (CIDAT)") // as sending a command is instantienous those two bits will probably always be 0
357                                                                                   // ...
358                 .WithFlag(10, FieldMode.Read, name: "Buffer Write Enable (BWE)", valueProviderCallback: _ => true)
359                 .WithFlag(11, FieldMode.Read, name: "Buffer Read Enable (BRE)", valueProviderCallback: _ => RegisteredPeripheral == null ? false : internalBuffer.Any())
360                 .WithFlag(16, FieldMode.Read, name: "Card Inserted (CI)", valueProviderCallback: _ => RegisteredPeripheral != null)
361                 .WithFlag(17, FieldMode.Read, name: "Card State Stable (CSS)", valueProviderCallback: _ => true)
362                 .WithFlag(18, FieldMode.Read, name: "Card Detect Pin Level (CDSL)", valueProviderCallback: _ => RegisteredPeripheral != null)
363                 .WithFlag(20, FieldMode.Read, name: "Line Signal Level (DATSL1 - DAT[0])", valueProviderCallback: _ => true)
364                 .WithFlag(21, FieldMode.Read, name: "Line Signal Level (DATSL1 - DAT[1])", valueProviderCallback: _ => true)
365                 .WithFlag(22, FieldMode.Read, name: "Line Signal Level (DATSL1 - DAT[2])", valueProviderCallback: _ => true)
366                 .WithFlag(23, FieldMode.Read, name: "Line Signal Level (DATSL1 - DAT[3])", valueProviderCallback: _ => true)
367             ;
368 
369             Registers.HostControl2_SRS11.Define32(this)
370                 .WithFlag(1, FieldMode.Read, name: "Internal Clock Stable (ICS)", valueProviderCallback: _ => true)
371                 .WithTag("Software Reset For CMD Line (SRCMD)", 25, 1)
372                 .WithTag("Software Reset For DAT Line (SRDAT)", 26, 1)
373             ;
374 
375             Registers.ErrorNormalInterruptStatus_SRS12.Bind(this, irqManager.GetRegister<DoubleWordRegister>(
376                 valueProviderCallback: (irq, _) => irqManager.IsSet(irq),
377                 writeCallback: (irq, prev, curr) => { if(curr) irqManager.ClearInterrupt(irq); } ))
378             ;
379 
380             Registers.ErrorNormalStatusEnable_SRS13.Bind(this, irqManager.GetRegister<DoubleWordRegister>(
381                 valueProviderCallback: (irq, _) => irqManager.IsEnabled(irq),
382                 writeCallback: (irq, _, curr) =>
383                 {
384                     if(curr)
385                     {
386                         irqManager.EnableInterrupt(irq, curr);
387                     }
388                     else
389                     {
390                         irqManager.DisableInterrupt(irq);
391                     }
392                 }))
393             ;
394 
395             Registers.Capabilities1_SRS16.Define32(this)
396                 // these fields must return non-zero values in order for u-boot to boot
397                 .WithValueField(0, 6, FieldMode.Read, valueProviderCallback: _ => 4, name: "Timeout clock frequency (TCS)")
398                 .WithFlag(7, FieldMode.Read, valueProviderCallback: _ => true, name: "Timeout clock unit (TCU)")
399                 .WithValueField(8, 8, FieldMode.Read, valueProviderCallback: _ => 1, name: "Base Clock Frequency For SD Clock (BCSDCLK)")
400                 .WithFlag(19, FieldMode.Read, valueProviderCallback: _ => false, name: "ADMA1 Support")
401                 .WithFlag(22, FieldMode.Read, valueProviderCallback: _ => true, name: "SDMA Support")
402                 .WithFlag(24, FieldMode.Read, valueProviderCallback: _ => true, name: "Voltage Support 3.3V (VS33)")
403                 .WithFlag(25, FieldMode.Read, valueProviderCallback: _ => true, name: "Voltage Support 3.0V (VS30)")
404                 .WithFlag(26, FieldMode.Read, valueProviderCallback: _ => true, name: "Voltage Support 1.8V (VS18)")
405                 .WithFlag(28, FieldMode.Read, valueProviderCallback: _ => true, name: "64-bit DMA Support")
406             ;
407             Registers.SDMASystemAddressArgument2_SRS00.Define32(this)
408                 .WithValueField(0, 32, name: "SDMA Address",
409                     valueProviderCallback: _ =>
410                     {
411                         if(dmaSystemAddressHigh.Value != 0)
412                         {
413                             this.Log(LogLevel.Warning, "DMA System address 2 is nonzero: {0} ", dmaSystemAddressHigh.Value);
414                         }
415                         return dmaSystemAddressLow.Value;
416                     },
417                     writeCallback: (_, val) =>
418                     {
419                         dmaSystemAddressHigh.Value = 0;
420                         dmaSystemAddressLow.Value = val;
421                     }
422                 )
423 
424             ;
425 
426             Registers.DmaSystemAddressLow_SRS22.Define32(this)
427                 .WithValueField(0, 32, out dmaSystemAddressLow, name: "ADMA/SDMA System Address 1")
428             ;
429 
430             Registers.DmaSystemAddressHigh_SRS23.Define32(this)
431                 .WithValueField(0, 32, out dmaSystemAddressHigh, name: "ADMA/SDMA System Address 2")
432             ;
433         }
434 
ProcessCommand(SDCard sdCard, SDCardCommand command)435         private void ProcessCommand(SDCard sdCard, SDCardCommand command)
436         {
437             switch(command)
438             {
439                 case SDCardCommand.CheckSwitchableFunction:
440                     internalBuffer.EnqueueRange(sdCard.ReadSwitchFunctionStatusRegister());
441                     return;
442                 case SDCardCommand.SendInterfaceConditionCommand:
443                     internalBuffer.EnqueueRange(sdCard.ReadExtendedCardSpecificDataRegister());
444                     return;
445             }
446 
447             // early exit if no data is present
448             if(dataPresentSelect.Value != DataPresentSelect.DataPresent)
449             {
450                 return;
451             }
452 
453             var bytesCount = (uint)(blockCountField.Value * blockSizeField.Value);
454             switch(dataTransferDirectionSelect.Value)
455             {
456                 case DataTransferDirectionSelect.Read:
457                     ReadCard(sdCard, bytesCount);
458                     break;
459                 case DataTransferDirectionSelect.Write:
460                     WriteCard(sdCard, bytesCount);
461                     break;
462                 default:
463                     this.Log(LogLevel.Warning, "Invalid data transfer direction {};", dataTransferDirectionSelect.Value);
464                     break;
465             }
466         }
467 
ReadCard(SDCard sdCard, uint size)468         private void ReadCard(SDCard sdCard, uint size)
469         {
470             var data = sdCard.ReadData(size);
471             if(isDmaEnabled.Value)
472             {
473                 internalBuffer.Clear();
474                 bytesRead = 0;
475                 sysbus.WriteBytes(data, ((ulong)dmaSystemAddressHigh.Value << 32) | dmaSystemAddressLow.Value);
476                 Machine.LocalTimeSource.ExecuteInNearestSyncedState(_ =>
477                 {
478                     irqManager.SetInterrupt(Interrupts.TransferComplete, irqManager.IsEnabled(Interrupts.TransferComplete));
479                 });
480             }
481             internalBuffer.EnqueueRange(data);
482         }
483 
WriteBuffer(SDCard sdCard, byte[] data)484         private void WriteBuffer(SDCard sdCard, byte[] data)
485         {
486             var limit = (uint)(blockCountField.Value * blockSizeField.Value);
487             internalBuffer.EnqueueRange(data);
488             if(internalBuffer.Count < limit)
489             {
490                 return;
491             }
492             sdCard.WriteData(internalBuffer.DequeueAll());
493             irqManager.SetInterrupt(Interrupts.TransferComplete, irqManager.IsEnabled(Interrupts.TransferComplete));
494         }
495 
WriteCard(SDCard sdCard, uint size)496         private void WriteCard(SDCard sdCard, uint size)
497         {
498             var bytes = new byte[size];
499             if(isDmaEnabled.Value)
500             {
501                 bytes = sysbus.ReadBytes(((ulong)dmaSystemAddressHigh.Value << 32) | dmaSystemAddressLow.Value, (int)size);
502             }
503             else
504             {
505                 if(internalBuffer.Count < size)
506                 {
507                     this.Log(LogLevel.Warning, "Could not write {0} bytes to SD card, writing {1} bytes instead.", size, internalBuffer.Count);
508                     size = (uint)internalBuffer.Count;
509                 }
510                 bytes = internalBuffer.DequeueRange((int)size);
511             }
512             sdCard.WriteData(bytes);
513             Machine.LocalTimeSource.ExecuteInNearestSyncedState(_ =>
514             {
515                 irqManager.SetInterrupt(Interrupts.TransferComplete, irqManager.IsEnabled(Interrupts.TransferComplete));
516             });
517         }
518 
ReadBuffer()519         private uint ReadBuffer()
520         {
521             var internalBytes = internalBuffer.DequeueRange(4);
522             bytesRead += (uint)internalBytes.Length;
523             irqManager.SetInterrupt(Interrupts.BufferReadReady, irqManager.IsEnabled(Interrupts.BufferReadReady));
524             if(bytesRead >= (blockCountField.Value * blockSizeField.Value) || !internalBuffer.Any())
525             {
526                 irqManager.SetInterrupt(Interrupts.TransferComplete, irqManager.IsEnabled(Interrupts.TransferComplete));
527                 bytesRead = 0;
528                 // If we have read the exact amount of data we wanted, we can clear the buffer from any leftovers.
529                 internalBuffer.Clear();
530             }
531             return internalBytes.ToUInt32Smart();
532         }
533 
534         private IFlagRegisterField ackField;
535         private IFlagRegisterField isDmaEnabled;
536         private IValueRegisterField blockSizeField;
537         private IValueRegisterField blockCountField;
538         private IValueRegisterField addressField;
539         private IValueRegisterField readDataField;
540         private IValueRegisterField writeDataField;
541         private IValueRegisterField dmaSystemAddressLow;
542         private IValueRegisterField dmaSystemAddressHigh;
543         private IEnumRegisterField<DataPresentSelect> dataPresentSelect;
544         private IEnumRegisterField<DataTransferDirectionSelect> dataTransferDirectionSelect;
545         private IEnumRegisterField<SDCardCommand> commandIndex;
546         private IEnumRegisterField<ResponseType> responseTypeSelectField;
547 
548         private uint bytesRead;
549         private IPhysicalLayer<byte> phy;
550         private Queue<byte> internalBuffer;
551 
552         private readonly IBusController sysbus;
553         private readonly InterruptManager<Interrupts> irqManager;
554 
555         private enum Registers
556         {
557             GeneralInformation_HRS00 = 0x000,
558             DebounceSetting_HRS01 = 0x004,
559             BusSetting_HRS02 = 0x008,
560             AXIEErrorResponses_HRS03 = 0x00C,
561             PhySettings_HRS04 = 0x10,
562             EMMCControl_HRS06 = 0x18,
563             IODelayInformation_HRS07 = 0x01C,
564             HostCapability_HRS30 = 0x078,
565             HostControllerVersion_HRS31 = 0x07C,
566             FSMMonitor_HRS32 = 0x080,
567             TuneStatus0_HRS33 = 0x084,
568             TuneStatus1_HRS34 = 0x088,
569             TuneDebug_HRS35 = 0x08C,
570             BootStatus_HRS36 = 0x090,
571             ReadBlockGapCoefficientInterfaceModeSelect_HRS37 = 0x094,
572             ReadBlockGapCoefficient_HRS38 = 0x098,
573             HostControllerVersion_SlotInterruptStatus_CRS63 = 0x0FC,
574             SDMASystemAddressArgument2_SRS00 = 0x200,
575             BlockSizeBlockCount_SRS01 = 0x204,
576             Argument1_SRS02 = 0x208,
577             CommandTransferMode_SRS03 = 0x20C,
578             Response1_SRS04 = 0x210,
579             Response2_SRS05 = 0x214,
580             Response3_SRS06 = 0x218,
581             Response4_SRS07 = 0x21C,
582             DataBuffer_SRS08 = 0x220,
583             PresentState_SRS09 = 0x224,
584             HostControl1_SRS10 = 0x228,
585             HostControl2_SRS11 = 0x22C,
586             ErrorNormalInterruptStatus_SRS12 = 0x230,
587             ErrorNormalStatusEnable_SRS13 = 0x234,
588             ErrorNormalSignalEnable_SRS14 = 0x238,
589             HostControl2_SRS15 = 0x23C,
590             Capabilities1_SRS16 = 0x240,
591             Capabilities2_SRS17 = 0x244,
592             Capabilities3_SRS18 = 0x248,
593             Capabilities4_SRS19 = 0x24C,
594             ForceEvent_SRS20 = 0x250,
595             ADMAErrorStatus_SRS21 = 0x254,
596             DmaSystemAddressLow_SRS22 = 0x258,
597             DmaSystemAddressHigh_SRS23 = 0x25C,
598             PresetValue_DefaultSpeed_SRS24 = 0x260,
599             PresetValue_HighSpeedAndSDR12_SRS25 = 0x264,
600             PresetValue_SDR25AndSDR50_SRS26 = 0x268,
601             PresetValue_SDR104AndDDR50_SRS27 = 0x26C,
602             PresetValue_UHSII_SRS29 = 0x274,
603             CommandQueuingVersion_CQRS00 = 0x400,
604             CommandQueuingCapabilities_CQRS01 = 0x404,
605             CommandQueuingConfiguration_CQRS02 = 0x408,
606             CommandQueuingControl_CQRS03 = 0x40C,
607             CommandQueuingInterruptStatus_CQRS04 = 0x410,
608             CommandQueuingInterruptStatusEnable_CQRS05 = 0x414,
609             CommandQueuingInterruptSignalEnable_CQRS06 = 0x418,
610             InterruptCoalescing_CQRS07 = 0x41C,
611             CommandQueuingTaskDescriptorListBaseAddress_CQRS08 = 0x420,
612             CommandQueuingTaskDescriptorListBaseAddressUpper32Bits_CQRS09 = 0x424,
613             CommandQueuingTaskDoorbell_CQRS10 = 0x428,
614             TaskCompleteNotification_CQRS11 = 0x42C,
615             DeviceQueueStatus_CQRS12 = 0x430,
616             DevicePendingTasks_CQRS13 = 0x434,
617             TaskClear_CQRS14 = 0x438,
618             SendStatusConfiguration1_CQRS16 = 0x440,
619             SendStatusConfiguration2_CQRS17 = 0x444,
620             CommandResponseForDirect_CommandTask_CQRS18 = 0x448,
621             ResponseModeErrorMask_CQRS20 = 0x450,
622             TaskErrorInformation_CQRS21 = 0x454,
623             CommandResponseIndex_CQRS22 = 0x458,
624             CommandResponseArgument_CQRS23 = 0x45C
625         }
626 
627         private enum ByteRegisters {
628             CommandTransferMode_SRS03_0 = 0x20C,
629             CommandTransferMode_SRS03_1 = 0x20D,
630             CommandTransferMode_SRS03_2 = 0x20E,
631             CommandTransferMode_SRS03_3 = 0x20F
632         }
633 
634         private enum DataPresentSelect
635         {
636             NoDataPresent = 0,
637             DataPresent = 1
638         }
639 
640         private enum DataTransferDirectionSelect
641         {
642             Write = 0,
643             Read = 1
644         }
645 
646         private enum ResponseType
647         {
648             NoResponse = 0,
649             Response136Bits = 1,
650             Response48Bits = 2,
651             Response48BitsWithBusy = 3
652         }
653 
654         private enum Interrupts
655         {
656             CommandComplete = 0,
657             TransferComplete = 1,
658             BlockGapEvent = 2,
659             DMAInterrupt = 3,
660             BufferWriteReady = 4,
661             BufferReadReady = 5,
662             CardIsertion = 6,
663             CardRemoval = 7,
664             CardInterrupt = 8,
665             // [13:9] Reserved
666             QueuingEnabledInterrupt = 14,
667             ErrorInterrupt = 15,
668             CommandTimeoutError = 16,
669             CommandCRCError = 17,
670             CommandEndBitError = 18,
671             CommandIndexError = 19,
672             DataTimeoutError = 20,
673             DataCRCError = 21,
674             DataEndBitError = 22,
675             CurrentLimitError = 23,
676             AutoCMDError = 24,
677             ADMAError = 25,
678             // [26] Reserved
679             ResponseError = 27,
680             // [31:28] Reserved
681         }
682 
683         private enum SDCardCommand
684         {
685             CheckSwitchableFunction = 6,
686             SendInterfaceConditionCommand = 8,
687             ReadSingleBlock = 17,
688             ReadMultipleBlocks = 18,
689             WriteSingleBlock = 24,
690             WriteMultipleBlocks = 25,
691         }
692     }
693 }
694