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 System.Collections.Generic;
9 using System.Linq;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Core.Structure;
12 using Antmicro.Renode.Core.Structure.Registers;
13 using Antmicro.Renode.Exceptions;
14 using Antmicro.Renode.Logging;
15 using Antmicro.Renode.Peripherals.Bus;
16 using Antmicro.Renode.Peripherals.Memory;
17 using Antmicro.Renode.Peripherals.MTD;
18 using static Antmicro.Renode.Peripherals.Bus.GaislerAPBPlugAndPlayRecord;
19 
20 namespace Antmicro.Renode.Peripherals.MemoryControllers
21 {
22     public class Gaisler_FaultTolerantMemoryController : BasicDoubleWordPeripheral, IKnownSize, IGaislerAPB,
23         IPeripheralContainer<MappedMemory, NullRegistrationPoint>, IPeripheralContainer<AMDCFIFlash, NullRegistrationPoint>
24     {
Gaisler_FaultTolerantMemoryController(IMachine machine)25         public Gaisler_FaultTolerantMemoryController(IMachine machine) : base(machine)
26         {
27             DefineRegisters();
28             Reset();
29         }
30 
Reset()31         public override void Reset()
32         {
33             base.Reset();
34             SetPromWriteEnable(false);
35         }
36 
GetRegistrationPoints(MappedMemory peripheral)37         public IEnumerable<NullRegistrationPoint> GetRegistrationPoints(MappedMemory peripheral)
38         {
39             return prom != null ?
40                 new [] { NullRegistrationPoint.Instance } :
41                 Enumerable.Empty<NullRegistrationPoint>();
42         }
43 
Register(MappedMemory peripheral, NullRegistrationPoint registrationPoint)44         public void Register(MappedMemory peripheral, NullRegistrationPoint registrationPoint)
45         {
46             if(prom != null)
47             {
48                 throw new RegistrationException("PROM MappedMemory already registered");
49             }
50 
51             machine.RegisterAsAChildOf(this, peripheral, registrationPoint);
52             prom = peripheral;
53             promAddress = sysbus.GetRegistrationPoints(prom).Single().Range.StartAddress;
54         }
55 
Unregister(MappedMemory peripheral)56         public void Unregister(MappedMemory peripheral)
57         {
58             prom = null;
59         }
60 
GetRegistrationPoints(AMDCFIFlash peripheral)61         public IEnumerable<NullRegistrationPoint> GetRegistrationPoints(AMDCFIFlash peripheral)
62         {
63             return flash != null ?
64                 new [] { NullRegistrationPoint.Instance } :
65                 Enumerable.Empty<NullRegistrationPoint>();
66         }
67 
Register(AMDCFIFlash peripheral, NullRegistrationPoint registrationPoint)68         public void Register(AMDCFIFlash peripheral, NullRegistrationPoint registrationPoint)
69         {
70             if(flash != null)
71             {
72                 throw new RegistrationException("Flash already registered");
73             }
74 
75             machine.RegisterAsAChildOf(this, peripheral, registrationPoint);
76             flash = peripheral;
77         }
78 
Unregister(AMDCFIFlash peripheral)79         public void Unregister(AMDCFIFlash peripheral)
80         {
81             flash = null;
82         }
83 
84         public long Size => 0x100;
85 
86         IEnumerable<IRegistered<MappedMemory, NullRegistrationPoint>> IPeripheralContainer<MappedMemory, NullRegistrationPoint>.Children
87         {
88             get => prom != null ?
89                 new [] { Registered.Create(prom, NullRegistrationPoint.Instance) } :
90                 Enumerable.Empty<IRegistered<MappedMemory, NullRegistrationPoint>>();
91         }
92 
93         IEnumerable<IRegistered<AMDCFIFlash, NullRegistrationPoint>> IPeripheralContainer<AMDCFIFlash, NullRegistrationPoint>.Children
94         {
95             get => flash != null ?
96                 new [] { Registered.Create(flash, NullRegistrationPoint.Instance) } :
97                 Enumerable.Empty<IRegistered<AMDCFIFlash, NullRegistrationPoint>>();
98         }
99 
DefineRegisters()100         private void DefineRegisters()
101         {
102             Registers.MemoryConfiguration1.Define(this)
103                 .WithTag("promReadWaitStates", 0, 4)
104                 .WithTag("promWriteWaitStates", 4, 4)
105                 .WithTag("promWidth", 8, 2)
106                 .WithReservedBits(10, 1)
107                 .WithFlag(11, name: "promWriteEnable", changeCallback: (_, value) => SetPromWriteEnable(value))
108                 .WithReservedBits(12, 2)
109                 .WithTag("promBankSize", 14, 3)
110                 .WithReservedBits(18, 1)
111                 .WithTaggedFlag("ioEnable", 19)
112                 .WithTag("ioWaitStates", 20, 4)
113                 .WithReservedBits(24, 1)
114                 .WithTaggedFlag("busErrorCode", 25)
115                 .WithTaggedFlag("ioBusReadyEnable", 26)
116                 .WithTag("ioBusWidth", 27, 2)
117                 .WithTaggedFlag("asynchronousBusReady", 29)
118                 .WithTaggedFlag("promAreaBusReady", 30)
119                 .WithReservedBits(31, 1);
120 
121             Registers.MemoryConfiguration2.Define(this)
122                 .WithTag("ramReadWaitStates", 0, 2)
123                 .WithTag("ramWriteWaitStates", 2, 2)
124                 .WithTag("ramWidth", 4, 2)
125                 .WithTaggedFlag("readModifyWrite", 6)
126                 .WithReservedBits(7, 2)
127                 .WithTag("ramBankSize", 9, 4)
128                 .WithTaggedFlag("sramDisable", 13)
129                 .WithTaggedFlag("sdramEnable", 14)
130                 .WithReservedBits(15, 4)
131                 .WithTag("sdramCommand", 19, 2)
132                 .WithTag("sdramColumnSize", 21, 2)
133                 .WithTag("sdramBankSize", 23, 3)
134                 .WithTaggedFlag("sdramTcas", 26)
135                 .WithTag("sdramTrfc", 27, 3)
136                 .WithTaggedFlag("sdramTrp", 30)
137                 .WithTaggedFlag("sdramRefreshEnable", 31);
138 
139             Registers.MemoryConfiguration3.Define(this)
140                 .WithTag("testCheckbits", 0, 8)
141                 .WithTaggedFlag("promEdacEnable", 8)
142                 .WithTaggedFlag("ramEdacEnable", 9)
143                 .WithTaggedFlag("edacDiagnosticReadBypass", 10)
144                 .WithTaggedFlag("edacDiagnosticWriteBypass", 11)
145                 .WithTag("sdramRefreshCounterReload", 12, 15)
146                 .WithReservedBits(27, 1)
147                 .WithTaggedFlag("reedSolomonEdacEnable", 28)
148                 .WithReservedBits(29, 3);
149 
150             Registers.MemoryConfiguration4.Define(this)
151                 .WithTag("testCheckbits", 0, 16)
152                 .WithTaggedFlag("edacDiagnosticWriteBypass", 16)
153                 .WithReservedBits(17, 15);
154         }
155 
SetPromWriteEnable(bool enable)156         private void SetPromWriteEnable(bool enable)
157         {
158             if(isWriteEnabled == enable)
159             {
160                 return;
161             }
162             if(prom == null || flash == null)
163             {
164                 this.ErrorLog("Attempted to set PROM write enable to {0} without a {1} (PROM) or {2} (flash) registered",
165                     enable, nameof(MappedMemory), nameof(AMDCFIFlash));
166                 return;
167             }
168             this.DebugLog("Set PROM Write enable to {0}", enable);
169             if(enable)
170             {
171                 sysbus.Unregister(prom);
172                 sysbus.Register(flash, new BusPointRegistration(promAddress.Value));
173             }
174             else
175             {
176                 sysbus.Unregister(flash);
177                 sysbus.Register(prom, new BusPointRegistration(promAddress.Value));
178             }
179             isWriteEnabled = enable;
180         }
181 
GetVendorID()182         public uint GetVendorID() => VendorID;
183 
GetDeviceID()184         public uint GetDeviceID() => DeviceID;
185 
GetInterruptNumber()186         public uint GetInterruptNumber() => 0;
187 
GetSpaceType()188         public SpaceType GetSpaceType() => SpaceType.APBIOSpace;
189 
190         private ulong? promAddress;
191         private bool isWriteEnabled;
192         private MappedMemory prom;
193         private AMDCFIFlash flash;
194 
195         private const uint VendorID = 0x01;  // Frontgrade Gaisler
196         private const uint DeviceID = 0x054; // FTMCTRL
197 
198         private enum Registers : uint
199         {
200             MemoryConfiguration1 = 0x0,
201             MemoryConfiguration2 = 0x4,
202             MemoryConfiguration3 = 0x8,
203             MemoryConfiguration4 = 0xc,
204         }
205     }
206 }
207