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 
8 using Antmicro.Renode.Core;
9 using Antmicro.Renode.Core.Structure;
10 using Antmicro.Renode.Core.Structure.Registers;
11 using Antmicro.Renode.Logging;
12 using Antmicro.Renode.Peripherals.Bus;
13 using Antmicro.Renode.Utilities;
14 using System;
15 using System.Collections.Generic;
16 using System.Linq;
17 
18 namespace Antmicro.Renode.Peripherals.SPI
19 {
20     public class RenesasRZG_SPI : SimpleContainer<ISPIPeripheral>, ISPIPeripheral, IKnownSize, INumberedGPIOOutput, IBytePeripheral, IWordPeripheral, IDoubleWordPeripheral
21     {
RenesasRZG_SPI(IMachine machine)22         public RenesasRZG_SPI(IMachine machine) : base(machine)
23         {
24             Connections = Enumerable
25                 .Range(0, NrOfInterrupts)
26                 .ToDictionary<int, int, IGPIO>(idx => idx, _ => new GPIO());
27 
28             byteRegisters = new ByteRegisterCollection(this);
29             wordRegisters = new WordRegisterCollection(this);
30             DefineRegisters();
31             Reset();
32         }
33 
Reset()34         public override void Reset()
35         {
36             receiveQueue.Clear();
37             transmitQueue.Clear();
38             byteRegisters.Reset();
39             wordRegisters.Reset();
40             UpdateInterrupts();
41         }
42 
ReadByte(long offset)43         public byte ReadByte(long offset)
44         {
45             if(IsDataOffset(offset))
46             {
47                 return (byte)HandleDataRead(AccessWidth.Byte);
48             }
49             return byteRegisters.Read(offset);
50         }
51 
WriteByte(long offset, byte value)52         public void WriteByte(long offset, byte value)
53         {
54             if(IsDataOffset(offset))
55             {
56                 HandleDataWrite(AccessWidth.Byte, (uint)value);
57             }
58             byteRegisters.Write(offset, value);
59         }
60 
ReadWord(long offset)61         public ushort ReadWord(long offset)
62         {
63             if(IsDataOffset(offset))
64             {
65                 return (ushort)HandleDataRead(AccessWidth.Word);
66             }
67             return wordRegisters.Read(offset);
68         }
69 
WriteWord(long offset, ushort value)70         public void WriteWord(long offset, ushort value)
71         {
72             if(IsDataOffset(offset))
73             {
74                 HandleDataWrite(AccessWidth.Word, (uint)value);
75             }
76             wordRegisters.Write(offset, value);
77         }
78 
ReadDoubleWord(long offset)79         public uint ReadDoubleWord(long offset)
80         {
81             if(IsDataOffset(offset))
82             {
83                 return HandleDataRead(AccessWidth.LongWord);
84             }
85             this.WarningLog(
86                 "Trying to read double word from non double word register at offset 0x{1:X}. Returning 0x0",
87                 offset
88             );
89             return 0x0;
90         }
91 
WriteDoubleWord(long offset, uint value)92         public void WriteDoubleWord(long offset, uint value)
93         {
94             if(IsDataOffset(offset))
95             {
96                 HandleDataWrite(AccessWidth.LongWord, value);
97             }
98             else
99             {
100                 this.WarningLog(
101                     "Trying to write double word 0x{1:X} to non double word register at offset 0x{2:X}. Register won't be updated",
102                     value,
103                     offset
104                 );
105             }
106         }
107 
Transmit(byte data)108         public byte Transmit(byte data)
109         {
110             if(isMaster.Value)
111             {
112                 this.ErrorLog("Peripheral is in master mode, but received transmission from another SPI master.");
113                 return 0x0;
114             }
115 
116             receiveQueue.Enqueue(data);
117             var response = transmitQueue.Count > (byte)0 ? transmitQueue.Dequeue() : (byte)0;
118             UpdateInterrupts();
119 
120             return response;
121         }
122 
FinishTransmission()123         public void FinishTransmission()
124         {
125             // intentionally left blank
126         }
127 
128         public long Size => 0x100;
129 
130         // IRQs are bundled into 3 signals per channel in the following order:
131         // 0: SPRI - Receive interrupt
132         // 1: SPTI - Transmit interrupt
133         // 2: SPEI - Error interrupt
134         public IReadOnlyDictionary<int, IGPIO> Connections { get; }
135 
DefineRegisters()136         private void DefineRegisters()
137         {
138             // Byte registers
139             Registers.Control.Define(byteRegisters)
140                 .WithReservedBits(0, 2)
141                 .WithTaggedFlag("MODFEN", 2)
142                 .WithFlag(3, out isMaster, name: "MSTR")
143                 .WithTaggedFlag("SPEIE", 4)
144                 .WithFlag(5, out transmitInterruptEnabled, name: "SPTIE")
145                 .WithTaggedFlag("SPE", 6)
146                 .WithFlag(7, out receiveInterruptEnabled, name: "SPRIE")
147                 .WithChangeCallback((_, __) => UpdateInterrupts());
148 
149             Registers.SlaveSelectPolarity.Define(byteRegisters)
150                 .WithTaggedFlag("SSL0P", 0)
151                 .WithReservedBits(1, 7);
152 
153             Registers.PinControl.Define(byteRegisters)
154                 .WithTaggedFlag("SPLP", 0)
155                 .WithReservedBits(1, 3)
156                 .WithTaggedFlag("MOIFV", 4)
157                 .WithTaggedFlag("MOIFE", 5)
158                 .WithReservedBits(6, 2);
159 
160             Registers.Status.Define(byteRegisters, 0x60)
161                 .WithTaggedFlag("OVRF", 0)
162                 .WithReservedBits(1, 1)
163                 .WithTaggedFlag("MODF", 2)
164                 .WithReservedBits(3, 2)
165                 .WithFlag(5, out isTransmitBufferEmpty, FieldMode.Read, name: "SPTEF")
166                 .WithFlag(6, out transmitEnd, FieldMode.Read, name: "TEND")
167                 .WithFlag(7, out isReceiveBufferFull, FieldMode.Read, name: "SPRF");
168 
169             Registers.SequenceControl.Define(byteRegisters)
170                 .WithTag("SPSLN", 0, 2)
171                 .WithReservedBits(2, 6);
172 
173             Registers.SequenceStatus.Define(byteRegisters)
174                 .WithTag("SPCP0", 0, 2)
175                 .WithReservedBits(2, 6);
176 
177             Registers.BitRate.Define(byteRegisters, 0xFF)
178                 .WithTag("SPBR", 0, 8);
179 
180             Registers.DataControl.Define(byteRegisters, 0x20)
181                 .WithReservedBits(0, 5)
182                 .WithEnumField<ByteRegister, AccessWidth>(5, 2, out dataAccessWidth, name: "SPLW")
183                 .WithTaggedFlag("TXDMY", 7);
184 
185             Registers.ClockDelay.Define(byteRegisters)
186                 .WithTag("SCKDL", 0, 3)
187                 .WithReservedBits(3, 5);
188 
189             Registers.SlaveSelectNegationDelay.Define(byteRegisters)
190                 .WithTag("SLNDL", 0, 3)
191                 .WithReservedBits(3, 5);
192 
193             Registers.NextAccessDelay.Define(byteRegisters)
194                 .WithTag("SPNDL", 0, 3)
195                 .WithReservedBits(3, 5);
196 
197             Registers.BufferControl.Define(byteRegisters)
198                 .WithValueField(0, 3, out receiveTriggerNumber, name: "RXTRG")
199                 .WithReservedBits(3, 1)
200                 .WithValueField(4, 2, out transmitTriggerNumber, name: "TXTRG")
201                 .WithFlag(6,
202                     writeCallback: (_, value) => TryResetReceiveBuffer(value),
203                     name: "RXRST")
204                 .WithFlag(7,
205                     writeCallback: (_, value) => TryResetTransmitBuffer(value),
206                     name: "TXRST");
207 
208             // Word registers
209             DefineCommandRegister(Registers.Command0);
210             DefineCommandRegister(Registers.Command1);
211             DefineCommandRegister(Registers.Command2);
212             DefineCommandRegister(Registers.Command3);
213 
214             Registers.BufferDataCountSetting.Define(wordRegisters)
215                 .WithValueField(0, 6, FieldMode.Read, valueProviderCallback: _ => (ulong)receiveQueue.Count, name: "R")
216                 .WithReservedBits(6, 2)
217                 .WithValueField(8, 4, FieldMode.Read, valueProviderCallback: _ => (ulong)transmitQueue.Count, name: "T")
218                 .WithReservedBits(12, 4);
219         }
220 
DefineCommandRegister(Registers commandRegister)221         private void DefineCommandRegister(Registers commandRegister)
222         {
223             commandRegister.Define(wordRegisters, 0x070D)
224                 .WithTaggedFlag("CPHA", 0)
225                 .WithTaggedFlag("CPOL", 1)
226                 .WithTag("BRDV", 2, 2)
227                 .WithReservedBits(4, 3)
228                 .WithTaggedFlag("SSLKP", 7)
229                 .WithTag("SPB", 8, 4)
230                 .WithTaggedFlag("LSBF", 12)
231                 .WithTaggedFlag("SPNDEN", 13)
232                 .WithTaggedFlag("SLNDEN", 14)
233                 .WithTaggedFlag("SCKDEN", 15);
234         }
235 
IsDataOffset(long offset)236         private bool IsDataOffset(long offset)
237         {
238             return (Registers)offset == Registers.Data;
239         }
240 
UpdateInterrupts()241         private void UpdateInterrupts()
242         {
243             isReceiveBufferFull.Value = (ulong)receiveQueue.Count >= receiveTriggerNumber.Value;
244             isTransmitBufferEmpty.Value = (ulong)transmitQueue.Count <= transmitTriggerNumber.Value;
245             transmitEnd.Value = (ulong)transmitQueue.Count == 0;
246 
247             Connections[ReceiveInterruptIdx].Set(receiveInterruptEnabled.Value && isReceiveBufferFull.Value);
248             Connections[TransmitInterruptIdx].Set(transmitInterruptEnabled.Value && isTransmitBufferEmpty.Value);
249             // Error interrupt is not implemented
250             Connections[ErrorInterruptIdx].Set(false);
251         }
252 
HandleDataRead(AccessWidth width)253         private uint HandleDataRead(AccessWidth width)
254         {
255             if(width != dataAccessWidth.Value)
256             {
257                 this.WarningLog(
258                     "Trying to read data of width {0} from Data register when access width {1} is set. Returning 0x0.",
259                     width,
260                     dataAccessWidth.Value
261                 );
262                 return 0x0;
263             }
264 
265             if(receiveQueue.Count == 0)
266             {
267                 this.WarningLog("Trying to read data, but recevie buffer is empty. Returning 0x0.");
268                 return 0x0;
269             }
270 
271             uint data = 0;
272             switch(width)
273             {
274                 case AccessWidth.Byte:
275                     data = receiveQueue.Dequeue();
276                     break;
277                 case AccessWidth.Word:
278                     data = (uint)receiveQueue.Dequeue() << 8 |
279                            (uint)receiveQueue.Dequeue();
280                     break;
281                 case AccessWidth.LongWord:
282                     data = (uint)receiveQueue.Dequeue() << 24 |
283                            (uint)receiveQueue.Dequeue() << 16 |
284                            (uint)receiveQueue.Dequeue() << 8  |
285                            (uint)receiveQueue.Dequeue();
286                     break;
287             }
288 
289             UpdateInterrupts();
290 
291             return data;
292         }
293 
HandleDataWrite(AccessWidth width, uint value)294         private void HandleDataWrite(AccessWidth width, uint value)
295         {
296             if(width != dataAccessWidth.Value)
297             {
298                 this.WarningLog(
299                     "Trying to write data of width {0} to Data register when access width {1} is set. Dropping data.",
300                     width,
301                     dataAccessWidth.Value
302                 );
303                 return;
304             }
305 
306             if(isMaster.Value)
307             {
308                 TransmitData(value);
309             }
310             else
311             {
312                 WriteDataToTransmitQueue(value);
313             }
314 
315             UpdateInterrupts();
316         }
317 
WriteDataToTransmitQueue(uint data)318         private void WriteDataToTransmitQueue(uint data)
319         {
320             switch(dataAccessWidth.Value)
321             {
322                 case AccessWidth.Byte:
323                     transmitQueue.Enqueue((byte)data);
324                     break;
325                 case AccessWidth.Word:
326                     foreach(var b in BitHelper.GetBytesFromValue(data, 2))
327                     {
328                         transmitQueue.Enqueue((byte)b);
329                     }
330                     break;
331                 case AccessWidth.LongWord:
332                     foreach(var b in BitHelper.GetBytesFromValue(data, 4))
333                     {
334                         transmitQueue.Enqueue((byte)b);
335                     }
336                     break;
337             }
338         }
339 
TransmitData(uint data)340         private void TransmitData(uint data)
341         {
342             if(!TryGetByAddress(0, out var selectedPeripheral))
343             {
344                 this.WarningLog("Trying to transmit data with no slave registered. Data dropped.");
345                 return;
346             }
347 
348             switch(dataAccessWidth.Value)
349             {
350                 case AccessWidth.Byte:
351                     receiveQueue.Enqueue(selectedPeripheral.Transmit((byte)data));
352                     break;
353                 case AccessWidth.Word:
354                     foreach(var b in BitHelper.GetBytesFromValue(data, 2))
355                     {
356                         receiveQueue.Enqueue(selectedPeripheral.Transmit(b));
357                     }
358                     break;
359                 case AccessWidth.LongWord:
360                     foreach(var b in BitHelper.GetBytesFromValue(data, 4))
361                     {
362                         receiveQueue.Enqueue(selectedPeripheral.Transmit(b));
363                     }
364                     break;
365             }
366         }
367 
TryResetReceiveBuffer(bool resetRequested)368         private void TryResetReceiveBuffer(bool resetRequested)
369         {
370             if(resetRequested)
371             {
372                 receiveQueue.Clear();
373                 UpdateInterrupts();
374             }
375         }
376 
TryResetTransmitBuffer(bool resetRequested)377         private void TryResetTransmitBuffer(bool resetRequested)
378         {
379             if(resetRequested)
380             {
381                 transmitQueue.Clear();
382                 UpdateInterrupts();
383             }
384         }
385 
386         private readonly Queue<byte> receiveQueue = new Queue<byte>();
387         private readonly Queue<byte> transmitQueue = new Queue<byte>();
388 
389         private readonly ByteRegisterCollection byteRegisters;
390         private readonly WordRegisterCollection wordRegisters;
391 
392         private IFlagRegisterField isMaster;
393         private IFlagRegisterField transmitInterruptEnabled;
394         private IFlagRegisterField receiveInterruptEnabled;
395         private IFlagRegisterField isReceiveBufferFull;
396         private IFlagRegisterField isTransmitBufferEmpty;
397         private IFlagRegisterField transmitEnd;
398         private IEnumRegisterField<AccessWidth> dataAccessWidth;
399         private IValueRegisterField receiveTriggerNumber;
400         private IValueRegisterField transmitTriggerNumber;
401 
402         private const int NrOfInterrupts = 3;
403         private const int ReceiveInterruptIdx = 0;
404         private const int TransmitInterruptIdx = 1;
405         private const int ErrorInterruptIdx = 2;
406 
407         private enum Registers
408         {
409             Control                     = 0x00, // SPCR
410             SlaveSelectPolarity         = 0x01, // SSLP
411             PinControl                  = 0x02, // SPPCR
412             Status                      = 0x03, // SPSR
413             Data                        = 0x04, // SPDR
414             SequenceControl             = 0x08, // SPSCR
415             SequenceStatus              = 0x09, // SPSSR
416             BitRate                     = 0x0A, // SPBR
417             DataControl                 = 0x0B, // SPDCR
418             ClockDelay                  = 0x0C, // SPCKD
419             SlaveSelectNegationDelay    = 0x0D, // SSLND
420             NextAccessDelay             = 0x0E, // SPND
421             Command0                    = 0x10, // SPCMD0
422             Command1                    = 0x12, // SPCMD1
423             Command2                    = 0x14, // SPCMD2
424             Command3                    = 0x16, // SPCMD3
425             BufferControl               = 0x20, // SPBFCR
426             BufferDataCountSetting      = 0x22, // SPBFDR
427         }
428 
429         private enum AccessWidth
430         {
431             Byte        = 1,
432             Word        = 2,
433             LongWord    = 3,
434         }
435     }
436 }
437