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 using System.Collections.Generic; 8 using Antmicro.Renode.Core; 9 using Antmicro.Renode.Core.Structure.Registers; 10 using Antmicro.Renode.Exceptions; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Peripherals.Memory; 13 using Antmicro.Renode.Peripherals.SPI.NORFlash; 14 using Antmicro.Renode.Utilities; 15 16 using Range = Antmicro.Renode.Core.Range; 17 18 namespace Antmicro.Renode.Peripherals.SPI 19 { 20 public class GenericSpiFlash : ISPIPeripheral, IGPIOReceiver 21 { GenericSpiFlash(MappedMemory underlyingMemory, byte manufacturerId, byte memoryType, bool writeStatusCanSetWriteEnable = true, byte extendedDeviceId = DefaultExtendedDeviceID, byte deviceConfiguration = DefaultDeviceConfiguration, byte remainingIdBytes = DefaultRemainingIDBytes, int sectorSizeKB = DefaultSectorSizeKB)22 public GenericSpiFlash(MappedMemory underlyingMemory, byte manufacturerId, byte memoryType, 23 bool writeStatusCanSetWriteEnable = true, byte extendedDeviceId = DefaultExtendedDeviceID, 24 byte deviceConfiguration = DefaultDeviceConfiguration, byte remainingIdBytes = DefaultRemainingIDBytes, 25 // "Sector" here is the largest erasable memory unit. It's also named "block" by many flash memory vendors. 26 int sectorSizeKB = DefaultSectorSizeKB) 27 { 28 if(!Misc.IsPowerOfTwo((ulong)underlyingMemory.Size)) 29 { 30 throw new ConstructionException("Size of the underlying memory must be a power of 2"); 31 } 32 33 volatileConfigurationRegister = new ByteRegister(this, 0xfb).WithFlag(3, name: "XIP"); 34 nonVolatileConfigurationRegister = new WordRegister(this, 0xffff).WithEnumField<WordRegister, AddressingMode>(0, 1, out addressingMode, name: "addressWith3Bytes"); 35 enhancedVolatileConfigurationRegister = new ByteRegister(this, 0xff) 36 .WithValueField(0, 3, name: "Output driver strength") 37 .WithReservedBits(3, 1) 38 .WithTaggedFlag("Reset/hold", 4) 39 //these flags are intentionally not implemented, as they described physical details 40 .WithFlag(5, name: "Double transfer rate protocol") 41 .WithFlag(6, name: "Dual I/O protocol") 42 .WithFlag(7, name: "Quad I/O protocol"); 43 statusRegister = new ByteRegister(this) 44 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => false, name: "writeInProgress") 45 .WithFlag(1, out enable, writeStatusCanSetWriteEnable ? FieldMode.Read | FieldMode.Write : FieldMode.Read, name: "writeEnableLatch"); 46 configurationRegister = new WordRegister(this); 47 flagStatusRegister = new ByteRegister(this) 48 .WithEnumField<ByteRegister, AddressingMode>(0, 1, FieldMode.Read, valueProviderCallback: _ => addressingMode.Value, name: "Addressing") 49 //other bits indicate either protection errors (not implemented) or pending operations (they already finished) 50 .WithReservedBits(3, 1) 51 .WithFlag(7, FieldMode.Read, valueProviderCallback: _ => true, name: "ProgramOrErase"); 52 53 sectorSize = sectorSizeKB.KB(); 54 this.underlyingMemory = underlyingMemory; 55 underlyingMemory.ResetByte = EmptySegment; 56 57 this.manufacturerId = manufacturerId; 58 this.memoryType = memoryType; 59 this.capacityCode = GetCapacityCode(); 60 this.remainingIdBytes = remainingIdBytes; 61 this.extendedDeviceId = extendedDeviceId; 62 this.deviceConfiguration = deviceConfiguration; 63 64 deviceData = GetDeviceData(); 65 SFDPSignature = GetSFDPSignature(); 66 } 67 OnGPIO(int number, bool value)68 public void OnGPIO(int number, bool value) 69 { 70 if(number == 0 && value) 71 { 72 this.Log(LogLevel.Noisy, "Chip Select is deasserted."); 73 FinishTransmission(); 74 } 75 } 76 FinishTransmission()77 public void FinishTransmission() 78 { 79 switch(currentOperation.State) 80 { 81 case DecodedOperation.OperationState.RecognizeOperation: 82 case DecodedOperation.OperationState.AccumulateCommandAddressBytes: 83 case DecodedOperation.OperationState.AccumulateNoDataCommandAddressBytes: 84 this.Log(LogLevel.Warning, "Transmission finished in the unexpected state: {0}", currentOperation.State); 85 break; 86 } 87 // If an operation has at least 1 data byte or more than 0 address bytes, 88 // we can clear the write enable flag only when we are finishing a transmission. 89 switch(currentOperation.Operation) 90 { 91 case DecodedOperation.OperationType.Program: 92 case DecodedOperation.OperationType.Erase: 93 case DecodedOperation.OperationType.WriteRegister: 94 //although the docs are not clear, it seems that all register writes should clear the flag 95 enable.Value = false; 96 break; 97 } 98 currentOperation.State = DecodedOperation.OperationState.RecognizeOperation; 99 currentOperation = default(DecodedOperation); 100 temporaryConfiguration = 0; 101 } 102 Reset()103 public void Reset() 104 { 105 statusRegister.Reset(); 106 flagStatusRegister.Reset(); 107 volatileConfigurationRegister.Reset(); 108 nonVolatileConfigurationRegister.Reset(); 109 enhancedVolatileConfigurationRegister.Reset(); 110 currentOperation = default(DecodedOperation); 111 lockedRange = null; 112 FinishTransmission(); 113 } 114 Transmit(byte data)115 public byte Transmit(byte data) 116 { 117 this.Log(LogLevel.Noisy, "Transmitting data 0x{0:X}, current state: {1}", data, currentOperation.State); 118 switch(currentOperation.State) 119 { 120 case DecodedOperation.OperationState.RecognizeOperation: 121 // When the command is decoded, depending on the operation we will either start accumulating address bytes 122 // or immediately handle the command bytes 123 RecognizeOperation(data); 124 break; 125 case DecodedOperation.OperationState.AccumulateCommandAddressBytes: 126 AccumulateAddressBytes(data, DecodedOperation.OperationState.HandleCommand); 127 break; 128 case DecodedOperation.OperationState.AccumulateNoDataCommandAddressBytes: 129 AccumulateAddressBytes(data, DecodedOperation.OperationState.HandleNoDataCommand); 130 break; 131 case DecodedOperation.OperationState.HandleCommand: 132 // Process the remaining command bytes 133 return HandleCommand(data); 134 } 135 136 // Warning: commands without data require immediate handling after the address was accumulated 137 if(currentOperation.State == DecodedOperation.OperationState.HandleNoDataCommand) 138 { 139 HandleNoDataCommand(); 140 } 141 return 0; 142 } 143 144 public MappedMemory UnderlyingMemory => underlyingMemory; 145 WriteToMemory(byte val)146 protected virtual void WriteToMemory(byte val) 147 { 148 if(!TryVerifyWriteToMemory(out var position)) 149 { 150 return; 151 } 152 underlyingMemory.WriteByte(position, val); 153 } 154 TryVerifyWriteToMemory(out long position)155 protected bool TryVerifyWriteToMemory(out long position) 156 { 157 position = currentOperation.ExecutionAddress + currentOperation.CommandBytesHandled; 158 if(position > underlyingMemory.Size) 159 { 160 this.Log(LogLevel.Error, "Cannot write to address 0x{0:X} because it is bigger than configured memory size.", currentOperation.ExecutionAddress); 161 return false; 162 } 163 if(lockedRange.HasValue && lockedRange.Value.Contains((ulong)position)) 164 { 165 this.Log(LogLevel.Error, "Cannot write to address 0x{0:X} because it is in the locked range", position); 166 return false; 167 } 168 return true; 169 } 170 GetCapacityCode()171 protected virtual byte GetCapacityCode() 172 { 173 // capacity code: 174 // 0x10 - 64 KB 175 // 0x11 - 128 KB 176 // 0x12 - 256 KB 177 // .. 178 // 0x19 - 32 MB 179 // NOTE: there is a gap between 0x19 and 0x20 180 // 0x20 - 64 MB 181 // 0x21 - 128 MB 182 // 0x22 - 256 MB 183 byte capacityCode = 0; 184 185 if(underlyingMemory.Size <= 32.MB()) 186 { 187 capacityCode = (byte)BitHelper.GetMostSignificantSetBitIndex((ulong)underlyingMemory.Size); 188 } 189 else 190 { 191 capacityCode = (byte)((BitHelper.GetMostSignificantSetBitIndex((ulong)underlyingMemory.Size) - 26) + 0x20); 192 } 193 194 return capacityCode; 195 } 196 GetSFDPSignature()197 protected virtual byte[] GetSFDPSignature() 198 { 199 return DefaultSFDPSignature; 200 } 201 GetDummyBytes(Commands command)202 protected virtual int GetDummyBytes(Commands command) 203 { 204 switch(command) 205 { 206 case Commands.FastRead: 207 return 1; 208 default: 209 return 0; 210 } 211 } 212 213 protected Range? lockedRange; 214 215 protected readonly int sectorSize; 216 protected readonly ByteRegister statusRegister; 217 protected readonly WordRegister configurationRegister; 218 protected readonly MappedMemory underlyingMemory; 219 AccumulateAddressBytes(byte addressByte, DecodedOperation.OperationState nextState)220 private void AccumulateAddressBytes(byte addressByte, DecodedOperation.OperationState nextState) 221 { 222 if(currentOperation.TryAccumulateAddress(addressByte)) 223 { 224 this.Log(LogLevel.Noisy, "Address accumulated: 0x{0:X}", currentOperation.ExecutionAddress); 225 currentOperation.State = nextState; 226 } 227 } 228 GetDeviceData()229 private byte[] GetDeviceData() 230 { 231 var data = new byte[20]; 232 data[0] = manufacturerId; 233 data[1] = memoryType; 234 data[2] = capacityCode; 235 data[3] = remainingIdBytes; 236 data[4] = extendedDeviceId; 237 data[5] = deviceConfiguration; 238 // unique ID code (bytes 7:20) 239 return data; 240 } 241 RecognizeOperation(byte firstByte)242 private void RecognizeOperation(byte firstByte) 243 { 244 currentOperation.Operation = DecodedOperation.OperationType.None; 245 currentOperation.State = DecodedOperation.OperationState.HandleCommand; 246 currentOperation.DummyBytesRemaining = GetDummyBytes((Commands)firstByte); 247 switch(firstByte) 248 { 249 case (byte)Commands.ReadID: 250 case (byte)Commands.MultipleIoReadID: 251 currentOperation.Operation = DecodedOperation.OperationType.ReadID; 252 break; 253 case (byte)Commands.ReadSerialFlashDiscoveryParameter: 254 currentOperation.Operation = DecodedOperation.OperationType.ReadSerialFlashDiscoveryParameter; 255 currentOperation.State = DecodedOperation.OperationState.AccumulateCommandAddressBytes; 256 currentOperation.AddressLength = 3; 257 break; 258 case (byte)Commands.FastRead: 259 // fast read - 3 bytes of address + a dummy byte 260 currentOperation.Operation = DecodedOperation.OperationType.ReadFast; 261 currentOperation.AddressLength = 3; 262 currentOperation.State = DecodedOperation.OperationState.AccumulateCommandAddressBytes; 263 break; 264 case (byte)Commands.Read: 265 case (byte)Commands.DualOutputFastRead: 266 case (byte)Commands.DualInputOutputFastRead: 267 case (byte)Commands.QuadOutputFastRead: 268 case (byte)Commands.QuadInputOutputFastRead: 269 case (byte)Commands.DtrFastRead: 270 case (byte)Commands.DtrDualOutputFastRead: 271 case (byte)Commands.DtrDualInputOutputFastRead: 272 case (byte)Commands.DtrQuadOutputFastRead: 273 case (byte)Commands.DtrQuadInputOutputFastRead: 274 case (byte)Commands.QuadInputOutputWordRead: 275 currentOperation.Operation = DecodedOperation.OperationType.Read; 276 currentOperation.AddressLength = NumberOfAddressBytes; 277 currentOperation.State = DecodedOperation.OperationState.AccumulateCommandAddressBytes; 278 break; 279 case (byte)Commands.Read4byte: 280 case (byte)Commands.FastRead4byte: 281 case (byte)Commands.DualOutputFastRead4byte: 282 case (byte)Commands.DualInputOutputFastRead4byte: 283 case (byte)Commands.QuadOutputFastRead4byte: 284 case (byte)Commands.QuadInputOutputFastRead4byte: 285 case (byte)Commands.DtrFastRead4byte: 286 case (byte)Commands.DtrDualInputOutputFastRead4byte: 287 case (byte)Commands.DtrQuadInputOutputFastRead4byte: 288 currentOperation.Operation = DecodedOperation.OperationType.Read; 289 currentOperation.AddressLength = 4; 290 currentOperation.State = DecodedOperation.OperationState.AccumulateCommandAddressBytes; 291 break; 292 case (byte)Commands.PageProgram: 293 case (byte)Commands.DualInputFastProgram: 294 case (byte)Commands.ExtendedDualInputFastProgram: 295 case (byte)Commands.QuadInputFastProgram: 296 case (byte)Commands.ExtendedQuadInputFastProgram: 297 currentOperation.Operation = DecodedOperation.OperationType.Program; 298 currentOperation.AddressLength = NumberOfAddressBytes; 299 currentOperation.State = DecodedOperation.OperationState.AccumulateCommandAddressBytes; 300 break; 301 case (byte)Commands.PageProgram4byte: 302 case (byte)Commands.QuadInputFastProgram4byte: 303 currentOperation.Operation = DecodedOperation.OperationType.Program; 304 currentOperation.AddressLength = 4; 305 currentOperation.State = DecodedOperation.OperationState.AccumulateCommandAddressBytes; 306 break; 307 case (byte)Commands.WriteEnable: 308 this.Log(LogLevel.Noisy, "Setting write enable latch"); 309 enable.Value = true; 310 return; //return to prevent further logging 311 case (byte)Commands.WriteDisable: 312 this.Log(LogLevel.Noisy, "Unsetting write enable latch"); 313 enable.Value = false; 314 return; //return to prevent further logging 315 case (byte)Commands.SubsectorErase4kb: 316 currentOperation.Operation = DecodedOperation.OperationType.Erase; 317 currentOperation.EraseSize = DecodedOperation.OperationEraseSize.Subsector4K; 318 currentOperation.AddressLength = NumberOfAddressBytes; 319 currentOperation.State = DecodedOperation.OperationState.AccumulateNoDataCommandAddressBytes; 320 break; 321 case (byte)Commands.SubsectorErase32kb: 322 currentOperation.Operation = DecodedOperation.OperationType.Erase; 323 currentOperation.EraseSize = DecodedOperation.OperationEraseSize.Subsector32K; 324 currentOperation.AddressLength = NumberOfAddressBytes; 325 currentOperation.State = DecodedOperation.OperationState.AccumulateNoDataCommandAddressBytes; 326 break; 327 case (byte)Commands.SectorErase: 328 currentOperation.Operation = DecodedOperation.OperationType.Erase; 329 currentOperation.EraseSize = DecodedOperation.OperationEraseSize.Sector; 330 currentOperation.AddressLength = NumberOfAddressBytes; 331 currentOperation.State = DecodedOperation.OperationState.AccumulateNoDataCommandAddressBytes; 332 break; 333 case (byte)Commands.DieErase: 334 currentOperation.Operation = DecodedOperation.OperationType.Erase; 335 currentOperation.EraseSize = DecodedOperation.OperationEraseSize.Die; 336 currentOperation.AddressLength = NumberOfAddressBytes; 337 currentOperation.State = DecodedOperation.OperationState.AccumulateNoDataCommandAddressBytes; 338 break; 339 case (byte)Commands.BulkErase: 340 case (byte)Commands.ChipErase: 341 this.Log(LogLevel.Noisy, "Performing bulk/chip erase"); 342 EraseChip(); 343 break; 344 case (byte)Commands.SubsectorErase4byte4kb: 345 currentOperation.Operation = DecodedOperation.OperationType.Erase; 346 currentOperation.EraseSize = DecodedOperation.OperationEraseSize.Subsector4K; 347 currentOperation.AddressLength = 4; 348 currentOperation.State = DecodedOperation.OperationState.AccumulateNoDataCommandAddressBytes; 349 break; 350 case (byte)Commands.SectorErase4byte: 351 currentOperation.Operation = DecodedOperation.OperationType.Erase; 352 currentOperation.EraseSize = DecodedOperation.OperationEraseSize.Sector; 353 currentOperation.AddressLength = 4; 354 currentOperation.State = DecodedOperation.OperationState.AccumulateNoDataCommandAddressBytes; 355 break; 356 case (byte)Commands.Enter4byteAddressMode: 357 this.Log(LogLevel.Noisy, "Entering 4-byte address mode"); 358 addressingMode.Value = AddressingMode.FourByte; 359 break; 360 case (byte)Commands.Exit4byteAddressMode: 361 this.Log(LogLevel.Noisy, "Exiting 4-byte address mode"); 362 addressingMode.Value = AddressingMode.ThreeByte; 363 break; 364 case (byte)Commands.ReadStatusRegister: 365 currentOperation.Operation = DecodedOperation.OperationType.ReadRegister; 366 currentOperation.Register = (uint)Register.Status; 367 break; 368 case (byte)Commands.ReadConfigurationRegister: 369 currentOperation.Operation = DecodedOperation.OperationType.ReadRegister; 370 currentOperation.Register = (uint)Register.Configuration; 371 break; 372 case (byte)Commands.WriteStatusRegister: 373 currentOperation.Operation = DecodedOperation.OperationType.WriteRegister; 374 currentOperation.Register = (uint)Register.Status; 375 break; 376 case (byte)Commands.ReadFlagStatusRegister: 377 currentOperation.Operation = DecodedOperation.OperationType.ReadRegister; 378 currentOperation.Register = (uint)Register.FlagStatus; 379 break; 380 case (byte)Commands.ReadVolatileConfigurationRegister: 381 currentOperation.Operation = DecodedOperation.OperationType.ReadRegister; 382 currentOperation.Register = (uint)Register.VolatileConfiguration; 383 break; 384 case (byte)Commands.WriteVolatileConfigurationRegister: 385 currentOperation.Operation = DecodedOperation.OperationType.WriteRegister; 386 currentOperation.Register = (uint)Register.VolatileConfiguration; 387 break; 388 case (byte)Commands.ReadNonVolatileConfigurationRegister: 389 currentOperation.Operation = DecodedOperation.OperationType.ReadRegister; 390 currentOperation.Register = (uint)Register.NonVolatileConfiguration; 391 break; 392 case (byte)Commands.WriteNonVolatileConfigurationRegister: 393 currentOperation.Operation = DecodedOperation.OperationType.WriteRegister; 394 currentOperation.Register = (uint)Register.NonVolatileConfiguration; 395 break; 396 case (byte)Commands.ReadEnhancedVolatileConfigurationRegister: 397 currentOperation.Operation = DecodedOperation.OperationType.ReadRegister; 398 currentOperation.Register = (uint)Register.EnhancedVolatileConfiguration; 399 break; 400 case (byte)Commands.WriteEnhancedVolatileConfigurationRegister: 401 currentOperation.Operation = DecodedOperation.OperationType.WriteRegister; 402 currentOperation.Register = (uint)Register.EnhancedVolatileConfiguration; 403 break; 404 case (byte)Commands.ResetEnable: 405 // This command should allow ResetMemory to be executed 406 case (byte)Commands.ResetMemory: 407 // This command should reset volatile bits in configuration registers 408 case (byte)Commands.EnterDeepPowerDown: 409 // This command should enter deep power-down mode 410 case (byte)Commands.ReleaseFromDeepPowerdown: 411 // This command should leave deep power-down mode, but some chips use a different mechanism 412 this.Log(LogLevel.Warning, "Unhandled parameterless command {0}", (Commands)firstByte); 413 return; 414 default: 415 this.Log(LogLevel.Error, "Command decoding failed on byte: 0x{0:X} ({1}).", firstByte, (Commands)firstByte); 416 return; 417 } 418 this.Log(LogLevel.Noisy, "Decoded operation: {0}, write enabled {1}", currentOperation, enable.Value); 419 } 420 HandleCommand(byte data)421 private byte HandleCommand(byte data) 422 { 423 byte result = 0; 424 if(currentOperation.DummyBytesRemaining > 0) 425 { 426 currentOperation.DummyBytesRemaining--; 427 this.Log(LogLevel.Noisy, "Handling dummy byte in {0} operation, {1} remaining after this one", 428 currentOperation.Operation, currentOperation.DummyBytesRemaining); 429 return result; 430 } 431 432 switch(currentOperation.Operation) 433 { 434 case DecodedOperation.OperationType.ReadFast: 435 case DecodedOperation.OperationType.Read: 436 result = ReadFromMemory(); 437 break; 438 case DecodedOperation.OperationType.ReadID: 439 if(currentOperation.CommandBytesHandled < deviceData.Length) 440 { 441 result = deviceData[currentOperation.CommandBytesHandled]; 442 } 443 else 444 { 445 this.Log(LogLevel.Error, "Trying to read beyond the length of the device ID table."); 446 result = 0; 447 } 448 break; 449 case DecodedOperation.OperationType.ReadSerialFlashDiscoveryParameter: 450 result = GetSFDPByte(); 451 break; 452 case DecodedOperation.OperationType.Program: 453 if(enable.Value) 454 { 455 WriteToMemory(data); 456 result = data; 457 } 458 else 459 { 460 this.Log(LogLevel.Error, "Memory write operations are disabled."); 461 } 462 break; 463 case DecodedOperation.OperationType.ReadRegister: 464 result = ReadRegister((Register)currentOperation.Register); 465 break; 466 case DecodedOperation.OperationType.WriteRegister: 467 WriteRegister((Register)currentOperation.Register, data); 468 break; 469 default: 470 this.Log(LogLevel.Warning, "Unhandled operation encountered while processing command bytes: {0}", currentOperation.Operation); 471 break; 472 } 473 currentOperation.CommandBytesHandled++; 474 this.Log(LogLevel.Noisy, "Handled command: {0}, returning 0x{1:X}", currentOperation, result); 475 return result; 476 } 477 GetSFDPByte()478 private byte GetSFDPByte() 479 { 480 if(currentOperation.ExecutionAddress >= SFDPSignature.Length) 481 { 482 this.Log(LogLevel.Warning, "Tried to read SFDP signature byte out of range at position {0}", currentOperation.ExecutionAddress); 483 return 0; 484 } 485 486 var output = SFDPSignature[currentOperation.ExecutionAddress]; 487 currentOperation.ExecutionAddress = (currentOperation.ExecutionAddress + 1) % (uint)SFDPSignature.Length; 488 return output; 489 } 490 WriteRegister(Register register, byte data)491 private void WriteRegister(Register register, byte data) 492 { 493 if(!enable.Value) 494 { 495 this.Log(LogLevel.Error, "Trying to write a register, but write enable latch is not set"); 496 return; 497 } 498 switch(register) 499 { 500 case Register.VolatileConfiguration: 501 volatileConfigurationRegister.Write(0, data); 502 break; 503 case Register.NonVolatileConfiguration: 504 case Register.Configuration: 505 if((currentOperation.CommandBytesHandled) >= 2) 506 { 507 this.Log(LogLevel.Error, "Trying to write to register {0} with more than expected 2 bytes.", register); 508 break; 509 } 510 BitHelper.UpdateWithShifted(ref temporaryConfiguration, data, currentOperation.CommandBytesHandled * 8, 8); 511 if(currentOperation.CommandBytesHandled == 1) 512 { 513 var targetReg = register == Register.Configuration ? configurationRegister : nonVolatileConfigurationRegister; 514 targetReg.Write(0, (ushort)temporaryConfiguration); 515 } 516 break; 517 //listing all cases as other registers are not writable at all 518 case Register.EnhancedVolatileConfiguration: 519 enhancedVolatileConfigurationRegister.Write(0, data); 520 break; 521 case Register.Status: 522 statusRegister.Write(0, data); 523 // Switch to the Configuration register and write from its start 524 currentOperation.Register = (uint)Register.Configuration; 525 currentOperation.CommandBytesHandled--; 526 break; 527 default: 528 this.Log(LogLevel.Warning, "Trying to write 0x{0} to unsupported register \"{1}\"", data, register); 529 break; 530 } 531 } 532 ReadRegister(Register register)533 private byte ReadRegister(Register register) 534 { 535 switch(register) 536 { 537 case Register.Status: 538 // The documentation states that at least 1 byte will be read 539 // If more than 1 byte is read, the same byte is returned 540 return statusRegister.Read(); 541 case Register.FlagStatus: 542 // The documentation states that at least 1 byte will be read 543 // If more than 1 byte is read, the same byte is returned 544 return flagStatusRegister.Read(); 545 case Register.VolatileConfiguration: 546 // The documentation states that at least 1 byte will be read 547 // If more than 1 byte is read, the same byte is returned 548 return volatileConfigurationRegister.Read(); 549 case Register.NonVolatileConfiguration: 550 case Register.Configuration: 551 // The documentation states that at least 2 bytes will be read 552 // After all 16 bits of the register have been read, 0 is returned 553 if((currentOperation.CommandBytesHandled) < 2) 554 { 555 var sourceReg = register == Register.Configuration ? configurationRegister : nonVolatileConfigurationRegister; 556 return (byte)BitHelper.GetValue(sourceReg.Read(), currentOperation.CommandBytesHandled * 8, 8); 557 } 558 return 0; 559 case Register.EnhancedVolatileConfiguration: 560 return enhancedVolatileConfigurationRegister.Read(); 561 case Register.ExtendedAddress: 562 default: 563 this.Log(LogLevel.Warning, "Trying to read from unsupported register \"{0}\"", register); 564 return 0; 565 } 566 } 567 HandleNoDataCommand()568 private void HandleNoDataCommand() 569 { 570 // The documentation describes more commands that don't have any data bytes (just code + address) 571 // but at the moment we have implemented just these ones 572 switch(currentOperation.Operation) 573 { 574 case DecodedOperation.OperationType.Erase: 575 if(enable.Value) 576 { 577 if(currentOperation.ExecutionAddress >= underlyingMemory.Size) 578 { 579 this.Log(LogLevel.Error, "Cannot erase memory because current address 0x{0:X} exceeds configured memory size.", currentOperation.ExecutionAddress); 580 return; 581 } 582 switch(currentOperation.EraseSize) 583 { 584 case DecodedOperation.OperationEraseSize.Subsector4K: 585 EraseSegment(4.KB()); 586 break; 587 case DecodedOperation.OperationEraseSize.Subsector32K: 588 EraseSegment(32.KB()); 589 break; 590 case DecodedOperation.OperationEraseSize.Sector: 591 EraseSegment(sectorSize); 592 break; 593 case DecodedOperation.OperationEraseSize.Die: 594 EraseDie(); 595 break; 596 default: 597 this.Log(LogLevel.Warning, "Unsupported erase type: {0}", currentOperation.EraseSize); 598 break; 599 } 600 } 601 else 602 { 603 this.Log(LogLevel.Error, "Erase operations are disabled."); 604 } 605 break; 606 default: 607 this.Log(LogLevel.Warning, "Encountered unexpected command: {0}", currentOperation); 608 break; 609 } 610 } 611 EraseChip()612 private void EraseChip() 613 { 614 // Don't allow erasing the chip if range protection is enabled 615 if(lockedRange.HasValue) 616 { 617 this.Log(LogLevel.Error, "Chip erase can only be performed when there is no locked range"); 618 return; 619 } 620 underlyingMemory.ZeroAll(); 621 } 622 EraseDie()623 private void EraseDie() 624 { 625 // Die erase is a separate operation because on multi-die chips it 626 // will erase only one die (part of the chip). This is not yet 627 // implemented, so we erase the whole chip. 628 EraseChip(); 629 } 630 EraseRangeUnchecked(Range range)631 private void EraseRangeUnchecked(Range range) 632 { 633 var segment = new byte[range.Size]; 634 for(ulong i = 0; i < range.Size; i++) 635 { 636 segment[i] = EmptySegment; 637 } 638 underlyingMemory.WriteBytes((long)range.StartAddress, segment); 639 } 640 EraseSegment(int segmentSize)641 private void EraseSegment(int segmentSize) 642 { 643 // The documentations states that on erase the operation address is 644 // aligned to the segment size 645 var position = segmentSize * (currentOperation.ExecutionAddress / segmentSize); 646 var segmentToErase = new Range((ulong)position, (ulong)segmentSize); 647 this.Log(LogLevel.Noisy, "Full segment to erase: {0}", segmentToErase); 648 foreach(var subrange in lockedRange.HasValue ? segmentToErase.Subtract(lockedRange.Value) : new List<Range>() { segmentToErase }) 649 { 650 this.Log(LogLevel.Noisy, "Erasing subrange {0}", subrange); 651 EraseRangeUnchecked(subrange); 652 } 653 } 654 ReadFromMemory()655 private byte ReadFromMemory() 656 { 657 if(currentOperation.ExecutionAddress + currentOperation.CommandBytesHandled > underlyingMemory.Size) 658 { 659 this.Log(LogLevel.Error, "Cannot read from address 0x{0:X} because it is bigger than configured memory size.", currentOperation.ExecutionAddress); 660 return 0; 661 } 662 663 var position = currentOperation.ExecutionAddress + currentOperation.CommandBytesHandled; 664 return underlyingMemory.ReadByte(position); 665 } 666 667 // The addressingMode field is 1-bit wide, so a conditional expression covers all possible cases 668 private int NumberOfAddressBytes => addressingMode.Value == AddressingMode.ThreeByte ? 3 : 4; 669 670 private DecodedOperation currentOperation; 671 private uint temporaryConfiguration; //this should be an ushort, but due to C# type promotions it's easier to use uint 672 673 private readonly byte[] deviceData; 674 private readonly byte[] SFDPSignature; 675 private readonly IFlagRegisterField enable; 676 private readonly ByteRegister flagStatusRegister; 677 private readonly IEnumRegisterField<AddressingMode> addressingMode; 678 private readonly ByteRegister volatileConfigurationRegister; 679 private readonly ByteRegister enhancedVolatileConfigurationRegister; 680 private readonly WordRegister nonVolatileConfigurationRegister; 681 private readonly byte manufacturerId; 682 private readonly byte memoryType; 683 private readonly byte capacityCode; 684 private readonly byte remainingIdBytes; 685 private readonly byte extendedDeviceId; 686 private readonly byte deviceConfiguration; 687 private const byte EmptySegment = 0xff; 688 private const byte DeviceGeneration = 0x1; // 2nd generation 689 private const byte DefaultRemainingIDBytes = 0x10; 690 private const byte DefaultExtendedDeviceID = DeviceGeneration << 6; 691 private const byte DefaultDeviceConfiguration = 0x0; // standard 692 private const int DefaultSectorSizeKB = 64; 693 694 // Dummy SFDP header: 0 parameter tables, one empty required 695 private readonly byte[] DefaultSFDPSignature = new byte[] 696 { 697 0x53, 0x46, 0x44, 0x50, 0x06, 0x01, 0x00, 0xFF, 698 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF 699 }; 700 701 protected enum Commands : byte 702 { 703 // Software RESET Operations 704 ResetEnable = 0x66, 705 ResetMemory = 0x99, 706 707 // READ ID Operations 708 ReadID = 0x9F, 709 MultipleIoReadID = 0xAF, 710 ReadSerialFlashDiscoveryParameter = 0x5A, 711 712 // READ MEMORY Operations 713 Read = 0x03, 714 FastRead = 0x0B, 715 DualOutputFastRead = 0x3B, 716 DualInputOutputFastRead = 0xBB, 717 QuadOutputFastRead = 0x6B, 718 QuadInputOutputFastRead = 0xEB, 719 DtrFastRead = 0x0D, 720 DtrDualOutputFastRead = 0x3D, 721 DtrDualInputOutputFastRead = 0xBD, 722 DtrQuadOutputFastRead = 0x6D, 723 DtrQuadInputOutputFastRead = 0xED, 724 QuadInputOutputWordRead = 0xE7, 725 726 // READ MEMORY Operations with 4-Byte Address 727 Read4byte = 0x13, 728 FastRead4byte = 0x0C, 729 DualOutputFastRead4byte = 0x3C, 730 DualInputOutputFastRead4byte = 0xBC, 731 QuadOutputFastRead4byte = 0x6C, 732 QuadInputOutputFastRead4byte = 0xEC, 733 DtrFastRead4byte = 0x0E, 734 DtrDualInputOutputFastRead4byte = 0xBE, 735 DtrQuadInputOutputFastRead4byte = 0xEE, 736 737 // WRITE Operations 738 WriteEnable = 0x06, 739 WriteDisable = 0x04, 740 741 // READ REGISTER Operations 742 ReadStatusRegister = 0x05, 743 ReadConfigurationRegister = 0x15, 744 ReadFlagStatusRegister = 0x70, 745 ReadNonVolatileConfigurationRegister = 0xB5, 746 ReadVolatileConfigurationRegister = 0x85, 747 ReadEnhancedVolatileConfigurationRegister = 0x65, 748 ReadExtendedAddressRegister = 0xC8, 749 ReadGeneralPurposeReadRegister = 0x96, 750 751 // WRITE REGISTER Operations 752 WriteStatusRegister = 0x01, 753 WriteNonVolatileConfigurationRegister = 0xB1, 754 WriteVolatileConfigurationRegister = 0x81, 755 WriteEnhancedVolatileConfigurationRegister = 0x61, 756 WriteExtendedAddressRegister = 0xC5, 757 758 // CLEAR FLAG STATUS REGISTER Operation 759 ClearFlagStatusRegister = 0x50, 760 761 // PROGRAM Operations 762 PageProgram = 0x02, 763 DualInputFastProgram = 0xA2, 764 ExtendedDualInputFastProgram = 0xD2, 765 QuadInputFastProgram = 0x32, 766 ExtendedQuadInputFastProgram = 0x38, 767 768 // PROGRAM Operations with 4-Byte Address 769 PageProgram4byte = 0x12, 770 QuadInputFastProgram4byte = 0x34, 771 QuadInputExtendedFastProgram4byte = 0x3E, 772 773 // ERASE Operations 774 SubsectorErase32kb = 0x52, 775 SubsectorErase4kb = 0x20, 776 SectorErase = 0xD8, 777 BulkErase = 0x60, 778 ChipErase = 0xC7, 779 DieErase = 0xC4, 780 781 // ERASE Operations with 4-Byte Address 782 SectorErase4byte = 0xDC, 783 SubsectorErase4byte4kb = 0x21, 784 SubsectorErase4byte32kb = 0x5C, 785 786 // SUSPEND/RESUME Operations 787 ProgramEraseSuspend = 0x75, 788 ProgramEraseResume = 0x7A, 789 790 // ONE-TIME PROGRAMMABLE (OTP) Operations 791 ReadOtpArray = 0x4B, 792 ProgramOtpArray = 0x42, 793 794 // 4-BYTE ADDRESS MODE Operations 795 Enter4byteAddressMode = 0xB7, 796 Exit4byteAddressMode = 0xE9, 797 798 // QUAD PROTOCOL Operations 799 EnterQuadInputOutputMode = 0x35, 800 ResetQuadInputOutputMode = 0xF5, 801 802 // Deep Power-Down Operations 803 EnterDeepPowerDown = 0xB9, 804 ReleaseFromDeepPowerdown = 0xAB, 805 806 // ADVANCED SECTOR PROTECTION Operations 807 ReadSectorProtection = 0x2D, 808 ProgramSectorProtection = 0x2C, 809 ReadVolatileLockBits = 0xE8, 810 WriteVolatileLockBits = 0xE5, 811 ReadNonvolatileLockBits = 0xE2, 812 WriteNonvolatileLockBits = 0xE3, 813 EraseNonvolatileLockBits = 0xE4, 814 ReadGlobalFreezeBit = 0xA7, 815 WriteGlobalFreezeBit = 0xA6, 816 ReadPassword = 0x27, 817 WritePassword = 0x28, 818 UnlockPassword = 0x29, 819 820 // ADVANCED SECTOR PROTECTION Operations with 4-Byte Address 821 ReadVolatileLockBits4byte = 0xE0, 822 WriteVolatileLockBits4byte = 0xE1, 823 824 // ADVANCED FUNCTION INTERFACE Operations 825 InterfaceActivation = 0x9B, 826 CyclicRedundancyCheck = 0x27 827 } 828 829 private enum AddressingMode : byte 830 { 831 FourByte = 0x0, 832 ThreeByte = 0x1 833 } 834 835 private enum Register : uint 836 { 837 Status = 1, //starting from 1 to leave 0 as an unused value 838 Configuration, 839 FlagStatus, 840 ExtendedAddress, 841 NonVolatileConfiguration, 842 VolatileConfiguration, 843 EnhancedVolatileConfiguration 844 } 845 } 846 } 847