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 using System;
9 using Antmicro.Renode.Utilities;
10 
11 namespace Antmicro.Renode.Core.Structure.Registers
12 {
13     public static class PeripheralRegisterExtensions
14     {
15         /// <summary>
16         /// Creates a fluent conditional wrapper for conditionally executing actions on a register.
17         /// </summary>
18         /// <param name="condition">The condition to evaluate.</param>
19         /// <returns>An <see cref="IfWrapper{T}"/> object wrapping the register.</returns>
20         /// <example>
21         /// This example demonstrates how to use the <c>If</c> and <c>Else</c> methods
22         /// of <see cref="IfWrapper{T}"/> to conditionally define a field on a register:
23         /// <code>
24         /// Registers.Control.Define(this)
25         ///     .WithValueField(0, 4, out transmissionSize, name: "TXSIZE")
26         ///     .If(SupportsEncryption)
27         ///         .Then(r => r.WithValueField(4, 12, out transmissionKey, name: "TXKEY"))
28         ///         .Else(r => r.WithReservedBits(4, 12));
29         /// </code>
30         /// </example>
31         public static IfWrapper<T> If<T>(this T register, bool condition) where T : PeripheralRegister
32         {
33             return new IfWrapper<T>(register, condition);
34         }
35 
36         /// <summary>
37         /// Fluent API for handling for loops. This helper is equivalent to calling the callback in a for loop
38         /// going from "start" to "end" being incremented by "step"
39         /// </summary>
40         /// <param name="callback">Callback to execute on each loop iteration</param>
41         /// <param name="start">Starting value of the loop variable</param>
42         /// <param name="end">Exclusive ending value of the loop variable</param>
43         /// <param name="step">Amount that the loop variable will be incremented by after each iteration</param>
44         /// <returns>This register after all loop iterations</returns>
45         public static T For<T>(this T register, Action<T, int> callback, int start, int end, int step = 1) where T : PeripheralRegister
46         {
47             for(var i = start; i < end; i += step)
48             {
49                 callback(register, i);
50             }
51             return register;
52         }
53 
54         /// <summary>
55         /// Fluent API for flag field creation. For parameters see <see cref="PeripheralRegister.DefineFlagField"/>.
56         /// </summary>
57         /// <returns>This register with a defined flag.</returns>
58         public static T WithFlag<T>(this T register, int position, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<bool, bool> readCallback = null,
59             Action<bool, bool> writeCallback = null, Action<bool, bool> changeCallback = null, Func<bool, bool> valueProviderCallback = null, bool softResettable = true,
60             string name = null) where T : PeripheralRegister
61         {
62             register.DefineFlagField(position, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name);
63             return register;
64         }
65 
66         /// <summary>
67         /// Fluent API for creation of a set of consecutive flag fields.
68         /// </summary>
69         /// <param name="position">Offset in the register of the first field.</param>
70         /// <param name="count">Number of flag fields to create.</param>
71         /// <param name="mode">Access modifiers of each field.</param>
72         /// <param name="readCallback">Method to be called whenever the containing register is read. The first parameter is the index of the flag field, the second is the value of this field before read,
73         /// the third parameter is the value after read. Note that it will also be called for unreadable fields.</param>
74         /// <param name="writeCallback">Method to be called whenever the containing register is written to. The first parameter is the index of the flag, the second is the value of this field before write,
75         /// the third parameter is the value written (without any modification). Note that it will also be called for unwrittable fields.</param>
76         /// <param name="changeCallback">Method to be called whenever this field's value is changed, either due to read or write. The first parameter is the index of the flag, the second is the value of this field before change,
77         /// the third parameter is the value after change. Note that it will also be called for unwrittable fields.</param>
78         /// <param name="valueProviderCallback">Method to be called whenever this field is read. The value passed is the current field's value, that will be overwritten by
79         /// the value returned from it. This returned value is eventually passed as the second parameter of <paramref name="readCallback"/>.</param>
80         /// <param name="softResettable">Indicates whether the field should be cleared by soft reset.</param>
81         /// <param name="name">Ignored parameter, for convenience. Treat it as a comment.</param>
82         /// <returns>This register with defined flags.</returns>
83         public static T WithFlags<T>(this T register, int position, int count, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<int, bool, bool> readCallback = null,
84             Action<int, bool, bool> writeCallback = null, Action<int, bool, bool> changeCallback = null, Func<int, bool, bool> valueProviderCallback = null, bool softResettable = true,
85             string name = null) where T : PeripheralRegister
86         {
87             return WithFlags(register, position, count, out var _, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name);
88         }
89 
90         /// <summary>
91         /// Fluent API for value field creation. For parameters see <see cref="PeripheralRegister.DefineValueField"/>.
92         /// </summary>
93         /// <returns>This register with a defined value field.</returns>
94         public static T WithValueField<T>(this T register, int position, int width, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<ulong, ulong> readCallback = null,
95             Action<ulong, ulong> writeCallback = null, Action<ulong, ulong> changeCallback = null, Func<ulong, ulong> valueProviderCallback = null, bool softResettable = true,
96             string name = null) where T : PeripheralRegister
97         {
98             register.DefineValueField(position, width, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name);
99             return register;
100         }
101 
102         /// <summary>
103         /// Fluent API for creation of a set of consecutive value fields
104         /// </summary>
105         /// <param name="position">Offset in the register of the first field.</param>
106         /// <param name="width">Maximum width of the value, in terms of binary representation.</param>
107         /// <param name="count">Number of flag fields to create.</param>
108         /// <param name="mode">Access modifiers of each field.</param>
109         /// <param name="readCallback">Method to be called whenever the containing register is read. The first parameter is the index of the value field, the second is the value of this field before read,
110         /// the third parameter is the value after read. Note that it will also be called for unreadable fields.</param>
111         /// <param name="writeCallback">Method to be called whenever the containing register is written to. The first parameter is the index of the field, the second is the value of this field before write,
112         /// the third parameter is the value written (without any modification). Note that it will also be called for unwrittable fields.</param>
113         /// <param name="changeCallback">Method to be called whenever this field's value is changed, either due to read or write. The first parameter is the index of the field, the second is the value of this field before change,
114         /// the third parameter is the value after change. Note that it will also be called for unwrittable fields.</param>
115         /// <param name="valueProviderCallback">Method to be called whenever this field is read. The value passed is the current field's value, that will be overwritten by
116         /// the value returned from it. This returned value is eventually passed as the second parameter of <paramref name="readCallback"/>.</param>
117         /// <param name="softResettable">Indicates whether the field should be cleared by soft reset.</param>
118         /// <param name="name">Ignored parameter, for convenience. Treat it as a comment.</param>
119         /// <returns>This register with defined value fields.</returns>
120         public static T WithValueFields<T>(this T register, int position, int width, int count, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<int, ulong, ulong> readCallback = null,
121             Action<int, ulong, ulong> writeCallback = null, Action<int, ulong, ulong> changeCallback = null, Func<int, ulong, ulong> valueProviderCallback = null, bool softResettable = true,
122             string name = null) where T : PeripheralRegister
123         {
124             return WithValueFields(register, position, width, count, out var _, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name);
125         }
126 
127         /// <summary>
128         /// Fluent API for enum field creation. For parameters see <see cref="PeripheralRegister.DefineEnumField"/>.
129         /// </summary>
130         /// <returns>This register with a defined enum field.</returns>
131         public static R WithEnumField<R, T>(this R register, int position, int width, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<T, T> readCallback = null,
132             Action<T, T> writeCallback = null, Action<T, T> changeCallback = null, Func<T, T> valueProviderCallback = null, bool softResettable = true, string name = null)
133             where R : PeripheralRegister
134             where T : struct, IConvertible
135         {
register.DefineEnumFieldAntmicro.Renode.Core.Structure.Registers.PeripheralRegisterExtensions.IConvertible136             register.DefineEnumField<T>(position, width, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name);
137             return register;
138         }
139 
140         /// <summary>
141         /// Fluent API for tagged field creation. For parameters see <see cref="PeripheralRegister.Tag"/>.
142         /// </summary>
143         /// <returns>This register with a defined tag field.</returns>
144         public static T WithTag<T>(this T register, string name, int position, int width) where T : PeripheralRegister
145         {
146             register.Tag(name, position, width);
147             return register;
148         }
149 
150         /// <summary>
151         /// Fluent API for creating a set of tagged fields. For parameters see <see cref="PeripheralRegister.Tag"/>.
152         /// </summary>
153         /// <returns>This register with a defined tag field set.</returns>
154         public static T WithTags<T>(this T register, string name, int position, int width, int count) where T : PeripheralRegister
155         {
156             for(var i = 0; i < count; i++)
157             {
158                 register.Tag(name == null ? null : $"{name}_{i}", position + (i * width), width);
159             }
160             return register;
161         }
162 
163         /// <summary>
164         /// Fluent API for tagged flag creation - a tag of width equal to 1. For parameters see <see cref="PeripheralRegister.DefineValueField"/>.
165         /// </summary>
166         /// <returns>This register with a defined tag field.</returns>
167         public static T WithTaggedFlag<T>(this T register, string name, int position) where T : PeripheralRegister
168         {
169             register.Tag(name, position, 1);
170             return register;
171         }
172 
173         /// <summary>
174         /// Fluent API for creating a set of tagged flags - a tag of width equal to 1. For parameters see <see cref="PeripheralRegister.DefineValueField"/>.
175         /// </summary>
176         /// <returns>This register with a defined tag field set.</returns>
177         public static T WithTaggedFlags<T>(this T register, string name, int position, int count) where T : PeripheralRegister
178         {
179             for(var i = 0; i < count; i++)
180             {
181                 register.WithTaggedFlag(name == null ? null : $"{name}_{i}", position + i);
182             }
183             return register;
184         }
185 
186         /// <summary>
187         /// Fluent API for value field creation. For parameters see <see cref="PeripheralRegister.DefineValueField"/>.
188         /// This overload allows you to retrieve the created field via <c>valueField</c> parameter.
189         /// </summary>
190         /// <returns>This register with a defined value field.</returns>
191         public static T WithValueField<T>(this T register, int position, int width, out IValueRegisterField valueField, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<ulong, ulong> readCallback = null,
192             Action<ulong, ulong> writeCallback = null, Action<ulong, ulong> changeCallback = null, Func<ulong, ulong> valueProviderCallback = null, bool softResettable = true, string name = null) where T : PeripheralRegister
193         {
194             valueField = register.DefineValueField(position, width, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name);
195             return register;
196         }
197 
198         /// <summary>
199         /// Fluent API for creation of set of value fields. For parameters see the other overload of <see cref="PeripheralRegisterExtensions.WithValueFields"/>.
200         /// This overload allows you to retrieve the created array of fields via <c>valueFields</c> parameter.
201         /// </summary>
202         /// <returns>This register with defined value fields.</returns>
203         public static T WithValueFields<T>(this T register, int position, int width, int count, out IValueRegisterField[] valueFields, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<int, ulong, ulong> readCallback = null,
204             Action<int, ulong, ulong> writeCallback = null, Action<int, ulong, ulong> changeCallback = null, Func<int, ulong, ulong> valueProviderCallback = null, bool softResettable = true,
205             string name = null) where T : PeripheralRegister
206         {
207             valueFields = new IValueRegisterField[count];
208             for(var i = 0; i < count; i++)
209             {
210                 var j = i;
211 
212                 valueFields[j] = register.DefineValueField(position + (j * width), width, mode,
213                     readCallback == null ? null : (Action<ulong, ulong>)((x, y) => readCallback(j, x, y)),
214                     writeCallback == null ? null : (Action<ulong, ulong>)((x, y) => writeCallback(j, x, y)),
215                     changeCallback == null ? null : (Action<ulong, ulong>)((x, y) => changeCallback(j, x, y)),
216                     valueProviderCallback == null ? null : (Func<ulong, ulong>)((x) => valueProviderCallback(j, x)),
217                     softResettable,
218                     name == null ? null : $"{name}_{j}");
219             }
220             return register;
221         }
222 
223         /// <summary>
224         /// Fluent API for enum field creation. For parameters see <see cref="PeripheralRegister.DefineEnumField"/>.
225         /// This overload allows you to retrieve the created field via <c>enumField</c> parameter.
226         /// </summary>
227         /// <returns>This register with a defined enum field.</returns>
228         public static R WithEnumField<R, T>(this R register, int position, int width, out IEnumRegisterField<T> enumField, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<T, T> readCallback = null,
229             Action<T, T> writeCallback = null, Action<T, T> changeCallback = null, Func<T, T> valueProviderCallback = null, bool softResettable = true, string name = null) where R : PeripheralRegister
230             where T : struct, IConvertible
231         {
232             enumField = register.DefineEnumField<T>(position, width, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name);
233             return register;
234         }
235 
236         /// <summary>
237         /// Fluent API for creation of set of enum fields. For parameters see the other overload of <see cref="PeripheralRegisterExtensions.WithEnumFields"/>.
238         /// This overload allows you to retrieve the created array of fields via <c>enumFields</c> parameter.
239         /// </summary>
240         /// <returns>This register with defined enum fields.</returns>
241         public static R WithEnumFields<R, T>(this R register, int position, int width, int count, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<int, T, T> readCallback = null,
242             Action<int, T, T> writeCallback = null, Action<int, T, T> changeCallback = null, Func<int, T, T> valueProviderCallback = null, bool softResettable = true, string name = null)
243             where R : PeripheralRegister
244             where T : struct, IConvertible
245         {
246             return WithEnumFields<R, T>(register, position, width, count, out var _, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name);
247         }
248 
249         /// <summary>
250         /// Fluent API for creation of set of enum fields. For parameters see the other overload of <see cref="PeripheralRegisterExtensions.WithEnumFields"/>.
251         /// This overload allows you to retrieve the created array of fields via <c>enumFields</c> parameter.
252         /// </summary>
253         /// <returns>This register with defined enum fields.</returns>
254         public static R WithEnumFields<R, T>(this R register, int position, int width, int count, out IEnumRegisterField<T>[] enumFields, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<int, T, T> readCallback = null,
255             Action<int, T, T> writeCallback = null, Action<int, T, T> changeCallback = null, Func<int, T, T> valueProviderCallback = null, bool softResettable = true, string name = null)
256             where R : PeripheralRegister
257             where T : struct, IConvertible
258         {
259             enumFields = new IEnumRegisterField<T>[count];
260             for(var i = 0; i < count; i++)
261             {
262                 var j = i;
263 
264                 enumFields[j] = register.DefineEnumField<T>(position + (j * width), width, mode,
265                     readCallback == null ? null : (Action<T, T>)((x, y) => readCallback(j, x, y)),
266                     writeCallback == null ? null : (Action<T, T>)((x, y) => writeCallback(j, x, y)),
267                     changeCallback == null ? null : (Action<T, T>)((x, y) => changeCallback(j, x, y)),
268                     valueProviderCallback == null ? null : (Func<T, T>)((x) => valueProviderCallback(j, x)),
269                     softResettable,
270                     name == null ? null : $"{name}_{j}");
271             }
272             return register;
273         }
274 
275         /// <summary>
276         /// Fluent API for flag field creation. For parameters see <see cref="PeripheralRegister.DefineFlagField"/>.
277         /// This overload allows you to retrieve the created field via <c>flagField</c> parameter.
278         /// </summary>
279         /// <returns>This register with a defined flag.</returns>
280         public static T WithFlag<T>(this T register, int position, out IFlagRegisterField flagField, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<bool, bool> readCallback = null,
281             Action<bool, bool> writeCallback = null, Action<bool, bool> changeCallback = null, Func<bool, bool> valueProviderCallback = null, bool softResettable = true, string name = null)
282             where T : PeripheralRegister
283         {
284             flagField = register.DefineFlagField(position, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name);
285             return register;
286         }
287 
288         /// <summary>
289         /// Fluent API for creation of sets of flag fields. For parameters see the other overload of <see cref="PeripheralRegisterExtensions.WithFlags"/>.
290         /// This overload allows you to retrieve the created array of fields via <c>flagFields</c> parameter.
291         /// </summary>
292         /// <returns>This register with defined flags.</returns>
293         public static T WithFlags<T>(this T register, int position, int count, out IFlagRegisterField[] flagFields, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<int, bool, bool> readCallback = null,
294             Action<int, bool, bool> writeCallback = null, Action<int, bool, bool> changeCallback = null, Func<int, bool, bool> valueProviderCallback = null, bool softResettable = true,
295             string name = null) where T : PeripheralRegister
296         {
297             flagFields = new IFlagRegisterField[count];
298             for(var i = 0; i < count; i++)
299             {
300                 var j = i;
301 
302                 flagFields[j] = register.DefineFlagField(position + j, mode,
303                     readCallback == null ? null : (Action<bool, bool>)((x, y) => readCallback(j, x, y)),
304                     writeCallback == null ? null : (Action<bool, bool>)((x, y) => writeCallback(j, x, y)),
305                     changeCallback == null ? null : (Action<bool, bool>)((x, y) => changeCallback(j, x, y)),
306                     valueProviderCallback == null ? null : (Func<bool, bool>)((x) => valueProviderCallback(j, x)),
307                     softResettable,
308                     name == null ? null : $"{name}_{j}");
309             }
310             return register;
311         }
312 
313         /// <summary>
314         /// Fluent API for tagging bits as "RESERVED". For description see <see cref="PeripheralRegister.Reserved"/>.
315         /// </summary>
316         /// <returns>This register with a new "RESERVED" tag.</returns>
317         public static T WithReservedBits<T>(this T register, int position, int width, uint? allowedValue = null) where T : PeripheralRegister
318         {
319             register.Reserved(position, width, allowedValue);
320             return register;
321         }
322 
323         /// <summary>
324         /// Fluent API for tagging bits as ignored.
325         /// </summary>
326         /// <returns>This defines a value field to avoid warnings about unhandled bits.</returns>
327         public static T WithIgnoredBits<T>(this T register, int position, int width) where T : PeripheralRegister
328         {
329             return register.WithValueField(position, width, name: "ignored");
330         }
331     }
332 
333     public static class QuadWordRegisterExtensions
334     {
335         /// <summary>
336         /// Fluent API for read callback registration. For description see <see cref="QuadWordRegister.DefineReadCallback"/>.
337         /// </summary>
338         /// <returns>This register with a defined callback.</returns>
WithReadCallback(this QuadWordRegister register, Action<ulong, ulong> readCallback)339         public static QuadWordRegister WithReadCallback(this QuadWordRegister register, Action<ulong, ulong> readCallback)
340         {
341             register.DefineReadCallback(readCallback);
342             return register;
343         }
344 
345         /// <summary>
346         /// Fluent API for write callback registration. For description see <see cref="QuadWordRegister.DefineWriteCallback"/>.
347         /// </summary>
348         /// <returns>This register with a defined callback.</returns>
WithWriteCallback(this QuadWordRegister register, Action<ulong, ulong> writeCallback)349         public static QuadWordRegister WithWriteCallback(this QuadWordRegister register, Action<ulong, ulong> writeCallback)
350         {
351             register.DefineWriteCallback(writeCallback);
352             return register;
353         }
354 
355         /// <summary>
356         /// Fluent API for change callback registration. For description see <see cref="QuadWordRegister.DefineChangeCallback"/>.
357         /// </summary>
358         /// <returns>This register with a defined callback.</returns>
WithChangeCallback(this QuadWordRegister register, Action<ulong, ulong> changeCallback)359         public static QuadWordRegister WithChangeCallback(this QuadWordRegister register, Action<ulong, ulong> changeCallback)
360         {
361             register.DefineChangeCallback(changeCallback);
362             return register;
363         }
364     }
365 
366     public static class DoubleWordRegisterExtensions
367     {
368         /// <summary>
369         /// Fluent API for read callback registration. For description see <see cref="DoubleWordRegister.DefineReadCallback"/>.
370         /// </summary>
371         /// <returns>This register with a defined callback.</returns>
WithReadCallback(this DoubleWordRegister register, Action<uint, uint> readCallback)372         public static DoubleWordRegister WithReadCallback(this DoubleWordRegister register, Action<uint, uint> readCallback)
373         {
374             register.DefineReadCallback(readCallback);
375             return register;
376         }
377 
378         /// <summary>
379         /// Fluent API for write callback registration. For description see <see cref="DoubleWordRegister.DefineWriteCallback"/>.
380         /// </summary>
381         /// <returns>This register with a defined callback.</returns>
WithWriteCallback(this DoubleWordRegister register, Action<uint, uint> writeCallback)382         public static DoubleWordRegister WithWriteCallback(this DoubleWordRegister register, Action<uint, uint> writeCallback)
383         {
384             register.DefineWriteCallback(writeCallback);
385             return register;
386         }
387 
388         /// <summary>
389         /// Fluent API for change callback registration. For description see <see cref="DoubleWordRegister.DefineChangeCallback"/>.
390         /// </summary>
391         /// <returns>This register with a defined callback.</returns>
WithChangeCallback(this DoubleWordRegister register, Action<uint, uint> changeCallback)392         public static DoubleWordRegister WithChangeCallback(this DoubleWordRegister register, Action<uint, uint> changeCallback)
393         {
394             register.DefineChangeCallback(changeCallback);
395             return register;
396         }
397     }
398 
399     public static class WordRegisterExtensions
400     {
401         /// <summary>
402         /// Fluent API for read callback registration. For description see <see cref="WordRegister.DefineReadCallback"/>.
403         /// </summary>
404         /// <returns>This register with a defined callback.</returns>
WithReadCallback(this WordRegister register, Action<ushort, ushort> readCallback)405         public static WordRegister WithReadCallback(this WordRegister register, Action<ushort, ushort> readCallback)
406         {
407             register.DefineReadCallback(readCallback);
408             return register;
409         }
410 
411         /// <summary>
412         /// Fluent API for write callback registration. For description see <see cref="WordRegister.DefineWriteCallback"/>.
413         /// </summary>
414         /// <returns>This register with a defined callback.</returns>
WithWriteCallback(this WordRegister register, Action<ushort, ushort> writeCallback)415         public static WordRegister WithWriteCallback(this WordRegister register, Action<ushort, ushort> writeCallback)
416         {
417             register.DefineWriteCallback(writeCallback);
418             return register;
419         }
420 
421         /// <summary>
422         /// Fluent API for change callback registration. For description see <see cref="WordRegister.DefineChangeCallback"/>.
423         /// </summary>
424         /// <returns>This register with a defined callback.</returns>
WithChangeCallback(this WordRegister register, Action<ushort, ushort> changeCallback)425         public static WordRegister WithChangeCallback(this WordRegister register, Action<ushort, ushort> changeCallback)
426         {
427             register.DefineChangeCallback(changeCallback);
428             return register;
429         }
430     }
431 
432     public static class ByteRegisterExtensions
433     {
434         /// <summary>
435         /// Fluent API for read callback registration. For description see <see cref="ByteRegister.DefineReadCallback"/>.
436         /// </summary>
437         /// <returns>This register with a defined callback.</returns>
WithReadCallback(this ByteRegister register, Action<byte, byte> readCallback)438         public static ByteRegister WithReadCallback(this ByteRegister register, Action<byte, byte> readCallback)
439         {
440             register.DefineReadCallback(readCallback);
441             return register;
442         }
443 
444         /// <summary>
445         /// Fluent API for write callback registration. For description see <see cref="ByteRegister.DefineWriteCallback"/>.
446         /// </summary>
447         /// <returns>This register with a defined callback.</returns>
WithWriteCallback(this ByteRegister register, Action<byte, byte> writeCallback)448         public static ByteRegister WithWriteCallback(this ByteRegister register, Action<byte, byte> writeCallback)
449         {
450             register.DefineWriteCallback(writeCallback);
451             return register;
452         }
453 
454         /// <summary>
455         /// Fluent API for change callback registration. For description see <see cref="ByteRegister.DefineChangeCallback"/>.
456         /// </summary>
457         /// <returns>This register with a defined callback.</returns>
WithChangeCallback(this ByteRegister register, Action<byte, byte> changeCallback)458         public static ByteRegister WithChangeCallback(this ByteRegister register, Action<byte, byte> changeCallback)
459         {
460             register.DefineChangeCallback(changeCallback);
461             return register;
462         }
463     }
464 }
465