1 // 2 // Copyright (c) 2010-2024 Antmicro 3 // Copyright (c) 2021 Google LLC 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 using System.IO; 9 using System.Linq; 10 using Antmicro.Renode.Logging; 11 using Antmicro.Renode.Core; 12 using Antmicro.Renode.Utilities; 13 using Antmicro.Renode.Exceptions; 14 using Antmicro.Renode.Core.Structure.Registers; 15 using Antmicro.Renode.Peripherals.Memory; 16 using Antmicro.Renode.Peripherals.Miscellaneous; 17 18 namespace Antmicro.Renode.Peripherals.MTD 19 { 20 public class OpenTitan_FlashController : BasicDoubleWordPeripheral, IKnownSize 21 { OpenTitan_FlashController(IMachine machine, MappedMemory flash)22 public OpenTitan_FlashController(IMachine machine, MappedMemory flash) : base(machine) 23 { 24 ProgramEmptyIRQ = new GPIO(); 25 ProgramLevelIRQ = new GPIO(); 26 ReadFullIRQ = new GPIO(); 27 ReadLevelIRQ = new GPIO(); 28 OperationDoneIRQ = new GPIO(); 29 CorrectableErrorIRQ = new GPIO(); 30 31 RecoverableAlert = new GPIO(); 32 FatalStandardAlert = new GPIO(); 33 FatalAlert = new GPIO(); 34 FatalPrimitiveFlashAlert = new GPIO(); 35 RecoverablePrimitiveFlashAlert = new GPIO(); 36 37 mpRegionEnabled = new IEnumRegisterField<MultiBitBool4>[NumberOfMpRegions]; 38 mpRegionBase = new IValueRegisterField[NumberOfMpRegions]; 39 mpRegionSize = new IValueRegisterField[NumberOfMpRegions]; 40 mpRegionReadEnabled = new IEnumRegisterField<MultiBitBool4>[NumberOfMpRegions]; 41 mpRegionProgEnabled = new IEnumRegisterField<MultiBitBool4>[NumberOfMpRegions]; 42 mpRegionEraseEnabled = new IEnumRegisterField<MultiBitBool4>[NumberOfMpRegions]; 43 mpRegionScrambleEnabled = new IEnumRegisterField<MultiBitBool4>[NumberOfMpRegions]; 44 mpRegionEccEnabled = new IEnumRegisterField<MultiBitBool4>[NumberOfMpRegions]; 45 mpRegionHighEnduranceEnabled = new IEnumRegisterField<MultiBitBool4>[NumberOfMpRegions]; 46 47 bankInfoPageEnabled = new IEnumRegisterField<MultiBitBool4>[FlashNumberOfBanks, FlashNumberOfInfoTypes][]; 48 bankInfoPageReadEnabled = new IEnumRegisterField<MultiBitBool4>[FlashNumberOfBanks, FlashNumberOfInfoTypes][]; 49 bankInfoPageProgramEnabled = new IEnumRegisterField<MultiBitBool4>[FlashNumberOfBanks, FlashNumberOfInfoTypes][]; 50 bankInfoPageEraseEnabled = new IEnumRegisterField<MultiBitBool4>[FlashNumberOfBanks, FlashNumberOfInfoTypes][]; 51 bankInfoPageScrambleEnabled = new IEnumRegisterField<MultiBitBool4>[FlashNumberOfBanks, FlashNumberOfInfoTypes][]; 52 bankInfoPageEccEnabled = new IEnumRegisterField<MultiBitBool4>[FlashNumberOfBanks, FlashNumberOfInfoTypes][]; 53 bankInfoPageHighEnduranceEnabled = new IEnumRegisterField<MultiBitBool4>[FlashNumberOfBanks, FlashNumberOfInfoTypes][]; 54 55 dataFlash = flash; 56 // This is required as part of the tests use full address, while the other use just flash offset 57 // Ex. 58 // this one uses just offset: https://github.com/lowRISC/opentitan/blob/1e86ba2a238dc26c2111d325ee7645b0e65058e5/sw/device/tests/flash_ctrl_test.c#L70 59 // this one - full address: https://github.com/lowRISC/opentitan/blob/1e86ba2a238dc26c2111d325ee7645b0e65058e5/sw/device/tests/flash_ctrl_test.c#L224 60 flashAddressMask = (uint)(flash.Size - 1); 61 62 for(var bankNumber = 0; bankNumber < FlashNumberOfBanks; ++bankNumber) 63 { 64 for(var infoType = 0; infoType < FlashNumberOfInfoTypes; ++infoType) 65 { 66 bankInfoPageEnabled[bankNumber, infoType] = new IEnumRegisterField<MultiBitBool4>[FlashNumberOfPagesInInfo[infoType]]; 67 bankInfoPageReadEnabled[bankNumber, infoType] = new IEnumRegisterField<MultiBitBool4>[FlashNumberOfPagesInInfo[infoType]]; 68 bankInfoPageProgramEnabled[bankNumber, infoType] = new IEnumRegisterField<MultiBitBool4>[FlashNumberOfPagesInInfo[infoType]]; 69 bankInfoPageEraseEnabled[bankNumber, infoType] = new IEnumRegisterField<MultiBitBool4>[FlashNumberOfPagesInInfo[infoType]]; 70 bankInfoPageScrambleEnabled[bankNumber, infoType] = new IEnumRegisterField<MultiBitBool4>[FlashNumberOfPagesInInfo[infoType]]; 71 bankInfoPageEccEnabled[bankNumber, infoType] = new IEnumRegisterField<MultiBitBool4>[FlashNumberOfPagesInInfo[infoType]]; 72 bankInfoPageHighEnduranceEnabled[bankNumber, infoType] = new IEnumRegisterField<MultiBitBool4>[FlashNumberOfPagesInInfo[infoType]]; 73 } 74 } 75 76 Registers.InterruptState.Define(this) 77 .WithFlag(0, out interruptStatusProgramEmpty, FieldMode.Read | FieldMode.WriteOneToClear, name: "prog_empty") 78 .WithFlag(1, out interruptStatusProgramLevel, FieldMode.Read | FieldMode.WriteOneToClear, name: "prog_lvl") 79 .WithFlag(2, out interruptStatusReadFull, FieldMode.Read | FieldMode.WriteOneToClear, name: "rd_full") 80 .WithFlag(3, out interruptStatusReadLevel, FieldMode.Read | FieldMode.WriteOneToClear, name: "rd_lvl") 81 .WithFlag(4, out interruptStatusOperationDone, FieldMode.Read | FieldMode.WriteOneToClear, name: "op_done") 82 .WithFlag(5, out interruptStatusCorrectableError, FieldMode.Read | FieldMode.WriteOneToClear, name: "corr_err") 83 .WithReservedBits(6, 26) 84 .WithWriteCallback((_, __) => UpdateInterrupts()); 85 86 Registers.InterruptEnable.Define(this) 87 .WithFlag(0, out interruptEnableProgramEmpty, name: "prog_empty") 88 .WithFlag(1, out interruptEnableProgramLevel, name: "prog_lvl") 89 .WithFlag(2, out interruptEnableReadFull, name: "rd_full") 90 .WithFlag(3, out interruptEnableReadLevel, name: "rd_lvl") 91 .WithFlag(4, out interruptEnableOperationDone, name: "op_done") 92 .WithFlag(5, out interruptEnableCorrectableError, name: "corr_err") 93 .WithReservedBits(6, 26) 94 .WithWriteCallback((_, __) => UpdateInterrupts()); 95 96 Registers.InterruptTest.Define(this) 97 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { interruptStatusProgramEmpty.Value |= val; }, name: "prog_empty") 98 .WithFlag(1, FieldMode.Write, writeCallback: (_, val) => { interruptStatusProgramLevel.Value |= val; }, name: "prog_lvl") 99 .WithFlag(2, FieldMode.Write, writeCallback: (_, val) => { interruptStatusReadFull.Value |= val; }, name: "rd_full") 100 .WithFlag(3, FieldMode.Write, writeCallback: (_, val) => { interruptStatusReadLevel.Value |= val; }, name: "rd_lvl") 101 .WithFlag(4, FieldMode.Write, writeCallback: (_, val) => { interruptStatusOperationDone.Value |= val; }, name: "op_done") 102 .WithFlag(5, FieldMode.Write, writeCallback: (_, val) => { interruptStatusCorrectableError.Value |= val; }, name: "corr_err") 103 .WithReservedBits(6, 26) 104 .WithWriteCallback((_, __) => UpdateInterrupts()); 105 106 Registers.AlertTest.Define(this) 107 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) RecoverableAlert.Blink(); }, name:"recov_err") 108 .WithFlag(1, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalStandardAlert.Blink(); }, name:"fatal_std_err") 109 .WithFlag(2, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalAlert.Blink(); }, name:"fatal_err") 110 .WithFlag(3, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalPrimitiveFlashAlert.Blink(); }, name:"fatal_prim_flash_alert") 111 .WithFlag(4, FieldMode.Write, writeCallback: (_, val) => { if(val) RecoverablePrimitiveFlashAlert.Blink(); }, name:"recov_prim_flash_alert") 112 .WithReservedBits(5, 27); 113 114 Registers.DisableFlashFunctionality.Define(this) 115 .WithTag("VAL", 0, 4) 116 .WithReservedBits(4, 28); 117 118 Registers.ExecutionFetchesEnabled.Define(this) 119 // this is a field, not a tag to hush warnings 120 // TODO: this should control if execution from flash is possible 121 .WithValueField(0, 32, name: "EN"); 122 123 Registers.ControllerInit.Define(this) 124 .WithTaggedFlag("VAL", 0) 125 .WithReservedBits(1, 31); 126 127 // TODO(julianmb): support register write enable. this isnt tested in the unittests currently 128 Registers.ControlEnable.Define(this, 0x1) 129 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => true, name: "EN") 130 .WithReservedBits(1, 31); 131 132 Registers.Control.Define(this) 133 .WithFlag(0, name: "START", writeCallback: (o, n) => { 134 if(n) 135 { 136 StartOperation(); 137 } 138 }) 139 .WithReservedBits(1, 3) 140 .WithEnumField<DoubleWordRegister, ControlOp>(4, 2, out operation, name: "OP") 141 .WithTaggedFlag("PROG_SEL", 6) 142 .WithFlag(7, out flashSelectBankEraseMode, name: "ERASE_SEL") 143 .WithFlag(8, out flashSelectPartition, name: "PARTITION_SEL") 144 .WithValueField(9, 2, out flashSelectInfo, name: "INFO_SEL") 145 .WithReservedBits(11, 5) 146 .WithValueField(16, 12, out controlNum, name: "NUM") 147 .WithReservedBits(28, 4); 148 149 Registers.AddressForFlashOperation.Define(this) 150 .WithValueField(0, 32, out address, changeCallback: (_, address) => { 151 // This is required as the tests use full address or just flash offset 152 this.address.Value = address & flashAddressMask; 153 flashAddress = null; 154 var addresses = machine.SystemBus.GetRegistrationPoints(dataFlash) 155 .Select(pint => pint.Range.StartAddress); 156 157 if(!addresses.Any()) 158 { 159 this.Log(LogLevel.Warning, "Underlying data flash is not registered on the system bus, so it cannot be accessed"); 160 return; 161 } 162 163 flashAddress = (long)addresses.First(); 164 }, name: "START"); 165 166 Registers.EnableDifferentProgramTypes.Define(this) 167 .WithTaggedFlag("NORMAL", 0) 168 .WithTaggedFlag("REPAIR", 1) 169 .WithReservedBits(2, 30); 170 171 // Erase is performed immediately so write to SuspendErase will never happen during erasing process. 172 // Cleared immediately. 173 Registers.SuspendErase.Define(this) 174 .WithFlag(0, valueProviderCallback: _ => false, name: "REQ") 175 .WithReservedBits(1, 31); 176 177 for(var i = 0; i < NumberOfMpRegions; i++) 178 { 179 // TODO(julianmb): support register write enable. this isnt tested in the unittests currently 180 RegistersCollection.AddRegister((long)Registers.RegionConfigurationEnable0 + 0x4 * i, new DoubleWordRegister(this, 0x1) 181 .WithTaggedFlag($"REGION_{i}", 0) 182 .WithReservedBits(1, 31)); 183 184 RegistersCollection.AddRegister((long)(Registers.RegionConfiguration0 + 0x4 * i), new DoubleWordRegister(this) 185 .WithEnumField<DoubleWordRegister, MultiBitBool4>(0, 4, out mpRegionEnabled[i], name: $"EN_{i}") 186 .WithEnumField<DoubleWordRegister, MultiBitBool4>(4, 4, out mpRegionReadEnabled[i], name: $"RD_EN_{i}") 187 .WithEnumField<DoubleWordRegister, MultiBitBool4>(8, 4, out mpRegionProgEnabled[i], name: $"PROG_EN_{i}") 188 .WithEnumField<DoubleWordRegister, MultiBitBool4>(12, 4, out mpRegionEraseEnabled[i], name: $"ERASE_EN_{i}") 189 .WithEnumField<DoubleWordRegister, MultiBitBool4>(16, 4, out mpRegionScrambleEnabled[i], name: $"SCRAMBLE_EN_{i}") 190 .WithEnumField<DoubleWordRegister, MultiBitBool4>(20, 4, out mpRegionEccEnabled[i], name: $"ECC_EN_{i}") 191 .WithEnumField<DoubleWordRegister, MultiBitBool4>(24, 4, out mpRegionHighEnduranceEnabled[i], name: $"HE_EN_{i}") 192 .WithReservedBits(28, 4)); 193 194 RegistersCollection.AddRegister((long)(Registers.RegionBaseAndSizeConfiguration0 + 0x4 * i), new DoubleWordRegister(this) 195 .WithValueField(0, 9, out mpRegionBase[i], name: $"BASE_{i}") 196 .WithValueField(9, 10, out mpRegionSize[i], name: $"SIZE_{i}") 197 .WithReservedBits(19, 13)); 198 } 199 200 Registers.DefaultRegionConfiguration.Define(this) 201 .WithEnumField<DoubleWordRegister, MultiBitBool4>(0, 4, out defaultMpRegionReadEnabled, name: "RD_EN") 202 .WithEnumField<DoubleWordRegister, MultiBitBool4>(4, 4, out defaultMpRegionProgEnabled, name: "PROG_EN") 203 .WithEnumField<DoubleWordRegister, MultiBitBool4>(8, 4, out defaultMpRegionEraseEnabled, name: "ERASE_EN") 204 .WithEnumField<DoubleWordRegister, MultiBitBool4>(12, 4, out defaultMpRegionScrambleEnabled, name: "SCRAMBLE_EN") 205 .WithEnumField<DoubleWordRegister, MultiBitBool4>(16, 4, out defaultMpRegionEccEnabled, name: "ECC_EN") 206 .WithEnumField<DoubleWordRegister, MultiBitBool4>(20, 4, out defaultMpRegionHighEnduranceEnabled, name: "HE_EN") 207 .WithReservedBits(24, 8); 208 209 var registerOffset = Registers.Bank0Info0Enable0; 210 for(var bankNumber = 0; bankNumber < FlashNumberOfBanks; ++bankNumber) 211 { 212 for(var infoType = 0; infoType < FlashNumberOfInfoTypes; ++infoType) 213 { 214 // For each info type, first are defined configuration enabling registers and then 215 // configuration registers. 216 for(var pageNumber = 0; pageNumber < FlashNumberOfPagesInInfo[infoType]; ++pageNumber) 217 { 218 // TODO(julianmb): support register write enable. this isnt tested in the unittests currently 219 registerOffset.Define(this, 0x1) 220 .WithTaggedFlag($"REGION_{pageNumber}", 0) 221 .WithReservedBits(1, 31); 222 registerOffset += 0x4; 223 } 224 225 for(var pageNumber = 0; pageNumber < FlashNumberOfPagesInInfo[infoType]; ++pageNumber) 226 { 227 registerOffset.Define(this) 228 .WithEnumField<DoubleWordRegister, MultiBitBool4>(0, 4, out bankInfoPageEnabled[bankNumber, infoType][pageNumber], name: $"EN_{pageNumber}") 229 .WithEnumField<DoubleWordRegister, MultiBitBool4>(4, 4, out bankInfoPageReadEnabled[bankNumber, infoType][pageNumber], name: $"RD_EN_{pageNumber}") 230 .WithEnumField<DoubleWordRegister, MultiBitBool4>(8, 4, out bankInfoPageProgramEnabled[bankNumber, infoType][pageNumber], name: $"PROG_EN_{pageNumber}") 231 .WithEnumField<DoubleWordRegister, MultiBitBool4>(12, 4, out bankInfoPageEraseEnabled[bankNumber, infoType][pageNumber], name: $"ERASE_EN_{pageNumber}") 232 .WithEnumField<DoubleWordRegister, MultiBitBool4>(16, 4, out bankInfoPageScrambleEnabled[bankNumber, infoType][pageNumber], name: $"SCRAMBLE_EN_{pageNumber}") 233 .WithEnumField<DoubleWordRegister, MultiBitBool4>(20, 4, out bankInfoPageEccEnabled[bankNumber, infoType][pageNumber], name: $"ECC_EN_{pageNumber}") 234 .WithEnumField<DoubleWordRegister, MultiBitBool4>(24, 4, out bankInfoPageHighEnduranceEnabled[bankNumber, infoType][pageNumber], name: $"HE_EN_{pageNumber}") 235 .WithReservedBits(28, 4); 236 registerOffset += 0x4; 237 } 238 } 239 } 240 241 // TODO(julianmb): support register write enable. this isnt tested in the unittests currently 242 Registers.BankConfigurationEnable.Define(this, 0x1) 243 .WithTaggedFlag("BANK", 0) 244 .WithReservedBits(1, 31); 245 Registers.BankConfiguration.Define(this) 246 .WithFlag(0, out eraseBank0, name: "ERASE_EN_0") 247 .WithFlag(1, out eraseBank1, name: "ERASE_EN_1") 248 .WithReservedBits(2, 30); 249 250 Registers.FlashOperationStatus.Define(this) 251 .WithFlag(0, out opStatusRegisterDoneFlag, name: "done") 252 .WithFlag(1, out opStatusRegisterErrorFlag, name: "err") 253 .WithReservedBits(2, 30); 254 255 Registers.Status.Define(this, 0xa) 256 .WithFlag(0, out statusReadFullFlag, FieldMode.Read, name: "rd_full") 257 .WithFlag(1, out statusReadEmptyFlag, FieldMode.Read, name: "rd_empty") 258 .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => false, name: "prog_full") 259 .WithFlag(3, FieldMode.Read, valueProviderCallback: _ => true, name: "prog_empty") 260 .WithFlag(4, FieldMode.Read, valueProviderCallback: _ => false, name: "init_wip") 261 .WithReservedBits(5, 27); 262 263 Registers.ErrorCode.Define(this) 264 .WithFlag(0, out errorCodeOutOfBoundsError, FieldMode.Read | FieldMode.WriteOneToClear, name: "op_err") 265 .WithFlag(1, out errorCodeMemoryProtectionError, FieldMode.Read | FieldMode.WriteOneToClear, name: "mp_err") 266 .WithTaggedFlag("rd_err", 2) 267 .WithTaggedFlag("prog_err", 3) 268 .WithTaggedFlag("prog_win_err", 4) 269 .WithTaggedFlag("prog_type_err", 5) 270 .WithTaggedFlag("flash_macro", 6) 271 .WithTaggedFlag("update_err", 7) 272 .WithReservedBits(8, 24); 273 274 Registers.FaultStatus.Define(this) 275 .WithTaggedFlag("op_err", 0) 276 .WithTaggedFlag("mp_err", 1) 277 .WithTaggedFlag("rd_err", 2) 278 .WithTaggedFlag("prog_err", 3) 279 .WithTaggedFlag("prog_win_err", 4) 280 .WithTaggedFlag("prog_type_err", 5) 281 .WithTaggedFlag("flash_macro_err", 6) 282 .WithTaggedFlag("seed_err", 7) 283 .WithTaggedFlag("phy_relbl_err", 8) 284 .WithTaggedFlag("phy_storage_err", 9) 285 .WithTaggedFlag("spurious_ack", 10) 286 .WithTaggedFlag("arb_err", 11) 287 .WithTaggedFlag("host_gnt_err", 12) 288 .WithReservedBits(13, 19); 289 290 Registers.ErrorAddress.Define(this) 291 .WithValueField(0, 32, out errorAddress, FieldMode.Read, name: "ERR_ADDR"); 292 293 Registers.ECCSingleErrorCount.Define(this) 294 .WithTag("ECC_SINGLE_ERR_CNT_0", 0, 8) 295 .WithTag("ECC_SINGLE_ERR_CNT_1", 8, 8) 296 .WithReservedBits(16, 16); 297 298 Registers.ECCSingleErrorAddress0.Define(this) 299 .WithTag("ECC_SINGLE_ERR_ADDR_0", 0, 20) 300 .WithReservedBits(20, 12); 301 302 Registers.ECCSingleErrorAddress1.Define(this) 303 .WithTag("ECC_SINGLE_ERR_ADDR_1", 0, 20) 304 .WithReservedBits(20, 12); 305 306 Registers.PhyAlertConfiguration.Define(this) 307 .WithTaggedFlag("alert_ack", 0) 308 .WithTaggedFlag("alert_trig", 1) 309 .WithReservedBits(2, 30); 310 311 Registers.PhyStatus.Define(this, 0x6) 312 .WithTaggedFlag("init_wip", 0) 313 .WithTaggedFlag("prog_normal_avail", 1) 314 .WithTaggedFlag("prog_repair_avail", 2) 315 .WithReservedBits(3, 29); 316 317 Registers.Scratch.Define(this) 318 .WithTag("data", 0, 32); 319 320 Registers.FifoLevel.Define(this, 0xf0f) 321 .WithValueField(0, 5, out programFifoLevel, name: "PROG") 322 .WithReservedBits(5, 1 + 7 - 5) 323 .WithValueField(8, 1 + 12 - 8, out readFifoLevel, name: "RD") 324 .WithReservedBits(13, 19); 325 326 // TODO(julianmb): implement fifo reset. There isnt any unittest for this currently. 327 Registers.FifoReset.Define(this) 328 .WithTaggedFlag("EN", 0) 329 .WithReservedBits(1, 31); 330 331 Registers.ProgramFifo.Define(this) 332 .WithValueField(0, 32, mode: FieldMode.Write, writeCallback: (_, data) => 333 { 334 var isInBounds = flashAddress.HasValue && IsOffsetInBounds(programOffset); 335 var isAllowed = isInBounds && IsOperationAllowed(OperationType.ProgramData, programOffset); 336 337 if(isInBounds && isAllowed) 338 { 339 var oldData = ReadFlashDoubleWord(programOffset); 340 WriteFlashDoubleWord(programOffset, oldData & (uint)data); 341 programOffset += 4; 342 } 343 else 344 { 345 opStatusRegisterErrorFlag.Value = true; 346 opStatusRegisterDoneFlag.Value = true; 347 interruptStatusOperationDone.Value = true; 348 349 if(isInBounds) 350 { 351 errorCodeMemoryProtectionError.Value = true; 352 errorAddress.Value = (uint)(programOffset + flashAddress.Value); 353 } 354 else 355 { 356 errorCodeOutOfBoundsError.Value = true; 357 } 358 return; 359 } 360 361 var offset = address.Value; 362 if(programOffset > (long)(offset + 4 * controlNum.Value)) 363 { 364 opStatusRegisterDoneFlag.Value = true; 365 interruptStatusOperationDone.Value = true; 366 } 367 else 368 { 369 interruptStatusProgramLevel.Value = true; 370 interruptStatusProgramEmpty.Value = true; 371 } 372 }) 373 .WithWriteCallback((_, __) => UpdateInterrupts()); 374 375 Registers.ReadFifo.Define(this) 376 .WithValueField(0, 32, mode: FieldMode.Read, valueProviderCallback: _ => 377 { 378 uint value = 0; 379 var isInBounds = flashAddress.HasValue && IsOffsetInBounds(readOffset); 380 var isAllowed = isInBounds && IsOperationAllowed(OperationType.ReadData, readOffset); 381 382 if(isInBounds && isAllowed) 383 { 384 value = ReadFlashDoubleWord(readOffset); 385 readOffset += 4; 386 } 387 else 388 { 389 opStatusRegisterErrorFlag.Value = true; 390 opStatusRegisterDoneFlag.Value = true; 391 interruptStatusOperationDone.Value = true; 392 393 if(isInBounds) 394 { 395 errorCodeMemoryProtectionError.Value = true; 396 errorAddress.Value = (uint)(readOffset + flashAddress.Value); 397 } 398 else 399 { 400 errorCodeOutOfBoundsError.Value = true; 401 } 402 return value; 403 } 404 405 var offset = address.Value; 406 if(readOffset > (long)(offset + 4 * controlNum.Value)) 407 { 408 opStatusRegisterDoneFlag.Value = true; 409 interruptStatusOperationDone.Value = true; 410 UpdateReadFifoSignals(false); 411 } 412 else 413 { 414 UpdateReadFifoSignals(true); 415 } 416 417 return value; 418 }) 419 .WithWriteCallback((_, __) => UpdateInterrupts()); 420 421 infoFlash = new ArrayMemory[FlashNumberOfBanks, FlashNumberOfInfoTypes]; 422 for(var bankNumber = 0; bankNumber < FlashNumberOfBanks; ++bankNumber) 423 { 424 for(var infoType = 0; infoType < FlashNumberOfInfoTypes; ++infoType) 425 { 426 infoFlash[bankNumber, infoType] = new ArrayMemory(FlashNumberOfPagesInInfo[infoType] * BytesPerPage); 427 } 428 } 429 this.Reset(); 430 } 431 Reset()432 public override void Reset() 433 { 434 RegistersCollection.Reset(); 435 statusReadFullFlag.Value = false; 436 statusReadEmptyFlag.Value = true; 437 438 readOffset = 0; 439 programOffset = 0; 440 RecoverableAlert.Unset(); 441 FatalStandardAlert.Unset(); 442 FatalAlert.Unset(); 443 FatalPrimitiveFlashAlert.Unset(); 444 RecoverablePrimitiveFlashAlert.Unset(); 445 UpdateInterrupts(); 446 } 447 LoadFlashInfoPartitionFromBinary(uint bankNumber, uint infoType, long offset, ReadFilePath fileName)448 public void LoadFlashInfoPartitionFromBinary(uint bankNumber, uint infoType, long offset, ReadFilePath fileName) 449 { 450 if (bankNumber >= FlashNumberOfBanks || infoType >= FlashNumberOfInfoTypes) 451 { 452 throw new RecoverableException("Invalid bank number or info type."); 453 } 454 455 var partitionSize = infoFlash[bankNumber, infoType].Size; 456 if(partitionSize < offset) 457 { 458 throw new RecoverableException($"Specified offset {offset} is bigger than partition size {partitionSize}."); 459 } 460 var bufferSize = partitionSize - offset; 461 462 try 463 { 464 using(var reader = new FileStream(fileName, FileMode.Open, FileAccess.Read)) 465 { 466 var buffer = new byte[bufferSize]; 467 var written = 0; 468 var read = 0; 469 while((read = reader.Read(buffer, 0, buffer.Length)) > 0 && written < bufferSize) 470 { 471 infoFlash[bankNumber, infoType].WriteBytes(offset + written, buffer, 0, read); 472 written += read; 473 } 474 } 475 } 476 catch(IOException e) 477 { 478 throw new RecoverableException($"Exception while loading file {fileName}: {e.Message}"); 479 } 480 } 481 482 public long Size => 0x1000; 483 484 public GPIO ProgramEmptyIRQ { get; } 485 public GPIO ProgramLevelIRQ { get; } 486 public GPIO ReadFullIRQ { get; } 487 public GPIO ReadLevelIRQ { get; } 488 public GPIO OperationDoneIRQ { get; } 489 public GPIO CorrectableErrorIRQ { get; } 490 491 public GPIO RecoverableAlert { get; } 492 public GPIO FatalStandardAlert { get; } 493 public GPIO FatalAlert { get; } 494 public GPIO FatalPrimitiveFlashAlert { get; } 495 public GPIO RecoverablePrimitiveFlashAlert { get; } 496 StartOperation()497 private void StartOperation() 498 { 499 switch(operation.Value) 500 { 501 case ControlOp.FlashRead: 502 { 503 this.Log( 504 LogLevel.Noisy, 505 "OpenTitan_FlashController/StartOperation: Read"); 506 StartReadOperation(); 507 break; 508 } 509 510 case ControlOp.FlashProgram: 511 { 512 this.Log( 513 LogLevel.Noisy, 514 "OpenTitan_FlashController/StartOperation: Program"); 515 StartProgramOperation(); 516 break; 517 } 518 519 case ControlOp.FlashErase: 520 { 521 this.Log( 522 LogLevel.Noisy, 523 "OpenTitan_FlashController/StartOperation: Erase"); 524 StartEraseOperation(); 525 break; 526 } 527 528 default: 529 { 530 this.Log( 531 LogLevel.Warning, 532 "OpenTitan_FlashController/StartOperation: invalid controlOpValue: 0x{0:X}", operation.Value); 533 break; 534 } 535 } 536 } 537 StartReadOperation()538 private void StartReadOperation() 539 { 540 this.Log( 541 LogLevel.Noisy, 542 "OpenTitan_FlashController/StartReadOperation: address = 0x{0:X}", 543 address.Value); 544 545 this.Log( 546 LogLevel.Noisy, 547 "OpenTitan_FlashController/StartReadOperation: reading {0}", 548 flashSelectPartition.Value ? "InfoPartition" : "DataPartition"); 549 550 readOffset = (long)address.Value; 551 UpdateReadFifoSignals(true); 552 } 553 StartProgramOperation()554 private void StartProgramOperation() 555 { 556 this.Log( 557 LogLevel.Noisy, 558 "OpenTitan_FlashController/StartProgramOperation: address = 0x{0:X}", 559 address.Value); 560 561 this.Log( 562 LogLevel.Noisy, 563 "OpenTitan_FlashController/StartProgramOperation: programming {0}", 564 flashSelectPartition.Value ? "InfoPartition" : "DataPartition"); 565 566 programOffset = (long)address.Value; 567 } 568 StartEraseOperation()569 private void StartEraseOperation() 570 { 571 this.Log( 572 LogLevel.Noisy, 573 "OpenTitan_FlashController/StartEraseOperation: address = 0x{0:X}", 574 address.Value); 575 576 this.Log( 577 LogLevel.Noisy, 578 "OpenTitan_FlashController/StartEraseOperation: erasing {0}", 579 flashSelectPartition.Value ? "InfoPartition" : "DataPartition"); 580 581 var offset = (uint)address.Value; 582 var size = flashSelectBankEraseMode.Value ? BytesPerBank : BytesPerPage; 583 var truncatedOffset = offset & ~(size - 1); 584 var bankNumber = truncatedOffset / BytesPerBank; 585 586 if(!IsOffsetInBounds(truncatedOffset)) 587 { 588 errorCodeOutOfBoundsError.Value = true; 589 opStatusRegisterErrorFlag.Value = true; 590 opStatusRegisterDoneFlag.Value = true; 591 interruptStatusOperationDone.Value = true; 592 UpdateInterrupts(); 593 return; 594 } 595 596 var notAllowed = false; 597 if(flashSelectBankEraseMode.Value) 598 { 599 switch(bankNumber) 600 { 601 case 0: 602 notAllowed = !eraseBank0.Value; 603 break; 604 case 1: 605 notAllowed = !eraseBank1.Value; 606 break; 607 default: 608 notAllowed = true; 609 break; 610 } 611 } 612 else 613 { 614 notAllowed = !IsOperationAllowed(OperationType.EraseDataPage, truncatedOffset); 615 } 616 617 if(notAllowed) 618 { 619 opStatusRegisterErrorFlag.Value = true; 620 opStatusRegisterDoneFlag.Value = true; 621 interruptStatusOperationDone.Value = true; 622 errorCodeMemoryProtectionError.Value = true; 623 UpdateInterrupts(); 624 return; 625 } 626 627 for(var i = 0 ; i < size ; i += 4) 628 { 629 WriteFlashDoubleWord(truncatedOffset + i, 0xffffffff); 630 } 631 opStatusRegisterDoneFlag.Value = true; 632 interruptStatusOperationDone.Value = true; 633 UpdateInterrupts(); 634 } 635 UpdateReadFifoSignals(bool readInProgress)636 private void UpdateReadFifoSignals(bool readInProgress) 637 { 638 var flashOffset = (uint)address.Value; 639 if(readInProgress) 640 { 641 var wordsLeft = (readOffset - flashOffset) / 4 + 1; 642 statusReadFullFlag.Value = wordsLeft >= 16; 643 interruptStatusReadFull.Value |= statusReadFullFlag.Value; 644 interruptStatusReadLevel.Value |= wordsLeft >= (long)readFifoLevel.Value; 645 statusReadEmptyFlag.Value = false; 646 } 647 else 648 { 649 statusReadFullFlag.Value = false; 650 statusReadEmptyFlag.Value = true; 651 } 652 UpdateInterrupts(); 653 } 654 IsOffsetInBounds(long offset)655 private bool IsOffsetInBounds(long offset) 656 { 657 if(offset < 0) 658 { 659 return false; 660 } 661 662 if(flashSelectPartition.Value) 663 { 664 var infoType = flashSelectInfo.Value; 665 return (offset % BytesPerBank) < BytesPerPage * FlashNumberOfPagesInInfo[infoType]; 666 } 667 else 668 { 669 return offset < BytesPerBank * FlashNumberOfBanks; 670 } 671 } 672 IsOperationAllowed(OperationType opType, long operationOffset)673 private bool IsOperationAllowed(OperationType opType, long operationOffset) 674 { 675 return flashSelectPartition.Value 676 ? IsOperationAllowedInfo(opType, operationOffset) 677 : IsOperationAllowedData(opType, operationOffset); 678 } 679 IsOperationAllowedInfo(OperationType opType, long operationOffset)680 private bool IsOperationAllowedInfo(OperationType opType, long operationOffset) 681 { 682 var bankNumber = operationOffset / BytesPerBank; 683 var infoType = flashSelectInfo.Value; 684 var pageNumber = (operationOffset % BytesPerBank) / BytesPerPage; 685 686 if(bankInfoPageEnabled[bankNumber, infoType][pageNumber].Value == MultiBitBool4.False) 687 { 688 return false; 689 } 690 691 var ret = false; 692 switch(opType) 693 { 694 case OperationType.ReadData: 695 ret = (bankInfoPageReadEnabled[bankNumber, infoType][pageNumber].Value == MultiBitBool4.True); 696 break; 697 case OperationType.ProgramData: 698 ret = (bankInfoPageProgramEnabled[bankNumber, infoType][pageNumber].Value == MultiBitBool4.True); 699 break; 700 case OperationType.EraseDataPage: 701 ret = (bankInfoPageEraseEnabled[bankNumber, infoType][pageNumber].Value == MultiBitBool4.True); 702 break; 703 case OperationType.ScrambleData: 704 ret = (bankInfoPageScrambleEnabled[bankNumber, infoType][pageNumber].Value == MultiBitBool4.True); 705 break; 706 case OperationType.Ecc: 707 ret = (bankInfoPageEccEnabled[bankNumber, infoType][pageNumber].Value == MultiBitBool4.True); 708 break; 709 case OperationType.HighEndurance: 710 ret = (bankInfoPageHighEnduranceEnabled[bankNumber, infoType][pageNumber].Value == MultiBitBool4.True); 711 break; 712 default: 713 break; 714 } 715 716 if(!ret) 717 { 718 this.Log( 719 LogLevel.Debug, "OpenTitan_FlashController/IsOperationAllowedInfo: Operation not allowed!"); 720 } 721 722 return ret; 723 } 724 IsOperationAllowedInDefaultRegion(OperationType opType)725 private bool IsOperationAllowedInDefaultRegion(OperationType opType) 726 { 727 var ret = false; 728 switch(opType) 729 { 730 case OperationType.ReadData: 731 ret = (defaultMpRegionReadEnabled.Value == MultiBitBool4.True); 732 break; 733 case OperationType.ProgramData: 734 ret = (defaultMpRegionProgEnabled.Value == MultiBitBool4.True); 735 break; 736 case OperationType.EraseDataPage: 737 ret = (defaultMpRegionEraseEnabled.Value == MultiBitBool4.True); 738 break; 739 case OperationType.ScrambleData: 740 ret = (defaultMpRegionScrambleEnabled.Value == MultiBitBool4.True); 741 break; 742 case OperationType.Ecc: 743 ret = (defaultMpRegionEccEnabled.Value == MultiBitBool4.True); 744 break; 745 case OperationType.HighEndurance: 746 ret = (defaultMpRegionHighEnduranceEnabled.Value == MultiBitBool4.True); 747 break; 748 default: 749 break; 750 } 751 752 if(!ret) 753 { 754 this.Log( 755 LogLevel.Debug, 756 "OpenTitan_FlashController/IsOperationAllowedInDefaultRegion: Operation not allowed in the default region"); 757 } 758 759 return ret; 760 } 761 IsOperationAllowedData(OperationType opType, long operationOffset)762 private bool IsOperationAllowedData(OperationType opType, long operationOffset) 763 { 764 var ret = false; 765 var matched = false; 766 767 for(var i = 0; i < NumberOfMpRegions; i++) 768 { 769 if(MpRegionRegisterAppliesToOperation(i, operationOffset)) 770 { 771 matched = true; 772 ret = IsOperationAllowedInMpRegion(opType, i); 773 break; 774 } 775 } 776 if(!matched) 777 { 778 ret = IsOperationAllowedInDefaultRegion(opType); 779 } 780 781 if(!ret) 782 { 783 this.Log( 784 LogLevel.Debug, "OpenTitan_FlashController/IsOperationAllowedData: Operation not allowed!"); 785 } 786 787 return ret; 788 } 789 IsOperationAllowedInMpRegion(OperationType opType, int regionId)790 private bool IsOperationAllowedInMpRegion(OperationType opType, int regionId) 791 { 792 if(mpRegionEnabled[regionId].Value == MultiBitBool4.False) 793 { 794 return false; 795 } 796 797 var ret = false; 798 switch(opType) 799 { 800 case OperationType.ReadData: 801 ret = (mpRegionReadEnabled[regionId].Value == MultiBitBool4.True); 802 break; 803 case OperationType.ProgramData: 804 ret = (mpRegionProgEnabled[regionId].Value == MultiBitBool4.True); 805 break; 806 case OperationType.EraseDataPage: 807 ret = (mpRegionEraseEnabled[regionId].Value == MultiBitBool4.True); 808 break; 809 case OperationType.ScrambleData: 810 ret = (mpRegionScrambleEnabled[regionId].Value == MultiBitBool4.True); 811 break; 812 case OperationType.Ecc: 813 ret = (mpRegionEccEnabled[regionId].Value == MultiBitBool4.True); 814 break; 815 case OperationType.HighEndurance: 816 ret = (mpRegionHighEnduranceEnabled[regionId].Value == MultiBitBool4.True); 817 break; 818 default: 819 break; 820 } 821 822 if(!ret) 823 { 824 this.Log( 825 LogLevel.Debug, "OpenTitan_FlashController/IsOperationAllowedInMpRegion: Operation not allowed!"); 826 } 827 828 return ret; 829 } 830 MpRegionRegisterAppliesToOperation(int regionId, long operationOffset)831 private bool MpRegionRegisterAppliesToOperation(int regionId, long operationOffset) 832 { 833 if(mpRegionEnabled[regionId].Value == MultiBitBool4.False) 834 { 835 return false; 836 } 837 838 var operationPage = operationOffset / BytesPerPage; 839 var regionStart = (uint)mpRegionBase[regionId].Value; 840 var regionEnd = regionStart + (uint)mpRegionSize[regionId].Value; 841 842 return regionStart <= operationPage && operationPage < regionEnd; 843 } 844 WriteFlashDoubleWord(long offset, uint value)845 private void WriteFlashDoubleWord(long offset, uint value) 846 { 847 if(flashSelectPartition.Value) 848 { 849 var bankNumber = offset / BytesPerBank; 850 var bankOffset = offset % BytesPerBank; 851 852 infoFlash[bankNumber, flashSelectInfo.Value].WriteDoubleWord(bankOffset, value); 853 } 854 else 855 { 856 dataFlash.WriteDoubleWord(offset, value); 857 } 858 } 859 ReadFlashDoubleWord(long offset)860 private uint ReadFlashDoubleWord(long offset) 861 { 862 if(flashSelectPartition.Value) 863 { 864 var bankNumber = offset / BytesPerBank; 865 var bankOffset = offset % BytesPerBank; 866 867 return infoFlash[bankNumber, flashSelectInfo.Value].ReadDoubleWord(bankOffset); 868 } 869 else 870 { 871 return dataFlash.ReadDoubleWord(offset); 872 } 873 } 874 UpdateInterrupts()875 private void UpdateInterrupts() 876 { 877 ProgramEmptyIRQ.Set(interruptStatusProgramEmpty.Value && interruptEnableProgramEmpty.Value); 878 ProgramLevelIRQ.Set(interruptStatusProgramLevel.Value && interruptEnableProgramLevel.Value); 879 ReadFullIRQ.Set(interruptStatusReadFull.Value && interruptEnableReadFull.Value); 880 ReadLevelIRQ.Set(interruptStatusReadLevel.Value && interruptEnableReadLevel.Value); 881 OperationDoneIRQ.Set(interruptStatusOperationDone.Value && interruptEnableOperationDone.Value); 882 CorrectableErrorIRQ.Set(interruptStatusCorrectableError.Value && interruptEnableCorrectableError.Value); 883 } 884 885 private long readOffset; 886 private long programOffset; 887 private long? flashAddress; 888 889 private readonly IFlagRegisterField interruptStatusProgramEmpty; 890 private readonly IFlagRegisterField interruptStatusProgramLevel; 891 private readonly IFlagRegisterField interruptStatusReadFull; 892 private readonly IFlagRegisterField interruptStatusReadLevel; 893 private readonly IFlagRegisterField interruptStatusOperationDone; 894 private readonly IFlagRegisterField interruptStatusCorrectableError; 895 896 private readonly IFlagRegisterField interruptEnableProgramEmpty; 897 private readonly IFlagRegisterField interruptEnableProgramLevel; 898 private readonly IFlagRegisterField interruptEnableReadFull; 899 private readonly IFlagRegisterField interruptEnableReadLevel; 900 private readonly IFlagRegisterField interruptEnableOperationDone; 901 private readonly IFlagRegisterField interruptEnableCorrectableError; 902 903 private readonly MappedMemory dataFlash; 904 private readonly ArrayMemory[,] infoFlash; 905 // This is required as the tests use full address or just flash offset 906 private readonly uint flashAddressMask; 907 private readonly IFlagRegisterField opStatusRegisterDoneFlag; 908 private readonly IFlagRegisterField opStatusRegisterErrorFlag; 909 private readonly IFlagRegisterField statusReadFullFlag; 910 private readonly IFlagRegisterField statusReadEmptyFlag; 911 912 private readonly IFlagRegisterField errorCodeOutOfBoundsError; 913 private readonly IFlagRegisterField errorCodeMemoryProtectionError; 914 915 private readonly IEnumRegisterField<MultiBitBool4> defaultMpRegionReadEnabled; 916 private readonly IEnumRegisterField<MultiBitBool4> defaultMpRegionProgEnabled; 917 private readonly IEnumRegisterField<MultiBitBool4> defaultMpRegionEraseEnabled; 918 private readonly IEnumRegisterField<MultiBitBool4> defaultMpRegionScrambleEnabled; 919 private readonly IEnumRegisterField<MultiBitBool4> defaultMpRegionEccEnabled; 920 private readonly IEnumRegisterField<MultiBitBool4> defaultMpRegionHighEnduranceEnabled; 921 922 private readonly IEnumRegisterField<MultiBitBool4>[] mpRegionEnabled; 923 private readonly IValueRegisterField[] mpRegionBase; 924 private readonly IValueRegisterField[] mpRegionSize; 925 private readonly IEnumRegisterField<MultiBitBool4>[] mpRegionReadEnabled; 926 private readonly IEnumRegisterField<MultiBitBool4>[] mpRegionProgEnabled; 927 private readonly IEnumRegisterField<MultiBitBool4>[] mpRegionEraseEnabled; 928 private readonly IEnumRegisterField<MultiBitBool4>[] mpRegionScrambleEnabled; 929 private readonly IEnumRegisterField<MultiBitBool4>[] mpRegionEccEnabled; 930 private readonly IEnumRegisterField<MultiBitBool4>[] mpRegionHighEnduranceEnabled; 931 private readonly IEnumRegisterField<MultiBitBool4>[,][] bankInfoPageEnabled; 932 private readonly IEnumRegisterField<MultiBitBool4>[,][] bankInfoPageReadEnabled; 933 private readonly IEnumRegisterField<MultiBitBool4>[,][] bankInfoPageProgramEnabled; 934 private readonly IEnumRegisterField<MultiBitBool4>[,][] bankInfoPageEraseEnabled; 935 private readonly IEnumRegisterField<MultiBitBool4>[,][] bankInfoPageScrambleEnabled; 936 private readonly IEnumRegisterField<MultiBitBool4>[,][] bankInfoPageEccEnabled; 937 private readonly IEnumRegisterField<MultiBitBool4>[,][] bankInfoPageHighEnduranceEnabled; 938 939 private readonly IFlagRegisterField flashSelectBankEraseMode; 940 private readonly IFlagRegisterField flashSelectPartition; 941 private readonly IValueRegisterField flashSelectInfo; 942 943 private readonly IFlagRegisterField eraseBank0; 944 private readonly IFlagRegisterField eraseBank1; 945 946 private readonly IValueRegisterField address; 947 948 private readonly IEnumRegisterField<ControlOp> operation; 949 950 private readonly IValueRegisterField controlNum; 951 952 private readonly IValueRegisterField errorAddress; 953 954 private readonly IValueRegisterField programFifoLevel; 955 private readonly IValueRegisterField readFifoLevel; 956 957 private readonly uint[] FlashNumberOfPagesInInfo = { 10, 1, 2 }; 958 959 private const uint ReadFifoDepth = 16; 960 private const uint ProgramFifoDepth = 16; 961 private const uint FlashWordsPerPage = 256; 962 private const uint FlashWordSize = 8; 963 private const uint FlashPagesPerBank = 256; 964 private const uint FlashNumberOfBanks = 2; 965 private const uint FlashNumberOfInfoTypes = 3; 966 967 private const int NumberOfMpRegions = 8; 968 private const uint BytesPerPage = FlashWordsPerPage * FlashWordSize; 969 private const uint BytesPerBank = FlashPagesPerBank * BytesPerPage; 970 971 #pragma warning restore format 972 private enum Registers : long 973 { 974 InterruptState = 0x000, 975 InterruptEnable = 0x004, 976 InterruptTest = 0x008, 977 AlertTest = 0x00C, 978 DisableFlashFunctionality = 0x010, 979 ExecutionFetchesEnabled = 0x014, 980 ControllerInit = 0x018, 981 ControlEnable = 0x01C, 982 Control = 0x020, 983 AddressForFlashOperation = 0x024, 984 EnableDifferentProgramTypes = 0x028, 985 SuspendErase = 0x02C, 986 RegionConfigurationEnable0 = 0x030, 987 RegionConfigurationEnable1 = 0x034, 988 RegionConfigurationEnable2 = 0x038, 989 RegionConfigurationEnable3 = 0x03C, 990 RegionConfigurationEnable4 = 0x040, 991 RegionConfigurationEnable5 = 0x044, 992 RegionConfigurationEnable6 = 0x048, 993 RegionConfigurationEnable7 = 0x04C, 994 RegionConfiguration0 = 0x050, 995 RegionConfiguration1 = 0x054, 996 RegionConfiguration2 = 0x058, 997 RegionConfiguration3 = 0x05C, 998 RegionConfiguration4 = 0x060, 999 RegionConfiguration5 = 0x064, 1000 RegionConfiguration6 = 0x068, 1001 RegionConfiguration7 = 0x06C, 1002 RegionBaseAndSizeConfiguration0 = 0x070, 1003 RegionBaseAndSizeConfiguration1 = 0x074, 1004 RegionBaseAndSizeConfiguration2 = 0x078, 1005 RegionBaseAndSizeConfiguration3 = 0x07C, 1006 RegionBaseAndSizeConfiguration4 = 0x080, 1007 RegionBaseAndSizeConfiguration5 = 0x084, 1008 RegionBaseAndSizeConfiguration6 = 0x088, 1009 RegionBaseAndSizeConfiguration7 = 0x08C, 1010 DefaultRegionConfiguration = 0x090, 1011 Bank0Info0Enable0 = 0x094, 1012 Bank0Info0Enable1 = 0x098, 1013 Bank0Info0Enable2 = 0x09C, 1014 Bank0Info0Enable3 = 0x0A0, 1015 Bank0Info0Enable4 = 0x0A4, 1016 Bank0Info0Enable5 = 0x0A8, 1017 Bank0Info0Enable6 = 0x0AC, 1018 Bank0Info0Enable7 = 0x0B0, 1019 Bank0Info0Enable8 = 0x0B4, 1020 Bank0Info0Enable9 = 0x0B8, 1021 Bank0Info0PageConfiguration0 = 0x0BC, 1022 Bank0Info0PageConfiguration1 = 0x0C0, 1023 Bank0Info0PageConfiguration2 = 0x0C4, 1024 Bank0Info0PageConfiguration3 = 0x0C8, 1025 Bank0Info0PageConfiguration4 = 0x0CC, 1026 Bank0Info0PageConfiguration5 = 0x0D0, 1027 Bank0Info0PageConfiguration6 = 0x0D4, 1028 Bank0Info0PageConfiguration7 = 0x0D8, 1029 Bank0Info0PageConfiguration8 = 0x0DC, 1030 Bank0Info0PageConfiguration9 = 0x0E0, 1031 Bank0Info1Enable = 0x0E4, 1032 Bank0Info1PageConfiguration = 0x0E8, 1033 Bank0Info2Enable0 = 0x0EC, 1034 Bank0Info2Enable1 = 0x0F0, 1035 Bank0Info2PageConfiguration0 = 0x0F4, 1036 Bank0Info2PageConfiguration1 = 0x0F8, 1037 Bank1Info0Enable0 = 0x0FC, 1038 Bank1Info0Enable1 = 0x100, 1039 Bank1Info0Enable2 = 0x104, 1040 Bank1Info0Enable3 = 0x108, 1041 Bank1Info0Enable4 = 0x10C, 1042 Bank1Info0Enable5 = 0x110, 1043 Bank1Info0Enable6 = 0x114, 1044 Bank1Info0Enable7 = 0x118, 1045 Bank1Info0Enable8 = 0x11C, 1046 Bank1Info0Enable9 = 0x120, 1047 Bank1Info0PageConfiguration0 = 0x124, 1048 Bank1Info0PageConfiguration1 = 0x128, 1049 Bank1Info0PageConfiguration2 = 0x12C, 1050 Bank1Info0PageConfiguration3 = 0x130, 1051 Bank1Info0PageConfiguration4 = 0x134, 1052 Bank1Info0PageConfiguration5 = 0x138, 1053 Bank1Info0PageConfiguration6 = 0x13C, 1054 Bank1Info0PageConfiguration7 = 0x140, 1055 Bank1Info0PageConfiguration8 = 0x144, 1056 Bank1Info0PageConfiguration9 = 0x148, 1057 Bank1Info1Enable = 0x14C, 1058 Bank1Info1PageConfiguration = 0x150, 1059 Bank1Info2Enable0 = 0x154, 1060 Bank1Info2Enable1 = 0x158, 1061 Bank1Info2PageConfiguration0 = 0x15C, 1062 Bank1Info2PageConfiguration1 = 0x160, 1063 HardwareInfoConfigurationOverride = 0x164, 1064 BankConfigurationEnable = 0x164+0x4, 1065 BankConfiguration = 0x168+0x4, 1066 FlashOperationStatus = 0x16C+0x4, 1067 Status = 0x170+0x4, 1068 ErrorCode = 0x174+0x4, 1069 FaultStatus = 0x178+0x4, 1070 ErrorAddress = 0x17C+0x4, 1071 ECCSingleErrorCount = 0x180+0x4, 1072 ECCSingleErrorAddress0 = 0x184+0x4, 1073 ECCSingleErrorAddress1 = 0x188+0x4, 1074 PhyErrorConfigurationEnable = 0x18C+0x4, 1075 PhyErrorConfiguration = 0x190+0x4, 1076 PhyAlertConfiguration = 0x194+0x4, 1077 PhyStatus = 0x198+0x4, 1078 Scratch = 0x19C+0x4, 1079 FifoLevel = 0x1A0+0x4, 1080 FifoReset = 0x1A4+0x4, 1081 CurrengFifoLevel = 0x1A8+0x4, 1082 ProgramFifo = 0x1AC+0x4, // 1 item wo window. Byte writes are not supported 1083 ReadFifo = 0x1B0+0x4, // 1 item ro window. Byte writes are not supported 1084 } 1085 1086 private enum ControlOp : uint 1087 { 1088 FlashRead = 0x0, 1089 FlashProgram = 0x1, 1090 FlashErase = 0x2 1091 } 1092 1093 private enum OperationType 1094 { 1095 ReadData, 1096 ProgramData, 1097 EraseDataPage, 1098 ScrambleData, 1099 Ecc, 1100 HighEndurance 1101 } 1102 #pragma warning restore format 1103 } // class 1104 } // namespace 1105