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