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 System.Linq; 10 11 using Antmicro.Renode.Core; 12 using Antmicro.Renode.Core.Structure; 13 using Antmicro.Renode.Core.Structure.Registers; 14 using Antmicro.Renode.Debugging; 15 using Antmicro.Renode.Logging; 16 using Antmicro.Renode.Peripherals.Bus; 17 using Antmicro.Renode.Utilities; 18 19 namespace Antmicro.Renode.Peripherals.SPI 20 { 21 public class IMXRT_FlexSPI : NullRegistrationPointPeripheralContainer<ISPIPeripheral>, IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize 22 { IMXRT_FlexSPI(IMachine machine)23 public IMXRT_FlexSPI(IMachine machine) : base(machine) 24 { 25 IRQ = new GPIO(); 26 RegistersCollection = new DoubleWordRegisterCollection(this); 27 lutMemory = new byte[NumberOfLUTs * 4]; 28 29 rxQueue = new RandomAccessQueue(FifoDepth * 4); 30 txQueue = new RandomAccessQueue(FifoDepth * 4); 31 32 commandsEngine = new CommandsEngine(this); 33 34 DefineRegisters(); 35 UpdateInterrupts(); 36 } 37 Reset()38 public override void Reset() 39 { 40 Array.Clear(lutMemory, 0, lutMemory.Length); 41 42 rxQueue.Reset(); 43 txQueue.Reset(); 44 45 isInTransmit = false; 46 totalReadCounter = 0; 47 48 RegistersCollection.Reset(); 49 commandsEngine.Reset(); 50 51 UpdateInterrupts(); 52 } 53 54 [ConnectionRegion("ciphertext")] ReadDoubleWordFromCiphertext(long offset)55 public uint ReadDoubleWordFromCiphertext(long offset) 56 { 57 return ReadFromCiphertext(offset, 4); 58 } 59 60 [ConnectionRegion("ciphertext")] WriteDoubleWordToCiphertext(long offset, uint value)61 public void WriteDoubleWordToCiphertext(long offset, uint value) 62 { 63 WriteToCiphertext(offset, value, 4); 64 } 65 66 [ConnectionRegion("ciphertext")] ReadWordFromCiphertext(long offset)67 public ushort ReadWordFromCiphertext(long offset) 68 { 69 return (ushort)ReadFromCiphertext(offset, 2); 70 } 71 72 [ConnectionRegion("ciphertext")] WriteWordToCiphertext(long offset, ushort value)73 public void WriteWordToCiphertext(long offset, ushort value) 74 { 75 WriteToCiphertext(offset, value, 2); 76 } 77 78 [ConnectionRegion("ciphertext")] ReadByteFromCiphertext(long offset)79 public byte ReadByteFromCiphertext(long offset) 80 { 81 return (byte)ReadFromCiphertext(offset, 1); 82 } 83 84 [ConnectionRegion("ciphertext")] WriteByteToCiphertext(long offset, byte value)85 public void WriteByteToCiphertext(long offset, byte value) 86 { 87 WriteToCiphertext(offset, value, 1); 88 } 89 ReadDoubleWord(long offset)90 public uint ReadDoubleWord(long offset) 91 { 92 return RegistersCollection.Read(offset); 93 } 94 WriteDoubleWord(long offset, uint value)95 public void WriteDoubleWord(long offset, uint value) 96 { 97 RegistersCollection.Write(offset, value); 98 } 99 100 public long Size => 0x4000; 101 102 public GPIO IRQ { get; } 103 104 public DoubleWordRegisterCollection RegistersCollection { get; } 105 ReadFromCiphertext(long offset, int width)106 private uint ReadFromCiphertext(long offset, int width) 107 { 108 DebugHelper.Assert(width > 0 && width <= 4); 109 110 // here we set parameters for the read command 111 // that will be executed by the commands engine 112 // note: this overwrites values in registers; not sure if this is how the actual HW works 113 dataSize.Value = (uint)width; 114 rxQueue.Reset(); 115 serialFlashAddress.Value = (uint)offset; 116 117 commandsEngine.LoadCommands((uint)ahbReadSequenceIndex.Value, (uint)ahbReadSequenceLength.Value + 1); 118 commandsEngine.Execute(); 119 120 var result = rxQueue.Read(0, width); 121 122 this.Log(LogLevel.Debug, "Read {0}-byte{1} from ciphertext at offset 0x{2:X}: 0x{3:X}", width, width == 1 ? string.Empty : "s", offset, result); 123 124 return result; 125 } 126 WriteToCiphertext(long offset, uint value, int width)127 private void WriteToCiphertext(long offset, uint value, int width) 128 { 129 DebugHelper.Assert(width > 0 && width <= 4); 130 this.Log(LogLevel.Debug, "Writing {0}-byte{1} to ciphertext at offset 0x{2:X}: 0x{3:X}", width, width == 1 ? string.Empty : "s", offset, value); 131 132 // here we set parameters for the write command 133 // that will be executed by the commands engine 134 // note: this overwrites values in registers; not sure if this is how the actual HW works 135 dataSize.Value = (uint)width; 136 var count = txQueue.Fill(BitConverter.GetBytes(value).Take(width), reset: true); 137 if(count != width) 138 { 139 this.Log(LogLevel.Warning, "Could not fit all bytes into FIFO - {0} of them were dropped", width - count); 140 } 141 142 serialFlashAddress.Value = (uint)offset; 143 144 commandsEngine.LoadCommands((uint)ahbWriteSequenceIndex.Value, (uint)ahbWriteSequenceLength.Value + 1); 145 commandsEngine.Execute(); 146 TryPushData(); 147 } 148 DefineRegisters()149 private void DefineRegisters() 150 { 151 Registers.StatusRegister0.Define(this) 152 .WithFlag(0, FieldMode.Read, name: "SEQIDLE - Command sequence idle ", valueProviderCallback: _ => !commandsEngine.InProgress) 153 .WithFlag(1, FieldMode.Read, name: "ARBIDLE - Arbitrator idle", valueProviderCallback: _ => true) // when false: there is command sequence granted by arbitrator and not finished yet on FlexSPI interface 154 .WithTag("ARBCMDSRC", 2, 2) 155 .WithReservedBits(4, 28); 156 157 Registers.IPCommandRegister.Define(this) 158 .WithFlag(0, name: "TRG", writeCallback: (_, val) => 159 { 160 if(val) 161 { 162 TriggerCommand(); 163 } 164 }) 165 .WithReservedBits(1, 31); 166 167 Registers.IPControlRegister0.Define(this) 168 .WithValueField(0, 32, out serialFlashAddress, name: "SFAR - Serial Flash Address for IP command"); 169 170 Registers.IPControlRegister1.Define(this) 171 .WithValueField(0, 16, out dataSize, name: "IDATSZ - Flash Read/Program Data Size (in bytes) for IP command") 172 .WithValueField(16, 4, out sequenceIndex, name: "ISEQID - Sequence Index in LUT for IP command") 173 .WithReservedBits(20, 4) 174 .WithValueField(24, 3, out sequenceNumber, name: "ISEQNUM - Sequence Number for IP command: ISEQNUM+1") 175 .WithReservedBits(27, 4) 176 .WithTaggedFlag("IPAREN - Parallel mode Enabled for IP command", 31); 177 178 Registers.LUT0.DefineMany(this, NumberOfLUTs, (register, idx) => 179 { 180 var j = idx; 181 register. 182 WithValueFields(0, 8, 4, 183 valueProviderCallback: (i, _) => lutMemory[j * 0x4 + i], 184 writeCallback: (i, _, value) => lutMemory[j * 0x4 + i] = (byte)value); 185 }); 186 187 Registers.IPRXFIFOControlRegister.Define(this) 188 .WithFlag(0, name: "CLRIPRXF - Clear all valid data entries in IP RX FIFO", 189 valueProviderCallback: _ => false, // this is not explicitly stated in the documentation 190 writeCallback: (_, val) => { if(val) rxQueue.Reset(); }) 191 .WithTaggedFlag("RXDMAEN - IP RX FIFO reading by DMA enabled", 1) 192 .WithValueField(2, 4, out rxWatermark, name: "RXWMRK - Watermark level") 193 .WithReservedBits(6, 26) 194 .WithWriteCallback((_, __) => UpdateInterrupts()); 195 196 Registers.IPTXFIFOControlRegister.Define(this) 197 .WithFlag(0, name: "CLRIPTXF - Clear all valid data entries in IP TX FIFO", 198 valueProviderCallback: _ => false, // this is not explicitly stated in the documentation 199 writeCallback: (_, val) => { if(val) txQueue.Reset(); }) 200 .WithTaggedFlag("TXDMAEN - IP TX FIFO reading by DMA enabled", 1) 201 .WithValueField(2, 4, out txWatermark, name: "TXWMRK - Watermark level") 202 .WithReservedBits(6, 26) 203 .WithWriteCallback((_, __) => UpdateInterrupts()); 204 205 Registers.InterruptRegister.Define(this) 206 .WithFlag(0, out ipCommandDone, FieldMode.Read | FieldMode.WriteOneToClear, name: "IPCMDDONE - IP triggered Command Sequences Execution finished interrupt") 207 .WithTaggedFlag("AHBCMDERR - AHB triggered Command Sequences Error Detected interrupt", 1) 208 .WithTaggedFlag("IPCMDGE - IP triggered Command Sequences Grant Timeout interrupt", 2) 209 .WithTaggedFlag("AHBCMDGE - AHB triggered Command Sequences Grant Timeout interrupt", 3) 210 .WithTaggedFlag("IPCMDERR - IP triggered Command Sequences Error Detected interrupt", 4) 211 .WithFlag(5, out ipRxWatermarkAvailable, FieldMode.Read | FieldMode.WriteOneToClear, name: "IPRXWA - IP RX FIFO watermark available interrupt") 212 .WithFlag(6, out ipTxWatermarkEmpty, FieldMode.Read | FieldMode.WriteOneToClear, name: "IPTXWE - IP TX FIFO watermark empty interrupt", writeCallback: (_, val) => { if(val) TryPushData(); }) 213 .WithReservedBits(7, 1) 214 .WithTaggedFlag("SEQTIMEOUT - Sequence execution timeout interrupt", 8) 215 .WithTaggedFlag("SCKSTOPBYRD - SCLK is stopped during command sequence because Async RX FIFO full interrupt", 9) 216 .WithTaggedFlag("SCKSTOPBYWR - SCLK is stopped during command sequence because Async TX FIFO empty interrupt", 10) 217 .WithTaggedFlag("AHBBUSTIMEOUT - AHB Bus timeout interrupt", 11) 218 .WithReservedBits(12, 20) 219 .WithWriteCallback((_, __) => UpdateInterrupts()); 220 221 Registers.InterruptEnableRegister.Define(this) 222 .WithFlag(0, out ipCommandDoneEnabled, name: "IPCMDDONEEN - IP triggered Command Sequences Execution finished interrupt enable") 223 .WithTaggedFlag("AHBCMDERREN - AHB triggered Command Sequences Error Detected interrupt enable", 1) 224 .WithTaggedFlag("IPCMDGEEN - IP triggered Command Sequences Grant Timeout interrupt enable", 2) 225 .WithTaggedFlag("AHBCMDGEEN - AHB triggered Command Sequences Grant Timeout interrupt enable", 3) 226 .WithTaggedFlag("IPCMDERREN - IP triggered Command Sequences Error Detected interrupt enable", 4) 227 .WithFlag(5, out ipRxWatermarkAvailableEnabled, name: "IPRXWAEN - IP RX FIFO watermark available interrupt enable") 228 .WithFlag(6, out ipTxWatermarkEmptyEnabled, name: "IPTXWEEN - IP TX FIFO watermark empty interrupt enable") 229 .WithReservedBits(7, 1) 230 .WithTaggedFlag("SEQTIMEOUTEN - Sequence execution timeout interrupt enable", 8) 231 .WithTaggedFlag("SCKSTOPBYRDEN - SCLK is stopped during command sequence because Async RX FIFO full interrupt enable", 9) 232 .WithTaggedFlag("SCKSTOPBYWREN - SCLK is stopped during command sequence because Async TX FIFO empty interrupt enable", 10) 233 .WithTaggedFlag("AHBBUSTIMEOUTEN - AHB Bus timeout interrupt enable", 11) 234 .WithReservedBits(12, 20) 235 .WithWriteCallback((_, __) => UpdateInterrupts()); 236 237 Registers.IPRXFIFOStatusRegister.Define(this) 238 .WithValueField(0, 8, FieldMode.Read, name: "FILL - Fill level of IP RX FIFO", valueProviderCallback: _ => (uint)rxQueue.FillLevel) 239 .WithReservedBits(8, 8) 240 .WithTag("RDCNTR - Total Read Data Counter", 16, 16); 241 242 Registers.IPRXFIFODataRegister0.DefineMany(this, FifoDepth, (register, idx) => 243 { 244 var j = idx; 245 register 246 .WithValueField(0, 32, FieldMode.Read, name: "RXDATA", valueProviderCallback: _ => 247 { 248 totalReadCounter += 4; 249 return rxQueue.Read(4 * j); 250 }); 251 }); 252 253 Registers.IPTXFIFODataRegister0.DefineMany(this, FifoDepth, (register, idx) => 254 { 255 var j = idx; 256 register 257 .WithValueField(0, 32, FieldMode.Write, name: "TXDATA", writeCallback: (_, val) => 258 { 259 // since the position is based on the registed id 260 // there is no possiblity of running out of the buffer 261 txQueue.Fill(position: 4 * j, data: new [] 262 { 263 (byte)(val >> 24), 264 (byte)(val >> 16), 265 (byte)(val >> 8), 266 (byte)(val) 267 }); 268 UpdateInterrupts(); 269 }); 270 }); 271 272 Registers.FlashA1ControlRegister2.Define(this) 273 .WithValueField(0, 4, out ahbReadSequenceIndex, name: "ARDSEQID - Sequence Index for AHB Read triggered Command in LUT") 274 .WithReservedBits(4, 1) 275 .WithValueField(5, 3, out ahbReadSequenceLength, name: "ARDSEQNUM - Sequence Number for AHB Read triggered Command in LUT") 276 .WithValueField(8, 4, out ahbWriteSequenceIndex, name: "AWRSEQID - Sequence Index for AHB Write triggered Command") 277 .WithReservedBits(12, 1) 278 .WithValueField(13, 3, out ahbWriteSequenceLength, name: "AWRSEQNUM - Sequence Number for AHB Write triggered Command") 279 .WithTag("AWRWRITE", 16, 12) 280 .WithTag("AWRWAITUNIT", 28, 3) 281 .WithTag("CLRINSTRPTR", 31, 1); 282 } 283 TryPushData()284 private bool TryPushData() 285 { 286 lock(txQueue) 287 { 288 if(!isInTransmit) 289 { 290 // it's fine to just return without issuing a warning; 291 // the transmit process is multi-step and there might 292 // be different ordering of operations 293 return false; 294 } 295 296 this.Log(LogLevel.Debug, "Trying to push data to the device"); 297 if(!TryGetDevice(out var device)) 298 { 299 this.Log(LogLevel.Warning, "Tried to push data to the device, but nothing is connected"); 300 return false; 301 } 302 303 var dequeuedBytes = txQueue.Dequeue((int)dataSize.Value); 304 if(dequeuedBytes.Length == 0) 305 { 306 this.Log(LogLevel.Warning, "Tried to push data to the device, but there is nothing in the queue"); 307 return false; 308 } 309 310 this.Log(LogLevel.Debug, "Pushing {0} bytes of data to the device", dequeuedBytes.Length); 311 312 foreach(var b in dequeuedBytes) 313 { 314 device.Transmit(b); 315 } 316 317 dataSize.Value -= (uint)dequeuedBytes.Length; 318 UpdateInterrupts(); 319 320 if(dataSize.Value == 0) 321 { 322 this.Log(LogLevel.Debug, "Programming finished"); 323 isInTransmit = false; 324 if(commandsEngine.InProgress) 325 { 326 // execute the rest of commands 327 commandsEngine.Execute(); 328 } 329 } 330 else 331 { 332 this.Log(LogLevel.Debug, "There is {0} more bytes to send left", dataSize.Value); 333 } 334 335 return true; 336 } 337 } 338 TryGetDevice(out ISPIPeripheral device)339 private bool TryGetDevice(out ISPIPeripheral device) 340 { 341 device = RegisteredPeripheral; 342 if(device == null) 343 { 344 this.Log(LogLevel.Warning, "No device connected"); 345 return false; 346 } 347 348 return true; 349 } 350 TriggerCommand()351 private void TriggerCommand() 352 { 353 if(commandsEngine.InProgress) 354 { 355 this.Log(LogLevel.Warning, "Tried to trigger a command, but the previous one is still in progress"); 356 return; 357 } 358 359 // sequenceNumber's value in register is 1 less than the actual value 360 commandsEngine.LoadCommands((uint)sequenceIndex.Value, (uint)sequenceNumber.Value + 1); 361 commandsEngine.Execute(); 362 } 363 UpdateInterrupts()364 private void UpdateInterrupts() 365 { 366 var flag = false; 367 368 ipTxWatermarkEmpty.Value = txQueue.EmptyLevel >= (int)txWatermark.Value; 369 ipRxWatermarkAvailable.Value = rxQueue.FillLevel >= (int)rxWatermark.Value; 370 371 flag |= ipCommandDone.Value && ipCommandDoneEnabled.Value; 372 flag |= ipTxWatermarkEmpty.Value && ipTxWatermarkEmptyEnabled.Value; 373 flag |= ipRxWatermarkAvailable.Value && ipRxWatermarkAvailableEnabled.Value; 374 375 this.Log(LogLevel.Debug, "Setting IRQ flag to {0}", flag); 376 IRQ.Set(flag); 377 } 378 379 private IValueRegisterField sequenceIndex; 380 private IValueRegisterField sequenceNumber; 381 private IValueRegisterField dataSize; 382 383 private IValueRegisterField ahbWriteSequenceIndex; 384 private IValueRegisterField ahbWriteSequenceLength; 385 386 private IValueRegisterField ahbReadSequenceIndex; 387 private IValueRegisterField ahbReadSequenceLength; 388 389 private IValueRegisterField serialFlashAddress; 390 391 private IFlagRegisterField ipCommandDone; 392 private IFlagRegisterField ipCommandDoneEnabled; 393 394 private IFlagRegisterField ipRxWatermarkAvailable; 395 private IFlagRegisterField ipRxWatermarkAvailableEnabled; 396 397 private IFlagRegisterField ipTxWatermarkEmpty; 398 private IFlagRegisterField ipTxWatermarkEmptyEnabled; 399 400 private IValueRegisterField rxWatermark; 401 private IValueRegisterField txWatermark; 402 403 private bool isInTransmit; 404 private uint totalReadCounter; 405 406 private readonly CommandsEngine commandsEngine; 407 private readonly RandomAccessQueue txQueue; 408 private readonly RandomAccessQueue rxQueue; 409 private readonly byte[] lutMemory; 410 411 private const int NumberOfLUTs = 64; 412 private const int SequenceLength = 8; 413 private const int FifoDepth = 32; 414 415 private class CommandsEngine 416 { CommandsEngine(IMXRT_FlexSPI parent)417 public CommandsEngine(IMXRT_FlexSPI parent) 418 { 419 this.parent = parent; 420 descriptors = new List<IPCommandDescriptor>(); 421 } 422 Reset()423 public void Reset() 424 { 425 currentCommand = 0; 426 descriptors.Clear(); 427 } 428 LoadCommands(uint index, uint number)429 public void LoadCommands(uint index, uint number) 430 { 431 if(currentCommand != descriptors.Count) 432 { 433 parent.Log(LogLevel.Warning, "Loading new commands, but there are some left"); 434 descriptors.Clear(); 435 currentCommand = 0; 436 } 437 438 for(var i = 0u; i < number; i++) 439 { 440 foreach(var cmd in DecodeCommands(index + i)) 441 { 442 descriptors.Add(cmd); 443 } 444 } 445 } 446 Execute()447 public void Execute() 448 { 449 if(currentCommand == descriptors.Count) 450 { 451 // there is nothing more to do 452 InProgress = false; 453 return; 454 } 455 456 if(!parent.TryGetDevice(out var device)) 457 { 458 return; 459 } 460 461 InProgress = true; 462 while(currentCommand < descriptors.Count) 463 { 464 if(!HandleCommand(descriptors[currentCommand++], device)) 465 { 466 // come commands (e.g. write) are multi-step 467 // and do not finish right away; 468 // we need to exit the execution loop and wait 469 // for them to complete before handling the next 470 // command 471 return; 472 } 473 } 474 InProgress = false; 475 } 476 477 public bool InProgress { get; private set; } 478 DecodeCommands(uint sequenceIndex)479 private IEnumerable<IPCommandDescriptor> DecodeCommands(uint sequenceIndex) 480 { 481 var result = new List<IPCommandDescriptor>(); 482 var startingIndex = sequenceIndex * 0x10; 483 484 parent.Log(LogLevel.Debug, "Decoding command at starting index: {0}", startingIndex); 485 486 for(var i = 0; i < SequenceLength; i++) 487 { 488 var currentIndex = startingIndex + (2 * i); 489 var instr = (short)((parent.lutMemory[currentIndex + 1] << 8) + parent.lutMemory[currentIndex]); 490 var cmd = DecodeCommand(instr); 491 result.Add(cmd); 492 493 if(cmd.Command == IPCommand.Stop) 494 { 495 break; 496 } 497 } 498 return result; 499 } 500 DecodeCommand(short instr)501 private IPCommandDescriptor DecodeCommand(short instr) 502 { 503 return new IPCommandDescriptor 504 { 505 Command = (IPCommand)(instr >> 10), 506 NumberOfPaddings = (instr >> 8) & 0x3, 507 Operand = (byte)instr 508 }; 509 } 510 ReadFromDevice(ISPIPeripheral device, int count)511 private byte[] ReadFromDevice(ISPIPeripheral device, int count) 512 { 513 var result = new byte[count]; 514 for(var i = 0; i < result.Length; i++) 515 { 516 // send a dummy byte 517 result[i] = device.Transmit(0); 518 } 519 520 return result; 521 } 522 HandleCommand(IPCommandDescriptor cmd, ISPIPeripheral device)523 private bool HandleCommand(IPCommandDescriptor cmd, ISPIPeripheral device) 524 { 525 var result = true; 526 parent.Log(LogLevel.Debug, "About to execute command {0}", cmd); 527 528 switch(cmd.Command) 529 { 530 case IPCommand.TransmitCommand_SDR: 531 device.Transmit(cmd.Operand); 532 break; 533 534 case IPCommand.ReceiveReadData_SDR: 535 { 536 var dataCount = (parent.dataSize.Value == 0) 537 ? cmd.Operand 538 : parent.dataSize.Value; 539 540 var data = ReadFromDevice(device, (int)dataCount); 541 var count = parent.rxQueue.Enqueue(data); 542 if(count != data.Length) 543 { 544 parent.Log(LogLevel.Warning, "There is no more space left in the RX queue. {0} bytes were dropped", data.Length - count); 545 } 546 } 547 break; 548 549 case IPCommand.Stop: 550 { 551 device.FinishTransmission(); 552 parent.ipCommandDone.Value = true; 553 parent.UpdateInterrupts(); 554 } 555 break; 556 557 558 case IPCommand.TransmitProgrammingData_SDR: 559 { 560 parent.isInTransmit = true; 561 // note: parent operation breaks execution of the command 562 // waiting for the data to be written to FIFO 563 result = false; 564 } 565 break; 566 567 case IPCommand.TransmitRowAddress_SDR: 568 { 569 var a0 = (byte)(parent.serialFlashAddress.Value); 570 var a1 = (byte)(parent.serialFlashAddress.Value >> 8); 571 var a2 = (byte)(parent.serialFlashAddress.Value >> 16); 572 device.Transmit(a2); 573 device.Transmit(a1); 574 device.Transmit(a0); 575 } 576 break; 577 578 default: 579 parent.Log(LogLevel.Info, "Unsupported IP command: {0}", cmd); 580 break; 581 } 582 583 return result; 584 } 585 586 private int currentCommand; 587 588 private readonly IMXRT_FlexSPI parent; 589 private readonly List<IPCommandDescriptor> descriptors; 590 } 591 592 private class RandomAccessQueue 593 { RandomAccessQueue(int size)594 public RandomAccessQueue(int size) 595 { 596 internalBuffer = new byte[size]; 597 } 598 Reset()599 public void Reset() 600 { 601 FillLevel = 0; 602 Array.Clear(internalBuffer, 0, internalBuffer.Length); 603 } 604 Read(int position, int width = 4)605 public uint Read(int position, int width = 4) 606 { 607 DebugHelper.Assert(width > 0 && width <= 4); 608 609 if(position >= FillLevel) 610 { 611 return 0; 612 } 613 return BitHelper.ToUInt32(internalBuffer, position, Math.Min(width, FillLevel - position), true); 614 } 615 Dequeue(int maxCount)616 public byte[] Dequeue(int maxCount) 617 { 618 var bytesToDequeue = Math.Min(FillLevel, maxCount); 619 var result = new byte[bytesToDequeue]; 620 621 Array.Copy(internalBuffer, 0, result, 0, result.Length); 622 623 var bytesLeft = FillLevel - bytesToDequeue; 624 for(int i = 0; i < bytesLeft; i++) 625 { 626 internalBuffer[i] = internalBuffer[i + bytesToDequeue]; 627 } 628 629 FillLevel = bytesLeft; 630 return result; 631 } 632 Enqueue(byte[] bs)633 public int Enqueue(byte[] bs) 634 { 635 var counter = 0; 636 foreach(var b in bs) 637 { 638 if(FillLevel == internalBuffer.Length) 639 { 640 break; 641 } 642 643 internalBuffer[FillLevel++] = b; 644 counter++; 645 } 646 647 return counter; 648 } 649 Fill(IEnumerable<byte> data, bool reset = false, int position = -1)650 public int Fill(IEnumerable<byte> data, bool reset = false, int position = -1) 651 { 652 var counter = 0; 653 if(reset) 654 { 655 FillLevel = 0; 656 } 657 658 var idx = (position >= 0) 659 ? position 660 : FillLevel; 661 662 foreach(var d in data) 663 { 664 if(idx >= internalBuffer.Length) 665 { 666 break; 667 } 668 internalBuffer[idx++] = d; 669 counter++; 670 } 671 672 FillLevel = Math.Max(FillLevel, idx); 673 674 return counter; 675 } 676 677 public int FillLevel { get; private set; } 678 public int EmptyLevel => internalBuffer.Length - FillLevel; 679 680 private readonly byte[] internalBuffer; 681 } 682 683 private struct IPCommandDescriptor 684 { 685 public IPCommand Command; 686 public int NumberOfPaddings; 687 public byte Operand; 688 ToStringAntmicro.Renode.Peripherals.SPI.IMXRT_FlexSPI.IPCommandDescriptor689 public override string ToString() 690 { 691 return $"[IPCommandDescriptor: {Command} (0x{Command:X}), NumberOfPaddings: {NumberOfPaddings}, Operand: 0x{Operand:X}]"; 692 } 693 } 694 695 private enum IPCommand 696 { 697 TransmitCommand_SDR = 0x1, // CMD_SDR 698 TransmitCommand_DDR = 0x21, // CMD_DDR 699 700 TransmitRowAddress_SDR = 0x2, // RADDR_SDR 701 TransmitRowAddress_DDR = 0x22, // RADDR_DDR 702 703 TransmitColumnAddress_SDR = 0x3, // CADDR_SDR 704 TransmitColumnAddress_DDR = 0x23, // CADDR_SDR 705 706 TransmitModeBits1_SDR = 0x4, // MODE1_SDR 707 TransmitModeBits1_DDR = 0x24, // MODE1_DDR 708 709 TransmitModeBits2_SDR = 0x5, // MODE2_SDR 710 TransmitModeBits2_DDR = 0x25, // MODE2_DDR 711 712 TransmitModeBits4_SDR = 0x6, // MODE4_SDR 713 TransmitModeBits4_DDR = 0x26, // MODE4_DDR 714 715 TransmitModeBits8_SDR = 0x7, // MODE8_SDR 716 TransmitModeBits8_DDR = 0x27, // MODE8_DDR 717 718 TransmitProgrammingData_SDR = 0x8, // WRITE_SDR 719 TransmitProgrammingData_DDR = 0x28, // WRITE_DDR 720 721 ReceiveReadData_SDR = 0x9, // READ_SDR 722 ReceiveReadData_DDR = 0x29, // READ_DDR 723 724 ReceiveReadDataOrPreamble_SDR = 0xa, // LEARN_SDR 725 ReceiveReadDataOrPreamble_DDR = 0x2a, // LEARN_DDR 726 727 DataSize_SDR = 0xb, // DATASZ_SDR 728 DataSize_DDR = 0x2b, // DATASZ_DDR 729 730 Dummy_SDR = 0xc, // DUMMY_SDR 731 Dummy_DDR = 0x2c, // DUMMY_DDR 732 733 DummyRWDS_SDR = 0xd, // DUMMY_RWDS_SDR 734 DummyRWDS_DDR = 0x2d, // DUMMY_RWDS_DDR 735 736 JumpOnCS = 0x1F, // JMP_ON_CS 737 Stop = 0x00, // STOP 738 } 739 740 private enum Registers : long 741 { 742 ModuleControlRegister0 = 0x0, // (MCR0) 32 RW FFFF_80C2h 743 ModuleControlRegister1 = 0x4, // (MCR1) 32 RW FFFF_FFFFh 744 ModuleControlRegister2 = 0x8, // (MCR2) 32 RW 2000_81F7h 745 AHBBusControlRegister = 0xC, // (AHBCR) 32 RW 0000_0018h 746 InterruptEnableRegister = 0x10, // (INTEN) 32 RW 0000_0000h 747 InterruptRegister = 0x14, // (INTR) 32 RW 0000_0000h 748 LUTKeyRegister = 0x18, //(LUTKEY) 32 RW 5AF0_5AF0h 749 LUTControlRegister = 0x1C, //(LUTCR) 32 RW 0000_0002h 750 AHBRXBuffer0ControlRegister0 = 0x20, //(AHBRXBUF0CR0) 32 RW 8000_0020h 751 AHBRXBuffer1ControlRegister0 = 0x24, //(AHBRXBUF1CR0) 32 RW 8001_0020h 752 AHBRXBuffer2ControlRegister0 = 0x28, //(AHBRXBUF2CR0) 32 RW 8002_0020h 753 AHBRXBuffer3ControlRegister0 = 0x2C, //(AHBRXBUF3CR0) 32 RW 8003_0020h 754 FlashA1ControlRegister0 = 0x60, //(FLSHA1CR0) 32 RW 0001_0000h 755 FlashA2ControlRegister0 = 0x64, //(FLSHA2CR0) 32 RW 0001_0000h 756 FlashB1ControlRegister0 = 0x68, //(FLSHB1CR0) 32 RW 0001_0000h 757 FlashB2ControlRegister0 = 0x6C, //(FLSHB2CR0) 32 RW 0001_0000h 758 FlashA1ControlRegister1 = 0x70, //(FLSHA1CR1) 32 RW 0000_0063h 759 FlashA2ControlRegister1 = 0x74, //(FLSHA2CR1) 32 RW 0000_0063h 760 FlashB1ControlRegister1 = 0x78, //(FLSHB1CR1) 32 RW 0000_0063h 761 FlashB2ControlRegister1 = 0x7C, //(FLSHB2CR1) 32 RW 0000_0063h 762 FlashA1ControlRegister2 = 0x80, //(FLSHA1CR2) 32 RW 0000_0000h 763 FlashA2ControlRegister2 = 0x84, //(FLSHA2CR2) 32 RW 0000_0000h 764 FlashB1ControlRegister2 = 0x88, //(FLSHB1CR2) 32 RW 0000_0000h 765 FlashB2ControlRegister2 = 0x8C, //(FLSHB2CR2) 32 RW 0000_0000h 766 FlashControlRegister4 = 0x94, //(FLSHCR4) 32 RW 0000_0000h 767 IPControlRegister0 = 0xA0, //(IPCR0) 32 RW 0000_0000h 768 IPControlRegister1 = 0xA4, //(IPCR1) 32 RW 0000_0000h 769 IPCommandRegister = 0xB0, //(IPCMD) 32 RW 0000_0000h 770 IPRXFIFOControlRegister = 0xB8, //(IPRXFCR) 32 RW 0000_0000h 771 IPTXFIFOControlRegister = 0xBC, //(IPTXFCR) 32 RW 0000_0000h 772 DLLAControlRegister0 = 0xC0, //(DLLACR) 32 RW 0000_0100h 773 DLLBControlRegister0 = 0xC4, //(DLLBCR) 32 RW 0000_0100h 774 StatusRegister0 = 0xE0, //(STS0) 32 RO 0000_0002h 775 StatusRegister1 = 0xE4, //(STS1) 32 RO 0000_0000h 776 StatusRegister2 = 0xE8, //(STS2) 32 RO 0100_0100h 777 AHBSuspendStatusRegister = 0xEC, //(AHBSPNDSTS) 32 RO 0000_0000h 778 IPRXFIFOStatusRegister = 0xF0, //(IPRXFSTS) 32 RO 0000_0000h 779 IPTXFIFOStatusRegister = 0xF4, //(IPTXFSTS) 32 RO 0000_0000h 780 IPRXFIFODataRegister0 = 0x100, // (RFDR0 - RFDR31) 32 RO 0000_0000h 781 IPTXFIFODataRegister0 = 0x180, 782 LUT0 = 0x200, 783 } 784 } 785 } 786