diff --git a/Documentation/_build/doctrees/Developer/ClassHierarchy.doctree b/Documentation/_build/doctrees/Developer/ClassHierarchy.doctree deleted file mode 100644 index 3d268cfcc..000000000 Binary files a/Documentation/_build/doctrees/Developer/ClassHierarchy.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/Developer/EventScheduler.doctree b/Documentation/_build/doctrees/Developer/EventScheduler.doctree deleted file mode 100644 index 9af8c8f49..000000000 Binary files a/Documentation/_build/doctrees/Developer/EventScheduler.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/Developer/MessageQueue.doctree b/Documentation/_build/doctrees/Developer/MessageQueue.doctree deleted file mode 100644 index c3005c887..000000000 Binary files a/Documentation/_build/doctrees/Developer/MessageQueue.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/Developer/RunLoop.doctree b/Documentation/_build/doctrees/Developer/RunLoop.doctree deleted file mode 100644 index 4da0405c2..000000000 Binary files a/Documentation/_build/doctrees/Developer/RunLoop.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/Developer/SuperHires.doctree b/Documentation/_build/doctrees/Developer/SuperHires.doctree deleted file mode 100644 index 539ff1c92..000000000 Binary files a/Documentation/_build/doctrees/Developer/SuperHires.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/Developer/ThreadClass.doctree b/Documentation/_build/doctrees/Developer/ThreadClass.doctree deleted file mode 100644 index bc7698ecc..000000000 Binary files a/Documentation/_build/doctrees/Developer/ThreadClass.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/HowTo/MappingCmd.doctree b/Documentation/_build/doctrees/HowTo/MappingCmd.doctree deleted file mode 100644 index fcfa0b306..000000000 Binary files a/Documentation/_build/doctrees/HowTo/MappingCmd.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/HowTo/NullModemCable.doctree b/Documentation/_build/doctrees/HowTo/NullModemCable.doctree deleted file mode 100644 index 4f25895ad..000000000 Binary files a/Documentation/_build/doctrees/HowTo/NullModemCable.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/Overview/About.doctree b/Documentation/_build/doctrees/Overview/About.doctree deleted file mode 100644 index ecc1e2d24..000000000 Binary files a/Documentation/_build/doctrees/Overview/About.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/References/Configuration/Audio.doctree b/Documentation/_build/doctrees/References/Configuration/Audio.doctree deleted file mode 100644 index 8e07149fb..000000000 Binary files a/Documentation/_build/doctrees/References/Configuration/Audio.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/References/Configuration/Chipset.doctree b/Documentation/_build/doctrees/References/Configuration/Chipset.doctree deleted file mode 100644 index 1a4fb05c7..000000000 Binary files a/Documentation/_build/doctrees/References/Configuration/Chipset.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/References/Configuration/Compatibility.doctree b/Documentation/_build/doctrees/References/Configuration/Compatibility.doctree deleted file mode 100644 index d525224aa..000000000 Binary files a/Documentation/_build/doctrees/References/Configuration/Compatibility.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/References/Configuration/Memory.doctree b/Documentation/_build/doctrees/References/Configuration/Memory.doctree deleted file mode 100644 index e6049e165..000000000 Binary files a/Documentation/_build/doctrees/References/Configuration/Memory.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/References/Configuration/Peripherals.doctree b/Documentation/_build/doctrees/References/Configuration/Peripherals.doctree deleted file mode 100644 index efaf2fc11..000000000 Binary files a/Documentation/_build/doctrees/References/Configuration/Peripherals.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/References/Configuration/Roms.doctree b/Documentation/_build/doctrees/References/Configuration/Roms.doctree deleted file mode 100644 index 7871f49ee..000000000 Binary files a/Documentation/_build/doctrees/References/Configuration/Roms.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/References/Configuration/Video.doctree b/Documentation/_build/doctrees/References/Configuration/Video.doctree deleted file mode 100644 index e7096601b..000000000 Binary files a/Documentation/_build/doctrees/References/Configuration/Video.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/References/Configuration/index.doctree b/Documentation/_build/doctrees/References/Configuration/index.doctree deleted file mode 100644 index f8bec6b42..000000000 Binary files a/Documentation/_build/doctrees/References/Configuration/index.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/References/FileFormats.doctree b/Documentation/_build/doctrees/References/FileFormats.doctree deleted file mode 100644 index 7f77f2895..000000000 Binary files a/Documentation/_build/doctrees/References/FileFormats.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/References/Preferences/Controls.doctree b/Documentation/_build/doctrees/References/Preferences/Controls.doctree deleted file mode 100644 index 5393ad71a..000000000 Binary files a/Documentation/_build/doctrees/References/Preferences/Controls.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/References/Preferences/Devices.doctree b/Documentation/_build/doctrees/References/Preferences/Devices.doctree deleted file mode 100644 index f529109fb..000000000 Binary files a/Documentation/_build/doctrees/References/Preferences/Devices.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/References/Preferences/General.doctree b/Documentation/_build/doctrees/References/Preferences/General.doctree deleted file mode 100644 index d971f8f38..000000000 Binary files a/Documentation/_build/doctrees/References/Preferences/General.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/References/Preferences/index.doctree b/Documentation/_build/doctrees/References/Preferences/index.doctree deleted file mode 100644 index 28f2f11ab..000000000 Binary files a/Documentation/_build/doctrees/References/Preferences/index.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/Tutorials/Exploring.doctree b/Documentation/_build/doctrees/Tutorials/Exploring.doctree deleted file mode 100644 index 8c797da1d..000000000 Binary files a/Documentation/_build/doctrees/Tutorials/Exploring.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/Tutorials/GettingStarted.doctree b/Documentation/_build/doctrees/Tutorials/GettingStarted.doctree deleted file mode 100644 index af176d068..000000000 Binary files a/Documentation/_build/doctrees/Tutorials/GettingStarted.doctree and /dev/null differ diff --git a/Documentation/_build/doctrees/environment.pickle b/Documentation/_build/doctrees/environment.pickle deleted file mode 100644 index 9bd651dba..000000000 Binary files a/Documentation/_build/doctrees/environment.pickle and /dev/null differ diff --git a/Documentation/_build/doctrees/index.doctree b/Documentation/_build/doctrees/index.doctree deleted file mode 100644 index 44f9ab8b2..000000000 Binary files a/Documentation/_build/doctrees/index.doctree and /dev/null differ diff --git a/Documentation/_build/html/.buildinfo b/Documentation/_build/html/.buildinfo deleted file mode 100644 index 753aa9bee..000000000 --- a/Documentation/_build/html/.buildinfo +++ /dev/null @@ -1,4 +0,0 @@ -# Sphinx build info version 1 -# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: 3bc9f9d8ead04faa306e2a69a21122b9 -tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/Documentation/_build/html/.nojekyll b/Documentation/_build/html/.nojekyll deleted file mode 100644 index e69de29bb..000000000 diff --git a/Documentation/_build/html/Developer/ClassHierarchy.html b/Documentation/_build/html/Developer/ClassHierarchy.html deleted file mode 100644 index 24ac847d1..000000000 --- a/Documentation/_build/html/Developer/ClassHierarchy.html +++ /dev/null @@ -1,245 +0,0 @@ - - - - - - - - - The Class Hierarchy — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

The Class Hierarchy

-

This document describes the basic software architecture of vAmiga. The emulator has been written in C++ and is based on the following class hierarchy:

-

Class hierarchy

-

The most prominent class is the Amiga class, as each instance of this class represents a complete virtual Amiga. The class inherits from three other classes:

-
    -
  • CoreObject

    -

    This class encapsulates some common functionalities that are useful for most classes in the vAmiga universe. For example, it provides the API functions for printing debug messages.

    -
  • -
  • CoreComponent

    -

    This class defines functionalities shared by all classes representing a hardware component. It includes functions to initialize, configure, and serialize objects, as well as functions to power on, power off, run, and pause.

    -
  • -
  • Thread

    -

    This class enables the Amiga class to run code in a separate thread. The architecture and functionality of this class is covered in a separate document.

    -
  • -
-

Another important entity is the SubComponent class, which is the ancestor of all, you guessed it, subcomponents of the Amiga. As a rule of thumb, you’ll find a separate class for almost every component you’ll find on the motherboard of a real Amiga. There is a CPU class, a Memory class, and classes for the custom chips Agnus, Denise and Paula. The Blitter and Copper are also encapsulated in individual classes. You’ll find the instances of these classes inside Agnus, just as you would find the logic circuits of these chips inside the Agnus chip in the real machine.

-

The inner structure of the SubComponent class is very simple, as its main purpose is to make all subcomponents visible to each others. In the class diagram you may have spotted the associated arrow that connects the SubComponent class with the Amiga class:

-

SubComponent Association

-

In the code, the connection is established in the constructor of the SubComponent class:

-
SubComponent(Amiga& ref);
-
-
-

Inside the constructor, a number of references like the following are set up:

-
CPU &cpu;
-Memory &mem;
-Agnus &agnus;
-...
-
-
-

The references are available in any subclass of SubComponent and provide easy access to all subcomponents of the virtual Amiga. For example, whenever Agnus needs to block the CPU for a certain number of cycles, it can do so by calling an appropriate API function of the cpu reference:

-
cpu.addWaitStates(delay);
-
-
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/Developer/EventScheduler.html b/Documentation/_build/html/Developer/EventScheduler.html deleted file mode 100644 index e71e3793a..000000000 --- a/Documentation/_build/html/Developer/EventScheduler.html +++ /dev/null @@ -1,340 +0,0 @@ - - - - - - - - - The Event Scheduler — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

The Event Scheduler

-

vAmiga is an event-driven emulator. If an action has to be performed in a certain bus cycle, the action is scheduled via the event handler API and executed when the trigger cycle is reached. The scheduler can be viewed as a large to-do list that is processed sequentially in Agnus::executeUntil. In the document about the Run Loop you have learned that this function is called in Agnus::execute which emulates Agnus for one bus cycle.

-
-

Event slots

-

Scheduled events are stored in so-called event slots. Each slot is bound to a specific component and is either empty or contains a single event. For instance, there is a slot for Copper events, a slot for Blitter events, a slot for UART events, and so on. From a theoretical point of view, each event slot represents a state machine that runs in parallel with all others. It is important to remember that the state machines interact with each other in various ways (e.g., by blocking the DMA bus). Therefore, the slot ordering is important: if two events are triggered in the same cycle, the slot with the smaller number is served first.

-

Enough theory for now. Let’s open the Events tab of the Inspector panel and examine what an event typically looks like. When the emulator is running, you’ll see something similar to this:

-

Event scheduler

-

The first seven slots comprise the so-called primary event table. The basic idea of the primary table is to group together all event slots with high traffic. Let’s look at the contents of these slots at the time the screenshot was taken:

-
    -
  • Registers -This event slot is used to emulate the access delays of the custom registers. It is either empty if no register change is pending, or it contains a REG_CHANGE event if one or more registers will change in the near future. Note that in our example, the trigger cycle of this slot is overdue. For speed reasons, the event scheduler sometimes skips updating the trigger cycle. A trigger cycle lying in the past has the same meaning as a trigger cycle that matches the value of the Agnus clock: It is due immediately.

  • -
  • CIA A and CIA B

    -

    Each CIA is controlled by its own event slot. As you can see in the screenshot, the slots for both CIAs contain a CIA_WAKEUP event, which means that both CIAs are inactive at the moment. The event slots are grayed out, which means that the slots are disabled. When either CIA gets something to do, the corresponding slot is enabled by updating the trigger cycle.

    -
  • -
  • Bitplane DMA

    -

    This slot manages all bitplane DMA accesses. In the example shown above, a BPL_L3 event is due at DMA cycle 61 ($3D) in the current scanline. If you are familiar with the DMA cycle diagram found in the Hardware Reference Manuel, you can easily understand what the emulator will be doing when the event triggers. It will perform the bitplane DMA fetch cycle surrounded by a red box:

    -

    Bus cycle diagram from the HRM

    -
  • -
  • Other DMA

    -

    This slot is used to manage disk DMA, audio DMA and sprite DMA, as well as to perform some special actions that must be carried out at specific positions in the processed scanline. In the example shown above, the slot contains a scheduled DAS_TICK event. When this event is triggered, the 24-bit counter of CIA B is incremented by one. This counter is used by the Amiga to keep track of the currently processed scanline.

    -
  • -
  • Copper and Blitter

    -

    These two slots manage the Copper and Blitter, respectively. The Copper slot has a scheduled wake-up event which is used to implement the WAIT instruction. Nothing is scheduled in the Blitter slot, which means that the Blitter is currently inactive.

    -
  • -
  • Next secondary event

    -

    This is the last slot in the primary slot table and utilized to speed up emulation. It indicates whether the event scheduler needs to proceed with checking the events in the other slots. To understand how this works, let’s return to theory for a moment.

    -
  • -
-

The event slots are divided into primary, secondary and tertiary slots. We have already made ourselves familiar with the primary slots, which manage all frequently occurring events. The secondary slots manage events that occur less frequently, such as interrupts or the events that control Paula’s four audio state machines. Events that occur very occasionally are scheduled in the tertiary slots, such as the insertion of a floppy disk. Accordingly, we call an event primary, secondary, or tertiary if it is scheduled in a primary, secondary, or tertiary slot, respectively.

-

To speed up, the event scheduler checks only the primary event slots by default. In order for the event handler to also check the secondary slots, a SEC_TRIGGER event must be scheduled in the SEC_SLOT. Since this slot belongs to the primary event table, too, it is always checked, just like the other slots in the primary event table. Triggering this event acts like a wake-up call requesting the event handler to check for secondary events as well. Thus, if an event is scheduled in a secondary slot, it must be ensured that SEC_SLOT contains a SEC_TRIGGER event with a trigger cycle equal to the smallest trigger cycle of all secondary events.

-

The same applies to tertiary events. When such an event is scheduled, the event scheduler automatically schedules a TER_TRIGGER wake-up event in TER_SLOT, which is the last event slot in the secondary slot table.

-

As you can see in the screenshot above, two tertiary slots contain a scheduled event. The first event is scheduled in the Server Daemon slot. It is used to monitor external socket connections. Such a connection is used, for example, to emulate a null modem cable connecting two vAmigas. The last slot is the Inspector slot and contains an event of type INS_EVENTS. When this event is triggered, an inspection of the event table is carried out. This means that all entries of the event table are recorded and passed to the GUI. In fact, it’s these recorded values that we see in the screenshot above. This also clarifies why the INS_EVENT event is always listed as “due immediately” in the inspector.

-

Overall, the introduction of an event hierarchy significantly improves emulation speed, as it prevents the event scheduler from having to traverse the entire event table when looking for due events.

-
-
-

Scheduling events

-

Internally, events are scheduled by calling an appropriate function from the event scheduling API. Among those are the following two variants of scheduleAbs which are implemented as follows:

-
template<EventSlot s> void scheduleAbs(Cycle cycle, EventID id)
-{
-    this->trigger[s] = cycle;
-    this->id[s] = id;
-        
-    if (cycle < nextTrigger) nextTrigger = cycle;
-    
-    if constexpr (isTertiarySlot(s)) {
-        if (cycle < trigger[SLOT_TER]) trigger[SLOT_TER] = cycle;
-        if (cycle < trigger[SLOT_SEC]) trigger[SLOT_SEC] = cycle;
-    }
-    if constexpr (isSecondarySlot(s)) {
-        if (cycle < trigger[SLOT_SEC]) trigger[SLOT_SEC] = cycle;
-    }
-}
-
-template<EventSlot s> void scheduleAbs(Cycle cycle, EventID id, i64 data)
-{
-      scheduleAbs<s>(cycle, id);
-      this->data[s] = data;
-}
-
-
-

The first variant requires three arguments. In addition to the template argument, which specifies the event slot in which the event is to be scheduled, it expects a trigger cycle and an event ID. The second variant has an additional data argument. For example, most events dealing with floppy drives store the drive number in the event’s data field.

-

Other scheduling functions are scheduleImm, scheduleInc, or scheduleRel. All these functions differ in the way the trigger cycle is set:

-
    -
  • Absolute (Abs)

    -

    The trigger cycle is specified in the form of a specific master cycle.

    -
  • -
  • Immediate (Imm)

    -

    The trigger cycle is the next DMA cycle.

    -
  • -
  • Incremental (Inc)

    -

    The trigger cycle is specified relative to the old trigger cycle.

    -
  • -
  • Relative (Rel)

    -

    The trigger cycle is specified relative to the current Agnus clock cycle.

    -
  • -
-

Events can also be rescheduled, cancelled or disabled. Rescheduling means that the event ID in the selected event slot remains unchanged. Canceling is done by calling the following function:

-
template<EventSlot s> void cancel()
-{
-    id[s] = (EventID)0;
-    data[s] = 0;
-    trigger[s] = NEVER;
-}
-
-
-

The crucial statement here is the last assignment. It sets the trigger cycle to NEVER, which is defined as a simple preprocessor constant:

-
// Time stamp used for messages that never trigger
-#define NEVER INT64_MAX
-
-
-

This means that a canceled event keeps being scheduled, but with a trigger cycle so high that it will never trigger.

-

When we say that an event slot is disabled, we simply mean that the trigger cycle is set to NEVER, but the ID and data are preserved. This is sometimes done for speed reasons, e.g. when the IDs of two consecutive events do not change.

-

Note that the event scheduler treats all cycle values as master cycles. If a trigger value is specified in a different unit, it must be converted to master cycles first. Several conversion macros are defined for this purpose:

-
#define CPU_CYCLES(cycles)    ((Cycle)(cycles) << 2)
-#define CIA_CYCLES(cycles)    ((Cycle)(cycles) * 40)
-#define DMA_CYCLES(cycles)    ((Cycle)(cycles) << 3)
-
-
-

The macros convert a value given in CPU cycles, CIA cycles or DMA cycles to the corresponding value on the master cycle scale. Reconversion is also possible by applying one of the following macros:

-
#define AS_CPU_CYCLES(cycles) ((Cycle)(cycles) >> 2)
-#define AS_CIA_CYCLES(cycles) ((Cycle)(cycles) / 40)
-#define AS_DMA_CYCLES(cycles) ((Cycle)(cycles) >> 3)
-
-
-

All event IDs are defined in a large enum called EventID.

-
enum_i8(EventID)
-{
-    EVENT_NONE          = 0,
-    
-    //
-    // Events in the primary event table
-    //
-
-    // REG slot
-    REG_CHANGE          = 1,
-    REG_EVENT_COUNT,
-
-    // CIA slots
-    CIA_EXECUTE         = 1,
-    CIA_WAKEUP,
-    CIA_EVENT_COUNT,
-
-    ...
-
-
-

Note that event IDs are reused across the event slots. For example, the REG_CHANGE and CIA_EXECUTE events share the same ID.

-

Congratulations. If you have worked through the documentation up to this point, you already have a good understanding of the basic software structure and inner workings of vAmiga.

-
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/Developer/MessageQueue.html b/Documentation/_build/html/Developer/MessageQueue.html deleted file mode 100644 index 715b725c8..000000000 --- a/Documentation/_build/html/Developer/MessageQueue.html +++ /dev/null @@ -1,332 +0,0 @@ - - - - - - - - - The Message Queue — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

The Message Queue

-

In this document we will examine how vAmiga communicates with the graphical user interface. Sending commands from the GUI to the emulator core is simple. The GUI simply calls one of the API functions of the Amiga instance or one of its subcomponents.

-

The other way is a bit more sophisticated. The emulator communicates with the GUI via a message queue. The message queue is implemented by the MsgQueue class, which stores all pending messages in a ring buffer.

-
class MsgQueue : public SubComponent {
-
-    // Ring buffer storing all pending messages
-    util::RingBuffer <Message, 512> queue;
-
-    ...
-}
-
-
-

Class MsgQueue supports two different access methods: Polling or Subscribing.

-
-

Polling the message queue

-

The message queue provides a public function bool MsgQueue::get(Message &msg) for reading a message. If the queue contains at least one message, true is returned and the oldest message is copied over to msg. If the queue is empty, the function returns false.

-

The polling method is utilized by vAmiga.net, a web port of vAmiga based on WebAssembly. The corresponding JavaScript code looks like this:

-
export function doAnimationFrame()
-{
-    // Process pending messages
-    while (1) {
-
-        let msg = $amiga.readMessage();
-        if (msg.type == 0) break;
-
-        $proxy.processMsg(msg);
-    }
-}
-
-
-

Function $amiga.readMessage() is a small C++ wrapper around the get function:

-
Message AmigaProxy::readMessage()
-{
-    Message msg;
-
-    if (!amiga->msgQueue.get(msg)) {
-        msg.type = 0;
-    }
-
-    return msg;
-}
-
-
-

On a positive note, polling ensures that message processing is always done in a separate thread. That is, it is never performed within the emulator thread itself. However, polling the queue is subject to potential message loss. If the GUI thread does not keep up with polling the queue, the ring buffer may overflow, resulting in lost messages. This drawback is solved by the subscription method, which we will discuss below.

-
-
-

Subscribing to the message queue

-

As an alternative to storing pending messages in a ring buffer, the message queue also supports a callback mechanism. In this mode, sent messages are no longer written to the ring buffer. Instead, the registered callback function is called with the sent message as parameter.

-

Subscribing to the message queue works by specifying the callback function as an argument to the Amiga::launch function, which we have already discussed earlier:

-
void launch(const void *listener, Callback *func);
-
-
-

Callback is a type alias which is defined as follows:

-
typedef void Callback(const void *, Message);
-
-
-

Whenever the emulator sends a message, the provided callback function is invoked. The first argument is the raw pointer passed as the first argument to Amiga::launch. The second argument is an instance of the class Message.

-

The subscription method is used by both the Mac version of vAmiga and vAmiga Headless. The latter is a small wrapper around the core emulator used mainly for testing the integrity of nightly builds. vAmiga Headless first creates an instance of the Amiga class on the stack:

-
class Headless {
-
-    ...
-
-    // The emulator instance
-    Amiga amiga;
-}
-
-
-

Subscribing to the message queue happens in the main function:

-
int
-Headless::main(int argc, char *argv[])
-{
-    ...
-
-    // Launch the emulator thread
-    amiga.launch(this, vamiga::process);
-}
-
-
-

The first argument of the launch function is a pointer to the instance of the calling object. The second argument is a pointer to a global function called process, which is defined as follows:

-
void
-process(const void *listener, Message msg)
-{
-    ((Headless *)listener)->process(msg);
-}
-
-
-

The implementation of this function is fairly straightforward. It converts the provided raw pointer (which was set to this above) back to the correct type and calls the process function for that object. The implementation of this function looks like this:

-
void
-Headless::process(Message msg)
-{
-    switch (msg.type) {
-            
-        case MSG_SCRIPT_DONE:
-            ...
-
-        }
-    }
-}
-
-
-

Subscribing to the message queue has the advantage of preventing any message from being lost. However, it is important to note that the message processing code is executed inside the emulator thread. This may cause problems if the message processing code calls functions of the public API of the Amiga class, since many of these functions assume that they are not called by the emulator thread itself. The Mac version of vAmiga solves this problem by passing all incoming messages to the GUI thread before execution. The relevant code is encapsulated in the MyController.launch() function, which is part of the Swift UI:

-
    func launch() {
-
-        // Convert 'self' to a void pointer
-        let myself = UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque())
-
-        amiga.launch(myself) { (ptr, msg: Message) in
-
-            // Convert void pointer back to 'self'
-            let myself = Unmanaged<MyController>.fromOpaque(ptr!).takeUnretainedValue()
-
-            // Process message in the main thread
-            DispatchQueue.main.async {
-                myself.processMessage(msg)
-            }
-        }
-    }
-
-
-
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/Developer/RunLoop.html b/Documentation/_build/html/Developer/RunLoop.html deleted file mode 100644 index 444e4a478..000000000 --- a/Documentation/_build/html/Developer/RunLoop.html +++ /dev/null @@ -1,334 +0,0 @@ - - - - - - - - - The Run Loop — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

The Run Loop

-

In this document we will examine how vAmiga calculates a single frame. If you’ve studied the document about the Thread class, you already know that the calculation of a single frame is triggered within the threads main execution function. E.g., when the thread is running in pulsed mode, the following function is executed:

-
template <> void
-Thread::execute<THREAD_PULSED>()
-{
-    loadClock.go();
-    execute();
-    loadClock.stop();
-}
-
-
-

The loadClock object is used to measure the CPU load. All the action takes place in function execute, which is declared as a pure virtual function inside the Thread class:

-
virtual void execute() = 0;
-
-
-

The Amiga class implements this function as follows:

-
void
-Amiga::execute()
-{    
-    while (1) {
-        
-        // Emulate the next CPU instruction
-        cpu.execute();
-
-        // Check if special action needs to be taken
-        if (flags) {
-                        
-            ...
-            
-            // Are we requested to synchronize the thread?
-            if (flags & RL::SYNC_THREAD) {
-                clearFlag(RL::SYNC_THREAD);
-                break;
-            }
-        }
-    }
-
-
-

The function enters an infinite loop, which we refer to as the run loop. The inner working is quite simple. First the CPU is asked to execute a single instruction. After that, the variable flags is checked. This variable is a bit field storing several action flags whose purpose is to trigger specific actions within the run loop. The following list gives you an idea about what kind of actions we are talking about:

-
namespace RL
-{
-constexpr u32 STOP               = (1 << 0);
-constexpr u32 SOFTSTOP_REACHED   = (1 << 1);
-constexpr u32 BREAKPOINT_REACHED = (1 << 2);
-constexpr u32 WATCHPOINT_REACHED = (1 << 3);
-constexpr u32 CATCHPOINT_REACHED = (1 << 4);
-constexpr u32 SWTRAP_REACHED     = (1 << 5);
-constexpr u32 COPPERBP_REACHED   = (1 << 6);
-constexpr u32 COPPERWP_REACHED   = (1 << 7);
-constexpr u32 AUTO_SNAPSHOT      = (1 << 8);
-constexpr u32 USER_SNAPSHOT      = (1 << 9);
-constexpr u32 SYNC_THREAD        = (1 << 10);
-};
-
-
-

In most cases the variable flags equals zero. In this case, the loop simply executes one CPU instruction after another.

-

But wait, didn’t we say the function only calculates a single frame? The answer is yes, and this is where the SYNC_THREAD flag comes into play. The flag is set by Agnus in the following function:

-
void
-Agnus::eofHandler()
-{
-    ...
-
-    // Let the thread synchronize
-    amiga.setFlag(RL::SYNC_THREAD);
-}
-
-
-

The acronym eof refers to end of frame. As you may have guessed already, the function is executed at the end of each frame. Once the variable SYNC_THREAD is set, the run loop will be terminated with the next check of the variable flags.

-

Overall, it’s pretty simple, isn’t it? Well, the answer is yes and no. For instance, we just learned that the SYNC_THREAD flag is set by Agnus in its end-of-frame handler, but where is this function called? The run loop does nothing of that sort, it just calls the CPU and checks some flags.

-

The sky clears up by taking a closer look at what’s happening inside CPU::execute(). Let’s assume that the next instruction to be executed is a BRA instruction. Inside CPU::execute() the CPU starts executing some internal actions. After that it calls the execution handler of the BRA instruction, which begins as follows:

-
template <Core C, Instr I, Mode M, Size S> void
-Moira::execBra(u16 opcode)
-{
-    AVAILABILITY(S == Long ? C68020 : C68000)
-
-    u32 oldpc = reg.pc;
-    u32 disp = S == Byte ? (u8)opcode : queue.irc;
-
-    SYNC(2);
-
-    ...
-}
-
-
-

The SYNC statement is the one we need to examine. It is a macro that expands to a call to the sync function, at least when emulating a M68000 or M68010. The CPU calls this function to signal to the surrounding logic that the CPU clock has advanced a certain number of cycles. In this particular example, it signals that 2 CPU cycles have elapsed.

-

Let’s see how the sync function is implemented. An uncluttered version of this function looks like this:

-
void
-Moira::sync(int cycles)
-{
-    // Advance the CPU clock
-    clock += cycles;
-
-    // Emulate Agnus up to the same cycle
-    agnus.execute(CPU_AS_DMA_CYCLES(cycles));
-}
-
-
-

After advancing the internal clock, the function asks Agnus to emulate the surrounding logic up to the point in time where the CPU currently is. After that, control is returned to the CPU. Now, when the CPU performs a memory access, it is assured that the surrounding logic is up to date. For write accesses, this means that the operation is carried out at the proper point in time, and for read accesses, it means that correct values will be read.

-

Let’s head over to Agnus and have a closer look at what the execute function does. The function that was actually called is a convenience wrapper around the actual execution function:

-
void
-Agnus::execute(DMACycle cycles)
-{
-    for (DMACycle i = 0; i < cycles; i++) execute();
-}
-
-
-

So let’s dig a little deeper:

-
void
-Agnus::execute()
-{
-    // Advance the internal clock and the horizontal counter
-    clock += DMA_CYCLES(1);
-    pos.h += 1;
-
-    // Process pending events
-    if (nextTrigger <= clock) executeUntil(clock);
-}
-
-
-

This function emulates Agnus for one bus cycle. First, it increments the color clock and the horizontal counter by one. After that, if a pending event is present, it calls the event scheduler.

-

The Event Scheduler can undoubtedly be considered the central component of vAmiga, as everything is built around it. All actions that have to be executed in a certain bus cycle are triggered by this component. Please always remember that the event scheduler, despite its central role, is never called directly inside the run loop of vAmiga. It is only called indirectly, before each memory access of the CPU.

-

Since the event scheduler is of such great importance, we’ll examine it in more detail in a separate document.

-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/Developer/SuperHires.html b/Documentation/_build/html/Developer/SuperHires.html deleted file mode 100644 index eded03420..000000000 --- a/Documentation/_build/html/Developer/SuperHires.html +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - SuperHires mode — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

SuperHires mode

-

This document outlines how SuperHires mode is implemented in vAmiga. This mode is a feature of the ECS chipset and available e.g. on the Amiga 500+. SuperHires mode provides a pixel display rate of 35 ns, which is twice the horizontal resolution of Hires mode, and four times the resolution of Lores mode.

-

The integration of SuperHires mode into vAmiga was driven by three design goals:

-
    -
  • Customizable texture size

    -

    Early versions of vAmiga generated a GPU texture in Hires resolution, meaning that each Hires pixel on the Amiga side corresponded to a single texel on the GPU side. The term texel is a mixture of the words pixel and commonly used to describe a single pixel in a GPU texture. Since SuperHires mode doubles the horizontal resolution, I had to decide whether the horizontal GPU texture size should be doubled, too. I have come to the conclusion that vAmiga should support two horizontal texture resolutions to better suit backends that do not take advantage of the higher resolution.

    -
  • -
  • Low performance impact

    -

    SuperHires mode is a rarely used feature of the Amiga and the vast majority of users will be running vAmiga in one of the default modes most of the time. Therefore, the performance hit caused by adding SuperHires mode had to be kept as low as possible.

    -
  • -
  • No code cluttering

    -

    One of the strengths of vAmiga is a clean code base. Therefore, my goal was to change the existing code as little as possible. I.e., I wanted to avoid cluttering the code with an armada of if-statements checking the currently used texture format.

    -
  • -
-

To fulfill the first requirement I added a configuration option called TPP. This abbreviation stands for Texels Per Pixel and describes the number of texels that make up a single Hires pixel. TPP can be either 1 or 2. When set to 1, vAmiga generates a Hires texture, just like the early versions, meaning that each Hires pixel is represented by a single texel. If set to 2, vAmiga generates a texture in SuperHires resolution, which means each hires pixel is represented by two texels.

-

The following images illustrate the effects of the TPP setting. When TPP is equal to 1 and the Amiga draws a line in Hires mode, each Hires pixel is mapped to a single texel:

-

TPP 1 Hires pixel stream

-

In SuperHires mode, however, the GPU texture is too coarse to represent each emulator pixel individually. In this case, the drawing logic interpolates two emulator pixels into a single texel:

-

TPP 1 Super-Hires pixel stream

-

If TPP equals 2, each Hires pixel is mapped to two texels:

-

TPP 2 Hires pixel stream

-

In SuperHires mode, vAmiga performs a one-to-one mapping of SuperHires pixels to texels:

-

TPP 2 Super-Hires pixel stream

-

Let us revisit the design goals mentioned above. To achieve the latter two, TPP had to be made a compile-time option. This means that it has to be decided in advance which texture format should be used.

-

Let us now take a closer look at the compile-time changes triggered by TPP. The most important code fragment is located in FrameBufferTypes.h. Among others, this file defines the Texel type, which is used to address elements in the GPU texture. It is defined as follows:

-
#if TPP == 1
-typedef u32 Texel;
-#else
-typedef u64 Texel;
-#endif
-
-
-

As you can see, the value of TPP affects the underlying data type of Texel. When TPP equals 1, Texel corresponds to an unsigned 32-bit integer. If TPP equals 2, the data type is twice as large.

-

In addition, there is a macro called TEXEL which converts an 32-bit RGBA value into a Texel.

-
#if TPP == 1
-#define TEXEL(rgba) (rgba)
-#else
-#define TEXEL(rgba) ((u64)rgba << 32 | rgba)
-#endif
-
-
-

The definition of this macro reveals the trick vAmiga uses to keep the performance penalty low. If TPP equals 1, this macro is a direct mapping. In other words: If TPP equals 1, a Texel is a 32-bit value. If TPP equals 2, the TEXEL macro repeats the RGBA pattern. This means that the generated 64-bit value will represent the same RGBA value twice in a row. Thus, when the emulator sets a single texel in the texture, it actually sets two texels because a texel is always 32-bit on the GPU side. Since writing a 64-bit value is about as fast as writing a 32-bit value, the actual TPP value has no relevant impact on vAmiga’s performance. Of course, we have to pay a price on the GPU side. Since the emulator texture has doubled in size, the GPU has to move around twice as much memory for each frame.

-

Also, hiding the actual texture size in the Texel data type prevents the code quality to degrade. From the emulator side, the horizontal texture size appears to be independent of the TPP value, since everything is counted in texels. As a result, the same code can be used for both possible TPP values and there is no need to clutter the code with a large amount of if statements.

-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/Developer/ThreadClass.html b/Documentation/_build/html/Developer/ThreadClass.html deleted file mode 100644 index 8c2844f45..000000000 --- a/Documentation/_build/html/Developer/ThreadClass.html +++ /dev/null @@ -1,359 +0,0 @@ - - - - - - - - - The Thread Class — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

The Thread Class

-

In this document we will take a closer look at the Thread class, which adds concurrent code execution capabilities to the Amiga class. In addition, it implements the state model of the emulator.

-

Thread class

-

Creating an emulator instance comprises two steps:

-
    -
  • Creating an instance of the Amiga class.

  • -
  • Calling Amiga::launch().

  • -
-

Inside Amiga::launch(), an emulator thread is spawned in the constructor:

-
Amiga::launch()
-{
-    ...
-    thread = std::thread(&Thread::main, this);
-    ...
-}
-
-
-

The thread is never terminated. It remains alive until the application quits.

-
-

Main function

-

After the thread has been created, it starts executing the Thread::main function which is inherited from the Thread class. This function consists of a large while loop which looks like this:

-
void
-Thread::main()
-{    
-    ...
-    while (++loopCounter) {
-
-        if (isRunning()) {
-                        
-            switch (getThreadMode()) {
-
-                case THREAD_PERIODIC:   execute<THREAD_PERIODIC>(); break;
-                case THREAD_PULSED:     execute<THREAD_PULSED>(); break;
-                case THREAD_ADAPTIVE:   execute<THREAD_ADAPTIVE>(); break;
-            }
-        }
-                
-        if (!warpMode || !isRunning()) {
-            
-            switch (getThreadMode()) {
-
-                case THREAD_PERIODIC:   sleep<THREAD_PERIODIC>(); break;
-                case THREAD_PULSED:     sleep<THREAD_PULSED>(); break;
-                case THREAD_ADAPTIVE:   sleep<THREAD_ADAPTIVE>(); break;
-            }
-        } 
-
-        if (stateChangeRequest.test()) {
-
-            switchState(newState);
-            stateChangeRequest.clear();
-            stateChangeRequest.notify_one();
-
-            if (state == EXEC_HALTED) return;
-        }
-        ...       
-    }
-}
-
-
-

Because the thread is never terminated, the loop is executed during the entire lifetime of the application. Within the loop body, two switch-case blocks can be spotted. The first one is executed as long as the emulator is running and calls one of three possible functions, depending on the operation mode of the thread. Both functions emulate the Amiga for a single frame. The second switch-case block is executed when the emulator is not running in warp mode. Within this block, one of three synchronization functions is called, again depending on the selected operation mode. The purpose of these functions is to keep the thread running at the right pace. That is, they ensure that the functions are called 50 times per second for PAL machines and 60 times per second for NTSC machines.

-

Three synchronization modes are available: Periodic, Pulsed, and Adaptive.

-
enum_long(THREAD_MODE)
-{
-    THREAD_PERIODIC,
-    THREAD_PULSED,
-    THREAD_ADAPTIVE
-};
-typedef THREAD_MODE ThreadMode;
-
-
-
    -
  • THREAD_PERIODIC:

    -

    In periodic mode the thread puts itself to sleep and utilizes a timer to schedule a wakeup call. In this mode, no further action has to be taken by the GUI. This method had been the default mode used by vAmiga up to version 2.3.

    -
  • -
  • THREAD_PULSED

    -

    In pulsed mode, the thread waits for an external wake-up signal that has to be sent by the GUI. When the wake-up signal is received, a single frame is computed. vAmiga uses this mode to implement VSYNC.

    -
  • -
  • THREAD_ADAPTIVE:

    -

    In adaptive mode, the thread waits for an external wake-up signal just as it does in pulsed mode. When the wake-up signal comes in, the thread computes the number of missing frames based on the current time and the time the thread had been lauchen. Then it executes all missing frames or resynchronizes if the number of missing frames is way off. Adaptive mode has been introduced in vAmiga 2.4. It has become the new default mode since then.

    -
  • -
-
-
-

State model

-

Let’s take a closer look at the isRunning() function, whose implementation is very straightforward:

-
bool isRunning() const override { return state == EXEC_RUNNING; }
-
-
-

The variable state may hold one of the following values:

-
    -
  • EXEC_OFF: The emulator is turned off.

  • -
  • EXEC_PAUSED: The emulator is turned on, but not running.

  • -
  • EXEC_RUNNING: The emulator does its job. The virtual Amiga is alive.

  • -
  • EXEC_SUSPENDED: The emulator is paused for a short period of time.

  • -
  • EXEC_HALTED: The emulator is shutting down.

  • -
-

The following image provides a visual representation of the state model:

-

State model

-

After creating an instance of the Amiga class the emulator is in OFF state. By calling the function powerOn() the emulator is put into PAUSED state. This is the same state that is entered when the user presses the Pause button in the toolbar. A call to run() brings the virtual Amiga to life by putting it into a RUNNING state.

-

The Thread class provides a suspend-resume mechanism that can be used to pause the thread for a short period of time. This functionality is frequently used by the graphical user interface to carry out atomic operations that cannot be performed while the emulator is running. Theoretically, the thread could also be put into PAUSED state for this purpose, but this would also stop audio. To avoid disruptions, a special SUSPENDED state has been added. In this state the execute function is no longer called, but other services, such as the audio playback, are kept alive.

-

The SUSPENDED state is entered by calling suspend() and exited by calling resume(). Critical code sections can be executed safely by embedding them in a suspend-resume block like this:

-
suspend();
-
-// Change the internal state of the emulator as you like.
-
-resume();
-
-
-

It is safe to nest multiple suspend-resume blocks, but it is essential that each call to suspend() is followed by a call to resume(). Consequently, the critical code section must not be exited in the middle, e.g. by throwing an exception. For this reason, you will often see the keyword SUSPENDED in the code, which is an exit-safe wrapper around suspend() and resume(). With this macro, the above code snippet can be rewritten as follows:

-
{   SUSPENDED
-
-    // Change the internal state of the emulator as you like.
-    // Feel free to return or throw an exception.
-}
-
-
-

To speed up emulation, e.g. during disk accesses, the emulator may be put into warp mode, which is also handled by the Thread class. As you have seen in the code fragment of the Thread::main() function, neither of the two synchronization functions is called when warp mode is active.

-

Similar to warp mode, the emulator can be put into track mode. This mode is activated when the GUI debugger is opened and deactivated when the debugger is closed. In track mode, several time-consuming tasks are performed that are normally skipped. For example, the CPU keeps track of all executed instructions and stores the recorded information in a trace buffer.

-

The Thread class provides several API functions for changing state such as powerOn(), powerOff(), run(), pause() or halt(). These functions request the thread to change state by setting the following variable to true:

-
std::atomic_flag stateChangeRequest;
-
-
-

As you may have already seen in the code snippet above, the main function checks this variable in each iteration of the while loop and performs a state change when necessary. The implementation of function switchState looks like this:

-
    while (newState != state) {
-
-        if (state == EXEC_OFF && newState == EXEC_PAUSED) {
-
-            CoreComponent::powerOn();
-            state = EXEC_PAUSED;
-
-        } else if (state == EXEC_OFF && newState == EXEC_RUNNING) {
-
-            CoreComponent::powerOn();
-            state = EXEC_PAUSED;
-       
-        } ...
-        
-        } else if (newState == EXEC_HALTED) {
-
-            CoreComponent::halt();
-            state = EXEC_HALTED;
-        }
-    }
-
-
-
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/HowTo/MappingCmd.html b/Documentation/_build/html/HowTo/MappingCmd.html deleted file mode 100644 index fcc0c27fc..000000000 --- a/Documentation/_build/html/HowTo/MappingCmd.html +++ /dev/null @@ -1,218 +0,0 @@ - - - - - - - - - Mapping the Command keys — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

Mapping the Command keys

-

In vAmiga you will be using the native Mac keyboard for typing, and for most Amiga keys you will find a perfect match on your native keyboard. This holds true for the two Amiga keys, too. They are located in the same places on the Amiga keyboard as the Command keys are on modern keyboards. Therefore, it would be natural to assign the two command keys to the two Amiga keys.

-

However, this creates a problem because the command keys in macOS are directly linked to operating system actions. If we grant the emulator free access to these keys, we would lose all standard key combinations like Cmd+H for hiding a window or Cmd+Q for quitting the application.

-

Therefore, the command keys are not mapped by default. However, if you want to associate the command keys with the Amiga keys, you can do so via the keyboard menu. By selecting the appropriate option, you can choose whether you want to map the left command key, the right command key or both keys.

-

Keyboard menu

-

A feasible trade off is to map the right Command key, only, since the Amiga used the right Amiga key to trigger OS-specific commands. If the left command key is left unmapped, you can trigger Amiga commands using the right Command key while still controlling the Mac application with the standard macOS-specific keyboard shortcuts.

-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/HowTo/NullModemCable.html b/Documentation/_build/html/HowTo/NullModemCable.html deleted file mode 100644 index e5a8815a6..000000000 --- a/Documentation/_build/html/HowTo/NullModemCable.html +++ /dev/null @@ -1,231 +0,0 @@ - - - - - - - - - Connecting Two Amigas — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

Connecting Two Amigas

-

vAmiga supports two emulator instances to be connected with a null modem cable, allowing the user to run multiplayer games. In this article we will walk through the necessary steps to connect two emulator instances running Battle Chess.

-

First of all, launch vAmiga, open the configuration window and switch to the Peripherals tab. In this tab you can configure the serial interface:

-

Peripherals Tab

-

Now open the serial port popup menu and select Null Modem Cable from the options list. This will connect one side of a null modem cable to the serial port of your virtual Amiga. Internally, the null modem cable is emulated using socket connections, which means that the connected Amigas must agree on a common port number to communicate. By default, vAmiga uses port 8080, but you can choose a different port if you like.

-

Peripherals Tab

-

As you can see in the screenshot above, a small icon has appeared in the status bar. This indicates that the socket server has been activated and is waiting for another emulator instance to connect.

-

Now launch another instance of vAmiga and connect the null modem cable the same way.

-

Peripherals Tab

-

After the null modem cable has been selected in the second emulator instance, the status icon has changed its shape, indicating that the connection has been established. If the icon looks different on your computer, please check if both emulator instances are listening to the same socket port.

-

Now it’s time to load Battle Chess on both Amigas. The configuration of the null modem cable is quite simple in this game: The the Settings menu let’s you select the player type for each side of the board.

-

This is how I configured the first emulator instance. The Amiga controls the blue army, the connected computer controls the red army.

-

Battle Chess Setup

-

The second emulator instance is configured the other way around. The Amiga controls the red soldiers, the connected computer controls the blue ones. After selecting New Game from the menu in either emulator instance, it’s time to chill. Have fun with two vAmigas fighting each other.

-
-

Troubleshooting

-

If everything works as expected, the socket connection should be established exactly as described above. If vAmiga refuses to connect, you can display some additional debug information in RetroShell. To do so, open RetroShell by pressing on the corresponding toolbar icon. Inside RetroShell, switch to the Debugger by pressing the Shift + Return. Now, type server serial as shown in the screenshot below. This command displays the current connection status and outputs some statistical information about the transferred data.

-

RetroShell

-
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/Overview/About.html b/Documentation/_build/html/Overview/About.html deleted file mode 100644 index a229d6ca1..000000000 --- a/Documentation/_build/html/Overview/About.html +++ /dev/null @@ -1,236 +0,0 @@ - - - - - - - - - About — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

About

-

vAmiga is a Commodore Amiga 500, 1000 and 2000 emulator for macOS. Development begun in January 2019 and has made great progress since then.

-

Screenshots

-
-

Design goals

-

I have written vAmiga with three goals in mind:

-
    -
  • Accuracy

    -

    vAmiga aims to emulate the three original Commodore Amiga machines, the A500, A1000, and A2000, with high accuracy. It tries to emulate all the components with cycle-exact precision, meaning that each memory access is performed at the exact same DMA cycle as on the original machine.

    -
  • -
  • Usability

    -

    Providing an appealing graphical user interface is a crucial aspect in retro computing for me, as the purpose of an emulator is not only to run aged software, but to bring back old memories from back in the day. vAmiga provides an easy-to-use interface that tries to hide as many technical details from the user as possible.

    -
  • -
  • Quality

    -

    It is my deep conviction that the code quality is as important as system-level functionality. For this reason, I have spent a lot of time on software architecture and refactoring. The effort already payed off. E.g., it was possible to port vAmiga to WebAssembly with little effort.

    -
  • -
-

Inspectors

-
-
-

Licensing

-

vAmiga is open-source and published under the terms of the GNU General Public License. The CPU core has been re-licensed recently. It is now published under the terms of the MIT license, allowing much broader use. Please refer to the Moira project for more details about this topic.

-

To run the emulator, a Kickstart ROM is required. Please note that the original Amiga ROMs cannot be shipped with the emulator as they are the intellectual property of Cloanto™. By purchasing a license of Amiga Forever™ you can acquire legal Kickstart ROMs and use them in vAmiga.

-
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/References/Configuration/Audio.html b/Documentation/_build/html/References/Configuration/Audio.html deleted file mode 100644 index 0a19c3b8b..000000000 --- a/Documentation/_build/html/References/Configuration/Audio.html +++ /dev/null @@ -1,250 +0,0 @@ - - - - - - - - - Audio Panel — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

Audio Panel

-

Use this panel to change the audio settings.

-

Audio Panel

-

The audio settings are organized in four sections:

-
-

Audio In

-

This section controls the volumes of the four Amiga audio channels. To mute an audio channel, simply lower the volume to zero. The pan controls can be used to freely distribute each channel to the left and right speakers. By default, channels 1 and 2 are routed to the left speaker and channels 0 and 4 to the right speaker, just like a real Amiga does.

-
-
-

Audio Out

-
    -
  • Left, Right

    -

    The two volume controls change the main volume of the two stereo output streams. Both streams are mixed together from the four Amiga audio channels as specified in the Audio In section.

    -
  • -
  • Interpolation

    -

    The Amiga can generate audio streams with different sampling rates. This means that the audio stream must be translated into a suitable audio stream for the host computer. The interpolation settings control how this conversion is performed. You can choose between three methods:

    -
      -
    • Off

      -

      In this mode, no interpolation takes place. Based on the timestamp of the audio sample to be created, the current content of the audio output buffer is fed into the audio stream of the host computer. This mode trades in quality for speed.

      -
    • -
    • Nearest

      -

      Based on the timestamp of the audio sample to be created, the Amiga audio sample with the closest timestamp is selected. This mode is slightly slower than the first one, but produces better quality.

      -
    • -
    • Linear

      -

      Based on the timestamp of the audio sample to be created, the two surrounding samples are looked up in the Amiga audio stream and linearly interpolated. This mode gives the best result, but is also the slowest among the three options.

      -
    • -
    -
  • -
-
-
-

Drive volumes

-

In this area, the volumes of several sound effects are controlled. vAmiga distinguishes between heads steps and polling clicks. The latter describe the steps of the drive head that are executed to detect a disk change. Since polling clicks may become annoying, especially when two or more drives are connected, it is possible to silence them by reducing the volume of the polling clicks to zero. All normal head movements will still be audible in this case.

-
-
-

Drive locations

-

With the pan controls you can freely distribute the drive sounds to the left and right speaker outputs. In the default setting, all sounds from the internal floppy drive are routed to the right speaker, since the floppy drive in the Amiga 500 is located on the right side of the computer case.

-
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/References/Configuration/Chipset.html b/Documentation/_build/html/References/Configuration/Chipset.html deleted file mode 100644 index 393806f95..000000000 --- a/Documentation/_build/html/References/Configuration/Chipset.html +++ /dev/null @@ -1,297 +0,0 @@ - - - - - - - - - Chipset Panel — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

Chipset Panel

-

Use this panel to configure the CPU and the custom chips of the virtual Amiga.

-

Chipset Panel

-
-

CPU

-

vAmiga supports three different CPU revisions:

-
    -
  • M68000

    -

    The M68000 is a 16/32-bit CISC microprocessor introduced by Motorola in 1979. Commodore has used this CPU in all classic Amiga models. Choose this revision to emulate the classic Amigas at the highest precision.

    -
  • -
  • M68010

    -

    The MC68010 processor was released in 1982 as the successor to the Motorola 68000. It was never officially used by Commodore in any Amiga model. However, since the M68010 was pin-compatible with the M68000, it can be used as a replacement for the M68000 in all classic Amigas. The following image shows one of my test machines that has been upgraded with a M68010. I’ve used this machine extensively while adding M68010 support in vAmiga:

    -

    M68010

    -

    Using the M68010 instead of the M68000 results in a speed gain of about 10%. Among other things, this is due to a special operating mode, called loop mode, which is entered automatically when certain loop constructs are executed. In this mode, some redundant memory accesses are skipped, resulting in faster execution speed. Please note that the M68010 is not 100% software compatible with the M68000. Therefore, some games or demos may not work when this CPU is selected.

    -
  • -
  • 68EC020

    -

    The M68EC020 is a lower-cost version of the Motorola 68020 processor, which was launched in 1984. It was used by Commodore in the Amiga 1200 with a clock frequency of 14MHz. The 68020 was a significant improvement over the M68010, as it was the first CPU in the M68K series to have an on-board cache. vAmiga emulates the M68EC020, but with less precision than the M68000 and M68010. The first two models can be emulated by vAmiga with exact cycle precision, which means that all instructions not only consume the proper number of CPU cycles, but also access memory during the exact same DMA cycle as the real machine does. In 68020 mode, the CPU is emulated with lower accuracy. For example, vAmiga does not emulate caching, yet.

    -
  • -
  • Warp mode

    -

    In warp mode vAmiga runs at maximum speed, i.e. it starts computing the next frame right after the current frame has been completed. Warp mode can be configured as always off, always on or automatically enabled. In auto mode, warp mode is linked to the disk drive logic. It turns on and off just as the drive motor does. This mode significantly reduces loading times and works quite well in most cases. However, some applications are coded to not turn off the drive motor even when no data is being transmitted. In such cases, auto mode must be turned off manually by the user.

    -
  • -
-

The next two options choose the emulated chip revisions of Agnus and Denise, two of the so-called custom chips. These chips were extremely important for the Amiga, as they were one of the main reasons for its competitive computing power back in the day. Without the custom chips, the Amiga would never have taken the prominent place in computer history it occupies today.

-

All custom chips can be classified into one of three generations. The first chip generation is called OCS (Original Chip Set). All original Amigas were equipped with these chips. The second generation is called ECS (Enhanced Chip Set) and was used by Commodore in the A500+ and the A600. Some ECS chips were also used in later revisions of the A500 and the A2000. Commodore shipped them with an ECS Agnus and an OCS Denise. My test computer pictured above also belongs to these models. It is equipped with an Agnus 8372A, a revision of the ECS generation. Denise, however, has revision number 8362R8, which is the OCS version of this chip. -The third generation of custom chips was called AGA (Advanced Graphics Architecture). Commodore equipped the A1200 and A4000 with these chips.

-

Both the OCS and ECS chipsets are supported by vAmiga. The AGA chipset is currently not supported and probably will never be.

-
-
-

Agnus

-

Agnus can be considered the boss among the custom chips, because it controls the interaction of all other components. It also acts as a data provider for the other chips, as it performs all DMA accesses.

-

vAmiga is able to emulate the following revisions of this chip:

-
    -
  • Early OCS

    -

    This option emulates the MOS 8367. It was used in the A1000 and in a very early version of the A2000, usually called the A2000A.

    -
  • -
  • OCS

    -

    This option emulates the MOS 8371 which was used by Commodore in many revisions of the A500 and A2000. It is the most commonly used OCS version of this chip.

    -
  • -
  • ECS (1MB)

    -

    This option emulates the MOS 8372A. It is the first ECS revision of this chip. Apart from some minor details, the ECS variant differs mainly in the size of the addressable memory space. While the OCS models can only address 512 KB of Chip Ram, the ECS version was capable of addressing twice as much.

    -
  • -
  • ECS (2MB)

    -

    This option emulates the MOS 8375, which increased the range of addressable Chip Ram to 2 MB. It is used in the A500+ and A600, released in 1991 and 1992 respectively.

    -
  • -
-
-
-

Denise

-
    -
  • OCS

    -

    This option selects the MOS 8362R8 which was used in all revisions of the Amiga 1000, Amiga 500, and Amiga 2000.

    -
  • -
  • ECS

    -

    This option selects the MOS 8373R4. The chip is sometimes referred to as HiRes Denise and was used in the Amiga 500+ and the Amiga 3000. Compared to its predecessor, it supports additional graphics modes and features an advanced sprite unit. It also offers a special Border Blank mode, which causes the border to be drawn in black color instead of the currently selected background color. Some games use this feature to surround the drawing area with a nicer looking border.

    -
  • -
-
-
-

CIAs

-

The Amiga utilizes MOS 8520 CIAs to interact with peripheral devices. These chips are similar to the well-known MOS 6526 revisions used in the C64. However, there are subtle differences. For example, Commodore replaced the TOD clock with a native 24-bit counter and supplied the CIA timers with an auto-start mechanism.

-
    -
  • DIP

    -

    This option selects the DIP version of the MOS 8520. The DIP models are the default option as they were used in all classic Amigas.

    -
  • -
  • PLCC

    -

    This option selects the PLCC version of the MOS 8520, which was used e.g. in the Amiga 600. The differences to the DIP version are extremely subtle.

    -
  • -
-
-
-

RTC

-

The term RTC refers to the Amiga’s real-time clock. The first Amiga, the Amiga 1000, never shipped with such a device and it was quite cumbersome to add one. For the Amiga 500, adding an RTC was easy, as many trapdoor memory expansion cards shipped with such a device on board. They are easily recognized by the battery needed to keep the register contents alive. In the Amiga 2000, the real-time clock was soldered directly to the motherboard. In hindsight, this was a bad idea, as the battery, which was also soldered directly to the motherboard, is now the number one death bringer of such machines. Many of us have lost their beloved devices because of the damage caused by the acid of a leaking battery.

-

vAmiga offers the following configuration options:

-
    -
  • None

    -

    If this option is selected, no real-time clock is emulated.

    -
  • -
  • Oki

    -

    This option emulates a MSM6242B real-time clock, manufactured by Oki Semiconductor. Commodore used this chip in the A2000 and the A500+.

    -
  • -
  • Ricoh

    -

    This option emulates a RF5C01A real-time clock, manufactured by Ricoh, Ltd. Commodore used this chip in the A3000 and the A4000.

    -
  • -
-
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/References/Configuration/Compatibility.html b/Documentation/_build/html/References/Configuration/Compatibility.html deleted file mode 100644 index 66c61d131..000000000 --- a/Documentation/_build/html/References/Configuration/Compatibility.html +++ /dev/null @@ -1,284 +0,0 @@ - - - - - - - - - Compatibility Panel — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

Compatibility Panel

-

Use this panel to configure the emulation accuracy.

-

Compatibility Panel

-
-

Blitter accuracy

-

Amiga supports three Blitter accuracy levels. Level 0 is the fastest option. In this mode, all data is moved together in a single chunk when the BLTSIZE register is written. Although this option is far from being accurate, many games do work with this option. In level 1, the Blitter also moves the data in a single chunk, just as in level 0; however, bus timing is emulated afterwards. This means that vAmiga blocks the data bus in the exact same cycles as the real Blitter would. Level 2 is recommended in all scenarios where high accuracy is required. In this mode, the Blitter is emulated cycle by cycle. It transfers data in the exact same cycles as the real Blitter would.

-
-
-

Chipset Features

-
    -
  • Emulate TOD bug

    -

    The Amiga CIAs exhibit a bug in the circuitry of the 24-bit counter, commonly referred to as the TOD bug. The bug is part of the increment logic which can falsely trigger a TOD interrupt. This happens when the alarm value matches the counter values at the time when the lowest three nibbles finished to increment.

    -
  • -
  • Emulate dropped register writes

    -

    Under certain circumstances writing to a DMA pointer register has no effect. On a real Amiga this happens when the pointer register has been used internally exactly one cycle before the update would happen. If you enable this option, vAmiga will check for the drop condition and abort the write operation if necessary.

    -
  • -
-
-
-

Timing

-
    -
  • Sync CIA accesses with E-clock

    -

    Both Complex Interface Adapters (CIAs) are driven by the so-called E-clock, a special signal that is output by the CPU with a frequency equal to one tenth of the native clock rate. Before the CPU can read or write a CIA register, it must synchronize with the E-clock, which slightly slows down program execution. If you disable this option, synchronization with the E-clock is skipped. In this case vAmiga can access CIA registers as fast as all other memory cells.

    -
  • -
-
-
-

Floppy drives

-
    -
  • Speed

    -

    vAmiga offers two different DMA modes for floppy drives: Standard DMA mode (compatible, but slow) and Turbo DMA mode (fast, but less compatible).

    -
      -
    • Standard DMA mode

      -

      In standard DMA mode, vAmiga performs three DMA accesses per scan line, just like the original Amiga. To speed up, drives can be operated with an acceleration factor. In this case, the emulator transfers multiple words in a single DMA slot, something the original machine obviously can’t do.

      -
    • -
    • Turbo DMA mode

      -

      Turbo DMA is applied when the drive speed is set to Infinite. In this mode, data is transferred immediately when the DSKLEN register is written to. Although this mode is far from precise, many games and demos can be run in this mode without any issues.

      -
    • -
    -
  • -
  • Emulate mechanical delays

    -

    When this option is enabled, vAmiga applies more stringent timing. That is, it emulates the acceleration and deceleration phases of the drive motor as well as the delay caused by the movement of the drive head from one cylinder to the next.

    -
  • -
  • Piracy

    -

    These options are rarely needed, but can help to bypass copy protection mechanisms.

    -
      -
    • Ignore writes to DSKSYNC

      -

      This option locks the DSKSYNC register. This means that any attempt to change the default SYNC word will be ignored by the emulator.

      -
    • -
    • Always find a SYNC mark

      -

      This option instructs vAmiga to issue a disk sync interrupt even for tracks that do not contain a SYNC word.

      -
    • -
    -
  • -
-
-
-

Sprites

-
    -
  • Collision detection

    -

    vAmiga allows to disable the collision checking circuity, which is part of Denise. By default, collision checking is disabled because it is expensive to emulate in software and is only needed by a few titles such as Archon or Rotor.

    -
  • -
-
-

Keyboard

-
    -
  • Transmit key codes bit by bit

    -

    The keyboard is a central input device of the Amiga. While Commodore had equipped the Amiga 1000 and the Amiga 2000 with an external keyboard, they decided to integrate the keyboard directly into the case of the Amiga 500. This was only an aesthetic difference, though, as the connection to the motherboard was always the same. The keyboard first generates a key code for each pressed key. After that, it sends the code bit by bit to one of the two CIAs. As soon as the last bit is received, an interrupt is generated and the interrupt handler takes over. By enabling this option, vAmiga emulates the bit-by-bit transmission exactly as described. Disabling this option tells vAmiga to skip the transmission phase and to write the generated keycode directly into the corresponding CIA register. This speeds up emulation, but is less accurate.

    -
  • -
-
-
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/References/Configuration/Memory.html b/Documentation/_build/html/References/Configuration/Memory.html deleted file mode 100644 index 603e20322..000000000 --- a/Documentation/_build/html/References/Configuration/Memory.html +++ /dev/null @@ -1,261 +0,0 @@ - - - - - - - - - Memory Panel — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

Memory Panel

-

Use this panel to configure the memory configuration and basic access properties.

-

Memory Panel

-
-

Ram

-

The Amiga distinguishes three types of random access memories:

-
    -
  • Chip RAM

    -

    Chip RAM refers to the factory-installed memory that is located on the motherboard. It is the most flexible RAM, as it can be accessed by both the CPU and the custom chipset. The Amiga 1000 had a limited amount of 256 KB on board, which could be expanded with a 256 KB RAM module plugged into an expansion slot which was located on the front of the computer case. The Amiga 500, which was released later, was shipped with 512 KB straight from the factory. The Amiga 2000 was released in different versions over time. The original Amiga 2000 shipped with 512 KB, just like the Amiga 500 did. Later versions were equipped with 1 MB.

    -
  • -
  • Slow RAM

    -

    The Amiga supports two types of RAM extensions. The first type is called Slow RAM or Ranger RAM. In the Amiga 500 case, Slow RAM is added by inserting a memory expansion card into the trapdoor slot at the bottom of the computer case.

    -

    Slow RAM has a somewhat bad reputation because it combines the disadvantages of two worlds. First, it cannot be accessed by the custom chips, as a result, it cannot be used for any data that is processed directly by the Blitter or Copper. Second, it uses the same memory bus as the Chip RAM; this means that Slow RAM cannot be accessed during DMA cycles, even though the RAM itself is not accessible via DMA.

    -
  • -
  • Fast RAM

    -

    Fast RAM is the third type of RAM expansion. This type of RAM is directly connected to the CPU, which means that it is not accessible to the custom chips, just like Slow RAM isn’t. However, since Fast RAM is not connected to the Chip RAM bus, the CPU can access this memory type in parallel to DMA activity. This is where the name Fast RAM stems from. The memory accesses themselves are not accelerated compared to Chip RAM or Slow RAM.

    -

    The default setting is 0 KB, because some Amiga programs refuse to work when Fast RAM is present.

    -
  • -
-

Since 512 KB of Chip RAM was very little and Fast RAM was very expensive, 512 KB of Chip RAM and 512 KB of Slow RAM was a common memory configuration at the time. Only a few users owned a Fast RAM memory expansion due to its high price.

-
-
-

Memory layout

-
    -
  • Bank map

    -

    The original Amigas use a 24-bit address bus, which means that they are capable of addressing 16 MB of memory. We can think of this memory as being divided into chunks of 64 KB, which we refer to as memory banks. The bank map determines where specific components are mapped at or mirrored to. For example, Chip RAM always starts at address $000000, while Slow RAM usually shows up at address $C00000. Mirroring means that we can access the same location, such as the register for setting the background color, through several different addresses. Thus a programmer could just as easily use an address from the mirrored range instead of the officially documented address, and many programmers have done so in the past. Unfortunately, the mirrored ranges are not the same in all Amiga models, which means that we have to tell the emulator which memory layout should be used. This is the purpose of this configuration option.

    -

    vAmiga supports four different bank maps: A500, A1000, A2000A, and A2000B. The bank maps mainly differ in the memory location of the RTC register space. In the first Amigas, namely the A1000 and the A2000A, the real-time clock was accessed through memory bank $D8. In the A500 and the most common A2000 model, the A2000B, Commodore mapped the real-time clock into memory bank $DC.

    -

    Other differences are related to mirroring. For example, the official location of the custom register space is memory bank $DF. However, this bank is usually mirrored multiple times, which means that the custom registers can also be accessed via other memory addresses. E.g., on older Amigas, the custom register space is mirrored in bank $DC, which is the same bank where later Amigas map in the real-time clock.

    -
  • -
  • Init Pattern

    -

    This configuration option determines how the memory should be initialized at startup. You can choose between random values, all zeros or all ones.

    -
  • -
  • Unmapped area

    -

    This option tells vAmiga what to put on the data bus when an unmapped memory location is accessed. Besides telling the emulator to leave the data bus in a floating state, you can choose to return all zeros or all ones. The first option is close to what happens in a real Amiga, but the current implementation is not 100% accurate. Any advice on how to improve emulation accuracy is very welcome.

    -
  • -
-
-
-

Chipset features

-
    -
  • Emulate Slow RAM Mirror

    -

    The ECS variants of Agnus have an interesting capability that the OCS variants do not. When an ECS Agnus is connected to 512 KB of Chip RAM and 512 KB of Slow RAM, it mirrors the Slow RAM pages into the second Chip RAM segment, making Slow RAM accessible for DMA. Now, the Blitter and Copper have full access to both RAMs. Move Any Mountain by Lazy Bones is an Amiga demo that relies on this feature. It was presented at the POLARIS computer party in 1993 and does not work when an OCS Agnus or an incompatible memory configuration is used.

    -

    This configuration option allows the user to enable or disable this feature. If an OCS Agnus is emulated or if the selected memory configuration does not match the 512 KB of Chip RAM + 512 KB of Slow RAM configuration, the selection has no effect. No mirroring will take place.

    -
  • -
  • Emulate Slow RAM Bus delays

    -

    As mentioned before, the CPU needs a free DMA cycle to access Slow RAM. By default, vAmiga emulates this behavior. Disabling this option removes this restriction, allowing the CPU to access Slow RAM at the same pace as Fast RAM. Please note that accelerating Slow RAM accesses may cause incompatibilities in rare occasions, as the emulated behavior now deviates from what we see on the real machine.

    -
  • -
-
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/References/Configuration/Peripherals.html b/Documentation/_build/html/References/Configuration/Peripherals.html deleted file mode 100644 index 67f7e8f6d..000000000 --- a/Documentation/_build/html/References/Configuration/Peripherals.html +++ /dev/null @@ -1,243 +0,0 @@ - - - - - - - - - Peripherals Panel — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

Peripherals Panel

-

Use this field to set up peripheral devices.

-

Peripherals Panel

-
-

Floppy Drives

-

Just like a real Amiga, vAmiga supports up to four floppy drives. The internal drive is labeled DF0 and is always present. The external drives are labeled DF1 to DF3. The internal drive is a 3.5” double-density drive providing a storage capacity of 880 KB per floppy disk. The external drives can be configured as double-density drives like the internal drive, or as high-density drives which provide twice the storage capacity. Back in the day, many users, including myself, had an external 5.25” floppy drive connected to their Amiga, mainly because of the much lower price of 5.25” floppy disks. However, such drives only offered a reduced storage capacity of 440 KB. Such single-density drives are not yet supported by vAmiga and will probably never be.

-
-
-

Hard Drives

-

Thanks to Michael Rasmussen, vAmiga is able to emulate hard drives. Up to four hard drive controllers are supported. Each controller occupies a Zorro II slot and identifies itself to the Amiga via the AUTOCONFIG mechanism at boot time.

-
-
-

Game Ports

-

The Amiga is equipped with two game ports for connecting input devices such as joysticks or mice. The connected input device can be selected via a popup menu. By default, vAmiga offers you to leave the port empty, to connect the internal mouse or to connect a keyboard-emulated joystick. If an external mouse or a compatible gamepad is present, the device is shown as another option in the popup menu.

-
-
-

Serial Port

-

vAmiga offers the following options for the serial port:

-
    -
  • No Device

    -

    No device is attached. This is the default option.

    -
  • -
  • Null Modem Cable

    -

    vAmiga is capable of emulating a null modem cable. By opening two instances of vAmiga on your computer, you can connect them via the null modem cable and play e.g. a nice game of Battle Chess with two Amigas fighting each other.

    -
  • -
  • Loopback Cable

    -

    A loopback cable connects the output pins of the serial port with its input pins. Such a cable is required, e.g., to run the serial port test built into Amiga Test Kit:

    -

    Amiga Test Kit

    -
  • -
-
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/References/Configuration/Roms.html b/Documentation/_build/html/References/Configuration/Roms.html deleted file mode 100644 index 86a32c0da..000000000 --- a/Documentation/_build/html/References/Configuration/Roms.html +++ /dev/null @@ -1,227 +0,0 @@ - - - - - - - - - ROM Panel — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

ROM Panel

-

Use this panel to add ROM images to the emulator.

-

Rom Panel

-

When vAmiga is started for the first time, you will be taken directly to this panel. This is the place where you will manage an essential part of your virtual Amiga: The Kickstart ROM.

-
-

Kickstart ROM

-

ROM images are added via drag and drop. To install a Kickstart ROM, simply drop a ROM image into the upper drop zone. Immediately after the image has been dropped, vAmiga performs a two-stage check. In the first stage, the file size and the values of some magic bytes are verified. If the file size does not match or the magic byte sequence is unknown to the emulator, the ROM image is rejected. Otherwise, the emulator continues by comparing the CRC checksum of the ROM image with the entries of a small database. When the CRC checksum is found, the name of the ROM is displayed along with some other information such as the release date. In the screenshot above you can see that vAmiga has recognized the dragged-in file as an original Commodore Kickstart ROM 1.3. If the CRC checksum is unknown to the emulator, vAmiga classifies the ROM as Unknown. You can still start the emulator with it, but there is no guarantee that the emulator will work as expected.

-

Please note that vAmiga does not ship with any of the original Commodore ROMs. All Amiga ROMs are the intellectual property Cloanto™ and distributed for a fee. However, if you have purchased a Kickstart ROM legally, you can use it in vAmiga with no issues.

-

If you don’t have an original Kickstart at hand, you may choose to install the AROS ROM. The Amiga Research Operating System ROM is an open-source Kickstart variant which is freely redistributable. Two revisions of the AROS ROM are shipped with the emulator, which can be installed using the dropdown menu in the lower left corner. Unfortunately, not all Amiga programs are compatible with AROS, which is why I strongly recommend buying original ROMs.

-
-
-

Extension ROM

-

In case you decide to resort to the AROS Kickstart replacement, you will notice that there will be two ROMs installed in your virtual Amiga. This is due to the size of the AROS ROM, which significantly exceeds the original Kickstart size of 512 KB. For this reason, AROS has been split into two separate ROMs. The first one appears in the same memory range as the original Kickstart, the second one appears in the address range $E00000 - $E7FFFF.

-

ROM extensions can also be installed manually by dropping a ROM image into the lower drop zone. Unlike the Kickstart ROM, which always resides in the same address range, the expansion ROM can be mapped to different memory areas. As mentioned above, the AROS expansion ROM must be visible to $E0000 to function. Other expansion ROMs, however, are expected to be visible in the $F00000 - $F7FFFF address range. You can set the address range manually by selecting the memory range from the popup menu next to the expansion ROM.

-
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/References/Configuration/Video.html b/Documentation/_build/html/References/Configuration/Video.html deleted file mode 100644 index 907842c77..000000000 --- a/Documentation/_build/html/References/Configuration/Video.html +++ /dev/null @@ -1,290 +0,0 @@ - - - - - - - - - Video Panel — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

Video Panel

-

Use this panel to change the video settings. The Video panel is divided into two sub-panels: The Screen panel and the Effects panel. In the first one we can control basic image properties, the visible screen area and sync mode. The second panel allows us to fine-tune the shader pipeline. It allows us to configure various effects that try to mimic the look and feel of a CRT monitor from back in the day.

-
-

Monitor

-

Video Panel

-
-

Palette

-

This option is used to select the monitor type. Besides emulating a color monitor, which is the default option, different types of monochrome monitors can be emulated, such as amber or green monitors. As with a real monitor from back in the day, you can set three parameters that affect the color palette: brightness, contrast, and color.

-

The following screenshot shows how vAmiga looks on a monochrome monitor with a sepia color:

-

Sepia

-
-
-

Zoom

-

The zoom level defines the visible screen area and can be changed manually for the horizontal and vertical axis. The drop-down menu provides some predefined values from which you can choose.

-
-
-

Center

-

While the zoom level defines the dimensions of the visible screen area, the two centering parameters determine the position of the center point. Please note that changing these parameters has no effect if the zoom level is zero. In this case, the visible screen area corresponds to the entire texture, which makes it impossible to move the center point.

-
-
-

Refresh

-

vAmiga supports two methods for synchronizing the emulator thread. The default method is based on timers. In this mode the emulator puts itself to sleep after a single frame has been computed. When the thread wakes up, the next frame is computed and so on. This method is the most flexible, as it supports arbitrary frame rates. I.e. vAmiga computes 50 frames per second in PAL mode and 60 frames per second in NTSC mode. However, there is a problem associated with this method. Since the emulator thread is not synchronized with the graphic loop, it may happen that some frames are either dropped or displayed twice.

-

In video games, a common workaround is to have the graphic loop trigger the image calculation. This method is usually called VSYNC because the image provider and the graphic loop no longer work independently. When VSYNC is enabled in vAmiga, something similar happens. The emulator thread no longer sets a timer to wake up the emulator thread. Instead, it waits for a wake-up signal from the graphic backend. The result is that the number of images requested exactly matches the number of images drawn. However, this method has its pitfalls, too. Since a modern TFT display normally updates at 60Hz, vAmiga is asked to calculate 60 frames per second. This is fine for NTSC, but not for PAL. If a PAL machine is emulated in this mode, it will run slightly faster than the original machine.

-

However, with modern Macs, this problem is easily solved. With the introduction of ProMotion technology, Macs can be configured to operate at user-defined refresh rates. On such machines, the default refresh rate can be lowered to 50 Hz in the system settings. As a result, the Amiga runs at its original speed again.

-

Mac Display Settings

-
-
-
-

Effects

-

vAmiga utilizes a sophisticated graphic pipeline that allows the emulator texture to be manipulated in various ways.

-

Effects Panel

-
-

Upscaling

-

The GPU pipeline of vAmiga includes two pixel upscaling stages. In the first stage, in-texture upscaling is performed to all lores lines. In this stage, the texture size remains unchanged. The second stage is a more traditional upscaling stage where the texture size is doubled. The selected upscaling algorithm is applied to both lores and hires pixels.

-

For each stage, the upscaling algorithm can be selected independently. Currently vAmiga supports the EPX and xBR upscaling algorithms. If upscaling is not desired, one or both stages can be disabled.

-

Original image -Upscaled image

-
-
-

Scanlines

-

Three scanline modes are supported: None, Embedded and Superimposed.

-
    -
  • Embedded Scanline Mode

    -

    In this mode, scanlines are emulated by darkening every other scanline of the emulator texture. This method has the disadvantage of creating Moiré patterns. To avoid these patterns, the height of the emulator window must be adjusted so that each line of the emulator texture maps to a unique line on the native screen. vAmiga can set the correct height for you. All you need to do is to select the Adjust menu item in the Window menu.

    -
  • -
  • Superimposed Scanline Mode

    -

    In this mode, scanlines are generated by the fragment shader. The fragment shader is applied very late in the graphic pipeline and already working on the final texture. As a result, Moiré effects are no longer possible. A disadvantage of this method is that the dimensions of the scanlines are now independent of the height of the emulator window. This means that the number of displayed scanlines does no longer match the number of scanline we would see on a real CRT monitor.

    -

    Original image -Scanlines

    -

    Dot Mask

    -

    vAmiga can emulate various dot mask patterns to emulate the small red, green and blue dots used by a real CRT monitor to compose the image.

    -

    Original image -Dot Mask

    -

    Flicker

    -

    PAL or NTSC screens are designed to transmit the image in the form of 50 or 60 fields per second. A picture consists of two fields, one containing all even lines and the other containing all odd lines. This results in an output rate of 25 frames for PAL and 30 frames for NTSC. In the default display modes, the Amiga uses the same pixel information for both fields, resulting in a stable picture at 50 or 60 Hz. However, the Amiga had the ability to double the vertical resolution by using different images for both fields. These modes are called interlace modes. Since both images only repeat 25 or 30 times per second, the image flickers for the human eye. vAmiga is able to emulate flickering in different intensities.

    -

    Back in the day, Flicker Fixer was a popular, albeit expensive, product. By buffering the video image, it managed to produce a smooth picture at twice the vertical resolution. To mimic what Flicker Fixer did back then, simply disable flicker emulation in vAmiga.

    -
  • -
-
-
-

Blur

-

When this option is enabled, vAmiga adds another stage to the graphics pipeline that applies a Gaussian blur filter to the upscaled image.

-

Original image -Blur

-
-
-

Bloom

-

When a bright object is displayed on a dark background, the white light spreads out a bit when displayed on a CRT monitor. As a result, the object looks as if it was slightly glowing. This effect is called blooming. By activating this option, vAmiga will try to reproduce this effect.

-

Original image -Bloom

-
-
-

Rays

-

A CRT tube uses three separate electron beams, one for each color channel. Each beam produces a separate image on the phosphor layer. When the electron beams are aligned, the color layers appear to be stacked precisely on top of each other and produce a crisp image. If the electron beams get misaligned, color artifacts occur because the three color layers are now shifted against each other. vAmiga can emulate this effect with varying intensity.

-

Original image -Misaligned

-
-
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/References/Configuration/index.html b/Documentation/_build/html/References/Configuration/index.html deleted file mode 100644 index 36388ab10..000000000 --- a/Documentation/_build/html/References/Configuration/index.html +++ /dev/null @@ -1,226 +0,0 @@ - - - - - - - - - Virtual Machine Settings — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

Virtual Machine Settings

-

The virtual machine settings include all configuration options that apply to a single emulator instance. The settings dialog can be opend via the Machine menu or by clicking the corresponding icon in the toolbar. The available options are organized in several tabs:

- -
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/References/FileFormats.html b/Documentation/_build/html/References/FileFormats.html deleted file mode 100644 index b012b71b9..000000000 --- a/Documentation/_build/html/References/FileFormats.html +++ /dev/null @@ -1,245 +0,0 @@ - - - - - - - - - Supported File Formats — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

Supported File Formats

-
-

Floppy disks

-

vAmiga supports the following file formats for floppy disks:

-
    -
  • ADF format

    -

    ADF files contain a byte dump of all sectors of an Amiga diskette. The format is extremely simple in structure, since it does not store any header information. The ADF format is the most widely used format for Amiga floppy disks and almost all non-copy-protected titles are available in form of ADF files.

    -
  • -
  • Extended ADF format

    -

    The extended ADF format has been created to store copy-protected disks or disks that were formatted in a non-standard format. It has a much more complicated structure than the standard ADF format and offers different methods to represent track data. For example, the format is able to store the uninterpreted MFM data stream of single tracks or the whole disk.

    -
  • -
  • DMS Format

    -

    DMS files store a digital image of an Amiga floppy disk, just like ADFs. However, the internal representation is much more complicated. The format is very popular in the demo scene. Thus, you will find many demos encoded in this format.

    -
  • -
  • EXE Format

    -

    vAmiga also supports pure Amiga executables. When such a file is passed to the emulator, vAmiga creates a floppy disk on-the-fly and copies the executable to it. It also makes the floppy bootable by adding a boot block and a startup sequence that loads the executable.

    -
  • -
  • IMG Format

    -

    Image files are floppy disks in MS-DOS format. Inserting such a floppy disk makes sense only if you use special software that can read such floppy disks.

    -
  • -
  • Folders

    -

    vAmiga allows directories of the host computer to be used in the form of floppy disks. When a directory is provided by drag-and-drop, the emulator tries to write all files of the directory to an empty floppy disk. If the floppy disk has sufficient space for all files, the disk can be used inside the emulator or exported, e.g., in form of an ADF file.

    -
  • -
-
-
-

Hard drives

-
    -
  • HDF Format

    -

    HDF files are the equivalent of ADF files for hard disks. An HDF file contains a byte dump of all sectors of a hard disk, just as an ADF file contains a byte dump of all sectors of a floppy disk.

    -
  • -
-
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/References/Preferences/Controls.html b/Documentation/_build/html/References/Preferences/Controls.html deleted file mode 100644 index fb9fb6589..000000000 --- a/Documentation/_build/html/References/Preferences/Controls.html +++ /dev/null @@ -1,228 +0,0 @@ - - - - - - - - - Controls Panel — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

Controls Panel

-

Use this section to configure the mouse, joysticks, and joystick emulation keys.

-

Controls Panel

-
-

Mouse

-

vAmiga supports several ways to release and retain the mouse pointer. The conventional way is to use a special key combination. Since different emulators use different combinations, vAmiga allows the user to choose between Alt+Cmd and Alt-Ctrl. The most convenient way to release the mouse is to activate the shake detector. When activated, rapidly move the mouse from left to right a few times to release the mouse.

-

vAmiga also offers several options for retaining the mouse. Besides using a special key combination, the emulator can be configured to retain the mouse when the user pushed the left button inside the emulator window or to retain the mouse automatically when the mouse pointer is dragged into the emulator window.

-
-
-

Joysticks

-

The emulator offers a built-in multi-shot mode. You can adjust the firing frequency and choose whether to fire constantly or in volleys with a certain number of bullets.

-
-
-

Emulation keys

-

As an alternative to a real joystick, you can use the emulator with a key-emulated joystick. vAmiga allows you to predefine two sets of emulation keys. Mouse buttons can be mapped, too. This is a handy solution for the right and middle mouse button, which are not physically present on most Apple mice.

-
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/References/Preferences/Devices.html b/Documentation/_build/html/References/Preferences/Devices.html deleted file mode 100644 index a3644c5da..000000000 --- a/Documentation/_build/html/References/Preferences/Devices.html +++ /dev/null @@ -1,244 +0,0 @@ - - - - - - - - - Devices Panel — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

Devices Panel

-

Use this field to configure external USB gamepads.

-

Devices Panel

-

After plugging in an external USB device, vAmiga checks the device for compatibility. If a suitable gamepad is detected, vAmiga allows the user to adjust the axis assignment. vAmiga comes with a list of known devices and automatically chooses the correct axis assignment when such a device is detected. For gamepads that are not known to the emulator, you have a good chance of getting it to work by trying some axis assignments manually.

-
-

Supported devices

-

At the time of writing this documentation, known devices include the following:

-
    -
  • Competition Pro SL-650212

  • -
  • Competition Pro SL-6602

  • -
  • Nimbus+

  • -
  • iNNEXT Retro (SNES)

  • -
  • Mayflash Magic-NS 1.2

  • -
  • XBox Carbon Black

  • -
  • XBox One Wired Controller

  • -
  • Sony DualShock 3

  • -
  • Sony DualShock 4

  • -
  • Sony DualShock 4 (2nd Gen)

  • -
  • Sony DualSense

  • -
  • HORIPAD for Nintendo Switch

  • -
  • The C64 Joystick

  • -
-
-
-

Supported USB adapters

-

With the help of a USB retro adapter you can also connect original Commodore joysticks. vAmiga has been tested with the following two adapters:

-
    -
  • aJoy Retro Adapter

  • -
  • RetroFun! Joystick Adapter

  • -
-

My personal recommendation is to invest in the Competition Pro SL-650212. It has lower latency than its predecessor, the SL-6602, and offers the best retro experience in my opinion. Also, I can recommend using an original Competition Pro from back in the day in combination with the RetroFun! joystick adapter.

-
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/References/Preferences/General.html b/Documentation/_build/html/References/Preferences/General.html deleted file mode 100644 index c12fd6c82..000000000 --- a/Documentation/_build/html/References/Preferences/General.html +++ /dev/null @@ -1,235 +0,0 @@ - - - - - - - - - General Panel — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

General Panel

-

Use this panel to change general settings, such as the screenshot and video format, or the behavior in fullscreen mode.

-

General Panel

-
-

Screenshots

-

The options in this category allow the user to customize the source, layout and target format of a screenshot.

-
-
-

Screen captures

-

vAmiga features a screen recorder that utilizes FFmpeg as a backend. The options in this category allow the user to set various recording parameters. Please note that FFmpeg cannot be bundled with the emulator due to licensing constraints. Before using the screen recorder, you must manually install FFmpeg on your computer.

-
-
-

Snapshots

-

vAmiga can be configured to take a snapshot at regular intervals. Originally, This option was added to master difficult games. Please keep in mind that snapshots are intended for being used as temporary save-points and not as a long-term preservation format. A snapshot created with the current version of vAmiga will most likely not be readable in the next.

-
-
-

Full screen mode

-

The first option lets you select the full-screen layout. The second option determines whether the ESC key should function as an emulation key or as a control key to exit the full screen mode.

-
-
-

Miscellaneous

-

The options in this category determine how vAmiga should react to certain events such as ejecting a floppy disk or closing an emulator window. For example, one option determines how vAmiga will behave when a floppy disk containing unsaved data is ejected. Unlike other emulators, vAmiga is designed to not modify media files. For example, if an ADF has been inserted into a floppy drive, the floppy disk can be modify without hesitation. The original ADF remains untouched. The disadvantage, however, is that you have to export a disk manually to preserve the new content.

-
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/References/Preferences/index.html b/Documentation/_build/html/References/Preferences/index.html deleted file mode 100644 index 184896e68..000000000 --- a/Documentation/_build/html/References/Preferences/index.html +++ /dev/null @@ -1,222 +0,0 @@ - - - - - - - - - Emulator Settings — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

Emulator Settings

-

The emulator settings include all configuration options that apply to all emulator instances simultaneously. To open the emulator settings, either select Settings… from the vAmiga menu or click on the corresponding icon in the toolbar. The available options are organized in three tabs:

-
-

Emulator Settings

- -
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/Tutorials/Exploring.html b/Documentation/_build/html/Tutorials/Exploring.html deleted file mode 100644 index c58554334..000000000 --- a/Documentation/_build/html/Tutorials/Exploring.html +++ /dev/null @@ -1,309 +0,0 @@ - - - - - - - - - Exploring the User Interface — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

Exploring the User Interface

-

In this tutorial, we will explore the most commonly used elements of the vAmiga user interface.

-
-

Toolbar

-

Many of the basic emulator properties can be controlled via the toolbar, which defaults to the following:

-

Toolbar

-

We will review the elements of the toolbar one by one.

-
-

Controls

-

The three buttons in the Control section allow us to control the emulator state:

-

Toolbar

-

The functionality of these buttons is what you might have already guessed:

-
    -
  • The left button pauses or resumes emulation.

  • -
  • The middle button performs a hard reset.

  • -
  • The right button switches the Amiga on or off.

  • -
-
-
-

Preferences

-

Toolbar

-

The two buttons in the Preferences section let us configure vAmiga. The left button opens the emulator settings window, which manages the settings that apply to all emulator instances simultaneously.

-

Preferences

-

All available options are described in a separate document. For the purpose of this tutorial, we do not need to change anything here and can proceed to the next option right away.

-

The right button opens the Configuration window where the virtual machine is configured. The options are organized in tabs, similar to the emulator settings window. You are already familiar with the first tab if you have read the Getting started tutorial. It is the tab where the ROM of the Amiga is configured.

-

Configuration

-

All available options are described in a separate document. Please note that all settings made in the Configuration are specific to a single emulator instance. Therefore, it is possible to run two emulator instances with different configurations side by side.

-
-
-

Keyboard

-

Toolbar

-

Although the Amiga is quite an aged computer by now, it already utilized a keyboard whose layout was quite similar to the ones used today. Therefore, in vAmiga you will be using the native Mac keyboard for typing, and for most Amiga keys you will find a perfect match on your native keyboard. However, there are exceptions. For example, the Amiga is equipped with a special Help key that has no direct counterpart on the Mac keyboard. Also, some Mac keys are directly linked to operating system actions, which affects emulation. The most prominent examples are the two Command keys that are used to trigger operating system actions.

-

In cases where you need to press a key that is not directly accessible from your native keyboard, the virtual keyboard can be used. If you click the corresponding icon in the toolbar, the virtual keyboard will open as a sheet on top of the emulator window:

-

Virtual keyboard

-

The keys on the virtual keyboard can be clicked with either the left or the right mouse button:

-
    -
  • Left Button

    -

    When the left mouse button is used, the selected key is pushed down and automatically released after a short delay. Use this option if you wish to press a single key on the keyboard.

    -
  • -
  • Right button

    -

    When the right mouse button is used, the selected key is permanently pushed down or permanently released if it was pushed down. Use this option if you want to press a specific key combination, e.g. the reset combination Ctrl+Amiga+Amiga as shown in the screenshot.

    -
  • -
-

As soon as a key is pressed with the left mouse button, the virtual keyboard disappears. However, it is also possible to open the virtual keyboard as a separate window that can reside next to the emulator window. To open the virtual keyboard as window, press Cmd-K, the key equivalent for the Show… item in the Keyboard menu.

-
-
-

Game Ports

-

The two gameport icons allow us to quickly switch between the input devices connected to the gameports of the Amiga.

-

Toolbar

-

All available devices are displayed in a popup menu:

-

Gameport menu

-

The mouse refers to the Mac’s internal mouse. Note that the Mac does not distinguish between the mouse and the touchpad. This means that both devices cannot be used independently. The next two items refer to keyboard-emulated joysticks. vAmiga differentiates between two sets of keys, which can be configured in the emulator settings. The last two items are placeholders, which are currently grayed out. As soon as a compatible gamepad is connected to the host, e.g. a compatible USB joystick, the new device will appear in one of the placeholder slots.

-
-
-

Snapshots

-

The three toolbar icons in this section can be used to manage snapshots. Snapshots are frozen emulator states that can be restored at a later time.

-

Toolbar

-
    -
  • The left button creates a snapshot and adds it to the snapshot storage.

  • -
  • The middle button reverts to the emulator state recorded in the most recent snapshot.

  • -
  • The right button opens the snapshot browser.

    -

    Snapshot browser

    -

    The snapshot browser is to vAmiga what Time Machine is to the Mac. It lets us browse through the snapshot memory in a graphical way.

    -
  • -
-

Please note that snapshots are not stored permanently. The next time you start vAmiga, you will start over with an empty snapshot storage. This is because snapshots were originally intended as a safe-point mechanism for mastering difficult games. Snapshots were never intended for long-term preservation of emulator states, and never will be, although many users would like to use them that way. The reason is that snapshots do not only contain Amiga specific data like the RAM contents or the values of CPU registers. It also contains the values of many emulator-specific variables that have no direct equivalent on the real machine. The set of internal variables usually changes from release to release, and so does the snapshot format. Therefore, you can almost be certain that snapshots taken with the current version of vAmiga will no longer work when the next version comes out.

-
-
-

Inspectors

-

A major design goal of vAmiga was to make the emulated Amiga as transparent as possible. To achieve this goal, vAmiga offers a number of tools that give the user insight into the Amiga’s internal workings. The Inspectors section of the toolbar grants access to these tools.

-

Toolbar

-
-

Inspector Panel

-

The Inspector is the primary place to retrieve information about the current state of the emulator. It provides several tabs where the current state of various components can be examined. The first tab is the CPU tab, which looks like this:

-

Inspector panel

-

The panel displays the currently executed program and the contents of all CPU registers. The CPU panel is also the gateway to the CPU debugger. We can use it to single-step through the currently executing instruction stream or to set breakpoints and watchpoints.

-
-
-

Monitor Panel

-

The monitor panel provides additional debugging aids:

-

Monitor panel

-

The left column contains the controls for the DMA debugger, which can be used to visualize all memory bus accesses in real time. When enabled, the emulator texture is overlaid with an additional graphics layer that visualizes the bus owner for Chip or Slow RAM accesses. The following screenshot shows a scene from Rink a Dink with the DMA debugger enabled.

-

DMA debugger

-

The yellow and brown dots represent Copper and Blitter accesses, respectively. The red dots mark the memory refresh cycles and the pink dots the DMA slots for transferring audio data. Bitplane DMA is visualized in cyan. The scene reveals a lot about the inner workings of this demo. The creators decided to use a very small bitplane window that just covers the polygon. This bitplane window is permanently relocated as the polygon moves. This small YouTube video shows what Rink a Dink looks like when run in vAmiga with the DMA debugger enabled. If you don’t want to watch the entire video, you can fast forward at 1:20. Here you can see the animated polygon in action.

-

The center area of the monitor panel controls the so-called activity monitors. When activated, the texture of the emulator is overlaid with small displays giving insight into the activity of various Amiga components:

-

Activity monitors

-

The elements in the right column control the stencil feature. With this feature, vAmiga is able to erase certain graphic layers. For example, it is possible to remove all pixels of a certain playfield or sprite. The removed pixels are replaced by the pixels of a checkerboard pattern that looks like it shines through holes in the emulator texture, especially in animated scenes.

-

Stencils

-
-
-

Retro Shell

-

The third button in the Inspectors section opens Retro Shell, vAmiga’s text-based debug console. The shell can be used to control vAmiga with a variety of text commands.

-

Retro Shell

-

Retro Shell can also process script files. This functionality is used extensively by vAmiga’s test suite (vAmigaTS) to perform automatic regression tests. As a normal user, you will most likely never need to use the shell, since most of the emulator’s functions are accessible through the graphical user interface.

-
-
-
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/Tutorials/GettingStarted.html b/Documentation/_build/html/Tutorials/GettingStarted.html deleted file mode 100644 index d629fcb5c..000000000 --- a/Documentation/_build/html/Tutorials/GettingStarted.html +++ /dev/null @@ -1,246 +0,0 @@ - - - - - - - - - Getting Started — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - -
-
-
-
- -
-

Getting Started

-

This tutorial describes how to launch vAmiga and install a Kickstart ROM.

-
-

Installing vAmiga

-

vAmiga is a native Mac application and as easy to install as most other Mac software. Download the latest version from the main page and copy the executable into the application folder.

-

vAmiga’s deployment target is macOS 12 (Monterey) which means that you can’t run the app on earlier macOS releases. Please note that vAmiga is only extensively tested with the latest macOS version. Thus, compatibility problems may well occur with older macOS versions.

-

Please keep in mind that vAmiga has been developed with limited work-power leaving no room for supporting older macOS releases. You can always extract older version from the source-code repository, but you will be on your own by doing so.

-
-
-

Installing a Kickstart ROM

-

Emulating an Amiga requires a Kickstart ROM. Since the original Amiga ROMs are the intellectual property of Cloanto™, they cannot be shipped with the emulator. Thus, when opening vAmiga for the first time, the emulator will greet you with a ROM dialog:

-

Inspectors

-

In this dialog, a Kickstart ROM can be added via drag and drop. If you are the legal owner of a ROM image, you can easily install it by dragging it over the ROM icon:

-

Inspectors

-

Once the ROM is installed, the emulator is ready to be powered on. To do so, click the power button and have fun with your new old Amiga:

-

Inspectors

-

In case you don’t own a legal ROM, you can alternatively start vAmiga with the free AROS Kickstart replacement. AROS ROMs ship with the emulator and can be selected from the Install ROM popup-menu located in the lower left corner.

-

At you can see below, the popup menu is presently grayed out therefore inaccessible. This is to protect against accidental changes to the Kickstart ROM while the emulator is running. To access the menu, turn off the emulator first by clicking on the lock icon.

-

Inspectors

-

After the emulator has been powered off, the AROS ROMs can be installed with a single click:

-

Inspectors

-

Again, clicking the power button starts the emulator. With the free Kickstart ROM replacement installed, the AROS boot screen shows up:

-

Inspectors

-

Even though the AROS ROMs are a great achievement of the open source community, we recommend installing original Commodore ROMs as they offer much higher compatibility.

-

Please keep in mind that vAmiga will not remember the ROM settings by default, i.e., the next time the emulator is started, the ROM dialog will appear again. If you wish to use the currently installed ROM permanently, click the Use as Default button next to the AROS button.

-
-
-

Inserting a floppy disk

-

Next, we’ll show how to insert a floppy disk. Thanks to the diligent work of many Amiga enthusiasts, almost all Amiga software from back in the day has been saved from decay and translated into modern data formats. The most important data format for the Amiga is the ADF format, which is a digital image of an Amiga floppy disk. On the Internet you will find countless ADFs and most likely your beloved titles from back then, too. Please note that despite their age, most Amiga titles are protected by copyright and may not be used without the permission of the rights holder.

-

The most convenient way to insert a floppy disk is by drag and drop. When an ADF file is dragged into the emulator window, four drop zones appear representing drives DF0 through DF3. Simply drop the file onto the drive in which you want to insert the disk.

-

Inserting a floppy disk

-

Shortly after dropping the disk onto the drop zone for drive DF0, the Amiga recognizes the inserted disk and starts to boot. In the example above, we’ve inserted a bootable version of Rink a Dink, a popular Amiga demo which was published in 1993 by Lemon. The demo works flawlessly with the AROS ROMs as it takes over the machine entirely.

-

Rink a dink

-
-
- -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/_images/68010.png b/Documentation/_build/html/_images/68010.png deleted file mode 100644 index bb8412c96..000000000 Binary files a/Documentation/_build/html/_images/68010.png and /dev/null differ diff --git a/Documentation/_build/html/_images/AmigaTestKitSerial.png b/Documentation/_build/html/_images/AmigaTestKitSerial.png deleted file mode 100644 index a346ea6c0..000000000 Binary files a/Documentation/_build/html/_images/AmigaTestKitSerial.png and /dev/null differ diff --git a/Documentation/_build/html/_images/activityMonitors.png b/Documentation/_build/html/_images/activityMonitors.png deleted file mode 100644 index 64374aa0f..000000000 Binary files a/Documentation/_build/html/_images/activityMonitors.png and /dev/null differ diff --git a/Documentation/_build/html/_images/audioPanel.png b/Documentation/_build/html/_images/audioPanel.png deleted file mode 100644 index 01683d396..000000000 Binary files a/Documentation/_build/html/_images/audioPanel.png and /dev/null differ diff --git a/Documentation/_build/html/_images/battlechess1.png b/Documentation/_build/html/_images/battlechess1.png deleted file mode 100644 index 078875e57..000000000 Binary files a/Documentation/_build/html/_images/battlechess1.png and /dev/null differ diff --git a/Documentation/_build/html/_images/battlechess2.png b/Documentation/_build/html/_images/battlechess2.png deleted file mode 100644 index 551437489..000000000 Binary files a/Documentation/_build/html/_images/battlechess2.png and /dev/null differ diff --git a/Documentation/_build/html/_images/battlechess3.png b/Documentation/_build/html/_images/battlechess3.png deleted file mode 100644 index e618505d9..000000000 Binary files a/Documentation/_build/html/_images/battlechess3.png and /dev/null differ diff --git a/Documentation/_build/html/_images/battlechess4.png b/Documentation/_build/html/_images/battlechess4.png deleted file mode 100644 index 044bef051..000000000 Binary files a/Documentation/_build/html/_images/battlechess4.png and /dev/null differ diff --git a/Documentation/_build/html/_images/battlechess5.png b/Documentation/_build/html/_images/battlechess5.png deleted file mode 100644 index 11e444d56..000000000 Binary files a/Documentation/_build/html/_images/battlechess5.png and /dev/null differ diff --git a/Documentation/_build/html/_images/busCycleDiagram.png b/Documentation/_build/html/_images/busCycleDiagram.png deleted file mode 100644 index 89f0851e1..000000000 Binary files a/Documentation/_build/html/_images/busCycleDiagram.png and /dev/null differ diff --git a/Documentation/_build/html/_images/chipsetPanel.png b/Documentation/_build/html/_images/chipsetPanel.png deleted file mode 100644 index 8a6d88417..000000000 Binary files a/Documentation/_build/html/_images/chipsetPanel.png and /dev/null differ diff --git a/Documentation/_build/html/_images/classHierarchy.png b/Documentation/_build/html/_images/classHierarchy.png deleted file mode 100644 index 2135ca859..000000000 Binary files a/Documentation/_build/html/_images/classHierarchy.png and /dev/null differ diff --git a/Documentation/_build/html/_images/classHierarchy2.png b/Documentation/_build/html/_images/classHierarchy2.png deleted file mode 100644 index ea1b08f79..000000000 Binary files a/Documentation/_build/html/_images/classHierarchy2.png and /dev/null differ diff --git a/Documentation/_build/html/_images/classHierarchyThread.png b/Documentation/_build/html/_images/classHierarchyThread.png deleted file mode 100644 index 9bd635dc7..000000000 Binary files a/Documentation/_build/html/_images/classHierarchyThread.png and /dev/null differ diff --git a/Documentation/_build/html/_images/compatibilityPanel.png b/Documentation/_build/html/_images/compatibilityPanel.png deleted file mode 100644 index 83fdb0572..000000000 Binary files a/Documentation/_build/html/_images/compatibilityPanel.png and /dev/null differ diff --git a/Documentation/_build/html/_images/controlsPanel.png b/Documentation/_build/html/_images/controlsPanel.png deleted file mode 100644 index 29a616aca..000000000 Binary files a/Documentation/_build/html/_images/controlsPanel.png and /dev/null differ diff --git a/Documentation/_build/html/_images/defenderBloom.png b/Documentation/_build/html/_images/defenderBloom.png deleted file mode 100644 index fe8fd09fd..000000000 Binary files a/Documentation/_build/html/_images/defenderBloom.png and /dev/null differ diff --git a/Documentation/_build/html/_images/defenderBlur.png b/Documentation/_build/html/_images/defenderBlur.png deleted file mode 100644 index 9013eadde..000000000 Binary files a/Documentation/_build/html/_images/defenderBlur.png and /dev/null differ diff --git a/Documentation/_build/html/_images/defenderDotMask.png b/Documentation/_build/html/_images/defenderDotMask.png deleted file mode 100644 index b5e9bb6c0..000000000 Binary files a/Documentation/_build/html/_images/defenderDotMask.png and /dev/null differ diff --git a/Documentation/_build/html/_images/defenderMisaligned.png b/Documentation/_build/html/_images/defenderMisaligned.png deleted file mode 100644 index bf3289e57..000000000 Binary files a/Documentation/_build/html/_images/defenderMisaligned.png and /dev/null differ diff --git a/Documentation/_build/html/_images/defenderOriginal.png b/Documentation/_build/html/_images/defenderOriginal.png deleted file mode 100644 index 7101fe995..000000000 Binary files a/Documentation/_build/html/_images/defenderOriginal.png and /dev/null differ diff --git a/Documentation/_build/html/_images/defenderScanlines.png b/Documentation/_build/html/_images/defenderScanlines.png deleted file mode 100644 index 31f8069fb..000000000 Binary files a/Documentation/_build/html/_images/defenderScanlines.png and /dev/null differ diff --git a/Documentation/_build/html/_images/defenderUpscaled.png b/Documentation/_build/html/_images/defenderUpscaled.png deleted file mode 100644 index d98dbf6a7..000000000 Binary files a/Documentation/_build/html/_images/defenderUpscaled.png and /dev/null differ diff --git a/Documentation/_build/html/_images/devicesPanel.png b/Documentation/_build/html/_images/devicesPanel.png deleted file mode 100644 index 488c7068b..000000000 Binary files a/Documentation/_build/html/_images/devicesPanel.png and /dev/null differ diff --git a/Documentation/_build/html/_images/dmaDebugger.png b/Documentation/_build/html/_images/dmaDebugger.png deleted file mode 100644 index 7eff9690d..000000000 Binary files a/Documentation/_build/html/_images/dmaDebugger.png and /dev/null differ diff --git a/Documentation/_build/html/_images/dropzone.png b/Documentation/_build/html/_images/dropzone.png deleted file mode 100644 index 4d53ba0c6..000000000 Binary files a/Documentation/_build/html/_images/dropzone.png and /dev/null differ diff --git a/Documentation/_build/html/_images/effectsPanel.png b/Documentation/_build/html/_images/effectsPanel.png deleted file mode 100644 index 8d7876685..000000000 Binary files a/Documentation/_build/html/_images/effectsPanel.png and /dev/null differ diff --git a/Documentation/_build/html/_images/events.png b/Documentation/_build/html/_images/events.png deleted file mode 100644 index 62c5f75fc..000000000 Binary files a/Documentation/_build/html/_images/events.png and /dev/null differ diff --git a/Documentation/_build/html/_images/gameports.png b/Documentation/_build/html/_images/gameports.png deleted file mode 100644 index 4753fb619..000000000 Binary files a/Documentation/_build/html/_images/gameports.png and /dev/null differ diff --git a/Documentation/_build/html/_images/generalPanel.png b/Documentation/_build/html/_images/generalPanel.png deleted file mode 100644 index 87142cf9d..000000000 Binary files a/Documentation/_build/html/_images/generalPanel.png and /dev/null differ diff --git a/Documentation/_build/html/_images/generalPanel1.png b/Documentation/_build/html/_images/generalPanel1.png deleted file mode 100644 index 87142cf9d..000000000 Binary files a/Documentation/_build/html/_images/generalPanel1.png and /dev/null differ diff --git a/Documentation/_build/html/_images/inspectorPanel.png b/Documentation/_build/html/_images/inspectorPanel.png deleted file mode 100644 index 223a3f84b..000000000 Binary files a/Documentation/_build/html/_images/inspectorPanel.png and /dev/null differ diff --git a/Documentation/_build/html/_images/mappingCmd.png b/Documentation/_build/html/_images/mappingCmd.png deleted file mode 100644 index e33276f67..000000000 Binary files a/Documentation/_build/html/_images/mappingCmd.png and /dev/null differ diff --git a/Documentation/_build/html/_images/memoryPanel.png b/Documentation/_build/html/_images/memoryPanel.png deleted file mode 100644 index 96abae0b7..000000000 Binary files a/Documentation/_build/html/_images/memoryPanel.png and /dev/null differ diff --git a/Documentation/_build/html/_images/monitorPanel.png b/Documentation/_build/html/_images/monitorPanel.png deleted file mode 100644 index d9981417b..000000000 Binary files a/Documentation/_build/html/_images/monitorPanel.png and /dev/null differ diff --git a/Documentation/_build/html/_images/peripheralsPanel.png b/Documentation/_build/html/_images/peripheralsPanel.png deleted file mode 100644 index 6da515be6..000000000 Binary files a/Documentation/_build/html/_images/peripheralsPanel.png and /dev/null differ diff --git a/Documentation/_build/html/_images/proMotion.png b/Documentation/_build/html/_images/proMotion.png deleted file mode 100644 index 65d4f4ece..000000000 Binary files a/Documentation/_build/html/_images/proMotion.png and /dev/null differ diff --git a/Documentation/_build/html/_images/retroShell.png b/Documentation/_build/html/_images/retroShell.png deleted file mode 100644 index 32b41efc9..000000000 Binary files a/Documentation/_build/html/_images/retroShell.png and /dev/null differ diff --git a/Documentation/_build/html/_images/rinkadink.png b/Documentation/_build/html/_images/rinkadink.png deleted file mode 100644 index 45024bbc5..000000000 Binary files a/Documentation/_build/html/_images/rinkadink.png and /dev/null differ diff --git a/Documentation/_build/html/_images/romPanel.png b/Documentation/_build/html/_images/romPanel.png deleted file mode 100644 index 100c98013..000000000 Binary files a/Documentation/_build/html/_images/romPanel.png and /dev/null differ diff --git a/Documentation/_build/html/_images/romPanel1.png b/Documentation/_build/html/_images/romPanel1.png deleted file mode 100644 index 4c33add26..000000000 Binary files a/Documentation/_build/html/_images/romPanel1.png and /dev/null differ diff --git a/Documentation/_build/html/_images/roms1.png b/Documentation/_build/html/_images/roms1.png deleted file mode 100644 index 3b9c2e461..000000000 Binary files a/Documentation/_build/html/_images/roms1.png and /dev/null differ diff --git a/Documentation/_build/html/_images/roms2.png b/Documentation/_build/html/_images/roms2.png deleted file mode 100644 index bd8f601b4..000000000 Binary files a/Documentation/_build/html/_images/roms2.png and /dev/null differ diff --git a/Documentation/_build/html/_images/roms3.png b/Documentation/_build/html/_images/roms3.png deleted file mode 100644 index 15114f157..000000000 Binary files a/Documentation/_build/html/_images/roms3.png and /dev/null differ diff --git a/Documentation/_build/html/_images/roms4.png b/Documentation/_build/html/_images/roms4.png deleted file mode 100644 index f7027515c..000000000 Binary files a/Documentation/_build/html/_images/roms4.png and /dev/null differ diff --git a/Documentation/_build/html/_images/roms5.png b/Documentation/_build/html/_images/roms5.png deleted file mode 100644 index aa563b2bc..000000000 Binary files a/Documentation/_build/html/_images/roms5.png and /dev/null differ diff --git a/Documentation/_build/html/_images/roms6.png b/Documentation/_build/html/_images/roms6.png deleted file mode 100644 index fa5745cf9..000000000 Binary files a/Documentation/_build/html/_images/roms6.png and /dev/null differ diff --git a/Documentation/_build/html/_images/sepia.png b/Documentation/_build/html/_images/sepia.png deleted file mode 100644 index 52644dc10..000000000 Binary files a/Documentation/_build/html/_images/sepia.png and /dev/null differ diff --git a/Documentation/_build/html/_images/snapshotBrowser.png b/Documentation/_build/html/_images/snapshotBrowser.png deleted file mode 100644 index 0827cf54f..000000000 Binary files a/Documentation/_build/html/_images/snapshotBrowser.png and /dev/null differ diff --git a/Documentation/_build/html/_images/stateModel.png b/Documentation/_build/html/_images/stateModel.png deleted file mode 100644 index 6c268aff9..000000000 Binary files a/Documentation/_build/html/_images/stateModel.png and /dev/null differ diff --git a/Documentation/_build/html/_images/stencil.png b/Documentation/_build/html/_images/stencil.png deleted file mode 100644 index a8d2b421d..000000000 Binary files a/Documentation/_build/html/_images/stencil.png and /dev/null differ diff --git a/Documentation/_build/html/_images/superHires1.png b/Documentation/_build/html/_images/superHires1.png deleted file mode 100644 index b0dedf6d9..000000000 Binary files a/Documentation/_build/html/_images/superHires1.png and /dev/null differ diff --git a/Documentation/_build/html/_images/superHires2.png b/Documentation/_build/html/_images/superHires2.png deleted file mode 100644 index c38d13c9d..000000000 Binary files a/Documentation/_build/html/_images/superHires2.png and /dev/null differ diff --git a/Documentation/_build/html/_images/superHires3.png b/Documentation/_build/html/_images/superHires3.png deleted file mode 100644 index 5e5bdd4eb..000000000 Binary files a/Documentation/_build/html/_images/superHires3.png and /dev/null differ diff --git a/Documentation/_build/html/_images/superHires4.png b/Documentation/_build/html/_images/superHires4.png deleted file mode 100644 index 2506fe546..000000000 Binary files a/Documentation/_build/html/_images/superHires4.png and /dev/null differ diff --git a/Documentation/_build/html/_images/toolbar.png b/Documentation/_build/html/_images/toolbar.png deleted file mode 100644 index 7e894fcf7..000000000 Binary files a/Documentation/_build/html/_images/toolbar.png and /dev/null differ diff --git a/Documentation/_build/html/_images/toolbar1.png b/Documentation/_build/html/_images/toolbar1.png deleted file mode 100644 index 16ad082eb..000000000 Binary files a/Documentation/_build/html/_images/toolbar1.png and /dev/null differ diff --git a/Documentation/_build/html/_images/toolbar2.png b/Documentation/_build/html/_images/toolbar2.png deleted file mode 100644 index 04640a9c9..000000000 Binary files a/Documentation/_build/html/_images/toolbar2.png and /dev/null differ diff --git a/Documentation/_build/html/_images/toolbar3.png b/Documentation/_build/html/_images/toolbar3.png deleted file mode 100644 index 3d1793cb4..000000000 Binary files a/Documentation/_build/html/_images/toolbar3.png and /dev/null differ diff --git a/Documentation/_build/html/_images/toolbar4.png b/Documentation/_build/html/_images/toolbar4.png deleted file mode 100644 index a6f03e546..000000000 Binary files a/Documentation/_build/html/_images/toolbar4.png and /dev/null differ diff --git a/Documentation/_build/html/_images/toolbar5.png b/Documentation/_build/html/_images/toolbar5.png deleted file mode 100644 index d7e4222a8..000000000 Binary files a/Documentation/_build/html/_images/toolbar5.png and /dev/null differ diff --git a/Documentation/_build/html/_images/toolbar6.png b/Documentation/_build/html/_images/toolbar6.png deleted file mode 100644 index 610a9565e..000000000 Binary files a/Documentation/_build/html/_images/toolbar6.png and /dev/null differ diff --git a/Documentation/_build/html/_images/va-games.png b/Documentation/_build/html/_images/va-games.png deleted file mode 100644 index b4611693f..000000000 Binary files a/Documentation/_build/html/_images/va-games.png and /dev/null differ diff --git a/Documentation/_build/html/_images/va-inspectors.png b/Documentation/_build/html/_images/va-inspectors.png deleted file mode 100644 index da078691e..000000000 Binary files a/Documentation/_build/html/_images/va-inspectors.png and /dev/null differ diff --git a/Documentation/_build/html/_images/va-titlepage.png b/Documentation/_build/html/_images/va-titlepage.png deleted file mode 100644 index ff61e73ad..000000000 Binary files a/Documentation/_build/html/_images/va-titlepage.png and /dev/null differ diff --git a/Documentation/_build/html/_images/videoPanel.png b/Documentation/_build/html/_images/videoPanel.png deleted file mode 100644 index 38038c5b1..000000000 Binary files a/Documentation/_build/html/_images/videoPanel.png and /dev/null differ diff --git a/Documentation/_build/html/_images/virtualKeyboard.png b/Documentation/_build/html/_images/virtualKeyboard.png deleted file mode 100644 index 11bc04e6e..000000000 Binary files a/Documentation/_build/html/_images/virtualKeyboard.png and /dev/null differ diff --git a/Documentation/_build/html/_sources/Developer/ClassHierarchy.md.txt b/Documentation/_build/html/_sources/Developer/ClassHierarchy.md.txt deleted file mode 100644 index d94f4897e..000000000 --- a/Documentation/_build/html/_sources/Developer/ClassHierarchy.md.txt +++ /dev/null @@ -1,41 +0,0 @@ -# The Class Hierarchy - -This document describes the basic software architecture of vAmiga. The emulator has been written in C++ and is based on the following class hierarchy: - -![Class hierarchy](images/classHierarchy.png "Class hierarchy") - -The most prominent class is the `Amiga` class, as each instance of this class represents a complete virtual Amiga. The class inherits from three other classes: - -- `CoreObject` - - This class encapsulates some common functionalities that are useful for most classes in the vAmiga universe. For example, it provides the API functions for printing debug messages. - -- `CoreComponent` - - This class defines functionalities shared by all classes representing a hardware component. It includes functions to initialize, configure, and serialize objects, as well as functions to power on, power off, run, and pause. - -- `Thread` - - This class enables the `Amiga` class to run code in a separate thread. The architecture and functionality of this class is covered in a separate document. - -Another important entity is the `SubComponent` class, which is the ancestor of all, you guessed it, subcomponents of the Amiga. As a rule of thumb, you'll find a separate class for almost every component you'll find on the motherboard of a real Amiga. There is a `CPU` class, a `Memory` class, and classes for the custom chips `Agnus`, `Denise` and `Paula`. The `Blitter` and `Copper` are also encapsulated in individual classes. You'll find the instances of these classes inside `Agnus`, just as you would find the logic circuits of these chips inside the `Agnus` chip in the real machine. - -The inner structure of the `SubComponent` class is very simple, as its main purpose is to make all subcomponents visible to each others. In the class diagram you may have spotted the associated arrow that connects the `SubComponent` class with the `Amiga` class: - -![SubComponent Association](images/classHierarchy2.png "SubComponent Association") - -In the code, the connection is established in the constructor of the `SubComponent` class: -````c++ -SubComponent(Amiga& ref); -```` -Inside the constructor, a number of references like the following are set up: -````c++ -CPU &cpu; -Memory &mem; -Agnus &agnus; -... -```` -The references are available in any subclass of `SubComponent` and provide easy access to all subcomponents of the virtual Amiga. For example, whenever `Agnus` needs to block the CPU for a certain number of cycles, it can do so by calling an appropriate API function of the `cpu` reference: -````c++ -cpu.addWaitStates(delay); -```` diff --git a/Documentation/_build/html/_sources/Developer/EventScheduler.md.txt b/Documentation/_build/html/_sources/Developer/EventScheduler.md.txt deleted file mode 100644 index 2a8081fca..000000000 --- a/Documentation/_build/html/_sources/Developer/EventScheduler.md.txt +++ /dev/null @@ -1,161 +0,0 @@ -# The Event Scheduler - -vAmiga is an event-driven emulator. If an action has to be performed in a certain bus cycle, the action is scheduled via the event handler API and executed when the trigger cycle is reached. The scheduler can be viewed as a large to-do list that is processed sequentially in `Agnus::executeUntil`. In the document about the *Run Loop* you have learned that this function is called in `Agnus::execute` which emulates Agnus for one bus cycle. - -## Event slots - -Scheduled events are stored in so-called *event slots*. Each slot is bound to a specific component and is either empty or contains a single event. For instance, there is a slot for Copper events, a slot for Blitter events, a slot for UART events, and so on. From a theoretical point of view, each event slot represents a state machine that runs in parallel with all others. It is important to remember that the state machines interact with each other in various ways (e.g., by blocking the DMA bus). Therefore, the slot ordering is important: if two events are triggered in the same cycle, the slot with the smaller number is served first. - -Enough theory for now. Let's open the *Events* tab of the *Inspector* panel and examine what an event typically looks like. When the emulator is running, you'll see something similar to this: - -![Event scheduler](images/events.png "Event scheduler") - -The first seven slots comprise the so-called *primary event table*. The basic idea of the primary table is to group together all event slots with high traffic. Let's look at the contents of these slots at the time the screenshot was taken: - -- **Registers** - This event slot is used to emulate the access delays of the custom registers. It is either empty if no register change is pending, or it contains a `REG_CHANGE` event if one or more registers will change in the near future. Note that in our example, the trigger cycle of this slot is overdue. For speed reasons, the event scheduler sometimes skips updating the trigger cycle. A trigger cycle lying in the past has the same meaning as a trigger cycle that matches the value of the Agnus clock: It is due immediately. - -- **CIA A** and **CIA B** - - Each CIA is controlled by its own event slot. As you can see in the screenshot, the slots for both CIAs contain a `CIA_WAKEUP` event, which means that both CIAs are inactive at the moment. The event slots are grayed out, which means that the slots are disabled. When either CIA gets something to do, the corresponding slot is enabled by updating the trigger cycle. - -- **Bitplane DMA** - - This slot manages all bitplane DMA accesses. In the example shown above, a `BPL_L3` event is due at DMA cycle 61 ($3D) in the current scanline. If you are familiar with the DMA cycle diagram found in the *Hardware Reference Manuel*, you can easily understand what the emulator will be doing when the event triggers. It will perform the bitplane DMA fetch cycle surrounded by a red box: - - ![Bus cycle diagram from the HRM](images/busCycleDiagram.png "Bus cycle diagram from the HRM") - -- **Other DMA** - - This slot is used to manage disk DMA, audio DMA and sprite DMA, as well as to perform some special actions that must be carried out at specific positions in the processed scanline. In the example shown above, the slot contains a scheduled `DAS_TICK` event. When this event is triggered, the 24-bit counter of CIA B is incremented by one. This counter is used by the Amiga to keep track of the currently processed scanline. - -- **Copper** and **Blitter** - - These two slots manage the Copper and Blitter, respectively. The Copper slot has a scheduled wake-up event which is used to implement the `WAIT` instruction. Nothing is scheduled in the Blitter slot, which means that the Blitter is currently inactive. - -- **Next secondary event** - - This is the last slot in the primary slot table and utilized to speed up emulation. It indicates whether the event scheduler needs to proceed with checking the events in the other slots. To understand how this works, let's return to theory for a moment. - -The event slots are divided into *primary*, *secondary* and *tertiary* slots. We have already made ourselves familiar with the primary slots, which manage all frequently occurring events. The secondary slots manage events that occur less frequently, such as interrupts or the events that control Paula's four audio state machines. Events that occur very occasionally are scheduled in the tertiary slots, such as the insertion of a floppy disk. Accordingly, we call an event *primary*, *secondary*, or *tertiary* if it is scheduled in a primary, secondary, or tertiary slot, respectively. - -To speed up, the event scheduler checks only the primary event slots by default. In order for the event handler to also check the secondary slots, a `SEC_TRIGGER` event must be scheduled in the SEC_SLOT. Since this slot belongs to the primary event table, too, it is always checked, just like the other slots in the primary event table. Triggering this event acts like a wake-up call requesting the event handler to check for secondary events as well. Thus, if an event is scheduled in a secondary slot, it must be ensured that `SEC_SLOT` contains a `SEC_TRIGGER` event with a trigger cycle equal to the smallest trigger cycle of all secondary events. - -The same applies to tertiary events. When such an event is scheduled, the event scheduler automatically schedules a `TER_TRIGGER` wake-up event in `TER_SLOT`, which is the last event slot in the secondary slot table. - -As you can see in the screenshot above, two tertiary slots contain a scheduled event. The first event is scheduled in the Server Daemon slot. It is used to monitor external socket connections. Such a connection is used, for example, to emulate a null modem cable connecting two vAmigas. The last slot is the *Inspector slot* and contains an event of type `INS_EVENTS`. When this event is triggered, an *inspection* of the event table is carried out. This means that all entries of the event table are recorded and passed to the GUI. In fact, it's these recorded values that we see in the screenshot above. This also clarifies why the `INS_EVENT` event is always listed as "due immediately" in the inspector. - -Overall, the introduction of an event hierarchy significantly improves emulation speed, as it prevents the event scheduler from having to traverse the entire event table when looking for due events. - -## Scheduling events - -Internally, events are scheduled by calling an appropriate function from the event scheduling API. Among those are the following two variants of `scheduleAbs` which are implemented as follows: - -```c++ -template void scheduleAbs(Cycle cycle, EventID id) -{ - this->trigger[s] = cycle; - this->id[s] = id; - - if (cycle < nextTrigger) nextTrigger = cycle; - - if constexpr (isTertiarySlot(s)) { - if (cycle < trigger[SLOT_TER]) trigger[SLOT_TER] = cycle; - if (cycle < trigger[SLOT_SEC]) trigger[SLOT_SEC] = cycle; - } - if constexpr (isSecondarySlot(s)) { - if (cycle < trigger[SLOT_SEC]) trigger[SLOT_SEC] = cycle; - } -} - -template void scheduleAbs(Cycle cycle, EventID id, i64 data) -{ - scheduleAbs(cycle, id); - this->data[s] = data; -} -``` - -The first variant requires three arguments. In addition to the template argument, which specifies the event slot in which the event is to be scheduled, it expects a trigger cycle and an event ID. The second variant has an additional data argument. For example, most events dealing with floppy drives store the drive number in the event's data field. - -Other scheduling functions are `scheduleImm`, `scheduleInc`, or `scheduleRel`. All these functions differ in the way the trigger cycle is set: - -- **Absolute (Abs)** - - The trigger cycle is specified in the form of a specific master cycle. - -- **Immediate (Imm)** - - The trigger cycle is the next DMA cycle. - -- **Incremental (Inc)** - - The trigger cycle is specified relative to the old trigger cycle. - -- **Relative (Rel)** - - The trigger cycle is specified relative to the current Agnus clock cycle. - -Events can also be *rescheduled*, *cancelled* or *disabled*. Rescheduling means that the event ID in the selected event slot remains unchanged. Canceling is done by calling the following function: - -```c++ -template void cancel() -{ - id[s] = (EventID)0; - data[s] = 0; - trigger[s] = NEVER; -} -``` - -The crucial statement here is the last assignment. It sets the trigger cycle to `NEVER`, which is defined as a simple preprocessor constant: - -```c++ -// Time stamp used for messages that never trigger -#define NEVER INT64_MAX -``` - -This means that a canceled event keeps being scheduled, but with a trigger cycle so high that it will never trigger. - -When we say that an event slot is *disabled*, we simply mean that the trigger cycle is set to `NEVER`, but the ID and data are preserved. This is sometimes done for speed reasons, e.g. when the IDs of two consecutive events do not change. - -Note that the event scheduler treats all cycle values as master cycles. If a trigger value is specified in a different unit, it must be converted to master cycles first. Several conversion macros are defined for this purpose: - -```c++ -#define CPU_CYCLES(cycles) ((Cycle)(cycles) << 2) -#define CIA_CYCLES(cycles) ((Cycle)(cycles) * 40) -#define DMA_CYCLES(cycles) ((Cycle)(cycles) << 3) -``` - -The macros convert a value given in CPU cycles, CIA cycles or DMA cycles to the corresponding value on the master cycle scale. Reconversion is also possible by applying one of the following macros: - -```c++ -#define AS_CPU_CYCLES(cycles) ((Cycle)(cycles) >> 2) -#define AS_CIA_CYCLES(cycles) ((Cycle)(cycles) / 40) -#define AS_DMA_CYCLES(cycles) ((Cycle)(cycles) >> 3) -``` - -All event IDs are defined in a large `enum` called `EventID`. - -```c++ -enum_i8(EventID) -{ - EVENT_NONE = 0, - - // - // Events in the primary event table - // - - // REG slot - REG_CHANGE = 1, - REG_EVENT_COUNT, - - // CIA slots - CIA_EXECUTE = 1, - CIA_WAKEUP, - CIA_EVENT_COUNT, - - ... -``` - -Note that event IDs are reused across the event slots. For example, the `REG_CHANGE` and `CIA_EXECUTE` events share the same ID. - -Congratulations. If you have worked through the documentation up to this point, you already have a good understanding of the basic software structure and inner workings of vAmiga. diff --git a/Documentation/_build/html/_sources/Developer/MessageQueue.md.txt b/Documentation/_build/html/_sources/Developer/MessageQueue.md.txt deleted file mode 100644 index 002e63a66..000000000 --- a/Documentation/_build/html/_sources/Developer/MessageQueue.md.txt +++ /dev/null @@ -1,131 +0,0 @@ -# The Message Queue - -In this document we will examine how vAmiga communicates with the graphical user interface. Sending commands from the GUI to the emulator core is simple. The GUI simply calls one of the API functions of the `Amiga` instance or one of its subcomponents. - -The other way is a bit more sophisticated. The emulator communicates with the GUI via a message queue. The message queue is implemented by the `MsgQueue` class, which stores all pending messages in a ring buffer. - -```c++ -class MsgQueue : public SubComponent { - - // Ring buffer storing all pending messages - util::RingBuffer queue; - - ... -} -``` - -Class `MsgQueue` supports two different access methods: *Polling* or *Subscribing*. - -## Polling the message queue - -The message queue provides a public function `bool MsgQueue::get(Message &msg)` for reading a message. If the queue contains at least one message, `true` is returned and the oldest message is copied over to `msg`. If the queue is empty, the function returns `false`. - -The polling method is utilized by [vAmiga.net](https://vamiganet.github.io), a web port of vAmiga based on WebAssembly. The corresponding JavaScript code looks like this: - -```js -export function doAnimationFrame() -{ - // Process pending messages - while (1) { - - let msg = $amiga.readMessage(); - if (msg.type == 0) break; - - $proxy.processMsg(msg); - } -} -``` - -Function `$amiga.readMessage()` is a small C++ wrapper around the `get` function: - -```c++ -Message AmigaProxy::readMessage() -{ - Message msg; - - if (!amiga->msgQueue.get(msg)) { - msg.type = 0; - } - - return msg; -} -``` - -On a positive note, polling ensures that message processing is always done in a separate thread. That is, it is never performed within the emulator thread itself. However, polling the queue is subject to potential message loss. If the GUI thread does not keep up with polling the queue, the ring buffer may overflow, resulting in lost messages. This drawback is solved by the subscription method, which we will discuss below. - -## Subscribing to the message queue - -As an alternative to storing pending messages in a ring buffer, the message queue also supports a callback mechanism. In this mode, sent messages are no longer written to the ring buffer. Instead, the registered callback function is called with the sent message as parameter. - -Subscribing to the message queue works by specifying the callback function as an argument to the `Amiga::launch` function, which we have already discussed earlier: -```c++ -void launch(const void *listener, Callback *func); -``` -`Callback` is a type alias which is defined as follows: -```c++ -typedef void Callback(const void *, Message); -``` -Whenever the emulator sends a message, the provided callback function is invoked. The first argument is the raw pointer passed as the first argument to `Amiga::launch`. The second argument is an instance of the class `Message`. - -The subscription method is used by both the Mac version of vAmiga and *vAmiga Headless*. The latter is a small wrapper around the core emulator used mainly for testing the integrity of nightly builds. *vAmiga Headless* first creates an instance of the Amiga class on the stack: -```c++ -class Headless { - - ... - - // The emulator instance - Amiga amiga; -} -``` -Subscribing to the message queue happens in the `main` function: -```c++ -int -Headless::main(int argc, char *argv[]) -{ - ... - - // Launch the emulator thread - amiga.launch(this, vamiga::process); -} -``` -The first argument of the `launch` function is a pointer to the instance of the calling object. The second argument is a pointer to a global function called `process`, which is defined as follows: -```c++ -void -process(const void *listener, Message msg) -{ - ((Headless *)listener)->process(msg); -} -``` -The implementation of this function is fairly straightforward. It converts the provided raw pointer (which was set to `this` above) back to the correct type and calls the `process` function for that object. The implementation of this function looks like this: -```c++ -void -Headless::process(Message msg) -{ - switch (msg.type) { - - case MSG_SCRIPT_DONE: - ... - - } - } -} -``` -Subscribing to the message queue has the advantage of preventing any message from being lost. However, it is important to note that the message processing code is executed inside the emulator thread. This may cause problems if the message processing code calls functions of the public API of the `Amiga` class, since many of these functions assume that they are *not* called by the emulator thread itself. The Mac version of vAmiga solves this problem by passing all incoming messages to the GUI thread before execution. The relevant code is encapsulated in the `MyController.launch()` function, which is part of the Swift UI: -```Swift - func launch() { - - // Convert 'self' to a void pointer - let myself = UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque()) - - amiga.launch(myself) { (ptr, msg: Message) in - - // Convert void pointer back to 'self' - let myself = Unmanaged.fromOpaque(ptr!).takeUnretainedValue() - - // Process message in the main thread - DispatchQueue.main.async { - myself.processMessage(msg) - } - } - } -``` \ No newline at end of file diff --git a/Documentation/_build/html/_sources/Developer/RunLoop.md.txt b/Documentation/_build/html/_sources/Developer/RunLoop.md.txt deleted file mode 100644 index a7061f5fd..000000000 --- a/Documentation/_build/html/_sources/Developer/RunLoop.md.txt +++ /dev/null @@ -1,148 +0,0 @@ -# The Run Loop - -In this document we will examine how vAmiga calculates a single frame. If you've studied the document about the `Thread` class, you already know that the calculation of a single frame is triggered within the threads main execution function. E.g., when the thread is running in *pulsed* mode, the following function is executed: - -```c++ -template <> void -Thread::execute() -{ - loadClock.go(); - execute(); - loadClock.stop(); -} -``` - -The `loadClock` object is used to measure the CPU load. All the action takes place in function `execute`, which is declared as a pure virtual function inside the `Thread` class: - -```c++ -virtual void execute() = 0; -``` - -The `Amiga` class implements this function as follows: - -```c++ -void -Amiga::execute() -{ - while (1) { - - // Emulate the next CPU instruction - cpu.execute(); - - // Check if special action needs to be taken - if (flags) { - - ... - - // Are we requested to synchronize the thread? - if (flags & RL::SYNC_THREAD) { - clearFlag(RL::SYNC_THREAD); - break; - } - } - } -``` - -The function enters an infinite loop, which we refer to as the `run loop`. The inner working is quite simple. First the CPU is asked to execute a single instruction. After that, the variable `flags` is checked. This variable is a bit field storing several *action flags* whose purpose is to trigger specific actions within the run loop. The following list gives you an idea about what kind of actions we are talking about: - -```c++ -namespace RL -{ -constexpr u32 STOP = (1 << 0); -constexpr u32 SOFTSTOP_REACHED = (1 << 1); -constexpr u32 BREAKPOINT_REACHED = (1 << 2); -constexpr u32 WATCHPOINT_REACHED = (1 << 3); -constexpr u32 CATCHPOINT_REACHED = (1 << 4); -constexpr u32 SWTRAP_REACHED = (1 << 5); -constexpr u32 COPPERBP_REACHED = (1 << 6); -constexpr u32 COPPERWP_REACHED = (1 << 7); -constexpr u32 AUTO_SNAPSHOT = (1 << 8); -constexpr u32 USER_SNAPSHOT = (1 << 9); -constexpr u32 SYNC_THREAD = (1 << 10); -}; -``` - -In most cases the variable `flags` equals zero. In this case, the loop simply executes one CPU instruction after another. - -But wait, didn't we say the function only calculates a single frame? The answer is yes, and this is where the `SYNC_THREAD` flag comes into play. The flag is set by `Agnus` in the following function: - -```c++ -void -Agnus::eofHandler() -{ - ... - - // Let the thread synchronize - amiga.setFlag(RL::SYNC_THREAD); -} -``` - -The acronym `eof` refers to *end of frame*. As you may have guessed already, the function is executed at the end of each frame. Once the variable `SYNC_THREAD` is set, the run loop will be terminated with the next check of the variable `flags`. - -Overall, it's pretty simple, isn't it? Well, the answer is yes and no. For instance, we just learned that the `SYNC_THREAD` flag is set by Agnus in its end-of-frame handler, but where is this function called? The run loop does nothing of that sort, it just calls the CPU and checks some flags. - -The sky clears up by taking a closer look at what's happening inside `CPU::execute()`. Let's assume that the next instruction to be executed is a `BRA` instruction. Inside `CPU::execute()` the CPU starts executing some internal actions. After that it calls the execution handler of the `BRA` instruction, which begins as follows: - -```c++ -template void -Moira::execBra(u16 opcode) -{ - AVAILABILITY(S == Long ? C68020 : C68000) - - u32 oldpc = reg.pc; - u32 disp = S == Byte ? (u8)opcode : queue.irc; - - SYNC(2); - - ... -} -``` - -The `SYNC` statement is the one we need to examine. It is a macro that expands to a call to the `sync` function, at least when emulating a M68000 or M68010. The CPU calls this function to signal to the surrounding logic that the CPU clock has advanced a certain number of cycles. In this particular example, it signals that 2 CPU cycles have elapsed. - -Let's see how the `sync` function is implemented. An uncluttered version of this function looks like this: - -```c++ -void -Moira::sync(int cycles) -{ - // Advance the CPU clock - clock += cycles; - - // Emulate Agnus up to the same cycle - agnus.execute(CPU_AS_DMA_CYCLES(cycles)); -} -``` - -After advancing the internal clock, the function asks `Agnus` to emulate the surrounding logic up to the point in time where the CPU currently is. After that, control is returned to the CPU. Now, when the CPU performs a memory access, it is assured that the surrounding logic is up to date. For write accesses, this means that the operation is carried out at the proper point in time, and for read accesses, it means that correct values will be read. - -Let's head over to `Agnus` and have a closer look at what the execute function does. The function that was actually called is a convenience wrapper around the actual execution function: - -```c++ -void -Agnus::execute(DMACycle cycles) -{ - for (DMACycle i = 0; i < cycles; i++) execute(); -} -``` - -So let's dig a little deeper: - -```c++ -void -Agnus::execute() -{ - // Advance the internal clock and the horizontal counter - clock += DMA_CYCLES(1); - pos.h += 1; - - // Process pending events - if (nextTrigger <= clock) executeUntil(clock); -} -``` - -This function emulates `Agnus` for one bus cycle. First, it increments the color clock and the horizontal counter by one. After that, if a pending event is present, it calls the event scheduler. - -The Event Scheduler can undoubtedly be considered the central component of vAmiga, as everything is built around it. All actions that have to be executed in a certain bus cycle are triggered by this component. Please always remember that the event scheduler, despite its central role, is never called directly inside the run loop of vAmiga. It is only called indirectly, before each memory access of the CPU. - -Since the event scheduler is of such great importance, we'll examine it in more detail in a separate document. diff --git a/Documentation/_build/html/_sources/Developer/SuperHires.md.txt b/Documentation/_build/html/_sources/Developer/SuperHires.md.txt deleted file mode 100644 index ae36d3e8d..000000000 --- a/Documentation/_build/html/_sources/Developer/SuperHires.md.txt +++ /dev/null @@ -1,63 +0,0 @@ -# SuperHires mode - -This document outlines how SuperHires mode is implemented in vAmiga. This mode is a feature of the ECS chipset and available e.g. on the Amiga 500+. SuperHires mode provides a pixel display rate of 35 ns, which is twice the horizontal resolution of Hires mode, and four times the resolution of Lores mode. - -The integration of SuperHires mode into vAmiga was driven by three design goals: - -- **Customizable texture size** - - Early versions of vAmiga generated a GPU texture in Hires resolution, meaning that each Hires pixel on the Amiga side corresponded to a single texel on the GPU side. The term texel is a mixture of the words pixel and commonly used to describe a single pixel in a GPU texture. Since SuperHires mode doubles the horizontal resolution, I had to decide whether the horizontal GPU texture size should be doubled, too. I have come to the conclusion that vAmiga should support two horizontal texture resolutions to better suit backends that do not take advantage of the higher resolution. - -- **Low performance impact** - - SuperHires mode is a rarely used feature of the Amiga and the vast majority of users will be running vAmiga in one of the default modes most of the time. Therefore, the performance hit caused by adding SuperHires mode had to be kept as low as possible. - -- **No code cluttering** - - One of the strengths of vAmiga is a clean code base. Therefore, my goal was to change the existing code as little as possible. I.e., I wanted to avoid cluttering the code with an armada of if-statements checking the currently used texture format. - -To fulfill the first requirement I added a configuration option called `TPP`. This abbreviation stands for Texels Per Pixel and describes the number of texels that make up a single Hires pixel. `TPP` can be either 1 or 2. When set to 1, vAmiga generates a Hires texture, just like the early versions, meaning that each Hires pixel is represented by a single texel. If set to 2, vAmiga generates a texture in SuperHires resolution, which means each hires pixel is represented by two texels. - -The following images illustrate the effects of the `TPP` setting. When `TPP` is equal to 1 and the Amiga draws a line in Hires mode, each Hires pixel is mapped to a single texel: - -![TPP 1 Hires pixel stream](images/superHires1.png "Hires pixel stream, TPP = 1") - -In SuperHires mode, however, the GPU texture is too coarse to represent each emulator pixel individually. In this case, the drawing logic interpolates two emulator pixels into a single texel: - -![TPP 1 Super-Hires pixel stream](images/superHires2.png "Super-Hires pixel stream, TPP = 1") - -If TPP equals 2, each Hires pixel is mapped to two texels: - -![TPP 2 Hires pixel stream](images/superHires3.png "Hires pixel stream, TPP = 2") - -In SuperHires mode, vAmiga performs a one-to-one mapping of SuperHires pixels to texels: - -![TPP 2 Super-Hires pixel stream](images/superHires4.png "Super-Hires pixel stream, TPP = 2") - -Let us revisit the design goals mentioned above. To achieve the latter two, `TPP` had to be made a compile-time option. This means that it has to be decided in advance which texture format should be used. - -Let us now take a closer look at the compile-time changes triggered by `TPP`. The most important code fragment is located in `FrameBufferTypes.h`. Among others, this file defines the `Texel` type, which is used to address elements in the GPU texture. It is defined as follows: - -```C++ -#if TPP == 1 -typedef u32 Texel; -#else -typedef u64 Texel; -#endif -``` - -As you can see, the value of `TPP` affects the underlying data type of `Texel`. When `TPP` equals 1, `Texel` corresponds to an unsigned 32-bit integer. If `TPP` equals 2, the data type is twice as large. - -In addition, there is a macro called `TEXEL` which converts an 32-bit RGBA value into a `Texel`. - -```C++ -#if TPP == 1 -#define TEXEL(rgba) (rgba) -#else -#define TEXEL(rgba) ((u64)rgba << 32 | rgba) -#endif -``` - -The definition of this macro reveals the trick vAmiga uses to keep the performance penalty low. If `TPP` equals 1, this macro is a direct mapping. In other words: If `TPP` equals 1, a `Texel` is a 32-bit value. If `TPP` equals 2, the `TEXEL` macro repeats the RGBA pattern. This means that the generated 64-bit value will represent the same RGBA value twice in a row. Thus, when the emulator sets a single texel in the texture, it actually sets two texels because a texel is always 32-bit on the GPU side. Since writing a 64-bit value is about as fast as writing a 32-bit value, the actual `TPP` value has no relevant impact on vAmiga’s performance. Of course, we have to pay a price on the GPU side. Since the emulator texture has doubled in size, the GPU has to move around twice as much memory for each frame. - -Also, hiding the actual texture size in the `Texel` data type prevents the code quality to degrade. From the emulator side, the horizontal texture size appears to be independent of the `TPP` value, since everything is counted in texels. As a result, the same code can be used for both possible `TPP` values and there is no need to clutter the code with a large amount of `if` statements. \ No newline at end of file diff --git a/Documentation/_build/html/_sources/Developer/ThreadClass.md.txt b/Documentation/_build/html/_sources/Developer/ThreadClass.md.txt deleted file mode 100644 index cb32f62af..000000000 --- a/Documentation/_build/html/_sources/Developer/ThreadClass.md.txt +++ /dev/null @@ -1,163 +0,0 @@ -# The Thread Class - -In this document we will take a closer look at the `Thread` class, which adds concurrent code execution capabilities to the `Amiga` class. In addition, it implements the state model of the emulator. - -![Thread class](images/classHierarchyThread.png "Thread class") - -Creating an emulator instance comprises two steps: - -- Creating an instance of the `Amiga` class. -- Calling `Amiga::launch()`. - -Inside `Amiga::launch()`, an emulator thread is spawned in the constructor: - -```c++ -Amiga::launch() -{ - ... - thread = std::thread(&Thread::main, this); - ... -} -``` - -The thread is never terminated. It remains alive until the application quits. - -## Main function - -After the thread has been created, it starts executing the `Thread::main` function which is inherited from the `Thread` class. This function consists of a large `while` loop which looks like this: - -```c++ -void -Thread::main() -{ - ... - while (++loopCounter) { - - if (isRunning()) { - - switch (getThreadMode()) { - - case THREAD_PERIODIC: execute(); break; - case THREAD_PULSED: execute(); break; - case THREAD_ADAPTIVE: execute(); break; - } - } - - if (!warpMode || !isRunning()) { - - switch (getThreadMode()) { - - case THREAD_PERIODIC: sleep(); break; - case THREAD_PULSED: sleep(); break; - case THREAD_ADAPTIVE: sleep(); break; - } - } - - if (stateChangeRequest.test()) { - - switchState(newState); - stateChangeRequest.clear(); - stateChangeRequest.notify_one(); - - if (state == EXEC_HALTED) return; - } - ... - } -} -``` - -Because the thread is never terminated, the loop is executed during the entire lifetime of the application. Within the loop body, two switch-case blocks can be spotted. The first one is executed as long as the emulator is running and calls one of three possible functions, depending on the operation mode of the thread. Both functions emulate the Amiga for a single frame. The second switch-case block is executed when the emulator is not running in warp mode. Within this block, one of three synchronization functions is called, again depending on the selected operation mode. The purpose of these functions is to keep the thread running at the right pace. That is, they ensure that the functions are called 50 times per second for PAL machines and 60 times per second for NTSC machines. - -Three synchronization modes are available: *Periodic*, *Pulsed*, and *Adaptive*. -```c++ -enum_long(THREAD_MODE) -{ - THREAD_PERIODIC, - THREAD_PULSED, - THREAD_ADAPTIVE -}; -typedef THREAD_MODE ThreadMode; -``` -- `THREAD_PERIODIC`: - - In periodic mode the thread puts itself to sleep and utilizes a timer to schedule a wakeup call. In this mode, no further action has to be taken by the GUI. This method had been the default mode used by vAmiga up to version 2.3. - -- `THREAD_PULSED` - - In pulsed mode, the thread waits for an external wake-up signal that has to be sent by the GUI. When the wake-up signal is received, a single frame is computed. vAmiga uses this mode to implement VSYNC. - -- `THREAD_ADAPTIVE`: - - In adaptive mode, the thread waits for an external wake-up signal just as it does in pulsed mode. When the wake-up signal comes in, the thread computes the number of missing frames based on the current time and the time the thread had been lauchen. Then it executes all missing frames or resynchronizes if the number of missing frames is way off. Adaptive mode has been introduced in vAmiga 2.4. It has become the new default mode since then. - -## State model - -Let's take a closer look at the `isRunning()` function, whose implementation is very straightforward: - -``` -bool isRunning() const override { return state == EXEC_RUNNING; } -``` - -The variable `state` may hold one of the following values: - -- `EXEC_OFF`: The emulator is turned off. -- `EXEC_PAUSED`: The emulator is turned on, but not running. -- `EXEC_RUNNING`: The emulator does its job. The virtual Amiga is alive. -- `EXEC_SUSPENDED`: The emulator is paused for a short period of time. -- `EXEC_HALTED`: The emulator is shutting down. - -The following image provides a visual representation of the state model: - -![State model](images/stateModel.png "State model") - -After creating an instance of the `Amiga` class the emulator is in `OFF` state. By calling the function `powerOn()` the emulator is put into `PAUSED` state. This is the same state that is entered when the user presses the *Pause* button in the toolbar. A call to `run()` brings the virtual Amiga to life by putting it into a `RUNNING` state. - -The Thread class provides a suspend-resume mechanism that can be used to pause the thread for a short period of time. This functionality is frequently used by the graphical user interface to carry out atomic operations that cannot be performed while the emulator is running. Theoretically, the thread could also be put into `PAUSED` state for this purpose, but this would also stop audio. To avoid disruptions, a special `SUSPENDED` state has been added. In this state the execute function is no longer called, but other services, such as the audio playback, are kept alive. - -The `SUSPENDED` state is entered by calling `suspend()` and exited by calling `resume()`. Critical code sections can be executed safely by embedding them in a suspend-resume block like this: -```c++ -suspend(); - -// Change the internal state of the emulator as you like. - -resume(); -``` -It is safe to nest multiple suspend-resume blocks, but it is essential that each call to `suspend()` is followed by a call to `resume()`. Consequently, the critical code section must not be exited in the middle, e.g. by throwing an exception. For this reason, you will often see the keyword `SUSPENDED` in the code, which is an exit-safe wrapper around `suspend()` and `resume()`. With this macro, the above code snippet can be rewritten as follows: -```c++ -{ SUSPENDED - - // Change the internal state of the emulator as you like. - // Feel free to return or throw an exception. -} -``` -To speed up emulation, e.g. during disk accesses, the emulator may be put into *warp mode*, which is also handled by the `Thread` class. As you have seen in the code fragment of the `Thread::main()` function, neither of the two synchronization functions is called when warp mode is active. - -Similar to warp mode, the emulator can be put into *track mode*. This mode is activated when the GUI debugger is opened and deactivated when the debugger is closed. In track mode, several time-consuming tasks are performed that are normally skipped. For example, the CPU keeps track of all executed instructions and stores the recorded information in a trace buffer. - -The `Thread` class provides several API functions for changing state such as `powerOn()`, `powerOff()`, `run()`, `pause()` or `halt()`. These functions request the thread to change state by setting the following variable to `true`: - ```c++ - std::atomic_flag stateChangeRequest; - ``` -As you may have already seen in the code snippet above, the `main` function checks this variable in each iteration of the `while` loop and performs a state change when necessary. The implementation of function `switchState` looks like this: -```c++ - while (newState != state) { - - if (state == EXEC_OFF && newState == EXEC_PAUSED) { - - CoreComponent::powerOn(); - state = EXEC_PAUSED; - - } else if (state == EXEC_OFF && newState == EXEC_RUNNING) { - - CoreComponent::powerOn(); - state = EXEC_PAUSED; - - } ... - - } else if (newState == EXEC_HALTED) { - - CoreComponent::halt(); - state = EXEC_HALTED; - } - } -``` diff --git a/Documentation/_build/html/_sources/HowTo/MappingCmd.md.txt b/Documentation/_build/html/_sources/HowTo/MappingCmd.md.txt deleted file mode 100644 index deb298dda..000000000 --- a/Documentation/_build/html/_sources/HowTo/MappingCmd.md.txt +++ /dev/null @@ -1,11 +0,0 @@ -# Mapping the Command keys - -In vAmiga you will be using the native Mac keyboard for typing, and for most Amiga keys you will find a perfect match on your native keyboard. This holds true for the two Amiga keys, too. They are located in the same places on the Amiga keyboard as the Command keys are on modern keyboards. Therefore, it would be natural to assign the two command keys to the two Amiga keys. - -However, this creates a problem because the command keys in macOS are directly linked to operating system actions. If we grant the emulator free access to these keys, we would lose all standard key combinations like *Cmd+H* for hiding a window or *Cmd+Q* for quitting the application. - -Therefore, the command keys are not mapped by default. However, if you want to associate the command keys with the Amiga keys, you can do so via the keyboard menu. By selecting the appropriate option, you can choose whether you want to map the left command key, the right command key or both keys. - -![Keyboard menu](images/mappingCmd.png "Keyboard menu") - -A feasible trade off is to map the right Command key, only, since the Amiga used the right Amiga key to trigger OS-specific commands. If the left command key is left unmapped, you can trigger Amiga commands using the right Command key while still controlling the Mac application with the standard macOS-specific keyboard shortcuts. diff --git a/Documentation/_build/html/_sources/HowTo/NullModemCable.md.txt b/Documentation/_build/html/_sources/HowTo/NullModemCable.md.txt deleted file mode 100644 index e0831aa94..000000000 --- a/Documentation/_build/html/_sources/HowTo/NullModemCable.md.txt +++ /dev/null @@ -1,33 +0,0 @@ -# Connecting Two Amigas - -vAmiga supports two emulator instances to be connected with a null modem cable, allowing the user to run multiplayer games. In this article we will walk through the necessary steps to connect two emulator instances running Battle Chess. - -First of all, launch vAmiga, open the configuration window and switch to the Peripherals tab. In this tab you can configure the serial interface: - -![Peripherals Tab](images/battlechess1.png "Peripherals Tab") - -Now open the serial port popup menu and select *Null Modem Cable* from the options list. This will connect one side of a null modem cable to the serial port of your virtual Amiga. Internally, the null modem cable is emulated using socket connections, which means that the connected Amigas must agree on a common port number to communicate. By default, vAmiga uses port 8080, but you can choose a different port if you like. - -![Peripherals Tab](images/battlechess2.png "Peripherals Tab") - -As you can see in the screenshot above, a small icon has appeared in the status bar. This indicates that the socket server has been activated and is waiting for another emulator instance to connect. - -Now launch another instance of vAmiga and connect the null modem cable the same way. - -![Peripherals Tab](images/battlechess3.png "Peripherals Tab") - -After the null modem cable has been selected in the second emulator instance, the status icon has changed its shape, indicating that the connection has been established. If the icon looks different on your computer, please check if both emulator instances are listening to the same socket port. - -Now it's time to load Battle Chess on both Amigas. The configuration of the null modem cable is quite simple in this game: The the *Settings* menu let's you select the player type for each side of the board. - -This is how I configured the first emulator instance. The Amiga controls the blue army, the connected computer controls the red army. - -![Battle Chess Setup](images/battlechess4.png "Battle Chess Setup") - -The second emulator instance is configured the other way around. The Amiga controls the red soldiers, the connected computer controls the blue ones. After selecting *New Game* from the menu in either emulator instance, it's time to chill. Have fun with two vAmigas fighting each other. - -## Troubleshooting - -If everything works as expected, the socket connection should be established exactly as described above. If vAmiga refuses to connect, you can display some additional debug information in RetroShell. To do so, open RetroShell by pressing on the corresponding toolbar icon. Inside RetroShell, switch to the *Debugger* by pressing the *Shift + Return*. Now, type `server serial` as shown in the screenshot below. This command displays the current connection status and outputs some statistical information about the transferred data. - -![RetroShell](images/battlechess5.png "RetroShell") \ No newline at end of file diff --git a/Documentation/_build/html/_sources/Overview/About.md.txt b/Documentation/_build/html/_sources/Overview/About.md.txt deleted file mode 100644 index 4fe91d37a..000000000 --- a/Documentation/_build/html/_sources/Overview/About.md.txt +++ /dev/null @@ -1,29 +0,0 @@ -# About - -vAmiga is a Commodore Amiga 500, 1000 and 2000 emulator for macOS. Development begun in January 2019 and has made great progress since then. - -![Screenshots](../images/va-games.png "vAmiga screenshots") - -## Design goals - -I have written vAmiga with three goals in mind: - -- **Accuracy** - - vAmiga aims to emulate the three original Commodore Amiga machines, the A500, A1000, and A2000, with high accuracy. It tries to emulate all the components with cycle-exact precision, meaning that each memory access is performed at the exact same DMA cycle as on the original machine. - -- **Usability** - - Providing an appealing graphical user interface is a crucial aspect in retro computing for me, as the purpose of an emulator is not only to run aged software, but to bring back old memories from back in the day. vAmiga provides an easy-to-use interface that tries to hide as many technical details from the user as possible. - -- **Quality** - - It is my deep conviction that the code quality is as important as system-level functionality. For this reason, I have spent a lot of time on software architecture and refactoring. The effort already payed off. E.g., it was possible to port vAmiga to WebAssembly with little effort. - -![Inspectors](../images/va-inspectors.png "Inspector panels") - -## Licensing - -vAmiga is open-source and published under the terms of the GNU General Public License. The CPU core has been re-licensed recently. It is now published under the terms of the MIT license, allowing much broader use. Please refer to the Moira project for more details about this topic. - -To run the emulator, a Kickstart ROM is required. Please note that the original Amiga ROMs cannot be shipped with the emulator as they are the intellectual property of Cloanto™. By purchasing a license of Amiga Forever™ you can acquire legal Kickstart ROMs and use them in vAmiga. diff --git a/Documentation/_build/html/_sources/References/Configuration/Audio.md.txt b/Documentation/_build/html/_sources/References/Configuration/Audio.md.txt deleted file mode 100644 index 9c9f8cf23..000000000 --- a/Documentation/_build/html/_sources/References/Configuration/Audio.md.txt +++ /dev/null @@ -1,41 +0,0 @@ -# Audio Panel - -Use this panel to change the audio settings. - -![Audio Panel](images/audioPanel.png "Audio Panel") - -The audio settings are organized in four sections: - -## Audio In - -This section controls the volumes of the four Amiga audio channels. To mute an audio channel, simply lower the volume to zero. The pan controls can be used to freely distribute each channel to the left and right speakers. By default, channels 1 and 2 are routed to the left speaker and channels 0 and 4 to the right speaker, just like a real Amiga does. - -## Audio Out - -- **Left**, **Right** - - The two volume controls change the main volume of the two stereo output streams. Both streams are mixed together from the four Amiga audio channels as specified in the Audio In section. - -- **Interpolation** - - The Amiga can generate audio streams with different sampling rates. This means that the audio stream must be translated into a suitable audio stream for the host computer. The interpolation settings control how this conversion is performed. You can choose between three methods: - - - **Off** - - In this mode, no interpolation takes place. Based on the timestamp of the audio sample to be created, the current content of the audio output buffer is fed into the audio stream of the host computer. This mode trades in quality for speed. - - - **Nearest** - - Based on the timestamp of the audio sample to be created, the Amiga audio sample with the closest timestamp is selected. This mode is slightly slower than the first one, but produces better quality. - - - **Linear** - - Based on the timestamp of the audio sample to be created, the two surrounding samples are looked up in the Amiga audio stream and linearly interpolated. This mode gives the best result, but is also the slowest among the three options. - -## Drive volumes - -In this area, the volumes of several sound effects are controlled. vAmiga distinguishes between heads steps and polling clicks. The latter describe the steps of the drive head that are executed to detect a disk change. Since polling clicks may become annoying, especially when two or more drives are connected, it is possible to silence them by reducing the volume of the polling clicks to zero. All normal head movements will still be audible in this case. - -## Drive locations - -With the pan controls you can freely distribute the drive sounds to the left and right speaker outputs. In the default setting, all sounds from the internal floppy drive are routed to the right speaker, since the floppy drive in the Amiga 500 is located on the right side of the computer case. diff --git a/Documentation/_build/html/_sources/References/Configuration/Chipset.md.txt b/Documentation/_build/html/_sources/References/Configuration/Chipset.md.txt deleted file mode 100644 index 1075e15cb..000000000 --- a/Documentation/_build/html/_sources/References/Configuration/Chipset.md.txt +++ /dev/null @@ -1,98 +0,0 @@ -# Chipset Panel - -Use this panel to configure the CPU and the custom chips of the virtual Amiga. - -![Chipset Panel](images/chipsetPanel.png "Chipset Panel") - -## CPU - -vAmiga supports three different CPU revisions: - -- **M68000** - - The M68000 is a 16/32-bit CISC microprocessor introduced by Motorola in 1979. Commodore has used this CPU in all classic Amiga models. Choose this revision to emulate the classic Amigas at the highest precision. - -- **M68010** - - The MC68010 processor was released in 1982 as the successor to the Motorola 68000. It was never officially used by Commodore in any Amiga model. However, since the M68010 was pin-compatible with the M68000, it can be used as a replacement for the M68000 in all classic Amigas. The following image shows one of my test machines that has been upgraded with a M68010. I've used this machine extensively while adding M68010 support in vAmiga: - - ![M68010](images/68010.png "M68010") - - Using the M68010 instead of the M68000 results in a speed gain of about 10%. Among other things, this is due to a special operating mode, called *loop mode*, which is entered automatically when certain loop constructs are executed. In this mode, some redundant memory accesses are skipped, resulting in faster execution speed. Please note that the M68010 is not 100% software compatible with the M68000. Therefore, some games or demos may not work when this CPU is selected. - -- **68EC020** - - The M68EC020 is a lower-cost version of the Motorola 68020 processor, which was launched in 1984. It was used by Commodore in the Amiga 1200 with a clock frequency of 14MHz. The 68020 was a significant improvement over the M68010, as it was the first CPU in the M68K series to have an on-board cache. vAmiga emulates the M68EC020, but with less precision than the M68000 and M68010. The first two models can be emulated by vAmiga with exact cycle precision, which means that all instructions not only consume the proper number of CPU cycles, but also access memory during the exact same DMA cycle as the real machine does. In 68020 mode, the CPU is emulated with lower accuracy. For example, vAmiga does not emulate caching, yet. - -- **Warp mode** - - In warp mode vAmiga runs at maximum speed, i.e. it starts computing the next frame right after the current frame has been completed. Warp mode can be configured as **always off**, **always on** or **automatically enabled**. In auto mode, warp mode is linked to the disk drive logic. It turns on and off just as the drive motor does. This mode significantly reduces loading times and works quite well in most cases. However, some applications are coded to not turn off the drive motor even when no data is being transmitted. In such cases, auto mode must be turned off manually by the user. - -The next two options choose the emulated chip revisions of Agnus and Denise, two of the so-called *custom chips*. These chips were extremely important for the Amiga, as they were one of the main reasons for its competitive computing power back in the day. Without the custom chips, the Amiga would never have taken the prominent place in computer history it occupies today. - -All custom chips can be classified into one of three generations. The first chip generation is called OCS (Original Chip Set). All original Amigas were equipped with these chips. The second generation is called ECS (Enhanced Chip Set) and was used by Commodore in the A500+ and the A600. Some ECS chips were also used in later revisions of the A500 and the A2000. Commodore shipped them with an ECS Agnus and an OCS Denise. My test computer pictured above also belongs to these models. It is equipped with an Agnus 8372A, a revision of the ECS generation. Denise, however, has revision number 8362R8, which is the OCS version of this chip. -The third generation of custom chips was called AGA (Advanced Graphics Architecture). Commodore equipped the A1200 and A4000 with these chips. - -Both the OCS and ECS chipsets are supported by vAmiga. The AGA chipset is currently *not* supported and probably will never be. - -## Agnus - -Agnus can be considered the boss among the custom chips, because it controls the interaction of all other components. It also acts as a data provider for the other chips, as it performs all DMA accesses. - -vAmiga is able to emulate the following revisions of this chip: - -- **Early OCS** - - This option emulates the MOS 8367. It was used in the A1000 and in a very early version of the A2000, usually called the A2000A. - -- **OCS** - - This option emulates the MOS 8371 which was used by Commodore in many revisions of the A500 and A2000. It is the most commonly used OCS version of this chip. - -- **ECS (1MB)** - - This option emulates the MOS 8372A. It is the first ECS revision of this chip. Apart from some minor details, the ECS variant differs mainly in the size of the addressable memory space. While the OCS models can only address 512 KB of Chip Ram, the ECS version was capable of addressing twice as much. - -- **ECS (2MB)** - - This option emulates the MOS 8375, which increased the range of addressable Chip Ram to 2 MB. It is used in the A500+ and A600, released in 1991 and 1992 respectively. - -## Denise - -- **OCS** - - This option selects the MOS 8362R8 which was used in all revisions of the Amiga 1000, Amiga 500, and Amiga 2000. - -- **ECS** - - This option selects the MOS 8373R4. The chip is sometimes referred to as *HiRes Denise* and was used in the Amiga 500+ and the Amiga 3000. Compared to its predecessor, it supports additional graphics modes and features an advanced sprite unit. It also offers a special *Border Blank* mode, which causes the border to be drawn in black color instead of the currently selected background color. Some games use this feature to surround the drawing area with a nicer looking border. - -## CIAs - - The Amiga utilizes MOS 8520 CIAs to interact with peripheral devices. These chips are similar to the well-known MOS 6526 revisions used in the C64. However, there are subtle differences. For example, Commodore replaced the TOD clock with a native 24-bit counter and supplied the CIA timers with an auto-start mechanism. - -- **DIP** - - This option selects the DIP version of the MOS 8520. The DIP models are the default option as they were used in all classic Amigas. - -- **PLCC** - - This option selects the PLCC version of the MOS 8520, which was used e.g. in the Amiga 600. The differences to the DIP version are extremely subtle. - -## RTC - -The term RTC refers to the Amiga's real-time clock. The first Amiga, the Amiga 1000, never shipped with such a device and it was quite cumbersome to add one. For the Amiga 500, adding an RTC was easy, as many trapdoor memory expansion cards shipped with such a device on board. They are easily recognized by the battery needed to keep the register contents alive. In the Amiga 2000, the real-time clock was soldered directly to the motherboard. In hindsight, this was a bad idea, as the battery, which was also soldered directly to the motherboard, is now the number one death bringer of such machines. Many of us have lost their beloved devices because of the damage caused by the acid of a leaking battery. - -vAmiga offers the following configuration options: - -- **None** - - If this option is selected, no real-time clock is emulated. - -- **Oki** - - This option emulates a MSM6242B real-time clock, manufactured by Oki Semiconductor. Commodore used this chip in the A2000 and the A500+. - -- **Ricoh** - - This option emulates a RF5C01A real-time clock, manufactured by Ricoh, Ltd. Commodore used this chip in the A3000 and the A4000. diff --git a/Documentation/_build/html/_sources/References/Configuration/Compatibility.md.txt b/Documentation/_build/html/_sources/References/Configuration/Compatibility.md.txt deleted file mode 100644 index 5c7141a04..000000000 --- a/Documentation/_build/html/_sources/References/Configuration/Compatibility.md.txt +++ /dev/null @@ -1,67 +0,0 @@ -# Compatibility Panel - -Use this panel to configure the emulation accuracy. - -![Compatibility Panel](images/compatibilityPanel.png "Compatibility Panel") - -## Blitter accuracy - -Amiga supports three Blitter accuracy levels. Level 0 is the fastest option. In this mode, all data is moved together in a single chunk when the **BLTSIZE** register is written. Although this option is far from being accurate, many games do work with this option. In level 1, the Blitter also moves the data in a single chunk, just as in level 0; however, bus timing is emulated afterwards. This means that vAmiga blocks the data bus in the exact same cycles as the real Blitter would. Level 2 is recommended in all scenarios where high accuracy is required. In this mode, the Blitter is emulated cycle by cycle. It transfers data in the exact same cycles as the real Blitter would. - -## Chipset Features - -- **Emulate TOD bug** - - The Amiga CIAs exhibit a bug in the circuitry of the 24-bit counter, commonly referred to as the TOD bug. The bug is part of the increment logic which can falsely trigger a TOD interrupt. This happens when the alarm value matches the counter values at the time when the lowest three nibbles finished to increment. - -- **Emulate dropped register writes** - - Under certain circumstances writing to a DMA pointer register has no effect. On a real Amiga this happens when the pointer register has been used internally exactly one cycle before the update would happen. If you enable this option, vAmiga will check for the drop condition and abort the write operation if necessary. - -## Timing - -- **Sync CIA accesses with E-clock** - - Both Complex Interface Adapters (CIAs) are driven by the so-called *E-clock*, a special signal that is output by the CPU with a frequency equal to one tenth of the native clock rate. Before the CPU can read or write a CIA register, it must synchronize with the E-clock, which slightly slows down program execution. If you disable this option, synchronization with the E-clock is skipped. In this case vAmiga can access CIA registers as fast as all other memory cells. - -## Floppy drives - -- **Speed** - - vAmiga offers two different DMA modes for floppy drives: Standard DMA mode (compatible, but slow) and Turbo DMA mode (fast, but less compatible). - - - **Standard DMA mode** - - In standard DMA mode, vAmiga performs three DMA accesses per scan line, just like the original Amiga. To speed up, drives can be operated with an acceleration factor. In this case, the emulator transfers multiple words in a single DMA slot, something the original machine obviously can't do. - - - **Turbo DMA mode** - - Turbo DMA is applied when the drive speed is set to *Infinite*. In this mode, data is transferred immediately when the DSKLEN register is written to. Although this mode is far from precise, many games and demos can be run in this mode without any issues. - -- **Emulate mechanical delays** - - When this option is enabled, vAmiga applies more stringent timing. That is, it emulates the acceleration and deceleration phases of the drive motor as well as the delay caused by the movement of the drive head from one cylinder to the next. - -- **Piracy** - - These options are rarely needed, but can help to bypass copy protection mechanisms. - - - **Ignore writes to DSKSYNC** - - This option locks the DSKSYNC register. This means that any attempt to change the default SYNC word will be ignored by the emulator. - - - **Always find a SYNC mark** - - This option instructs vAmiga to issue a disk sync interrupt even for tracks that do not contain a SYNC word. - -## Sprites - -- **Collision detection** - - vAmiga allows to disable the collision checking circuity, which is part of Denise. By default, collision checking is disabled because it is expensive to emulate in software and is only needed by a few titles such as Archon or Rotor. - -### Keyboard - -- **Transmit key codes bit by bit** - - The keyboard is a central input device of the Amiga. While Commodore had equipped the Amiga 1000 and the Amiga 2000 with an external keyboard, they decided to integrate the keyboard directly into the case of the Amiga 500. This was only an aesthetic difference, though, as the connection to the motherboard was always the same. The keyboard first generates a key code for each pressed key. After that, it sends the code bit by bit to one of the two CIAs. As soon as the last bit is received, an interrupt is generated and the interrupt handler takes over. By enabling this option, vAmiga emulates the bit-by-bit transmission exactly as described. Disabling this option tells vAmiga to skip the transmission phase and to write the generated keycode directly into the corresponding CIA register. This speeds up emulation, but is less accurate. diff --git a/Documentation/_build/html/_sources/References/Configuration/Memory.md.txt b/Documentation/_build/html/_sources/References/Configuration/Memory.md.txt deleted file mode 100644 index 181f8f267..000000000 --- a/Documentation/_build/html/_sources/References/Configuration/Memory.md.txt +++ /dev/null @@ -1,57 +0,0 @@ -# Memory Panel - -Use this panel to configure the memory configuration and basic access properties. - -![Memory Panel](images/memoryPanel.png "Memory Panel") - -## Ram - -The Amiga distinguishes three types of random access memories: - -- **Chip RAM** - - Chip RAM refers to the factory-installed memory that is located on the motherboard. It is the most flexible RAM, as it can be accessed by both the CPU and the custom chipset. The Amiga 1000 had a limited amount of 256 KB on board, which could be expanded with a 256 KB RAM module plugged into an expansion slot which was located on the front of the computer case. The Amiga 500, which was released later, was shipped with 512 KB straight from the factory. The Amiga 2000 was released in different versions over time. The original Amiga 2000 shipped with 512 KB, just like the Amiga 500 did. Later versions were equipped with 1 MB. - -- **Slow RAM** - - The Amiga supports two types of RAM extensions. The first type is called *Slow RAM* or *Ranger RAM*. In the Amiga 500 case, Slow RAM is added by inserting a memory expansion card into the trapdoor slot at the bottom of the computer case. - - Slow RAM has a somewhat bad reputation because it combines the disadvantages of two worlds. First, it cannot be accessed by the custom chips, as a result, it cannot be used for any data that is processed directly by the Blitter or Copper. Second, it uses the same memory bus as the Chip RAM; this means that Slow RAM cannot be accessed during DMA cycles, even though the RAM itself is not accessible via DMA. - -- **Fast RAM** - - Fast RAM is the third type of RAM expansion. This type of RAM is directly connected to the CPU, which means that it is not accessible to the custom chips, just like Slow RAM isn't. However, since Fast RAM is not connected to the Chip RAM bus, the CPU can access this memory type in parallel to DMA activity. This is where the name Fast RAM stems from. The memory accesses themselves are not accelerated compared to Chip RAM or Slow RAM. - - The default setting is 0 KB, because some Amiga programs refuse to work when Fast RAM is present. - -Since 512 KB of Chip RAM was very little and Fast RAM was very expensive, 512 KB of Chip RAM and 512 KB of Slow RAM was a common memory configuration at the time. Only a few users owned a Fast RAM memory expansion due to its high price. - -## Memory layout - -- **Bank map** - - The original Amigas use a 24-bit address bus, which means that they are capable of addressing 16 MB of memory. We can think of this memory as being divided into chunks of 64 KB, which we refer to as *memory banks*. The bank map determines where specific components are mapped at or mirrored to. For example, Chip RAM always starts at address $000000, while Slow RAM usually shows up at address $C00000. Mirroring means that we can access the same location, such as the register for setting the background color, through several different addresses. Thus a programmer could just as easily use an address from the mirrored range instead of the officially documented address, and many programmers have done so in the past. Unfortunately, the mirrored ranges are not the same in all Amiga models, which means that we have to tell the emulator which memory layout should be used. This is the purpose of this configuration option. - - vAmiga supports four different bank maps: **A500**, **A1000**, **A2000A**, and **A2000B**. The bank maps mainly differ in the memory location of the RTC register space. In the first Amigas, namely the A1000 and the A2000A, the real-time clock was accessed through memory bank $D8. In the A500 and the most common A2000 model, the A2000B, Commodore mapped the real-time clock into memory bank $DC. - - Other differences are related to mirroring. For example, the official location of the custom register space is memory bank $DF. However, this bank is usually mirrored multiple times, which means that the custom registers can also be accessed via other memory addresses. E.g., on older Amigas, the custom register space is mirrored in bank $DC, which is the same bank where later Amigas map in the real-time clock. - -- **Init Pattern** - - This configuration option determines how the memory should be initialized at startup. You can choose between random values, all zeros or all ones. - -- **Unmapped area** - - This option tells vAmiga what to put on the data bus when an unmapped memory location is accessed. Besides telling the emulator to leave the data bus in a floating state, you can choose to return all zeros or all ones. The first option is close to what happens in a real Amiga, but the current implementation is not 100% accurate. Any advice on how to improve emulation accuracy is very welcome. - -## Chipset features - -- **Emulate Slow RAM Mirror** - - The ECS variants of Agnus have an interesting capability that the OCS variants do not. When an ECS Agnus is connected to 512 KB of Chip RAM and 512 KB of Slow RAM, it mirrors the Slow RAM pages into the second Chip RAM segment, making Slow RAM accessible for DMA. Now, the Blitter and Copper have full access to both RAMs. *Move Any Mountain* by Lazy Bones is an Amiga demo that relies on this feature. It was presented at the POLARIS computer party in 1993 and does not work when an OCS Agnus or an incompatible memory configuration is used. - - This configuration option allows the user to enable or disable this feature. If an OCS Agnus is emulated or if the selected memory configuration does not match the 512 KB of Chip RAM + 512 KB of Slow RAM configuration, the selection has no effect. No mirroring will take place. - -- **Emulate Slow RAM Bus delays** - - As mentioned before, the CPU needs a free DMA cycle to access Slow RAM. By default, vAmiga emulates this behavior. Disabling this option removes this restriction, allowing the CPU to access Slow RAM at the same pace as Fast RAM. Please note that accelerating Slow RAM accesses may cause incompatibilities in rare occasions, as the emulated behavior now deviates from what we see on the real machine. diff --git a/Documentation/_build/html/_sources/References/Configuration/Peripherals.md.txt b/Documentation/_build/html/_sources/References/Configuration/Peripherals.md.txt deleted file mode 100644 index 342d43493..000000000 --- a/Documentation/_build/html/_sources/References/Configuration/Peripherals.md.txt +++ /dev/null @@ -1,35 +0,0 @@ -# Peripherals Panel - -Use this field to set up peripheral devices. - -![Peripherals Panel](images/peripheralsPanel.png "Peripherals Panel") - -## Floppy Drives - -Just like a real Amiga, vAmiga supports up to four floppy drives. The internal drive is labeled DF0 and is always present. The external drives are labeled DF1 to DF3. The internal drive is a 3.5" double-density drive providing a storage capacity of 880 KB per floppy disk. The external drives can be configured as double-density drives like the internal drive, or as high-density drives which provide twice the storage capacity. Back in the day, many users, including myself, had an external 5.25" floppy drive connected to their Amiga, mainly because of the much lower price of 5.25" floppy disks. However, such drives only offered a reduced storage capacity of 440 KB. Such single-density drives are not yet supported by vAmiga and will probably never be. - -## Hard Drives - -Thanks to Michael Rasmussen, vAmiga is able to emulate hard drives. Up to four hard drive controllers are supported. Each controller occupies a Zorro II slot and identifies itself to the Amiga via the AUTOCONFIG mechanism at boot time. - -## Game Ports - -The Amiga is equipped with two game ports for connecting input devices such as joysticks or mice. The connected input device can be selected via a popup menu. By default, vAmiga offers you to leave the port empty, to connect the internal mouse or to connect a keyboard-emulated joystick. If an external mouse or a compatible gamepad is present, the device is shown as another option in the popup menu. - -## Serial Port - -vAmiga offers the following options for the serial port: - - - **No Device** - - No device is attached. This is the default option. - - - **Null Modem Cable** - - vAmiga is capable of emulating a null modem cable. By opening two instances of vAmiga on your computer, you can connect them via the null modem cable and play e.g. a nice game of Battle Chess with two Amigas fighting each other. - - - **Loopback Cable** - - A loopback cable connects the output pins of the serial port with its input pins. Such a cable is required, e.g., to run the serial port test built into **Amiga Test Kit**: - - ![Amiga Test Kit](images/AmigaTestKitSerial.png "Amiga Test Kit") diff --git a/Documentation/_build/html/_sources/References/Configuration/Roms.md.txt b/Documentation/_build/html/_sources/References/Configuration/Roms.md.txt deleted file mode 100644 index 9de09794a..000000000 --- a/Documentation/_build/html/_sources/References/Configuration/Roms.md.txt +++ /dev/null @@ -1,21 +0,0 @@ -# ROM Panel - -Use this panel to add ROM images to the emulator. - -![Rom Panel](images/romPanel.png "Rom Panel") - -When vAmiga is started for the first time, you will be taken directly to this panel. This is the place where you will manage an essential part of your virtual Amiga: The Kickstart ROM. - -## Kickstart ROM - -ROM images are added via drag and drop. To install a Kickstart ROM, simply drop a ROM image into the upper drop zone. Immediately after the image has been dropped, vAmiga performs a two-stage check. In the first stage, the file size and the values of some magic bytes are verified. If the file size does not match or the magic byte sequence is unknown to the emulator, the ROM image is rejected. Otherwise, the emulator continues by comparing the CRC checksum of the ROM image with the entries of a small database. When the CRC checksum is found, the name of the ROM is displayed along with some other information such as the release date. In the screenshot above you can see that vAmiga has recognized the dragged-in file as an original Commodore Kickstart ROM 1.3. If the CRC checksum is unknown to the emulator, vAmiga classifies the ROM as *Unknown*. You can still start the emulator with it, but there is no guarantee that the emulator will work as expected. - -Please note that vAmiga does not ship with any of the original Commodore ROMs. All Amiga ROMs are the intellectual property Cloanto™ and distributed for a fee. However, if you have purchased a Kickstart ROM legally, you can use it in vAmiga with no issues. - -If you don't have an original Kickstart at hand, you may choose to install the AROS ROM. The Amiga Research Operating System ROM is an open-source Kickstart variant which is freely redistributable. Two revisions of the AROS ROM are shipped with the emulator, which can be installed using the dropdown menu in the lower left corner. Unfortunately, not all Amiga programs are compatible with AROS, which is why I strongly recommend buying original ROMs. - -## Extension ROM - -In case you decide to resort to the AROS Kickstart replacement, you will notice that there will be two ROMs installed in your virtual Amiga. This is due to the size of the AROS ROM, which significantly exceeds the original Kickstart size of 512 KB. For this reason, AROS has been split into two separate ROMs. The first one appears in the same memory range as the original Kickstart, the second one appears in the address range $E00000 - $E7FFFF. - -ROM extensions can also be installed manually by dropping a ROM image into the lower drop zone. Unlike the Kickstart ROM, which always resides in the same address range, the expansion ROM can be mapped to different memory areas. As mentioned above, the AROS expansion ROM must be visible to $E0000 to function. Other expansion ROMs, however, are expected to be visible in the $F00000 - $F7FFFF address range. You can set the address range manually by selecting the memory range from the popup menu next to the expansion ROM. diff --git a/Documentation/_build/html/_sources/References/Configuration/Video.md.txt b/Documentation/_build/html/_sources/References/Configuration/Video.md.txt deleted file mode 100644 index 144f3cc67..000000000 --- a/Documentation/_build/html/_sources/References/Configuration/Video.md.txt +++ /dev/null @@ -1,97 +0,0 @@ -# Video Panel - -Use this panel to change the video settings. The Video panel is divided into two sub-panels: The *Screen panel* and the *Effects panel*. In the first one we can control basic image properties, the visible screen area and sync mode. The second panel allows us to fine-tune the shader pipeline. It allows us to configure various effects that try to mimic the look and feel of a CRT monitor from back in the day. - -## Monitor - - ![Video Panel](images/videoPanel.png "Video Panel") - -### Palette - - This option is used to select the monitor type. Besides emulating a color monitor, which is the default option, different types of monochrome monitors can be emulated, such as amber or green monitors. As with a real monitor from back in the day, you can set three parameters that affect the color palette: *brightness*, *contrast*, and *color*. - - The following screenshot shows how vAmiga looks on a monochrome monitor with a sepia color: - - ![Sepia](images/sepia.png "Sepia") - - ### Zoom - -The zoom level defines the visible screen area and can be changed manually for the horizontal and vertical axis. The drop-down menu provides some predefined values from which you can choose. - - ### Center - -While the zoom level defines the dimensions of the visible screen area, the two centering parameters determine the position of the center point. Please note that changing these parameters has no effect if the zoom level is zero. In this case, the visible screen area corresponds to the entire texture, which makes it impossible to move the center point. - - ### Refresh - -vAmiga supports two methods for synchronizing the emulator thread. The default method is based on timers. In this mode the emulator puts itself to sleep after a single frame has been computed. When the thread wakes up, the next frame is computed and so on. This method is the most flexible, as it supports arbitrary frame rates. I.e. vAmiga computes 50 frames per second in PAL mode and 60 frames per second in NTSC mode. However, there is a problem associated with this method. Since the emulator thread is not synchronized with the graphic loop, it may happen that some frames are either dropped or displayed twice. - - In video games, a common workaround is to have the graphic loop trigger the image calculation. This method is usually called VSYNC because the image provider and the graphic loop no longer work independently. When VSYNC is enabled in vAmiga, something similar happens. The emulator thread no longer sets a timer to wake up the emulator thread. Instead, it waits for a wake-up signal from the graphic backend. The result is that the number of images requested exactly matches the number of images drawn. However, this method has its pitfalls, too. Since a modern TFT display normally updates at 60Hz, vAmiga is asked to calculate 60 frames per second. This is fine for NTSC, but not for PAL. If a PAL machine is emulated in this mode, it will run slightly faster than the original machine. - - However, with modern Macs, this problem is easily solved. With the introduction of ProMotion technology, Macs can be configured to operate at user-defined refresh rates. On such machines, the default refresh rate can be lowered to 50 Hz in the system settings. As a result, the Amiga runs at its original speed again. - - ![Mac Display Settings](images/proMotion.png "Mac Display Settings") - -## Effects - - vAmiga utilizes a sophisticated graphic pipeline that allows the emulator texture to be manipulated in various ways. - - ![Effects Panel](images/effectsPanel.png "Effects Panel") - -### Upscaling - - The GPU pipeline of vAmiga includes two pixel upscaling stages. In the first stage, in-texture upscaling is performed to all lores lines. In this stage, the texture size remains unchanged. The second stage is a more traditional upscaling stage where the texture size is doubled. The selected upscaling algorithm is applied to both lores and hires pixels. - - For each stage, the upscaling algorithm can be selected independently. Currently vAmiga supports the EPX and xBR upscaling algorithms. If upscaling is not desired, one or both stages can be disabled. - - ![Original image](images/defenderOriginal.png "Original image") - ![Upscaled image](images/defenderUpscaled.png "Upscaled image") - -### Scanlines - -Three scanline modes are supported: *None*, *Embedded* and *Superimposed*. - -- **Embedded Scanline Mode** - - In this mode, scanlines are emulated by darkening every other scanline of the emulator texture. This method has the disadvantage of creating Moiré patterns. To avoid these patterns, the height of the emulator window must be adjusted so that each line of the emulator texture maps to a unique line on the native screen. vAmiga can set the correct height for you. All you need to do is to select the *Adjust* menu item in the *Window* menu. - -- **Superimposed Scanline Mode** - - In this mode, scanlines are generated by the fragment shader. The fragment shader is applied very late in the graphic pipeline and already working on the final texture. As a result, Moiré effects are no longer possible. A disadvantage of this method is that the dimensions of the scanlines are now independent of the height of the emulator window. This means that the number of displayed scanlines does no longer match the number of scanline we would see on a real CRT monitor. - - ![Original image](images/defenderOriginal.png "Original image") - ![Scanlines](images/defenderScanlines.png "Scanlines") - - ### Dot Mask - - vAmiga can emulate various dot mask patterns to emulate the small red, green and blue dots used by a real CRT monitor to compose the image. - - ![Original image](images/defenderOriginal.png "Original image") - ![Dot Mask](images/defenderDotMask.png "Dot Mask") - - ### Flicker - - PAL or NTSC screens are designed to transmit the image in the form of 50 or 60 fields per second. A picture consists of two fields, one containing all even lines and the other containing all odd lines. This results in an output rate of 25 frames for PAL and 30 frames for NTSC. In the default display modes, the Amiga uses the same pixel information for both fields, resulting in a stable picture at 50 or 60 Hz. However, the Amiga had the ability to double the vertical resolution by using different images for both fields. These modes are called interlace modes. Since both images only repeat 25 or 30 times per second, the image flickers for the human eye. vAmiga is able to emulate flickering in different intensities. - - Back in the day, *Flicker Fixer* was a popular, albeit expensive, product. By buffering the video image, it managed to produce a smooth picture at twice the vertical resolution. To mimic what Flicker Fixer did back then, simply disable flicker emulation in vAmiga. - -### Blur - - When this option is enabled, vAmiga adds another stage to the graphics pipeline that applies a Gaussian blur filter to the upscaled image. - - ![Original image](images/defenderOriginal.png "Original image") - ![Blur](images/defenderBlur.png "Blur") - -### Bloom - - When a bright object is displayed on a dark background, the white light spreads out a bit when displayed on a CRT monitor. As a result, the object looks as if it was slightly glowing. This effect is called *blooming*. By activating this option, vAmiga will try to reproduce this effect. - - ![Original image](images/defenderOriginal.png "Original image") - ![Bloom](images/defenderBloom.png "Bloom") - -### Rays - - A CRT tube uses three separate electron beams, one for each color channel. Each beam produces a separate image on the phosphor layer. When the electron beams are aligned, the color layers appear to be stacked precisely on top of each other and produce a crisp image. If the electron beams get misaligned, color artifacts occur because the three color layers are now shifted against each other. vAmiga can emulate this effect with varying intensity. - - ![Original image](images/defenderOriginal.png "Original image") - ![Misaligned](images/defenderMisaligned.png "Misaligned") diff --git a/Documentation/_build/html/_sources/References/Configuration/index.rst.txt b/Documentation/_build/html/_sources/References/Configuration/index.rst.txt deleted file mode 100644 index 7f9f8ebca..000000000 --- a/Documentation/_build/html/_sources/References/Configuration/index.rst.txt +++ /dev/null @@ -1,16 +0,0 @@ -Virtual Machine Settings -======================== - -The virtual machine settings include all configuration options that apply to a single emulator instance. The settings dialog can be opend via the **Machine** menu or by clicking the corresponding icon in the toolbar. The available options are organized in several tabs: - -.. toctree:: - :maxdepth: 1 - :caption: Virtual Machine Settings - - Roms - Chipset - Memory - Peripherals - Compatibility - Audio - Video diff --git a/Documentation/_build/html/_sources/References/FileFormats.md.txt b/Documentation/_build/html/_sources/References/FileFormats.md.txt deleted file mode 100644 index 1d15741ff..000000000 --- a/Documentation/_build/html/_sources/References/FileFormats.md.txt +++ /dev/null @@ -1,36 +0,0 @@ -# Supported File Formats - -## Floppy disks - -vAmiga supports the following file formats for floppy disks: - -- **ADF format** - - ADF files contain a byte dump of all sectors of an Amiga diskette. The format is extremely simple in structure, since it does not store any header information. The ADF format is the most widely used format for Amiga floppy disks and almost all non-copy-protected titles are available in form of ADF files. - -- **Extended ADF format** - - The extended ADF format has been created to store copy-protected disks or disks that were formatted in a non-standard format. It has a much more complicated structure than the standard ADF format and offers different methods to represent track data. For example, the format is able to store the uninterpreted MFM data stream of single tracks or the whole disk. - -- **DMS Format** - - DMS files store a digital image of an Amiga floppy disk, just like ADFs. However, the internal representation is much more complicated. The format is very popular in the demo scene. Thus, you will find many demos encoded in this format. - -- **EXE Format** - - vAmiga also supports pure Amiga executables. When such a file is passed to the emulator, vAmiga creates a floppy disk on-the-fly and copies the executable to it. It also makes the floppy bootable by adding a boot block and a startup sequence that loads the executable. - -- **IMG Format** - - Image files are floppy disks in MS-DOS format. Inserting such a floppy disk makes sense only if you use special software that can read such floppy disks. - -- **Folders** - - vAmiga allows directories of the host computer to be used in the form of floppy disks. When a directory is provided by drag-and-drop, the emulator tries to write all files of the directory to an empty floppy disk. If the floppy disk has sufficient space for all files, the disk can be used inside the emulator or exported, e.g., in form of an ADF file. - -## Hard drives - -- **HDF Format** - - HDF files are the equivalent of ADF files for hard disks. An HDF file contains a byte dump of all sectors of a hard disk, just as an ADF file contains a byte dump of all sectors of a floppy disk. - diff --git a/Documentation/_build/html/_sources/References/Preferences/Controls.md.txt b/Documentation/_build/html/_sources/References/Preferences/Controls.md.txt deleted file mode 100644 index 7c2254b76..000000000 --- a/Documentation/_build/html/_sources/References/Preferences/Controls.md.txt +++ /dev/null @@ -1,19 +0,0 @@ -# Controls Panel - -Use this section to configure the mouse, joysticks, and joystick emulation keys. - -![Controls Panel](images/controlsPanel.png "Controls Panel") - -## Mouse - -vAmiga supports several ways to release and retain the mouse pointer. The conventional way is to use a special key combination. Since different emulators use different combinations, vAmiga allows the user to choose between **Alt+Cmd** and **Alt-Ctrl**. The most convenient way to release the mouse is to activate the shake detector. When activated, rapidly move the mouse from left to right a few times to release the mouse. - -vAmiga also offers several options for retaining the mouse. Besides using a special key combination, the emulator can be configured to retain the mouse when the user pushed the left button inside the emulator window or to retain the mouse automatically when the mouse pointer is dragged into the emulator window. - -## Joysticks - -The emulator offers a built-in multi-shot mode. You can adjust the firing frequency and choose whether to fire constantly or in volleys with a certain number of bullets. - -## Emulation keys - -As an alternative to a real joystick, you can use the emulator with a key-emulated joystick. vAmiga allows you to predefine two sets of emulation keys. Mouse buttons can be mapped, too. This is a handy solution for the right and middle mouse button, which are not physically present on most Apple mice. diff --git a/Documentation/_build/html/_sources/References/Preferences/Devices.md.txt b/Documentation/_build/html/_sources/References/Preferences/Devices.md.txt deleted file mode 100644 index 65b6224e4..000000000 --- a/Documentation/_build/html/_sources/References/Preferences/Devices.md.txt +++ /dev/null @@ -1,35 +0,0 @@ -# Devices Panel - -Use this field to configure external USB gamepads. - -![Devices Panel](images/devicesPanel.png "Devices Panel") - -After plugging in an external USB device, vAmiga checks the device for compatibility. If a suitable gamepad is detected, vAmiga allows the user to adjust the axis assignment. vAmiga comes with a list of known devices and automatically chooses the correct axis assignment when such a device is detected. For gamepads that are not known to the emulator, you have a good chance of getting it to work by trying some axis assignments manually. - -## Supported devices - -At the time of writing this documentation, known devices include the following: - -- Competition Pro SL-650212 -- Competition Pro SL-6602 -- Nimbus+ -- iNNEXT Retro (SNES) -- Mayflash Magic-NS 1.2 -- XBox Carbon Black -- XBox One Wired Controller -- Sony DualShock 3 -- Sony DualShock 4 -- Sony DualShock 4 (2nd Gen) -- Sony DualSense -- HORIPAD for Nintendo Switch -- The C64 Joystick - -## Supported USB adapters - -With the help of a USB retro adapter you can also connect original Commodore joysticks. vAmiga has been tested with the following two adapters: - -- aJoy Retro Adapter -- RetroFun! Joystick Adapter - -My personal recommendation is to invest in the Competition Pro SL-650212. It has lower latency than its predecessor, the SL-6602, and offers the best retro experience in my opinion. Also, I can recommend using an original Competition Pro from back in the day in combination with the RetroFun! joystick adapter. - diff --git a/Documentation/_build/html/_sources/References/Preferences/General.md.txt b/Documentation/_build/html/_sources/References/Preferences/General.md.txt deleted file mode 100644 index bd74a0173..000000000 --- a/Documentation/_build/html/_sources/References/Preferences/General.md.txt +++ /dev/null @@ -1,25 +0,0 @@ -# General Panel - -Use this panel to change general settings, such as the screenshot and video format, or the behavior in fullscreen mode. - -![General Panel](images/generalPanel.png "General Panel") - -## Screenshots - -The options in this category allow the user to customize the source, layout and target format of a screenshot. - -## Screen captures - -vAmiga features a screen recorder that utilizes FFmpeg as a backend. The options in this category allow the user to set various recording parameters. Please note that FFmpeg cannot be bundled with the emulator due to licensing constraints. Before using the screen recorder, you must manually install FFmpeg on your computer. - -## Snapshots - -vAmiga can be configured to take a snapshot at regular intervals. Originally, This option was added to master difficult games. Please keep in mind that snapshots are intended for being used as temporary save-points and not as a long-term preservation format. A snapshot created with the current version of vAmiga will most likely not be readable in the next. - -## Full screen mode - -The first option lets you select the full-screen layout. The second option determines whether the ESC key should function as an emulation key or as a control key to exit the full screen mode. - -## Miscellaneous - -The options in this category determine how vAmiga should react to certain events such as ejecting a floppy disk or closing an emulator window. For example, one option determines how vAmiga will behave when a floppy disk containing unsaved data is ejected. Unlike other emulators, vAmiga is designed to not modify media files. For example, if an ADF has been inserted into a floppy drive, the floppy disk can be modify without hesitation. The original ADF remains untouched. The disadvantage, however, is that you have to export a disk manually to preserve the new content. diff --git a/Documentation/_build/html/_sources/References/Preferences/index.rst.txt b/Documentation/_build/html/_sources/References/Preferences/index.rst.txt deleted file mode 100644 index 3f1ce6108..000000000 --- a/Documentation/_build/html/_sources/References/Preferences/index.rst.txt +++ /dev/null @@ -1,12 +0,0 @@ -Emulator Settings -================= - -The emulator settings include all configuration options that apply to all emulator instances simultaneously. To open the emulator settings, either select **Settings...** from the **vAmiga** menu or click on the corresponding icon in the toolbar. The available options are organized in three tabs: - -.. toctree:: - :maxdepth: 1 - :caption: Emulator Settings - - General - Controls - Devices diff --git a/Documentation/_build/html/_sources/Tutorials/Exploring.md.txt b/Documentation/_build/html/_sources/Tutorials/Exploring.md.txt deleted file mode 100644 index 0ddfe6ea7..000000000 --- a/Documentation/_build/html/_sources/Tutorials/Exploring.md.txt +++ /dev/null @@ -1,130 +0,0 @@ -# Exploring the User Interface - -In this tutorial, we will explore the most commonly used elements of the vAmiga user interface. - -## Toolbar - -Many of the basic emulator properties can be controlled via the toolbar, which defaults to the following: - -![Toolbar](images/toolbar.png "Toolbar") - -We will review the elements of the toolbar one by one. - -### Controls - -The three buttons in the *Control* section allow us to control the emulator state: - -![Toolbar](images/toolbar1.png "Toolbar") - -The functionality of these buttons is what you might have already guessed: -- The left button pauses or resumes emulation. -- The middle button performs a hard reset. -- The right button switches the Amiga on or off. - -### Preferences - -![Toolbar](images/toolbar2.png "Toolbar") - -The two buttons in the *Preferences* section let us configure vAmiga. The left button opens the *emulator settings* window, which manages the settings that apply to all emulator instances simultaneously. - -![Preferences](images/generalPanel.png "Preferences") - -All available options are described in a separate document. For the purpose of this tutorial, we do not need to change anything here and can proceed to the next option right away. - -The right button opens the Configuration window where the virtual machine is configured. The options are organized in tabs, similar to the emulator settings window. You are already familiar with the first tab if you have read the *Getting started* tutorial. It is the tab where the ROM of the Amiga is configured. - -![Configuration](images/romPanel.png "Configuration") - -All available options are described in a separate document. Please note that all settings made in the Configuration are specific to a single emulator instance. Therefore, it is possible to run two emulator instances with different configurations side by side. - -### Keyboard - -![Toolbar](images/toolbar3.png "Toolbar") - -Although the Amiga is quite an aged computer by now, it already utilized a keyboard whose layout was quite similar to the ones used today. Therefore, in vAmiga you will be using the native Mac keyboard for typing, and for most Amiga keys you will find a perfect match on your native keyboard. However, there are exceptions. For example, the Amiga is equipped with a special *Help* key that has no direct counterpart on the Mac keyboard. Also, some Mac keys are directly linked to operating system actions, which affects emulation. The most prominent examples are the two Command keys that are used to trigger operating system actions. - -In cases where you need to press a key that is not directly accessible from your native keyboard, the virtual keyboard can be used. If you click the corresponding icon in the toolbar, the virtual keyboard will open as a sheet on top of the emulator window: - -![Virtual keyboard](images/virtualKeyboard.png "Virtual keyboard") - -The keys on the virtual keyboard can be clicked with either the left or the right mouse button: - -- **Left Button** - - When the left mouse button is used, the selected key is pushed down and automatically released after a short delay. Use this option if you wish to press a single key on the keyboard. - -- **Right button** - - When the right mouse button is used, the selected key is permanently pushed down or permanently released if it was pushed down. Use this option if you want to press a specific key combination, e.g. the reset combination *Ctrl+Amiga+Amiga* as shown in the screenshot. - -As soon as a key is pressed with the left mouse button, the virtual keyboard disappears. However, it is also possible to open the virtual keyboard as a separate window that can reside next to the emulator window. To open the virtual keyboard as window, press *Cmd-K*, the key equivalent for the *Show...* item in the *Keyboard* menu. - -### Game Ports - -The two gameport icons allow us to quickly switch between the input devices connected to the gameports of the Amiga. - -![Toolbar](images/toolbar4.png "Toolbar") - -All available devices are displayed in a popup menu: - -![Gameport menu](images/gameports.png "Gameport menu") - -The mouse refers to the Mac's internal mouse. Note that the Mac does not distinguish between the mouse and the touchpad. This means that both devices cannot be used independently. The next two items refer to keyboard-emulated joysticks. vAmiga differentiates between two sets of keys, which can be configured in the emulator settings. The last two items are placeholders, which are currently grayed out. As soon as a compatible gamepad is connected to the host, e.g. a compatible USB joystick, the new device will appear in one of the placeholder slots. - -### Snapshots - -The three toolbar icons in this section can be used to manage snapshots. Snapshots are frozen emulator states that can be restored at a later time. - -![Toolbar](images/toolbar5.png "Toolbar") - -- The left button creates a snapshot and adds it to the snapshot storage. -- The middle button reverts to the emulator state recorded in the most recent snapshot. -- The right button opens the snapshot browser. - - ![Snapshot browser](images/snapshotBrowser.png "Snapshot browser") - - The snapshot browser is to vAmiga what *Time Machine* is to the Mac. It lets us browse through the snapshot memory in a graphical way. - -Please note that snapshots are not stored permanently. The next time you start vAmiga, you will start over with an empty snapshot storage. This is because snapshots were originally intended as a safe-point mechanism for mastering difficult games. Snapshots were never intended for long-term preservation of emulator states, and never will be, although many users would like to use them that way. The reason is that snapshots do not only contain Amiga specific data like the RAM contents or the values of CPU registers. It also contains the values of many emulator-specific variables that have no direct equivalent on the real machine. The set of internal variables usually changes from release to release, and so does the snapshot format. Therefore, you can almost be certain that snapshots taken with the current version of vAmiga will no longer work when the next version comes out. - -### Inspectors - -A major design goal of vAmiga was to make the emulated Amiga as transparent as possible. To achieve this goal, vAmiga offers a number of tools that give the user insight into the Amiga's internal workings. The *Inspectors* section of the toolbar grants access to these tools. - -![Toolbar](images/toolbar6.png "Toolbar") - -#### Inspector Panel - -The Inspector is the primary place to retrieve information about the current state of the emulator. It provides several tabs where the current state of various components can be examined. The first tab is the CPU tab, which looks like this: - -![Inspector panel](images/inspectorPanel.png "Inspector panel") - -The panel displays the currently executed program and the contents of all CPU registers. The CPU panel is also the gateway to the CPU debugger. We can use it to single-step through the currently executing instruction stream or to set breakpoints and watchpoints. - -#### Monitor Panel - -The monitor panel provides additional debugging aids: - -![Monitor panel](images/monitorPanel.png "Monitor panel") - -The left column contains the controls for the DMA debugger, which can be used to visualize all memory bus accesses in real time. When enabled, the emulator texture is overlaid with an additional graphics layer that visualizes the bus owner for Chip or Slow RAM accesses. The following screenshot shows a scene from Rink a Dink with the DMA debugger enabled. - -![DMA debugger](images/dmaDebugger.png "DMA debugger") - -The yellow and brown dots represent Copper and Blitter accesses, respectively. The red dots mark the memory refresh cycles and the pink dots the DMA slots for transferring audio data. Bitplane DMA is visualized in cyan. The scene reveals a lot about the inner workings of this demo. The creators decided to use a very small bitplane window that just covers the polygon. This bitplane window is permanently relocated as the polygon moves. [This small YouTube video](https://www.youtube.com/watch?v=aDFVwy4gTaE) shows what *Rink a Dink* looks like when run in vAmiga with the DMA debugger enabled. If you don't want to watch the entire video, you can fast forward at 1:20. Here you can see the animated polygon in action. - -The center area of the monitor panel controls the so-called *activity monitors*. When activated, the texture of the emulator is overlaid with small displays giving insight into the activity of various Amiga components: - -![Activity monitors](images/activityMonitors.png "Activity monitors") - -The elements in the right column control the stencil feature. With this feature, vAmiga is able to erase certain graphic layers. For example, it is possible to remove all pixels of a certain playfield or sprite. The removed pixels are replaced by the pixels of a checkerboard pattern that looks like it shines through holes in the emulator texture, especially in animated scenes. - -![Stencils](images/stencil.png "Stencils") - -#### Retro Shell - -The third button in the *Inspectors* section opens *Retro Shell*, vAmiga's text-based debug console. The shell can be used to control vAmiga with a variety of text commands. - -![Retro Shell](images/retroShell.png "Retro Shell") - -Retro Shell can also process script files. This functionality is used extensively by vAmiga's test suite (vAmigaTS) to perform automatic regression tests. As a normal user, you will most likely never need to use the shell, since most of the emulator's functions are accessible through the graphical user interface. diff --git a/Documentation/_build/html/_sources/Tutorials/GettingStarted.md.txt b/Documentation/_build/html/_sources/Tutorials/GettingStarted.md.txt deleted file mode 100644 index 263ed4ea3..000000000 --- a/Documentation/_build/html/_sources/Tutorials/GettingStarted.md.txt +++ /dev/null @@ -1,55 +0,0 @@ -# Getting Started - -This tutorial describes how to launch vAmiga and install a Kickstart ROM. - -## Installing vAmiga - -vAmiga is a native Mac application and as easy to install as most other Mac software. Download the latest version from the main page and copy the executable into the application folder. - -vAmiga's deployment target is **macOS 12 (Monterey)** which means that you can't run the app on earlier macOS releases. Please note that vAmiga is only extensively tested with the latest macOS version. Thus, compatibility problems may well occur with older macOS versions. - -Please keep in mind that vAmiga has been developed with limited work-power leaving no room for supporting older macOS releases. You can always extract older version from the source-code repository, but you will be on your own by doing so. - -## Installing a Kickstart ROM - -Emulating an Amiga requires a Kickstart ROM. Since the original Amiga ROMs are the intellectual property of Cloanto™, they cannot be shipped with the emulator. Thus, when opening vAmiga for the first time, the emulator will greet you with a ROM dialog: - -![Inspectors](images/roms1.png "Rom Dialog") - -In this dialog, a Kickstart ROM can be added via drag and drop. If you are the legal owner of a ROM image, you can easily install it by dragging it over the ROM icon: - -![Inspectors](images/roms2.png "Rom Dialog") - -Once the ROM is installed, the emulator is ready to be powered on. To do so, click the power button and have fun with your new old Amiga: - -![Inspectors](images/roms3.png "Rom Dialog") - -In case you don't own a legal ROM, you can alternatively start vAmiga with the free AROS Kickstart replacement. AROS ROMs ship with the emulator and can be selected from the *Install ROM* popup-menu located in the lower left corner. - -At you can see below, the popup menu is presently grayed out therefore inaccessible. This is to protect against accidental changes to the Kickstart ROM while the emulator is running. To access the menu, turn off the emulator first by clicking on the lock icon. - -![Inspectors](images/roms4.png "Rom Dialog") - -After the emulator has been powered off, the AROS ROMs can be installed with a single click: - -![Inspectors](images/roms5.png "Rom Dialog") - -Again, clicking the power button starts the emulator. With the free Kickstart ROM replacement installed, the AROS boot screen shows up: - -![Inspectors](images/roms6.png "Rom Dialog") - -Even though the AROS ROMs are a great achievement of the open source community, we recommend installing original Commodore ROMs as they offer much higher compatibility. - -Please keep in mind that vAmiga will not remember the ROM settings by default, i.e., the next time the emulator is started, the ROM dialog will appear again. If you wish to use the currently installed ROM permanently, click the *Use as Default* button next to the AROS button. - -## Inserting a floppy disk - -Next, we'll show how to insert a floppy disk. Thanks to the diligent work of many Amiga enthusiasts, almost all Amiga software from back in the day has been saved from decay and translated into modern data formats. The most important data format for the Amiga is the ADF format, which is a digital image of an Amiga floppy disk. On the Internet you will find countless ADFs and most likely your beloved titles from back then, too. Please note that despite their age, most Amiga titles are protected by copyright and may not be used without the permission of the rights holder. - -The most convenient way to insert a floppy disk is by drag and drop. When an ADF file is dragged into the emulator window, four drop zones appear representing drives DF0 through DF3. Simply drop the file onto the drive in which you want to insert the disk. - -![Inserting a floppy disk](images/dropzone.png "Inserting a floppy disk") - -Shortly after dropping the disk onto the drop zone for drive DF0, the Amiga recognizes the inserted disk and starts to boot. In the example above, we've inserted a bootable version of *Rink a Dink*, a popular Amiga demo which was published in 1993 by *Lemon*. The demo works flawlessly with the AROS ROMs as it takes over the machine entirely. - -![Rink a dink](images/rinkadink.png "Rink a dink") diff --git a/Documentation/_build/html/_sources/index.rst.txt b/Documentation/_build/html/_sources/index.rst.txt deleted file mode 100644 index c967fdffa..000000000 --- a/Documentation/_build/html/_sources/index.rst.txt +++ /dev/null @@ -1,46 +0,0 @@ -.. image:: images/va-titlepage.png - :width: 100% - :align: center - :alt: Banner - -vAmiga User's Manual -==================== - -.. toctree:: - :maxdepth: 1 - :caption: Overview - - Overview/About - -.. toctree:: - :maxdepth: 1 - :caption: Tutorials - - Tutorials/GettingStarted - Tutorials/Exploring - -.. toctree:: - :maxdepth: 1 - :caption: How-to guides - - HowTo/MappingCmd - HowTo/NullModemCable - -.. toctree:: - :maxdepth: 1 - :caption: References - - References/Preferences/index.rst - References/Configuration/index.rst - References/FileFormats - -.. toctree:: - :maxdepth: 1 - :caption: Developers Corner - - Developer/ClassHierarchy - Developer/ThreadClass - Developer/MessageQueue - Developer/RunLoop - Developer/EventScheduler - Developer/SuperHires diff --git a/Documentation/_build/html/_static/basic.css b/Documentation/_build/html/_static/basic.css deleted file mode 100644 index 4313f86a6..000000000 --- a/Documentation/_build/html/_static/basic.css +++ /dev/null @@ -1,903 +0,0 @@ -/* - * basic.css - * ~~~~~~~~~ - * - * Sphinx stylesheet -- basic theme. - * - * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- main layout ----------------------------------------------------------- */ - -div.clearer { - clear: both; -} - -div.section::after { - display: block; - content: ''; - clear: left; -} - -/* -- relbar ---------------------------------------------------------------- */ - -div.related { - width: 100%; - font-size: 90%; -} - -div.related h3 { - display: none; -} - -div.related ul { - margin: 0; - padding: 0 0 0 10px; - list-style: none; -} - -div.related li { - display: inline; -} - -div.related li.right { - float: right; - margin-right: 5px; -} - -/* -- sidebar --------------------------------------------------------------- */ - -div.sphinxsidebarwrapper { - padding: 10px 5px 0 10px; -} - -div.sphinxsidebar { - float: left; - width: 19rem; - margin-left: -100%; - font-size: 90%; - word-wrap: break-word; - overflow-wrap : break-word; -} - -div.sphinxsidebar ul { - list-style: none; -} - -div.sphinxsidebar ul ul, -div.sphinxsidebar ul.want-points { - margin-left: 20px; - list-style: square; -} - -div.sphinxsidebar ul ul { - margin-top: 0; - margin-bottom: 0; -} - -div.sphinxsidebar form { - margin-top: 10px; -} - -div.sphinxsidebar input { - border: 1px solid #98dbcc; - font-family: sans-serif; - font-size: 1em; -} - -div.sphinxsidebar #searchbox form.search { - overflow: hidden; -} - -div.sphinxsidebar #searchbox input[type="text"] { - float: left; - width: 80%; - padding: 0.25em; - box-sizing: border-box; -} - -div.sphinxsidebar #searchbox input[type="submit"] { - float: left; - width: 20%; - border-left: none; - padding: 0.25em; - box-sizing: border-box; -} - - -img { - border: 0; - max-width: 100%; -} - -/* -- search page ----------------------------------------------------------- */ - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li p.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} - -/* -- index page ------------------------------------------------------------ */ - -table.contentstable { - width: 90%; - margin-left: auto; - margin-right: auto; -} - -table.contentstable p.biglink { - line-height: 150%; -} - -a.biglink { - font-size: 1.3em; -} - -span.linkdescr { - font-style: italic; - padding-top: 5px; - font-size: 90%; -} - -/* -- general index --------------------------------------------------------- */ - -table.indextable { - width: 100%; -} - -table.indextable td { - text-align: left; - vertical-align: top; -} - -table.indextable ul { - margin-top: 0; - margin-bottom: 0; - list-style-type: none; -} - -table.indextable > tbody > tr > td > ul { - padding-left: 0em; -} - -table.indextable tr.pcap { - height: 10px; -} - -table.indextable tr.cap { - margin-top: 10px; - background-color: #f2f2f2; -} - -img.toggler { - margin-right: 3px; - margin-top: 3px; - cursor: pointer; -} - -div.modindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -div.genindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -/* -- domain module index --------------------------------------------------- */ - -table.modindextable td { - padding: 2px; - border-collapse: collapse; -} - -/* -- general body styles --------------------------------------------------- */ - -div.body { - min-width: unset; - max-width: 45rem; -} - -div.body p, div.body dd, div.body li, div.body blockquote { - -moz-hyphens: auto; - -ms-hyphens: auto; - -webkit-hyphens: auto; - hyphens: auto; -} - -a.headerlink { - visibility: hidden; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink, -caption:hover > a.headerlink, -p.caption:hover > a.headerlink, -div.code-block-caption:hover > a.headerlink { - visibility: visible; -} - -div.body p.caption { - text-align: inherit; -} - -div.body td { - text-align: left; -} - -.first { - margin-top: 0 !important; -} - -p.rubric { - margin-top: 30px; - font-weight: bold; -} - -img.align-left, figure.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; -} - -img.align-right, figure.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; -} - -img.align-center, figure.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -img.align-default, figure.align-default, .figure.align-default { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left; -} - -.align-center { - text-align: center; -} - -.align-default { - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- sidebars -------------------------------------------------------------- */ - -div.sidebar, -aside.sidebar { - margin: 0 0 0.5em 1em; - border: 1px solid #ddb; - padding: 7px; - background-color: #ffe; - width: 40%; - float: right; - clear: right; - overflow-x: auto; -} - -p.sidebar-title { - font-weight: bold; -} - -nav.contents, -aside.topic, -div.admonition, div.topic, blockquote { - clear: left; -} - -/* -- topics ---------------------------------------------------------------- */ - -nav.contents, -aside.topic, -div.topic { - border: 1px solid #ccc; - padding: 7px; - margin: 10px 0 10px 0; -} - -p.topic-title { - font-size: 1.1em; - font-weight: bold; - margin-top: 10px; -} - -/* -- admonitions ----------------------------------------------------------- */ - -div.admonition { - margin-top: 10px; - margin-bottom: 10px; - padding: 7px; -} - -div.admonition dt { - font-weight: bold; -} - -p.admonition-title { - margin: 0px 10px 5px 0px; - font-weight: bold; -} - -div.body p.centered { - text-align: center; - margin-top: 25px; -} - -/* -- content of sidebars/topics/admonitions -------------------------------- */ - -div.sidebar > :last-child, -aside.sidebar > :last-child, -nav.contents > :last-child, -aside.topic > :last-child, -div.topic > :last-child, -div.admonition > :last-child { - margin-bottom: 0; -} - -div.sidebar::after, -aside.sidebar::after, -nav.contents::after, -aside.topic::after, -div.topic::after, -div.admonition::after, -blockquote::after { - display: block; - content: ''; - clear: both; -} - -/* -- tables ---------------------------------------------------------------- */ - -table.docutils { - margin-top: 10px; - margin-bottom: 10px; - border: 0; - border-collapse: collapse; -} - -table.align-center { - margin-left: auto; - margin-right: auto; -} - -table.align-default { - margin-left: auto; - margin-right: auto; -} - -table caption span.caption-number { - font-style: italic; -} - -table caption span.caption-text { -} - -table.docutils td, table.docutils th { - padding: 1px 8px 1px 5px; - border-top: 0; - border-left: 0; - border-right: 0; - border-bottom: 1px solid #aaa; -} - -th { - text-align: left; - padding-right: 5px; -} - -table.citation { - border-left: solid 1px gray; - margin-left: 1px; -} - -table.citation td { - border-bottom: none; -} - -th > :first-child, -td > :first-child { - margin-top: 0px; -} - -th > :last-child, -td > :last-child { - margin-bottom: 0px; -} - -/* -- figures --------------------------------------------------------------- */ - -div.figure, figure { - margin: 0.5em; - padding: 0.5em; -} - -div.figure p.caption, figcaption { - padding: 0.3em; -} - -div.figure p.caption span.caption-number, -figcaption span.caption-number { - font-style: italic; -} - -div.figure p.caption span.caption-text, -figcaption span.caption-text { -} - -/* -- field list styles ----------------------------------------------------- */ - -table.field-list td, table.field-list th { - border: 0 !important; -} - -.field-list ul { - margin: 0; - padding-left: 1em; -} - -.field-list p { - margin: 0; -} - -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -/* -- hlist styles ---------------------------------------------------------- */ - -table.hlist { - margin: 1em 0; -} - -table.hlist td { - vertical-align: top; -} - -/* -- object description styles --------------------------------------------- */ - -.sig { - font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; -} - -.sig-name, code.descname { - background-color: transparent; - font-weight: bold; -} - -.sig-name { - font-size: 1.1em; -} - -code.descname { - font-size: 1.2em; -} - -.sig-prename, code.descclassname { - background-color: transparent; -} - -.optional { - font-size: 1.3em; -} - -.sig-paren { - font-size: larger; -} - -.sig-param.n { - font-style: italic; -} - -/* C++ specific styling */ - -.sig-inline.c-texpr, -.sig-inline.cpp-texpr { - font-family: unset; -} - -.sig.c .k, .sig.c .kt, -.sig.cpp .k, .sig.cpp .kt { - color: #0033B3; -} - -.sig.c .m, -.sig.cpp .m { - color: #1750EB; -} - -.sig.c .s, .sig.c .sc, -.sig.cpp .s, .sig.cpp .sc { - color: #067D17; -} - - -/* -- other body styles ----------------------------------------------------- */ - -ol.arabic { - list-style: decimal; -} - -ol.loweralpha { - list-style: lower-alpha; -} - -ol.upperalpha { - list-style: upper-alpha; -} - -ol.lowerroman { - list-style: lower-roman; -} - -ol.upperroman { - list-style: upper-roman; -} - -:not(li) > ol > li:first-child > :first-child, -:not(li) > ul > li:first-child > :first-child { - margin-top: 0px; -} - -:not(li) > ol > li:last-child > :last-child, -:not(li) > ul > li:last-child > :last-child { - margin-bottom: 0px; -} - -ol.simple ol p, -ol.simple ul p, -ul.simple ol p, -ul.simple ul p { - margin-top: 0; -} - -ol.simple > li:not(:first-child) > p, -ul.simple > li:not(:first-child) > p { - margin-top: 0; -} - -ol.simple p, -ul.simple p { - margin-bottom: 0; -} - -aside.footnote > span, -div.citation > span { - float: left; -} -aside.footnote > span:last-of-type, -div.citation > span:last-of-type { - padding-right: 0.5em; -} -aside.footnote > p { - margin-left: 2em; -} -div.citation > p { - margin-left: 4em; -} -aside.footnote > p:last-of-type, -div.citation > p:last-of-type { - margin-bottom: 0em; -} -aside.footnote > p:last-of-type:after, -div.citation > p:last-of-type:after { - content: ""; - clear: both; -} - -dl.field-list { - display: grid; - grid-template-columns: fit-content(30%) auto; -} - -dl.field-list > dt { - font-weight: bold; - word-break: break-word; - padding-left: 0.5em; - padding-right: 5px; -} - -dl.field-list > dd { - padding-left: 0.5em; - margin-top: 0em; - margin-left: 0em; - margin-bottom: 0em; -} - -dl { - margin-bottom: 15px; -} - -dd > :first-child { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -dl > dd:last-child, -dl > dd:last-child > :last-child { - margin-bottom: 0; -} - -dt:target, span.highlighted { - background-color: #fbe54e; -} - -rect.highlighted { - fill: #fbe54e; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -.versionmodified { - font-style: italic; -} - -.system-message { - background-color: #fda; - padding: 5px; - border: 3px solid red; -} - -.footnote:target { - background-color: #ffa; -} - -.line-block { - display: block; - margin-top: 1em; - margin-bottom: 1em; -} - -.line-block .line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 1.5em; -} - -.guilabel, .menuselection { - font-family: sans-serif; -} - -.accelerator { - text-decoration: underline; -} - -.classifier { - font-style: oblique; -} - -.classifier:before { - font-style: normal; - margin: 0 0.5em; - content: ":"; - display: inline-block; -} - -abbr, acronym { - border-bottom: dotted 1px; - cursor: help; -} - -/* -- code displays --------------------------------------------------------- */ - -pre { - overflow: auto; - overflow-y: hidden; /* fixes display issues on Chrome browsers */ -} - -pre, div[class*="highlight-"] { - clear: both; -} - -span.pre { - -moz-hyphens: none; - -ms-hyphens: none; - -webkit-hyphens: none; - hyphens: none; - white-space: nowrap; -} - -div[class*="highlight-"] { - margin: 1em 0; -} - -td.linenos pre { - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - display: block; -} - -table.highlighttable tbody { - display: block; -} - -table.highlighttable tr { - display: flex; -} - -table.highlighttable td { - margin: 0; - padding: 0; -} - -table.highlighttable td.linenos { - padding-right: 0.5em; -} - -table.highlighttable td.code { - flex: 1; - overflow: hidden; -} - -.highlight .hll { - display: block; -} - -div.highlight pre, -table.highlighttable pre { - margin: 0; -} - -div.code-block-caption + div { - margin-top: 0; -} - -div.code-block-caption { - margin-top: 1em; - padding: 2px 5px; - font-size: small; -} - -div.code-block-caption code { - background-color: transparent; -} - -table.highlighttable td.linenos, -span.linenos, -div.highlight span.gp { /* gp: Generic.Prompt */ - user-select: none; - -webkit-user-select: text; /* Safari fallback only */ - -webkit-user-select: none; /* Chrome/Safari */ - -moz-user-select: none; /* Firefox */ - -ms-user-select: none; /* IE10+ */ -} - -div.code-block-caption span.caption-number { - padding: 0.1em 0.3em; - font-style: italic; -} - -div.code-block-caption span.caption-text { -} - -div.literal-block-wrapper { - margin: 1em 0; -} - -code.xref, a code { - background-color: transparent; - font-weight: bold; -} - -h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { - background-color: transparent; -} - -.viewcode-link { - float: right; -} - -.viewcode-back { - float: right; - font-family: sans-serif; -} - -div.viewcode-block:target { - margin: -1px -10px; - padding: 0 10px; -} - -/* -- math display ---------------------------------------------------------- */ - -img.math { - vertical-align: middle; -} - -div.body div.math p { - text-align: center; -} - -span.eqno { - float: right; -} - -span.eqno a.headerlink { - position: absolute; - z-index: 1; -} - -div.math:hover a.headerlink { - visibility: visible; -} - -/* -- printout stylesheet --------------------------------------------------- */ - -@media print { - div.document, - div.documentwrapper, - div.bodywrapper { - margin: 0 !important; - width: 100%; - } - - div.sphinxsidebar, - div.related, - div.footer, - #top-link { - display: none; - } -} \ No newline at end of file diff --git a/Documentation/_build/html/_static/doctools.js b/Documentation/_build/html/_static/doctools.js deleted file mode 100644 index d06a71d75..000000000 --- a/Documentation/_build/html/_static/doctools.js +++ /dev/null @@ -1,156 +0,0 @@ -/* - * doctools.js - * ~~~~~~~~~~~ - * - * Base JavaScript utilities for all Sphinx HTML documentation. - * - * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ -"use strict"; - -const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ - "TEXTAREA", - "INPUT", - "SELECT", - "BUTTON", -]); - -const _ready = (callback) => { - if (document.readyState !== "loading") { - callback(); - } else { - document.addEventListener("DOMContentLoaded", callback); - } -}; - -/** - * Small JavaScript module for the documentation. - */ -const Documentation = { - init: () => { - Documentation.initDomainIndexTable(); - Documentation.initOnKeyListeners(); - }, - - /** - * i18n support - */ - TRANSLATIONS: {}, - PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), - LOCALE: "unknown", - - // gettext and ngettext don't access this so that the functions - // can safely bound to a different name (_ = Documentation.gettext) - gettext: (string) => { - const translated = Documentation.TRANSLATIONS[string]; - switch (typeof translated) { - case "undefined": - return string; // no translation - case "string": - return translated; // translation exists - default: - return translated[0]; // (singular, plural) translation tuple exists - } - }, - - ngettext: (singular, plural, n) => { - const translated = Documentation.TRANSLATIONS[singular]; - if (typeof translated !== "undefined") - return translated[Documentation.PLURAL_EXPR(n)]; - return n === 1 ? singular : plural; - }, - - addTranslations: (catalog) => { - Object.assign(Documentation.TRANSLATIONS, catalog.messages); - Documentation.PLURAL_EXPR = new Function( - "n", - `return (${catalog.plural_expr})` - ); - Documentation.LOCALE = catalog.locale; - }, - - /** - * helper function to focus on search bar - */ - focusSearchBar: () => { - document.querySelectorAll("input[name=q]")[0]?.focus(); - }, - - /** - * Initialise the domain index toggle buttons - */ - initDomainIndexTable: () => { - const toggler = (el) => { - const idNumber = el.id.substr(7); - const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); - if (el.src.substr(-9) === "minus.png") { - el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; - toggledRows.forEach((el) => (el.style.display = "none")); - } else { - el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; - toggledRows.forEach((el) => (el.style.display = "")); - } - }; - - const togglerElements = document.querySelectorAll("img.toggler"); - togglerElements.forEach((el) => - el.addEventListener("click", (event) => toggler(event.currentTarget)) - ); - togglerElements.forEach((el) => (el.style.display = "")); - if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); - }, - - initOnKeyListeners: () => { - // only install a listener if it is really needed - if ( - !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && - !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS - ) - return; - - document.addEventListener("keydown", (event) => { - // bail for input elements - if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; - // bail with special keys - if (event.altKey || event.ctrlKey || event.metaKey) return; - - if (!event.shiftKey) { - switch (event.key) { - case "ArrowLeft": - if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; - - const prevLink = document.querySelector('link[rel="prev"]'); - if (prevLink && prevLink.href) { - window.location.href = prevLink.href; - event.preventDefault(); - } - break; - case "ArrowRight": - if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; - - const nextLink = document.querySelector('link[rel="next"]'); - if (nextLink && nextLink.href) { - window.location.href = nextLink.href; - event.preventDefault(); - } - break; - } - } - - // some keyboard layouts may need Shift to get / - switch (event.key) { - case "/": - if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; - Documentation.focusSearchBar(); - event.preventDefault(); - } - }); - }, -}; - -// quick alias for translations -const _ = Documentation.gettext; - -_ready(Documentation.init); diff --git a/Documentation/_build/html/_static/documentation_options.js b/Documentation/_build/html/_static/documentation_options.js deleted file mode 100644 index 902bb3358..000000000 --- a/Documentation/_build/html/_static/documentation_options.js +++ /dev/null @@ -1,14 +0,0 @@ -var DOCUMENTATION_OPTIONS = { - URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '', - LANGUAGE: 'en', - COLLAPSE_INDEX: false, - BUILDER: 'html', - FILE_SUFFIX: '.html', - LINK_SUFFIX: '.html', - HAS_SOURCE: true, - SOURCELINK_SUFFIX: '.txt', - NAVIGATION_WITH_KEYS: true, - SHOW_SEARCH_SUMMARY: true, - ENABLE_SEARCH_SHORTCUTS: true, -}; \ No newline at end of file diff --git a/Documentation/_build/html/_static/file.png b/Documentation/_build/html/_static/file.png deleted file mode 100644 index a858a410e..000000000 Binary files a/Documentation/_build/html/_static/file.png and /dev/null differ diff --git a/Documentation/_build/html/_static/icon.png b/Documentation/_build/html/_static/icon.png deleted file mode 100644 index 73d48a6e1..000000000 Binary files a/Documentation/_build/html/_static/icon.png and /dev/null differ diff --git a/Documentation/_build/html/_static/insipid-sidebar-readthedocs.css b/Documentation/_build/html/_static/insipid-sidebar-readthedocs.css deleted file mode 100644 index ad79916e6..000000000 --- a/Documentation/_build/html/_static/insipid-sidebar-readthedocs.css +++ /dev/null @@ -1,66 +0,0 @@ - - -#ethical-ad-placement { - margin-top: auto; - padding-top: 3em; - min-height: 200px; -} - -#readthedocs-embed-flyout, #duplicated-readthedocs-versions { - margin-left: -10px; - margin-right: -10px; -} - -#duplicated-readthedocs-versions { - margin-bottom: -10px; -} - -#duplicated-readthedocs-versions { - position: sticky; - width: auto; -} - -#readthedocs-embed-flyout .rst-versions.rst-badge { - position: static; - max-width: none; -} - - -#readthedocs-embed-flyout .rst-versions.shift-up { - max-height: none; -} - -/* We have duplicated this section, so we don't need the second instance: */ -#readthedocs-embed-flyout .rst-versions.rst-badge .rst-current-version { - display: none; -} - -#duplicated-readthedocs-versions .rst-current-version { - font-size: 0.9rem; -} - -#readthedocs-embed-flyout .rst-versions .rst-other-versions { - display: block; - font-size: 0.9rem; -} - -#flyout-search-form input { - width: 100%; -} - -#sidebar-checkbox:not(:checked) ~ .ethical-fixedfooter { - left: 0; - right: 0; - width: unset; -} - -#sidebar-checkbox:checked ~ .ethical-fixedfooter { - left: var(--sidebar-width); - right: 0; - width: unset; -} - -body:not(.sidebar-resizing) .ethical-fixedfooter { - transition: left 0.3s ease-out; -} - diff --git a/Documentation/_build/html/_static/insipid-sidebar.js b/Documentation/_build/html/_static/insipid-sidebar.js deleted file mode 100644 index 4ec001690..000000000 --- a/Documentation/_build/html/_static/insipid-sidebar.js +++ /dev/null @@ -1,308 +0,0 @@ -(dom_loaded => { - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', dom_loaded); - } else { - dom_loaded(); - } -})(() => { - 'use strict'; - - const sidebar = document.querySelector('.sphinxsidebar'); - const sidebar_tabbable = sidebar.querySelectorAll('input, textarea, select, button, a[href], area[href], iframe'); - const sidebar_button = document.getElementById('sidebar-button'); - const sidebar_checkbox = document.getElementById('sidebar-checkbox'); - const topbar = document.getElementById('topbar'); - const overlay = document.getElementById('overlay'); - const root = document.documentElement; - - sidebar.setAttribute('id', 'sphinxsidebar'); // for aria-controls - - Element.prototype.css = function (name, ...value) { - if (value.length) { - this.style.setProperty(name, ...value); - } else { - return window.getComputedStyle(this).getPropertyValue(name); - } - } - - function updateSidebarAttributesVisible() { - sidebar_button.setAttribute('title', "Collapse sidebar"); - sidebar_button.setAttribute('aria-label', "Collapse sidebar"); - sidebar_button.setAttribute('aria-expanded', true); - sidebar.setAttribute('aria-hidden', false); - sidebar_tabbable.forEach(el => el.setAttribute('tabindex', 0)); - } - - function updateSidebarAttributesHidden() { - sidebar_button.setAttribute('title', "Expand sidebar"); - sidebar_button.setAttribute('aria-label', "Expand sidebar"); - sidebar_button.setAttribute('aria-expanded', false); - sidebar.setAttribute('aria-hidden', true); - sidebar_tabbable.forEach(el => el.setAttribute('tabindex', -1)); - } - - sidebar.setAttribute('tabindex', -1); - - function store(key, value) { - try { - localStorage.setItem(key, value); - } catch (e) { - } - } - - sidebar_checkbox.addEventListener('change', event => { - if (event.target.checked) { - updateSidebarAttributesVisible(); - store('sphinx-sidebar', 'visible'); - document.body.classList.remove('topbar-folded'); - sidebar.focus({preventScroll: true}); - sidebar.blur(); - } else { - updateSidebarAttributesHidden(); - store('sphinx-sidebar', 'hidden'); - if (document.scrollingElement.scrollTop < topbar.offsetHeight) { - document.body.classList.remove('topbar-folded'); - } else { - document.body.classList.add('topbar-folded'); - } - document.scrollingElement.focus({preventScroll: true}); - document.scrollingElement.blur(); - } - }); - - if (sidebar_checkbox.checked) { - updateSidebarAttributesVisible(); - } else { - updateSidebarAttributesHidden(); - } - - function show() { - sidebar_checkbox.checked = true; - sidebar_checkbox.dispatchEvent(new Event('change')); - } - - function hide() { - sidebar_checkbox.checked = false; - sidebar_checkbox.dispatchEvent(new Event('change')); - } - - sidebar_button.addEventListener('keydown', event => { - if (event.code === 'Enter' || event.code === 'Space') { - sidebar_button.click(); - event.preventDefault(); - } - }); - - let touchstart; - - document.addEventListener('touchstart', event => { - if (event.touches.length > 1) { return; } - const touch = event.touches[0]; - if (sidebar_checkbox.checked) { - if (touch.clientX > sidebar.offsetWidth) { - return; - } - } else { - if (touch.clientX > 20) { - return; - } - } - touchstart = { - x: touch.clientX, - y: touch.clientY, - t: Date.now(), - }; - }); - - document.addEventListener('touchend', event => { - if (!touchstart) { return; } - if (event.touches.length > 0 || event.changedTouches.length > 1) { - touchstart = null; - return; - } - const touch = event.changedTouches[0]; - const x = touch.clientX; - const y = touch.clientY; - const x_diff = x - touchstart.x; - const y_diff = y - touchstart.y; - const t_diff = Date.now() - touchstart.t; - if (t_diff < 400 && Math.abs(x_diff) > Math.max(100, Math.abs(y_diff))) { - if (x_diff > 0) { - if (!sidebar_checkbox.checked) { - show(); - } - } else { - if (sidebar_checkbox.checked) { - hide(); - } - } - } - touchstart = null; - }); - - const sidebar_resize_handles = document.querySelectorAll('.sidebar-resize-handle'); - sidebar_resize_handles.forEach(el => { - el.addEventListener('mousedown', event => { - window.addEventListener('mousemove', resize_mouse); - window.addEventListener('mouseup', stop_resize_mouse); - document.body.classList.add('sidebar-resizing'); - event.preventDefault(); // Prevent unwanted text selection while resizing - }); - el.addEventListener('touchstart', event => { - if (event.touches.length > 1) { return; } - window.addEventListener('touchmove', resize_touch); - window.addEventListener('touchend', stop_resize_touch); - document.body.classList.add('sidebar-resizing'); - event.preventDefault(); // Prevent unwanted text selection while resizing - }); - }); - - let ignore_resize = false; - - function resize_base(event) { - if (ignore_resize) { return; } - const window_width = window.innerWidth; - const width = event.clientX; - if (width > window_width) { - root.css('--sidebar-width', window_width + 'px'); - } else if (width > 10) { - root.css('--sidebar-width', width + 'px'); - } else { - ignore_resize = true; - hide(); - } - } - - function resize_mouse(event) { - resize_base(event); - } - - function resize_touch(event) { - if (event.touches.length > 1) { return; } - resize_base(event.touches[0]); - } - - function stop_resize_base() { - if (ignore_resize) { - root.css('--sidebar-width', '19rem'); - ignore_resize = false; - } - store('sphinx-sidebar-width', root.css('--sidebar-width')); - document.body.classList.remove('sidebar-resizing'); - } - - function stop_resize_mouse(event) { - window.removeEventListener('mousemove', resize_mouse); - window.removeEventListener('mouseup', stop_resize_mouse); - stop_resize_base(); - } - - function stop_resize_touch(event) { - if (event.touches.length > 0 || event.changedTouches.length > 1) { - return; - } - window.removeEventListener('touchmove', resize_touch); - window.removeEventListener('touchend', stop_resize_touch); - stop_resize_base(); - } - - window.addEventListener('resize', event => { - const window_width = window.innerWidth; - if (window_width < sidebar.offsetWidth) { - root.css('--sidebar-width', window_width + 'px'); - } - }); - - // This is part of the sidebar code because it only affects the sidebar - if (window.ResizeObserver) { - const resizeObserver = new ResizeObserver(entries => { - for (let entry of entries) { - let height; - if (entry.borderBoxSize && entry.borderBoxSize.length > 0) { - height = entry.borderBoxSize[0].blockSize; - } else { - height = entry.contentRect.height; - } - root.css('--topbar-height', height + 'px'); - } - }); - resizeObserver.observe(topbar); - } - - let current = []; - let links = []; - - document.querySelectorAll('.sphinxsidebar *').forEach(el => { - let link = el.querySelector(':scope > a[href^="#"]'); - if (link) { - el.classList.add('current-page'); - current.push(el); - links.push(link); - } - }); - const small_screen = window.matchMedia('(max-width: 39rem)'); - - if (current.length === 1 && current[0].childElementCount === 1 && small_screen.matches) { - hide(); - } - const bottom_space = 0; - - if (current.length) { - const top = current[0].getBoundingClientRect().top; - const bottom = current[current.length - 1].getBoundingClientRect().bottom; - if (top < topbar.offsetHeight || bottom > (sidebar.offsetHeight - bottom_space)) { - current[0].scrollIntoView(true); - } - } - - let sections = new Map(); - - const intersection_callback = (entries, observer) => { - entries.forEach(entry => { - let link = sections.get(entry.target); - if (entry.isIntersecting) { - link.classList.add('in-view'); - } else { - link.classList.remove('in-view'); - } - }); - }; - - const intersection_observer = new IntersectionObserver(intersection_callback, { - root: null, - // NB: This uses the initial topbar height, later changes are ignored: - rootMargin: -topbar.offsetHeight + 'px 0px 0px 0px', - threshold: 0.0, - }); - - links.forEach(link => { - let section; - let id = link.hash; - if (id) { - id = id.slice(1); - section = document.getElementById(decodeURI(id)); - // Detect API doc headers: - let single_definition_term = ( - section.nodeName == 'DT' && - section.nextElementSibling.nodeName == 'DD' && - !section.nextElementSibling.nextElementSibling && - section.parentElement.nodeName == 'DL'); - if (single_definition_term) { - // The
contains only a single
+
, - // therefore we can observe the whole
. - section = section.parentElement; - } - } else { - // NB: The first section has no hash, so we don't know its ID: - section = document.querySelector('div.body .section, div.body section'); - } - sections.set(section, link); - intersection_observer.observe(section); - link.addEventListener('click', event => { - if (small_screen.matches) { - hide(); - } - }); - }); -}); - diff --git a/Documentation/_build/html/_static/insipid.css b/Documentation/_build/html/_static/insipid.css deleted file mode 100644 index 7834022d3..000000000 --- a/Documentation/_build/html/_static/insipid.css +++ /dev/null @@ -1,1223 +0,0 @@ -/* -- variables ------------------------------------------------------------- */ - -:root { - --sidebar-width: 19rem; - --topbar-height: 3rem; -} - -/* -- page layout ----------------------------------------------------------- */ - -body { - position: relative; /* reference for sidebar-resize-handle */ - margin: 0; - font-family: 'Open Sans', sans-serif; - min-width: unset; - color: #000; - background-color: #fff; - text-size-adjust: none; - -webkit-text-size-adjust: none; -} - -/* keep the footer at the bottom (on very short pages) */ -html { height: 100%; } -body { min-height: 100%; display: flex; flex-direction: column; } -div.document { flex-grow: 1; } - -div.body { - padding: 0 20px; - min-width: unset; /* body_min_width is applied to */ - overflow-x: auto; - - margin-left: auto; - margin-right: auto; - - line-height: 1.618; -} - -* { - scroll-margin-top: var(--topbar-height); - scroll-snap-margin-top: var(--topbar-height); /* Safari */ -} - -/* -- scrollbars ------------------------------------------------------------ */ - -html::-webkit-scrollbar, div.sphinxsidebar::-webkit-scrollbar { - width: 12px; - background-color: #fff; -} - -html::-webkit-scrollbar-thumb, div.sphinxsidebar::-webkit-scrollbar-thumb { - background-color: #ccc; - border-radius: 6px; -} - -html, div.sphinxsidebar { - scrollbar-color: #ccc transparent; -} - -body { - scrollbar-color: initial; -} - -div.sphinxsidebar::-webkit-scrollbar { - width: 7px; -} - -div.sphinxsidebar::-webkit-scrollbar-thumb { - border-radius: 3.5px; -} - -div.sphinxsidebar { - scrollbar-width: thin; -} - -/* -- body styles ----------------------------------------------------------- */ - -strong { - font-weight: 600; -} - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6, -.toctree-wrapper .caption, -p.rubric { - margin-top: 1.3em; - margin-bottom: 1rem; - font-weight: 600; - line-height: 1.35; - overflow-wrap: break-word; -} - -div.body h5, -div.body h6 { - font-weight: bold; -} - -div.body h1 strong, -div.body h2 strong, -div.body h3 strong, -div.body h4 strong, -div.body h5 strong, -div.body h6 strong { - font-weight: 800; -} - -div.body h1 { font-size: 2em; } -div.body h2 { font-size: 1.7em; } -div.body h3 { font-size: 1.4em; } -div.body h4 { font-size: 1.2em; } -div.body h5 { font-size: 1em; } -div.body h6 { font-size: 0.9em } - -.toctree-wrapper .caption, -p.rubric { - font-size: 1.1em; - font-weight: bold; -} - -a.headerlink { - padding: 0 4px; - font-size: 1rem; - font-weight: normal; -} - -blockquote { - clear: inline-start; - margin: 10px 0; - border: 1px solid #0002; - border-left-width: 7px; - padding: 0 1em; -} - -.section > blockquote, -section > blockquote { - margin: 10px -7px; -} - -blockquote.pull-quote p:not(.attribution), -blockquote.epigraph p:not(.attribution) { - font-size: 130%; - font-style: italic; - color: #666; -} - -blockquote:not(.pull-quote):not(.epigraph) p.attribution { - font-style: italic; -} - -blockquote p.attribution { - text-align: end; -} - -div.body a:target, -strong:target { - padding: 3px; - margin: -3px; -} - -div.body dl > dt:target, -div.body div.admonition dl > dt:target, -div.body .topic dl > dt:target, -div.body .sidebar dl > dt:target, -div.body .sidebar .sidebar-title a:target, -div.body a:target, -strong:target { - background-color: #fbe54e; -} - -.footnote:target { - background-color: unset; -} - -.footnote:target .label { - padding: 3px; - margin: -3px; - background-color: #fbe54e; -} - -.citation:target .label { - padding: 3px; - margin-left: -3px; - margin-top: -3px; - margin-bottom: -3px; - margin-right: 5px; - background-color: #fbe54e; -} - -.citation:target .backrefs { - margin-left: -8px; -} - -hr.docutils { - border: 0; - border-top: solid 1px #ccc; -} - -.section > hr.docutils, -section > hr.docutils { - margin-left: -7px; - margin-right: -7px; -} - -.compound:not(.toctree-wrapper) { - margin-top: 1em; - margin-bottom: 1em; -} - -.compound:not(.toctree-wrapper) > * { - margin-top: 0.2em; - margin-bottom: 0.2em; -} - -.compound:not(.toctree-wrapper) > *:first-child { - margin-top: 0; - margin-bottom: 0.2em; -} - -.compound:not(.toctree-wrapper) > *:last-child { - margin-top: 0.2em; - margin-bottom: 0; -} - -section, .section { - clear: inline-start; -} - -/* -- hyperlink styles ------------------------------------------------------ */ - -a { - color: #1863b5; - text-decoration: none; - overflow-wrap: break-word; -} - -a:hover { - text-decoration: underline; -} - -a:visited { - color: #004188; -} - -a.external { - text-decoration: underline; -} - -a.external:hover { - text-decoration: none; -} - -a.external:visited { - text-decoration: none; -} - -/* -- code formatting ------------------------------------------------------- */ - -code, pre, kbd, samp { - font-family: 'DejaVu Sans Mono', Menlo, monospace; -} - -pre { - padding: 7px; - line-height: normal; - font-size: 0.875em; -} - -.section > div > div.highlight, -.section > .compound > div > div.highlight, -.section > .literal-block-wrapper > div > div.highlight, -.section > pre.literal-block, -.section > .compound > pre.literal-block, -section > div > div.highlight, -section > .compound > div > div.highlight, -section > .literal-block-wrapper > div > div.highlight, -section > pre.literal-block, -section > .compound > pre.literal-block { - margin-left: -7px; - margin-right: -7px; -} - -code, -code.xref, -a code, -div.body div.admonition dl > dt code, -div.body .topic dl > dt code, -div.body .sidebar dl > dt code, -h1 code, h2 code, h3 code, h4 code, h5 code, h6 code, -div.code-block-caption code { - background-color: rgba(27,31,35,.05); - padding: 0.1em 0.2em; - font-weight: normal; -} - -div.body dl > dt code { - background-color: unset; - padding: unset; -} - -code.xref, -a code { - font-weight: unset; -} - -code.descname { - font-size: unset; -} - -.sig-name { - font-size: unset; -} - -.sig-paren, -.optional { - line-height: 0; -} - -div.code-block-caption { - text-align: center; - font-size: unset; -} - -div.literal-block-wrapper { - clear: both; -} - -td.linenos .linenodiv pre { - color: #666; - background-color: transparent; - padding: 7px 0px; -} - -table.highlighttable td.linenos { - padding-right: 0.5em; -} - -span.linenos { - margin-right: 0.7em; -} - -/* highlighted line (:emphasize-lines:) */ -.highlight .hll { - padding: 0 0.5em; - margin: 0 -0.5em; -} - -kbd.docutils:not(.compound) { - padding: 0.15em; - border-radius: 3px; - border: 1px solid #333; -} - -span.pre { - white-space: pre-wrap; - overflow-wrap: anywhere; -} - -/* -- admonitions ----------------------------------------------------------- */ - -div.topic, aside.topic, -div.sidebar, aside.sidebar, -nav.contents { - border: none; - padding: 7px; -} - -.section > div.admonition, -section > div.admonition, -div.body > div.admonition, -.section > .topic, -section > .topic, -div.body > .topic, -.section > nav.contents, -section > nav.contents, -div.body > nav.contents { - margin: 10px -7px; -} - -div.sidebar, -aside.sidebar { - margin-right: -7px; -} - -div.admonition > p.admonition-title, -.topic > p.topic-title, -nav.contents > p.topic-title, -.sidebar > p.sidebar-title { - margin: -7px -7px 7px -7px; - padding: 4px 7px; - font-weight: normal; - font-size: unset; - color: #333; -} - -.first.admonition-title, -.first.topic-title, -.first.sidebar-title { - /* override basic.css, which uses !important */ - margin-top: -7px !important; -} - -div.admonition > p.admonition-title + *, -.topic > p.topic-title + *, -nav.contents > p.topic-title + *, -.sidebar > p.sidebar-title + * { - margin-top: 0; -} - -div.admonition > :first-child:not(.admonition-title), -div.topic > :first-child:not(.topic-title), -aside.topic > :first-child:not(.topic-title), -nav.contents > :first-child:not(.topic-title) { - margin-top: 0; -} - -nav.contents > :last-child { - margin-bottom: 0; -} - -div.admonition { - background-color: #e4ebf2; -} - -div.admonition > p.admonition-title { - background-color: #cadcea; -} - -div.admonition.attention, -div.admonition.caution, -div.admonition.danger, -div.admonition.error, -div.admonition.warning { - background-color: #fbe7d4; -} - -div.admonition.attention > p.admonition-title, -div.admonition.caution > p.admonition-title, -div.admonition.danger > p.admonition-title, -div.admonition.error > p.admonition-title, -div.admonition.warning > p.admonition-title { - background-color: #f0d5b8; -} - -div.topic, nav.contents, aside.topic { - background-color: #fff0eb; -} - -.topic > p.topic-title, -nav.contents > p.topic-title { - background-color: #f0dbd4; -} - -div.sidebar, -aside.sidebar, -div.admonition.seealso { - background-color: #f4f4f4; -} - -.sidebar > p.sidebar-title, -div.admonition.seealso > p.admonition-title { - background-color: #e4e4e4; -} - -div.admonition.seealso { - clear: both; -} - -p.sidebar-subtitle { - font-style: italic; -} - -/* More specific selectors to override previous defintions */ -div.body div.admonition dl > dt, -div.body .topic dl > dt, -div.body .sidebar dl > dt { - padding: unset; - background-color: unset; -} - -div.body div.admonition dl:not(.glossary) > dt, -div.body .topic dl:not(.glossary) > dt, -div.body .sidebar dl:not(.glossary) > dt { - font-weight: unset; -} - -/* -- tables and lists ------------------------------------------------------ */ - -table.docutils { - overflow-x: auto; - display: block; - border-collapse: separate; - border-spacing: 4px 4px; - margin-top: 1em; - margin-bottom: 1em; -} - -table.docutils th { - font-weight: normal; - background-color: rgba(27,31,35,.05); - border-bottom: 2px solid #333; -} - -table.docutils td { - overflow-wrap: break-word; -} - - - -ol, ul { - padding-left: 1.2em; -} - -ol.simple p, ul.simple p { - margin-bottom: 0.3em; -} - -.toctree-wrapper ul, -.contents ul { - list-style: none; - margin-top: 0.5em; - padding-left: 2em; -} - -.toctree-wrapper li:not(:first-child), -.contents li:not(:first-child) { - margin-top: 0.5em; -} - -.toctree-wrapper > ul, -.contents > ul { - padding-left: unset; -} - -dl.citation > dt { - font-weight: 600; -} - -div.body dl { - margin: 1em 0; -} - -div.body dl > dt, -dl.field-list > dt { - display: table; -} - -div.body dt:not(.label), -dl.field-list > dt { - margin-top: 1em; - padding: 1px 7px; - background-color: #f5f5f5; -} - -.section > dl > dt:not(.label), -.section > dl.field-list > dt, -section > dl > dt:not(.label), -section > dl.field-list > dt { - margin: 1em -7px 0; -} - -div.body dl > dt:first-child { - margin-top: 0; -} - -div.body dl > dt.label:target, -div.body div.admonition dl > dt:target, -div.body .topic dl > dt:target, -div.body .sidebar dl > dt:target { - padding: 3px 7px; - margin-top: -3px; - margin-bottom: -3px; - margin-left: -7px; -} - -dl.glossary > dt { - font-size: unset; - font-weight: 600; -} - -dl.glossary > dt strong { - font-weight: bold; -} - -dl.field-list { - display: unset; -} - -dl.field-list > dt { - font-weight: unset; -} - -dl.field-list > dt::after { - content: unset; -} - -dd, -dl.field-list > dd { - padding-left: 0; - margin-top: 3px; - margin-left: 2em; -} - -dd:not(:last-child), -dl.field-list > dd:not(:last-child) { - margin-bottom: 1em; -} - -div.body dl.class > dt:not(:target), -div.body dl.type > dt:not(:target), -div.body dl.concept > dt:not(:target), -div.body dl.enum > dt:not(:target), -div.body dl.enum-class > dt:not(:target), -div.body dl.union > dt:not(:target) { - background-color: #e4ebf2; -} - -div.body dl.exception > dt:not(:target) { - background-color: #fbe7d4; -} - -/* -- relbar ---------------------------------------------------------------- */ - -.relbar { - padding: 10px 10px 0; -} - -.relbar > a { - box-sizing: border-box; - width: 50%; - padding: 10px; - display: flex; - align-items: center; - color: inherit; - text-decoration: none; - user-select: none; -} - -.relbar > a.previous { - float: left; -} - -.relbar > a.next { - float: right; - text-align: right; -} - -.relbar .icon { - color: #888; -} - -.relbar .previous .icon { - margin-right: 1em; -} - -.relbar .next .icon { - margin-left: 1em; -} - -.relbar .title { - position: relative; - flex: 1; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - font-size: 1.4em; - font-weight: 200; -} - -.relbar .title .text { - line-height: 2.1em; -} - -.relbar .title .text .direction { - position: absolute; - right: 0; - left: 0; - top: 0; - font-size: 60%; - line-height: 0.5em; -} - -.relbar .pre { - white-space: pre; -} - -/* -- breadcrumbs ----------------------------------------------------------- */ - -nav.crumbs { - color: #888; - font-size: 90%; -} - -nav.crumbs ul { - padding: 0; - list-style: none; -} - -nav.crumbs ul li { - display: inline; -} - -nav.crumbs a:visited { - color: #1565c0; -} - -/* -- footer ---------------------------------------------------------------- */ - -footer { - padding: 9px 0 9px 0; - text-align: center; - font-size: 75%; - color: #333; -} - -footer, div.articleComments { - border-top: #ccc solid 1px; -} - -/* -- sidebar --------------------------------------------------------------- */ - -div.sphinxsidebar { - position: fixed; - width: var(--sidebar-width); - left: 0; - top: 0; - bottom: 0; - overflow-y: auto; - float: unset; - margin-left: unset; /* override basic.css */ - padding-top: var(--topbar-height); - z-index: 390; - color: #333; - background-color: #f5f5f5; - overscroll-behavior: contain; -} - -#sidebar-checkbox:checked ~ div.document, -#sidebar-checkbox:checked ~ .relbar, -#sidebar-checkbox:checked ~ .articleComments, -#sidebar-checkbox:checked ~ footer { - margin-left: var(--sidebar-width); -} - -body:not(.sidebar-resizing) div.document, -body:not(.sidebar-resizing) .relbar, -body:not(.sidebar-resizing) .articleComments, -body:not(.sidebar-resizing) footer { - transition: margin-left 0.3s ease-out; -} - -body:not(.sidebar-resizing) .sphinxsidebar { - transition: left 0.3s ease-out; -} - -div.sphinxsidebarwrapper { - position: relative; /* reference for sidebar-resize-handle */ - box-sizing: border-box; - padding: 10px; - display: flex; - flex-direction: column; - min-height: 100%; -} - -div.sphinxsidebarwrapper > :first-child { - margin-top: 0; -} - -div.sphinxsidebarwrapper > :last-child { - margin-bottom: 0; -} - -.sidebar-resize-handle { - display: none; - position: absolute; - width: 0; - top: 0; - bottom: 0; -} - -body.js #sidebar-checkbox:checked ~ .sidebar-resize-handle, -body.js #sidebar-checkbox:checked ~ div.document .sidebar-resize-handle { - display: block; - cursor: col-resize; - width: 10px; -} - -.sphinxsidebar .sidebar-resize-handle { - right: 0; -} - -body.js #sidebar-checkbox:checked ~ .sidebar-resize-handle { - z-index: 390; - left: var(--sidebar-width); -} - -#sidebar-checkbox:not(:checked) ~ div.document .sphinxsidebar { - left: calc(0px - var(--sidebar-width)); -} - -div.sphinxsidebar h3 { - font-size: 1.4em; - font-weight: normal; - margin-top: 10px; - margin-bottom: 5px; -} - -div.sphinxsidebar h4 { - font-size: 1.3em; - font-weight: normal; - margin-top: 10px; - margin-bottom: 5px; -} - -div.sphinxsidebar p.caption { - text-transform: uppercase; - margin-top: 10px; - margin-bottom: 5px; -} - -div.sphinxsidebar p.caption + ul { - margin-top: 0; -} - -div.sphinxsidebar p.topless { - margin: 10px; -} - -div.sphinxsidebar p.topless { - margin-top: 0; -} - -div.sphinxsidebar ul { - padding-left: 0; - margin-left: 10px; -} - -div.sphinxsidebar h3 + ul, -div.sphinxsidebar h4 + ul { - margin-top: -5px; -} - -div.sphinxsidebar li { - padding-top: 0.4em; - padding-bottom: 0.4em; -} - -div.sphinxsidebar li li:first-child { - margin-top: 0.4em; -} - -div.sphinxsidebar li li:last-child { - margin-bottom: -0.4em; -} - -div.sphinxsidebar ul ul { - list-style: unset; -} - -.sphinxsidebar a { - color: #004188; -} - -div.sphinxsidebar a.in-view { - font-weight: 600; - letter-spacing: -0.013em; -} - -div.sphinxsidebar code { - background-color: unset; - padding: 0; -} - -div.sphinxsidebar h3, -div.sphinxsidebar h4, -div.sphinxsidebar p, -div.sphinxsidebar li { - margin-right: -10px; - padding-right: 10px; -} - -div.sphinxsidebar h3, -div.sphinxsidebar h4, -div.sphinxsidebar p, -div.sphinxsidebar li { - margin-left: -20px; - padding-left: 20px; -} - -div.sphinxsidebar li.toctree-l2 { - margin-left: -40px; - padding-left: 40px; -} - -div.sphinxsidebar li.toctree-l3 { - margin-left: -60px; - padding-left: 60px; -} - -div.sphinxsidebar li.toctree-l4 { - margin-left: -80px; - padding-left: 80px; -} - -div.sphinxsidebar li.toctree-l5 { - margin-left: -100px; - padding-left: 100px; -} - -div.sphinxsidebar li.toctree-l6 { - margin-left: -120px; - padding-left: 120px; -} - -div.sphinxsidebar li.toctree-l7 { - margin-left: -140px; - padding-left: 140px; -} - -div.sphinxsidebar li.toctree-l8 { - margin-left: -160px; - padding-left: 160px; -} - -div.sphinxsidebar li.toctree-l9 { - margin-left: -180px; - padding-left: 180px; -} - -div.sphinxsidebar li.toctree-l10 { - margin-left: -200px; - padding-left: 200px; -} - -body:not(.js) div.sphinxsidebar li.current, -div.sphinxsidebar .current-page:not(.logo) { - background-color: #fff; -} - -div.sphinxsidebar .current-page li:not(.current-page) { - background-color: #f5f5f5; -} - -div.sphinxsidebar .current-page { - transition: background-color 0.3s ease-out; -} - -div.sphinxsidebar input { - border-color: #ccc; - font-family: unset; -} - -/* -- topbar ---------------------------------------------------------------- */ - -#topbar-placeholder { - z-index: 500; - position: -webkit-sticky; - position: sticky; - top: 0; -} - -#topbar { - border-bottom: #ccc solid 1px; - background-color: #fff; -} - -#topbar, -#titlebar a, -#titlebar a:visited { - color: #888; -} - -.relbar, -.relbar > a:hover .direction { - color: #ccc; -} - -#topbar button:hover, -#titlebar .buttons > *:hover, -#titlebar a:hover, -.relbar a:hover, -.relbar a:hover .icon { - color: #333; -} - -#titlebar { - display: flex; - align-items: center; - flex-wrap: wrap; - min-height: 3rem; -} - -#titlebar .buttons { - display: flex; - align-items: baseline; - margin: 0 5px; -} - -#titlebar .buttons > *, -#topbar button { - margin: 0; - border: none; - padding: 8px; - color: inherit; - background: none; - font: inherit; - cursor: pointer; -} - -#titlebar .title button { - padding: 0; -} - -#titlebar svg, -.insipid-icon svg, -.relbar svg, -.related svg, -.crumbs svg { - width: 1em; - height: 1em; - vertical-align: middle; - fill: currentColor; -} - -#topbar a { - text-decoration: none; -} - -body.js.topbar-folded #topbar-placeholder:not(.fake-hover) #topbar { - transform: translateY(-100%); -} - -body.js #topbar { - transition: transform 0.3s ease-out; -} - -body:not(.js) #search-button { - display: none; -} - -#titlebar .title { - font-weight: 200; - font-size: 1.7rem; - text-align: center; - margin: 0; - flex: 1; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -#titlebar .top, -body.scrolled #titlebar .parent { - display: none; -} - -body.scrolled #titlebar .top { - display: inline-block; -} - -/* -- search field in topbar ------------------------------------------------ */ - -#topbar #searchbox form { - display: flex; - align-items: stretch; - margin: 5px; -} - -#topbar #searchbox input { - flex-grow: 1; - border: 1px solid #ccc; - padding: 7px; - color: #333; -} - -#topbar #searchbox p.highlight-link { - text-align: center; - margin: 8px; -} - -#searchbox p.highlight-link a { - padding: 0 4px; - background-color: #fbe54e; -} - - - -/* -- navigation icons ------------------------------------------------------ */ - -/* cover nav-icon */ -div.body, .relbar, footer, div.articleComments { - position: relative; - background-color: #fff; -} - -.nav-icon svg { - position: absolute; - top: 50%; - left: 50%; - margin: -1.25em; - width: 2.5em; - height: 2.5em; - fill: currentColor; -} - -.nav-icon { - position: fixed; - right: 0; - margin: -2em 1em; - width: 4em; - height: 4em; - color: #f5f5f5; -} - -.nav-icon:visited { - color: #f5f5f5; -} - -.nav-icon:hover { - color: #fff; - background-color: #f5f5f5; -} - -.nav-icon.previous { - bottom: 50vh; - left: 0; - right: unset; -} - -.nav-icon.next { - top: 50vh; -} -#sidebar-checkbox:checked ~ nav .nav-icon.previous { - left: var(--sidebar-width); -} - -body:not(.sidebar-resizing) .nav-icon.previous { - transition: left 0.3s ease-out; -} - -/* -- sphinx.ext.viewcode --------------------------------------------------- */ - -.viewcode-link { - font-size: 90%; - margin-left: 1em; -} - -div.viewcode-block:target { - margin: -0.5em; - padding: 0.5em; - background-color: #ffffcc; -} - -/* -- media queries --------------------------------------------------------- */ -@media only screen and (max-width: 39rem) { - #sidebar-checkbox:checked ~ div.document, - #sidebar-checkbox:checked ~ .relbar, - #sidebar-checkbox:checked ~ .articleComments, - #sidebar-checkbox:checked ~ footer { - margin-left: 0; - } - - #sidebar-checkbox:checked ~ #topbar-placeholder { - margin-left: 0; - } - - #overlay { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - visibility: hidden; - opacity: 0; - background-color: rgba(100%, 100%, 100%, 80%); - transition: opacity 0.3s ease-out, visibility 0s 0.3s ease-out; - z-index: 380; - } - - #sidebar-checkbox:checked ~ #overlay { - visibility: visible; - opacity: 1; - transition: opacity 0.3s ease-out; - } - - #sidebar-checkbox:checked ~ #topbar-placeholder #titlebar .parent { - display: unset; - } - - #sidebar-checkbox:checked ~ #topbar-placeholder #titlebar #titlebar .top { - display: none; - } -} - -body:not(.js) #fullscreen-button { - display: none; -} - -body.js #fullscreen-button .disable { - display: none; -} - -@media all and (display-mode: fullscreen) { - body.js #fullscreen-button .enable { - display: none; - } - - body.js #fullscreen-button .disable { - display: unset; - } -} - -/* -- fix Firefox buttons --------------------------------------------------- */ - -button::-moz-focus-inner { - border-style: none; - padding: 0; -} - -button:-moz-focusring { - outline: 1px dotted; -} \ No newline at end of file diff --git a/Documentation/_build/html/_static/insipid.js b/Documentation/_build/html/_static/insipid.js deleted file mode 100644 index 0b71b9415..000000000 --- a/Documentation/_build/html/_static/insipid.js +++ /dev/null @@ -1,149 +0,0 @@ -(dom_loaded => { - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', dom_loaded); - } else { - dom_loaded(); - } -})(() => { - 'use strict'; - - // make sure all scripts are re-executed when navigating to cached page - window.onunload = () => {}; - - const topbar = document.getElementById('topbar'); - const topbar_placeholder = document.getElementById('topbar-placeholder'); - - const threshold = 10; - - // auto-hide topbar - function scroll_callback(scroller) { - let ignore_scroll = true; - let initial; - let scroll_timeout; - return event => { - window.clearTimeout(scroll_timeout); - const current = scroller.scrollTop; - if (current <= topbar.offsetHeight || (scroller.scrollHeight - current - scroller.clientHeight) < (scroller.clientHeight / 3)) { - document.body.classList.remove('topbar-folded'); - ignore_scroll = true; - return; - } else if (ignore_scroll) { - // We ignore single jumps - ignore_scroll = false; - initial = current; - } else if (current - initial > threshold) { - document.body.classList.add('topbar-folded'); - ignore_scroll = true; - return; - } else if (current - initial < -threshold) { - document.body.classList.remove('topbar-folded'); - ignore_scroll = true; - return; - } - scroll_timeout = setTimeout(() => { ignore_scroll = true; }, 66); - }; - } - - document.addEventListener('scroll', scroll_callback(document.scrollingElement)); - - const sidebar_scroller = document.querySelector('.sphinxsidebar'); - if (sidebar_scroller) { - sidebar_scroller.addEventListener('scroll', scroll_callback(sidebar_scroller)); - } - - const div_body = document.querySelector('div.body'); - const first_section = document.querySelector('div.body .section, div.body section'); - if (first_section) { - document.addEventListener('scroll', event => { - if (window.pageYOffset >= div_body.offsetTop + first_section.offsetTop) { - document.body.classList.add('scrolled'); - } else { - document.body.classList.remove('scrolled'); - } - }); - document.dispatchEvent(new Event('scroll')); - } - - topbar.querySelector('.top').addEventListener('click', event => { - window.scroll({ top: 0, behavior: 'smooth' }); - event.preventDefault(); - }); - - const search_button = document.getElementById('search-button'); - if (search_button) { - const search_form = document.getElementById('search-form'); - const search_field = search_form.querySelector('input'); - - function show_search() { - try { - // https://readthedocs-sphinx-search.readthedocs.io/ - showSearchModal(); - return; - } catch(e) {} - search_form.style.display = 'flex'; - search_button.setAttribute('aria-expanded', 'true'); - search_field.focus(); - document.body.classList.remove('topbar-folded'); - } - - function hide_search() { - search_form.style.display = 'none'; - search_button.setAttribute('aria-expanded', 'false'); - search_button.blur(); - } - - function toggle_search() { - if (window.getComputedStyle(search_form).display === 'none') { - show_search(); - } else { - hide_search(); - } - } - - search_button.addEventListener('click', toggle_search); - if (Documentation.focusSearchBar) { - // Monkey-patch function provided by Sphinx: - Documentation.focusSearchBar = show_search; - } - - search_field.addEventListener('keydown', event => { - if (event.code === 'Escape') { - hide_search(); - search_field.blur(); - } - }); - } - - const fullscreen_button = document.getElementById('fullscreen-button'); - if (document.fullscreenEnabled) { - fullscreen_button.addEventListener('click', event => { - if (!document.fullscreenElement) { - document.documentElement.requestFullscreen(); - } else { - document.exitFullscreen(); - } - fullscreen_button.blur(); - topbar_placeholder.classList.remove('fake-hover'); - }); - } else { - fullscreen_button.remove(); - } - - topbar_placeholder.addEventListener('mouseenter', event => { - topbar_placeholder.classList.add('fake-hover'); - }); - - topbar_placeholder.addEventListener('mouseleave', event => { - topbar_placeholder.classList.remove('fake-hover'); - }); - - document.addEventListener('touchend', event => { - if (event.touches.length > 1) { return; } - const touch = event.touches[0]; - if (touch.clientY < topbar.offsetHeight) { - topbar_placeholder.classList.add('fake-hover'); - } else { - topbar_placeholder.classList.remove('fake-hover'); - } - }); -}); diff --git a/Documentation/_build/html/_static/language_data.js b/Documentation/_build/html/_static/language_data.js deleted file mode 100644 index 250f5665f..000000000 --- a/Documentation/_build/html/_static/language_data.js +++ /dev/null @@ -1,199 +0,0 @@ -/* - * language_data.js - * ~~~~~~~~~~~~~~~~ - * - * This script contains the language-specific data used by searchtools.js, - * namely the list of stopwords, stemmer, scorer and splitter. - * - * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; - - -/* Non-minified version is copied as a separate JS file, is available */ - -/** - * Porter Stemmer - */ -var Stemmer = function() { - - var step2list = { - ational: 'ate', - tional: 'tion', - enci: 'ence', - anci: 'ance', - izer: 'ize', - bli: 'ble', - alli: 'al', - entli: 'ent', - eli: 'e', - ousli: 'ous', - ization: 'ize', - ation: 'ate', - ator: 'ate', - alism: 'al', - iveness: 'ive', - fulness: 'ful', - ousness: 'ous', - aliti: 'al', - iviti: 'ive', - biliti: 'ble', - logi: 'log' - }; - - var step3list = { - icate: 'ic', - ative: '', - alize: 'al', - iciti: 'ic', - ical: 'ic', - ful: '', - ness: '' - }; - - var c = "[^aeiou]"; // consonant - var v = "[aeiouy]"; // vowel - var C = c + "[^aeiouy]*"; // consonant sequence - var V = v + "[aeiou]*"; // vowel sequence - - var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 - var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 - var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 - var s_v = "^(" + C + ")?" + v; // vowel in stem - - this.stemWord = function (w) { - var stem; - var suffix; - var firstch; - var origword = w; - - if (w.length < 3) - return w; - - var re; - var re2; - var re3; - var re4; - - firstch = w.substr(0,1); - if (firstch == "y") - w = firstch.toUpperCase() + w.substr(1); - - // Step 1a - re = /^(.+?)(ss|i)es$/; - re2 = /^(.+?)([^s])s$/; - - if (re.test(w)) - w = w.replace(re,"$1$2"); - else if (re2.test(w)) - w = w.replace(re2,"$1$2"); - - // Step 1b - re = /^(.+?)eed$/; - re2 = /^(.+?)(ed|ing)$/; - if (re.test(w)) { - var fp = re.exec(w); - re = new RegExp(mgr0); - if (re.test(fp[1])) { - re = /.$/; - w = w.replace(re,""); - } - } - else if (re2.test(w)) { - var fp = re2.exec(w); - stem = fp[1]; - re2 = new RegExp(s_v); - if (re2.test(stem)) { - w = stem; - re2 = /(at|bl|iz)$/; - re3 = new RegExp("([^aeiouylsz])\\1$"); - re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); - if (re2.test(w)) - w = w + "e"; - else if (re3.test(w)) { - re = /.$/; - w = w.replace(re,""); - } - else if (re4.test(w)) - w = w + "e"; - } - } - - // Step 1c - re = /^(.+?)y$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - re = new RegExp(s_v); - if (re.test(stem)) - w = stem + "i"; - } - - // Step 2 - re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - suffix = fp[2]; - re = new RegExp(mgr0); - if (re.test(stem)) - w = stem + step2list[suffix]; - } - - // Step 3 - re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - suffix = fp[2]; - re = new RegExp(mgr0); - if (re.test(stem)) - w = stem + step3list[suffix]; - } - - // Step 4 - re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; - re2 = /^(.+?)(s|t)(ion)$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - re = new RegExp(mgr1); - if (re.test(stem)) - w = stem; - } - else if (re2.test(w)) { - var fp = re2.exec(w); - stem = fp[1] + fp[2]; - re2 = new RegExp(mgr1); - if (re2.test(stem)) - w = stem; - } - - // Step 5 - re = /^(.+?)e$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - re = new RegExp(mgr1); - re2 = new RegExp(meq1); - re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); - if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) - w = stem; - } - re = /ll$/; - re2 = new RegExp(mgr1); - if (re.test(w) && re2.test(w)) { - re = /.$/; - w = w.replace(re,""); - } - - // and turn initial Y back to y - if (firstch == "y") - w = firstch.toLowerCase() + w.substr(1); - return w; - } -} - diff --git a/Documentation/_build/html/_static/minus.png b/Documentation/_build/html/_static/minus.png deleted file mode 100644 index d96755fda..000000000 Binary files a/Documentation/_build/html/_static/minus.png and /dev/null differ diff --git a/Documentation/_build/html/_static/plus.png b/Documentation/_build/html/_static/plus.png deleted file mode 100644 index 7107cec93..000000000 Binary files a/Documentation/_build/html/_static/plus.png and /dev/null differ diff --git a/Documentation/_build/html/_static/pygments.css b/Documentation/_build/html/_static/pygments.css deleted file mode 100644 index 7a181158c..000000000 --- a/Documentation/_build/html/_static/pygments.css +++ /dev/null @@ -1,74 +0,0 @@ -pre { line-height: 125%; } -td.linenos .normal { color: #666666; background-color: transparent; padding-left: 5px; padding-right: 5px; } -span.linenos { color: #666666; background-color: transparent; padding-left: 5px; padding-right: 5px; } -td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } -span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } -.highlight .hll { background-color: #ffffcc } -.highlight { background: #f0f0f0; } -.highlight .c { color: #60a0b0; font-style: italic } /* Comment */ -.highlight .err { border: 1px solid #FF0000 } /* Error */ -.highlight .k { color: #007020; font-weight: bold } /* Keyword */ -.highlight .o { color: #666666 } /* Operator */ -.highlight .ch { color: #60a0b0; font-style: italic } /* Comment.Hashbang */ -.highlight .cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */ -.highlight .cp { color: #007020 } /* Comment.Preproc */ -.highlight .cpf { color: #60a0b0; font-style: italic } /* Comment.PreprocFile */ -.highlight .c1 { color: #60a0b0; font-style: italic } /* Comment.Single */ -.highlight .cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */ -.highlight .gd { color: #A00000 } /* Generic.Deleted */ -.highlight .ge { font-style: italic } /* Generic.Emph */ -.highlight .gr { color: #FF0000 } /* Generic.Error */ -.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ -.highlight .gi { color: #00A000 } /* Generic.Inserted */ -.highlight .go { color: #888888 } /* Generic.Output */ -.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ -.highlight .gs { font-weight: bold } /* Generic.Strong */ -.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -.highlight .gt { color: #0044DD } /* Generic.Traceback */ -.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ -.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ -.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ -.highlight .kp { color: #007020 } /* Keyword.Pseudo */ -.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ -.highlight .kt { color: #902000 } /* Keyword.Type */ -.highlight .m { color: #40a070 } /* Literal.Number */ -.highlight .s { color: #4070a0 } /* Literal.String */ -.highlight .na { color: #4070a0 } /* Name.Attribute */ -.highlight .nb { color: #007020 } /* Name.Builtin */ -.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ -.highlight .no { color: #60add5 } /* Name.Constant */ -.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ -.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ -.highlight .ne { color: #007020 } /* Name.Exception */ -.highlight .nf { color: #06287e } /* Name.Function */ -.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ -.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ -.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ -.highlight .nv { color: #bb60d5 } /* Name.Variable */ -.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ -.highlight .w { color: #bbbbbb } /* Text.Whitespace */ -.highlight .mb { color: #40a070 } /* Literal.Number.Bin */ -.highlight .mf { color: #40a070 } /* Literal.Number.Float */ -.highlight .mh { color: #40a070 } /* Literal.Number.Hex */ -.highlight .mi { color: #40a070 } /* Literal.Number.Integer */ -.highlight .mo { color: #40a070 } /* Literal.Number.Oct */ -.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ -.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ -.highlight .sc { color: #4070a0 } /* Literal.String.Char */ -.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ -.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ -.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ -.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ -.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ -.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ -.highlight .sx { color: #c65d09 } /* Literal.String.Other */ -.highlight .sr { color: #235388 } /* Literal.String.Regex */ -.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ -.highlight .ss { color: #517918 } /* Literal.String.Symbol */ -.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ -.highlight .fm { color: #06287e } /* Name.Function.Magic */ -.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ -.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ -.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ -.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ -.highlight .il { color: #40a070 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/Documentation/_build/html/_static/searchtools.js b/Documentation/_build/html/_static/searchtools.js deleted file mode 100644 index 97d56a74d..000000000 --- a/Documentation/_build/html/_static/searchtools.js +++ /dev/null @@ -1,566 +0,0 @@ -/* - * searchtools.js - * ~~~~~~~~~~~~~~~~ - * - * Sphinx JavaScript utilities for the full-text search. - * - * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ -"use strict"; - -/** - * Simple result scoring code. - */ -if (typeof Scorer === "undefined") { - var Scorer = { - // Implement the following function to further tweak the score for each result - // The function takes a result array [docname, title, anchor, descr, score, filename] - // and returns the new score. - /* - score: result => { - const [docname, title, anchor, descr, score, filename] = result - return score - }, - */ - - // query matches the full name of an object - objNameMatch: 11, - // or matches in the last dotted part of the object name - objPartialMatch: 6, - // Additive scores depending on the priority of the object - objPrio: { - 0: 15, // used to be importantResults - 1: 5, // used to be objectResults - 2: -5, // used to be unimportantResults - }, - // Used when the priority is not in the mapping. - objPrioDefault: 0, - - // query found in title - title: 15, - partialTitle: 7, - // query found in terms - term: 5, - partialTerm: 2, - }; -} - -const _removeChildren = (element) => { - while (element && element.lastChild) element.removeChild(element.lastChild); -}; - -/** - * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping - */ -const _escapeRegExp = (string) => - string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string - -const _displayItem = (item, searchTerms) => { - const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; - const docUrlRoot = DOCUMENTATION_OPTIONS.URL_ROOT; - const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; - const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; - const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; - - const [docName, title, anchor, descr, score, _filename] = item; - - let listItem = document.createElement("li"); - let requestUrl; - let linkUrl; - if (docBuilder === "dirhtml") { - // dirhtml builder - let dirname = docName + "/"; - if (dirname.match(/\/index\/$/)) - dirname = dirname.substring(0, dirname.length - 6); - else if (dirname === "index/") dirname = ""; - requestUrl = docUrlRoot + dirname; - linkUrl = requestUrl; - } else { - // normal html builders - requestUrl = docUrlRoot + docName + docFileSuffix; - linkUrl = docName + docLinkSuffix; - } - let linkEl = listItem.appendChild(document.createElement("a")); - linkEl.href = linkUrl + anchor; - linkEl.dataset.score = score; - linkEl.innerHTML = title; - if (descr) - listItem.appendChild(document.createElement("span")).innerHTML = - " (" + descr + ")"; - else if (showSearchSummary) - fetch(requestUrl) - .then((responseData) => responseData.text()) - .then((data) => { - if (data) - listItem.appendChild( - Search.makeSearchSummary(data, searchTerms) - ); - }); - Search.output.appendChild(listItem); -}; -const _finishSearch = (resultCount) => { - Search.stopPulse(); - Search.title.innerText = _("Search Results"); - if (!resultCount) - Search.status.innerText = Documentation.gettext( - "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." - ); - else - Search.status.innerText = _( - `Search finished, found ${resultCount} page(s) matching the search query.` - ); -}; -const _displayNextItem = ( - results, - resultCount, - searchTerms -) => { - // results left, load the summary and display it - // this is intended to be dynamic (don't sub resultsCount) - if (results.length) { - _displayItem(results.pop(), searchTerms); - setTimeout( - () => _displayNextItem(results, resultCount, searchTerms), - 5 - ); - } - // search finished, update title and status message - else _finishSearch(resultCount); -}; - -/** - * Default splitQuery function. Can be overridden in ``sphinx.search`` with a - * custom function per language. - * - * The regular expression works by splitting the string on consecutive characters - * that are not Unicode letters, numbers, underscores, or emoji characters. - * This is the same as ``\W+`` in Python, preserving the surrogate pair area. - */ -if (typeof splitQuery === "undefined") { - var splitQuery = (query) => query - .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) - .filter(term => term) // remove remaining empty strings -} - -/** - * Search Module - */ -const Search = { - _index: null, - _queued_query: null, - _pulse_status: -1, - - htmlToText: (htmlString) => { - const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); - htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); - const docContent = htmlElement.querySelector('[role="main"]'); - if (docContent !== undefined) return docContent.textContent; - console.warn( - "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." - ); - return ""; - }, - - init: () => { - const query = new URLSearchParams(window.location.search).get("q"); - document - .querySelectorAll('input[name="q"]') - .forEach((el) => (el.value = query)); - if (query) Search.performSearch(query); - }, - - loadIndex: (url) => - (document.body.appendChild(document.createElement("script")).src = url), - - setIndex: (index) => { - Search._index = index; - if (Search._queued_query !== null) { - const query = Search._queued_query; - Search._queued_query = null; - Search.query(query); - } - }, - - hasIndex: () => Search._index !== null, - - deferQuery: (query) => (Search._queued_query = query), - - stopPulse: () => (Search._pulse_status = -1), - - startPulse: () => { - if (Search._pulse_status >= 0) return; - - const pulse = () => { - Search._pulse_status = (Search._pulse_status + 1) % 4; - Search.dots.innerText = ".".repeat(Search._pulse_status); - if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); - }; - pulse(); - }, - - /** - * perform a search for something (or wait until index is loaded) - */ - performSearch: (query) => { - // create the required interface elements - const searchText = document.createElement("h2"); - searchText.textContent = _("Searching"); - const searchSummary = document.createElement("p"); - searchSummary.classList.add("search-summary"); - searchSummary.innerText = ""; - const searchList = document.createElement("ul"); - searchList.classList.add("search"); - - const out = document.getElementById("search-results"); - Search.title = out.appendChild(searchText); - Search.dots = Search.title.appendChild(document.createElement("span")); - Search.status = out.appendChild(searchSummary); - Search.output = out.appendChild(searchList); - - const searchProgress = document.getElementById("search-progress"); - // Some themes don't use the search progress node - if (searchProgress) { - searchProgress.innerText = _("Preparing search..."); - } - Search.startPulse(); - - // index already loaded, the browser was quick! - if (Search.hasIndex()) Search.query(query); - else Search.deferQuery(query); - }, - - /** - * execute search (requires search index to be loaded) - */ - query: (query) => { - const filenames = Search._index.filenames; - const docNames = Search._index.docnames; - const titles = Search._index.titles; - const allTitles = Search._index.alltitles; - const indexEntries = Search._index.indexentries; - - // stem the search terms and add them to the correct list - const stemmer = new Stemmer(); - const searchTerms = new Set(); - const excludedTerms = new Set(); - const highlightTerms = new Set(); - const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); - splitQuery(query.trim()).forEach((queryTerm) => { - const queryTermLower = queryTerm.toLowerCase(); - - // maybe skip this "word" - // stopwords array is from language_data.js - if ( - stopwords.indexOf(queryTermLower) !== -1 || - queryTerm.match(/^\d+$/) - ) - return; - - // stem the word - let word = stemmer.stemWord(queryTermLower); - // select the correct list - if (word[0] === "-") excludedTerms.add(word.substr(1)); - else { - searchTerms.add(word); - highlightTerms.add(queryTermLower); - } - }); - - if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js - localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) - } - - // console.debug("SEARCH: searching for:"); - // console.info("required: ", [...searchTerms]); - // console.info("excluded: ", [...excludedTerms]); - - // array of [docname, title, anchor, descr, score, filename] - let results = []; - _removeChildren(document.getElementById("search-progress")); - - const queryLower = query.toLowerCase(); - for (const [title, foundTitles] of Object.entries(allTitles)) { - if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { - for (const [file, id] of foundTitles) { - let score = Math.round(100 * queryLower.length / title.length) - results.push([ - docNames[file], - titles[file] !== title ? `${titles[file]} > ${title}` : title, - id !== null ? "#" + id : "", - null, - score, - filenames[file], - ]); - } - } - } - - // search for explicit entries in index directives - for (const [entry, foundEntries] of Object.entries(indexEntries)) { - if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { - for (const [file, id] of foundEntries) { - let score = Math.round(100 * queryLower.length / entry.length) - results.push([ - docNames[file], - titles[file], - id ? "#" + id : "", - null, - score, - filenames[file], - ]); - } - } - } - - // lookup as object - objectTerms.forEach((term) => - results.push(...Search.performObjectSearch(term, objectTerms)) - ); - - // lookup as search terms in fulltext - results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); - - // let the scorer override scores with a custom scoring function - if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); - - // now sort the results by score (in opposite order of appearance, since the - // display function below uses pop() to retrieve items) and then - // alphabetically - results.sort((a, b) => { - const leftScore = a[4]; - const rightScore = b[4]; - if (leftScore === rightScore) { - // same score: sort alphabetically - const leftTitle = a[1].toLowerCase(); - const rightTitle = b[1].toLowerCase(); - if (leftTitle === rightTitle) return 0; - return leftTitle > rightTitle ? -1 : 1; // inverted is intentional - } - return leftScore > rightScore ? 1 : -1; - }); - - // remove duplicate search results - // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept - let seen = new Set(); - results = results.reverse().reduce((acc, result) => { - let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); - if (!seen.has(resultStr)) { - acc.push(result); - seen.add(resultStr); - } - return acc; - }, []); - - results = results.reverse(); - - // for debugging - //Search.lastresults = results.slice(); // a copy - // console.info("search results:", Search.lastresults); - - // print the results - _displayNextItem(results, results.length, searchTerms); - }, - - /** - * search for object names - */ - performObjectSearch: (object, objectTerms) => { - const filenames = Search._index.filenames; - const docNames = Search._index.docnames; - const objects = Search._index.objects; - const objNames = Search._index.objnames; - const titles = Search._index.titles; - - const results = []; - - const objectSearchCallback = (prefix, match) => { - const name = match[4] - const fullname = (prefix ? prefix + "." : "") + name; - const fullnameLower = fullname.toLowerCase(); - if (fullnameLower.indexOf(object) < 0) return; - - let score = 0; - const parts = fullnameLower.split("."); - - // check for different match types: exact matches of full name or - // "last name" (i.e. last dotted part) - if (fullnameLower === object || parts.slice(-1)[0] === object) - score += Scorer.objNameMatch; - else if (parts.slice(-1)[0].indexOf(object) > -1) - score += Scorer.objPartialMatch; // matches in last name - - const objName = objNames[match[1]][2]; - const title = titles[match[0]]; - - // If more than one term searched for, we require other words to be - // found in the name/title/description - const otherTerms = new Set(objectTerms); - otherTerms.delete(object); - if (otherTerms.size > 0) { - const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); - if ( - [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) - ) - return; - } - - let anchor = match[3]; - if (anchor === "") anchor = fullname; - else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; - - const descr = objName + _(", in ") + title; - - // add custom score for some objects according to scorer - if (Scorer.objPrio.hasOwnProperty(match[2])) - score += Scorer.objPrio[match[2]]; - else score += Scorer.objPrioDefault; - - results.push([ - docNames[match[0]], - fullname, - "#" + anchor, - descr, - score, - filenames[match[0]], - ]); - }; - Object.keys(objects).forEach((prefix) => - objects[prefix].forEach((array) => - objectSearchCallback(prefix, array) - ) - ); - return results; - }, - - /** - * search for full-text terms in the index - */ - performTermsSearch: (searchTerms, excludedTerms) => { - // prepare search - const terms = Search._index.terms; - const titleTerms = Search._index.titleterms; - const filenames = Search._index.filenames; - const docNames = Search._index.docnames; - const titles = Search._index.titles; - - const scoreMap = new Map(); - const fileMap = new Map(); - - // perform the search on the required terms - searchTerms.forEach((word) => { - const files = []; - const arr = [ - { files: terms[word], score: Scorer.term }, - { files: titleTerms[word], score: Scorer.title }, - ]; - // add support for partial matches - if (word.length > 2) { - const escapedWord = _escapeRegExp(word); - Object.keys(terms).forEach((term) => { - if (term.match(escapedWord) && !terms[word]) - arr.push({ files: terms[term], score: Scorer.partialTerm }); - }); - Object.keys(titleTerms).forEach((term) => { - if (term.match(escapedWord) && !titleTerms[word]) - arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); - }); - } - - // no match but word was a required one - if (arr.every((record) => record.files === undefined)) return; - - // found search word in contents - arr.forEach((record) => { - if (record.files === undefined) return; - - let recordFiles = record.files; - if (recordFiles.length === undefined) recordFiles = [recordFiles]; - files.push(...recordFiles); - - // set score for the word in each file - recordFiles.forEach((file) => { - if (!scoreMap.has(file)) scoreMap.set(file, {}); - scoreMap.get(file)[word] = record.score; - }); - }); - - // create the mapping - files.forEach((file) => { - if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) - fileMap.get(file).push(word); - else fileMap.set(file, [word]); - }); - }); - - // now check if the files don't contain excluded terms - const results = []; - for (const [file, wordList] of fileMap) { - // check if all requirements are matched - - // as search terms with length < 3 are discarded - const filteredTermCount = [...searchTerms].filter( - (term) => term.length > 2 - ).length; - if ( - wordList.length !== searchTerms.size && - wordList.length !== filteredTermCount - ) - continue; - - // ensure that none of the excluded terms is in the search result - if ( - [...excludedTerms].some( - (term) => - terms[term] === file || - titleTerms[term] === file || - (terms[term] || []).includes(file) || - (titleTerms[term] || []).includes(file) - ) - ) - break; - - // select one (max) score for the file. - const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); - // add result to the result list - results.push([ - docNames[file], - titles[file], - "", - null, - score, - filenames[file], - ]); - } - return results; - }, - - /** - * helper function to return a node containing the - * search summary for a given text. keywords is a list - * of stemmed words. - */ - makeSearchSummary: (htmlText, keywords) => { - const text = Search.htmlToText(htmlText); - if (text === "") return null; - - const textLower = text.toLowerCase(); - const actualStartPosition = [...keywords] - .map((k) => textLower.indexOf(k.toLowerCase())) - .filter((i) => i > -1) - .slice(-1)[0]; - const startWithContext = Math.max(actualStartPosition - 120, 0); - - const top = startWithContext === 0 ? "" : "..."; - const tail = startWithContext + 240 < text.length ? "..." : ""; - - let summary = document.createElement("p"); - summary.classList.add("context"); - summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; - - return summary; - }, -}; - -_ready(Search.init); diff --git a/Documentation/_build/html/_static/sphinx_highlight.js b/Documentation/_build/html/_static/sphinx_highlight.js deleted file mode 100644 index aae669d7e..000000000 --- a/Documentation/_build/html/_static/sphinx_highlight.js +++ /dev/null @@ -1,144 +0,0 @@ -/* Highlighting utilities for Sphinx HTML documentation. */ -"use strict"; - -const SPHINX_HIGHLIGHT_ENABLED = true - -/** - * highlight a given string on a node by wrapping it in - * span elements with the given class name. - */ -const _highlight = (node, addItems, text, className) => { - if (node.nodeType === Node.TEXT_NODE) { - const val = node.nodeValue; - const parent = node.parentNode; - const pos = val.toLowerCase().indexOf(text); - if ( - pos >= 0 && - !parent.classList.contains(className) && - !parent.classList.contains("nohighlight") - ) { - let span; - - const closestNode = parent.closest("body, svg, foreignObject"); - const isInSVG = closestNode && closestNode.matches("svg"); - if (isInSVG) { - span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); - } else { - span = document.createElement("span"); - span.classList.add(className); - } - - span.appendChild(document.createTextNode(val.substr(pos, text.length))); - parent.insertBefore( - span, - parent.insertBefore( - document.createTextNode(val.substr(pos + text.length)), - node.nextSibling - ) - ); - node.nodeValue = val.substr(0, pos); - - if (isInSVG) { - const rect = document.createElementNS( - "http://www.w3.org/2000/svg", - "rect" - ); - const bbox = parent.getBBox(); - rect.x.baseVal.value = bbox.x; - rect.y.baseVal.value = bbox.y; - rect.width.baseVal.value = bbox.width; - rect.height.baseVal.value = bbox.height; - rect.setAttribute("class", className); - addItems.push({ parent: parent, target: rect }); - } - } - } else if (node.matches && !node.matches("button, select, textarea")) { - node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); - } -}; -const _highlightText = (thisNode, text, className) => { - let addItems = []; - _highlight(thisNode, addItems, text, className); - addItems.forEach((obj) => - obj.parent.insertAdjacentElement("beforebegin", obj.target) - ); -}; - -/** - * Small JavaScript module for the documentation. - */ -const SphinxHighlight = { - - /** - * highlight the search words provided in localstorage in the text - */ - highlightSearchWords: () => { - if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight - - // get and clear terms from localstorage - const url = new URL(window.location); - const highlight = - localStorage.getItem("sphinx_highlight_terms") - || url.searchParams.get("highlight") - || ""; - localStorage.removeItem("sphinx_highlight_terms") - url.searchParams.delete("highlight"); - window.history.replaceState({}, "", url); - - // get individual terms from highlight string - const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); - if (terms.length === 0) return; // nothing to do - - // There should never be more than one element matching "div.body" - const divBody = document.querySelectorAll("div.body"); - const body = divBody.length ? divBody[0] : document.querySelector("body"); - window.setTimeout(() => { - terms.forEach((term) => _highlightText(body, term, "highlighted")); - }, 10); - - const searchBox = document.getElementById("searchbox"); - if (searchBox === null) return; - searchBox.appendChild( - document - .createRange() - .createContextualFragment( - '" - ) - ); - }, - - /** - * helper function to hide the search marks again - */ - hideSearchWords: () => { - document - .querySelectorAll("#searchbox .highlight-link") - .forEach((el) => el.remove()); - document - .querySelectorAll("span.highlighted") - .forEach((el) => el.classList.remove("highlighted")); - localStorage.removeItem("sphinx_highlight_terms") - }, - - initEscapeListener: () => { - // only install a listener if it is really needed - if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; - - document.addEventListener("keydown", (event) => { - // bail for input elements - if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; - // bail with special keys - if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; - if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { - SphinxHighlight.hideSearchWords(); - event.preventDefault(); - } - }); - }, -}; - -_ready(SphinxHighlight.highlightSearchWords); -_ready(SphinxHighlight.initEscapeListener); diff --git a/Documentation/_build/html/genindex.html b/Documentation/_build/html/genindex.html deleted file mode 100644 index 182a7181d..000000000 --- a/Documentation/_build/html/genindex.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - Index — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
- -
- -
-
- -
-
- - - - - - - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/index.html b/Documentation/_build/html/index.html deleted file mode 100644 index 22ca6aaea..000000000 --- a/Documentation/_build/html/index.html +++ /dev/null @@ -1,227 +0,0 @@ - - - - - - - - - vAmiga User’s Manual — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -
-
- vAmiga 2.4 - vAmiga User’s Manual -
-
- -
-
- -
-
- - - - - - - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/objects.inv b/Documentation/_build/html/objects.inv deleted file mode 100644 index 6e9ba25f0..000000000 Binary files a/Documentation/_build/html/objects.inv and /dev/null differ diff --git a/Documentation/_build/html/search.html b/Documentation/_build/html/search.html deleted file mode 100644 index bfb7e0e62..000000000 --- a/Documentation/_build/html/search.html +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - Search — vAmiga 2.4 - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- -
- -
- -
-
-
-
- - - - -
-
-
-
- -

Search

- - - - -

- Searching for multiple words only shows matches that contain - all words. -

- - -
- - - -
- - - -
- -
- - -
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/Documentation/_build/html/searchindex.js b/Documentation/_build/html/searchindex.js deleted file mode 100644 index 510171d92..000000000 --- a/Documentation/_build/html/searchindex.js +++ /dev/null @@ -1 +0,0 @@ -Search.setIndex({"docnames": ["Developer/ClassHierarchy", "Developer/EventScheduler", "Developer/MessageQueue", "Developer/RunLoop", "Developer/SuperHires", "Developer/ThreadClass", "HowTo/MappingCmd", "HowTo/NullModemCable", "Overview/About", "References/Configuration/Audio", "References/Configuration/Chipset", "References/Configuration/Compatibility", "References/Configuration/Memory", "References/Configuration/Peripherals", "References/Configuration/Roms", "References/Configuration/Video", "References/Configuration/index", "References/FileFormats", "References/Preferences/Controls", "References/Preferences/Devices", "References/Preferences/General", "References/Preferences/index", "Tutorials/Exploring", "Tutorials/GettingStarted", "index"], "filenames": ["Developer/ClassHierarchy.md", "Developer/EventScheduler.md", "Developer/MessageQueue.md", "Developer/RunLoop.md", "Developer/SuperHires.md", "Developer/ThreadClass.md", "HowTo/MappingCmd.md", "HowTo/NullModemCable.md", "Overview/About.md", "References/Configuration/Audio.md", "References/Configuration/Chipset.md", "References/Configuration/Compatibility.md", "References/Configuration/Memory.md", "References/Configuration/Peripherals.md", "References/Configuration/Roms.md", "References/Configuration/Video.md", "References/Configuration/index.rst", "References/FileFormats.md", "References/Preferences/Controls.md", "References/Preferences/Devices.md", "References/Preferences/General.md", "References/Preferences/index.rst", "Tutorials/Exploring.md", "Tutorials/GettingStarted.md", "index.rst"], "titles": ["The Class Hierarchy", "The Event Scheduler", "The Message Queue", "The Run Loop", "SuperHires mode", "The Thread Class", "Mapping the Command keys", "Connecting Two Amigas", "About", "Audio Panel", "Chipset Panel", "Compatibility Panel", "Memory Panel", "Peripherals Panel", "ROM Panel", "Video Panel", "Virtual Machine Settings", "Supported File Formats", "Controls Panel", "Devices Panel", "General Panel", "Emulator Settings", "Exploring the User Interface", "Getting Started", "vAmiga User\u2019s Manual"], "terms": {"thi": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 22, 23], "document": [0, 1, 2, 3, 4, 5, 12, 19, 22], "describ": [0, 4, 7, 9, 11, 22, 23], "basic": [0, 1, 12, 15, 22], "softwar": [0, 1, 8, 10, 11, 17, 23], "architectur": [0, 8, 10], "vamiga": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22], "emul": [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, 22, 23, 24], "ha": [0, 1, 2, 3, 4, 5, 7, 8, 10, 11, 12, 14, 15, 17, 19, 20, 22, 23], "been": [0, 5, 7, 8, 10, 11, 14, 15, 17, 19, 20, 23], "written": [0, 2, 8, 11], "c": [0, 2, 3], "i": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 22, 23], "base": [0, 2, 4, 5, 9, 15, 22], "follow": [0, 1, 2, 3, 4, 5, 10, 13, 15, 17, 19, 22], "most": [0, 1, 3, 4, 6, 10, 12, 15, 17, 18, 20, 22, 23], "promin": [0, 10, 22], "amiga": [0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 17, 22, 23, 24], "each": [0, 1, 3, 4, 5, 7, 8, 9, 11, 13, 15], "instanc": [0, 1, 2, 3, 5, 7, 13, 16, 21, 22], "repres": [0, 1, 4, 17, 22, 23], "complet": [0, 10], "virtual": [0, 3, 5, 7, 10, 14, 22, 24], "inherit": [0, 5], "from": [0, 1, 2, 4, 5, 7, 8, 9, 10, 11, 12, 14, 15, 18, 19, 21, 22, 23], "three": [0, 1, 4, 5, 8, 9, 10, 11, 12, 15, 21, 22], "other": [0, 1, 2, 4, 5, 7, 10, 11, 12, 13, 14, 15, 20, 23], "coreobject": 0, "encapsul": [0, 2], "some": [0, 1, 3, 7, 10, 12, 14, 15, 19, 22], "common": [0, 7, 12, 15], "function": [0, 1, 2, 3, 8, 14, 20, 22], "ar": [0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23], "us": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 22, 23], "univers": 0, "For": [0, 1, 3, 5, 8, 10, 12, 14, 15, 17, 19, 20, 22], "exampl": [0, 1, 3, 5, 10, 12, 17, 20, 22, 23], "provid": [0, 2, 4, 5, 8, 10, 13, 15, 17, 22], "api": [0, 1, 2, 5], "print": 0, "debug": [0, 7, 22], "messag": [0, 1, 24], "corecompon": [0, 5], "defin": [0, 1, 2, 4, 15], "share": [0, 1], "all": [0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 21, 22, 23], "hardwar": [0, 1], "compon": [0, 1, 3, 8, 10, 12, 22], "It": [0, 1, 2, 3, 4, 5, 8, 10, 11, 12, 15, 17, 19, 22], "includ": [0, 13, 15, 16, 19, 21], "initi": [0, 12], "configur": [0, 4, 7, 10, 11, 12, 13, 15, 16, 18, 19, 20, 21, 22], "serial": [0, 7], "object": [0, 2, 3, 15], "well": [0, 1, 3, 10, 11, 23], "power": [0, 10, 23], "off": [0, 5, 6, 8, 9, 10, 22, 23], "run": [0, 1, 4, 5, 7, 8, 10, 11, 13, 15, 22, 23, 24], "paus": [0, 5, 22], "thread": [0, 2, 3, 15, 24], "enabl": [0, 1, 10, 11, 12, 15, 22], "code": [0, 2, 4, 5, 8, 10, 11, 23], "separ": [0, 2, 3, 14, 15, 22], "cover": [0, 22], "anoth": [0, 3, 7, 13, 15], "import": [0, 1, 2, 3, 4, 8, 10, 23], "entiti": 0, "subcompon": [0, 2], "which": [0, 1, 2, 3, 4, 5, 7, 10, 11, 12, 13, 14, 15, 18, 22, 23], "ancestor": 0, "you": [0, 1, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 17, 18, 19, 20, 22, 23], "guess": [0, 3, 22], "As": [0, 1, 2, 3, 4, 5, 7, 11, 12, 14, 15, 18, 22], "rule": 0, "thumb": 0, "ll": [0, 1, 3, 23], "find": [0, 6, 11, 17, 22, 23], "almost": [0, 17, 22, 23], "everi": [0, 15], "motherboard": [0, 10, 11, 12], "real": [0, 9, 10, 11, 12, 13, 15, 18, 22], "There": 0, "cpu": [0, 1, 3, 5, 8, 11, 12, 22], "memori": [0, 3, 4, 8, 10, 11, 14, 16, 22], "custom": [0, 1, 10, 12, 20], "chip": [0, 10, 12, 22], "agnu": [0, 1, 3, 12], "denis": [0, 11], "paula": [0, 1], "blitter": [0, 1, 12, 22], "copper": [0, 1, 12, 22], "also": [0, 1, 2, 4, 5, 9, 10, 11, 12, 14, 17, 18, 19, 22], "individu": [0, 4], "insid": [0, 2, 3, 5, 7, 17, 18], "just": [0, 1, 3, 4, 5, 9, 10, 11, 12, 13, 17, 22], "would": [0, 5, 6, 10, 11, 15, 22], "logic": [0, 3, 4, 10, 11], "circuit": 0, "machin": [0, 1, 5, 8, 10, 11, 12, 15, 22, 23, 24], "inner": [0, 1, 3, 22], "structur": [0, 1, 17], "veri": [0, 1, 5, 10, 12, 15, 17, 22], "simpl": [0, 1, 2, 3, 7, 17], "its": [0, 1, 2, 3, 5, 7, 10, 12, 13, 15, 19], "main": [0, 2, 3, 9, 10, 23], "purpos": [0, 1, 3, 5, 8, 12, 22], "make": [0, 4, 12, 15, 17, 22], "visibl": [0, 14, 15], "In": [0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 14, 15, 22, 23], "diagram": [0, 1], "mai": [0, 2, 3, 5, 9, 10, 12, 14, 15, 23], "have": [0, 1, 2, 3, 4, 5, 7, 8, 10, 12, 14, 15, 19, 20, 22, 23], "spot": [0, 5], "associ": [0, 6, 15], "arrow": 0, "connect": [0, 1, 9, 11, 12, 13, 19, 22, 24], "establish": [0, 7], "constructor": [0, 5], "ref": 0, "number": [0, 1, 3, 4, 5, 7, 10, 15, 18, 22], "refer": [0, 1, 3, 8, 10, 11, 12, 22], "like": [0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 12, 13, 17, 20, 22, 23], "set": [0, 1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 15, 18, 20, 22, 23, 24], "up": [0, 1, 2, 3, 4, 5, 9, 11, 12, 13, 15, 23], "mem": 0, "avail": [0, 3, 4, 5, 16, 17, 21, 22], "ani": [0, 2, 10, 11, 12, 14, 17], "subclass": 0, "easi": [0, 8, 10, 23], "access": [0, 1, 2, 3, 5, 6, 8, 10, 11, 12, 22, 23], "whenev": [0, 2], "need": [0, 1, 3, 4, 10, 11, 12, 15, 22], "block": [0, 1, 5, 11, 17], "certain": [0, 1, 3, 10, 11, 18, 20, 22], "cycl": [0, 1, 3, 8, 10, 11, 12, 22], "can": [0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23], "do": [0, 1, 4, 6, 7, 11, 12, 15, 17, 22, 23], "so": [0, 1, 3, 6, 7, 10, 11, 12, 15, 22, 23], "call": [0, 1, 2, 3, 4, 5, 10, 11, 12, 15, 22], "an": [0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 22, 23], "appropri": [0, 1, 6], "addwaitst": 0, "delai": [0, 1, 11, 12, 22], "driven": [1, 4, 11], "If": [1, 2, 3, 4, 6, 7, 10, 11, 12, 13, 14, 15, 17, 19, 22, 23], "action": [1, 3, 5, 6, 22], "perform": [1, 2, 3, 4, 5, 8, 9, 10, 11, 14, 15, 22], "bu": [1, 3, 11, 12, 22], "via": [1, 2, 6, 12, 13, 14, 16, 22, 23], "handler": [1, 3, 11], "execut": [1, 2, 3, 5, 9, 10, 11, 17, 22, 23], "when": [1, 3, 4, 5, 9, 10, 11, 12, 14, 15, 17, 18, 19, 20, 22, 23], "trigger": [1, 3, 4, 6, 11, 15, 22], "reach": 1, "view": 1, "larg": [1, 4, 5], "list": [1, 3, 7, 19], "process": [1, 2, 3, 12, 22], "sequenti": 1, "executeuntil": [1, 3], "about": [1, 3, 4, 7, 10, 22, 24], "loop": [1, 5, 10, 15, 24], "learn": [1, 3], "one": [1, 2, 3, 4, 5, 7, 9, 10, 11, 14, 15, 20, 22], "store": [1, 2, 3, 5, 17, 22], "bound": 1, "specif": [1, 3, 6, 12, 22], "either": [1, 4, 7, 15, 21, 22], "empti": [1, 2, 13, 17, 22], "contain": [1, 2, 11, 15, 17, 20, 22], "singl": [1, 3, 4, 5, 11, 13, 15, 16, 17, 22, 23], "uart": 1, "theoret": [1, 5], "point": [1, 3, 15, 20, 22], "state": [1, 12, 22], "parallel": [1, 12], "rememb": [1, 3, 23], "interact": [1, 10], "variou": [1, 15, 20, 22], "wai": [1, 2, 5, 7, 15, 18, 22, 23], "e": [1, 3, 4, 5, 8, 10, 11, 12, 13, 15, 17, 22, 23], "g": [1, 3, 4, 5, 8, 10, 12, 13, 17, 22], "dma": [1, 8, 10, 11, 12, 22], "therefor": [1, 4, 6, 10, 22, 23], "order": 1, "two": [1, 2, 4, 5, 6, 9, 10, 11, 12, 13, 14, 15, 18, 19, 22, 24], "same": [1, 3, 4, 5, 6, 7, 8, 10, 11, 12, 14, 15], "smaller": 1, "serv": 1, "first": [1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 14, 15, 20, 22, 23], "enough": 1, "theori": 1, "now": [1, 3, 4, 7, 8, 10, 12, 15, 22], "let": [1, 2, 3, 4, 5, 7, 20, 22], "": [1, 3, 4, 5, 7, 10, 22, 23], "open": [1, 5, 7, 8, 13, 14, 21, 22, 23], "tab": [1, 7, 16, 21, 22], "inspector": 1, "panel": [1, 16, 21], "examin": [1, 2, 3, 22], "what": [1, 3, 12, 15, 22], "typic": 1, "look": [1, 2, 3, 4, 5, 7, 9, 10, 15, 22], "see": [1, 3, 4, 5, 7, 12, 14, 15, 22, 23], "someth": [1, 11, 15], "similar": [1, 5, 10, 15, 22], "seven": 1, "compris": [1, 5], "primari": [1, 22], "tabl": 1, "idea": [1, 3, 10], "group": 1, "togeth": [1, 9, 11], "high": [1, 8, 11, 12, 13], "traffic": 1, "content": [1, 9, 10, 20, 22], "time": [1, 3, 4, 5, 7, 8, 10, 12, 13, 14, 15, 18, 19, 22, 23], "screenshot": [1, 7, 14, 15, 22], "wa": [1, 2, 3, 4, 8, 10, 11, 12, 15, 20, 22, 23], "taken": [1, 3, 5, 10, 14, 22], "regist": [1, 2, 10, 11, 12, 22], "chang": [1, 4, 5, 7, 9, 11, 15, 20, 22, 23], "pend": [1, 2, 3], "reg_chang": 1, "more": [1, 2, 3, 8, 9, 11, 15, 17], "futur": 1, "note": [1, 2, 8, 10, 12, 14, 15, 20, 22, 23], "our": 1, "overdu": 1, "speed": [1, 5, 9, 10, 11, 15], "reason": [1, 5, 8, 10, 14, 22], "sometim": [1, 10], "skip": [1, 5, 10, 11], "updat": [1, 11, 15], "A": [1, 5, 6, 13, 15, 20, 22], "ly": 1, "past": [1, 12], "mean": [1, 3, 4, 7, 8, 9, 10, 11, 12, 15, 22, 23], "match": [1, 6, 11, 12, 14, 15, 22], "valu": [1, 3, 4, 5, 11, 12, 14, 15, 22], "clock": [1, 3, 10, 11, 12], "due": [1, 10, 12, 14, 20], "immedi": [1, 11, 14], "cia": [1, 11], "b": 1, "control": [1, 3, 6, 7, 9, 10, 13, 15, 19, 20, 21], "own": [1, 12, 23], "both": [1, 2, 4, 5, 6, 7, 9, 10, 11, 12, 15, 22], "cia_wakeup": 1, "inact": 1, "moment": 1, "grai": [1, 22, 23], "out": [1, 3, 5, 15, 22, 23], "disabl": [1, 11, 12, 15], "get": [1, 2, 15, 19, 22, 24], "correspond": [1, 2, 4, 7, 11, 15, 16, 21, 22], "bitplan": [1, 22], "manag": [1, 14, 15, 22], "shown": [1, 7, 13, 22], "abov": [1, 2, 4, 5, 7, 10, 14, 23], "bpl_l3": 1, "61": 1, "3d": 1, "current": [1, 3, 4, 5, 7, 9, 10, 12, 15, 20, 22, 23], "scanlin": 1, "familiar": [1, 22], "found": [1, 14], "manuel": 1, "easili": [1, 10, 12, 15, 23], "understand": 1, "fetch": 1, "surround": [1, 3, 9, 10], "red": [1, 7, 15, 22], "box": 1, "disk": [1, 5, 9, 10, 11, 13, 20], "audio": [1, 5, 16, 22], "sprite": [1, 10, 22], "special": [1, 3, 5, 10, 11, 17, 18, 22], "must": [1, 5, 7, 9, 10, 11, 14, 15, 20], "carri": [1, 3, 5], "posit": [1, 2, 15], "das_tick": 1, "24": [1, 10, 11, 12], "bit": [1, 2, 3, 4, 10, 11, 12, 15], "counter": [1, 3, 10, 11], "increment": [1, 3, 11], "keep": [1, 2, 4, 5, 10, 20, 23], "track": [1, 5, 11, 17], "These": [1, 5, 10, 11, 15], "respect": [1, 10, 22], "wake": [1, 5, 15], "implement": [1, 2, 3, 4, 5, 12], "wait": [1, 3, 5, 7, 15], "instruct": [1, 3, 5, 10, 11, 22], "noth": [1, 3], "next": [1, 3, 10, 11, 14, 15, 20, 22, 23], "secondari": 1, "last": [1, 11, 22], "util": [1, 2, 5, 10, 15, 20, 22], "indic": [1, 7], "whether": [1, 4, 6, 18, 20], "proce": [1, 22], "check": [1, 3, 4, 5, 7, 11, 14, 19], "To": [1, 4, 5, 7, 8, 9, 11, 14, 15, 21, 22, 23], "how": [1, 2, 3, 4, 7, 9, 12, 15, 20, 23], "work": [1, 2, 3, 7, 10, 11, 12, 14, 15, 19, 22, 23], "return": [1, 2, 3, 5, 7, 12], "divid": [1, 12, 15], "tertiari": 1, "we": [1, 2, 3, 4, 5, 6, 7, 12, 15, 22, 23], "alreadi": [1, 2, 3, 5, 8, 15, 22], "made": [1, 4, 8, 22], "ourselv": 1, "frequent": [1, 5], "occur": [1, 15, 23], "less": [1, 10, 11], "interrupt": [1, 11], "four": [1, 4, 9, 12, 13, 23], "occasion": 1, "insert": [1, 12, 17, 20], "floppi": [1, 9, 20], "accordingli": 1, "onli": [1, 3, 6, 8, 10, 11, 12, 13, 15, 17, 22, 23], "default": [1, 4, 5, 6, 7, 9, 10, 11, 12, 13, 15, 22, 23], "sec_trigg": 1, "sec_slot": 1, "sinc": [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 17, 18, 22, 23], "belong": [1, 10], "too": [1, 4, 6, 15, 18, 23], "alwai": [1, 2, 3, 4, 10, 11, 12, 13, 14, 23], "act": [1, 10], "request": [1, 3, 5, 15], "thu": [1, 4, 12, 17, 23], "ensur": [1, 2, 5], "equal": [1, 3, 4, 11], "smallest": 1, "appli": [1, 11, 15, 16, 21, 22], "automat": [1, 10, 18, 19, 22], "ter_trigg": 1, "ter_slot": 1, "server": [1, 7], "daemon": 1, "monitor": 1, "extern": [1, 5, 11, 13, 19], "socket": [1, 7], "Such": [1, 13], "null": [1, 7, 13], "modem": [1, 7, 13], "cabl": [1, 7, 13], "type": [1, 2, 4, 6, 7, 12, 15, 22], "ins_ev": 1, "inspect": 1, "entri": [1, 14], "record": [1, 5, 20, 22], "pass": [1, 2, 17], "gui": [1, 2, 5], "fact": 1, "clarifi": 1, "why": [1, 14], "overal": [1, 3], "introduct": [1, 15], "hierarchi": [1, 24], "significantli": [1, 10, 14], "improv": [1, 10, 12], "prevent": [1, 2, 4], "travers": 1, "entir": [1, 5, 15, 22, 23], "intern": [1, 3, 5, 7, 9, 11, 13, 17, 22], "among": [1, 4, 9, 10], "those": 1, "variant": [1, 10, 12, 14], "scheduleab": 1, "templat": [1, 3], "eventslot": 1, "void": [1, 2, 3, 5], "eventid": 1, "id": 1, "nexttrigg": [1, 3], "constexpr": [1, 3], "istertiaryslot": 1, "slot_ter": 1, "slot_sec": 1, "issecondaryslot": 1, "i64": 1, "data": [1, 4, 7, 10, 11, 12, 17, 20, 22, 23], "requir": [1, 4, 8, 11, 13, 23], "argument": [1, 2], "addit": [1, 4, 5, 7, 10, 22], "specifi": [1, 2, 9], "expect": [1, 7, 14], "second": [1, 2, 5, 7, 10, 12, 14, 15, 20], "deal": 1, "drive": [1, 10, 20, 23], "field": [1, 3, 13, 15, 19], "scheduleimm": 1, "scheduleinc": 1, "schedulerel": 1, "differ": [1, 2, 7, 9, 10, 11, 12, 14, 15, 17, 18, 22], "absolut": 1, "ab": 1, "form": [1, 15, 17], "master": [1, 20, 22], "imm": 1, "inc": 1, "rel": 1, "old": [1, 8, 23], "reschedul": 1, "cancel": 1, "select": [1, 5, 6, 7, 9, 10, 12, 13, 14, 15, 20, 21, 22, 23], "remain": [1, 5, 15, 20], "unchang": [1, 15], "done": [1, 2, 12], "0": [1, 2, 3, 9, 11, 12], "never": [1, 2, 3, 5, 10, 13, 22], "crucial": [1, 8], "statement": [1, 3, 4], "here": [1, 22], "assign": [1, 6, 19], "preprocessor": 1, "constant": 1, "stamp": 1, "int64_max": 1, "being": [1, 2, 10, 11, 12, 20], "sai": [1, 3], "simpli": [1, 2, 3, 9, 14, 15, 23], "preserv": [1, 20, 22], "consecut": 1, "treat": 1, "unit": [1, 10], "convert": [1, 2, 4], "sever": [1, 3, 5, 9, 12, 16, 18, 22], "convers": [1, 9], "macro": [1, 3, 4, 5], "cpu_cycl": 1, "2": [1, 3, 4, 5, 9, 10, 11, 19], "cia_cycl": 1, "40": 1, "dma_cycl": [1, 3], "3": [1, 3, 5, 13, 14, 19], "given": 1, "scale": 1, "reconvers": 1, "possibl": [1, 4, 5, 8, 9, 15, 22], "as_cpu_cycl": 1, "as_cia_cycl": 1, "as_dma_cycl": 1, "enum": 1, "enum_i8": 1, "event_non": 1, "reg": [1, 3], "1": [1, 2, 3, 4, 9, 11, 12, 14, 19, 22], "reg_event_count": 1, "cia_execut": 1, "cia_event_count": 1, "reus": 1, "across": 1, "congratul": 1, "through": [1, 7, 12, 22, 23], "good": [1, 19], "commun": [2, 7, 23], "graphic": [2, 5, 8, 10, 15, 22], "user": [2, 4, 5, 7, 8, 10, 12, 13, 15, 18, 19, 20], "interfac": [2, 5, 7, 8, 11, 24], "send": [2, 11], "command": [2, 7, 22, 24], "core": [2, 3, 8], "sophist": [2, 15], "msgqueue": 2, "class": [2, 3, 24], "ring": 2, "buffer": [2, 5, 9, 15], "public": [2, 8], "ringbuff": 2, "512": [2, 10, 12, 14], "support": [2, 4, 7, 10, 11, 12, 13, 15, 18, 23, 24], "method": [2, 5, 9, 15, 17], "bool": [2, 5], "msg": 2, "read": [2, 3, 11, 17, 22], "least": [2, 3], "true": [2, 5, 6], "oldest": 2, "copi": [2, 11, 17, 23], "over": [2, 3, 10, 11, 12, 22, 23], "fals": [2, 11], "net": 2, "web": 2, "port": [2, 7, 8], "webassembli": [2, 8], "javascript": 2, "export": [2, 17, 20], "doanimationfram": 2, "while": [2, 3, 5, 6, 10, 11, 12, 15, 23], "readmessag": 2, "break": [2, 3, 5], "proxi": 2, "processmsg": 2, "small": [2, 7, 14, 15, 22], "wrapper": [2, 3, 5], "around": [2, 3, 4, 5, 7], "amigaproxi": 2, "On": [2, 11, 15, 23], "That": [2, 5, 11], "within": [2, 3, 5], "itself": [2, 5, 12, 13, 15], "howev": [2, 4, 6, 10, 11, 12, 13, 14, 15, 17, 20, 22], "subject": 2, "potenti": 2, "loss": 2, "doe": [2, 3, 5, 9, 10, 12, 14, 15, 17, 22], "overflow": 2, "result": [2, 4, 9, 10, 12, 15], "lost": [2, 10], "drawback": 2, "solv": [2, 15], "subscript": 2, "discuss": 2, "below": [2, 7, 23], "altern": [2, 18, 23], "callback": 2, "mechan": [2, 5, 10, 11, 13, 22], "mode": [2, 3, 5, 9, 10, 11, 15, 18, 24], "sent": [2, 5], "longer": [2, 5, 15, 22], "instead": [2, 10, 12, 15], "paramet": [2, 15, 20], "launch": [2, 5, 7, 10, 23], "earlier": [2, 23], "const": [2, 5], "listen": [2, 7], "func": 2, "alia": 2, "typedef": [2, 4, 5], "invok": 2, "raw": 2, "pointer": [2, 11, 18], "mac": [2, 6, 15, 22, 23], "version": [2, 3, 4, 5, 10, 12, 20, 22, 23], "headless": 2, "latter": [2, 4, 9], "mainli": [2, 10, 12, 13], "test": [2, 5, 10, 13, 19, 22, 23], "integr": [2, 4, 11], "nightli": 2, "build": 2, "creat": [2, 5, 6, 9, 15, 17, 20, 22], "stack": [2, 15], "happen": [2, 3, 11, 12, 15], "int": [2, 3], "argc": 2, "char": 2, "argv": 2, "global": 2, "fairli": 2, "straightforward": [2, 5], "back": [2, 8, 10, 13, 15, 19, 23], "correct": [2, 3, 15, 19], "switch": [2, 5, 7, 19, 22], "case": [2, 3, 4, 5, 9, 10, 11, 12, 14, 15, 22, 23], "msg_script_don": 2, "advantag": [2, 4], "caus": [2, 4, 10, 11, 12], "problem": [2, 6, 15, 23], "mani": [2, 8, 10, 11, 12, 13, 17, 22, 23], "assum": [2, 3], "thei": [2, 5, 6, 8, 10, 11, 12, 23], "incom": 2, "befor": [2, 3, 11, 12, 20], "relev": [2, 4], "mycontrol": 2, "part": [2, 11, 14], "swift": 2, "ui": 2, "self": 2, "myself": [2, 13], "unsaferawpoint": 2, "unmanag": 2, "passunretain": 2, "toopaqu": 2, "ptr": 2, "fromopaqu": 2, "takeunretainedvalu": 2, "dispatchqueu": 2, "async": 2, "processmessag": 2, "calcul": [3, 15], "frame": [3, 4, 5, 10, 15], "ve": [3, 10, 23], "studi": 3, "know": 3, "puls": [3, 5], "thread_puls": [3, 5], "loadclock": 3, "go": 3, "stop": [3, 5], "measur": 3, "load": [3, 7, 10, 17], "take": [3, 4, 5, 9, 11, 12, 20, 23], "place": [3, 6, 9, 10, 12, 14, 22], "declar": 3, "pure": [3, 17], "flag": 3, "synchron": [3, 5, 11, 15], "rl": 3, "sync_thread": 3, "clearflag": 3, "enter": [3, 5, 10], "infinit": [3, 11], "quit": [3, 5, 6, 7, 10, 22], "ask": [3, 15], "after": [3, 5, 7, 10, 11, 14, 15, 19, 22, 23], "variabl": [3, 5, 22], "whose": [3, 5, 22], "give": [3, 9, 22], "kind": 3, "talk": 3, "namespac": 3, "u32": [3, 4], "softstop_reach": 3, "breakpoint_reach": 3, "watchpoint_reach": 3, "catchpoint_reach": 3, "4": [3, 5, 9, 19], "swtrap_reach": 3, "5": [3, 13], "copperbp_reach": 3, "6": 3, "copperwp_reach": 3, "7": 3, "auto_snapshot": 3, "8": 3, "user_snapshot": 3, "9": 3, "10": [3, 10], "zero": [3, 9, 12, 15], "But": 3, "didn": 3, "t": [3, 11, 12, 14, 22, 23], "answer": 3, "ye": 3, "where": [3, 11, 12, 14, 15, 22], "come": [3, 4, 5, 19, 22], "plai": [3, 13], "eofhandl": 3, "setflag": 3, "acronym": 3, "eof": 3, "end": 3, "onc": [3, 23], "termin": [3, 5], "pretti": 3, "isn": [3, 12], "sort": 3, "sky": 3, "clear": [3, 5], "closer": [3, 4, 5], "bra": 3, "start": [3, 5, 10, 12, 14, 22, 24], "begin": 3, "instr": 3, "m": [3, 17], "size": [3, 4, 10, 14, 15], "moira": [3, 8], "execbra": 3, "u16": 3, "opcod": 3, "long": [3, 5, 20, 22], "c68020": 3, "c68000": 3, "oldpc": 3, "pc": 3, "disp": 3, "byte": [3, 14, 17], "u8": 3, "queue": [3, 24], "irc": 3, "sync": [3, 11, 15], "expand": [3, 12], "m68000": [3, 10], "m68010": [3, 10], "signal": [3, 5, 11, 15], "advanc": [3, 4, 10], "particular": 3, "elaps": 3, "unclutt": 3, "cpu_as_dma_cycl": 3, "assur": 3, "date": [3, 14], "write": [3, 4, 11, 17, 19], "oper": [3, 5, 6, 10, 11, 14, 15, 22], "proper": [3, 10], "head": [3, 9, 11], "actual": [3, 4], "conveni": [3, 18, 23], "dmacycl": 3, "dig": 3, "littl": [3, 4, 8, 12], "deeper": 3, "horizont": [3, 4, 15], "po": 3, "h": [3, 4, 6], "event": [3, 20, 24], "color": [3, 10, 12, 15], "present": [3, 12, 13, 18, 23], "schedul": [3, 5, 24], "undoubtedli": 3, "consid": [3, 10], "central": [3, 11], "everyth": [3, 4, 7], "built": [3, 13, 18], "pleas": [3, 7, 8, 10, 12, 14, 15, 20, 22, 23], "despit": [3, 23], "role": 3, "directli": [3, 6, 10, 11, 12, 14, 22], "indirectli": 3, "great": [3, 8, 23], "detail": [3, 8, 10], "outlin": 4, "featur": [4, 10, 20, 22], "ec": [4, 10, 12], "chipset": [4, 16], "500": [4, 8, 9, 10, 11, 12], "pixel": [4, 15, 22], "displai": [4, 7, 14, 15, 22], "rate": [4, 9, 11, 15], "35": 4, "n": [4, 19], "twice": [4, 10, 13, 15], "resolut": [4, 15], "hire": [4, 10, 15], "lore": [4, 15], "The": [4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], "design": [4, 15, 20, 22], "goal": [4, 22], "customiz": 4, "textur": [4, 15, 22], "earli": [4, 10], "gener": [4, 8, 9, 10, 11, 15, 21], "gpu": [4, 15], "side": [4, 7, 9, 22], "texel": 4, "term": [4, 8, 10, 20, 22], "mixtur": 4, "word": [4, 11], "commonli": [4, 10, 11, 22], "doubl": [4, 13, 15], "had": [4, 5, 11, 12, 13, 15], "decid": [4, 11, 14, 22], "should": [4, 7, 12, 20], "conclus": 4, "better": [4, 9], "suit": [4, 22], "backend": [4, 15, 20], "higher": [4, 23], "low": 4, "impact": 4, "rare": [4, 11, 12], "vast": 4, "major": [4, 22], "hit": 4, "ad": [4, 5, 10, 12, 14, 17, 20, 23], "kept": [4, 5], "No": [4, 12, 13], "clutter": 4, "One": [4, 19], "strength": 4, "clean": 4, "my": [4, 8, 10, 19], "exist": 4, "want": [4, 6, 22, 23], "avoid": [4, 5, 15], "armada": 4, "format": [4, 20, 22, 23, 24], "fulfil": 4, "option": [4, 6, 7, 9, 10, 11, 12, 13, 15, 16, 18, 20, 21, 22], "tpp": 4, "abbrevi": 4, "stand": 4, "per": [4, 5, 11, 13, 15], "imag": [4, 5, 10, 14, 15, 17, 23], "illustr": 4, "effect": [4, 9, 11, 12], "draw": [4, 10], "line": [4, 11, 15], "map": [4, 12, 14, 15, 18, 24], "coars": 4, "interpol": [4, 9], "u": [4, 10, 15, 22], "revisit": 4, "mention": [4, 12, 14], "achiev": [4, 22, 23], "compil": 4, "fragment": [4, 5, 15], "locat": [4, 6, 12, 23], "framebuffertyp": 4, "file": [4, 14, 20, 22, 23, 24], "address": [4, 10, 12, 14], "element": [4, 22], "els": [4, 5], "u64": 4, "endif": 4, "affect": [4, 15, 22], "underli": 4, "unsign": 4, "32": [4, 10], "integ": 4, "rgba": 4, "definit": 4, "reveal": [4, 22], "trick": 4, "penalti": 4, "direct": [4, 22], "repeat": [4, 15], "pattern": [4, 12, 15, 22], "64": [4, 12], "row": 4, "becaus": [4, 5, 6, 10, 11, 12, 13, 15, 22], "fast": [4, 11, 12, 22], "Of": 4, "cours": 4, "pai": [4, 8], "price": [4, 12, 13], "move": [4, 11, 12, 15, 18, 22], "much": [4, 8, 10, 13, 17, 23], "hide": [4, 6, 8], "qualiti": [4, 8, 9], "degrad": 4, "appear": [4, 7, 14, 15, 22, 23], "independ": [4, 15, 22], "count": 4, "amount": [4, 12], "add": [5, 10, 14, 15, 22], "concurr": 5, "capabl": [5, 10, 12, 13], "step": [5, 7, 9, 22], "spawn": 5, "std": 5, "aliv": [5, 10], "until": 5, "applic": [5, 6, 10, 23], "consist": [5, 15], "loopcount": 5, "isrun": 5, "getthreadmod": 5, "thread_period": 5, "thread_adapt": 5, "warpmod": 5, "sleep": [5, 15], "statechangerequest": 5, "switchstat": 5, "newstat": 5, "notify_on": 5, "exec_halt": 5, "dure": [5, 10, 12], "lifetim": 5, "bodi": 5, "depend": 5, "warp": [5, 10], "again": [5, 15, 23], "right": [5, 6, 9, 10, 18, 22, 23], "pace": [5, 12], "50": [5, 15], "pal": [5, 15], "60": [5, 15], "ntsc": [5, 15], "period": 5, "adapt": [5, 11], "enum_long": 5, "thread_mod": 5, "threadmod": 5, "put": [5, 12, 15], "timer": [5, 10, 15], "wakeup": 5, "further": 5, "receiv": [5, 11], "comput": [5, 7, 8, 9, 10, 12, 13, 15, 17, 20, 22], "vsync": [5, 15], "miss": 5, "lauchen": 5, "Then": 5, "resynchron": 5, "introduc": [5, 10], "becom": [5, 9], "new": [5, 7, 20, 22, 23], "overrid": 5, "exec_run": 5, "hold": [5, 6], "exec_off": 5, "turn": [5, 10, 23], "exec_paus": 5, "job": 5, "exec_suspend": 5, "short": [5, 22], "shut": 5, "down": [5, 11, 15, 22], "visual": [5, 22], "represent": [5, 17], "By": [5, 6, 7, 8, 9, 11, 12, 13, 15], "poweron": 5, "press": [5, 7, 11, 22], "button": [5, 18, 22, 23], "toolbar": [5, 7, 16, 21], "bring": [5, 8], "life": 5, "suspend": 5, "resum": [5, 22], "atom": 5, "cannot": [5, 8, 12, 20, 22, 23], "could": [5, 12], "disrupt": 5, "servic": 5, "playback": 5, "exit": [5, 20], "critic": 5, "section": [5, 9, 18, 22], "safe": [5, 22], "embed": [5, 15], "them": [5, 8, 9, 10, 13, 22], "nest": 5, "multipl": [5, 11, 12], "essenti": [5, 14], "consequ": 5, "middl": [5, 18, 22], "throw": 5, "except": [5, 22], "often": 5, "keyword": 5, "With": [5, 9, 15, 19, 22, 23], "snippet": 5, "rewritten": 5, "feel": [5, 15], "free": [5, 6, 12, 23], "handl": 5, "seen": 5, "neither": 5, "activ": [5, 7, 12, 15, 18, 22], "debugg": [5, 7, 22], "deactiv": 5, "close": [5, 12, 20], "consum": [5, 10], "task": 5, "normal": [5, 9, 15, 22], "inform": [5, 7, 14, 15, 17, 22], "trace": 5, "poweroff": 5, "halt": 5, "atomic_flag": 5, "iter": 5, "necessari": [5, 7, 11], "nativ": [6, 10, 11, 15, 22, 23], "keyboard": [6, 13], "perfect": [6, 22], "your": [6, 7, 13, 14, 20, 22, 23], "modern": [6, 15, 23], "natur": 6, "maco": [6, 8, 23], "link": [6, 10, 22], "system": [6, 8, 14, 15, 22], "grant": [6, 22], "lose": 6, "standard": [6, 11, 17], "combin": [6, 12, 18, 19, 22], "cmd": [6, 18, 22], "window": [6, 7, 15, 18, 20, 22, 23], "q": 6, "menu": [6, 7, 13, 14, 15, 16, 21, 22, 23], "choos": [6, 7, 9, 10, 12, 14, 15, 18, 19], "left": [6, 9, 14, 18, 22, 23], "feasibl": 6, "trade": [6, 9], "o": 6, "unmap": [6, 12], "still": [6, 9, 14], "shortcut": 6, "allow": [7, 8, 11, 12, 15, 17, 18, 19, 20, 22], "multiplay": 7, "game": [7, 10, 11, 15, 20], "articl": 7, "walk": 7, "battl": [7, 13], "chess": [7, 13], "peripher": [7, 10, 16], "popup": [7, 13, 14, 22, 23], "agre": 7, "8080": 7, "icon": [7, 16, 21, 22, 23], "statu": 7, "bar": 7, "shape": 7, "player": 7, "board": [7, 10, 12], "blue": [7, 15], "armi": 7, "soldier": 7, "ones": [7, 12, 22], "chill": 7, "fun": [7, 23], "fight": [7, 13], "exactli": [7, 11, 15], "refus": [7, 12], "retroshel": 7, "shift": [7, 15], "output": [7, 9, 11, 13, 15], "statist": 7, "transfer": [7, 11, 22], "commodor": [8, 10, 11, 12, 14, 19, 23], "1000": [8, 10, 11, 12], "2000": [8, 10, 11, 12], "develop": [8, 23], "begun": 8, "januari": 8, "2019": 8, "progress": 8, "mind": [8, 20, 23], "accuraci": [8, 10, 12], "aim": 8, "origin": [8, 10, 11, 12, 14, 15, 19, 20, 22, 23], "a500": [8, 10, 12], "a1000": [8, 10, 12], "a2000": [8, 10, 12], "tri": [8, 17], "exact": [8, 10, 11], "precis": [8, 10, 11, 15], "usabl": 8, "appeal": 8, "aspect": 8, "retro": [8, 19], "me": 8, "ag": [8, 22, 23], "dai": [8, 10, 13, 15, 19, 23], "technic": 8, "deep": 8, "convict": 8, "level": [8, 11, 15], "spent": 8, "lot": [8, 22], "refactor": 8, "effort": 8, "sourc": [8, 14, 20, 23], "publish": [8, 23], "under": [8, 11], "gnu": 8, "re": 8, "recent": [8, 22], "mit": 8, "broader": 8, "project": 8, "topic": 8, "kickstart": 8, "rom": [8, 16, 22], "ship": [8, 10, 12, 14, 23], "intellectu": [8, 14, 23], "properti": [8, 12, 14, 15, 22, 23], "cloanto": [8, 14, 23], "purchas": [8, 14], "forev": 8, "acquir": 8, "legal": [8, 14, 23], "organ": [9, 16, 21, 22], "channel": [9, 15], "mute": 9, "lower": [9, 10, 13, 14, 15, 19, 23], "pan": 9, "freeli": [9, 14], "distribut": [9, 14], "speaker": 9, "rout": 9, "stereo": 9, "stream": [9, 17, 22], "mix": 9, "sampl": 9, "translat": [9, 23], "suitabl": [9, 19], "host": [9, 17, 22], "between": [9, 12, 18, 22], "timestamp": 9, "fed": 9, "nearest": 9, "closest": 9, "slightli": [9, 11, 15], "slower": 9, "than": [9, 10, 15, 17, 19], "produc": [9, 15], "linear": 9, "linearli": 9, "best": [9, 19], "slowest": 9, "area": [9, 10, 12, 14, 15, 22], "sound": 9, "distinguish": [9, 12, 22], "poll": 9, "click": [9, 16, 21, 22, 23], "detect": [9, 11, 19], "annoi": 9, "especi": [9, 22], "silenc": 9, "reduc": [9, 10, 13], "movement": [9, 11], "audibl": 9, "revis": [10, 14], "16": [10, 12], "cisc": 10, "microprocessor": 10, "motorola": 10, "1979": 10, "classic": 10, "model": [10, 12], "highest": 10, "mc68010": 10, "processor": 10, "releas": [10, 12, 14, 18, 22, 23], "1982": 10, "successor": 10, "68000": 10, "offici": [10, 12], "pin": [10, 13], "compat": [10, 13, 14, 16, 19, 22, 23], "replac": [10, 14, 22, 23], "show": [10, 12, 15, 22, 23], "upgrad": 10, "extens": [10, 12, 22, 23], "gain": 10, "thing": 10, "construct": 10, "redund": 10, "faster": [10, 15], "100": [10, 12], "demo": [10, 11, 12, 17, 22, 23], "68ec020": 10, "m68ec020": 10, "cost": 10, "68020": 10, "1984": 10, "1200": 10, "frequenc": [10, 11, 18], "14mhz": 10, "signific": 10, "m68k": 10, "seri": 10, "cach": 10, "yet": [10, 13], "maximum": 10, "auto": 10, "motor": [10, 11], "even": [10, 11, 12, 15, 23], "transmit": [10, 11, 15], "manual": [10, 14, 15, 19, 20], "were": [10, 12, 17, 22], "extrem": [10, 17], "competit": [10, 19], "without": [10, 11, 20, 23], "histori": 10, "occupi": [10, 13], "todai": [10, 22], "classifi": [10, 14], "oc": [10, 12], "equip": [10, 11, 12, 13, 22], "enhanc": 10, "a600": 10, "later": [10, 12, 22], "pictur": [10, 15], "8372a": 10, "8362r8": 10, "third": [10, 12, 22], "aga": 10, "a1200": 10, "a4000": 10, "probabl": [10, 13], "boss": 10, "abl": [10, 13, 15, 17, 22], "mo": 10, "8367": 10, "usual": [10, 12, 15, 22], "a2000a": [10, 12], "8371": 10, "1mb": 10, "apart": 10, "minor": 10, "space": [10, 12, 17], "kb": [10, 12, 13, 14], "ram": [10, 22], "2mb": 10, "8375": 10, "increas": 10, "rang": [10, 12, 14], "mb": [10, 12], "1991": 10, "1992": 10, "8373r4": 10, "3000": 10, "compar": [10, 12, 14], "predecessor": [10, 19], "offer": [10, 11, 13, 17, 18, 19, 22, 23], "border": 10, "blank": 10, "drawn": [10, 15], "black": [10, 19], "background": [10, 12, 15], "nicer": 10, "8520": 10, "devic": [10, 11, 13, 21, 22], "known": [10, 19], "6526": 10, "c64": [10, 19], "subtl": 10, "tod": [10, 11], "suppli": 10, "dip": 10, "plcc": 10, "600": 10, "cumbersom": 10, "trapdoor": [10, 12], "expans": [10, 12, 14], "card": [10, 12], "recogn": [10, 14, 23], "batteri": 10, "solder": 10, "hindsight": 10, "bad": [10, 12], "death": 10, "bringer": 10, "belov": [10, 23], "damag": 10, "acid": 10, "leak": 10, "none": [10, 15], "oki": 10, "msm6242b": 10, "manufactur": 10, "semiconductor": 10, "ricoh": 10, "rf5c01a": 10, "ltd": 10, "a3000": 10, "fastest": 11, "chunk": [11, 12], "bltsize": 11, "although": [11, 22], "far": 11, "accur": [11, 12], "afterward": 11, "recommend": [11, 14, 19, 23], "scenario": 11, "bug": 11, "exhibit": 11, "circuitri": 11, "alarm": 11, "lowest": 11, "nibbl": 11, "finish": 11, "drop": [11, 14, 15, 17, 23], "circumst": 11, "condit": 11, "abort": 11, "complex": 11, "tenth": 11, "slow": [11, 12, 22], "program": [11, 12, 14, 22], "cell": 11, "turbo": 11, "scan": 11, "acceler": [11, 12], "factor": 11, "slot": [11, 12, 13, 22], "obvious": 11, "dsklen": 11, "issu": [11, 14], "stringent": 11, "deceler": 11, "phase": 11, "cylind": 11, "piraci": 11, "help": [11, 19, 22], "bypass": 11, "protect": [11, 17, 23], "ignor": 11, "dsksync": 11, "lock": [11, 23], "attempt": 11, "mark": [11, 22], "collis": 11, "circuiti": 11, "expens": [11, 12, 15], "few": [11, 12, 18], "titl": [11, 17, 23], "archon": 11, "rotor": 11, "kei": [11, 20, 22, 24], "input": [11, 13, 22], "aesthet": 11, "though": [11, 12, 23], "soon": [11, 22], "transmiss": 11, "tell": [11, 12], "keycod": 11, "random": 12, "factori": 12, "instal": [12, 14, 20], "flexibl": [12, 15], "limit": [12, 23], "256": 12, "modul": 12, "plug": [12, 19], "front": 12, "straight": 12, "did": [12, 15], "ranger": 12, "bottom": 12, "somewhat": 12, "reput": 12, "disadvantag": [12, 15, 20], "world": 12, "name": [12, 14], "stem": 12, "themselv": 12, "bank": 12, "think": 12, "determin": [12, 15, 20], "mirror": 12, "000000": 12, "c00000": 12, "programm": 12, "unfortun": [12, 14], "a2000b": 12, "rtc": 12, "d8": 12, "dc": 12, "relat": 12, "df": 12, "older": [12, 23], "init": 12, "startup": [12, 17], "besid": [12, 15, 18], "leav": [12, 13, 23], "float": 12, "advic": 12, "welcom": 12, "interest": 12, "page": [12, 23], "segment": 12, "full": 12, "mountain": 12, "lazi": 12, "bone": 12, "reli": 12, "polari": 12, "parti": 12, "1993": [12, 23], "incompat": 12, "behavior": [12, 20], "remov": [12, 22], "restrict": 12, "occas": 12, "deviat": 12, "label": 13, "df0": [13, 23], "df1": 13, "df3": [13, 23], "densiti": 13, "storag": [13, 22], "capac": 13, "880": 13, "25": [13, 15], "440": 13, "thank": [13, 23], "michael": 13, "rasmussen": 13, "zorro": 13, "ii": 13, "identifi": 13, "autoconfig": 13, "boot": [13, 17, 23], "joystick": [13, 19, 22], "mice": [13, 18], "mous": [13, 22], "gamepad": [13, 19, 22], "attach": 13, "nice": 13, "loopback": 13, "kit": 13, "drag": [14, 17, 18, 23], "upper": 14, "zone": [14, 23], "stage": [14, 15], "magic": [14, 19], "verifi": 14, "sequenc": [14, 17], "unknown": 14, "reject": 14, "otherwis": 14, "continu": 14, "crc": 14, "checksum": 14, "databas": 14, "along": 14, "guarante": 14, "fee": 14, "don": [14, 22, 23], "hand": 14, "aro": [14, 23], "research": 14, "redistribut": 14, "dropdown": 14, "corner": [14, 23], "strongli": 14, "bui": 14, "resort": 14, "notic": 14, "exce": 14, "split": 14, "e00000": 14, "e7ffff": 14, "unlik": [14, 20], "resid": [14, 22], "e0000": 14, "f00000": 14, "f7ffff": 14, "sub": 15, "screen": [15, 23], "fine": 15, "tune": 15, "shader": 15, "pipelin": 15, "try": [15, 19], "mimic": 15, "crt": 15, "monochrom": 15, "amber": 15, "green": 15, "bright": 15, "contrast": 15, "sepia": 15, "vertic": 15, "axi": [15, 19], "predefin": [15, 18], "dimens": 15, "imposs": 15, "arbitrari": 15, "workaround": 15, "pitfal": 15, "tft": 15, "60hz": 15, "promot": 15, "technologi": 15, "hz": 15, "manipul": 15, "tradit": 15, "algorithm": 15, "epx": 15, "xbr": 15, "desir": 15, "superimpos": 15, "darken": 15, "moir\u00e9": 15, "height": 15, "adjust": [15, 18, 19], "uniqu": 15, "item": [15, 22], "late": 15, "final": 15, "dot": [15, 22], "mask": 15, "compos": 15, "flicker": 15, "odd": 15, "30": 15, "stabl": 15, "abil": 15, "interlac": 15, "human": 15, "ey": 15, "intens": 15, "fixer": 15, "popular": [15, 17, 23], "albeit": 15, "product": 15, "smooth": 15, "gaussian": 15, "filter": 15, "dark": 15, "white": 15, "light": 15, "spread": 15, "glow": 15, "reproduc": 15, "tube": 15, "electron": 15, "beam": 15, "phosphor": 15, "layer": [15, 22], "align": 15, "top": [15, 22], "crisp": 15, "misalign": 15, "artifact": 15, "against": [15, 23], "vari": 15, "dialog": [16, 23], "opend": 16, "video": [16, 20, 22], "adf": [17, 20, 23], "dump": 17, "sector": 17, "diskett": 17, "header": 17, "wide": 17, "non": 17, "extend": 17, "complic": 17, "uninterpret": 17, "mfm": 17, "whole": 17, "dm": 17, "digit": [17, 23], "scene": [17, 22], "encod": 17, "ex": 17, "fly": 17, "bootabl": [17, 23], "img": 17, "sens": 17, "folder": [17, 23], "directori": 17, "suffici": 17, "hdf": 17, "equival": [17, 22], "retain": 18, "convent": 18, "alt": 18, "ctrl": [18, 22], "shake": 18, "detector": 18, "rapidli": 18, "push": [18, 22], "multi": 18, "shot": 18, "fire": 18, "constantli": 18, "vollei": 18, "bullet": 18, "handi": 18, "solut": 18, "physic": 18, "appl": 18, "chanc": 19, "At": [19, 23], "pro": 19, "sl": 19, "650212": 19, "6602": 19, "nimbu": 19, "innext": 19, "sne": 19, "mayflash": 19, "xbox": 19, "carbon": 19, "wire": 19, "soni": 19, "dualshock": 19, "2nd": 19, "gen": 19, "dualsens": 19, "horipad": 19, "nintendo": 19, "ajoi": 19, "retrofun": 19, "person": 19, "invest": 19, "latenc": 19, "experi": 19, "opinion": 19, "fullscreen": 20, "categori": 20, "layout": [20, 22], "target": [20, 23], "ffmpeg": 20, "bundl": 20, "licens": 20, "constraint": 20, "regular": 20, "interv": 20, "difficult": [20, 22], "intend": [20, 22], "temporari": 20, "save": [20, 23], "readabl": 20, "esc": 20, "react": 20, "eject": 20, "behav": 20, "unsav": 20, "modifi": 20, "media": 20, "hesit": 20, "untouch": 20, "simultan": [21, 22], "tutori": [22, 23], "review": 22, "might": 22, "hard": 22, "reset": 22, "anyth": 22, "awai": 22, "counterpart": 22, "sheet": 22, "wish": [22, 23], "perman": [22, 23], "disappear": 22, "k": 22, "gameport": 22, "quickli": 22, "touchpad": 22, "differenti": 22, "placehold": 22, "usb": 22, "frozen": 22, "restor": 22, "revert": 22, "browser": 22, "brows": 22, "transpar": 22, "tool": 22, "insight": 22, "retriev": 22, "gatewai": 22, "breakpoint": 22, "watchpoint": 22, "aid": 22, "column": 22, "overlaid": 22, "owner": [22, 23], "rink": [22, 23], "dink": [22, 23], "yellow": 22, "brown": 22, "refresh": 22, "pink": 22, "cyan": 22, "creator": 22, "polygon": 22, "reloc": 22, "youtub": 22, "watch": 22, "forward": 22, "20": 22, "anim": 22, "center": 22, "stencil": 22, "eras": 22, "playfield": 22, "checkerboard": 22, "shine": 22, "hole": 22, "text": 22, "consol": 22, "varieti": 22, "script": 22, "vamigat": 22, "regress": 22, "download": 23, "latest": 23, "deploy": 23, "12": 23, "monterei": 23, "app": 23, "room": 23, "extract": 23, "repositori": 23, "greet": 23, "readi": 23, "inaccess": 23, "accident": 23, "dilig": 23, "enthusiast": 23, "decai": 23, "internet": 23, "countless": 23, "copyright": 23, "permiss": 23, "holder": 23, "onto": 23, "shortli": 23, "lemon": 23, "flawlessli": 23, "explor": 24, "superhir": 24}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"The": [0, 1, 2, 3, 5], "class": [0, 5], "hierarchi": 0, "event": 1, "schedul": 1, "slot": 1, "messag": 2, "queue": 2, "poll": 2, "subscrib": 2, "run": 3, "loop": 3, "superhir": 4, "mode": [4, 20], "thread": 5, "main": 5, "function": 5, "state": 5, "model": 5, "map": 6, "command": 6, "kei": [6, 18], "connect": 7, "two": 7, "amiga": 7, "troubleshoot": 7, "about": 8, "design": 8, "goal": 8, "licens": 8, "audio": 9, "panel": [9, 10, 11, 12, 13, 14, 15, 18, 19, 20, 22], "In": 9, "out": 9, "drive": [9, 11, 13, 17], "volum": 9, "locat": 9, "chipset": [10, 11, 12], "cpu": 10, "agnu": 10, "denis": 10, "cia": 10, "rtc": 10, "compat": 11, "blitter": 11, "accuraci": 11, "featur": [11, 12], "time": 11, "floppi": [11, 13, 17, 23], "sprite": 11, "keyboard": [11, 22], "memori": 12, "ram": 12, "layout": 12, "peripher": 13, "hard": [13, 17], "game": [13, 22], "port": [13, 22], "serial": 13, "rom": [14, 23], "kickstart": [14, 23], "extens": 14, "video": 15, "monitor": [15, 22], "palett": 15, "zoom": 15, "center": 15, "refresh": 15, "effect": 15, "upscal": 15, "scanlin": 15, "blur": 15, "bloom": 15, "rai": 15, "virtual": 16, "machin": 16, "set": [16, 21], "support": [17, 19], "file": 17, "format": 17, "disk": [17, 23], "control": [18, 22], "mous": 18, "joystick": 18, "emul": [18, 21], "devic": 19, "usb": 19, "adapt": 19, "gener": 20, "screenshot": 20, "screen": 20, "captur": 20, "snapshot": [20, 22], "full": 20, "miscellan": 20, "explor": 22, "user": [22, 24], "interfac": 22, "toolbar": 22, "prefer": 22, "inspector": 22, "retro": 22, "shell": 22, "get": 23, "start": 23, "instal": 23, "vamiga": [23, 24], "insert": 23, "": 24, "manual": 24, "overview": 24, "tutori": 24, "how": 24, "guid": 24, "refer": 24, "develop": 24, "corner": 24}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 57}, "alltitles": {"The Class Hierarchy": [[0, "the-class-hierarchy"]], "The Event Scheduler": [[1, "the-event-scheduler"]], "Event slots": [[1, "event-slots"]], "Scheduling events": [[1, "scheduling-events"]], "The Message Queue": [[2, "the-message-queue"]], "Polling the message queue": [[2, "polling-the-message-queue"]], "Subscribing to the message queue": [[2, "subscribing-to-the-message-queue"]], "The Run Loop": [[3, "the-run-loop"]], "SuperHires mode": [[4, "superhires-mode"]], "The Thread Class": [[5, "the-thread-class"]], "Main function": [[5, "main-function"]], "State model": [[5, "state-model"]], "Mapping the Command keys": [[6, "mapping-the-command-keys"]], "Connecting Two Amigas": [[7, "connecting-two-amigas"]], "Troubleshooting": [[7, "troubleshooting"]], "About": [[8, "about"]], "Design goals": [[8, "design-goals"]], "Licensing": [[8, "licensing"]], "Audio Panel": [[9, "audio-panel"]], "Audio In": [[9, "audio-in"]], "Audio Out": [[9, "audio-out"]], "Drive volumes": [[9, "drive-volumes"]], "Drive locations": [[9, "drive-locations"]], "Chipset Panel": [[10, "chipset-panel"]], "CPU": [[10, "cpu"]], "Agnus": [[10, "agnus"]], "Denise": [[10, "denise"]], "CIAs": [[10, "cias"]], "RTC": [[10, "rtc"]], "Compatibility Panel": [[11, "compatibility-panel"]], "Blitter accuracy": [[11, "blitter-accuracy"]], "Chipset Features": [[11, "chipset-features"]], "Timing": [[11, "timing"]], "Floppy drives": [[11, "floppy-drives"]], "Sprites": [[11, "sprites"]], "Keyboard": [[11, "keyboard"], [22, "keyboard"]], "Memory Panel": [[12, "memory-panel"]], "Ram": [[12, "ram"]], "Memory layout": [[12, "memory-layout"]], "Chipset features": [[12, "chipset-features"]], "Peripherals Panel": [[13, "peripherals-panel"]], "Floppy Drives": [[13, "floppy-drives"]], "Hard Drives": [[13, "hard-drives"]], "Game Ports": [[13, "game-ports"], [22, "game-ports"]], "Serial Port": [[13, "serial-port"]], "ROM Panel": [[14, "rom-panel"]], "Kickstart ROM": [[14, "kickstart-rom"]], "Extension ROM": [[14, "extension-rom"]], "Video Panel": [[15, "video-panel"]], "Monitor": [[15, "monitor"]], "Palette": [[15, "palette"]], "Zoom": [[15, "zoom"]], "Center": [[15, "center"]], "Refresh": [[15, "refresh"]], "Effects": [[15, "effects"]], "Upscaling": [[15, "upscaling"]], "Scanlines": [[15, "scanlines"]], "Blur": [[15, "blur"]], "Bloom": [[15, "bloom"]], "Rays": [[15, "rays"]], "Virtual Machine Settings": [[16, "virtual-machine-settings"], [16, null]], "Supported File Formats": [[17, "supported-file-formats"]], "Floppy disks": [[17, "floppy-disks"]], "Hard drives": [[17, "hard-drives"]], "Controls Panel": [[18, "controls-panel"]], "Mouse": [[18, "mouse"]], "Joysticks": [[18, "joysticks"]], "Emulation keys": [[18, "emulation-keys"]], "Devices Panel": [[19, "devices-panel"]], "Supported devices": [[19, "supported-devices"]], "Supported USB adapters": [[19, "supported-usb-adapters"]], "General Panel": [[20, "general-panel"]], "Screenshots": [[20, "screenshots"]], "Screen captures": [[20, "screen-captures"]], "Snapshots": [[20, "snapshots"], [22, "snapshots"]], "Full screen mode": [[20, "full-screen-mode"]], "Miscellaneous": [[20, "miscellaneous"]], "Emulator Settings": [[21, "emulator-settings"], [21, null]], "Exploring the User Interface": [[22, "exploring-the-user-interface"]], "Toolbar": [[22, "toolbar"]], "Controls": [[22, "controls"]], "Preferences": [[22, "preferences"]], "Inspectors": [[22, "inspectors"]], "Inspector Panel": [[22, "inspector-panel"]], "Monitor Panel": [[22, "monitor-panel"]], "Retro Shell": [[22, "retro-shell"]], "Getting Started": [[23, "getting-started"]], "Installing vAmiga": [[23, "installing-vamiga"]], "Installing a Kickstart ROM": [[23, "installing-a-kickstart-rom"]], "Inserting a floppy disk": [[23, "inserting-a-floppy-disk"]], "vAmiga User\u2019s Manual": [[24, "vamiga-user-s-manual"]], "Overview": [[24, null]], "Tutorials": [[24, null]], "How-to guides": [[24, null]], "References": [[24, null]], "Developers Corner": [[24, null]]}, "indexentries": {}}) \ No newline at end of file