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.Registers;
12 using Antmicro.Renode.Peripherals;
13 using Antmicro.Renode.Peripherals.Bus;
14 using Antmicro.Renode.Peripherals.CPU;
15 
16 namespace Antmicro.Renode.Peripherals.Miscellaneous
17 {
18     public class S32KXX_ModeEntryModule : BasicDoubleWordPeripheral, IKnownSize
19     {
S32KXX_ModeEntryModule(IMachine machine, ICPU core0, ICPU core1 = null, ICPU core2 = null, ICPU core3 = null, ICPU core4 = null, ICPU core5 = null)20         public S32KXX_ModeEntryModule(IMachine machine, ICPU core0,
21             ICPU core1 = null, ICPU core2 = null, ICPU core3 = null, ICPU core4 = null, ICPU core5 = null)
22             : base(machine)
23         {
24             cores = new ICPU[]
25             {
26                 core0,
27                 core1,
28                 core2,
29                 core3,
30                 core4,
31                 core5
32             };
33             cofbsStatus = new uint[][]
34             {
35                 new uint[2],
36                 new uint[4],
37                 new uint[3]
38             };
39             DefineRegisters();
40             Initialize();
41         }
42 
Reset()43         public override void Reset()
44         {
45             base.Reset();
46             Initialize();
47         }
48 
49         public long Size => 0x4000;
50 
DefineRegisters()51         private void DefineRegisters()
52         {
53             Registers.ControlKey.Define(this)
54                 .WithTag("CTL_KEY (Control Key)", 0, 16)
55                 .WithReservedBits(16, 16);
56 
57             Registers.ModeConfiguration.Define(this)
58                 .WithTaggedFlag("DEST_RST (Destructive Reset Request)", 0)
59                 .WithTaggedFlag("FUNC_RST (Functional Reset Request)", 1)
60                 .WithReservedBits(2, 13)
61                 .WithTaggedFlag("STANDBY (Standby Request)", 15)
62                 .WithReservedBits(16, 16);
63 
64             Registers.ModeUpdate.Define(this)
65                 .WithTaggedFlag("MODE_UPD (Mode Update)", 0)
66                 .WithReservedBits(1, 31);
67 
68             Registers.ModeStatus.Define(this)
69                 .WithTaggedFlag("PREV_MODE (Previous Mode)", 0)
70                 .WithReservedBits(1, 31);
71 
72             Registers.MainCoreID.Define(this)
73                 .WithTag("CIDX (Core Index)", 0, 2)
74                 .WithReservedBits(3, 5)
75                 .WithTag("PIDX (Partition Index)", 8, 5)
76                 .WithReservedBits(13, 19);
77 
78             uint partitionSize = Registers.Partition1ProcessConfiguration - Registers.Partition0ProcessConfiguration;
79             Registers.Partition0ProcessConfiguration.DefineMany(this, PartitionCount, stepInBytes: partitionSize, resetValue: 0x1, setup: (reg, index) => reg
80                 .WithTaggedFlag("PCE (Partition Clock Enable)", 0)
81                 .WithReservedBits(1, 31)
82             );
83 
84             Registers.Partition0ProcessUpdate.DefineMany(this, PartitionCount, stepInBytes: partitionSize, setup: (reg, index) => reg
85                 .WithTaggedFlag("PCUD (Partition Clock Update)", 0)
86                 .WithReservedBits(1, 31)
87             );
88 
89             Registers.Partition0Status.DefineMany(this, PartitionCount, stepInBytes: partitionSize, resetValue: 0x1, setup: (reg, index) => reg
90                 .WithTaggedFlag("PCS (Partition Clock Status)", 0)
91                 .WithReservedBits(1, 31)
92             );
93 
94             DefineStatusEnableRegisters(Registers.Partition0COFBSet0ClockStatus, cofbsStatus[0]);
95             DefineStatusEnableRegisters(Registers.Partition1COFBSet0ClockStatus, cofbsStatus[1]);
96             DefineStatusEnableRegisters(Registers.Partition2COFBSet0ClockStatus, cofbsStatus[2]);
97 
98             // Registers specific for the Partition 0
99             Registers.Partition0CoreLockstepControl.Define(this)
100                 .WithReservedBits(0, 2)
101                 .WithTaggedFlag("LS2 (Lockstep 2)", 2)
102                 .WithReservedBits(3, 29);
103 
104             var coreSize = Registers.Partition0Core1ProcessConfiguration - Registers.Partition0Core0ProcessConfiguration;
105             foreach (var index in Enumerable.Range(0, cores.Length).Where(x => x != 2))
106             {
107                 var offset = index * coreSize;
108                 (Registers.Partition0Core0ProcessConfiguration + offset).Define(this)
109                     .WithTaggedFlag($"CCE (Core{index} Clock Enable)", 0)
110                     .WithReservedBits(1, 31);
111 
112                 (Registers.Partition0Core0ProcessUpdate + offset).Define(this)
113                     .WithTaggedFlag($"CCUPD (Core{index} Clock Update)", 0)
114                     .WithReservedBits(1, 31);
115             }
116 
117             // Currently only a single core configuration is supported.
118             // To mimics the initial state of a system, halted cores reports waiting for interrupt.
119             Registers.Partition0Core0Status.DefineMany(this, (uint)cores.Length, stepInBytes: (uint)coreSize, setup: (reg, index) => reg
120                 .WithFlag(0, name: $"CCS (Core{index} Clock Process Status)",
121                     valueProviderCallback: (_) => cores[index] != null
122                 )
123                 .WithReservedBits(1, 30)
124                 .WithFlag(31, name: "WFI (WaitForInterruptStatus)",
125                     valueProviderCallback: (_) => cores[index]?.IsHalted ?? false
126                 )
127             );
128 
129             Registers.Partition0Core0Address.DefineMany(this, (uint)cores.Length, stepInBytes: (uint)coreSize, setup: (reg, index) => reg
130                 .WithReservedBits(0, 2)
131                 .WithTag($"ADDR (Core{index} Boot Address)", 2, 30)
132             );
133         }
134 
DefineStatusEnableRegisters(Registers statusOffset, uint[] statuses)135         private void DefineStatusEnableRegisters(Registers statusOffset, uint[] statuses)
136         {
137             // COFB enable and status registers provides just a readback functionality.
138             // The registers don't distinguish between regular fields and reserved bits.
139             statusOffset.DefineMany(this, (uint)statuses.Length, (reg, index) => reg
140                 .WithValueField(0, 32, FieldMode.Read, name: "BLOCKn (IP Blocks Status)",
141                     valueProviderCallback: (_) => statuses[index]
142                 )
143             );
144 
145             var enableOffset = statusOffset - Registers.Partition0COFBSet0ClockStatus + Registers.Partition0COFBSet0ClockEnable;
146             enableOffset.DefineMany(this, (uint)statuses.Length, (reg, index) => reg
147                 .WithValueField(0, 32, name: "REQn (Clocks Enable)",
148                     writeCallback: (_, val) => statuses[index] = (uint)val,
149                     valueProviderCallback: (_) => statuses[index]
150                 )
151             );
152         }
153 
Initialize()154         private void Initialize()
155         {
156             cofbsStatus[0][0] = 0x00000004;
157             cofbsStatus[0][1] = 0x00001000;
158             cofbsStatus[1][0] = 0x5E3F0007;
159             cofbsStatus[1][1] = 0x7CFE2FFC;
160             cofbsStatus[1][2] = 0x300C0000;
161             cofbsStatus[1][3] = 0x00005FEE;
162             cofbsStatus[2][0] = 0x0600000F;
163             cofbsStatus[2][1] = 0xCC000000;
164             cofbsStatus[2][2] = 0x00000003;
165         }
166 
167         private readonly uint[][] cofbsStatus;
168         private readonly ICPU[] cores;
169         private const uint PartitionCount = 3;
170 
171         public enum Registers
172         {
173             ControlKey = 0x0, // CTL_KEY
174             ModeConfiguration = 0x4, // MODE_CONF
175             ModeUpdate = 0x8, // MODE_UPD
176             ModeStatus = 0xC, // MODE_STAT
177             MainCoreID = 0x10, // MAIN_COREID
178             Partition0ProcessConfiguration = 0x100, // PRTN0_PCONF
179             Partition0ProcessUpdate = 0x104, // PRTN0_PUPD
180             Partition0Status = 0x108, // PRTN0_STAT
181             Partition0CoreLockstepControl = 0x10C, // PRTN0_CORE_LOCKSTE
182             Partition0COFBSet0ClockStatus = 0x110, // PRTN0_COFB0_STAT
183             Partition0COFBSet1ClockStatus = 0x114, // PRTN0_COFB1_STAT
184             Partition0COFBSet0ClockEnable = 0x130, // PRTN0_COFB0_CLKE
185             Partition0COFBSet1ClockEnable = 0x134, // PRTN0_COFB1_CLKE
186             Partition0Core0ProcessConfiguration = 0x140, // PRTN0_CORE0_PCON
187             Partition0Core0ProcessUpdate = 0x144, // PRTN0_CORE0_PUPD
188             Partition0Core0Status = 0x148, // PRTN0_CORE0_STAT
189             Partition0Core0Address = 0x14C, // PRTN0_CORE0_ADDR
190             Partition0Core1ProcessConfiguration = 0x160, // PRTN0_CORE1_PCON
191             Partition0Core1ProcessUpdate = 0x164, // PRTN0_CORE1_PUPD
192             Partition0Core1Status = 0x168, // PRTN0_CORE1_STAT
193             Partition0Core1Address = 0x16C, // PRTN0_CORE1_ADDR
194             Partition0Core2Status = 0x188, // PRTN0_CORE2_STAT
195             Partition0Core2Address = 0x18C, // PRTN0_CORE2_ADDR
196             Partition0Core3ProcessConfiguration = 0x1A0, // PRTN0_CORE3_PCON
197             Partition0Core3ProcessUpdate = 0x1A4, // PRTN0_CORE3_PUPD
198             Partition0Core3Status = 0x1A8, // PRTN0_CORE3_STAT
199             Partition0Core3Address = 0x1AC, // PRTN0_CORE3_ADDR
200             Partition0Core4ProcessConfiguration = 0x1C0, // PRTN0_CORE4_PCON
201             Partition0Core4ProcessUpdate = 0x1C4, // PRTN0_CORE4_PUPD
202             Partition0Core4Status = 0x1C8, // PRTN0_CORE4_STAT
203             Partition0Core4Address = 0x1CC, // PRTN0_CORE4_ADDR
204             Partition0Core5ProcessConfiguration = 0x1E0, // PRTN0_CORE5_PCON
205             Partition0Core5ProcessUpdate = 0x1E4, // PRTN0_CORE5_PUPD
206             Partition0Core5Status = 0x1E8, // PRTN0_CORE5_STAT
207             Partition0Core5Address = 0x1EC, // PRTN0_CORE5_ADDR
208             Partition1ProcessConfiguration = 0x300, // PRTN1_PCONF
209             Partition1ProcessUpdate = 0x304, // PRTN1_PUPD
210             Partition1Status = 0x308, // PRTN1_STAT
211             Partition1COFBSet0ClockStatus = 0x310, // PRTN1_COFB0_STAT
212             Partition1COFBSet1ClockStatus = 0x314, // PRTN1_COFB1_STAT
213             Partition1COFBSet2ClockStatus = 0x318, // PRTN1_COFB2_STAT
214             Partition1COFBSet3ClockStatus = 0x31C, // PRTN1_COFB3_STAT
215             Partition1COFBSet0ClockEnable = 0x330, // PRTN1_COFB0_CLKE
216             Partition1COFBSet1ClockEnable = 0x334, // PRTN1_COFB1_CLKE
217             Partition1COFBSet2ClockEnable = 0x338, // PRTN1_COFB2_CLKE
218             Partition1COFBSet3ClockEnable = 0x33C, // PRTN1_COFB3_CLKE
219             Partition2ProcessConfiguration = 0x500, // PRTN2_PCONF
220             Partition2ProcessUpdate = 0x504, // PRTN2_PUPD
221             Partition2Status = 0x508, // PRTN2_STAT
222             Partition2COFBSet0ClockStatus = 0x510, // PRTN2_COFB0_STAT
223             Partition2COFBSet1ClockStatus = 0x514, // PRTN2_COFB1_STAT
224             Partition2COFBSet2ClockStatus = 0x518, // PRTN2_COFB2_STAT
225             Partition2COFBSet0ClockEnable = 0x530, // PRTN2_COFB0_CLKE
226             Partition2COFBSet1ClockEnable = 0x534, // PRTN2_COFB1_CLKE
227             Partition2COFBSet2ClockEnable = 0x538 // PRTN2_COFB2_CLKE
228         }
229     }
230 }
231