1 /* This file is automatically generated. Do not modify it manually! All changes should be made in `RegisterEnumParserContent.tt` file. */
2 using System;
3 using System.IO;
4 using System.Linq;
5 using System.Text;
6 using System.Collections.Generic;
7 using System.Text.RegularExpressions;
8 
9 namespace Antmicro.Renode.CoresSourceParser
10 {
11     public class RegistersEnumParser
12     {
RegistersEnumParser(Stream stream)13         public RegistersEnumParser(Stream stream) : this(stream, new string[0])
14         {
15         }
16 
RegistersEnumParser(Stream stream, IEnumerable<string> defines)17         public RegistersEnumParser(Stream stream, IEnumerable<string> defines)
18         {
19             registers = new List<RegisterDescriptor>();
20             registerGroups = new List<RegisterGroupDescriptor>();
21             groupedRegisters = new Dictionary<string, List<Tuple<RegisterDescriptor, int>>>();
22             handlers = new Dictionary<Mode, Action<string>>
23             {
24                 { Mode.ScanForEnum,          ScanForEnumHandler          },
25                 { Mode.InsideEnum,           InsideEnumHandler           },
26                 { Mode.SkipLines,            SkipLinesHandler            },
27                 { Mode.IncludeLines,         IncludeLinesHandler         }
28             };
29             modes = new Stack<Mode>();
30 
31             this.defines = defines;
32             Parse(stream);
33         }
34 
Map(string from, string to)35         public void Map(string from, string to)
36         {
37             var regTo = registers.SingleOrDefault(x => x.Name == to);
38             if(regTo.Name == null)
39             {
40                 throw new ArgumentException(string.Format("No register named {0} found.", to));
41             }
42 
43             var regFrom = new RegisterDescriptor
44             {
45                 Name = from,
46                 Width = regTo.Width,
47                 Value = regTo.Value
48             };
49 
50             registers.Add(regFrom);
51         }
52 
Ignore(string name)53         public void Ignore(string name)
54         {
55             var reg = registers.Cast<RegisterDescriptorBase>().Union(registerGroups.Cast<RegisterDescriptorBase>()).SingleOrDefault(x => x.Name == name);
56             if(reg != null)
57             {
58                 reg.IsIgnored = true;
59             }
60         }
61 
62         public RegisterDescriptor[] Registers { get { return registers.ToArray(); } }
63         public RegisterGroupDescriptor[] RegisterGroups { get { return registerGroups.ToArray(); } }
64 
Parse(Stream stream)65         private void Parse(Stream stream)
66         {
67             modes.Push(Mode.ScanForEnum);
68 
69             using(var reader = new StreamReader(stream))
70             {
71                 string line;
72                 while((line = reader.ReadLine()) != null)
73                 {
74                     handlers[modes.Peek()](line);
75                 }
76             }
77 
78             foreach(var group in groupedRegisters)
79             {
80                 var widths = group.Value.Select(x => x.Item1.Width).Distinct().ToList();
81                 if(widths.Count != 1)
82                 {
83                     // we found at least two registers having index with the same name, but different width
84                     throw new ArgumentException(string.Format("Inconsistent register width detected for group: {0}", group.Key));
85                 }
86 
87                 var groupDescriptor = new RegisterGroupDescriptor
88                 {
89                     Name = group.Key,
90                     Width = widths.First(),
91                     IndexValueMap = new Dictionary<int, int>()
92                 };
93 
94                 foreach(var x in group.Value.Select(x => Tuple.Create(x.Item2, x.Item1.Value)))
95                 {
96                     groupDescriptor.IndexValueMap.Add(x.Item1, x.Item2);
97                 }
98 
99                 registerGroups.Add(groupDescriptor);
100             }
101         }
102 
ScanForEnumHandler(string line)103         private void ScanForEnumHandler(string line)
104         {
105             if(line == BeginningOfEnum)
106             {
107                 modes.Push(Mode.InsideEnum);
108             }
109         }
110 
InsideEnumHandler(string line)111         private void InsideEnumHandler(string line)
112         {
113             // Trim lines with single line comment only
114             line = Regex.Replace(line, @"^(\s*//.*)$", "").Trim();
115             if(line.Length == 0)
116             {
117                 return;
118             }
119 
120             Mode? newMode = null;
121             if(line.StartsWith(BeginningOfIfdef, StringComparison.CurrentCulture))
122             {
123                 var value = line.Replace(BeginningOfIfdef, string.Empty).Trim();
124                 newMode = defines.Contains(value) ? Mode.IncludeLines : Mode.SkipLines;
125             }
126             else if(line.StartsWith(BeginningOfIfndef, StringComparison.CurrentCulture))
127             {
128                 var value = line.Replace(BeginningOfIfndef, string.Empty).Trim();
129                 // Notice the modes are inverted compared to 'ifdef'.
130                 newMode = defines.Contains(value) ? Mode.SkipLines : Mode.IncludeLines;
131             }
132 
133             if(newMode.HasValue)
134             {
135                 modes.Push(newMode.Value);
136                 return;
137             }
138 
139             if(line == EndOfEnum)
140             {
141                 modes.Pop();
142                 return;
143             }
144 
145             // e.g., R_0_32 = 147,
146             // X_32 = 155,
147             var match = Regex.Match(line, @"^(?<name>[\p{L}0-9]+)(_(?<index>[0-9]+))?_(?<width>[0-9]+)\s*=\s*(?<value>((0x)?[0-9a-fA-F]+)|([0-9]+))\s*,?$");
148             if(string.IsNullOrEmpty(match.Groups["name"].Value))
149             {
150                 throw new ArgumentException($"Register name was in a wrong format: {line}");
151             }
152 
153             var regValue = match.Groups["value"].Value;
154             var regDesc = new RegisterDescriptor
155             {
156                 Name = match.Groups["name"].Value,
157                 Width = int.Parse(match.Groups["width"].Value),
158                 Value = Convert.ToInt32(regValue, regValue.StartsWith("0x") ? 16 : 10)
159             };
160 
161             if(!string.IsNullOrEmpty(match.Groups["index"].Value))
162             {
163                 if(!groupedRegisters.ContainsKey(regDesc.Name))
164                 {
165                     groupedRegisters[regDesc.Name] = new List<Tuple<RegisterDescriptor, int>>();
166                 }
167 
168                 var index = int.Parse(match.Groups["index"].Value);
169                 groupedRegisters[regDesc.Name].Add(Tuple.Create(regDesc, index));
170             }
171             else
172             {
173                 registers.Add(regDesc);
174             }
175         }
176 
IncludeLinesHandler(string line)177         private void IncludeLinesHandler(string line)
178         {
179             if(line.Trim() == EndOfIfdef)
180             {
181                 modes.Pop();
182             }
183             else if(line.Trim() == ElseIfdef)
184             {
185                 modes.Pop();
186                 modes.Push(Mode.SkipLines);
187             }
188             else
189             {
190                 InsideEnumHandler(line);
191             }
192         }
193 
SkipLinesHandler(string line)194         private void SkipLinesHandler(string line)
195         {
196             if(line.Trim() == EndOfIfdef)
197             {
198                 modes.Pop();
199             }
200             else if(line.Trim() == ElseIfdef)
201             {
202                 modes.Pop();
203                 modes.Push(Mode.IncludeLines);
204             }
205             else if(line.Trim().StartsWith("#if"))
206             {
207                 // The mode should still be 'SkipLines' after ifdef + endif pairs.
208                 modes.Push(Mode.SkipLines);
209             }
210         }
211 
212         private readonly List<RegisterDescriptor> registers;
213         private readonly List<RegisterGroupDescriptor> registerGroups;
214 
215         private readonly IEnumerable<string> defines;
216 
217         private readonly Dictionary<Mode, Action<string>> handlers;
218         private readonly Stack<Mode> modes;
219         private readonly Dictionary<string, List<Tuple<RegisterDescriptor, int>>> groupedRegisters;
220 
221         private const string BeginningOfIfdef = "#ifdef";
222         private const string BeginningOfIfndef = "#ifndef";
223         private const string ElseIfdef = "#else";
224         private const string EndOfIfdef = "#endif";
225         private const string BeginningOfEnum = "typedef enum {";
226         private const string EndOfEnum = "} Registers;";
227 
228         private enum Mode
229         {
230             ScanForEnum,
231             InsideEnum,
232             SkipLines,
233             IncludeLines
234         }
235 
236         public class RegisterDescriptor : RegisterDescriptorBase
237         {
238             public int Value { get; set; }
239         }
240 
241         public class RegisterGroupDescriptor : RegisterDescriptorBase
242         {
243             public Dictionary<int, int> IndexValueMap { get; set; }
244 
GetRegisters()245             public IEnumerable<RegisterDescriptor> GetRegisters()
246             {
247                 return IndexValueMap.Select(x => new RegisterDescriptor
248                 {
249                     Name = $"{this.Name}{x.Key}",
250                     Width = this.Width,
251                     IsIgnored = this.IsIgnored,
252                     Value = x.Value
253                 });
254             }
255         }
256 
257         public class RegisterDescriptorBase
258         {
259             public string Name { get; set; }
260             public int Width { get; set; }
261             public bool IsIgnored { get; set; }
262         }
263     }
264 
265     public static class RegisterTypeHelper
266     {
GetTypeName(int width)267         public static string GetTypeName(int width)
268         {
269             switch(width)
270             {
271             case 64:
272                 return "ulong";
273             case 32:
274                 return "uint";
275             case 16:
276                 return "ushort";
277             case 8:
278                 return "byte";
279             default:
280                 throw new ArgumentException("Width not supported");
281             }
282         }
283     }
284 }
285 
286