summaryrefslogtreecommitdiff
path: root/Q1.core/Components/Bus.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Q1.core/Components/Bus.cs')
-rw-r--r--Q1.core/Components/Bus.cs100
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