ull 0.1.0

Provides core primitives for the ull emulation project.
Documentation
## ull

`ull` is the core of the other crates in this project as it contains the type-safe numeric
wrappers (`Nibble`, `Byte`, `Word`), the `Bus` trait, and some convenience implementations like `SimpleBus`.
Other crates leverage these fundamental building blocks so they can share the same semantics for addresses, DMA, and
memory I/O. While not every system will use every aspect of this crate, they will all still use this as the foundation.

### Bus trait

The `Bus` trait models a synchronous, byte-addressed data bus:

```rust
pub trait Bus {
    fn read<A>(&mut self, addr: A, access: AccessType) -> Byte
    where
        A: Into<Word>;

    fn write<A, V>(&mut self, addr: A, value: V, access: AccessType)
    where
        A: Into<Word>,
        V: Into<Byte>;

    fn on_tick(&mut self, cycles: u8) { … }
    fn request_dma(&mut self, request: DmaRequest) -> DmaResult { … }
    fn poll_dma_cycle(&mut self) -> Option<u8> { … }
}
```

- `AccessType` tags accesses (opcode fetch, stack read/write, DMA, etc.) so a
  bus can differentiate them.
- `on_tick` lets peripherals run “in parallel” with the CPU by giving the bus a
  chance to advance its own notion of time each time the CPU consumes cycles.
- `request_dma`/`poll_dma_cycle` allow the bus to enqueue DMA work that should
  be factored into the CPU’s total cycles.

### Included buses

- `SimpleBus` – a flat 64KiB RAM array with helpers to load buffers and update
  the reset vector.
- `TestingBus` – a 64KiB RAM array backed by `Box<[u8]>` that records total
  cycles, DMA cycles, and lets you enqueue DMA bursts up front.

They’re deliberately minimal so you can embed them into examples or as a
starting point for a richer memory map.

### Quick start

```rust
use ull::{AccessType, Bus, Byte, SimpleBus, Word};

fn main() {
    let mut bus = SimpleBus::default();

    bus.write_block(Word(0x8000), &[0xAA, 0xBB], AccessType::DataWrite);
    assert_eq!(bus.read(Word(0x8001), AccessType::DataRead), Byte(0xBB));
}

/// Example of embedding `SimpleBus` inside a richer memory map.
struct MirrorBus(SimpleBus);

impl Bus for MirrorBus {
    fn read<A>(&mut self, addr: A, access: AccessType) -> Byte
    where
        A: Into<Word>,
    {
        self.0.read(addr, access)
    }

    fn write<A, V>(&mut self, addr: A, value: V, access: AccessType)
    where
        A: Into<Word>,
        V: Into<Byte>,
    {
        // Mirror writes into two halves of RAM.
        let addr = addr.into();
        self.0.write(addr, value, access);
        self.0.write(addr + 0x8000, value, access);
    }
}
```