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