1 //
2 // Copyright (c) 2010-2024 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using Antmicro.Renode.Core.Structure.Registers;
9 using Antmicro.Renode.Peripherals.Memory;
10 
11 using Range = Antmicro.Renode.Core.Range;
12 
13 namespace Antmicro.Renode.Peripherals.SPI
14 {
15     public class Macronix_MX25R : GenericSpiFlash
16     {
Macronix_MX25R(MappedMemory underlyingMemory)17         public Macronix_MX25R(MappedMemory underlyingMemory)
18             : base(underlyingMemory, manufacturerId: ManufacturerId, memoryType: MemoryType,
19                    writeStatusCanSetWriteEnable: false)
20         {
21             statusRegister
22                 .WithValueField(2, 4,
23                     writeCallback: (_, value) => UpdateLockedRange((uint)value), name: "BP (level of protected block)")
24                 .WithTaggedFlag("QE (Quad Enable)", 6)
25                 .WithTaggedFlag("SRWD (Status register write protect)", 7);
26 
27             configurationRegister
28                 .WithReservedBits(0, 3)
29                 .WithFlag(3, out topBottom, name: "TB (top/bottom selected)")
30                 .WithReservedBits(4, 2)
31                 .WithTaggedFlag("DC (Dummy Cycle)", 6)
32                 .WithReservedBits(7, 1)
33                 .WithReservedBits(8, 1)
34                 .WithTaggedFlag("L/H Switch", 9)
35                 .WithReservedBits(10, 6);
36         }
37 
WriteToMemory(byte val)38         protected override void WriteToMemory(byte val)
39         {
40             if(!TryVerifyWriteToMemory(out var position))
41             {
42                 return;
43             }
44             var currentVal = underlyingMemory.ReadByte(position);
45             underlyingMemory.WriteByte(position, (byte)(val & currentVal));
46         }
47 
UpdateLockedRange(uint blockProtectionValue)48         private void UpdateLockedRange(uint blockProtectionValue)
49         {
50             if(blockProtectionValue == 0)
51             {
52                 lockedRange = null;
53                 return;
54             }
55 
56             // If protection is enabled (BP != 0), the minimum protected sector count
57             // is 1 (1 << 0). The maximum is 16384 (1 << 14).
58             var protectedSectorShift = (int)(blockProtectionValue - 1);
59             var protectedSectorCount = 1 << protectedSectorShift;
60 
61             // Protected sectors can cover the whole flash.
62             var protectedSize = Math.Min(sectorSize * protectedSectorCount, UnderlyingMemory.Size);
63             var start = topBottom.Value ? 0 : UnderlyingMemory.Size - protectedSize;
64             lockedRange = new Range((ulong)start, (ulong)protectedSize);
65         }
66 
67         private readonly IFlagRegisterField topBottom;
68 
69         private const byte ManufacturerId = 0xC2;
70         private const byte MemoryType = 0x28;
71     }
72 }
73