From f320e148560661c17528d83321093671be5ef683 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 19 Mar 2022 01:29:33 -0300 Subject: [PATCH] Initial review commit of API documentation --- conf.py | 1 + dev/api/device.rst | 314 ++++++++++++++++++++++++++++++++ dev/api/dma.rst | 76 ++++++++ dev/api/images/deviceconfig.png | Bin 0 -> 17975 bytes dev/api/index.rst | 11 ++ dev/api/io.rst | 133 ++++++++++++++ include.rst | 26 +++ index.rst | 1 + requirements.txt | 1 + 9 files changed, 563 insertions(+) create mode 100644 dev/api/device.rst create mode 100644 dev/api/dma.rst create mode 100644 dev/api/images/deviceconfig.png create mode 100644 dev/api/index.rst create mode 100644 dev/api/io.rst diff --git a/conf.py b/conf.py index f628c57..aaa7589 100644 --- a/conf.py +++ b/conf.py @@ -31,6 +31,7 @@ author = '86Box Project' extensions = [ 'sphinx_rtd_theme', 'sphinx.ext.autosectionlabel', + 'linuxdoc.rstFlatTable' ] autosectionlabel_prefix_document = True master_doc = 'index' diff --git a/dev/api/device.rst b/dev/api/device.rst new file mode 100644 index 0000000..fc8d688 --- /dev/null +++ b/dev/api/device.rst @@ -0,0 +1,314 @@ +.. include:: /include.rst + +Devices +======= + +The **device** is the main unit of emulated components in 86Box. Each device has one or more ``device_t`` structures, which contain metadata about the device itself, several callbacks and an array of user-facing configuration options. Unless otherwise stated, all structures and functions in this page are provided by ``86box/device.h``. + +.. flat-table:: device_t + :header-rows: 1 + :widths: 1 1 999 + + * - :cspan:`1` Member + - Description + + * - :cspan:`1` name + - The device's name, displayed in the user interface. ``"Foo-1234"`` for example. Suffixes like ``"(PCI)"`` are removed at run-time. + + * - :cspan:`1` internal_name + - The device's internal name, used to identify the device in the emulated machine's configuration file. ``"foo1234"`` for example. + + * - :cspan:`1` flags + - One or more bitwise flags to indicate the expansion bus(es) supported by the device, for determining device eligibility on the selected machine: + + * ``DEVICE_ISA``: 8-bit ISA; + * ``DEVICE_AT``: 16-bit ISA; + * ``DEVICE_EISA``: EISA (reserved for future use); + * ``DEVICE_VLB``: VESA Local Bus; + * ``DEVICE_PCI``: 32-bit PCI; + * ``DEVICE_AGP``: AGP 3.3V; + * ``DEVICE_AC97``: AMR or CNR; + * ``DEVICE_PCJR``: IBM PCjr; + * ``DEVICE_PS2``: IBM PS/1 or PS/2; + * ``DEVICE_MCA``: IBM Micro Channel Architecture; + * ``DEVICE_CBUS``: PC-98 C-BUS (reserved for future use); + * ``DEVICE_COM``: serial (reserved for future use); + * ``DEVICE_LPT``: parallel (reserved for future use). + + * - :cspan:`1` local + - 32-bit value which can be read from this structure by the ``init`` callback. + Use this value to tell different subtypes of the same device, for example. + + * - :cspan:`1` init + - Function called whenever this device is initialized, either from starting 86Box or from a hard reset. Can be ``NULL``. Takes the form of: + + ``void *init(const struct device_t *info)`` + + where ``info`` is a pointer to this ``device_t`` structure, and + the return value is an opaque pointer passed to the other callbacks below, usually a :ref:`state structure `. + The opaque pointer will be invalid if this function is ``NULL``. + + * - :cspan:`1` close + - Function called whenever this device is de-initialized, either from closing 86Box or from a hard reset. Can be ``NULL``. Takes the form of: + + ``void close(void *priv)`` + + where ``priv`` is the opaque pointer that was returned by ``init``. + + * - :cspan:`1` reset + - Function called whenever this device undergoes a soft reset. Can be ``NULL``. Takes the form of: + + ``void reset(void *priv)`` + + where ``priv`` is the opaque pointer that was returned by ``init``. + + * - :rspan:`2` + + .. raw:: html + +
union
+ - available + - Function called whenever this device's availability is being checked. Can be ``NULL``. Takes the form of: + + ``int available()`` + + where the return value must be ``1`` if the device is available for selection, or ``0`` if it is unavailable (due to missing ROMs, for example). + The device will always be available if this function is ``NULL``. + + * - poll + - Function called whenever the mouse position is updated. Valid for mouse devices only. Takes the form of: + + ``int poll(int x, int y, int z, int b, void *priv)`` + + where ``x`` and ``y`` are the relative movement coordinates, + ``z`` is the relative wheel coordinate, + ``b`` is the button state (bit 0 / 0x01 set for left button, bit 1 / 0x02 set for right button, bit 3 / 0x04 set for middle button), + ``priv`` is the opaque pointer that was returned by ``init``, and + the return value must be ``0`` if the change was processed or any other value otherwise. + + * - register_pci_slot + - Reserved for future use. + + * - :cspan:`1` speed_changed + - Function called whenever the emulated CPU clock speed is changed. Can be ``NULL``. Timer intervals and anything else sensitive to the CPU clock speed should be updated in this callback. Takes the form of: + + ``void speed_changed(void *priv)`` + + where ``priv`` is the opaque pointer that was returned by ``init``. + + * - :cspan:`1` force_redraw + - Function called whenever the emulated screen has to be fully redrawn. Can be ``NULL``. Only useful for video cards. Takes the form of: + + ``void force_redraw(void *priv)`` + + where ``priv`` is the opaque pointer that was returned by ``init``. + + * - :cspan:`1` config + - Array of device configuration options, or ``NULL`` if no options are available. See :ref:`dev/api/device:Configuration`. + +State structure +--------------- + +Most devices need a place to store their internal state. We discourage the use of global structures, and instead recommend allocating state structures dynamically in the ``init`` callback and freeing them in the ``close`` callback:: + + typedef struct { + uint32_t type; /* example: copied from device_t.local */ + uint8_t regs[256]; /* example: 256*8-bit registers */ + } foo_t; + + static void * + foo_init(const device_t *info) + { + /* Allocate a blank state structure. */ + foo_t *dev = (foo_t *) malloc(sizeof(foo_t)); + memset(dev, 0, sizeof(foo_t)); + + /* Do whatever you want. */ + dev->type = info->local; /* copy device_t.local value */ + + /* Return a pointer to the state structure. */ + return dev; + } + + static void + foo_close(void *priv) + { + /* Get the state structure. */ + foo_t *dev = (foo_t *) priv; + + /* Do whatever you want, then deallocate the state structure. */ + free(dev); + } + + const device_t foo1234_device = { + .name = "Foo-1234", + .internal_name = "foo1234", + .flags = DEVICE_AT, /* 16-bit ISA */ + .local = 1234, + .init = foo_init, + .close = foo_close, + /* ... */ + }; + + const device_t foo4321_device = { + .name = "Foo-4321", + .internal_name = "foo4321", + .flags = DEVICE_PCI, /* 32-bit PCI */ + .local = 4321, /* different device subtype */ + .init = foo_init, + .close = foo_close, + /* ... */ + }; + +Configuration +------------- + +Devices can have any number of user-facing configuration options, usually accessed through the **Configure** button next to the selection box for the device's class. Examples for all option types currently configurable through the user interface are shown in the image below. + +.. image:: images/deviceconfig.png + :align: center + +These options are stored in the emulated machine's configuration file, in a section identified by the device's ``name``: + +.. code-block:: none + + [Foo-1234] + selection = 0 + hex16 = 0220 + hex20 = D8000 + fname = D:/VMs/86Box/86Box.exe + binary = 1 + spinner = 1234 + midi_out = 0 + midi_in = 0 + + +Configuration options can be specified in the ``config`` member of ``device_t``, as a pointer to a ``const`` array of ``device_config_t`` objects terminated by an object of ``type`` ``-1``. + +.. flat-table:: device_config_t + :header-rows: 1 + :widths: 1 999 + + * - Member + - Description + + * - name + - Internal name for this option, used in the emulated machine's configuration file. + + * - description + - Description for this option, displayed in the user interface. + + * - type + - One of the following option types: + + * ``CONFIG_SELECTION``: combobox containing a list of values specified by the ``selection`` member; + * ``CONFIG_HEX16``: combobox containing a list of 16-bit hexadecimal values (useful for ISA I/O ports) specified by the ``selection`` member; + * ``CONFIG_HEX20``: combobox containing a list of 20-bit hexadecimal values (useful for ISA memory addresses) specified by the ``selection`` member; + * ``CONFIG_STRING``: arbitrary text string entered by the user, currently **not visible nor configurable** in the user interface; + * ``CONFIG_FNAME``: arbitrary file path entered by the user directly or through a file selector button; + * ``CONFIG_BINARY``: checkbox; + * ``CONFIG_INT``: arbitrary integer number, currently **not visible nor configurable** in the user interface; + * ``CONFIG_SPINNER``: arbitrary integer number entered by the user directly or through up/down arrows, within a range specified by the ``spinner`` member; + * ``CONFIG_MAC``: last 3 octets of a MAC address, currently **not visible nor configurable** in the user interface; + * ``CONFIG_MIDI_OUT``: combobox containing a list of system MIDI output devices; + * ``CONFIG_MIDI_IN``: combobox containing a list of system MIDI input devices; + * ``-1``: **mandatory** terminator to indicate the end of the option list. + + * - default_string + - Default string value for a ``CONFIG_STRING`` option. Can be ``""`` if not applicable. + + * - default_int + - Default integer value for a ``CONFIG_HEX16``, ``CONFIG_HEX20``, ``CONFIG_INT`` or ``CONFIG_SPINNER`` option. Can be 0 if not applicable. + + * - file_filter + - File type filter for a ``CONFIG_FNAME`` option. Can be ``""`` if not applicable. Must be specified in Windows ``description|mask|description|mask...`` format, for example: + + ``"Raw image (*.img)|*.img|Virtual Hard Disk (*.vhd)|*.vhd"`` + + * - spinner + - ``device_config_spinner_t`` sub-structure containing the minimum/maximum/step values for a ``CONFIG_SPINNER`` option. Can be ``{ 0 }`` if not applicable. + + .. flat-table:: + :header-rows: 1 + :widths: 1 999 + + * - Member + - Description + + * - min + - Minimum selectable value. + + * - max + - Maximum selectable value. + + * - step + - Units to be incremented/decremented with the arrow buttons. Note that the user can still type in arbitrary numbers that are within ``min`` and ``max`` but not aligned to ``step``. + + * - selection + - Array of ``device_config_selection_t`` sub-structures containing the choices for a ``CONFIG_SELECTION``, ``CONFIG_HEX16`` or ``CONFIG_HEX20`` option. Can be ``{ 0 }`` if not applicable. Must be terminated with an object with a ``description`` of ``""``. + + .. flat-table:: + :header-rows: 1 + :widths: 1 999 + + * - Member + - Description + + * - description + - Description for this choice, displayed in the user interface. + + * - value + - Integer value corresponding to this choice, used in the emulated machine's configuration file. + +Configured option values can be accessed using ``device_get_config_*`` functions from within the device's ``init`` callback. + +.. note:: ``device_get_config_*`` functions should **never** be called outside of a device's ``init`` callback. You are responsible for reading the options' configured values in the ``init`` callback and storing them in your device's :ref:`state structure ` if necessary. + +.. flat-table:: device_get_config_string + :header-rows: 1 + :widths: 1 999 + + * - Parameter + - Description + + * - name + - The option's ``name``. Accepted option types are ``CONFIG_STRING`` and ``CONFIG_FNAME``. + + * - **Return value** + - The option's configured string value, or its ``default_string`` if no value is present. Note that a ``const char *`` is returned. + +.. flat-table:: device_get_config_int / device_get_config_hex16 / device_get_config_hex20 + :header-rows: 1 + :widths: 1 999 + + * - Parameter + - Description + + * - name + - The option's ``name``. Accepted option types are: + + * ``device_get_config_int``: ``CONFIG_SELECTION``, ``CONFIG_BINARY``, ``CONFIG_INT``, ``CONFIG_SPINNER``, ``CONFIG_MIDI_OUT``, ``CONFIG_MIDI_IN`` + * ``device_get_config_hex16``: ``CONFIG_HEX16`` + * ``device_get_config_hex20``: ``CONFIG_HEX20`` + + * - **Return value** + - The option's configured integer value (``CONFIG_BINARY`` returns 1 if checked or 0 otherwise), or its ``default_int`` if no value is present. + +.. flat-table:: device_get_config_int_ex / device_get_config_mac + :header-rows: 1 + :widths: 1 999 + + * - Parameter + - Description + + * - name + - The option's ``name``. Accepted option types are: + + * ``device_get_config_int_ex``: ``CONFIG_SELECTION``, ``CONFIG_BINARY``, ``CONFIG_INT``, ``CONFIG_SPINNER``, ``CONFIG_MIDI_OUT``, ``CONFIG_MIDI_IN`` + * ``device_get_config_mac``: ``CONFIG_MAC`` + + * - dflt_int + - The default value to return if no configured value is present. + + * - **Return value** + - The option's configured integer value (``CONFIG_BINARY`` returns 1 if checked or 0 otherwise), or ``dflt_int`` if no value is present. diff --git a/dev/api/dma.rst b/dev/api/dma.rst new file mode 100644 index 0000000..5111224 --- /dev/null +++ b/dev/api/dma.rst @@ -0,0 +1,76 @@ +.. include:: /include.rst + +DMA +=== + +86Box offers two mechanisms for **Direct Memory Access**: 8237 DMA for ISA devices and direct memory read/write for PCI devices. + +8237 DMA +-------- + +``86box/dma.h`` provides the ``dma_channel_read`` and ``dma_channel_write`` functions to read or write (respectively) a value from or to an 8237 DMA channel. + +.. flat-table:: dma_channel_read + :header-rows: 1 + :widths: 1 999 + + * - Parameter + - Description + + * - channel + - DMA channel number: ``0``-``3`` for 8-bit channels or ``5``-``7`` for 16-bit channels. + + * - **Return value** + - 8- (channels ``0``-``3``) or 16-bit (channels ``5``-``7``) value read from the given DMA channel, or ``DMA_NODATA`` if no data was read. + + May include a ``DMA_OVER`` flag (located above the most significant data bit so as to not affect the data) indicating that this was the last byte or word transferred, after which the channel is auto-initialized or masked depending on its configuration. + +.. flat-table:: dma_channel_write + :header-rows: 1 + :widths: 1 999 + + * - Parameter + - Description + + * - channel + - DMA channel number: ``0``-``3`` for 8-bit channels or ``5``-``7`` for 16-bit channels. + + * - val + - 8- (channels ``0``-``3``) or 16-bit (channels ``5``-``7``) value to write to the given DMA channel. + + * - **Return value** + - * ``0`` on success; + * ``DMA_NODATA`` if no data was actually written; + * ``DMA_OVER`` if this was the last byte or word transferred, after which the channel is auto-initialized or masked depending on its configuration. + +Direct memory read/write +------------------------ + +``86box/mem.h`` provides the ``mem_read*_phys`` and ``mem_write*_phys`` functions, which directly read or write physical memory. These are useful for PCI devices, which have to perform DMA on their own. + +.. flat-table:: mem_readb_phys / mem_readw_phys / mem_readl_phys + :header-rows: 1 + :widths: 1 999 + + * - Parameter + - Description + + * - addr + - 32-bit memory address to read. + + * - **Return value** + - 8- (``mem_readb_phys``), 16- (``mem_readw_phys``) or 32-bit (``mem_readl_phys``) value read from the given memory address. + + +.. flat-table:: mem_writeb_phys / mem_writew_phys / mem_writel_phys + :header-rows: 1 + :widths: 1 999 + + * - Parameter + - Description + + * - addr + - 32-bit memory address to write. + + * - val + - 8- (``mem_readb_phys``), 16- (``mem_readw_phys``) or 32-bit (``mem_readl_phys``) value to write to the given memory address. diff --git a/dev/api/images/deviceconfig.png b/dev/api/images/deviceconfig.png new file mode 100644 index 0000000000000000000000000000000000000000..7a9b84b7d8625ab4b0af719a36ca09afa529507c GIT binary patch literal 17975 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. + +I/O handlers can be added or removed at any time, although ``io_removehandler`` must be called with the **exact same** parameters that ``io_sethandler`` was originally called with. For non-Plug and Play devices, you might want to add handlers in the ``init`` callback; for ISA Plug and Play devices, you'd add and/or remove handlers on the ``config_changed`` callback; for PCI devices, you'd do the same whenever the Command register or Base Address (BAR) registers are written to; and so on. + +.. note:: There is no need to call ``io_removehandler`` on the device's ``close`` callback, since a hard reset already removes all I/O handlers. + +Callback fallbacks +------------------ + +When an I/O handler receives an operation with a width for which it has no callback, the operation will automatically **fall back** to a lower width for which there is a callback. For example, if an ``inl`` operation falls on a handler which has no ``inl`` callback, 86Box will break the operation down to ``inw`` or ``inb`` callbacks on successive port numbers, then combine their return values: + +* ``inl`` callback present:: + + uint32_t val = inl(port); + +* ``inl`` callback not present, but ``inw`` callback present:: + + uint32_t val = inw(port); + val |= (inw(port + 1) << 16); + +* ``inl`` and ``inw`` callbacks not present, but ``inb`` callback present:: + + uint32_t val = inb(port); + val |= (inb(port + 1) << 8); + val |= (inb(port + 2) << 16); + val |= (inb(port + 3) << 24); + +* ``inl``, ``inw`` and ``inb`` callbacks not present:: + + uint32_t val = 0xffffffff; + +The same applies to write callbacks: + +* ``outl`` callback present:: + + uint32_t val = /* ... */; + outl(port, val); + +* ``outl`` callback not present, but ``outw`` callback present:: + + uint32_t val = /* ... */; + outw(port, val & 0xffff); + outw(port + 1, (val >> 16) & 0xffff); + +* ``outl`` and ``outw`` callbacks not present, but ``outb`` callback present:: + + uint32_t val = /* ... */; + outb(port, val & 0xff); + outb(port + 1, (val >> 8) & 0xff); + outb(port + 2, (val >> 16) & 0xff); + outb(port + 3, (val >> 24) & 0xff); + +* ``outl``, ``outw`` and ``outb`` callbacks not present: + + No operation performed. + +This feature's main use cases are devices which store registers that are 8-bit wide but may be accessed with 16- or 32-bit operations:: + + typedef struct { + uint8_t regs[256]; + } foo_t; + + uint8_t + foo_inb(uint16_t addr, void *priv) + { + foo_t *dev = (foo_t *) priv; + return dev->regs[addr & 0xff]; /* example: register index = I/O port's least significant byte */ + } + + /* No foo_inw, so a 16-bit operation will read two 8-bit registers in succession. + No foo_inl, so a 32-bit operation will read four 8-bit registers in succession. */ + +Multiple I/O handlers +--------------------- + +Any given I/O port can have an **unlimited** amount of I/O handlers, such that: + +* when a **read** operation occurs, all read callbacks will be called, and their return values will be logically **AND**\ ed together; +* when a **write** operation occurs, all write callbacks will be called with the same written value. + +Read callbacks can effectively return "don't care" (without interfering with other handlers) by returning a value with all bits set: ``0xff`` with ``inb``, ``0xffff`` with ``inw`` or ``0xffffffff`` with ``inl``. + +.. note:: The same callback fallback rules specified above also apply with multiple handlers. diff --git a/include.rst b/include.rst index ee3f22e..48505bd 100644 --- a/include.rst +++ b/include.rst @@ -67,4 +67,30 @@ div.admonition > p:nth-child(2) { margin-bottom: 0; } + .wy-table-responsive table td { + white-space: normal; + } + .rst-content table.docutils caption { + padding-top: 0; + font-family: monospace; + font-style: normal; + } + table.docutils > tbody > tr > td > ul { + margin-bottom: 0 !important; + } + table.docutils > tbody > tr > td > ul > li > p { + font-size: inherit; + } + table.docutils > tbody > tr > td > div.wy-table-responsive { + margin-top: 0.5em; + margin-bottom: 0; + } + tr.row-odd > td { + background-color: #fcfcfc !important; + } + .vertical-text { + transform: rotate(270deg); + } + +.. highlight:: c diff --git a/index.rst b/index.rst index 60b39e0..9f020b3 100644 --- a/index.rst +++ b/index.rst @@ -46,4 +46,5 @@ Contents dev/buildguide dev/builds + dev/api/index dev/formats/index diff --git a/requirements.txt b/requirements.txt index e75e102..ef0c43d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ Sphinx==4.3.0 sphinx-rtd-theme==1.0.0 +linuxdoc==20211220