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