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#v3.5" debug="True"#>
11<#@ import namespace="System.Collections.Generic" #>
12<#
13    Dictionary<string, string> types = new Dictionary<string, string>();
14    types.Add("byte", "Byte");
15    types.Add("ushort", "Word");
16    types.Add("uint", "DoubleWord");
17    types.Add("ulong", "QuadWord");
18#>
19/********************************************************
20*
21* Warning!
22* This file was generated automatically.
23* Please do not edit. Changes should be made in the
24* appropriate *.tt file.
25*
26*/
27
28using System;
29using Antmicro.Renode.Core;
30using Antmicro.Renode.Exceptions;
31using Antmicro.Renode.Logging;
32using Antmicro.Renode.Peripherals.Bus.Wrappers;
33using Antmicro.Renode.Peripherals.CPU;
34
35using Range = Antmicro.Renode.Core.Range;
36
37namespace Antmicro.Renode.Peripherals.Bus
38{
39    public partial class SystemBus
40    {
41<#
42    foreach(var entry in types)
43    {
44        var type = entry.Key;
45        var name = entry.Value;
46#>
47        public <#= type #> Read<#= name #>(ulong address, IPeripheral context = null, ulong? cpuState = null)
48        {
49            var accessWidth = SysbusAccessWidth.<#=name#>;
50            if(IsAddressRangeLocked(address.By((ulong)accessWidth), context))
51            {
52                this.Log(LogLevel.Warning, "Tried to read {0} bytes at 0x{1:X} which is inside a locked address range, returning 0",
53                    (uint)accessWidth, address);
54                return 0;
55            }
56
57            using(SetLocalContext(context, cpuState))
58            {
59                if(!TryFindPeripheralAccessMethods(address, context, out var accessMethods, out var startAddress, cpuState))
60                {
61                    return (<#= type #>)ReportNonExistingRead(address, accessWidth);
62                }
63                if(!IsPeripheralEnabled(accessMethods.Peripheral))
64                {
65                    this.Log(LogLevel.Warning, "Tried to read a locked peripheral: {0}. Address 0x{1:X}.", accessMethods.Peripheral, address);
66                    return 0;
67                }
68                var lockTaken = false;
69                try
70                {
71                    if(!accessMethods.Lock.IsHeldByCurrentThread)
72                    {
73                        accessMethods.Lock.Enter(ref lockTaken);
74                    }
75                    if(accessMethods.SetAbsoluteAddress != null)
76                    {
77                        accessMethods.SetAbsoluteAddress(address);
78                    }
79                    return accessMethods.Read<#=name#>(checked((long)(address - startAddress)));
80                }
81                finally
82                {
83                    if(lockTaken)
84                    {
85                        accessMethods.Lock.Exit();
86                    }
87                }
88            }
89        }
90
91        public <#= type #> Read<#= name #>WithState(ulong address, IPeripheral context, IContextState stateObj)
92        {
93            var accessWidth = SysbusAccessWidth.<#=name#>;
94            if(!TryConvertStateToUlongForContext(context, stateObj, out ulong? state))
95            {
96                this.Log(LogLevel.Warning, "Tried to read {0} bytes at 0x{1:X} but failed on context state conversion, returning 0",
97                    (uint)accessWidth, address);
98                return 0;
99            }
100            return Read<#=name#>(address, context, state);
101        }
102
103        public void Write<#=name#>(ulong address, <#=type#> value, IPeripheral context = null, ulong? cpuState = null)
104        {
105            var accessWidth = SysbusAccessWidth.<#=name#>;
106            if(IsAddressRangeLocked(address.By((ulong)accessWidth), context))
107            {
108                this.Log(LogLevel.Warning, "Tried to write {0} bytes (0x{1:X}) at 0x{2:X} which is inside a locked address range, write ignored",
109                    (uint)accessWidth, value, address);
110                return;
111            }
112
113            using(SetLocalContext(context, cpuState))
114            {
115                if(!TryFindPeripheralAccessMethods(address, context, out var accessMethods, out var startAddress, cpuState))
116                {
117                    ReportNonExistingWrite(address, value, accessWidth);
118                    return;
119                }
120                if(!IsPeripheralEnabled(accessMethods.Peripheral))
121                {
122                    this.Log(LogLevel.Warning, "Tried to write a locked peripheral: {0}. Address 0x{1:X}, value 0x{2:X}", accessMethods.Peripheral, address, value);
123                    return;
124                }
125
126                var lockTaken = false;
127                try
128                {
129                    if(!accessMethods.Lock.IsHeldByCurrentThread)
130                    {
131                        accessMethods.Lock.Enter(ref lockTaken);
132                    }
133                    if(accessMethods.SetAbsoluteAddress != null)
134                    {
135                        accessMethods.SetAbsoluteAddress(address);
136                    }
137                    accessMethods.Write<#=name#>(checked((long)(address - startAddress)), value);
138                }
139                finally
140                {
141                    if(lockTaken)
142                    {
143                        accessMethods.Lock.Exit();
144                    }
145                }
146            }
147        }
148
149        public void Write<#=name#>WithState(ulong address, <#=type#> value, IPeripheral context, IContextState stateObj)
150        {
151            var accessWidth = SysbusAccessWidth.<#=name#>;
152            if(!TryConvertStateToUlongForContext(context, stateObj, out ulong? state))
153            {
154                this.Log(LogLevel.Warning, "Tried to write {0} bytes (0x{1:X}) at 0x{2:X} but failed on context state conversion, write ignored",
155                    (uint)accessWidth, value, address);
156                return;
157            }
158            Write<#=name#>(address, value, context, state);
159        }
160
161<# }
162#>
163<#
164    foreach(var operation in new [] { "Read", "Write" })
165    {
166        var when = operation == "Read" ? "After" : "Before";
167        var actionOrFunc = operation == "Read" ? "Func" : "Action";
168#>
169        public void ClearHook<#=when#>Peripheral<#=operation#><T>(IBusPeripheral peripheral)
170        {
171            SetHook<#=when#>Peripheral<#=operation#><T>(peripheral, null);
172        }
173
174        public void SetHook<#=when#>Peripheral<#=operation#><T>(IBusPeripheral peripheral, Func<T, long, T> hook, Range? subrange = null)
175        {
176            if(!Machine.IsRegistered(peripheral))
177            {
178                throw new RecoverableException(string.Format("Cannot set hook on peripheral {0}, it is not registered.", peripheral));
179            }
180            var type = typeof(T);
181<#
182        foreach(var entry in types)
183        {
184            var type = entry.Key;
185            var name = entry.Value;
186#>
187            if(type == typeof(<#=type#>))
188            {
189                foreach(var peripherals in allPeripherals)
190                {
191                    peripherals.VisitAccessMethods(peripheral, pam =>
192                    {
193                        if(pam.<#=operation#><#=name#>.Target is <#=operation#>HookWrapper<<#=type#>>)
194                        {
195                            pam.<#=operation#><#=name#> = new BusAccess.<#=name#><#=operation#>Method(((<#=operation#>HookWrapper<<#=type#>>)pam.<#=operation#><#=name#>.Target).OriginalMethod);
196                        }
197                        if(hook != null)
198                        {
199                            pam.<#=operation#><#=name#> = new BusAccess.<#=name#><#=operation#>Method(new <#=operation#>HookWrapper<<#=type#>>(peripheral, new <#=actionOrFunc#><long, <#=type#>>(pam.<#=operation#><#=name#>), (Func<<#=type#>, long, <#=type#>>)(object)hook, subrange).<#=operation#>);
200                        }
201                        return pam;
202                    });
203                }
204                return;
205            }
206<#
207        }
208#>
209        }
210
211<#
212    }
213#>
214        private bool TryFindPeripheralAccessMethods(ulong address, IPeripheral context, out PeripheralAccessMethods accessMethods, out ulong startAddress, ulong? cpuState = null)
215        {
216            if(context == null)
217            {
218                TryGetCurrentCPU(out var cpu);
219                context = cpu;
220            }
221            if(context != null)
222            {
223                if(peripheralsCollectionByContext.TryGetValue(context, cpuState, out var collection))
224                {
225                    accessMethods = collection.FindAccessMethods(address, out startAddress, out var _);
226                    if(accessMethods != null)
227                    {
228                        return true;
229                    }
230                }
231            }
232            accessMethods = peripheralsCollectionByContext[null].FindAccessMethods(address, out startAddress, out _);
233            return accessMethods != null;
234        }
235    }
236}
237