1 //
2 // Copyright (c) 2010-2024 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 
9 using System.IO;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Exceptions;
12 using Antmicro.Renode.Peripherals.Bus;
13 using Antmicro.Renode.UserInterface;
14 using Antmicro.Renode.Utilities;
15 
16 namespace Antmicro.Renode.Peripherals.Python
17 {
18     public static class PythonPeripheralExtensions
19     {
PyDevFromFile(this Machine @this, ReadFilePath path, ulong address, int size, bool initable = false, string name = null, ulong offset = 0)20         public static void PyDevFromFile(this Machine @this, ReadFilePath path, ulong address, int size, bool initable = false, string name = null, ulong offset = 0)
21         {
22             var pyDev = new PythonPeripheral(size, initable, filename: path);
23             @this.SystemBus.Register(pyDev, new BusPointRegistration(address, offset));
24             if(!string.IsNullOrEmpty(name))
25             {
26                 @this.SetLocalName(pyDev, name);
27             }
28         }
29 
PyDevFromString(this Machine @this, string script, ulong address, int size, bool initable = false, string name = null, ulong offset = 0)30         public static void PyDevFromString(this Machine @this, string script, ulong address, int size, bool initable = false, string name = null, ulong offset = 0)
31         {
32             var pyDev = new PythonPeripheral(size, initable, script: script);
33             @this.SystemBus.Register(pyDev, new BusPointRegistration(address, offset));
34             if(!string.IsNullOrEmpty(name))
35             {
36                 @this.SetLocalName(pyDev, name);
37             }
38         }
39     }
40 
41     [Icon("python")]
42     public class PythonPeripheral : IBytePeripheral, IWordPeripheral, IDoubleWordPeripheral, IQuadWordPeripheral, IKnownSize, IAbsoluteAddressAware
43     {
PythonPeripheral(int size, bool initable = false, string script = null, string filename = null)44         public PythonPeripheral(int size, bool initable = false, string script = null, string filename = null)
45         {
46             this.size = size;
47             this.initable = initable;
48             this.script = script;
49             this.filename = filename;
50 
51             if((this.script == null && this.filename == null) || (this.script != null && this.filename != null))
52             {
53                 throw new ConstructionException("Parameters `script` and `filename` cannot be both set or both unset.");
54             }
55             if(this.script != null)
56             {
57                 this.pythonRunner = new PeripheralPythonEngine(this, x => x.CreateScriptSourceFromString(this.script));
58             }
59             else if(this.filename != null)
60             {
61                 if(!File.Exists(this.filename))
62                 {
63                     throw new ConstructionException(string.Format("Could not find source file for the script: {0}.", this.filename));
64                 }
65                 this.pythonRunner = new PeripheralPythonEngine(this, x => x.CreateScriptSourceFromFile(this.filename));
66             }
67         }
68 
SetAbsoluteAddress(ulong address)69         public void SetAbsoluteAddress(ulong address)
70         {
71             pythonRunner.Request.absolute = address;
72         }
73 
ReadByte(long offset)74         public byte ReadByte(long offset)
75         {
76             pythonRunner.Request.length = 1;
77             HandleRead(offset);
78             return unchecked((byte)pythonRunner.Request.value);
79         }
80 
WriteByte(long offset, byte value)81         public void WriteByte(long offset, byte value)
82         {
83             pythonRunner.Request.length = 1;
84             HandleWrite(offset, value);
85         }
86 
ReadDoubleWord(long offset)87         public uint ReadDoubleWord(long offset)
88         {
89             pythonRunner.Request.length = 4;
90             HandleRead(offset);
91             return unchecked((uint)pythonRunner.Request.value);
92         }
93 
WriteDoubleWord(long offset, uint value)94         public void WriteDoubleWord(long offset, uint value)
95         {
96             pythonRunner.Request.length = 4;
97             HandleWrite(offset, value);
98         }
99 
ReadQuadWord(long offset)100         public ulong ReadQuadWord(long offset)
101         {
102             pythonRunner.Request.length = 8;
103             HandleRead(offset);
104             return unchecked(pythonRunner.Request.value);
105         }
106 
WriteQuadWord(long offset, ulong value)107         public void WriteQuadWord(long offset, ulong value)
108         {
109             pythonRunner.Request.length = 8;
110             HandleWrite(offset, value);
111         }
112 
ReadWord(long offset)113         public ushort ReadWord(long offset)
114         {
115             pythonRunner.Request.length = 2;
116             HandleRead(offset);
117             return unchecked((ushort)pythonRunner.Request.value);
118         }
119 
WriteWord(long offset, ushort value)120         public void WriteWord(long offset, ushort value)
121         {
122             pythonRunner.Request.length = 2;
123             HandleWrite(offset, value);
124         }
125 
ControlWrite(long command, ulong value)126         public void ControlWrite(long command, ulong value)
127         {
128             // ignoring the return value
129             ControlRead(command, value);
130         }
131 
ControlRead(long command, ulong value)132         public ulong ControlRead(long command, ulong value)
133         {
134             EnsureInit();
135 
136             pythonRunner.Request.value = 0;
137             pythonRunner.Request.type = PeripheralPythonEngine.PythonRequest.RequestType.USER;
138             pythonRunner.Request.offset = command;
139             pythonRunner.Request.value = value;
140             pythonRunner.Request.length = 8;
141             Execute();
142             return unchecked(pythonRunner.Request.value);
143         }
144 
Reset()145         public void Reset()
146         {
147             inited = false;
148             EnsureInit();
149         }
150 
151         public long Size
152         {
153             get { return size; }
154         }
155 
EnsureInit()156         public void EnsureInit()
157         {
158             if(!inited)
159             {
160                 Init();
161                 inited = true;
162             }
163         }
164 
165         public string Code
166         {
167             get
168             {
169                 return pythonRunner.Code;
170             }
171         }
172 
Init()173         private void Init()
174         {
175             if(initable)
176             {
177                 pythonRunner.Request.type = PeripheralPythonEngine.PythonRequest.RequestType.INIT;
178                 Execute();
179             }
180         }
181 
HandleRead(long offset)182         private void HandleRead(long offset)
183         {
184             EnsureInit();
185 
186             pythonRunner.Request.value = 0;
187             pythonRunner.Request.type = PeripheralPythonEngine.PythonRequest.RequestType.READ;
188             pythonRunner.Request.offset = offset;
189             pythonRunner.Request.counter = requestCounter++;
190             Execute();
191         }
192 
HandleWrite(long offset, ulong value)193         private void HandleWrite(long offset, ulong value)
194         {
195             EnsureInit();
196 
197             pythonRunner.Request.value = value;
198             pythonRunner.Request.type = PeripheralPythonEngine.PythonRequest.RequestType.WRITE;
199             pythonRunner.Request.offset = offset;
200             pythonRunner.Request.counter = requestCounter++;
201             Execute();
202         }
203 
Execute()204         private void Execute()
205         {
206             pythonRunner.ExecuteCode();
207         }
208 
209         private bool inited;
210         private ulong requestCounter;
211 
212         private readonly PeripheralPythonEngine pythonRunner;
213         private readonly bool initable;
214         private readonly int size;
215         private readonly string script;
216         private readonly string filename;
217     }
218 }
219