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; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Peripherals; 12 using Antmicro.Renode.Peripherals.Bus; 13 using Antmicro.Renode.Peripherals.CPU; 14 using Antmicro.Renode.Utilities; 15 using NUnit.Framework; 16 using Moq; 17 using System.Linq; 18 using System.Collections.Generic; 19 using Antmicro.Renode.Peripherals.Memory; 20 using Antmicro.Renode.Core.Structure.Registers; 21 using Antmicro.Renode.Peripherals.Mocks; 22 23 namespace Antmicro.Renode.UnitTests 24 { 25 [TestFixture] 26 public class SystemBusTests 27 { 28 [SetUp] SetUp()29 public void SetUp() 30 { 31 var machine = new Machine(); 32 EmulationManager.Instance.CurrentEmulation.AddMachine(machine); 33 sysbus = machine.SystemBus; 34 bytes = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }; 35 } 36 37 [Test] ShouldReturnZeroAtNonExistingDevice()38 public void ShouldReturnZeroAtNonExistingDevice() 39 { 40 var read = sysbus.ReadByte(0xABCD1234); 41 Assert.AreEqual(0, read); 42 } 43 44 [Test] ShouldFindAfterRegistration()45 public void ShouldFindAfterRegistration() 46 { 47 var peripheral = new Mock<IDoubleWordPeripheral>(); 48 peripheral.Setup(x => x.ReadDoubleWord(0)).Returns(0x666); 49 sysbus.Register(peripheral.Object, 1000.By(1000)); 50 Assert.AreEqual(0x666, sysbus.ReadDoubleWord(1000)); 51 } 52 53 [Test] ShouldFindAfterManyRegistrations()54 public void ShouldFindAfterManyRegistrations() 55 { 56 var peri1 = new Mock<IDoubleWordPeripheral>(); 57 var peri2 = new Mock<IDoubleWordPeripheral>(); 58 var peri3 = new Mock<IDoubleWordPeripheral>(); 59 peri1.Setup(x => x.ReadDoubleWord(0)).Returns(0x666); 60 peri2.Setup(x => x.ReadDoubleWord(0)).Returns(0x667); 61 peri3.Setup(x => x.ReadDoubleWord(0)).Returns(0x668); 62 sysbus.Register(peri1.Object, 1000.By(100)); 63 sysbus.Register(peri2.Object, 2000.By(100)); 64 sysbus.Register(peri3.Object, 3000.By(100)); 65 Assert.AreEqual(0x666, sysbus.ReadDoubleWord(1000)); 66 Assert.AreEqual(0x667, sysbus.ReadDoubleWord(2000)); 67 Assert.AreEqual(0x668, sysbus.ReadDoubleWord(3000)); 68 } 69 70 [Test, Ignore("Ignored")] ShouldFindAfterManyRegistrationsAndRemoves()71 public void ShouldFindAfterManyRegistrationsAndRemoves() 72 { 73 const int NumberOfPeripherals = 100; 74 var MaximumPeripheralSize = 16.KB(); 75 76 var regPoints = new ulong[NumberOfPeripherals]; 77 var unregisteredPoints = new HashSet<ulong>(); 78 var random = EmulationManager.Instance.CurrentEmulation.RandomGenerator; 79 var lastPoint = 4u; 80 for(var i = 0; i < NumberOfPeripherals; i++) 81 { 82 // gap 83 lastPoint += (uint)random.Next(MaximumPeripheralSize); 84 var size = (uint)random.Next(1, MaximumPeripheralSize + 1); 85 regPoints[i] = lastPoint; 86 var mock = new Mock<IDoubleWordPeripheral>(); 87 mock.Setup(x => x.ReadDoubleWord(0)).Returns((uint)regPoints[i]); 88 sysbus.Register(mock.Object, lastPoint.By(size)); 89 // peripheral 90 lastPoint += size; 91 } 92 93 // now remove random devices 94 for(var i = 0; i < NumberOfPeripherals; i++) 95 { 96 if(random.Next(100) < 10) 97 { 98 sysbus.UnregisterFromAddress(regPoints[i], context: null); 99 unregisteredPoints.Add(regPoints[i]); 100 } 101 } 102 103 // finally some assertions 104 for(var i = 0; i < NumberOfPeripherals; i++) 105 { 106 var value = sysbus.ReadDoubleWord(regPoints[i]); 107 if(unregisteredPoints.Contains(regPoints[i])) 108 { 109 Assert.AreEqual(0, value); 110 } 111 else 112 { 113 Assert.AreEqual(regPoints[i], value); 114 } 115 } 116 } 117 118 [Test] ShouldPauseAndResumeOnlyOnce()119 public void ShouldPauseAndResumeOnlyOnce() 120 { 121 using(var emulation = new Emulation()) 122 using(var machine = new Machine()) 123 { 124 emulation.AddMachine(machine); 125 var sb = machine.SystemBus; 126 var mock = new Mock<IHasOwnLife>(); 127 sb.Register(mock.As<IDoubleWordPeripheral>().Object, 0.To(100)); 128 129 var cpuMock = new Mock<ICPU>(); 130 cpuMock.Setup(cpu => cpu.Architecture).Returns("mock"); // Required by InitializeInvalidatedAddressesList. 131 sb.Register(cpuMock.Object, new CPURegistrationPoint()); 132 133 machine.Start(); 134 PauseResumeRetries.Times(machine.Pause); 135 mock.Verify(x => x.Pause(), Times.Once()); 136 PauseResumeRetries.Times(machine.Start); 137 mock.Verify(x => x.Resume(), Times.Once()); 138 } 139 } 140 141 [Test] ShouldRegisterMultiFunctionPeripheral()142 public void ShouldRegisterMultiFunctionPeripheral() 143 { 144 var multiRegistration1 = new BusMultiRegistration(0, 100, "region1"); 145 var multiRegistration2 = new BusMultiRegistration(100, 200, "region2"); 146 var peripheral = new MultiRegistrationPeripheral(); 147 sysbus.Register(peripheral, multiRegistration1); 148 sysbus.Register(peripheral, multiRegistration2); 149 sysbus.Register(peripheral, new BusRangeRegistration(300, 100)); 150 151 Assert.AreEqual(false, peripheral.ByteRead1); 152 Assert.AreEqual(false, peripheral.ByteRead2); 153 Assert.AreEqual(false, peripheral.ByteWritten1); 154 Assert.AreEqual(false, peripheral.ByteWritten2); 155 Assert.AreEqual(false, peripheral.DoubleWordRead); 156 Assert.AreEqual(false, peripheral.DoubleWordWritten); 157 158 sysbus.ReadByte(10); 159 160 Assert.AreEqual(true, peripheral.ByteRead1); 161 Assert.AreEqual(false, peripheral.ByteRead2); 162 Assert.AreEqual(false, peripheral.ByteWritten1); 163 Assert.AreEqual(false, peripheral.ByteWritten2); 164 Assert.AreEqual(false, peripheral.DoubleWordRead); 165 Assert.AreEqual(false, peripheral.DoubleWordWritten); 166 167 sysbus.ReadByte(110); 168 169 Assert.AreEqual(true, peripheral.ByteRead1); 170 Assert.AreEqual(true, peripheral.ByteRead2); 171 Assert.AreEqual(false, peripheral.ByteWritten1); 172 Assert.AreEqual(false, peripheral.ByteWritten2); 173 Assert.AreEqual(false, peripheral.DoubleWordRead); 174 Assert.AreEqual(false, peripheral.DoubleWordWritten); 175 176 sysbus.WriteByte(10, 0); 177 178 Assert.AreEqual(true, peripheral.ByteRead1); 179 Assert.AreEqual(true, peripheral.ByteRead2); 180 Assert.AreEqual(true, peripheral.ByteWritten1); 181 Assert.AreEqual(false, peripheral.ByteWritten2); 182 Assert.AreEqual(false, peripheral.DoubleWordRead); 183 Assert.AreEqual(false, peripheral.DoubleWordWritten); 184 185 sysbus.WriteByte(110, 0); 186 187 Assert.AreEqual(true, peripheral.ByteRead1); 188 Assert.AreEqual(true, peripheral.ByteRead2); 189 Assert.AreEqual(true, peripheral.ByteWritten1); 190 Assert.AreEqual(true, peripheral.ByteWritten2); 191 Assert.AreEqual(false, peripheral.DoubleWordRead); 192 Assert.AreEqual(false, peripheral.DoubleWordWritten); 193 194 sysbus.ReadDoubleWord(310); 195 196 Assert.AreEqual(true, peripheral.ByteRead1); 197 Assert.AreEqual(true, peripheral.ByteRead2); 198 Assert.AreEqual(true, peripheral.ByteWritten1); 199 Assert.AreEqual(true, peripheral.ByteWritten2); 200 Assert.AreEqual(true, peripheral.DoubleWordRead); 201 Assert.AreEqual(false, peripheral.DoubleWordWritten); 202 203 sysbus.WriteDoubleWord(310, 0); 204 205 Assert.AreEqual(true, peripheral.ByteRead1); 206 Assert.AreEqual(true, peripheral.ByteRead2); 207 Assert.AreEqual(true, peripheral.ByteWritten1); 208 Assert.AreEqual(true, peripheral.ByteWritten2); 209 Assert.AreEqual(true, peripheral.DoubleWordRead); 210 Assert.AreEqual(true, peripheral.DoubleWordWritten); 211 } 212 213 [Test] ShouldRegisterParametrizedPeripheral()214 public void ShouldRegisterParametrizedPeripheral() 215 { 216 var parametrizedRegistration = new ParametrizedRegistrationPeripheral.Registration(0, 100); 217 var peripheral = new ParametrizedRegistrationPeripheral(); 218 sysbus.Register(peripheral, parametrizedRegistration); 219 sysbus.Register(peripheral, new BusRangeRegistration(200, 100)); 220 221 Assert.AreEqual(false, peripheral.ByteRead); 222 Assert.AreEqual(false, peripheral.ByteWritten); 223 Assert.AreEqual(false, peripheral.DoubleWordRead); 224 Assert.AreEqual(false, peripheral.DoubleWordWritten); 225 226 sysbus.ReadByte(10); 227 228 Assert.AreEqual(true, peripheral.ByteRead); 229 Assert.AreEqual(false, peripheral.ByteWritten); 230 Assert.AreEqual(false, peripheral.DoubleWordRead); 231 Assert.AreEqual(false, peripheral.DoubleWordWritten); 232 233 sysbus.WriteByte(10, 0); 234 235 Assert.AreEqual(true, peripheral.ByteRead); 236 Assert.AreEqual(true, peripheral.ByteWritten); 237 Assert.AreEqual(false, peripheral.DoubleWordRead); 238 Assert.AreEqual(false, peripheral.DoubleWordWritten); 239 240 sysbus.ReadDoubleWord(10); 241 242 Assert.AreEqual(true, peripheral.ByteRead); 243 Assert.AreEqual(true, peripheral.ByteWritten); 244 Assert.AreEqual(true, peripheral.DoubleWordRead); 245 Assert.AreEqual(false, peripheral.DoubleWordWritten); 246 247 sysbus.WriteDoubleWord(10, 0); 248 249 Assert.AreEqual(true, peripheral.ByteRead); 250 Assert.AreEqual(true, peripheral.ByteWritten); 251 Assert.AreEqual(true, peripheral.DoubleWordRead); 252 Assert.AreEqual(true, peripheral.DoubleWordWritten); 253 } 254 255 [Test] ShouldTestEnableAllTranslations()256 public void ShouldTestEnableAllTranslations() 257 { 258 var testData = new Tuple<int, IBusPeripheral> [] 259 { 260 Tuple.Create(64, (IBusPeripheral)new MockQuadWordPeripheralWithoutTranslations()), 261 Tuple.Create(32, (IBusPeripheral)new MockDoubleWordPeripheralWithoutTranslations()), 262 Tuple.Create(16, (IBusPeripheral)new MockWordPeripheralWithoutTranslations()), 263 Tuple.Create(8, (IBusPeripheral)new MockBytePeripheralWithoutTranslations()) 264 }; 265 266 ulong address = 0; 267 foreach(var data in testData) 268 { 269 var implementedWidth = data.Item1; 270 var peripheral = data.Item2; 271 sysbus.Register(peripheral, new BusRangeRegistration(address, 8)); 272 sysbus.Register(peripheral, new BusMultiRegistration(address + 8, 8, "region")); 273 address += 16; 274 } 275 276 var testValue = 0xdeadc0de12345678; 277 for(var i = 0; i < testData.Length; i += 1) 278 { 279 var implementedWidth = testData[i].Item1; 280 testAllTranslatedAccesses((ulong)i * 16, testValue, implementedWidth); 281 testAllTranslatedAccesses((ulong)i * 16 + 8, testValue, implementedWidth); 282 } 283 } 284 285 [Test] ShouldHandleWriteToMemorySegment()286 public void ShouldHandleWriteToMemorySegment() 287 { 288 CreateMachineAndExecute(sysbus => 289 { 290 // bytes fit into memory segment 291 sysbus.WriteBytes(bytes, 4); 292 Assert.AreEqual(bytes, sysbus.ReadBytes(4, 8)); 293 }); 294 } 295 296 [Test] ShouldHandlePartialWriteToMemorySegmentAtTheBeginning()297 public void ShouldHandlePartialWriteToMemorySegmentAtTheBeginning() 298 { 299 CreateMachineAndExecute(sysbus => 300 { 301 // beginning of bytes fits into memory segment 302 sysbus.WriteBytes(bytes, 10); 303 Assert.AreEqual(bytes.Take(6).Concat(Enumerable.Repeat((byte)0, 2)).ToArray(), sysbus.ReadBytes(10, 8)); 304 }); 305 } 306 307 [Test] ShouldReadBytes([Values(true, false)] bool isFirstMemory, [Values(true, false)] bool isSecondMemory)308 public void ShouldReadBytes([Values(true, false)] bool isFirstMemory, [Values(true, false)] bool isSecondMemory) 309 { 310 var peri1Values = new Dictionary<long, byte>(); 311 var peri2Values = new Dictionary<long, byte>(); 312 var machine = new Machine(); 313 if(isFirstMemory) 314 { 315 machine.SystemBus.Register(new MappedMemory(machine, 100), new BusPointRegistration(50)); 316 } 317 else 318 { 319 var mock = new Mock<IBytePeripheral>(); 320 mock.Setup(x => x.WriteByte(It.IsAny<long>(), It.IsAny<byte>())).Callback<long, byte>((x, y) => peri1Values.Add(x, y)); 321 mock.Setup(x => x.ReadByte(It.IsAny<long>())).Returns<long>(x => peri1Values[x]); 322 machine.SystemBus.Register(mock.Object, new BusRangeRegistration(50, 100)); 323 } 324 325 if(isSecondMemory) 326 { 327 machine.SystemBus.Register(new MappedMemory(machine, 100), new BusPointRegistration(200)); 328 } 329 else 330 { 331 var mock = new Mock<IBytePeripheral>(); 332 mock.Setup(x => x.WriteByte(It.IsAny<long>(), It.IsAny<byte>())).Callback<long, byte>((x, y) => peri2Values.Add(x, y)); 333 mock.Setup(x => x.ReadByte(It.IsAny<long>())).Returns<long>(x => peri2Values[x]); 334 machine.SystemBus.Register(mock.Object, new BusRangeRegistration(200, 100)); 335 } 336 var testArray = Enumerable.Range(0, 350).Select(x => (byte)(x % byte.MaxValue)).ToArray(); 337 machine.SystemBus.WriteBytes(testArray, 0); 338 var resultArray = machine.SystemBus.ReadBytes(0, 350); 339 int i = 0; 340 for(; i < 50; ++i) 341 { 342 Assert.AreEqual(0, resultArray[i]); 343 } 344 for(; i < 150; ++i) 345 { 346 Assert.AreEqual(testArray[i], resultArray[i]); 347 } 348 for(; i < 200; ++i) 349 { 350 Assert.AreEqual(0, resultArray[i]); 351 } 352 for(; i < 300; ++i) 353 { 354 Assert.AreEqual(testArray[i], resultArray[i]); 355 } 356 for(; i < 350; ++i) 357 { 358 Assert.AreEqual(0, resultArray[i]); 359 } 360 } 361 362 [Test] ShouldHandlePartialWriteToMemorySegmentAtTheEnd()363 public void ShouldHandlePartialWriteToMemorySegmentAtTheEnd() 364 { 365 CreateMachineAndExecute(sysbus => 366 { 367 // beginning of bytes fits into memory segment 368 sysbus.WriteBytes(bytes, 0xC0000000 - 4); 369 Assert.AreEqual(Enumerable.Repeat((byte)0, 4).Concat(bytes.Skip(4).Take(4)).ToArray(), sysbus.ReadBytes(0xC0000000 - 4, 8)); 370 }); 371 } 372 373 [Test] ShouldHandleWriteToAHoleBetweenMemorySegments()374 public void ShouldHandleWriteToAHoleBetweenMemorySegments() 375 { 376 CreateMachineAndExecute(sb => 377 { 378 // bytes do not fit into memory segment 379 sb.WriteBytes(bytes, 100); 380 Assert.AreEqual(Enumerable.Repeat((byte)0, 8).ToArray(), sb.ReadBytes(100, 8)); 381 }); 382 } 383 384 [Test] ShouldHandleWriteOverlappingMemorySegment()385 public void ShouldHandleWriteOverlappingMemorySegment() 386 { 387 CreateMachineAndExecute(sysbus => 388 { 389 // bytes overlap memory segment 390 var hugeBytes = Enumerable.Range(0, 32).Select(i => (byte)i).ToArray(); 391 sysbus.WriteBytes(hugeBytes, 0xC0000000 - 4); 392 Assert.AreEqual(Enumerable.Repeat((byte)0, 4).Concat(hugeBytes.Skip(4).Take(16)).Concat(Enumerable.Repeat((byte)0, 12)).ToArray(), sysbus.ReadBytes(0xC0000000 - 4, 32)); 393 }); 394 } 395 CreateMachineAndExecute(Action<IBusController> action)396 private void CreateMachineAndExecute(Action<IBusController> action) 397 { 398 using(var machine = new Machine()) 399 { 400 var sb = machine.SystemBus; 401 var memory = new MappedMemory(machine, 16); 402 sb.Register(memory, 0.By(16)); 403 sb.Register(memory, 0xC0000000.By(16)); 404 405 action(sb); 406 } 407 } 408 testAllTranslatedAccesses(ulong address, ulong testValue, int implementedWidth)409 private void testAllTranslatedAccesses(ulong address, ulong testValue, int implementedWidth) 410 { 411 var widths = new int [] { 8, 16, 32, 64 }; 412 var types = new dynamic [] 413 { 414 (Func<ulong, byte>)Convert.ToByte, 415 (Func<ulong, ushort>)Convert.ToUInt16, 416 (Func<ulong, uint>)Convert.ToUInt32, 417 (Func<ulong, ulong>)Convert.ToUInt64, 418 }; 419 420 var accessMethods = new dynamic [] 421 { 422 Tuple.Create((Func<ulong, IPeripheral, ulong?, byte>)sysbus.ReadByte, (Action<ulong, byte, IPeripheral, ulong?>)sysbus.WriteByte), 423 Tuple.Create((Func<ulong, IPeripheral, ulong?, ushort>)sysbus.ReadWord, (Action<ulong, ushort, IPeripheral, ulong?>)sysbus.WriteWord), 424 Tuple.Create((Func<ulong, IPeripheral, ulong?, uint>)sysbus.ReadDoubleWord, (Action<ulong, uint, IPeripheral, ulong?>)sysbus.WriteDoubleWord), 425 Tuple.Create((Func<ulong, IPeripheral, ulong?, ulong>)sysbus.ReadQuadWord, (Action<ulong, ulong, IPeripheral, ulong?>)sysbus.WriteQuadWord), 426 }; 427 428 for(var i = 0; i < accessMethods.Length; i++) 429 { 430 var width = widths[i]; 431 var type = types[i]; 432 var read = accessMethods[i].Item1; 433 var write = accessMethods[i].Item2; 434 435 if(width == implementedWidth) 436 continue; 437 438 sysbus.EnableAllTranslations(); 439 440 for(var offset = 0; offset < 64; offset += width) 441 { 442 var value = type(BitHelper.GetValue(testValue, offset, width)); 443 write(address + (ulong)offset / 8, value, null, null); 444 Assert.AreEqual(value, read(address + (ulong)offset / 8, null, null)); 445 } 446 447 sysbus.EnableAllTranslations(false); 448 449 for(var offset = 0; offset < 64; offset += width) 450 { 451 Assert.AreEqual(0x0, read(address + (ulong)offset / 8, null, null)); 452 } 453 454 sysbus.EnableAllTranslations(); 455 sysbus.WriteQuadWord(address, 0x0); 456 Assert.AreEqual(0x0, sysbus.ReadQuadWord(address)); 457 } 458 } 459 460 private IBusController sysbus; 461 private byte[] bytes; 462 private const int PauseResumeRetries = 5; 463 464 private class MultiRegistrationPeripheral : IBusPeripheral, IDoubleWordPeripheral 465 { Reset()466 public void Reset() 467 { 468 throw new NotImplementedException(); 469 } 470 471 public bool ByteRead1 { get; private set; } 472 473 public bool ByteRead2 { get; private set; } 474 475 public bool ByteWritten1 { get; private set; } 476 477 public bool ByteWritten2 { get; private set; } 478 479 public bool DoubleWordRead { get; private set; } 480 481 public bool DoubleWordWritten { get; private set; } 482 ReadDoubleWord(long offset)483 public uint ReadDoubleWord(long offset) 484 { 485 DoubleWordRead = true; 486 return 0; 487 } 488 WriteDoubleWord(long offset, uint value)489 public void WriteDoubleWord(long offset, uint value) 490 { 491 DoubleWordWritten = true; 492 } 493 494 [ConnectionRegion("region1")] ReadByte1(long offset)495 public byte ReadByte1(long offset) 496 { 497 ByteRead1 = true; 498 return 0; 499 } 500 501 [ConnectionRegion("region2")] ReadByte2(long offset)502 public byte ReadByte2(long offset) 503 { 504 ByteRead2 = true; 505 return 0; 506 } 507 508 [ConnectionRegion("region1")] WriteByte1(long offset, byte value)509 public void WriteByte1(long offset, byte value) 510 { 511 ByteWritten1 = true; 512 } 513 514 [ConnectionRegion("region2")] WriteByte2(long offset, byte value)515 public void WriteByte2(long offset, byte value) 516 { 517 ByteWritten2 = true; 518 } 519 } 520 521 private class ParametrizedRegistrationPeripheral : IBusPeripheral, IDoubleWordPeripheral 522 { Reset()523 public void Reset() 524 { 525 throw new NotImplementedException(); 526 } 527 528 public bool ByteRead { get; private set; } 529 530 public bool ByteWritten { get; private set; } 531 532 public bool DoubleWordRead { get; private set; } 533 534 public bool DoubleWordWritten { get; private set; } 535 ReadDoubleWord(long offset)536 public uint ReadDoubleWord(long offset) 537 { 538 DoubleWordRead = true; 539 return 0; 540 } 541 WriteDoubleWord(long offset, uint value)542 public void WriteDoubleWord(long offset, uint value) 543 { 544 DoubleWordWritten = true; 545 } 546 547 public class Registration : BusParametrizedRegistration 548 { Registration(ulong address, ulong size)549 public Registration(ulong address, ulong size) : base(address, size, null) 550 { 551 } 552 GetReadByteMethod(IBusPeripheral peripheral)553 public override Func<long, byte> GetReadByteMethod(IBusPeripheral peripheral) 554 { 555 var parent = peripheral as ParametrizedRegistrationPeripheral; 556 return (offset) => 557 { 558 parent.ByteRead = true; 559 return 0; 560 }; 561 } 562 GetWriteByteMethod(IBusPeripheral peripheral)563 public override Action<long, byte> GetWriteByteMethod(IBusPeripheral peripheral) 564 { 565 var parent = peripheral as ParametrizedRegistrationPeripheral; 566 return (offset, value) => 567 { 568 parent.ByteWritten = true; 569 }; 570 } 571 RegisterForEachContext(Action<BusParametrizedRegistration> register)572 public override void RegisterForEachContext(Action<BusParametrizedRegistration> register) 573 { 574 RegisterForEachContextInner(register, _ => new Registration(Range.StartAddress, Range.Size)); 575 } 576 } 577 } 578 } 579 580 public static class SysbusExtensions 581 { Register(this SystemBus sysbus, IBusPeripheral peripheral, Antmicro.Renode.Core.Range range)582 public static void Register(this SystemBus sysbus, IBusPeripheral peripheral, Antmicro.Renode.Core.Range range) 583 { 584 sysbus.Register(peripheral, new BusRangeRegistration(range)); 585 } 586 } 587 } 588