1 //
2 // Copyright (c) 2010-2025 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.Text;
10 using System.IO;
11 using Antmicro.Renode.Exceptions;
12 using Antmicro.Renode.Logging;
13 using Antmicro.Renode.Utilities;
14 using Antmicro.Renode.Utilities.Binding;
15 
16 namespace Antmicro.Renode.Peripherals.CPU
17 {
18     public abstract partial class TranslationCPU
19     {
20         public bool EnableOpcodesCounting
21         {
22             set
23             {
24                 TlibEnableOpcodesCounting(value ? 1 : 0u);
25             }
26         }
27 
InstallOpcodeCounterPattern(string name, string pattern)28         public void InstallOpcodeCounterPattern(string name, string pattern)
29         {
30             if(pattern.Length != 16 && pattern.Length != 32)
31             {
32                 throw new RecoverableException("Currently only 16 and 32-bit opcode patterns are supported");
33             }
34 
35             // no need to check the result value, as we have checked
36             // the pattern length already
37             Misc.TryParseBitPattern(pattern, out var opcode, out var mask);
38 
39             InstallOpcodeCounterPattern(name, opcode, mask);
40         }
41 
InstallOpcodeCounterPattern(string name, ulong opcode, ulong mask)42         public void InstallOpcodeCounterPattern(string name, ulong opcode, ulong mask)
43         {
44             if(opcodesMap.ContainsKey(name))
45             {
46                 throw new RecoverableException($"Opcode '{name}' already registered");
47             }
48 
49             var id = TlibInstallOpcodeCounter(opcode, mask);
50             if(id == 0)
51             {
52                 throw new RecoverableException("Could not install opcode counter pattern");
53             }
54 
55             opcodesMap[name] = id;
56             this.Log(LogLevel.Debug, "Registered counter for opcode: {0}", name);
57         }
58 
GetOpcodeCounter(string name)59         public ulong GetOpcodeCounter(string name)
60         {
61             if(!opcodesMap.TryGetValue(name, out var id))
62             {
63                 throw new RecoverableException($"Couldn't find the {name} opcode");
64             }
65             return TlibGetOpcodeCounter(id);
66         }
67 
GetAllOpcodesCounters()68         public string[,] GetAllOpcodesCounters()
69         {
70             return new Table()
71                 .AddRow("Opcode", "Count")
72                 .AddRows(opcodesMap,
73                            x => x.Key,
74                            x => TlibGetOpcodeCounter(x.Value).ToString()).ToArray();
75         }
76 
SaveAllOpcodesCounters(string path)77         public void SaveAllOpcodesCounters(string path)
78         {
79             using(var outputFile = new StreamWriter(path))
80             {
81                 foreach(var x in opcodesMap)
82                 {
83                     outputFile.WriteLine(string.Format("{0};{1}", x.Key, TlibGetOpcodeCounter(x.Value)));
84                 }
85             }
86         }
87 
ResetOpcodesCounters()88         public void ResetOpcodesCounters()
89         {
90             TlibResetOpcodeCounters();
91         }
92 
93         private readonly Dictionary<string, uint> opcodesMap = new Dictionary<string, uint>();
94 
95         #pragma warning disable 649
96 
97         [Import]
98         private Action<uint> TlibEnableOpcodesCounting;
99 
100         [Import]
101         private Func<uint, ulong> TlibGetOpcodeCounter;
102 
103         [Import]
104         private Func<ulong, ulong, uint> TlibInstallOpcodeCounter;
105 
106         [Import]
107         private Action TlibResetOpcodeCounters;
108 
109         #pragma warning restore 649
110     }
111 }
112 
113