1 //
2 // Copyright (c) 2010-2024 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 System.Collections.Generic;
10 using System.IO;
11 using System.Linq;
12 using Antmicro.Renode.Exceptions;
13 using Antmicro.Renode.Logging;
14 using Antmicro.Renode.Peripherals.SPI;
15 using Antmicro.Renode.Storage;
16 using Antmicro.Renode.Utilities;
17 using static Antmicro.Renode.Utilities.BitHelper;
18 
19 namespace Antmicro.Renode.Peripherals.SD
20 {
21     // Features NOT supported:
22     // * Toggling selected state
23     // * RCA (relative card address) filtering
24     // As a result any SD controller with more than one SD card attached at the same time might not work properly.
25     // Card type (SC/HC/XC/UC) is determined based on the provided capacity
26     public class SDCard : ISPIPeripheral, IDisposable
27     {
SDCard(long capacity, bool spiMode = false, BlockLength blockSize = BlockLength.Undefined)28         public SDCard(long capacity, bool spiMode = false, BlockLength blockSize = BlockLength.Undefined)
29             : this(DataStorage.CreateInMemory((int)capacity), capacity, spiMode, blockSize) {}
30 
SDCard(string imageFile, long capacity, bool persistent = false, bool spiMode = false, BlockLength blockSize = BlockLength.Undefined)31         public SDCard(string imageFile, long capacity, bool persistent = false, bool spiMode = false, BlockLength blockSize = BlockLength.Undefined)
32             : this(DataStorage.CreateFromFile(imageFile, capacity, persistent), capacity, spiMode, blockSize) {}
33 
SDCard(Stream dataBackend, long capacity, bool spiMode = false, BlockLength blockSize = BlockLength.Undefined)34         private SDCard(Stream dataBackend, long capacity, bool spiMode = false, BlockLength blockSize = BlockLength.Undefined)
35         {
36             var blockLenghtInBytes = SDHelpers.BlockLengthInBytes(blockSize);
37             if((blockSize != BlockLength.Undefined) && (capacity % blockLenghtInBytes != 0))
38             {
39                 throw new ConstructionException($"Size (0x{capacity:X}) is not aligned to selected block size(0x{blockLenghtInBytes:X})");
40             }
41 
42             this.spiMode = spiMode;
43             this.highCapacityMode = SDHelpers.TypeFromCapacity((ulong)capacity) != CardType.StandardCapacity_SC;
44             this.capacity = capacity;
45             this.blockSize = blockSize;
46             spiContext = new SpiContext();
47 
48             this.dataBackend = dataBackend;
49 
50             var sdCapacityParameters = SDHelpers.SeekForCapacityParameters(capacity, blockSize);
51             blockLengthInBytes = SDHelpers.BlockLengthInBytes(sdCapacityParameters.BlockSize);
52 
53             cardStatusGenerator = new VariableLengthValue(32)
54                 .DefineFragment(5, 1, () => (treatNextCommandAsAppCommand ? 1 : 0u), name: "APP_CMD bit")
55                 .DefineFragment(8, 1, 1, name: "READY_FOR_DATA bit")
56                 .DefineFragment(9, 4, () => (uint)state, name: "CURRENT_STATE")
57             ;
58 
59             operatingConditionsGenerator = new VariableLengthValue(32)
60                 .DefineFragment(7, 1, 1, name: "Reserved for Low Voltage Range")
61                 .DefineFragment(8, 1, 1, name: "VDD voltage window 2.0 - 2.1")
62                 .DefineFragment(9, 1, 1, name: "VDD voltage window 2.1 - 2.2")
63                 .DefineFragment(10, 1, 1, name: "VDD voltage window 2.2 - 2.3")
64                 .DefineFragment(11, 1, 1, name: "VDD voltage window 2.3 - 2.4")
65                 .DefineFragment(12, 1, 1, name: "VDD voltage window 2.4 - 2.5")
66                 .DefineFragment(13, 1, 1, name: "VDD voltage window 2.5 - 2.6")
67                 .DefineFragment(14, 1, 1, name: "VDD voltage window 2.6 - 2.7")
68                 .DefineFragment(15, 1, 1, name: "VDD voltage window 2.7 - 2.8")
69                 .DefineFragment(16, 1, 1, name: "VDD voltage window 2.8 - 2.9")
70                 .DefineFragment(17, 1, 1, name: "VDD voltage window 2.9 - 3.0")
71                 .DefineFragment(18, 1, 1, name: "VDD voltage window 3.0 - 3.1")
72                 .DefineFragment(19, 1, 1, name: "VDD voltage window 3.1 - 3.2")
73                 .DefineFragment(20, 1, 1, name: "VDD voltage window 3.2 - 3.3")
74                 .DefineFragment(21, 1, 1, name: "VDD voltage window 3.3 - 3.4")
75                 .DefineFragment(22, 1, 1, name: "VDD voltage window 3.4 - 3.5")
76                 .DefineFragment(23, 1, 1, name: "VDD voltage window 3.5 - 3.6")
77                 .DefineFragment(30, 1, () => this.highCapacityMode ? 1 : 0u, name: "Card Capacity Status")
78                 .DefineFragment(31, 1, 1, name: "Card power up status bit (busy)")
79             ;
80 
81             if(!highCapacityMode)
82             {
83                 cardSpecificDataGenerator = new VariableLengthValue(128)
84                     .DefineFragment(22, 4, (ulong)sdCapacityParameters.BlockSize, name: "max write data block length")
85                     .DefineFragment(47, 3, (uint)sdCapacityParameters.Multiplier, name: "device size multiplier")
86                     .DefineFragment(62, 12, (ulong)sdCapacityParameters.DeviceSize, name: "device size")
87                     .DefineFragment(80, 4, (uint)sdCapacityParameters.BlockSize, name: "max read data block length")
88                     .DefineFragment(84, 12, (uint)(
89                           CardCommandClass.Class0
90                         | CardCommandClass.Class2
91                         | CardCommandClass.Class4
92                         ), name: "card command classes")
93                     .DefineFragment(96, 3, (uint)TransferRate.Transfer10Mbit, name: "transfer rate unit")
94                     .DefineFragment(99, 4, (uint)TransferMultiplier.Multiplier2_5, name: "transfer multiplier")
95                     .DefineFragment(126, 2, (uint)CSD.Version1, name: "CSD structure")
96                 ;
97             }
98             else
99             {
100                 cardSpecificDataGenerator = new VariableLengthValue(128)
101                     .DefineFragment(22, 4, (ulong)sdCapacityParameters.BlockSize, name: "max write data block length")
102                     .DefineFragment(48, 22, (ulong)sdCapacityParameters.DeviceSize, name: "device size")
103                     .DefineFragment(80, 4, (uint)sdCapacityParameters.BlockSize, name: "max read data block length")
104                     .DefineFragment(84, 12, (uint)(
105                           CardCommandClass.Class0
106                         | CardCommandClass.Class2
107                         | CardCommandClass.Class4
108                         ), name: "card command classes")
109                     .DefineFragment(96, 3, (uint)TransferRate.Transfer10Mbit, name: "transfer rate unit")
110                     .DefineFragment(99, 5, (uint)TransferMultiplier.Multiplier2_5, name: "transfer multiplier")
111                     .DefineFragment(126, 2, (uint)CSD.Version2, name: "CSD structure")
112                 ;
113             }
114 
115             extendedCardSpecificDataGenerator = new VariableLengthValue(4096)
116                 .DefineFragment(120, 8, 1, name: "command queue enabled")
117                 .DefineFragment(200, 1, 1, name: "HS400 support")
118                 .DefineFragment(1472, 8, 1, name: "es support")
119                 .DefineFragment(1480, 8, 1, name: "hw hs timing")
120                 .DefineFragment(1568, 8, (uint)DeviceType.SDR50Mhz | (uint) DeviceType.HS200, name: "device type")
121                 .DefineFragment(2464, 8, 1, name: "command queue support")
122             ;
123 
124             cardIdentificationGenerator = new VariableLengthValue(128)
125                 .DefineFragment(8, 4, 8, name: "manufacturer date code - month")
126                 .DefineFragment(12, 8, 18, name: "manufacturer date code - year")
127                 .DefineFragment(64, 8, (uint)'D', name: "product name 5")
128                 .DefineFragment(72, 8, (uint)'O', name: "product name 4")
129                 .DefineFragment(80, 8, (uint)'N', name: "product name 3")
130                 .DefineFragment(88, 8, (uint)'E', name: "product name 2")
131                 .DefineFragment(96, 8, (uint)'R', name: "product name 1")
132                 .DefineFragment(120, 8, 0xab, name: "manufacturer ID")
133             ;
134 
135             switchFunctionStatusGenerator = new VariableLengthValue(512)
136                 .DefineFragment(128, 1, 0x1, name: "Function Number/Status Code")
137             ;
138 
139             cardConfigurationGenerator = new VariableLengthValue(64)
140                 .DefineFragment(0, 32, 0, name: "reserved")
141                 .DefineFragment(32, 16, 0, name: "reserved")
142                 .DefineFragment(48, 4, 5, name: "DAT Bus width supported") // DAT0 (1-bit) and DAT0-3 (4-bit)
143                 .DefineFragment(52, 3, 0, name: "SD Security Support") // 0: No security
144                 .DefineFragment(55, 1, 0, name: "data_status_after erases")
145                 .DefineFragment(56, 4, 0, name: "SD Card - Spec. Version") // 0: Version 1.0-1.01
146                 .DefineFragment(60, 4, 0, name: "SCR Structure") // 0: SCR version No 1.0
147             ;
148 
149             operatingVoltageGenerator = new VariableLengthValue(24)
150                 .DefineFragment(0, 4, 0x1, name: "voltage accepted") // 0x1: 2.7-3.6V
151                 .DefineFragment(4, 16, 0, name: "reserved")
152                 .DefineFragment(20, 4, 0, name: "command version");
153             ;
154 
155             crcEngine = new CRCEngine(0x1021, 16, false, false, 0x00);
156             var bufferSize = highCapacityMode ? HighCapacityBlockLength : blockLengthInBytes;
157             /*
158              * enough to hold:
159              * 1 byte - start block token
160              * bufferSize bytes - actual data
161              * 2 bytes - CRC
162              * 1 byte - dummy byte required for the read transaction
163              */
164             spiContext.DataBuffer = new byte[bufferSize + 4];
165         }
166 
Reset()167         public void Reset()
168         {
169             GoToIdle();
170 
171             var sdCapacityParameters = SDHelpers.SeekForCapacityParameters(capacity, blockSize);
172             blockLengthInBytes = SDHelpers.BlockLengthInBytes(sdCapacityParameters.BlockSize);
173         }
174 
Dispose()175         public void Dispose()
176         {
177             dataBackend.Dispose();
178         }
179 
HandleCommand(uint commandIndex, uint arg)180         public BitStream HandleCommand(uint commandIndex, uint arg)
181         {
182             BitStream result;
183             this.Log(LogLevel.Noisy, "Command received: 0x{0:x} with arg 0x{1:x}", commandIndex, arg);
184             var treatNextCommandAsAppCommandLocal = treatNextCommandAsAppCommand;
185             treatNextCommandAsAppCommand = false;
186             if(!treatNextCommandAsAppCommandLocal || !TryHandleApplicationSpecificCommand((SdCardApplicationSpecificCommand)commandIndex, arg, out result))
187             {
188                 result = HandleStandardCommand((SdCardCommand)commandIndex, arg);
189             }
190             this.Log(LogLevel.Noisy, "Sending command response: {0}", result.ToString());
191             return result;
192         }
193 
WriteData(byte[] data)194         public void WriteData(byte[] data)
195         {
196             WriteData(data, data.Length);
197         }
198 
ReadData(uint size)199         public byte[] ReadData(uint size)
200         {
201             byte[] result;
202             if(readContext.Data != null)
203             {
204                 result = readContext.Data.AsByteArray(readContext.Offset, size);
205                 Array.Reverse(result);
206                 readContext.Move(size * 8);
207             }
208             else
209             {
210                 result = ReadDataFromUnderlyingFile(readContext.Offset, checked((int)size));
211                 readContext.Move(size);
212             }
213             return result;
214         }
215 
Transmit(byte data)216         public byte Transmit(byte data)
217         {
218             if(!spiMode)
219             {
220                 this.Log(LogLevel.Error, "Received data over SPI, but the SPI mode is disabled.");
221                 return 0;
222             }
223 
224             this.Log(LogLevel.Noisy, "SPI: Received byte 0x{0:X} in state {1}", data, spiContext.State);
225 
226             switch(spiContext.State)
227             {
228                 case SpiState.WaitingForCommand:
229                 {
230                     if(spiContext.IoState == IoState.Idle && data == DummyByte)
231                     {
232                         this.Log(LogLevel.Noisy, "Received a DUMMY byte in the idle state, ignoring it");
233                         break;
234                     }
235 
236                     if((spiContext.IoState == IoState.Idle || spiContext.IoState == IoState.MultipleBlockRead) && data != DummyByte)
237                     {
238                         // two MSB of the SPI command byte should be '01'
239                         if(BitHelper.IsBitSet(data, 7) || !BitHelper.IsBitSet(data, 6))
240                         {
241                             this.Log(LogLevel.Warning, "Unexpected command number value 0x{0:X}, ignoring this - expect problems", data);
242                             return GenerateR1Response(illegalCommand: true).AsByte();
243                         }
244 
245                         // clear COMMAND bit, we don't need it anymore
246                         BitHelper.ClearBits(ref data, 6);
247 
248                         spiContext.CommandNumber = (uint)data;
249                         spiContext.ArgumentBytes = 0;
250                         spiContext.State = SpiState.WaitingForArgBytes;
251 
252                         break;
253                     }
254 
255                     switch(spiContext.IoState)
256                     {
257                         case IoState.SingleBlockRead:
258                         case IoState.MultipleBlockRead:
259                             return HandleRead();
260                         case IoState.SingleBlockWrite:
261                         case IoState.MultipleBlockWrite:
262                             var ret = HandleWrite(data);
263                             return ret;
264                     }
265 
266                     break;
267                 }
268 
269                 case SpiState.WaitingForArgBytes:
270                 {
271                     this.Log(LogLevel.Noisy, "Storing as arg byte #{0}", spiContext.ArgumentBytes);
272 
273                     spiContext.Argument <<= 8;
274                     spiContext.Argument |= data;
275                     spiContext.ArgumentBytes++;
276 
277                     if(spiContext.ArgumentBytes == 4)
278                     {
279                         spiContext.State = SpiState.WaitingForCRC;
280                     }
281                     break;
282                 }
283 
284                 case SpiState.WaitingForCRC:
285                 {
286                     // we don't check CRC
287 
288                     this.Log(LogLevel.Noisy, "Sending a command to the SD card");
289                     var result = HandleCommand(spiContext.CommandNumber, spiContext.Argument).AsByteArray();
290 
291                     if(result.Length == 0)
292                     {
293                         this.Log(LogLevel.Warning, "Received an empty response, this is strange and might cause problems!");
294                         spiContext.State = SpiState.WaitingForCommand;
295                     }
296                     else
297                     {
298                         // The response is sent back within command response time,
299                         // 0 to 8 bytes for SDC, 1 to 8 bytes for MMC.
300                         // Send single dummy byte for compatibility with both cases.
301                         spiContext.ResponseBuffer.Enqueue(DummyByte);
302 
303                         spiContext.ResponseBuffer.EnqueueRange(result);
304                         spiContext.State = SpiState.SendingResponse;
305                     }
306                     break;
307                 }
308 
309                 case SpiState.SendingResponse:
310                 {
311                     spiContext.ResponseBuffer.TryDequeue(out var res);
312 
313                     if(spiContext.ResponseBuffer.Count == 0)
314                     {
315                         this.Log(LogLevel.Noisy, "This is the end of response buffer");
316                         spiContext.State = SpiState.WaitingForCommand;
317                     }
318                     return res;
319                 }
320 
321                 default:
322                 {
323                     throw new ArgumentException($"Received data 0x{data:X} in an unexpected state {spiContext.State}");
324                 }
325             }
326 
327             return DummyByte;
328         }
329 
FinishTransmission()330         public void FinishTransmission()
331         {
332             if(!spiMode)
333             {
334                 this.Log(LogLevel.Error, "Received SPI transmission finish signal, but the SPI mode is disabled.");
335                 return;
336             }
337 
338             this.Log(LogLevel.Noisy, "Finishing transmission");
339             spiContext.Reset();
340         }
341 
ReadSwitchFunctionStatusRegister()342         public byte[] ReadSwitchFunctionStatusRegister()
343         {
344             return switchFunctionStatusGenerator.Bits.AsByteArray();
345         }
346 
ReadExtendedCardSpecificDataRegister()347         public byte[] ReadExtendedCardSpecificDataRegister()
348         {
349             return extendedCardSpecificDataGenerator.Bits.AsByteArray();
350         }
351 
352         public ushort CardAddress { get; set; }
353 
354         public BitStream CardStatus => cardStatusGenerator.Bits;
355 
356         public BitStream OperatingConditions => operatingConditionsGenerator.Bits;
357 
358         public BitStream SDConfiguration => cardConfigurationGenerator.Bits;
359 
360         public BitStream SDStatus => new VariableLengthValue(512).Bits;
361 
362         public BitStream CardSpecificData => cardSpecificDataGenerator.Bits;
363 
364         public BitStream CardIdentification => cardIdentificationGenerator.Bits;
365 
366         public BitStream OperatingVoltage => operatingVoltageGenerator.Bits;
367 
WriteData(byte[] data, int length)368         private void WriteData(byte[] data, int length)
369         {
370             WriteDataToUnderlyingFile(writeContext.Offset, length, data);
371             writeContext.Move((uint)length);
372             state = SDCardState.Transfer;
373         }
374 
WriteDataToUnderlyingFile(long offset, int size, byte[] data)375         private void WriteDataToUnderlyingFile(long offset, int size, byte[] data)
376         {
377             dataBackend.Position = offset;
378             var actualSize = checked((int)Math.Min(size, dataBackend.Length - dataBackend.Position));
379             if(actualSize < size)
380             {
381                 this.Log(LogLevel.Warning, "Tried to write {0} bytes of data to offset {1}, but space for only {2} is available.", size, offset, actualSize);
382             }
383             dataBackend.Write(data, 0, actualSize);
384         }
385 
ReadDataFromUnderlyingFile(long offset, int size)386         private byte[] ReadDataFromUnderlyingFile(long offset, int size)
387         {
388             dataBackend.Position = offset;
389             var actualSize = checked((int)Math.Min(size, dataBackend.Length - dataBackend.Position));
390             if(actualSize < size)
391             {
392                 this.Log(LogLevel.Warning, "Tried to read {0} bytes of data from offset {1}, but only {2} is available.", size, offset, actualSize);
393             }
394 
395             /* During multi-block read, when reading till the end of disk, the SD card could reach end of disk before receiving
396              * stop transmission command. SD card specification doesn't specify what should be done in such situation.
397              * Return 0s as missing bytes.
398              */
399             var result = new byte[size];
400             var readSoFar = 0;
401             while(readSoFar < actualSize)
402             {
403                 var readThisTime = dataBackend.Read(result, readSoFar, actualSize - readSoFar);
404                 if(readThisTime == 0)
405                 {
406                     // this should not happen as we calculated the available data size
407                     throw new ArgumentException("Unexpected end of data in file stream");
408                 }
409                 readSoFar += readThisTime;
410             }
411 
412             return result;
413         }
414 
GoToIdle()415         private void GoToIdle()
416         {
417             readContext.Reset();
418             writeContext.Reset();
419             treatNextCommandAsAppCommand = false;
420 
421             state = SDCardState.Idle;
422 
423             spiContext.Reset();
424         }
425 
426         /* Data packet has the following format:
427          * bytes:
428          * [ 0                          ] data token
429          * [ 1            : blockSize   ] actual data
430          * [ blocksSize+1 : blockSize+2 ] CRC
431          *
432          * After sending CRC, we have to send single DummyByte before sending next
433          * data packet.
434          */
HandleRead()435         private byte HandleRead()
436         {
437             var blockSize = highCapacityMode ? HighCapacityBlockLength : blockLengthInBytes;
438             ushort crc = 0;
439 
440             if(spiContext.BytesSent == 0)
441             {
442                 var readData = ReadData(blockSize);
443                 crc = (ushort)crcEngine.Calculate(readData);
444 
445                 spiContext.DataBuffer[0] = BlockBeginIndicator;
446                 System.Array.Copy(readData, 0, spiContext.DataBuffer, 1, blockSize);
447                 spiContext.DataBuffer[blockSize + 1] = crc.HiByte();
448                 spiContext.DataBuffer[blockSize + 2] = crc.LoByte();
449                 // before sending new packet, at least one DummyByte should be sent
450                 spiContext.DataBuffer[blockSize + 3] = DummyByte;
451             }
452 
453             var res = spiContext.DataBuffer[spiContext.BytesSent];
454 
455             spiContext.BytesSent++;
456             // We sent whole required data and can proceed to the next data packet,
457             // or finish the data read.
458             if(spiContext.BytesSent == blockSize + 4)
459             {
460                 if(spiContext.IoState == IoState.SingleBlockRead)
461                 {
462                     spiContext.IoState = IoState.Idle;
463                 }
464                 spiContext.BytesSent = 0;
465             }
466             return res;
467         }
468 
469         /* Data packet has the following format:
470          * bytes:
471          * [ 0                          ] data token
472          * [ 1            : blockSize   ] actual data
473          * [ blocksSize+1 : blockSize+2 ] CRC
474          *
475          * After sending CRC, we have to send data response.
476          */
HandleWrite(byte data)477         private byte HandleWrite(byte data)
478         {
479             var blockSize = highCapacityMode ? HighCapacityBlockLength : blockLengthInBytes;
480 
481             switch(spiContext.ReceptionState)
482             {
483                 case ReceptionState.WaitingForDataToken:
484                     switch((DataToken)data)
485                     {
486                         case DataToken.StopTran:
487                             spiContext.IoState = IoState.Idle;
488                             state = SDCardState.Programming;
489                             break;
490                         case DataToken.SingleWriteStartBlock:
491                         case DataToken.MultiWriteStartBlock:
492                             spiContext.DataBytesReceived = 0;
493                             spiContext.ReceptionState = ReceptionState.ReceivingData;
494                             break;
495                     }
496                     return DummyByte;
497                 case ReceptionState.ReceivingData:
498                     spiContext.DataBuffer[spiContext.DataBytesReceived] = data;
499                     spiContext.DataBytesReceived++;
500                     if(spiContext.DataBytesReceived == blockSize)
501                     {
502                         spiContext.ReceptionState = ReceptionState.ReceivingCRC;
503                         spiContext.CRCBytesReceived = 0;
504                     }
505                     return DummyByte;
506                 case ReceptionState.ReceivingCRC:
507                     spiContext.CRCBytesReceived++;
508                     if(spiContext.CRCBytesReceived == 2)
509                     {
510                         spiContext.ReceptionState = ReceptionState.SendingResponse;
511                     }
512                     return DummyByte;
513                 case ReceptionState.SendingResponse:
514                     WriteData(spiContext.DataBuffer, (int)blockSize);
515                     spiContext.ReceptionState = ReceptionState.WaitingForDataToken;
516                     if(spiContext.IoState == IoState.SingleBlockWrite)
517                     {
518                         spiContext.IoState = IoState.Idle;
519                         state = SDCardState.Programming;
520                     }
521                     return DataAcceptedResponse;
522             }
523             return DummyByte;
524         }
525 
GenerateR1Response(bool illegalCommand = false)526         private BitStream GenerateR1Response(bool illegalCommand = false)
527         {
528             return new BitStream()
529                 .AppendBit(state == SDCardState.Idle)
530                 .AppendBit(false) // Erase Reset
531                 .AppendBit(illegalCommand)
532                 .AppendBit(false) // Com CRC Error
533                 .AppendBit(false) // Erase Seq Error
534                 .AppendBit(false) // Address Error
535                 .AppendBit(false) // Parameter Error
536                 .AppendBit(false); // always 0
537         }
538 
GenerateR2Response()539         private BitStream GenerateR2Response()
540         {
541             return GenerateR1Response()
542                 .Append((byte)0); // TODO: fill with the actual data
543         }
544 
GenerateR3Response()545         private BitStream GenerateR3Response()
546         {
547             return GenerateR1Response()
548                 .Append(OperatingConditions.AsByteArray());
549         }
550 
GenerateR7Response(byte checkPattern)551         private BitStream GenerateR7Response(byte checkPattern)
552         {
553             return GenerateR1Response()
554                 .Append(OperatingVoltage.AsByteArray().Reverse().ToArray())
555                 .Append(checkPattern);
556         }
557 
GenerateRegisterResponse(BitStream register)558         private BitStream GenerateRegisterResponse(BitStream register)
559         {
560             var reg = register.AsByteArray().Reverse().ToArray();
561             ushort crc = (ushort)crcEngine.Calculate(reg);
562             return GenerateR1Response()
563                 .Append(BlockBeginIndicator)
564                 .Append(reg)
565                 .Append(crc.HiByte())
566                 .Append(crc.LoByte());
567         }
568 
HandleStandardCommand(SdCardCommand command, uint arg)569         private BitStream HandleStandardCommand(SdCardCommand command, uint arg)
570         {
571             this.Log(LogLevel.Noisy, "Handling as a standard command: {0}", command);
572             switch(command)
573             {
574                 case SdCardCommand.GoIdleState_CMD0:
575                     GoToIdle();
576                     return spiMode
577                         ? GenerateR1Response()
578                         : BitStream.Empty; // no response in SD mode
579 
580                 case SdCardCommand.SendSupportInformation_CMD1:
581                     return spiMode
582                         ? GenerateR3Response()
583                         : OperatingConditions;
584 
585                 case SdCardCommand.SendCardIdentification_CMD2:
586                 {
587                     if(spiMode)
588                     {
589                         // this command is not supported in the SPI mode
590                         break;
591                     }
592 
593                     state = SDCardState.Identification;
594 
595                     return CardIdentification;
596                 }
597 
598                 case SdCardCommand.SendRelativeAddress_CMD3:
599                 {
600                     if(spiMode)
601                     {
602                         // this command is not supported in the SPI mode
603                         break;
604                     }
605 
606                     state = SDCardState.Standby;
607 
608                     var status = CardStatus.AsUInt32();
609                     return BitHelper.BitConcatenator.New()
610                         .StackAbove(status, 13, 0)
611                         .StackAbove(status, 1, 19)
612                         .StackAbove(status, 2, 22)
613                         .StackAbove(CardAddress, 16, 0)
614                         .Bits;
615                 }
616 
617                 case SdCardCommand.CheckSwitchableFunction_CMD6:
618                     return spiMode
619                         ? GenerateR1Response()
620                         : CardStatus;
621 
622                 case SdCardCommand.SelectDeselectCard_CMD7:
623                 {
624                     if(spiMode)
625                     {
626                         // this command is not supported in the SPI mode
627                         break;
628                     }
629 
630                     // this is a toggle command:
631                     // Select is used to start a transfer;
632                     // Deselct is used to abort the active transfer
633                     switch(state)
634                     {
635                         case SDCardState.Standby:
636                             state = SDCardState.Transfer;
637                             break;
638 
639                         case SDCardState.Transfer:
640                         case SDCardState.Programming:
641                             state = SDCardState.Standby;
642                             break;
643                     }
644 
645                     return CardStatus;
646                 }
647 
648                 case SdCardCommand.SendInterfaceConditionCommand_CMD8:
649                     return spiMode
650                         ? GenerateR7Response((byte)arg)
651                         : CardStatus;
652 
653                 case SdCardCommand.SendCardSpecificData_CMD9:
654                     return spiMode
655                         ? GenerateRegisterResponse(CardSpecificData)
656                         : CardSpecificData;
657 
658                 case SdCardCommand.SendCardIdentification_CMD10:
659                     return spiMode
660                         ? GenerateRegisterResponse(CardIdentification)
661                         : CardIdentification;
662 
663                 case SdCardCommand.StopTransmission_CMD12:
664                     readContext.Reset();
665                     writeContext.Reset();
666 
667                     switch(state)
668                     {
669                         case SDCardState.SendingData:
670                             state = SDCardState.Transfer;
671                             spiContext.IoState = IoState.Idle;
672                             break;
673 
674                         case SDCardState.ReceivingData:
675                             state = SDCardState.Programming;
676                             break;
677                     }
678 
679                     return spiMode
680                         ? GenerateR1Response()
681                         : CardStatus;
682 
683                 case SdCardCommand.SendStatus_CMD13:
684                     return spiMode
685                         ? GenerateR2Response()
686                         : CardStatus;
687 
688                 case SdCardCommand.SetBlockLength_CMD16:
689                     blockLengthInBytes = arg;
690                     return spiMode
691                         ? GenerateR1Response()
692                         : CardStatus;
693 
694                 case SdCardCommand.ReadSingleBlock_CMD17:
695                     spiContext.IoState = IoState.SingleBlockRead;
696                     state = SDCardState.SendingData;
697                     spiContext.BytesSent = 0;
698                     readContext.Offset = highCapacityMode
699                         ? arg * HighCapacityBlockLength
700                         : arg;
701                     return spiMode
702                         ? GenerateR1Response()
703                         : CardStatus;
704 
705                 case SdCardCommand.ReadMultipleBlocks_CMD18:
706                     spiContext.IoState = IoState.MultipleBlockRead;
707                     state = SDCardState.SendingData;
708                     spiContext.BytesSent = 0;
709                     readContext.Offset = highCapacityMode
710                         ? arg * HighCapacityBlockLength
711                         : arg;
712                     return spiMode
713                         ? GenerateR1Response()
714                         : CardStatus;
715 
716                 case SdCardCommand.SendTuneBlock_CMD21:
717                     return new BitStream(new byte[4]);
718 
719                 case SdCardCommand.SetBlockCount_CMD23:
720                     return spiMode
721                         ? GenerateR1Response()
722                         : CardStatus;
723 
724                 case SdCardCommand.WriteSingleBlock_CMD24:
725                     state = SDCardState.ReceivingData;
726                     spiContext.IoState = IoState.SingleBlockWrite;
727                     spiContext.DataBytesReceived = 0;
728                     spiContext.ReceptionState = ReceptionState.WaitingForDataToken;
729                     writeContext.Offset = highCapacityMode
730                         ? arg * HighCapacityBlockLength
731                         : arg;
732                     return spiMode
733                         ? GenerateR1Response()
734                         : CardStatus;
735 
736                 case SdCardCommand.WriteMultipleBlocks_CMD25:
737                     state = SDCardState.ReceivingData;
738                     spiContext.IoState = IoState.MultipleBlockWrite;
739                     spiContext.DataBytesReceived = 0;
740                     spiContext.ReceptionState = ReceptionState.WaitingForDataToken;
741                     writeContext.Offset = highCapacityMode
742                         ? arg * HighCapacityBlockLength
743                         : arg;
744                     return spiMode
745                         ? GenerateR1Response()
746                         : CardStatus;
747 
748                 case SdCardCommand.AppCommand_CMD55:
749                     treatNextCommandAsAppCommand = true;
750                     return spiMode
751                         ? GenerateR1Response()
752                         : CardStatus;
753 
754                 case SdCardCommand.ReadOperationConditionRegister_CMD58:
755                     return spiMode
756                         ? GenerateR3Response()
757                         : BitStream.Empty;
758 
759                 case SdCardCommand.EnableCRCChecking_CMD59:
760                     // we don't have to check CRC, but the software requires proper response after such request
761                     return spiMode
762                         ? GenerateR1Response()
763                         : BitStream.Empty;
764             }
765 
766             this.Log(LogLevel.Warning, "Unsupported command: {0}. Ignoring it", command);
767             return spiMode
768                 ? GenerateR1Response(illegalCommand: true)
769                 : BitStream.Empty;
770         }
771 
TryHandleApplicationSpecificCommand(SdCardApplicationSpecificCommand command, uint arg, out BitStream result)772         private bool TryHandleApplicationSpecificCommand(SdCardApplicationSpecificCommand command, uint arg, out BitStream result)
773         {
774             this.Log(LogLevel.Noisy, "Handling as an application specific command: {0}", command);
775             switch(command)
776             {
777                 case SdCardApplicationSpecificCommand.SendSDCardStatus_ACMD13:
778                     readContext.Data = SDStatus;
779                     result = spiMode
780                         ? GenerateR2Response()
781                         : CardStatus;
782                     return true;
783 
784                 case SdCardApplicationSpecificCommand.SendOperatingConditionRegister_ACMD41:
785                     // If HCS is set to 0, High Capacity SD Memory Card never returns ready state
786                     var hcs = BitHelper.IsBitSet(arg, 30);
787                     if(!highCapacityMode || hcs)
788                     {
789                         // activate the card
790                         state = SDCardState.Ready;
791                     }
792 
793                     result = spiMode
794                         ? GenerateR1Response()
795                         : OperatingConditions;
796                     return true;
797 
798                 case SdCardApplicationSpecificCommand.SendSDConfigurationRegister_ACMD51:
799                     readContext.Data = SDConfiguration;
800                     state = SDCardState.SendingData;
801                     result = spiMode
802                         ? GenerateRegisterResponse(SDConfiguration)
803                         : CardStatus;
804                     return true;
805 
806                 default:
807                     this.Log(LogLevel.Noisy, "Command #{0} seems not to be any application specific command", command);
808                     result = null;
809                     return false;
810             }
811         }
812 
813         private SDCardState state;
814 
815         private bool treatNextCommandAsAppCommand;
816         private uint blockLengthInBytes;
817         private IoContext writeContext;
818         private IoContext readContext;
819         private readonly Stream dataBackend;
820         private readonly VariableLengthValue cardStatusGenerator;
821         private readonly VariableLengthValue cardConfigurationGenerator;
822         private readonly VariableLengthValue operatingConditionsGenerator;
823         private readonly VariableLengthValue cardSpecificDataGenerator;
824         private readonly VariableLengthValue extendedCardSpecificDataGenerator;
825         private readonly VariableLengthValue cardIdentificationGenerator;
826         private readonly VariableLengthValue switchFunctionStatusGenerator;
827         private readonly VariableLengthValue operatingVoltageGenerator;
828 
829         private readonly long capacity;
830         private readonly BlockLength blockSize;
831         private readonly bool spiMode;
832         private readonly bool highCapacityMode;
833         private readonly SpiContext spiContext;
834         private readonly CRCEngine crcEngine;
835         private const byte DummyByte = 0xFF;
836         private const byte BlockBeginIndicator = 0xFE;
837         private const int HighCapacityBlockLength = 512;
838         private const byte DataAcceptedResponse = 0x05;
839 
840         private struct IoContext
841         {
842             public uint Offset
843             {
844                 get { return offset; }
845                 set
846                 {
847                     offset = value;
848                     data = null;
849                 }
850             }
851 
852             public BitStream Data
853             {
854                 get { return data; }
855                 set
856                 {
857                     data = value;
858                     offset = 0;
859                 }
860             }
861 
MoveAntmicro.Renode.Peripherals.SD.SDCard.IoContext862             public void Move(uint offset)
863             {
864                 this.offset += offset;
865                 if(data == null)
866                 {
867                     bytesLeft -= offset;
868                 }
869             }
870 
ResetAntmicro.Renode.Peripherals.SD.SDCard.IoContext871             public void Reset()
872             {
873                 offset = 0;
874                 bytesLeft = 0;
875                 data = null;
876             }
877 
878             private uint bytesLeft;
879             private uint offset;
880             private BitStream data;
881         }
882 
883         private enum SdCardCommand
884         {
885             GoIdleState_CMD0 = 0,
886             SendSupportInformation_CMD1 = 1,
887             SendCardIdentification_CMD2 = 2,
888             SendRelativeAddress_CMD3 = 3,
889             CheckSwitchableFunction_CMD6 = 6,
890             SelectDeselectCard_CMD7 = 7,
891             // this command has been added in spec version 2.0 - we don't have to answer to it
892             SendInterfaceConditionCommand_CMD8 = 8,
893             SendCardSpecificData_CMD9 = 9,
894             SendCardIdentification_CMD10 = 10,
895             StopTransmission_CMD12 = 12,
896             SendStatus_CMD13 = 13,
897             SetBlockLength_CMD16 = 16,
898             ReadSingleBlock_CMD17 = 17,
899             ReadMultipleBlocks_CMD18 = 18,
900             SendTuneBlock_CMD21 = 21,
901             SetBlockCount_CMD23 = 23,
902             WriteSingleBlock_CMD24 = 24,
903             WriteMultipleBlocks_CMD25 = 25,
904             IOReadWriteDirect_CM52 = 52,
905             AppCommand_CMD55 = 55,
906             ReadOperationConditionRegister_CMD58 = 58,
907             EnableCRCChecking_CMD59 = 59
908         }
909 
910         private enum SdCardApplicationSpecificCommand
911         {
912             SendSDCardStatus_ACMD13 = 13,
913             SendOperatingConditionRegister_ACMD41 = 41,
914             SendSDConfigurationRegister_ACMD51 = 51
915         }
916 
917         [Flags]
918         private enum CardCommandClass
919         {
920             Class0 = (1 << 0),
921             Class1 = (1 << 1),
922             Class2 = (1 << 2),
923             Class3 = (1 << 3),
924             Class4 = (1 << 4),
925             Class5 = (1 << 5),
926             Class6 = (1 << 6),
927             Class7 = (1 << 7),
928             Class8 = (1 << 8),
929             Class9 = (1 << 9),
930             Class10 = (1 << 10),
931             Class11 = (1 << 11)
932         }
933 
934         private enum TransferRate
935         {
936             Transfer100kbit = 0,
937             Transfer1Mbit = 1,
938             Transfer10Mbit = 2,
939             Transfer100Mbit = 3,
940             // the rest is reserved
941         }
942 
943         private enum TransferMultiplier
944         {
945             Reserved = 0,
946             Multiplier1 = 1,
947             Multiplier1_2 = 2,
948             Multiplier1_3 = 3,
949             Multiplier1_5 = 4,
950             Multiplier2 = 5,
951             Multiplier2_5 = 6,
952             Multiplier3 = 7,
953             Multiplier3_5 = 8,
954             Multiplier4 = 9,
955             Multiplier4_5 = 10,
956             Multiplier5 = 11,
957             Multiplier5_5 = 12,
958             Multiplier6 = 13,
959             Multiplier7 = 14,
960             Multiplier8 = 15
961         }
962 
963         private enum DeviceType
964         {
965             Legacy = 0,
966             SDR25Mhz = 1,
967             SDR50Mhz = 2,
968             SDR = 3,
969             DDR = 4,
970             HS200 = 0x10
971         }
972 
973         private enum DataToken
974         {
975             SingleWriteStartBlock = 0xFE,
976             MultiWriteStartBlock = 0xFC,
977             StopTran = 0xFD
978         }
979 
980         private enum SpiState
981         {
982             WaitingForCommand,
983             WaitingForArgBytes,
984             WaitingForCRC,
985             SendingResponse
986         }
987 
988         private enum IoState
989         {
990             Idle,
991             SingleBlockRead,
992             MultipleBlockRead,
993             SingleBlockWrite,
994             MultipleBlockWrite
995         }
996 
997         private enum ReceptionState
998         {
999             WaitingForDataToken,
1000             ReceivingData,
1001             ReceivingCRC,
1002             SendingResponse
1003         }
1004 
1005         private class SpiContext
1006         {
Reset()1007             public void Reset()
1008             {
1009                 ResponseBuffer.Clear();
1010                 ArgumentBytes = 0;
1011                 Argument = 0;
1012                 CommandNumber = 0;
1013                 State = SpiState.WaitingForCommand;
1014                 BytesSent = 0;
1015                 IoState = IoState.Idle;
1016             }
1017 
1018             public Queue<byte> ResponseBuffer = new Queue<byte>();
1019             public byte[] DataBuffer;
1020             public int ArgumentBytes;
1021             public uint Argument;
1022             public uint CommandNumber;
1023             public SpiState State;
1024             public uint BytesSent;
1025             public uint DataBytesReceived;
1026             public uint CRCBytesReceived;
1027             public IoState IoState;
1028             public ReceptionState ReceptionState;
1029         }
1030 
1031         private enum SDCardState
1032         {
1033             Idle = 0,
1034             Ready = 1,
1035             Identification = 2,
1036             Standby = 3,
1037             Transfer = 4,
1038             SendingData = 5,
1039             ReceivingData = 6,
1040             Programming = 7,
1041             Disconnect = 8
1042             // the rest is reserved
1043         }
1044 
1045         private enum CSD
1046         {
1047             Version1 = 0,
1048             Version2 = 1
1049         }
1050     }
1051 }
1052