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.IO;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Peripherals;
11 using Antmicro.Renode.Peripherals.CPU;
12 using Microsoft.Scripting.Hosting;
13 using Antmicro.Migrant.Hooks;
14 using Antmicro.Migrant;
15 using Antmicro.Renode.Logging;
16 using Antmicro.Renode.Exceptions;
17 using Antmicro.Renode.Utilities;
18 
19 namespace Antmicro.Renode.Hooks
20 {
21     public sealed class RiscVInstructionPythonEngine : PythonEngine
22     {
RiscVInstructionPythonEngine(BaseRiscV cpu, string pattern, string script = null, OptionalReadFilePath path = null)23         public RiscVInstructionPythonEngine(BaseRiscV cpu, string pattern, string script = null, OptionalReadFilePath path = null)
24         {
25             if((script == null && path == null) || (script != null && path != null))
26             {
27                 throw new ConstructionException("Parameters 'script' and 'path' cannot be both set or both unset");
28             }
29 
30             this.cpu = cpu;
31             this.pattern = pattern;
32 
33             this.script = script;
34             this.path = path;
35 
36             InnerInit();
37 
38             Hook = (instr) =>
39             {
40                 Scope.SetVariable("instruction", instr);
41                 Execute(code, error =>
42                 {
43                     this.cpu.Log(LogLevel.Error, "Python runtime error: {0}", error);
44                     throw new CpuAbortException($"Python runtime error: {error}");
45                 });
46             };
47         }
48 
49         [PostDeserialization]
InnerInit()50         private void InnerInit()
51         {
52             Scope.SetVariable("cpu", cpu);
53             Scope.SetVariable("machine", cpu.GetMachine());
54             Scope.SetVariable("state", cpu.UserState);
55 
56             ScriptSource source;
57             if(script != null)
58             {
59                 source = Engine.CreateScriptSourceFromString(script);
60             }
61             else
62             {
63                 if(!File.Exists(path))
64                 {
65                     throw new RecoverableException($"Couldn't find the script file: {path}");
66                 }
67                 source = Engine.CreateScriptSourceFromFile(path);
68             }
69 
70             code = Compile(source);
71         }
72 
73         public Action<ulong> Hook { get; }
74 
75         [Transient]
76         private CompiledCode code;
77 
78         private readonly string script;
79         private readonly string path;
80 
81         private readonly BaseRiscV cpu;
82         private readonly string pattern;
83     }
84 }
85 
86