1 //
2 // Copyright (c) 2010-2024 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System.Collections.Generic;
8 using System.Linq;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Core.Structure;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Exceptions;
13 using Antmicro.Renode.Logging;
14 using Antmicro.Renode.Peripherals.Miscellaneous.S32K3XX_FlexIOModel;
15 
16 namespace Antmicro.Renode.Peripherals.Miscellaneous
17 {
18     public class S32K3XX_FlexIO : BasicDoubleWordPeripheral, IPeripheralContainer<IEndpoint, NullRegistrationPoint>, IKnownSize,
19         IResourceBlockOwner
20     {
S32K3XX_FlexIO(IMachine machine)21         public S32K3XX_FlexIO(IMachine machine) : base(machine)
22         {
23             timers = Timer.BuildRegisters(this, TimerCount);
24             TimersManager = new ResourceBlocksManager<Timer>(this, "timer", timers);
25             foreach(var timer in timers)
26             {
27                 timer.AnyInterruptChanged += UpdateInterrupt;
28             }
29 
30             shifters = Shifter.BuildRegisters(this, ShifterCount, TimersManager);
31             ShiftersManager = new ResourceBlocksManager<Shifter>(this, "shifter", shifters);
32             foreach(var shifter in shifters)
33             {
34                 shifter.AnyInterruptChanged += UpdateInterrupt;
35             }
36 
37             DefineRegisters();
38         }
39 
Reset()40         public override void Reset()
41         {
42             inReset.Value = false;
43             enabled.Value = false;
44             InternalReset();
45         }
46 
GetRegistrationPoints(IEndpoint peripheral)47         public IEnumerable<NullRegistrationPoint> GetRegistrationPoints(IEndpoint peripheral)
48         {
49             return endpoints.Select(_ => NullRegistrationPoint.Instance);
50         }
51 
Register(IEndpoint peripheral, NullRegistrationPoint registrationPoint)52         public void Register(IEndpoint peripheral, NullRegistrationPoint registrationPoint)
53         {
54             if(endpoints.Contains(peripheral))
55             {
56                 throw new RegistrationException("The specified endpoint is already registered.");
57             }
58             endpoints.Add(peripheral);
59             machine.RegisterAsAChildOf(this, peripheral, registrationPoint);
60             peripheral.RegisterInFlexIO(this);
61         }
62 
Unregister(IEndpoint peripheral)63         public void Unregister(IEndpoint peripheral)
64         {
65             if(!endpoints.Contains(peripheral))
66             {
67                 throw new RegistrationException("The specified endpoint was never registered.");
68             }
69             endpoints.Remove(peripheral);
70             machine.UnregisterAsAChildOf(this, peripheral);
71         }
72 
73         public IEnumerable<IRegistered<IEndpoint, NullRegistrationPoint>> Children => endpoints.Select(x => Registered.Create(x, NullRegistrationPoint.Instance));
74         public uint Frequency { get; set; }
75         public GPIO IRQ { get; } = new GPIO();
76         public long Size => 0x4000;
77 
78         public ResourceBlocksManager<Shifter> ShiftersManager { get; }
79         public ResourceBlocksManager<Timer> TimersManager { get; }
80 
DefineRegisters()81         private void DefineRegisters()
82         {
83             Registers.VersionID.Define(this, 0x02010003)
84                 .WithValueField(24, 8, FieldMode.Read, name: "MAJOR (Major Version)")
85                 .WithValueField(16, 8, FieldMode.Read, name: "MINOR (Minor Version)")
86                 .WithValueField(0, 16, FieldMode.Read, name: "FEATURE (Feature Specification)");
87 
88             Registers.Parameter.Define(this, 0x04000000)
89                 .WithTag("TRIGGER (Trigger Number)", 24, 8)
90                 .WithValueField(16, 8, FieldMode.Read, name: "PIN (Pin Number)",
91                     valueProviderCallback: _ => PinCount
92                 )
93                 .WithValueField(8, 8, FieldMode.Read, name: "TIMER (Timer Number)",
94                     valueProviderCallback: _ => (ulong)timers.Count
95                 )
96                 .WithValueField(0, 8, FieldMode.Read, name: "SHIFTER (Shifter Number)",
97                     valueProviderCallback: _ => (ulong)shifters.Count
98                 );
99 
100             Registers.Control.Define(this, softResettable: false)
101                 .WithReservedBits(31, 1)
102                 .WithTaggedFlag("DBGE (Debug Enable)", 30)
103                 .WithReservedBits(2, 28)
104                 .WithFlag(1, out inReset, name: "SWRSRT (Software Reset)",
105                     changeCallback: (_, val) => { if(val) InternalReset(); }
106                 )
107                 .WithFlag(0, out enabled, name: "FLEXEN (Enable)");
108 
109             Registers.PinState.Define(this)
110                 .WithTag("PDI (Pin Data Input)", 0, 32);
111 
112             Registers.ShifterStatusDMAEnable.Define(this)
113                 .WithReservedBits(8, 24)
114                 .WithTag("SSDE (Shifter Status DMA Enable)", 0, 8);
115 
116             Registers.TimerStatusDMAEnable.Define(this)
117                 .WithReservedBits(8, 24)
118                 .WithTag("TSDE (Timer Status DMA Enable)", 0, 8);
119 
120             Registers.ShifterState.Define(this)
121                 .WithReservedBits(3, 29)
122                 .WithTag("STATE (Current State Pointer)", 0, 3);
123 
124             Registers.TriggerStatus.Define(this)
125                 .WithReservedBits(4, 28)
126                 .WithTag("ETSF (External Trigger Status Flag)", 0, 4);
127 
128             Registers.ExternalTriggerInterruptEnable.Define(this)
129                 .WithReservedBits(4, 28)
130                 .WithTag("TRIE (External Trigger Interrupt Enable)", 0, 4);
131 
132             Registers.PinStatus.Define(this)
133                 .WithTag("PSF (Pin Status Flag)", 0, PinCount);
134 
135             Registers.PinInterruptEnable.Define(this)
136                 .WithTag("PSIE (Pin Status Interrupt Enable)", 0, PinCount);
137 
138             Registers.PinRisingEdgeEnable.Define(this)
139                 .WithTag("PRE (Pin Rising Edge)", 0, PinCount);
140 
141             Registers.PinFallingEdgeEnable.Define(this)
142                 .WithTag("PFE (Pin Falling Edge)", 0, PinCount);
143 
144             Registers.PinOutputData.Define(this)
145                 .WithTag("OUTD (Output Data)", 0, PinCount);
146 
147             Registers.PinOutputEnable.Define(this)
148                 .WithTag("OUTE (Output Enable)", 0, PinCount);
149 
150             Registers.PinOutputDisable.Define(this)
151                 .WithTag("OUTDIS (Output Disable)", 0, PinCount);
152 
153             Registers.PinOutputClear.Define(this)
154                 .WithTag("OUTCLR (Output Clear)", 0, PinCount);
155 
156             Registers.PinOutputSet.Define(this)
157                 .WithTag("OUTSET (Output Set)", 0, PinCount);
158 
159             Registers.PinOutputToggle.Define(this)
160                 .WithTag("OUTTOG (Output Toggle)", 0, PinCount);
161         }
162 
InternalReset()163         private void InternalReset()
164         {
165             base.Reset();
166             foreach(var shifter in shifters)
167             {
168                 shifter.Reset();
169             }
170             UpdateInterrupt();
171         }
172 
UpdateInterrupt(bool forceInterrupt = false)173         private void UpdateInterrupt(bool forceInterrupt = false)
174         {
175             var newValue = forceInterrupt || ResourceBlocks.SelectMany(x => x.Interrupts).Any(x => x.MaskedFlag);
176             if(newValue != IRQ.IsSet)
177             {
178                 this.Log(LogLevel.Debug, "Setting the IRQ interrupt to {0}", newValue);
179                 IRQ.Set(newValue);
180             }
181         }
182 
183         private IEnumerable<ResourceBlock> ResourceBlocks => shifters.Concat<ResourceBlock>(timers);
184 
185         private IFlagRegisterField enabled;
186         private IFlagRegisterField inReset;
187 
188         private readonly ISet<IEndpoint> endpoints = new HashSet<IEndpoint>();
189         private readonly IReadOnlyList<Shifter> shifters;
190         private readonly IReadOnlyList<Timer> timers;
191 
192         private const int PinCount = 32;
193         private const int ShifterCount = 8;
194         private const int TimerCount = 8;
195 
196         public enum Registers
197         {
198             VersionID = 0x0, // VERID
199             Parameter = 0x4, // PARAM
200             Control = 0x8, // CTRL
201             PinState = 0xC, // PIN
202             ShifterStatus = 0x10, // SHIFTSTAT
203             ShifterError = 0x14, // SHIFTERR
204             TimerStatus = 0x18, // TIMSTAT
205             ShifterStatusInterruptEnable = 0x20, // SHIFTSIEN
206             ShifterErrorInterruptEnable = 0x24, // SHIFTEIEN
207             TimerInterruptEnable = 0x28, // TIMIEN
208             ShifterStatusDMAEnable = 0x30, // SHIFTSDEN
209             TimerStatusDMAEnable = 0x38, // TIMERSDEN
210             ShifterState = 0x40, // SHIFTSTATE
211             TriggerStatus = 0x48, // TRGSTAT
212             ExternalTriggerInterruptEnable = 0x4C, // TRIGIEN
213             PinStatus = 0x50, // PINSTAT
214             PinInterruptEnable = 0x54, // PINIEN
215             PinRisingEdgeEnable = 0x58, // PINREN
216             PinFallingEdgeEnable = 0x5C, // PINFEN
217             PinOutputData = 0x60, // PINOUTD
218             PinOutputEnable = 0x64, // PINOUTE
219             PinOutputDisable = 0x68, // PINOUTDIS
220             PinOutputClear = 0x6C, // PINOUTCLR
221             PinOutputSet = 0x70, // PINOUTSET
222             PinOutputToggle = 0x74, // PINOUTTOG
223             ShifterControl0 = 0x80, // SHIFTCTL0
224             ShifterControl7 = 0x9C, // SHIFTCTL7
225             ShifterConfiguration0 = 0x100, // SHIFTCFG0
226             ShifterConfiguration7 = 0x11C, // SHIFTCFG7
227             ShifterBuffer0 = 0x200, // SHIFTBUF0
228             ShifterBuffer7 = 0x21C, // SHIFTBUF7
229             ShifterBuffer0BitSwapped = 0x280, // SHIFTBUFBIS0
230             ShifterBuffer7BitSwapped = 0x29C, // SHIFTBUFBIS7
231             ShifterBuffer0ByteSwapped = 0x300, // SHIFTBUFBYS0
232             ShifterBuffer7ByteSwapped = 0x31C, // SHIFTBUFBYS7
233             ShifterBuffer0BitByteSwapped = 0x380, // SHIFTBUFBBS0
234             ShifterBuffer7BitByteSwapped = 0x39C, // SHIFTBUFBBS7
235             TimerControl0 = 0x400, // TIMCTL0
236             TimerControl7 = 0x41C, // TIMCTL7
237             TimerConfiguration0 = 0x480, // TIMCFG0
238             TimerConfiguration7 = 0x49C, // TIMCFG7
239             TimerCompare0 = 0x500, // TIMCMP0
240             TimerCompare7 = 0x51C, // TIMCMP7
241             ShifterBuffer0NibbleByteSwapped = 0x680, // SHIFTBUFNBS0
242             ShifterBuffer7NibbleByteSwapped = 0x69C, // SHIFTBUFNBS7
243             ShifterBuffer0HalfwordSwapped = 0x700, // SHIFTBUFHWS0
244             ShifterBuffer7HalfwordSwapped = 0x71C, // SHIFTBUFHWS7
245             ShifterBuffer0NibbleSwapped = 0x780, // SHIFTBUFNIS0
246             ShifterBuffer7NibbleSwapped = 0x79C, // SHIFTBUFNIS7
247             ShifterBuffer0OddEvenSwapped = 0x800, // SHIFTBUFOES0
248             ShifterBuffer7OddEvenSwapped = 0x81C, // SHIFTBUFOES7
249             ShifterBuffer0EvenOddSwapped = 0x880, // SHIFTBUFEOS0
250             ShifterBuffer7EvenOddSwapped = 0x89C, // HIFTBUFEOS7
251             ShifterBuffer0HalfWordByteSwapped = 0x900, // SHIFTBUFHBS0
252             ShifterBuffer7HalfwordByteSwapped = 0x91C, // SHIFTBUFHBS7
253         }
254     }
255 }
256