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