1 // 2 // Copyright (c) 2010-2022 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.Globalization; 10 using System.IO; 11 using System.Linq; 12 using System.Text.RegularExpressions; 13 using Antmicro.Renode.Exceptions; 14 15 namespace Antmicro.Renode.Utilities 16 { 17 public class VmemReader 18 { 19 // Implementation based on section 17.2.9 of 20 // http://staff.ustc.edu.cn/~songch/download/IEEE.1364-2005.pdf VmemReader(ReadFilePath file)21 public VmemReader(ReadFilePath file) 22 { 23 this.file = file; 24 } 25 GetIndexDataPairs()26 public IEnumerable<Tuple<long, ulong>> GetIndexDataPairs() 27 { 28 return GetMappedEnumerable(data => 29 { 30 if(UInt64.TryParse(data, NumberStyles.HexNumber, null, out var l)) 31 { 32 return l; 33 } 34 else 35 { 36 throw new RecoverableException($"Invalid hexstring \"{data}\" at line {lineNumber}"); 37 } 38 }); 39 } 40 GetRawEnumerable()41 private IEnumerable<Tuple<long, string>> GetRawEnumerable() 42 { 43 if(started) 44 { 45 yield break; 46 } 47 else 48 { 49 started = true; 50 } 51 var matchEvaluator = new MatchEvaluator(MatchEvaluatorFunction); 52 53 foreach(var line in File.ReadLines(file)) 54 { 55 lineNumber += 1; 56 string dataLine; 57 if(inMultilineComment) 58 { 59 var endOfComment = line.IndexOf("*/"); 60 if(line.Length > 0 && endOfComment != -1) 61 { 62 inMultilineComment = false; 63 dataLine = line.Substring(endOfComment + 2); 64 } 65 else 66 { 67 continue; 68 } 69 } 70 else 71 { 72 dataLine = regexComments.Replace(line, matchEvaluator); 73 } 74 75 foreach(var e in ParseCommentless(dataLine)) 76 { 77 yield return e; 78 } 79 } 80 } 81 GetMappedEnumerable(Func<string, T> mapping)82 private IEnumerable<Tuple<long, T>> GetMappedEnumerable<T>(Func<string, T> mapping) 83 { 84 return GetRawEnumerable().Select(e => new Tuple<long, T>(e.Item1, mapping(e.Item2))); 85 } 86 MatchEvaluatorFunction(Match match)87 private string MatchEvaluatorFunction(Match match) 88 { 89 if(match.Length >= 2 && match.Value[1] == '*' && (match.Length == 2 || match.Value[match.Length - 2] != '*')) 90 { 91 inMultilineComment = true; 92 } 93 return " "; 94 } 95 ParseCommentless(string sub)96 private IEnumerable<Tuple<long, string>> ParseCommentless(string sub) 97 { 98 var words = sub.Split(whitespaces, StringSplitOptions.RemoveEmptyEntries); 99 foreach(var data in CheckForIndex(words)) 100 { 101 yield return new Tuple<long, string>(index, data); 102 index += 1; 103 } 104 } 105 CheckForIndex(IEnumerable<string> words)106 private IEnumerable<string> CheckForIndex(IEnumerable<string> words) 107 { 108 foreach(var word in words) 109 { 110 if(word.StartsWith("@")) 111 { 112 if(Int64.TryParse(word.Substring(1), NumberStyles.HexNumber, null, out var idx)) 113 { 114 index = idx; 115 } 116 else 117 { 118 throw new RecoverableException($"Invalid index \"{word}\" at line {lineNumber}"); 119 } 120 } 121 else 122 { 123 yield return word; 124 } 125 } 126 } 127 128 private static readonly char[] whitespaces = new char[] { ' ', '\n', '\t', '\f' }; 129 private static readonly Regex regexComments = new Regex(@"/\*(.*?\*/|.*)|//.*"); 130 131 private bool started; 132 private bool inMultilineComment; 133 private long index; 134 private long lineNumber; 135 136 private readonly string file; 137 } 138 } 139