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