1<#
2//
3// Copyright (c) 2010-2025 Antmicro
4// Copyright (c) 2011-2015 Realtime Embedded
5//
6// This file is licensed under the MIT License.
7// Full license text is available in 'licenses/MIT.txt'.
8//
9#>
10<#@ template language="C#" hostspecific="true" #>
11<#@ parameter type="System.String" name="BASE_PATH" #>
12<#@ assembly name="System.Core" #>
13<#@ import namespace="System.IO" #>
14<#@ import namespace="System.Linq" #>
15<#@ import namespace="System.Text" #>
16<#@ import namespace="System.Collections.Generic" #>
17<#@ include file="RegisterEnumParserContent.tt" #>
18<#
19    if(CLASS_NAME == null)
20    {
21        throw new ArgumentException("CLASS_NAME variable not set");
22    }
23    if(HEADER_FILE == null)
24    {
25        throw new ArgumentException("HEADER_FILE variable not set");
26    }
27    if(ACCESSOR_PREFIX == null)
28    {
29        // Assume tlibs by default
30        ACCESSOR_PREFIX = "tlib_";
31    }
32
33    RegistersEnumParser parser;
34    var baseDirectoryPath = Directory.GetParent(BASE_PATH).Parent.Parent.Parent.FullName;
35    var fullPath = Path.Combine(baseDirectoryPath, HEADER_FILE);
36    using(var stream = File.OpenRead(fullPath))
37    {
38        parser = new RegistersEnumParser(stream, DEFINES);
39    }
40
41    if(PC_REGISTER != null)
42    {
43        parser.Map("PC", PC_REGISTER);
44    }
45
46    foreach(var ignored in REGISTERS_FROM_BASE_CLASS)
47    {
48        parser.Ignore(ignored);
49    }
50
51    var virtualRegisters = new HashSet<string> { "PC" };
52
53    var OVERRIDE = "";
54
55    if(OVERRIDE_DEFINITIONS)
56    {
57        OVERRIDE = "override ";
58    }
59#>
60/********************************************************
61*
62* Warning!
63* This file was generated automatically.
64* Please do not edit. Changes should be made in the
65* appropriate *.tt file.
66*
67*/
68using System;
69using System.Linq;
70using System.Collections.Generic;
71using Antmicro.Renode.Peripherals.CPU.Registers;
72using Antmicro.Renode.Utilities.Binding;
73using Antmicro.Renode.Exceptions;
74
75namespace Antmicro.Renode.Peripherals.CPU
76{
77    public partial class <#=CLASS_NAME#>
78    {
79<#
80    var widths = parser.Registers
81        .Union(parser.RegisterGroups.SelectMany(x => x.GetRegisters()))
82        .Select(x => x.Width)
83        .OrderBy(x => x)
84        .Distinct()
85        .ToArray();
86#>
87        public <#=OVERRIDE#>void SetRegister(int register, RegisterValue value)
88        {
89            if(!mapping.TryGetValue((<#=CLASS_NAME#>Registers)register, out var r))
90            {
91<#
92    if(FALLBACK_SET_REGISTER != null)
93    {
94#>
95                if(<#=FALLBACK_SET_REGISTER#>(register, value))
96                {
97                    return;
98                }
99<#
100    }
101#>
102                throw new RecoverableException($"Wrong register index: {register}");
103            }
104<#
105    if(UNSETTABLE_REGISTERS.Any())
106    {
107#>
108            if(r.IsReadonly)
109            {
110                throw new RecoverableException($"The '{(<#=CLASS_NAME#>Registers)register}' register is read-only.");
111            }
112<#
113    }
114#>
115
116<#
117    if(widths.Length == 1)
118    {
119#>
120            SetRegisterValue<#=widths[0]#>(r.Index, checked((<#=RegisterTypeHelper.GetTypeName(widths[0])#>)value));
121<#
122    }
123    else
124    {
125#>
126            switch(r.Width)
127            {
128<#
129        foreach(var width in widths)
130        {
131#>
132            case <#=width#>:
133                SetRegisterValue<#=width#>(r.Index, checked((<#=RegisterTypeHelper.GetTypeName(width)#>)value));
134                break;
135<#
136        }
137#>
138            default:
139                throw new ArgumentException($"Unsupported register width: {r.Width}");
140            }
141<#
142    }
143#>
144        }
145
146        public <#=OVERRIDE#>RegisterValue GetRegister(int register)
147        {
148            if(!mapping.TryGetValue((<#=CLASS_NAME#>Registers)register, out var r))
149            {
150<#
151    if(FALLBACK_GET_REGISTER != null)
152    {
153#>
154                if(<#=FALLBACK_GET_REGISTER#>(register, out var value))
155                {
156                    return value;
157                }
158<#
159    }
160#>
161                throw new RecoverableException($"Wrong register index: {register}");
162            }
163<#
164    if(widths.Length == 1)
165    {
166#>
167            return GetRegisterValue<#=widths[0]#>(r.Index);
168<#
169    }
170    else
171    {
172#>
173            switch(r.Width)
174            {
175<#
176        foreach(var width in widths)
177        {
178#>
179            case <#=width#>:
180                return GetRegisterValue<#=width#>(r.Index);
181<#
182        }
183#>
184            default:
185                throw new ArgumentException($"Unsupported register width: {r.Width}");
186            }
187<#
188    }
189#>
190        }
191
192        public <#=OVERRIDE#>IEnumerable<CPURegister> GetRegisters()
193        {
194<#
195    if(FALLBACK_REGISTERS != null)
196    {
197#>
198            return mapping.Values.Concat(<#=FALLBACK_REGISTERS#>()).OrderBy(x => x.Index);
199<#
200    }
201    else
202    {
203#>
204            return mapping.Values.OrderBy(x => x.Index);
205<#
206    }
207#>
208        }
209
210<#
211    foreach(var register in parser.Registers.Where(x => !x.IsIgnored))
212    {
213#>
214        [Register]
215        public <#= virtualRegisters.Contains(register.Name) ? "override " : "" #>RegisterValue <#=register.Name#>
216        {
217            get
218            {
219<#
220        if(BEFORE_READ_HOOKS.ContainsKey(register.Name))
221        {
222#>
223                <#=BEFORE_READ_HOOKS[register.Name]#>();
224<#
225        }
226#>
227                return GetRegisterValue<#=register.Width#>((int)<#=CLASS_NAME#>Registers.<#=register.Name#>);
228            }
229            set
230            {
231<#
232        if(BEFORE_WRITE_HOOKS.ContainsKey(register.Name))
233        {
234#>
235                value = <#=BEFORE_WRITE_HOOKS[register.Name]#>(value);
236<#
237        }
238#>
239                SetRegisterValue<#=register.Width#>((int)<#=CLASS_NAME#>Registers.<#=register.Name#>, value);
240<#
241        if(AFTER_WRITE_HOOKS.ContainsKey(register.Name))
242        {
243#>
244                <#=AFTER_WRITE_HOOKS[register.Name]#>(value);
245<#
246        }
247#>
248            }
249        }
250<#
251    }
252
253    foreach(var registerGroup in parser.RegisterGroups.Where(x => !x.IsIgnored))
254    {
255#>
256        public RegistersGroup <#=registerGroup.Name#> { get; private set; }
257<#
258    }
259#>
260
261        protected <#=OVERRIDE#>void InitializeRegisters()
262        {
263<#
264    if(REGISTERS_FROM_BASE_CLASS.Count > 0)
265    {
266#>
267            base.InitializeRegisters();
268<#
269    }
270    foreach(var registerGroup in parser.RegisterGroups.Where(x => !x.IsIgnored))
271    {#>
272            var indexValueMap<#=registerGroup.Name#> = new Dictionary<int, <#=CLASS_NAME#>Registers>
273            {
274<#
275        foreach(var elem in registerGroup.IndexValueMap)
276        {
277#>
278                { <#=elem.Key#>, <#=CLASS_NAME#>Registers.<#=registerGroup.Name#><#=elem.Key#> },
279<#
280        }
281#>
282            };
283            <#=registerGroup.Name#> = new RegistersGroup(
284                indexValueMap<#=registerGroup.Name#>.Keys,
285                i => GetRegister((int)indexValueMap<#=registerGroup.Name#>[i]),
286                (i, v) => SetRegister((int)indexValueMap<#=registerGroup.Name#>[i], v));
287
288<#
289    }
290#>
291        }
292
293<#
294    var ignoredWidths = parser.RegisterGroups.Where(x => x.IsIgnored).Select(x => x.Width).Union(parser.Registers.Where(x => x.IsIgnored).Select(x => x.Width)).Distinct();
295    foreach(var width in parser.RegisterGroups.Select(x => x.Width).Union(parser.Registers.Select(x => x.Width)).Except(ignoredWidths).Distinct())
296    {
297#>
298        // 649:  Field '...' is never assigned to, and will always have its default value null
299        #pragma warning disable 649
300
301        [Import(Name = "<#=ACCESSOR_PREFIX#>set_register_value_<#=width#>")]
302        protected Action<int, <#=RegisterTypeHelper.GetTypeName(width)#>> SetRegisterValue<#=width#>;
303        [Import(Name = "<#=ACCESSOR_PREFIX#>get_register_value_<#=width#>")]
304        protected Func<int, <#=RegisterTypeHelper.GetTypeName(width)#>> GetRegisterValue<#=width#>;
305
306        #pragma warning restore 649
307
308<#
309    }
310#>
311        private static readonly Dictionary<<#=CLASS_NAME#>Registers, CPURegister> mapping = new Dictionary<<#=CLASS_NAME#>Registers, CPURegister>
312        {
313<#
314    foreach(var register in
315        parser.Registers
316        .Union(parser.RegisterGroups.SelectMany(x => x.GetRegisters()))
317        .GroupBy(x => x.Value)
318        .OrderBy(x => x.Key))
319    {
320        var firstName = register.First().Name;
321        var id = register.Key;
322        var width = register.Select(x => x.Width).First();
323        var isGeneral = register.Any(x => GENERAL_REGISTERS.Contains(x.Name)) ? "true" : "false";
324        var isReadonly = register.Any(x => UNSETTABLE_REGISTERS.Contains(x.Name)) ? "true" : "false";
325        var names = String.Join(", ", register.Select(x => $"\"{x.Name}\""));
326        var aliases = $"new [] {{ {names} }}";
327#>
328            { <#=CLASS_NAME#>Registers.<#=firstName#>,  new CPURegister(<#=id#>, <#=width#>, isGeneral: <#=isGeneral#>, isReadonly: <#=isReadonly#>, aliases: <#=aliases#>) },
329<#
330    }
331#>
332        };
333    }
334
335    public enum <#=CLASS_NAME#>Registers
336    {
337<#
338    foreach(var register in parser.Registers)
339    {
340#>
341        <#=register.Name#> = <#=register.Value#>,
342<#
343    }
344
345    foreach(var registerGroup in parser.RegisterGroups)
346    {
347        foreach(var index in registerGroup.IndexValueMap.OrderBy(x => x.Key))
348        {
349#>
350        <#=registerGroup.Name#><#=index.Key#> = <#=index.Value#>,
351<#
352        }
353    }
354#>
355    }
356}
357