1<#
2//
3// Copyright (c) 2010-2024 Antmicro
4// Copyright (c) 2011-2015 Realtime Embedded
5//
6// This file is licensed under the MIT License.
7// Full license text is available in 'licenses/MIT.txt'.
8//
9#>
10<#@ template language="C#" #>
11<#@ import namespace="System.Collections.Generic" #>
12/********************************************************
13*
14* Warning!
15* This file was generated automatically.
16* Please do not edit. Changes should be made in the
17* appropriate *.tt file.
18*
19*/
20using System;
21using System.Text;
22using Antmicro.Renode.Logging;
23using Antmicro.Renode.Peripherals;
24using Antmicro.Renode.Peripherals.Bus;
25using Antmicro.Renode.Utilities;
26
27namespace Antmicro.Renode.Core.Extensions
28{
29    public static class ReadWriteExtensions
30    {
31<#
32    var widthNames = new Dictionary<int, string>()
33    {
34        {8, "Byte"},
35        {16, "Word"},
36        {32, "DoubleWord"},
37        {64, "QuadWord"}
38    };
39
40    var widthTypes = new Dictionary<int, string>()
41    {
42        {8, "byte"},
43        {16, "ushort"},
44        {32, "uint"},
45        {64, "ulong"}
46    };
47
48    var swapBytes = new Dictionary<int, string>()
49    {
50        {8, ""},
51        {16, "Misc.SwapBytesUShort"},
52        {32, "Misc.SwapBytesUInt"},
53        {64, "Misc.SwapBytesULong"}
54    };
55
56    var masks = new Dictionary<int, string>()
57    {
58        {8, "0xFF"},
59        {16, "0xFFFF"},
60        {32, "0xFFFFFFFFUL"}
61    };
62
63    foreach(var inWidth in new int[] {8, 16, 32, 64})
64    {
65        foreach(var outWidth in new int[] {8, 16, 32, 64})
66        {
67            if(inWidth == outWidth)
68            {
69                continue;
70            }
71
72            var inType = widthTypes[inWidth];
73            var outType = widthTypes[outWidth];
74            var outName = widthNames[outWidth];
75            var inName = widthNames[inWidth];
76            var swapFuncIn = swapBytes[inWidth];
77            var swapFuncOut = swapBytes[outWidth];
78
79            if(inWidth < outWidth)
80            {
81#>
82        public static <#= outType #> Read<#= outName #>Using<#= inName #>(this I<#= inName #>Peripheral peripheral, long address)
83        {
84            unchecked
85            {
86                return (<#= outType #>)((<#= outType #>)peripheral.Read<#= inName #>(address)
87<#
88                for(var i = inWidth; i < outWidth; i += inWidth)
89                {
90#>
91                    | (<#= outType #>)peripheral.Read<#= inName #>(address + <#= i / 8 #>) << <#= i #>
92<#
93                }
94#>
95                );
96            }
97        }
98
99        public static BusAccess.<#= outName #>ReadMethod Build<#= outName #>ReadUsing(BusAccess.<#= inName #>ReadMethod read)
100        {
101            return address =>
102            {
103                unchecked
104                {
105                    return (<#= outType #>)((<#= outType #>)read(address)
106<#
107                for(var i = inWidth; i < outWidth; i += inWidth)
108                {
109#>
110                        | (<#= outType #>)read(address + <#= i / 8 #>) << <#= i #>
111<#
112                }
113#>
114                    );
115                }
116            };
117        }
118
119        public static void Write<#= outName #>Using<#= inName #>(this I<#= inName #>Peripheral peripheral, long address, <#= outType #> value)
120        {
121            unchecked
122            {
123<#
124                for(var i = 0; i < outWidth; i += inWidth)
125                {
126#>
127                peripheral.Write<#= inName #>(address + <#= i / 8 #>, (<#= inType #>)(value >> <#= i #>));
128<#
129                }
130#>
131            }
132        }
133
134        public static BusAccess.<#= outName #>WriteMethod Build<#= outName #>WriteUsing(BusAccess.<#= inName #>ReadMethod read, BusAccess.<#= inName #>WriteMethod write)
135        {
136            return (address, value) =>
137            {
138                unchecked
139                {
140<#
141                    for(var i = 0; i < outWidth; i += inWidth)
142                    {
143#>
144                    write(address + <#= i / 8 #>, (<#= inType #>)(value >> <#= i #>));
145<#
146                    }
147#>
148                }
149            };
150        }
151
152        public static <#= outType #> Read<#= outName #>Using<#= inName #>BigEndian(this I<#= inName #>Peripheral peripheral, long address)
153        {
154            unchecked
155            {
156                return (<#= outType #>)((<#= outType #>)<#= swapFuncIn #>(peripheral.Read<#= inName #>(address + <#= (outWidth - inWidth) / 8 #>))
157<#
158                for(var i = outWidth - 2 * inWidth; i >= 0; i -= inWidth)
159                {
160#>
161                    | (<#= outType #>)<#= swapFuncIn #>(peripheral.Read<#= inName #>(address + <#= i / 8 #>)) << <#= outWidth - inWidth - i #>
162<#
163                }
164#>
165                );
166            }
167        }
168
169        public static BusAccess.<#= outName #>ReadMethod Build<#= outName #>ReadBigEndianUsing(BusAccess.<#= inName #>ReadMethod read)
170        {
171            return address =>
172            {
173                unchecked
174                {
175                    return (<#= outType #>)((<#= outType #>)<#= swapFuncIn #>(read(address + <#= (outWidth - inWidth) / 8 #>))
176<#
177                    for(var i = outWidth - 2 * inWidth; i >= 0; i -= inWidth)
178                    {
179#>
180                        | (<#= outType #>)<#= swapFuncIn #>(read(address + <#= i / 8 #>)) << <#= outWidth - inWidth - i #>
181<#
182                    }
183#>
184                    );
185                }
186            };
187        }
188
189        public static void Write<#= outName #>Using<#= inName #>BigEndian(this I<#= inName #>Peripheral peripheral, long address, <#= outType #> value)
190        {
191            unchecked
192            {
193<#
194                for(var i = outWidth - inWidth; i >= 0; i -= inWidth)
195                {
196#>
197                peripheral.Write<#= inName #>(address + <#= (outWidth - inWidth - i) / 8 #>, <#= swapFuncIn #>((<#= inType #>)(value >> <#= i #>)));
198<#
199                }
200#>
201            }
202        }
203
204        public static BusAccess.<#= outName #>WriteMethod Build<#= outName #>WriteBigEndianUsing(BusAccess.<#= inName #>ReadMethod read, BusAccess.<#= inName #>WriteMethod write)
205        {
206            return (address, value) =>
207            {
208                unchecked
209                {
210<#
211                    for(var i = outWidth - inWidth; i >= 0; i -= inWidth)
212                    {
213#>
214                    write(address + <#= (outWidth - inWidth - i) / 8 #>, <#= swapFuncIn #>((<#= inType #>)(value >> <#= i #>)));
215<#
216                    }
217#>
218                }
219            };
220        }
221
222<#
223            }
224            else // inWidth >= outWidth
225            {
226                var mask = masks[outWidth];
227#>
228        public static <#= outType #> Read<#= outName #>Using<#= inName #>(this I<#= inName #>Peripheral peripheral, long address)
229        {
230            unchecked
231            {
232                var readAddress = address & (~<#= inWidth / 8 - 1 #>);
233                var offset = (int)(address & <#= inWidth / 8 - 1 #>);
234                return (<#= outType #>)(peripheral.Read<#= inName #>(readAddress) >> offset * 8);
235            }
236        }
237
238        public static BusAccess.<#= outName #>ReadMethod Build<#= outName #>ReadUsing(BusAccess.<#= inName #>ReadMethod read)
239        {
240            return address =>
241            {
242                unchecked
243                {
244                    var readAddress = address & (~<#= inWidth / 8 - 1 #>);
245                    var offset = (int)(address & <#= inWidth / 8 - 1 #>);
246                    return (<#= outType #>)(read(readAddress) >> offset * 8);
247                }
248            };
249        }
250
251        public static void Write<#= outName #>Using<#= inName #>(this I<#= inName #>Peripheral peripheral, long address, <#= outType #> value)
252        {
253            unchecked
254            {
255                var writeAddress = address & (~<#= inWidth / 8 - 1 #>);
256                var offset = (int)(address & <#= inWidth / 8 - 1 #>);
257                var oldValue = peripheral.Read<#= inName #>(writeAddress) & ~((<#= inType #>)<#= mask #> << offset * 8);
258                peripheral.Write<#= inName #>(writeAddress, (<#= inType #>)(oldValue | ((<#= inType #>)value << 8 * offset)));
259            }
260        }
261
262        public static BusAccess.<#= outName #>WriteMethod Build<#= outName #>WriteUsing(BusAccess.<#= inName #>ReadMethod read, BusAccess.<#= inName #>WriteMethod write)
263        {
264            return (address, value) =>
265            {
266                unchecked
267                {
268                    var writeAddress = address & (~<#= inWidth / 8 - 1 #>);
269                    var offset = (int)(address & <#= inWidth / 8 - 1 #>);
270                    var oldValue = read(writeAddress) & ~((<#= inType #>)<#= mask #> << offset * 8);
271                    write(writeAddress, (<#= inType #>)(oldValue | ((<#= inType #>)value << 8 * offset)));
272                }
273            };
274        }
275
276        public static <#= outType #> Read<#= outName #>Using<#= inName #>BigEndian(this I<#= inName #>Peripheral peripheral, long address)
277        {
278            unchecked
279            {
280                var readAddress = address & (~<#= inWidth / 8 - 1 #>);
281                var offset = <#= (inWidth - outWidth) / 8 #> - (int)(address & <#= inWidth / 8 - 1 #>);
282                return <#= swapFuncOut #>((<#= outType #>)(peripheral.Read<#= inName #>(readAddress) >> offset * 8));
283            }
284        }
285
286        public static BusAccess.<#= outName #>ReadMethod Build<#= outName #>ReadBigEndianUsing(BusAccess.<#= inName #>ReadMethod read)
287        {
288            return address =>
289            {
290                unchecked
291                {
292                    var readAddress = address & (~<#= inWidth / 8 - 1 #>);
293                    var offset = <#= (inWidth - outWidth) / 8 #> - (int)(address & <#= inWidth / 8 - 1 #>);
294                    return <#= swapFuncOut #>((<#= outType #>)(read(readAddress) >> offset * 8));
295                }
296            };
297        }
298
299        public static void Write<#= outName #>Using<#= inName #>BigEndian(this I<#= inName #>Peripheral peripheral, long address, <#= outType #> value)
300        {
301            unchecked
302            {
303<#
304                if(outWidth > 8)
305                {
306#>
307                value = <#= swapFuncOut #>(value);
308<#
309                }
310#>
311                var writeAddress = address & (~<#= inWidth / 8 - 1 #>);
312                var offset = <#= (inWidth - outWidth) / 8 #> - (int)(address & <#= inWidth / 8 - 1 #>);
313                var oldValue = peripheral.Read<#= inName #>(writeAddress) & ~((<#= inType #>)<#= mask #> << offset * 8);
314                peripheral.Write<#= inName #>(writeAddress, (<#= inType #>)(oldValue | ((<#= inType #>)value << 8 * offset)));
315            }
316        }
317
318        public static BusAccess.<#= outName #>WriteMethod Build<#= outName #>WriteBigEndianUsing(BusAccess.<#= inName #>ReadMethod read, BusAccess.<#= inName #>WriteMethod write)
319        {
320            return (address, value) =>
321            {
322                unchecked
323                {
324<#
325                if(outWidth > 8)
326                {
327#>
328                    value = <#= swapFuncOut #>(value);
329<#
330                }
331#>
332                    var writeAddress = address & (~<#= inWidth / 8 - 1 #>);
333                    var offset = <#= (inWidth - outWidth) / 8 #> - (int)(address & <#= inWidth / 8 - 1 #>);
334                    var oldValue = read(writeAddress) & ~((<#= inType #>)<#= mask #> << offset * 8);
335                    write(writeAddress, (<#= inType #>)(oldValue | ((<#= inType #>)value << 8 * offset)));
336                }
337            };
338        }
339<#
340            } // else
341        } // foreach outWidth
342    } // foreach inWidth
343
344    foreach(var width in new int[] {16, 32, 64})
345    {
346        var type = widthTypes[width];
347        var name = widthNames[width];
348        var swapFunc = swapBytes[width];
349#>
350
351        public static <#= type #> Read<#= name #>BigEndian(this I<#= name #>Peripheral peripheral, long address)
352        {
353            return <#= swapFunc #>(peripheral.Read<#= name #>(address));
354        }
355
356        public static void Write<#= name #>BigEndian(this I<#= name #>Peripheral peripheral, long address, <#= type #> value)
357        {
358            peripheral.Write<#= name #>(address, <#= swapFunc #>(value));
359        }
360
361<#
362    } // foreach
363
364    foreach(var width in new int[] {8, 16, 32, 64})
365    {
366        var type = widthTypes[width];
367        var name = widthNames[width];
368#>
369
370        public static <#= type #> Read<#= name #>NotTranslated(this IBusPeripheral peripheral, long address)
371        {
372            LogNotTranslated(peripheral, SysbusAccessWidth.<#= name #>, address);
373            return 0;
374        }
375
376        public static void Write<#= name #>NotTranslated(this IBusPeripheral peripheral, long address, <#= type #> value)
377        {
378            LogNotTranslated(peripheral, SysbusAccessWidth.<#= name #>, address, value);
379        }
380<#
381    } // foreach
382#>
383
384        private static void LogNotTranslated(IBusPeripheral peripheral, SysbusAccessWidth operationWidth, long address, ulong? value = null)
385        {
386            var strBldr = new StringBuilder();
387            var isWrite = value.HasValue;
388            strBldr.AppendFormat("Attempted {0} {1} isn't supported by the peripheral.", operationWidth, isWrite ? "write" : "read");
389            strBldr.AppendFormat(" Offset 0x{0:X}", address);
390            if(isWrite)
391            {
392                strBldr.AppendFormat(", value 0x{0:X}", value.Value);
393            }
394            strBldr.Append(".");
395
396            peripheral.Log(LogLevel.Warning, peripheral.GetMachine().GetSystemBus(peripheral).DecorateWithCPUNameAndPC(strBldr.ToString()));
397        }
398    }
399}
400