summaryrefslogtreecommitdiff
path: root/Q1.core/Components
diff options
context:
space:
mode:
authorMelodi <62381002+Melodi17@users.noreply.github.com>2026-03-18 07:19:22 +1000
committerMelodi <62381002+Melodi17@users.noreply.github.com>2026-03-18 07:19:22 +1000
commit0bb62fc65526a0981cd328dea1b09aba8ce0a576 (patch)
treea601bb87ead0f58674ee18088e9e41e77512d3b8 /Q1.core/Components
parent203331522e22c778ff830c3c6cf4f439778939fa (diff)
add: Add bus
Diffstat (limited to 'Q1.core/Components')
-rw-r--r--Q1.core/Components/Bus.cs100
-rw-r--r--Q1.core/Components/IAddressable.cs29
-rw-r--r--Q1.core/Components/Memory.cs21
3 files changed, 150 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
diff --git a/Q1.core/Components/IAddressable.cs b/Q1.core/Components/IAddressable.cs
new file mode 100644
index 0000000..54218d9
--- /dev/null
+++ b/Q1.core/Components/IAddressable.cs
@@ -0,0 +1,29 @@
+namespace Q1.core.Components;
+
+public interface IAddressable
+{
+ public u8 Read(u16 address);
+ public void Write(u16 address, u8 value);
+ public void Clock();
+
+ public u16 AddressableStart { get; }
+ public u16 AddressableEnd { get; }
+}
+
+public static class AddressableExtensions
+{
+ public static u16 ReadWord(this IAddressable bus, u16 address)
+ {
+ u8 high = bus.Read(address);
+ u8 low = bus.Read((u16) (address + 1));
+ return (u16) ((high << 8) | low);
+ }
+
+ public static void WriteWord(this IAddressable bus, u16 address, u16 value)
+ {
+ u8 high = (u8) (value & 0xFF);
+ u8 low = (u8) ((value >> 8) & 0xFF);
+ bus.Write(address, low);
+ bus.Write((u16) (address + 1), high);
+ }
+} \ No newline at end of file
diff --git a/Q1.core/Components/Memory.cs b/Q1.core/Components/Memory.cs
new file mode 100644
index 0000000..9d23c7a
--- /dev/null
+++ b/Q1.core/Components/Memory.cs
@@ -0,0 +1,21 @@
+namespace Q1.core.Components;
+
+public class Memory : IAddressable
+{
+ private readonly u8[] _memory;
+
+ public u16 AddressableStart { get; }
+ public u16 AddressableEnd { get; }
+
+ public Memory(u16 start, u16 size)
+ {
+ this.AddressableStart = start;
+ this.AddressableEnd = (u16) (start + size);
+
+ this._memory = new u8[size];
+ }
+
+ public u8 Read(u16 address) => this._memory[address];
+ public void Write(u16 address, u8 value) => this._memory[address] = value;
+ public void Clock() { /* No timing behavior for simple memory */ }
+} \ No newline at end of file