1 // Copyright (C) 2024 Antmicro
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // SPDX-License-Identifier: Apache-2.0
16 
17 using System;
18 using System.Reflection;
19 using System.Collections.Generic;
20 using System.Linq;
21 using NUnit.Framework;
22 using Antmicro.Renode.Core.Structure.Registers;
23 using Antmicro.Renode.Peripherals.Bus;
24 using Antmicro.Renode.Utilities;
25 using System.Text.Json;
26 using System.Text.Json.Serialization;
27 using System.IO;
28 using Mono.Cecil;
29 
30 namespace Antmicro.Renode.PeripheralsTests
31 {
32     [TestFixture]
33     public class SystemRDLGenTest
34     {
35         private class LoadedAssemblies
36         {
LoadedAssemblies()37             private LoadedAssemblies()
38             {
39                 Assemblies = new Dictionary<string, AssemblyDefinition>();
40                 compiler = new AdHocCompiler();
41             }
42 
43             static public LoadedAssemblies Instance
44             {
45                 get
46                 {
47                     if(instance == null)
48                     {
49                         instance = new LoadedAssemblies();
50                     }
51                     return instance;
52                 }
53             }
54 
55             public IDictionary<string, AssemblyDefinition> Assemblies { get; set; }
56 
LoadAssembly(RdlMeta meta)57             public AssemblyDefinition LoadAssembly(RdlMeta meta)
58             {
59                 var adhocPath = Path.Join(Assembly.GetExecutingAssembly().Location, "../../../../", meta.File);
60                 if(!Assemblies.TryGetValue(adhocPath, out var assembly))
61                 {
62                     var assemblyPath = compiler.Compile(adhocPath);
63                     assembly = AssemblyDefinition.ReadAssembly(assemblyPath);
64                     Assemblies[adhocPath] = assembly;
65                     TypeManager.Instance.ScanFile(assemblyPath);
66                 }
67                 return assembly;
68             }
69 
70             private static LoadedAssemblies instance;
71             private readonly AdHocCompiler compiler;
72         }
73 
74         static private IEnumerable<RdlMeta> GetTestCases
75         {
76             get
77             {
78                 var assembly = Assembly.GetExecutingAssembly();
79                 if(!assembly.TryFromResourceToTemporaryFile(SystemRDLResource, out var file))
80                 {
81                     Console.WriteLine($"Couldn't load the {SystemRDLResource} resource");
82                     yield break;
83                 }
84                 var fstream = File.OpenRead(file);
85 
86                 var options = new JsonSerializerOptions
87                 {
88                     PropertyNameCaseInsensitive = true,
89                 };
90                 options.Converters.Add(new TestFieldModeFlagConverter());
91 
92                 var metas = (List<RdlMeta>)JsonSerializer.Deserialize(fstream, typeof(List<RdlMeta>), options);
93 
94                 foreach(var meta in metas)
95                 {
96                     yield return meta;
97                 }
98             }
99         }
100 
101         [OneTimeSetUp]
Setup()102         public void Setup()
103         {
104             var peripheralRegisterClasses = typeof(PeripheralRegister).GetTypeInfo().DeclaredNestedTypes.ToDictionary(ti => ti.Name);
105             this.ValueRegisterField = peripheralRegisterClasses["ValueRegisterField"];
106             Assert.NotNull(this.ValueRegisterField);
107             this.FlagRegisterField = peripheralRegisterClasses["FlagRegisterField"];
108             Assert.NotNull(this.FlagRegisterField);
109             this.RegisterField = peripheralRegisterClasses["RegisterField"];
110             Assert.NotNull(this.RegisterField);
111         }
112 
113         public class TestFieldModeFlagConverter : JsonConverter<FieldMode> {
Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)114             public override FieldMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
115             {
116                 FieldMode flags = 0;
117 
118                 if(reader.TokenType != JsonTokenType.StartArray)
119                 {
120                     throw new JsonException("Expected a start of a flag array");
121                 }
122 
123                 while(reader.Read())
124                 {
125                     if(reader.TokenType == JsonTokenType.EndArray)
126                     {
127                         return flags;
128                     }
129 
130                     var flagStr = reader.GetString();
131                     foreach(var flag in Enum.GetValues(typeof(FieldMode)))
132                     {
133                         if(flagStr == flag.ToString())
134                         {
135                             flags |= (FieldMode)flag;
136                         }
137                     }
138                 }
139 
140                 throw new JsonException("Unexpected end of stream");
141             }
142 
Write(Utf8JsonWriter writer, FieldMode fieldMode, JsonSerializerOptions options)143             public override void Write(Utf8JsonWriter writer, FieldMode fieldMode, JsonSerializerOptions options)
144             {
145                 throw new JsonException("Write not supported");
146             }
147         }
148 
149         public class RdlField
150         {
151             public string Name { get; set; }
152             public uint Low { get; set; }
153             public uint High { get; set; }
154             public FieldMode Mode { get; set; }
155             public string FieldType { get; set; }
156 
GetFieldType()157             public Type GetFieldType() =>
158                 Type.GetType("Antmicro.Renode.Core.Structure.Registers." + FieldType + ", Infrastructure");
159         }
160 
161         public class RdlRegister
162         {
163             public string ClassName { get; set; }
164             public string InstanceName { get; set; }
165             public ulong Offset { get; set; }
166             public ulong ResetValue { get; set; }
167             public List<RdlField> Fields { get; set; }
168         }
169 
170         public class RdlMeta
171         {
172             public string File { get; set; }
173             public string Class { get; set; }
174             public string RegisterContainerClass { get; set; }
175             public List<RdlRegister> Registers { get; set; }
176 
GetClass()177             public Type GetClass()
178             {
179                 return TypeManager.Instance.GetTypeByName(Class);
180             }
181 
GetRegisterContainerClass()182             public Type GetRegisterContainerClass() =>
183                 Type.GetType("Antmicro.Renode.Core.Structure.Registers." + RegisterContainerClass + ", Infrastructure");
184         }
185 
186         public List<RdlMeta> TestCases { get; set; }
187 
InitPeripheral(RdlMeta meta)188         private void InitPeripheral(RdlMeta meta)
189         {
190             if(meta.File != "")
191             {
192                 var assembly = LoadedAssemblies.Instance.LoadAssembly(meta);
193                 Console.WriteLine("Loaded extra peripheral code, assembly: " + assembly.FullName);
194             }
195             pType = meta.GetClass();
196             Assert.IsNotNull(pType);
197             peripheral = (IDoubleWordPeripheral)Activator.CreateInstance(pType);
198             Assert.IsNotNull(peripheral);
199         }
200 
201         [Test, TestCaseSource(nameof(GetTestCases))]
TestStaticMeta(RdlMeta meta)202         public void TestStaticMeta(RdlMeta meta)
203         {
204             Console.WriteLine("Checking structure of " + meta.Class + "...");
205             InitPeripheral(meta);
206 
207             var classes = pType.GetTypeInfo().DeclaredNestedTypes.ToDictionary(ti => ti.Name);
208             var cFields = pType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
209                 .ToDictionary(fi => fi.Name);
210 
211             Assert.AreEqual(meta.Registers.Count, classes.Count);
212 
213             var registersCollection = pType.GetProperty("RegistersCollection");
214             Assert.NotNull(registersCollection);
215             Assert.AreEqual(meta.GetRegisterContainerClass(), registersCollection.PropertyType);
216 
217             foreach(var register in meta.Registers)
218             {
219                 Console.WriteLine("- Checking register " + register.InstanceName + "...");
220 
221 
222                 Assert.IsTrue(classes.ContainsKey(register.ClassName));
223                 Assert.IsTrue(cFields.ContainsKey(register.InstanceName));
224 
225                 var rClass = classes[register.ClassName];
226                 var rInstance = cFields[register.InstanceName];
227 
228                 Assert.AreEqual(rClass, rInstance.FieldType);
229 
230                 foreach(var field in register.Fields)
231                 {
232                     Console.WriteLine("  - Checking field " + register.InstanceName + "." + field.Name + "...");
233                     var rField = rClass.GetField(field.Name);
234                     Assert.IsNotNull(rField);
235                     Assert.AreEqual(field.GetFieldType(), rField.FieldType);
236                 }
237             }
238         }
239 
240         [Test, TestCaseSource(nameof(GetTestCases))]
TestDynamicMeta(RdlMeta meta)241         public void TestDynamicMeta(RdlMeta meta)
242         {
243             Console.WriteLine("Checking behavior of " + meta.Class + "...");
244 
245             var getPrivateFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField;
246 
247             InitPeripheral(meta);
248 
249             foreach(var register in meta.Registers)
250             {
251                 var regInst = pType.GetField(register.InstanceName, getPrivateFlags).GetValue(peripheral);
252 
253                 foreach(var field in register.Fields)
254                 {
255                     Console.WriteLine("Testing " + pType.ToString() + "." + register.InstanceName + "." + field.Name + "...");
256 
257                     var fieldField = regInst.GetType().GetField(field.Name, getPrivateFlags);
258                     Assert.AreEqual(field.GetFieldType(), fieldField.FieldType);
259 
260                     var fieldInst = fieldField.GetValue(regInst);
261 
262                     var fieldMode = this.RegisterField.GetField("fieldMode").GetValue(fieldInst);
263                     var position = this.RegisterField.GetField("position").GetValue(fieldInst);
264                     var width = this.RegisterField.GetField("width").GetValue(fieldInst);
265                     Assert.AreEqual(field.Mode, fieldMode);
266                     Assert.AreEqual(field.Low, position);
267                     Assert.AreEqual(field.High - field.Low + 1, width);
268 
269 
270 
271                     if(fieldInst.GetType() == this.ValueRegisterField)
272                     {
273                         TestFieldMode((IValueRegisterField)fieldInst, register.Offset, (int)field.Low, field.Mode);
274                         TestFieldReset((IValueRegisterField)fieldInst, (int)field.Low, register.ResetValue);
275                     }
276                     else if(fieldInst.GetType() == this.FlagRegisterField)
277                     {
278                         TestFieldMode((IFlagRegisterField)fieldInst, register.Offset, (int)field.Low, field.Mode);
279                         TestFieldReset((IFlagRegisterField)fieldInst, (int)field.Low, register.ResetValue);
280                     }
281                     else
282                     {
283                         Assert.Fail("Unhandled underlying field type: " + fieldInst.GetType());
284                     }
285                 }
286             }
287         }
288 
TestPattern(uint width = sizeof(ulong) * 8)289         static private IEnumerable<ulong> TestPattern(uint width = sizeof(ulong) * 8)
290         {
291             yield return 0;
292             for(int i = 0; i < width; ++i)
293             {
294                 yield return 1UL << i;
295             }
296         }
297 
TestPatternMask(uint width = sizeof(ulong) * 8)298         static private IEnumerable<ulong> TestPatternMask(uint width = sizeof(ulong) * 8)
299         {
300             ulong l = 0;
301             for(int i = 0; i < width; i += 2)
302             {
303                 l |= 1UL << i;
304             }
305             yield return l;
306             yield return l << 1;
307         }
308 
TestFieldModeRead(IRegisterField<ulong> field, ulong offset, int low)309         private void TestFieldModeRead(IRegisterField<ulong> field, ulong offset, int low)
310         {
311             foreach(var pat in TestPattern((uint)field.Width))
312             {
313                 ReportPattern(pat);
314 
315                 field.Value = pat;
316                 var read = peripheral.ReadDoubleWord((long)offset);
317                 Assert.AreEqual(pat, BitHelper.GetMaskedValue(read, low, field.Width) >> low);
318                 read = peripheral.ReadDoubleWord((long)offset); // Another check to ensure that the value was not modified by the read.
319                 Assert.AreEqual(pat, BitHelper.GetMaskedValue(read, low, field.Width) >> low);
320             }
321         }
322 
TestFieldModeRead(IRegisterField<bool> field, ulong offset, int low)323         private void TestFieldModeRead(IRegisterField<bool> field, ulong offset, int low)
324         {
325             field.Value = false;
326             var read = peripheral.ReadDoubleWord((long)offset);
327             Assert.AreEqual(0, BitHelper.GetMaskedValue(read, low, field.Width));
328             read = peripheral.ReadDoubleWord((long)offset);
329             Assert.AreEqual(0, BitHelper.GetMaskedValue(read, low, field.Width));
330 
331             field.Value = true;
332             read = peripheral.ReadDoubleWord((long)offset);
333             Assert.AreEqual(1, BitHelper.GetMaskedValue(read, low, field.Width) >> low);
334             read = peripheral.ReadDoubleWord((long)offset);
335             Assert.AreEqual(1, BitHelper.GetMaskedValue(read, low, field.Width) >> low);
336         }
337 
TestFieldModeReadToClear(IRegisterField<ulong> field, ulong offset)338         private void TestFieldModeReadToClear(IRegisterField<ulong> field, ulong offset)
339         {
340             field.Value = BitHelper.GetMaskedValue(~0UL, 0, field.Width) ;
341             peripheral.ReadDoubleWord((long)offset);
342             Assert.AreEqual(0, field.Value);
343         }
344 
TestFieldModeReadToClear(IRegisterField<bool> field, ulong offset)345         private void TestFieldModeReadToClear(IRegisterField<bool> field, ulong offset)
346         {
347             field.Value = false;
348             peripheral.ReadDoubleWord((long)offset);
349             Assert.AreEqual(false, field.Value);
350 
351             field.Value = true;
352             peripheral.ReadDoubleWord((long)offset);
353             Assert.AreEqual(false, field.Value);
354         }
355 
TestFieldModeReadToSet(IRegisterField<ulong> field, ulong offset)356         private void TestFieldModeReadToSet(IRegisterField<ulong> field, ulong offset)
357         {
358             field.Value = 0UL;
359             peripheral.ReadDoubleWord((long)offset);
360             Assert.AreEqual(~0UL, field.Value);
361         }
362 
TestFieldModeReadToSet(IRegisterField<bool> field, ulong offset)363         private void TestFieldModeReadToSet(IRegisterField<bool> field, ulong offset)
364         {
365             field.Value = false;
366             peripheral.ReadDoubleWord((long)offset);
367             Assert.AreEqual(true, field.Value);
368 
369             field.Value = true;
370             peripheral.ReadDoubleWord((long)offset);
371             Assert.AreEqual(true, field.Value);
372         }
373 
TestFieldModeWrite(IRegisterField<ulong> field, ulong offset, int low, bool negate = false)374         private void TestFieldModeWrite(IRegisterField<ulong> field, ulong offset, int low, bool negate = false)
375         {
376             foreach(var pat in TestPattern((uint)field.Width))
377             {
378                 ReportPattern(pat);
379 
380                 var v = (negate ? ~(uint)pat : (uint)pat) << low;
381                 peripheral.WriteDoubleWord((long)offset, v);
382                 Assert.AreEqual(pat, field.Value);
383                 peripheral.WriteDoubleWord((long)offset, v);
384                 Assert.AreEqual(pat, field.Value);
385             }
386         }
387 
TestFieldModeWrite(IRegisterField<bool> field, ulong offset, int low, bool negate = false)388         private void TestFieldModeWrite(IRegisterField<bool> field, ulong offset, int low, bool negate = false)
389         {
390             field.Value = false;
391             peripheral.WriteDoubleWord((long)offset, negate ? (1U << low) : 0U);
392             Assert.AreEqual(false, field.Value);
393 
394             peripheral.WriteDoubleWord((long)offset, negate ? 0 : (1U << low));
395             Assert.AreEqual(true, field.Value);
396             peripheral.WriteDoubleWord((long)offset, negate ? 0 : (1U << low));
397             Assert.AreEqual(true, field.Value);
398         }
399 
TestFieldModeSet(IRegisterField<ulong> field, ulong offset, int low, bool negate = false)400         private void TestFieldModeSet(IRegisterField<ulong> field, ulong offset, int low, bool negate = false)
401         {
402             foreach(var mask in TestPatternMask((uint)field.Width))
403             {
404                 foreach(var pat in TestPattern((uint)field.Width))
405                 {
406                     ReportMaskAndPattern(mask, pat);
407 
408                     var v = (negate ? ~(uint)pat : (uint)pat) << low;
409                     field.Value = mask;
410                     peripheral.WriteDoubleWord((long)offset, v);
411                     Assert.AreEqual(mask | pat, field.Value);
412                     peripheral.WriteDoubleWord((long)offset, v);
413                     Assert.AreEqual(mask | pat, field.Value);
414                     peripheral.WriteDoubleWord((long)offset, 0U);
415                     Assert.AreEqual(mask | pat, field.Value);
416                 }
417             }
418         }
419 
TestFieldModeSet(IRegisterField<bool> field, ulong offset, int low, bool negate = false)420         private void TestFieldModeSet(IRegisterField<bool> field, ulong offset, int low, bool negate = false)
421         {
422             field.Value = false;
423             peripheral.WriteDoubleWord((long)offset, negate ? (1U << low) : 0U);
424             Assert.AreEqual(false, field.Value);
425 
426             peripheral.WriteDoubleWord((long)offset, negate ? 0 : (1U << low));
427             Assert.AreEqual(true, field.Value);
428             peripheral.WriteDoubleWord((long)offset, negate ? 0 : (1U << low));
429             Assert.AreEqual(true, field.Value);
430             peripheral.WriteDoubleWord((long)offset, negate ? (1U << low) : 0);
431             Assert.AreEqual(true, field.Value);
432         }
433 
TestFieldModeToggle(IRegisterField<ulong> field, ulong offset, int low, bool negate = false)434         private void TestFieldModeToggle(IRegisterField<ulong> field, ulong offset, int low, bool negate = false)
435         {
436             foreach(var mask in TestPatternMask((uint)field.Width))
437             {
438                 field.Value = mask;
439                 foreach(var pat in TestPattern((uint)field.Width))
440                 {
441                     ReportMaskAndPattern(mask, pat);
442 
443                     var v = (negate ? ~(uint)pat : (uint)pat) << low;
444                     peripheral.WriteDoubleWord((long)offset, v);
445                     Assert.AreEqual((mask | pat) & ~(mask & pat), field.Value);
446                     peripheral.WriteDoubleWord((long)offset, v);
447                     Assert.AreEqual(mask, field.Value);
448                 }
449             }
450         }
451 
TestFieldModeToggle(IRegisterField<bool> field, ulong offset, int low, bool negate = false)452         private void TestFieldModeToggle(IRegisterField<bool> field, ulong offset, int low, bool negate = false)
453         {
454             field.Value = false;
455             peripheral.WriteDoubleWord((long)offset, negate ? (1U << low) : 0U);
456             Assert.AreEqual(false, field.Value);
457 
458             peripheral.WriteDoubleWord((long)offset, negate ? 0 : (1U << low));
459             Assert.AreEqual(true, field.Value);
460             peripheral.WriteDoubleWord((long)offset, negate ? (1U << low) : 0U);
461             Assert.AreEqual(true, field.Value);
462 
463             peripheral.WriteDoubleWord((long)offset, negate ? 0 : (1U << low));
464             Assert.AreEqual(false, field.Value);
465         }
466 
TestFieldModeWriteOneToClear(IRegisterField<ulong> field, ulong offset, int low, bool negate = false)467         private void TestFieldModeWriteOneToClear(IRegisterField<ulong> field, ulong offset, int low, bool negate = false)
468         {
469             foreach(var mask in TestPatternMask((uint)field.Width))
470             {
471                 foreach(var pat in TestPattern((uint)field.Width))
472                 {
473                     ReportMaskAndPattern(mask, pat);
474 
475                     var v = (negate ? ~(uint)pat : (uint)pat) << low;
476                     field.Value = mask;
477                     peripheral.WriteDoubleWord((long)offset, v);
478                     Assert.AreEqual(mask & ~pat, field.Value);
479                 }
480 
481             }
482         }
483 
TestFieldModeWriteOneToClear(IRegisterField<bool> field, ulong offset, int low, bool negate = false)484         private void TestFieldModeWriteOneToClear(IRegisterField<bool> field, ulong offset, int low, bool negate = false)
485         {
486             field.Value = true;
487             peripheral.WriteDoubleWord((long)offset, negate ? (1U << low) : 0U);
488             Assert.AreEqual(true, field.Value);
489 
490             peripheral.WriteDoubleWord((long)offset, negate ? 0U : (1U << low));
491             Assert.AreEqual(false, field.Value);
492 
493             peripheral.WriteDoubleWord((long)offset, negate ? 0U : (1U << low));
494             Assert.AreEqual(false, field.Value);
495         }
496 
ReportPattern(ulong pat)497         private static void ReportPattern(ulong pat)
498         {
499             Console.WriteLine("  - Test pattern: " + FormatBits(pat));
500         }
501 
ReportMaskAndPattern(ulong mask, ulong pat)502         private static void ReportMaskAndPattern(ulong mask, ulong pat)
503         {
504             Console.WriteLine("  - Test Mask:    " + FormatBits(mask));
505             Console.WriteLine("    Test pattern: " + FormatBits(pat));
506         }
507 
TestFieldMode(IRegisterField<ulong> field, ulong offset, int low, FieldMode mode)508         private void TestFieldMode(IRegisterField<ulong> field, ulong offset, int low, FieldMode mode)
509         {
510             if(FieldModeHelper.ReadBits(mode) != 0)
511             {
512                 Console.WriteLine("  Performing read test...");
513             }
514             switch(FieldModeHelper.ReadBits(mode))
515             {
516                 case FieldMode.Read: TestFieldModeRead(field, offset, low); break;
517                 case FieldMode.ReadToClear: TestFieldModeReadToClear(field, offset); break;
518                 case FieldMode.ReadToSet: TestFieldModeReadToSet(field, offset); break;
519             }
520 
521             if(FieldModeHelper.WriteBits(mode) != 0)
522             {
523                 Console.WriteLine("  Performing write test...");
524             }
525             switch(FieldModeHelper.WriteBits(mode))
526             {
527                 case FieldMode.Write: TestFieldModeWrite(field, offset, low); break;
528                 case FieldMode.Set: TestFieldModeSet(field, offset, low); break;
529                 case FieldMode.Toggle: TestFieldModeToggle(field, offset, low); break;
530                 case FieldMode.WriteOneToClear: TestFieldModeWriteOneToClear(field, offset, low); break;
531                 case FieldMode.WriteZeroToClear: TestFieldModeWriteOneToClear(field, offset, low, negate: true); break;
532                 case FieldMode.WriteZeroToSet: TestFieldModeSet(field, offset, low, negate: true); break;
533                 case FieldMode.WriteZeroToToggle: TestFieldModeToggle(field, offset, low, negate: true); break;
534             }
535         }
536 
TestFieldMode(IRegisterField<bool> field, ulong offset, int low, FieldMode mode)537         private void TestFieldMode(IRegisterField<bool> field, ulong offset, int low, FieldMode mode)
538         {
539             if(FieldModeHelper.ReadBits(mode) != 0)
540             {
541                 Console.WriteLine("  Performing read test...");
542             }
543             switch(FieldModeHelper.ReadBits(mode))
544             {
545                 case FieldMode.Read: TestFieldModeRead(field, offset, low); break;
546                 case FieldMode.ReadToClear: TestFieldModeReadToClear(field, offset); break;
547                 case FieldMode.ReadToSet: TestFieldModeReadToSet(field, offset); break;
548             }
549 
550             if(FieldModeHelper.WriteBits(mode) != 0)
551             {
552                 Console.WriteLine("  Performing write test...");
553             }
554             switch(FieldModeHelper.WriteBits(mode))
555             {
556                 case FieldMode.Write: TestFieldModeWrite(field, offset, low); break;
557                 case FieldMode.Set: TestFieldModeSet(field, offset, low); break;
558                 case FieldMode.Toggle: TestFieldModeToggle(field, offset, low); break;
559                 case FieldMode.WriteOneToClear: TestFieldModeWriteOneToClear(field, offset, low); break;
560                 case FieldMode.WriteZeroToClear: TestFieldModeWriteOneToClear(field, offset, low, negate: true); break;
561                 case FieldMode.WriteZeroToSet: TestFieldModeSet(field, offset, low, negate: true); break;
562                 case FieldMode.WriteZeroToToggle: TestFieldModeToggle(field, offset, low, negate: true); break;
563             }
564         }
565 
TestFieldReset(IRegisterField<ulong> field, int low, ulong registerResetValue)566         void TestFieldReset(IRegisterField<ulong> field, int low, ulong registerResetValue)
567         {
568             var expect = registerResetValue >> low;
569             field.Value = BitHelper.GetMaskedValue(~expect, 0, field.Width);
570 
571             var registers = (peripheral as IProvidesRegisterCollection<DoubleWordRegisterCollection>).RegistersCollection;
572             registers.Reset();
573 
574             Assert.AreEqual(field.Value, expect);
575         }
576 
TestFieldReset(IRegisterField<bool> field, int low, ulong registerResetValue)577         void TestFieldReset(IRegisterField<bool> field, int low, ulong registerResetValue)
578         {
579             var expect = BitHelper.GetMaskedValue(registerResetValue >> low, 0, 1) == 1;
580             field.Value = !expect;
581 
582             var registers = (peripheral as IProvidesRegisterCollection<DoubleWordRegisterCollection>).RegistersCollection;
583             registers.Reset();
584 
585             Assert.AreEqual(field.Value, expect);
586         }
587 
588         // Older .NET versions do not support "b" format specifier
FormatBits(ulong value)589         static string FormatBits(ulong value)
590         {
591             string res = "";
592             foreach(var bit in BitHelper.GetBits(value).Reverse())
593             {
594                 res += bit ? '1' : '0';
595             }
596             return res;
597         }
598 
599         private IDoubleWordPeripheral peripheral;
600         private Type pType;
601 
602         private Type ValueRegisterField;
603         private Type FlagRegisterField;
604         private Type RegisterField;
605 
606         private const string SystemRDLResource = "Antmicro.Renode.PeripheralsTests.SystemRDLJson";
607     }
608 }
609