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