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 using System; 8 using System.Collections.Generic; 9 using Antmicro.Renode.Core; 10 using Antmicro.Renode.Core.Structure; 11 using Antmicro.Renode.Core.Structure.Registers; 12 using Antmicro.Renode.Logging; 13 using Antmicro.Renode.Peripherals.Bus; 14 using Antmicro.Renode.Utilities; 15 using Antmicro.Renode.Exceptions; 16 17 namespace Antmicro.Renode.Peripherals.SPI 18 { 19 public class DesignWare_SPI: SimpleContainer<ISPIPeripheral>, IDoubleWordPeripheral, IKnownSize 20 { DesignWare_SPI(IMachine machine, uint transmitDepth, uint receiveDepth)21 public DesignWare_SPI(IMachine machine, uint transmitDepth, uint receiveDepth) : base(machine) 22 { 23 transmitBuffer = new Queue<ushort>(); 24 receiveBuffer = new Queue<ushort>(); 25 26 this.transmitDepth = transmitDepth; 27 28 var registersMap = new Dictionary<long, DoubleWordRegister> 29 { 30 {(long)Registers.Control0, new DoubleWordRegister(this, 0x7) 31 .WithReservedBits(20, 12) 32 .WithValueField(16, 4, FieldMode.Read, valueProviderCallback: _ => dataFrameSize.Value, name: "DFS_32") 33 .WithTag("CFS", 12, 4) 34 .WithTaggedFlag("SRL", 11) 35 .WithTaggedFlag("SLV_OE", 10) 36 .WithEnumField<DoubleWordRegister, TransferMode>(8, 2, out transferMode, name: "TMOD") 37 .WithTaggedFlag("SCPOL", 7) 38 .WithTaggedFlag("SCPH", 6) 39 .WithTag("FRF", 4, 2) 40 .WithValueField(0, 4, out dataFrameSize, name: "DFS", writeCallback: (_, val) => 41 { 42 if(val == 7) 43 { 44 FrameSize = TransferSize.SingleByte; 45 } 46 else if(val == 15) 47 { 48 FrameSize = TransferSize.DoubleByte; 49 } 50 else 51 { 52 this.Log(LogLevel.Error, "Only 8/16-bit transfers are supported. Falling back to the default 8-bit mode"); 53 dataFrameSize.Value = 7; 54 FrameSize = TransferSize.SingleByte; 55 } 56 }) 57 }, 58 59 {(long)Registers.Control1, new DoubleWordRegister(this) 60 .WithReservedBits(16, 16) 61 .WithValueField(0, 16, out numberOfFrames, name: "NDF") 62 }, 63 64 {(long)Registers.Enable, new DoubleWordRegister(this) 65 .WithReservedBits(1, 31) 66 .WithFlag(0, out enabled, changeCallback: (_, val) => 67 { 68 if(val == false) 69 { 70 ClearBuffers(); 71 } 72 }, name: "SSI_EN") 73 }, 74 75 {(long)Registers.SlaveSelect, new DoubleWordRegister(this) 76 .WithReservedBits(3, 29) 77 .WithEnumField<DoubleWordRegister, SlaveSelect>(0, 3, name: "SER", writeCallback: (previousVal, val) => 78 { 79 if(!TryDecodeSlaveId(val, out var newId)) 80 { 81 return; 82 } 83 84 // no slave selected 85 if(newId == 0) 86 { 87 if(!TryDecodeSlaveId(previousVal, out var oldId)) 88 { 89 return; 90 } 91 92 if(!TryGetByAddress(oldId, out var slave)) 93 { 94 this.Log(LogLevel.Warning, "Trying to de-select slave #{0} that is not connected", oldId); 95 return; 96 } 97 98 slave.FinishTransmission(); 99 } 100 else 101 { 102 TrySendData(newId); 103 } 104 }) 105 }, 106 107 {(long)Registers.ClockDivider, new DoubleWordRegister(this) 108 .WithValueField(1, 16, name: "SCKDV_15_1") 109 .WithFlag(0, FieldMode.Read, name: "SCKDV_0") // it's always 0 to ensure that the divider is even 110 }, 111 112 {(long)Registers.TransmitTreshold, new DoubleWordRegister(this) 113 .WithReservedBits(8, 24) 114 .WithValueField(0, 8, writeCallback: (_, val) => 115 { 116 if(val <= transmitDepth) 117 { 118 transmitThreshold = (uint)val; 119 } 120 else 121 { 122 this.Log(LogLevel.Warning, "Ignored setting transmit threshold to a value (0x{0:X}) greater than the fifo depth (0x{1:X})", val, transmitDepth); 123 } 124 }, valueProviderCallback: _ => transmitThreshold, name: "TFT") 125 }, 126 127 {(long)Registers.ReceiveTreshold, new DoubleWordRegister(this) 128 .WithReservedBits(8, 24) 129 .WithValueField(0, 8, writeCallback: (_, val) => 130 { 131 if(val <= receiveDepth) 132 { 133 receiveThreshold = (uint)val; 134 } 135 else 136 { 137 this.Log(LogLevel.Warning, "Ignored setting receive threshold to a value (0x{0:X}) greater than the fifo depth (0x{1:X})", val, receiveDepth); 138 } 139 }, valueProviderCallback: _ => receiveThreshold, name: "RFT") 140 }, 141 142 {(long)Registers.TransmitLevel, new DoubleWordRegister(this) 143 .WithReservedBits(3, 29) 144 .WithValueField(0, 3, FieldMode.Read, valueProviderCallback: _ => (uint)transmitBuffer.Count, name: "TXFLR") 145 }, 146 147 {(long)Registers.ReceiveLevel, new DoubleWordRegister(this) 148 .WithReservedBits(3, 29) 149 .WithValueField(0, 3, FieldMode.Read, valueProviderCallback: _ => (uint)receiveBuffer.Count, name: "RXFLR") 150 }, 151 152 {(long)Registers.Status, new DoubleWordRegister(this) 153 .WithReservedBits(7, 25) 154 .WithTag("DCOL", 6, 1) // read-to-clear 155 .WithTag("TXE", 5, 1) // read-to-clear, available in slave mode only 156 .WithFlag(4, FieldMode.Read, valueProviderCallback: _ => receiveBuffer.Count == receiveDepth, name: "RFF") 157 .WithFlag(3, FieldMode.Read, valueProviderCallback: _ => receiveBuffer.Count != 0, name: "RFNE") 158 .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => transmitBuffer.Count == 0, name: "TFE") 159 .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => transmitBuffer.Count < transmitDepth, name: "TFNF") 160 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => false, name: "BUSY") // in Renode transfers are instant, so BUSY is always 'false' 161 }, 162 163 {(long)Registers.InterruptMask, new DoubleWordRegister(this) 164 .WithReservedBits(6, 26) 165 .WithFlag(5, out multiMasterContentionMask, name: "MSTIM") 166 .WithFlag(4, out receiveFullMask, name: "RXFIM") 167 .WithFlag(3, out receiveOverflowMask, name: "RXFOIM") 168 .WithFlag(2, out receiveUnderflowMask, name: "RXUIM") 169 .WithFlag(1, out transmitOverflowMask, name: "TXOIM") 170 .WithFlag(0, out transmitEmptyMask, name: "TXEIM") 171 .WithWriteCallback((_, __) => UpdateInterrupt()) 172 }, 173 174 {(long)Registers.InterruptStatus, new DoubleWordRegister(this) 175 .WithReservedBits(6, 26) 176 .WithFlag(5, mode: FieldMode.Read, valueProviderCallback: _ => multiMasterContention.Value && multiMasterContentionMask.Value, name: "MSTIS") 177 .WithFlag(4, mode: FieldMode.Read, valueProviderCallback: _ => receiveFull.Value && receiveFullMask.Value, name: "RXFIS") 178 .WithFlag(3, mode: FieldMode.Read, valueProviderCallback: _ => receiveOverflow.Value && receiveOverflowMask.Value, name: "RXFOIS") 179 .WithFlag(2, mode: FieldMode.Read, valueProviderCallback: _ => receiveUnderflow.Value && receiveUnderflowMask.Value, name: "RXUIS") 180 .WithFlag(1, mode: FieldMode.Read, valueProviderCallback: _ => transmitOverflow.Value && transmitOverflowMask.Value, name: "TXOIS") 181 .WithFlag(0, mode: FieldMode.Read, valueProviderCallback: _ => transmitEmpty.Value && transmitEmptyMask.Value, name: "TXEIS") 182 }, 183 184 {(long)Registers.InterruptRawStatus, new DoubleWordRegister(this) 185 .WithReservedBits(6, 26) 186 .WithFlag(5, mode: FieldMode.Read, flagField: out multiMasterContention, name: "MSTIR") 187 .WithFlag(4, mode: FieldMode.Read, flagField: out receiveFull, name: "RXFIR") 188 .WithFlag(3, mode: FieldMode.Read, flagField: out receiveOverflow, name: "RXFOIR") 189 .WithFlag(2, mode: FieldMode.Read, flagField: out receiveUnderflow, name: "RXUIR") 190 .WithFlag(1, mode: FieldMode.Read, flagField: out transmitOverflow, name: "TXOIR") 191 .WithFlag(0, mode: FieldMode.Read, flagField: out transmitEmpty, name: "TXEIR") 192 }, 193 194 {(long)Registers.TransmitOverflowInterruptClear, new DoubleWordRegister(this) 195 .WithReservedBits(1, 31) 196 .WithFlag(0, mode: FieldMode.Read, name: "TXOICR", readCallback: (_, __) => { transmitOverflow.Value = false; UpdateInterrupt(); }) 197 }, 198 199 {(long)Registers.ReceiveOverflowInterruptClear, new DoubleWordRegister(this) 200 .WithReservedBits(1, 31) 201 .WithFlag(0, mode: FieldMode.Read, name: "RXOICR", readCallback: (_, __) => { receiveOverflow.Value = false; UpdateInterrupt(); }) 202 }, 203 204 {(long)Registers.ReceiveUnderflowInterruptClear, new DoubleWordRegister(this) 205 .WithReservedBits(1, 31) 206 .WithFlag(0, mode: FieldMode.Read, name: "RXUICR", readCallback: (_, __) => { receiveUnderflow.Value = false; UpdateInterrupt(); }) 207 }, 208 209 {(long)Registers.MultiMasterContentionInterruptClear, new DoubleWordRegister(this) 210 .WithReservedBits(1, 31) 211 .WithFlag(0, mode: FieldMode.Read, name: "MSTICR", readCallback: (_, __) => { multiMasterContention.Value = false; UpdateInterrupt(); }) 212 }, 213 214 {(long)Registers.InterruptClear, new DoubleWordRegister(this) 215 .WithReservedBits(1, 31) 216 .WithFlag(0, mode: FieldMode.Read, readCallback: (_, __) => 217 { 218 transmitOverflow.Value = false; 219 receiveOverflow.Value = false; 220 receiveUnderflow.Value = false; 221 multiMasterContention.Value = false; 222 223 UpdateInterrupt(); 224 }, name: "ICR") 225 }, 226 227 {(long)Registers.DeviceIdentificationCode, new DoubleWordRegister(this) 228 .WithValueField(0, 32, FieldMode.Read, valueProviderCallback: _ => 0xFFFFFFFF, name: "IDCODE") 229 }, 230 231 {(long)Registers.SynopsisComponentVersion, new DoubleWordRegister(this) 232 .WithValueField(0, 32, FieldMode.Read, valueProviderCallback: _ => 0x3332332A, name: "SSI_COMP_VERSION") 233 }, 234 235 {(long)Registers.DataRegister, new DoubleWordRegister(this) 236 .WithReservedBits(16, 16) 237 .WithValueField(0, 16, valueProviderCallback: _ => 238 { 239 if(!enabled.Value) 240 { 241 this.Log(LogLevel.Warning, "Trying to read value from a disabled SPI"); 242 return 0; 243 } 244 245 if(!TryDequeueFromReceiveBuffer(out var data)) 246 { 247 this.Log(LogLevel.Warning, "Trying to read from an empty FIFO"); 248 return 0; 249 } 250 251 return data; 252 }, 253 writeCallback: (_, val) => 254 { 255 if(!enabled.Value) 256 { 257 this.Log(LogLevel.Warning, "Cannot write to SPI buffer while disabled"); 258 return; 259 } 260 261 EnqueueToTransmitBuffer((ushort)val); 262 }, name: "DR") 263 }, 264 }; 265 266 registersCollection = new DoubleWordRegisterCollection(this, registersMap); 267 } 268 Register(ISPIPeripheral peripheral, NumberRegistrationPoint<int> registrationPoint)269 public override void Register(ISPIPeripheral peripheral, NumberRegistrationPoint<int> registrationPoint) 270 { 271 if(registrationPoint.Address < 1 || registrationPoint.Address > 3) 272 { 273 throw new RegistrationException("EOS S3 SPI Master supports 3 slaves at addresses 1, 2, 3"); 274 } 275 276 base.Register(peripheral, registrationPoint); 277 } 278 Reset()279 public override void Reset() 280 { 281 FrameSize = TransferSize.SingleByte; 282 283 transmitThreshold = 0; 284 receiveThreshold = 0; 285 286 ClearBuffers(); 287 288 registersCollection.Reset(); 289 UpdateInterrupt(); 290 } 291 ReadDoubleWord(long offset)292 public uint ReadDoubleWord(long offset) 293 { 294 return registersCollection.Read(offset); 295 } 296 WriteDoubleWord(long offset, uint value)297 public void WriteDoubleWord(long offset, uint value) 298 { 299 registersCollection.Write(offset, value); 300 } 301 TryDequeueFromReceiveBuffer(out ushort data)302 public bool TryDequeueFromReceiveBuffer(out ushort data) 303 { 304 if(!receiveBuffer.TryDequeue(out data)) 305 { 306 receiveUnderflow.Value = true; 307 UpdateInterrupt(); 308 309 data = 0; 310 return false; 311 } 312 313 if(receiveBuffer.Count <= receiveThreshold) 314 { 315 receiveFull.Value = false; 316 UpdateInterrupt(); 317 } 318 319 return true; 320 } 321 UpdateInterrupt()322 private void UpdateInterrupt() 323 { 324 var value = false; 325 326 value |= multiMasterContention.Value && multiMasterContentionMask.Value; 327 value |= receiveFull.Value && receiveFullMask.Value; 328 value |= receiveOverflow.Value && receiveOverflowMask.Value; 329 value |= receiveUnderflow.Value && receiveUnderflowMask.Value; 330 value |= transmitOverflow.Value && transmitOverflowMask.Value; 331 value |= transmitEmpty.Value && transmitEmptyMask.Value; 332 333 this.Log(LogLevel.Noisy, "Setting IRQ to {0}", value); 334 IRQ.Set(value); 335 } 336 TrySendData(int slaveAddress)337 private bool TrySendData(int slaveAddress) 338 { 339 if(!enabled.Value) 340 { 341 this.Log(LogLevel.Warning, "Cannot transmit data while SPI is disabled"); 342 return false; 343 } 344 345 if(!this.TryGetByAddress(slaveAddress, out var peripheral)) 346 { 347 this.Log(LogLevel.Warning, "Trying to send data to a not attached slave #{0}", slaveAddress); 348 return false; 349 } 350 351 this.Log(LogLevel.Noisy, "Transmit mode {0} selected", transferMode.Value); 352 353 if(transmitBuffer.Count == 0 && transferMode.Value != TransferMode.Receive) 354 { 355 this.Log(LogLevel.Warning, "No data to transmit"); 356 return false; 357 } 358 359 var bytesFromFrames = ((int)numberOfFrames.Value + 1) * (FrameSize == TransferSize.SingleByte ? 1 : 2 /* TransferSize.DoubleByte */); 360 switch(transferMode.Value) 361 { 362 case TransferMode.TransmitReceive: 363 DoTransfer(peripheral, transmitBuffer.Count, readFromFifo: true, writeToFifo: true); 364 break; 365 case TransferMode.Transmit: 366 DoTransfer(peripheral, transmitBuffer.Count, readFromFifo: true, writeToFifo: false); 367 break; 368 case TransferMode.Receive: 369 DoTransfer(peripheral, bytesFromFrames, readFromFifo: false, writeToFifo: true); 370 break; 371 case TransferMode.EEPROM: 372 // control bytes 373 DoTransfer(peripheral, transmitBuffer.Count, readFromFifo: true, writeToFifo: false); 374 // data bytes 375 DoTransfer(peripheral, bytesFromFrames, readFromFifo: false, writeToFifo: true); 376 break; 377 } 378 379 return true; 380 } 381 DoTransfer(ISPIPeripheral peripheral, int size, bool readFromFifo, bool writeToFifo)382 private void DoTransfer(ISPIPeripheral peripheral, int size, bool readFromFifo, bool writeToFifo) 383 { 384 this.Log(LogLevel.Noisy, "Doing an SPI transfer of size {0} bytes (reading from fifo: {1}, writing to fifo: {2})", size, readFromFifo, writeToFifo); 385 for(var i = 0; i < size; i++) 386 { 387 ushort dataFromSlave = 0; 388 var dataToSlave = readFromFifo ? transmitBuffer.Dequeue() : (ushort)0; 389 switch(FrameSize) 390 { 391 case TransferSize.SingleByte: 392 dataFromSlave = peripheral.Transmit((byte)dataToSlave); 393 break; 394 395 case TransferSize.DoubleByte: 396 { 397 var responseHigh = peripheral.Transmit((byte)(dataToSlave >> 8)); 398 var responseLow = peripheral.Transmit((byte)dataToSlave); 399 dataFromSlave = (ushort)((responseHigh << 8) | responseLow); 400 break; 401 } 402 403 default: 404 throw new ArgumentException($"Unexpected transfer size {FrameSize}"); 405 } 406 407 this.Log(LogLevel.Noisy, "Sent 0x{0:X}, received 0x{1:X}", dataToSlave, dataFromSlave); 408 409 if(!writeToFifo) 410 { 411 continue; 412 } 413 414 lock(innerLock) 415 { 416 receiveBuffer.Enqueue(dataFromSlave); 417 if(receiveBuffer.Count > receiveThreshold) 418 { 419 receiveFull.Value = true; 420 UpdateInterrupt(); 421 } 422 } 423 } 424 } 425 EnqueueToTransmitBuffer(ushort val)426 private void EnqueueToTransmitBuffer(ushort val) 427 { 428 if(transmitBuffer.Count == transmitDepth) 429 { 430 this.Log(LogLevel.Warning, "Trying to write to a full FIFO. Dropping the data"); 431 transmitOverflow.Value = true; 432 UpdateInterrupt(); 433 return; 434 } 435 436 transmitBuffer.Enqueue(val); 437 438 if(transmitBuffer.Count <= transmitThreshold) 439 { 440 transmitEmpty.Value = true; 441 UpdateInterrupt(); 442 } 443 } 444 TryDecodeSlaveId(SlaveSelect val, out int id)445 private bool TryDecodeSlaveId(SlaveSelect val, out int id) 446 { 447 switch(val) 448 { 449 case SlaveSelect.Slave1: 450 id = 1; 451 return true; 452 case SlaveSelect.Slave2: 453 id = 2; 454 return true; 455 case SlaveSelect.Slave3: 456 id = 3; 457 return true; 458 case SlaveSelect.None: 459 id = 0; 460 return true; 461 default: 462 this.Log(LogLevel.Warning, "Unexpected Slave Select (SER) value: 0x{0:X}", val); 463 id = -1; 464 return false; 465 } 466 } 467 ClearBuffers()468 private void ClearBuffers() 469 { 470 lock(innerLock) 471 { 472 receiveBuffer.DequeueAll(); 473 transmitBuffer.DequeueAll(); 474 475 transmitEmpty.Value = true; 476 receiveFull.Value = false; 477 UpdateInterrupt(); 478 } 479 } 480 481 public long Size => 0x400; 482 483 public GPIO IRQ { get; private set; } = new GPIO(); 484 485 public TransferSize FrameSize { get; private set; } 486 487 private uint transmitThreshold; 488 private uint receiveThreshold; 489 490 private IValueRegisterField dataFrameSize; 491 private IEnumRegisterField<TransferMode> transferMode; 492 private IValueRegisterField numberOfFrames; 493 private IFlagRegisterField enabled; 494 495 private IFlagRegisterField multiMasterContentionMask; 496 private IFlagRegisterField receiveFullMask; 497 private IFlagRegisterField receiveOverflowMask; 498 private IFlagRegisterField receiveUnderflowMask; 499 private IFlagRegisterField transmitOverflowMask; 500 private IFlagRegisterField transmitEmptyMask; 501 502 private IFlagRegisterField multiMasterContention; // this IRQ is never set in the current implementation 503 private IFlagRegisterField receiveFull; 504 private IFlagRegisterField receiveOverflow; 505 private IFlagRegisterField receiveUnderflow; 506 private IFlagRegisterField transmitOverflow; 507 private IFlagRegisterField transmitEmpty; 508 509 private readonly uint transmitDepth; 510 511 // a single frame can have up to 16-bits 512 private readonly Queue<ushort> receiveBuffer; 513 private readonly Queue<ushort> transmitBuffer; 514 515 private readonly DoubleWordRegisterCollection registersCollection; 516 private readonly object innerLock = new object(); 517 518 public enum TransferSize 519 { 520 SingleByte = 0, 521 DoubleByte = 1 522 } 523 524 private enum TransferMode 525 { 526 TransmitReceive = 0x0, 527 Transmit = 0x1, 528 Receive = 0x2, 529 EEPROM = 0x3, 530 } 531 532 private enum SlaveSelect 533 { 534 None = 0, 535 Slave1 = 1, 536 Slave2 = 2, 537 Slave3 = 4 538 } 539 540 private enum Registers 541 { 542 Control0 = 0x0, 543 Control1 = 0x4, 544 Enable = 0x8, 545 SlaveSelect = 0x10, 546 ClockDivider = 0x14, 547 TransmitTreshold = 0x18, 548 ReceiveTreshold = 0x1C, 549 TransmitLevel = 0x20, 550 ReceiveLevel = 0x24, 551 Status = 0x28, 552 InterruptMask = 0x2C, 553 InterruptStatus = 0x30, 554 InterruptRawStatus = 0x34, 555 TransmitOverflowInterruptClear = 0x38, 556 ReceiveOverflowInterruptClear = 0x3C, 557 ReceiveUnderflowInterruptClear = 0x40, 558 MultiMasterContentionInterruptClear = 0x44, 559 InterruptClear = 0x48, 560 DeviceIdentificationCode = 0x58, 561 SynopsisComponentVersion = 0x5C, 562 DataRegister = 0x60, 563 } 564 } 565 } 566