diff options
Diffstat (limited to 'Q1.core/Components/Bus.cs')
| -rw-r--r-- | Q1.core/Components/Bus.cs | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/Q1.core/Components/Bus.cs b/Q1.core/Components/Bus.cs new file mode 100644 index 0000000..02b20a7 --- /dev/null +++ b/Q1.core/Components/Bus.cs @@ -0,0 +1,100 @@ +namespace Q1.core.Components; + +using Q1.core.Arch; + +public class Bus : IAddressable +{ + private Chip? _chip; + private readonly List<IAddressable> _devices; + + public u16 AddressableStart { get; } + public u16 AddressableEnd { get; } + + public Bus(u16 addressableStart, u16 addressableEnd) + { + this.AddressableStart = addressableStart; + this.AddressableEnd = addressableEnd; + this._devices = new(); + } + + public void SendInterrupt(u16 code) + { + if (this._chip == null) + throw new InvalidOperationException("Chip is not attached to bus"); + + this._chip.Interrupt(code); + } + + public void AttachChip(Chip chip) + { + if (this._chip != null) + throw new InvalidOperationException("Bus already has a chip attached."); + + this._chip = chip; + chip.Bus = this; + } + + public void MountDevice(IAddressable device) + { + if (device.AddressableStart >= device.AddressableEnd) + throw new ArgumentException("Addressable range is invalid.", nameof(device)); + + int index = 0; + while (index < this._devices.Count && this._devices[index].AddressableStart < device.AddressableStart) + index++; + + if (index > 0) + { + IAddressable prev = this._devices[index - 1]; + if (device.AddressableStart < prev.AddressableEnd) + throw new InvalidOperationException("Address range overlaps with previous device."); + } + + if (index < this._devices.Count) + { + IAddressable next = this._devices[index]; + if (device.AddressableEnd > next.AddressableStart) + throw new InvalidOperationException("Address range overlaps with next device."); + } + + this._devices.Insert(index, device); + } + + private IAddressable? GetDevice(u16 address) + { + foreach (IAddressable device in this._devices) + { + if (address < device.AddressableStart) + break; + + if (address < device.AddressableEnd) + return device; + } + + return null; + } + + public u8 Read(u16 address) + { + IAddressable? device = this.GetDevice(address); + if (device == null) + return 0; + + return device.Read((u16) (address - device.AddressableStart)); + } + + public void Write(u16 address, u8 value) + { + IAddressable? device = this.GetDevice(address); + if (device == null) + return; + + device.Write((u16) (address - device.AddressableStart), value); + } + + public void Clock() + { + foreach (IAddressable addressable in this._devices) + addressable.Clock(); + } +}
\ No newline at end of file |
