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