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 RiscVCsrPythonEngine : PythonEngine
22     {
RiscVCsrPythonEngine(BaseRiscV cpu, ulong csr, bool initable, string script = null, OptionalReadFilePath path = null)23         public RiscVCsrPythonEngine(BaseRiscV cpu, ulong csr, bool initable, 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.csr = csr;
32 
33             this.script = script;
34             this.path = path;
35 
36             this.initable = initable;
37 
38             InnerInit();
39 
40             CsrWriteHook = (value) =>
41             {
42                 TryInit();
43 
44                 request.value = value;
45                 request.type = CsrRequest.RequestType.WRITE;
46 
47                 Execute(code, error =>
48                 {
49                     this.cpu.Log(LogLevel.Error, "Python runtime error: {0}", error);
50                     throw new CpuAbortException($"Python runtime error: {error}");
51                 });
52             };
53 
54             CsrReadHook = () =>
55             {
56                 TryInit();
57 
58                 request.type = CsrRequest.RequestType.READ;
59                 Execute(code, error =>
60                 {
61                     this.cpu.Log(LogLevel.Error, "Python runtime error: {0}", error);
62                     throw new CpuAbortException($"Python runtime error: {error}");
63                 });
64 
65                 return request.value;
66             };
67         }
68 
69         [PostDeserialization]
InnerInit()70         private void InnerInit()
71         {
72             request = new CsrRequest();
73             request.csr = this.csr;
74 
75             Scope.SetVariable("cpu", cpu);
76             Scope.SetVariable("machine", cpu.GetMachine());
77             Scope.SetVariable("request", request);
78 
79             ScriptSource source;
80 
81             if(script != null)
82             {
83                 source = Engine.CreateScriptSourceFromString(script);
84             }
85             else
86             {
87                 if(!File.Exists(path))
88                 {
89                     throw new RecoverableException($"Couldn't find the script file: {path}");
90                 }
91                 source = Engine.CreateScriptSourceFromFile(path);
92             }
93 
94             code = Compile(source);
95         }
96 
TryInit()97         private void TryInit()
98         {
99             if(!initable || isInitialized)
100             {
101                 return;
102             }
103 
104             request.type = CsrRequest.RequestType.INIT;
105             Execute(code);
106             isInitialized = true;
107         }
108 
109         public Action<ulong> CsrWriteHook { get; }
110 
111         public Func<ulong> CsrReadHook { get; }
112 
113         [Transient]
114         private CompiledCode code;
115 
116         private bool isInitialized;
117 
118         private CsrRequest request;
119 
120         private readonly string script;
121         private readonly string path;
122 
123         private readonly ICPU cpu;
124         private readonly ulong csr;
125         private readonly bool initable;
126 
127         // naming convention here is pythonic
128         public class CsrRequest
129         {
130             public ulong csr { get; set; }
131             public ulong value { get; set; }
132             public RequestType type { get; set; }
133 
134             public bool isInit
135             {
136                 get
137                 {
138                     return type == RequestType.INIT;
139                 }
140             }
141 
142             public bool isRead
143             {
144                 get
145                 {
146                     return type == RequestType.READ;
147                 }
148             }
149 
150             public bool isWrite
151             {
152                 get
153                 {
154                     return type == RequestType.WRITE;
155                 }
156             }
157 
158             public enum RequestType
159             {
160                 READ,
161                 WRITE,
162                 INIT
163             }
164         }
165     }
166 }
167 
168