From 146827a76e5daa1552622b67c7bb7a6433fc70b5 Mon Sep 17 00:00:00 2001 From: Christian Gleissner Date: Thu, 4 Jun 2026 17:49:49 +0100 Subject: [PATCH 1/3] Add docs for new REST API endpoints /v1/machine:input and /v1/machine:menu_screen. Add OpenAPI docs for REST API to facilitate auto-generated REST clients. Add docs for Machine Code Monitor. --- .gitignore | 3 +- api/api_calls.rst | 192 ++++- api/openapi.rst | 23 + api/rest_api_openapi.yaml | 1459 ++++++++++++++++++++++++++++++++ howto/machine_code_monitor.rst | 651 ++++++++++++++ index.rst | 3 +- 6 files changed, 2326 insertions(+), 5 deletions(-) create mode 100644 api/openapi.rst create mode 100644 api/rest_api_openapi.yaml create mode 100644 howto/machine_code_monitor.rst diff --git a/.gitignore b/.gitignore index 137ad8a..c77e7dc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,7 @@ # local utils and files local/* -build/* +build/ _build # temp files *.tmp - diff --git a/api/api_calls.rst b/api/api_calls.rst index e61c956..fc888dd 100644 --- a/api/api_calls.rst +++ b/api/api_calls.rst @@ -4,6 +4,8 @@ REST API Calls Starting from Ultimate firmware 3.11, the application supports API calls by means of the HTTP protocol. This simplifies the integration of remote control functionality in external applications, as it follows a well defined standard. +For generated clients and tooling, see the machine-readable :doc:`OpenAPI specification `. + The format of the URL is as follows: ``/v1//:?`` @@ -300,7 +302,10 @@ Machine - This U64-only command causes the machine to power off. Note that it is likely that you won't receive a valid response. * - ``PUT /v1/machine:menu_button`` - - - This command does the same thing as pressing the Menu button on an 1541 Ultimate cartridge, or briefly pressing the Multi Button on the Ultimate 64. The system will either enter or exit the Ultimate menu system depending on it's current state. + - This command does the same thing as pressing the Menu button on a 1541 Ultimate cartridge, or briefly pressing the Multi Button on the Ultimate 64. The system toggles the Ultimate menu: if the menu is closed, it opens; if the menu is open, it closes. + * - ``GET /v1/machine:menu_screen`` + - + - Returns the currently active firmware menu screen as a binary 40x25 character matrix followed by a 40x25 colour-attribute matrix. Use this together with ``/v1/machine:input`` to drive and inspect the menu over REST without using the video stream. If no readable menu screen is active, the endpoint returns ``404 Not Found`` with the normal JSON ``errors`` array. * - ``PUT /v1/machine:writemem`` - | *address* | *data* @@ -332,6 +337,190 @@ Machine - This command writes the value specified by the *value* argument (in hexadecimal) into the debug register ($D7FF), and then reads the debug register ($D7FF) and returns it in the "value" field of the JSON response. *This is currently an U64-only call.* +Menu Screen Response +^^^^^^^^^^^^^^^^^^^^ + +``GET /v1/machine:menu_screen`` returns ``Content-Type: application/octet-stream`` and +``Content-Disposition: attachment`` on success, with a ``Content-Length`` of ``2000``. The body is always exactly +2000 bytes: + +.. list-table:: + :widths: 20 20 60 + :header-rows: 1 + + * - Byte range + - Size + - Content + * - ``0..999`` + - 1000 bytes + - 40x25 character matrix + * - ``1000..1999`` + - 1000 bytes + - 40x25 colour-attribute matrix + +Both matrices are row-major. For a cell at *row* 0..24 and *column* 0..39, the offset within each matrix is:: + + offset = row * 40 + column + +Each colour-attribute byte stores both colours: + +.. list-table:: + :widths: 20 80 + :header-rows: 1 + + * - Bits + - Meaning + * - ``0..3`` + - Foreground colour + * - ``4..7`` + - Background colour + +The character matrix contains the firmware UI character bytes. Printable text is stored as normal printable character +values. Firmware box-drawing and UI glyphs use low character values, and reverse-video cells are marked by bit 7 of the +character byte. + +Input (U64 only) +^^^^^^^^^^^^^^^^ + +The input endpoint injects keyboard and joystick input on Ultimate 64-class hardware. + +.. list-table:: + :widths: 25 10 65 + :header-rows: 1 + + * - URL + - Parameters + - Action + * - ``GET /v1/machine:input`` + - + - Returns the currently active REST-injected keyboard and joystick inputs. + * - ``POST /v1/machine:input`` + - + - Applies a JSON batch of keyboard, joystick, and release-all events, then returns the resulting input state. The request body must use ``Content-Type: application/json``. + +On products that do not provide the required Ultimate 64 input hardware, these calls return HTTP status code ``501`` with +an error message. Password handling is the same as other REST API calls. + +The request body may be up to 4096 bytes. The successful response format is:: + + { + "keyboard": { + "inputs": ["left_shift", "a"] + }, + "joysticks": [ + { + "port": 1, + "inputs": [] + }, + { + "port": 2, + "inputs": ["up", "fire"] + } + ], + "errors": [] + } + +``POST /v1/machine:input`` expects a top-level object with an ``events`` array. The array must contain 1 to 64 events. +The complete batch is validated before any event is applied; if validation fails, the endpoint returns ``400 Bad +Request`` and leaves the current input state unchanged. + +Keyboard events +""""""""""""""" + +Keyboard events have this format:: + + { + "kind": "keyboard", + "inputs": ["left_shift", "a"], + "transition": "tap" + } + +``transition`` must be one of: + +.. list-table:: + :widths: 20 80 + :header-rows: 1 + + * - Transition + - Meaning + * - ``press`` + - Hold the listed inputs until they are released or all REST inputs are cleared. + * - ``release`` + - Release the listed inputs. + * - ``tap`` + - Press and release the listed inputs automatically. + +Valid keyboard input names are: + +``inst_del``, ``return``, ``cursor_left_right``, ``f7``, ``f1``, ``f3``, ``f5``, ``cursor_up_down``, +digits ``0`` through ``9``, letters ``a`` through ``z``, ``left_shift``, ``right_shift``, ``plus``, ``minus``, ``period``, ``colon``, ``at``, +``comma``, ``pound``, ``star``, ``semicolon``, ``clr_home``, ``equals``, ``arrow_up``, ``slash``, ``arrow_left``, +``ctrl``, ``space``, ``commodore``, ``run_stop``, and ``restore``. + +In the ranges above, each digit and each letter is a separate input name. + +The ``inputs`` array must contain 1 to 8 unique keyboard input names. ``restore`` is special: it must appear alone and +can only be used with ``"transition": "tap"``. + +When the firmware menu is active, keyboard events are translated to menu keystrokes. This allows a client to open the +menu with ``PUT /v1/machine:menu_button``, navigate or type with ``POST /v1/machine:input``, and read the result with +``GET /v1/machine:menu_screen``. + +Joystick events +""""""""""""""" + +Joystick events have this format:: + + { + "kind": "joystick", + "port": 2, + "inputs": ["up", "fire"], + "transition": "press" + } + +``port`` must be ``1`` or ``2``. Valid joystick input names are ``up``, ``down``, ``left``, ``right``, ``fire``, +``fire2``, and ``fire3``. The ``inputs`` array must contain 1 to 7 unique joystick input names. The same ``press``, +``release``, and ``tap`` transitions are supported. + +Release-all events +"""""""""""""""""" + +A release-all event clears every REST-injected keyboard and joystick input:: + + { + "kind": "release_all" + } + +It may not contain ``inputs``, ``port``, or ``transition``. A successful machine reset or reboot also clears the +REST-injected keyboard and joystick state. + +Example input batch +""""""""""""""""""" + +This example holds joystick port 2 up and fire, types ``A`` on the keyboard, and then releases all REST input state:: + + POST /v1/machine:input + Content-Type: application/json + + { + "events": [ + { + "kind": "joystick", + "port": 2, + "inputs": ["up", "fire"], + "transition": "press" + }, + { + "kind": "keyboard", + "inputs": ["left_shift", "a"], + "transition": "tap" + }, + { + "kind": "release_all" + } + ] + } + Floppy Drives ~~~~~~~~~~~~~ @@ -502,4 +691,3 @@ This section lists the API commands for file manipulation. This is the current s to be created. The number of tracks is a required argument to this function. Each track will have 256 sectors. The maximum number of tracks is 255, which makes the maximum DNP size almost 16 Megabytes. The optional *diskname* argument overrides the name to be used in the header of the disk. When not given, it is taken from the name of the file that is being created. - diff --git a/api/openapi.rst b/api/openapi.rst new file mode 100644 index 0000000..e64f956 --- /dev/null +++ b/api/openapi.rst @@ -0,0 +1,23 @@ +OpenAPI Specification +===================== + +The REST API is also available as an OpenAPI 3.1 document: + +:download:`Download rest_api_openapi.yaml ` + +The specification covers the Ultimate REST API for U64 and U2-family devices. It is based on the firmware REST API reference. + +Why this is useful +------------------ + +YAML-based OpenAPI documentation is useful because it is both documentation and a machine-readable contract: + +- Client libraries can be generated from it, reducing hand-written HTTP wrapper code. +- Test suites can validate that request and response shapes still match the documented firmware contract. +- Mock servers can use it to emulate the REST API during application development when no Ultimate device is available. +- API explorers and documentation tools can render it as an interactive reference. +- The exact path, method, parameter, request body, response body, header, and error shapes are kept in one structured file. +- Changes to the REST API can be reviewed as precise schema diffs, which makes omissions and incompatible changes easier to spot than in prose alone. + +.. literalinclude:: rest_api_openapi.yaml + :language: yaml diff --git a/api/rest_api_openapi.yaml b/api/rest_api_openapi.yaml new file mode 100644 index 0000000..31fe995 --- /dev/null +++ b/api/rest_api_openapi.yaml @@ -0,0 +1,1459 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/schemas/v3.1/schema.yaml +openapi: 3.1.0 +info: + title: Ultimate REST API + version: "1.0.0" + summary: REST interface exposed by Ultimate 64 and 1541 Ultimate firmware >= 3.11. + description: | + This OpenAPI document captures the public HTTP interface described in the + official Ultimate REST API documentation at + https://1541u-documentation.readthedocs.io/en/latest/api/api_calls.html. + Responses always include an `errors` array unless noted. When a network + password is configured, clients must supply the `X-Password` header on every + request. Example payloads were captured against a local Ultimate 64 Elite + reachable as `http://u64` running firmware 3.12a. +servers: + - url: http://u64 + description: Ultimate device on the local network (example fixture) +components: + securitySchemes: + NetworkPassword: + type: apiKey + in: header + name: X-Password + schemas: + ErrorResponse: + type: object + required: + - errors + properties: + errors: + type: array + items: + type: string + VersionResponse: + allOf: + - $ref: "#/components/schemas/ErrorResponse" + - type: object + required: + - version + properties: + version: + type: string + InfoResponse: + allOf: + - $ref: "#/components/schemas/ErrorResponse" + - type: object + properties: + product: + type: string + firmware_version: + type: string + fpga_version: + type: string + core_version: + type: string + description: Present on Ultimate 64 devices. + hostname: + type: string + unique_id: + type: string + ConfigListResponse: + allOf: + - $ref: "#/components/schemas/ErrorResponse" + - type: object + properties: + categories: + type: array + items: + type: string + ConfigCategoryResponse: + allOf: + - $ref: "#/components/schemas/ErrorResponse" + - type: object + additionalProperties: + type: object + ConfigItemResponse: + allOf: + - $ref: "#/components/schemas/ErrorResponse" + - type: object + additionalProperties: + type: object + MemoryReadJson: + allOf: + - $ref: "#/components/schemas/ErrorResponse" + - type: object + properties: + data: + oneOf: + - type: string + description: Base64 encoded bytes. + - type: array + items: + type: integer + format: int32 + minimum: 0 + maximum: 255 + MemoryDebugResponse: + allOf: + - $ref: "#/components/schemas/ErrorResponse" + - type: object + required: + - value + properties: + value: + type: string + description: Hex string read from $D7FF. + DriveListResponse: + allOf: + - $ref: "#/components/schemas/ErrorResponse" + - type: object + properties: + drives: + type: array + items: + type: object + additionalProperties: + type: object + properties: + enabled: + type: boolean + bus_id: + type: integer + type: + type: string + rom: + type: string + image_file: + type: string + image_path: + type: string + last_error: + type: string + partitions: + type: array + items: + type: object + properties: + id: + type: integer + path: + type: string + FileInfoResponse: + allOf: + - $ref: "#/components/schemas/ErrorResponse" + - type: object + properties: + files: + type: object + properties: + path: + type: string + filename: + type: string + size: + type: integer + extension: + type: string + additionalProperties: true + MachineActionResponse: + allOf: + - $ref: "#/components/schemas/ErrorResponse" + MenuScreenUnavailableResponse: + allOf: + - $ref: "#/components/schemas/ErrorResponse" + example: + errors: + - Menu screen unavailable. + MenuScreenBytes: + type: string + format: binary + description: | + Exactly 2000 bytes. Bytes 0..999 are the 40x25 firmware UI character + matrix. Bytes 1000..1999 are the matching 40x25 colour-attribute + matrix. Both matrices are row-major: offset = row * 40 + column. + In each colour-attribute byte, bits 0..3 are the foreground colour + and bits 4..7 are the background colour. + minLength: 2000 + maxLength: 2000 + InputTransition: + type: string + enum: + - press + - release + - tap + KeyboardInputName: + type: string + enum: + - inst_del + - return + - cursor_left_right + - f7 + - f1 + - f3 + - f5 + - cursor_up_down + - "0" + - "1" + - "2" + - "3" + - "4" + - "5" + - "6" + - "7" + - "8" + - "9" + - a + - b + - c + - d + - e + - f + - g + - h + - i + - j + - k + - l + - m + - "n" + - o + - p + - q + - r + - s + - t + - u + - v + - w + - x + - "y" + - z + - left_shift + - right_shift + - plus + - minus + - period + - colon + - at + - comma + - pound + - star + - semicolon + - clr_home + - equals + - arrow_up + - slash + - arrow_left + - ctrl + - space + - commodore + - run_stop + - restore + description: | + REST input name from the C64 keyboard matrix. `restore` is special: + firmware accepts it only as the sole input in a keyboard event with + transition `tap`. + JoystickInputName: + type: string + enum: + - up + - down + - left + - right + - fire + - fire2 + - fire3 + KeyboardInputEvent: + type: object + additionalProperties: false + required: + - kind + - inputs + - transition + properties: + kind: + type: string + const: keyboard + inputs: + type: array + minItems: 1 + maxItems: 8 + uniqueItems: true + items: + $ref: "#/components/schemas/KeyboardInputName" + transition: + $ref: "#/components/schemas/InputTransition" + JoystickInputEvent: + type: object + additionalProperties: false + required: + - kind + - port + - inputs + - transition + properties: + kind: + type: string + const: joystick + port: + type: integer + enum: + - 1 + - 2 + inputs: + type: array + minItems: 1 + maxItems: 7 + uniqueItems: true + items: + $ref: "#/components/schemas/JoystickInputName" + transition: + $ref: "#/components/schemas/InputTransition" + ReleaseAllInputEvent: + type: object + additionalProperties: false + required: + - kind + properties: + kind: + type: string + const: release_all + InputEvent: + oneOf: + - $ref: "#/components/schemas/KeyboardInputEvent" + - $ref: "#/components/schemas/JoystickInputEvent" + - $ref: "#/components/schemas/ReleaseAllInputEvent" + InputRequest: + type: object + additionalProperties: false + required: + - events + properties: + events: + type: array + minItems: 1 + maxItems: 64 + items: + $ref: "#/components/schemas/InputEvent" + KeyboardInputState: + type: object + required: + - inputs + properties: + inputs: + type: array + items: + $ref: "#/components/schemas/KeyboardInputName" + JoystickInputState: + type: object + required: + - port + - inputs + properties: + port: + type: integer + enum: + - 1 + - 2 + inputs: + type: array + items: + $ref: "#/components/schemas/JoystickInputName" + InputStateResponse: + allOf: + - $ref: "#/components/schemas/ErrorResponse" + - type: object + required: + - keyboard + - joysticks + properties: + keyboard: + $ref: "#/components/schemas/KeyboardInputState" + joysticks: + type: array + minItems: 2 + maxItems: 2 + items: + $ref: "#/components/schemas/JoystickInputState" + RunnerActionResponse: + description: Standard response for runner control actions. + allOf: + - $ref: "#/components/schemas/ErrorResponse" + - type: object + +security: + - NetworkPassword: [] + +paths: + /v1/version: + get: + summary: Get API version + description: Returns the firmware-defined REST API semantic version. + responses: + "200": + description: Successful response + content: + application/json: + schema: + $ref: "#/components/schemas/VersionResponse" + examples: + live: + value: + version: "0.1" + errors: [] + /v1/info: + get: + summary: Get device information + description: >- + Returns hardware metadata (product, firmware version, FPGA/core + versions, hostname). Available on Ultimate firmware 3.12 and newer. On + earlier releases the endpoint responds with HTTP 404. + responses: + "200": + description: Successful response + content: + application/json: + schema: + $ref: "#/components/schemas/InfoResponse" + examples: + live: + value: + product: Ultimate 64 Elite + firmware_version: "3.12a" + fpga_version: "121" + core_version: "1.45" + hostname: c64u + unique_id: 38C1BA + errors: [] + /v1/runners:sidplay: + put: + summary: Play SID from filesystem + parameters: + - in: query + name: file + required: true + schema: + type: string + - in: query + name: songnr + schema: + type: integer + minimum: 0 + responses: + "200": + description: Request accepted + content: + application/json: + schema: + $ref: "#/components/schemas/RunnerActionResponse" + post: + summary: Play uploaded SID + description: > + Upload a SID file for playback. Optionally attach a song-lengths (.ssl) file + as the second multipart file to specify per-subsong durations. + parameters: + - in: query + name: songnr + schema: + type: integer + minimum: 0 + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: array + minItems: 1 + maxItems: 2 + items: + type: string + format: binary + description: > + Multipart field name used for uploads. The first entry is the SID file + to play. The optional second entry is a .ssl song-lengths file: a binary + array of 2-byte entries, one per subsong in order: [minutes, seconds], + both packed BCD. Minutes range 00-99, seconds range 00-59. Max 512 bytes + (256 entries). Missing or invalid entries are replaced with firmware defaults. + required: + - file + responses: + "200": + description: Request accepted + content: + application/json: + schema: + $ref: "#/components/schemas/RunnerActionResponse" + + /v1/runners:modplay: + put: + summary: Play MOD from filesystem + parameters: + - in: query + name: file + required: true + schema: + type: string + responses: + "200": + description: Request accepted + content: + application/json: + schema: + $ref: "#/components/schemas/RunnerActionResponse" + post: + summary: Play uploaded MOD + requestBody: + required: true + content: + application/octet-stream: + schema: + type: string + format: binary + responses: + "200": + description: Request accepted + content: + application/json: + schema: + $ref: "#/components/schemas/RunnerActionResponse" + /v1/runners:load_prg: + put: + summary: Load PRG from filesystem + parameters: + - in: query + name: file + required: true + schema: + type: string + responses: + "200": + description: Request accepted + content: + application/json: + schema: + $ref: "#/components/schemas/RunnerActionResponse" + post: + summary: Load uploaded PRG + requestBody: + required: true + content: + application/octet-stream: + schema: + type: string + format: binary + responses: + "200": + description: Request accepted + content: + application/json: + schema: + $ref: "#/components/schemas/RunnerActionResponse" + /v1/runners:run_prg: + put: + summary: Run PRG from filesystem + parameters: + - in: query + name: file + required: true + schema: + type: string + responses: + "200": + description: Request accepted + content: + application/json: + schema: + $ref: "#/components/schemas/RunnerActionResponse" + post: + summary: Run uploaded PRG + requestBody: + required: true + content: + application/octet-stream: + schema: + type: string + format: binary + responses: + "200": + description: Request accepted + content: + application/json: + schema: + $ref: "#/components/schemas/RunnerActionResponse" + /v1/runners:run_crt: + put: + summary: Run cartridge from filesystem + parameters: + - in: query + name: file + required: true + schema: + type: string + responses: + "200": + description: Request accepted + content: + application/json: + schema: + $ref: "#/components/schemas/RunnerActionResponse" + post: + summary: Run uploaded cartridge + requestBody: + required: true + content: + application/octet-stream: + schema: + type: string + format: binary + responses: + "200": + description: Request accepted + content: + application/json: + schema: + $ref: "#/components/schemas/RunnerActionResponse" + /v1/configs: + get: + summary: List configuration categories + description: Enumerates top-level configuration pages as displayed in the + Ultimate menu. Supports wildcard queries via URL encoding. + responses: + "200": + description: Categories returned + content: + application/json: + schema: + $ref: "#/components/schemas/ConfigListResponse" + examples: + live: + value: + categories: + - Audio Mixer + - SID Sockets Configuration + - UltiSID Configuration + - SID Addressing + - U64 Specific Settings + - C64 and Cartridge Settings + - Clock Settings + - Network Settings + - Ethernet Settings + - WiFi settings + - LED Strip Settings + - Data Streams + - SoftIEC Drive Settings + - Printer Settings + - Modem Settings + - User Interface Settings + - Tape Settings + - Drive A Settings + - Drive B Settings + errors: [] + post: + summary: Batch update configuration + requestBody: + required: true + content: + application/json: + schema: + type: object + additionalProperties: + type: object + responses: + "200": + description: Update applied + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /v1/configs/{category}: + get: + summary: Inspect category + description: Returns all items inside the specified category. Wildcards + may match multiple categories; each appears as an object property in the + response. + parameters: + - in: path + name: category + required: true + schema: + type: string + responses: + "200": + description: Category returned + content: + application/json: + schema: + $ref: "#/components/schemas/ConfigCategoryResponse" + examples: + drive_a: + summary: Drive A Settings (firmware 3.12a) + value: + Drive A Settings: + Drive: Enabled + Drive Type: "1541" + Drive Bus ID: 8 + ROM for 1541 mode: 1541.rom + ROM for 1571 mode: 1571.rom + ROM for 1581 mode: 1581.rom + Extra RAM: Disabled + Disk swap delay: 1 + Resets when C64 resets: "Yes" + Freezes in menu: "Yes" + GCR Save Align Tracks: "Yes" + Leave Menu on Mount: "Yes" + D64 Geos Copy Protection: none + errors: [] + /v1/configs/{category}/{item}: + get: + summary: Inspect configuration item + parameters: + - in: path + name: category + required: true + schema: + type: string + - in: path + name: item + required: true + schema: + type: string + responses: + "200": + description: Item returned + content: + application/json: + schema: + $ref: "#/components/schemas/ConfigItemResponse" + put: + summary: Update configuration item + parameters: + - in: path + name: category + required: true + schema: + type: string + - in: path + name: item + required: true + schema: + type: string + - in: query + name: value + required: true + schema: + type: string + responses: + "200": + description: Update applied + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /v1/configs:load_from_flash: + put: + summary: Load configuration from flash + responses: + "200": + description: Loaded + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /v1/configs:save_to_flash: + put: + summary: Save configuration to flash + responses: + "200": + description: Saved + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /v1/configs:reset_to_default: + put: + summary: Reset configuration to defaults + responses: + "200": + description: Reset complete + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /v1/machine:reset: + put: + summary: Soft reset machine + responses: + "200": + description: Reset triggered + content: + application/json: + schema: + $ref: "#/components/schemas/MachineActionResponse" + /v1/machine:reboot: + put: + summary: Reboot machine + responses: + "200": + description: Reboot triggered + content: + application/json: + schema: + $ref: "#/components/schemas/MachineActionResponse" + /v1/machine:pause: + put: + summary: Pause machine via DMA + responses: + "200": + description: Pause applied + content: + application/json: + schema: + $ref: "#/components/schemas/MachineActionResponse" + /v1/machine:resume: + put: + summary: Resume machine from pause + responses: + "200": + description: Resume applied + content: + application/json: + schema: + $ref: "#/components/schemas/MachineActionResponse" + /v1/machine:poweroff: + put: + summary: Power off machine + responses: + "200": + description: Power off requested + content: + application/json: + schema: + $ref: "#/components/schemas/MachineActionResponse" + /v1/machine:menu_button: + put: + summary: Toggle Ultimate menu button + description: Toggles the Ultimate firmware menu, equivalent to pressing + the physical menu button. If the menu is closed it opens; if the menu is + open it closes. + responses: + "200": + description: Button event queued + content: + application/json: + schema: + $ref: "#/components/schemas/MachineActionResponse" + /v1/machine:menu_screen: + get: + summary: Read active firmware menu screen + description: | + Returns the active 40x25 firmware menu text-mode screen as two raw + matrices. The first 1000 bytes are character bytes; the second 1000 + bytes are colour-attribute bytes. This endpoint is intended to be used + with `/v1/machine:menu_button` and `/v1/machine:input` to drive and + inspect the firmware menu over REST. + responses: + "200": + description: Readable 40x25 menu screen returned + headers: + Content-Disposition: + schema: + type: string + const: attachment + Content-Length: + schema: + type: integer + const: 2000 + content: + application/octet-stream: + schema: + $ref: "#/components/schemas/MenuScreenBytes" + "404": + description: No readable menu screen is currently available + content: + application/json: + schema: + $ref: "#/components/schemas/MenuScreenUnavailableResponse" + examples: + unavailable: + value: + errors: + - Menu screen unavailable. + /v1/machine:input: + get: + summary: Get REST-injected input state + description: Returns the currently active keyboard and joystick inputs + injected through the REST input endpoint. Ultimate 64-class input + hardware is required. + responses: + "200": + description: Input state returned + content: + application/json: + schema: + $ref: "#/components/schemas/InputStateResponse" + examples: + empty: + value: + keyboard: + inputs: [] + joysticks: + - port: 1 + inputs: [] + - port: 2 + inputs: [] + errors: [] + "501": + description: Keyboard and joystick injection are not available on this hardware + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + post: + summary: Inject keyboard and joystick input + description: | + Applies a validated batch of keyboard, joystick, and release-all events, + then returns the resulting input state. The firmware validates the + complete batch before applying any event; invalid batches return HTTP + 400 and leave the current input state unchanged. When the firmware menu + is active, keyboard events are translated to menu keystrokes. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/InputRequest" + examples: + shifted_key_and_joystick: + value: + events: + - kind: joystick + port: 2 + inputs: + - up + - fire + transition: press + - kind: keyboard + inputs: + - left_shift + - a + transition: tap + responses: + "200": + description: Events applied + content: + application/json: + schema: + $ref: "#/components/schemas/InputStateResponse" + "400": + description: Invalid body, content type, or event batch + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "501": + description: Keyboard and joystick injection are not available on this hardware + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /v1/machine:writemem: + put: + summary: Write memory via query data + parameters: + - in: query + name: address + required: true + schema: + type: string + description: Hexadecimal start address. + - in: query + name: data + required: true + schema: + type: string + description: Hex string representing bytes (up to 128 bytes). + responses: + "200": + description: Write applied + content: + application/json: + schema: + $ref: "#/components/schemas/MachineActionResponse" + post: + summary: Write memory via binary payload + parameters: + - in: query + name: address + required: true + schema: + type: string + description: Hexadecimal start address. + requestBody: + required: true + content: + application/octet-stream: + schema: + type: string + format: binary + responses: + "200": + description: Write applied + content: + application/json: + schema: + $ref: "#/components/schemas/MachineActionResponse" + /v1/machine:readmem: + get: + summary: Read memory + description: Performs a DMA read at the requested address. Firmware + returns either a JSON wrapper or raw bytes. Use `length` to limit the + transfer (default 256 bytes). + parameters: + - in: query + name: address + required: true + schema: + type: string + description: Hexadecimal start address. + - in: query + name: length + schema: + type: integer + minimum: 1 + maximum: 4096 + responses: + "200": + description: Memory data + content: + application/json: + schema: + $ref: "#/components/schemas/MemoryReadJson" + application/octet-stream: + schema: + type: string + format: binary + examples: + vic_border: + summary: Base64 rendering of two raw bytes for $D020-$D021 + value: "/vY=" + /v1/machine:debugreg: + get: + summary: Read debug register + responses: + "200": + description: Register value + content: + application/json: + schema: + $ref: "#/components/schemas/MemoryDebugResponse" + put: + summary: Write debug register + parameters: + - in: query + name: value + required: true + schema: + type: string + description: Hexadecimal value to write. + responses: + "200": + description: Updated register value + content: + application/json: + schema: + $ref: "#/components/schemas/MemoryDebugResponse" + /v1/drives: + get: + summary: List internal drives + description: Returns current Ultimate-managed drives, images, and service + devices (SoftIEC, printer emulation). + responses: + "200": + description: Drive information + content: + application/json: + schema: + $ref: "#/components/schemas/DriveListResponse" + examples: + live: + value: + drives: + - a: + enabled: true + bus_id: 8 + type: "1541" + rom: "1541.rom" + image_file: "" + image_path: "" + - b: + enabled: false + bus_id: 9 + type: "1541" + rom: "1541.rom" + image_file: "" + image_path: "" + - IEC Drive: + bus_id: 11 + enabled: false + type: "DOS emulation" + last_error: "73,U64IEC ULTIMATE DOS V1.1,00,00" + partitions: + - id: 0 + path: "/Usb0/" + - Printer Emulation: + bus_id: 4 + enabled: false + errors: [] + /v1/drives/{drive}:mount: + put: + summary: Mount disk image from filesystem + parameters: + - in: path + name: drive + required: true + schema: + type: string + - in: query + name: image + required: true + schema: + type: string + - in: query + name: type + schema: + type: string + enum: [d64, g64, d71, g71, d81] + - in: query + name: mode + schema: + type: string + enum: [readwrite, readonly, unlinked] + responses: + "200": + description: Mount complete + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + post: + summary: Mount uploaded disk image + parameters: + - in: path + name: drive + required: true + schema: + type: string + - in: query + name: type + schema: + type: string + enum: [d64, g64, d71, g71, d81] + - in: query + name: mode + schema: + type: string + enum: [readwrite, readonly, unlinked] + requestBody: + required: true + content: + application/octet-stream: + schema: + type: string + format: binary + responses: + "200": + description: Mount complete + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /v1/drives/{drive}:reset: + put: + summary: Reset drive + parameters: + - in: path + name: drive + required: true + schema: + type: string + responses: + "200": + description: Reset complete + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /v1/drives/{drive}:remove: + put: + summary: Remove mounted image + parameters: + - in: path + name: drive + required: true + schema: + type: string + responses: + "200": + description: Removal complete + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /v1/drives/{drive}:on: + put: + summary: Power on drive + parameters: + - in: path + name: drive + required: true + schema: + type: string + responses: + "200": + description: Drive powered on + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /v1/drives/{drive}:off: + put: + summary: Power off drive + parameters: + - in: path + name: drive + required: true + schema: + type: string + responses: + "200": + description: Drive powered off + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /v1/drives/{drive}:load_rom: + put: + summary: Load ROM from filesystem + parameters: + - in: path + name: drive + required: true + schema: + type: string + - in: query + name: file + required: true + schema: + type: string + responses: + "200": + description: ROM loaded + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + post: + summary: Load ROM from upload + parameters: + - in: path + name: drive + required: true + schema: + type: string + requestBody: + required: true + content: + application/octet-stream: + schema: + type: string + format: binary + responses: + "200": + description: ROM loaded + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /v1/drives/{drive}:set_mode: + put: + summary: Set drive mode + parameters: + - in: path + name: drive + required: true + schema: + type: string + - in: query + name: mode + required: true + schema: + type: string + enum: [1541, 1571, 1581] + responses: + "200": + description: Mode updated + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /v1/streams/{stream}:start: + put: + summary: Start data stream + parameters: + - in: path + name: stream + required: true + schema: + type: string + enum: [video, audio, debug] + - in: query + name: ip + required: true + schema: + type: string + description: Target IP address with optional port (ip[:port]). + responses: + "200": + description: Stream started + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /v1/streams/{stream}:stop: + put: + summary: Stop data stream + parameters: + - in: path + name: stream + required: true + schema: + type: string + enum: [video, audio, debug] + responses: + "200": + description: Stream stopped + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /v1/files/{path}:info: + get: + summary: Inspect file metadata + parameters: + - in: path + name: path + required: true + schema: + type: string + responses: + "200": + description: Metadata returned + content: + application/json: + schema: + $ref: "#/components/schemas/FileInfoResponse" + examples: + live: + value: + files: + path: /Flash/roms/1541.rom + filename: 1541.rom + size: 16384 + extension: ROM + errors: [] + /v1/files/{path}:create_d64: + put: + summary: Create D64 image + parameters: + - in: path + name: path + required: true + schema: + type: string + - in: query + name: tracks + schema: + type: integer + enum: [35, 40] + - in: query + name: diskname + schema: + type: string + responses: + "200": + description: Image created + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /v1/files/{path}:create_d71: + put: + summary: Create D71 image + parameters: + - in: path + name: path + required: true + schema: + type: string + - in: query + name: diskname + schema: + type: string + responses: + "200": + description: Image created + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /v1/files/{path}:create_d81: + put: + summary: Create D81 image + parameters: + - in: path + name: path + required: true + schema: + type: string + - in: query + name: diskname + schema: + type: string + responses: + "200": + description: Image created + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + /v1/files/{path}:create_dnp: + put: + summary: Create DNP image + parameters: + - in: path + name: path + required: true + schema: + type: string + - in: query + name: tracks + required: true + schema: + type: integer + minimum: 1 + maximum: 255 + - in: query + name: diskname + schema: + type: string + responses: + "200": + description: Image created + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" diff --git a/howto/machine_code_monitor.rst b/howto/machine_code_monitor.rst new file mode 100644 index 0000000..5a83548 --- /dev/null +++ b/howto/machine_code_monitor.rst @@ -0,0 +1,651 @@ +Machine Code Monitor +==================== + +The Machine Code Monitor is a keyboard-driven tool for inspecting and editing live or frozen C64 memory. + +It supports hexadecimal, ASCII, screen-code, binary, and assembly views, plus inline editing, bulk memory operations, file load/save, and execution from a selected address. + +*Applies to: Ultimate 1541-II, Ultimate-II+, Ultimate 64* + +Entry and Exit +-------------- + +``C=`` denotes the Commodore key. For example, ``C=+O`` means: hold the Commodore key, then press ``O``. + +To open the monitor, use one of the following: + +- Press ``C=+O``. +- Press ``F5``, open ``Developer``, then select ``Machine Code Monitor``. + +Open the built-in help with ``F3`` or ``?``. + +To close the monitor: + +- Press ``C=+O`` again. +- Press ``RUN/STOP`` when no edit operation or popup is active. + +Screen Layout +------------- + +The monitor screen has three fixed regions: + +Header +~~~~~~ + +- Shows the current view, cursor address, and active modes. +- Mode indicators may include ``Undoc``, ``Frz``, ``Poll``, or ``EDIT``. + +Body +~~~~ + +- Shows the memory region around the current cursor address. +- The active cursor position is highlighted in reverse. +- May show popups, such as search results, load/save prompts, completion pickers, or bookmarks. + +Footer +~~~~~~ + +- Shows the active CPU port mapping and VIC bank. For more details, see :ref:`machine-monitor-cpu-vic-bank-display`. +- ``CPU0``..\ ``CPU7`` identify the selected CPU memory configuration. +- ``VIC0``..\ ``VIC3`` identify the selected VIC bank and its base address. +- When jumping to a bookmark, the footer briefly shows bookmark information. + +Example layout: + +.. code:: text + + +--------------------------------------+ + |MONITOR ASM $E011 Undoc Frz Poll EDIT| + |... | + |CPU7 $A:BAS $D:I/O $E:KRN VIC0 $0000 | + +--------------------------------------+ + +Views +----- + +The monitor provides five primary views: + +===== ======== === =============================== +Key View ID Purpose +===== ======== === =============================== +``M`` Memory HEX Hexadecimal byte view +``A`` Assembly ASM Disassembly and inline assembly +``B`` Binary BIN Bit-level byte view +``I`` ASCII ASC ASCII byte view +``V`` Screen SCR Screen code view +===== ======== === =============================== + +.. _memory--hex-view: + +Memory / Hex View +~~~~~~~~~~~~~~~~~ + +Memory view shows raw bytes in hexadecimal together with a compact printable-character preview. + +Example: + +.. code:: text + + +--------------------------------------+ + |MONITOR HEX $0168 | + |00E0 85 85 85 85 85 85 86 86 ........ | + |00E8 86 86 86 86 86 87 87 87 ........ | + |00F0 87 87 87 F0 DB 00 00 00 ........ | + |00F8 00 00 00 00 00 00 00 20 ....... | + |0100 33 38 39 31 31 00 30 30 38911.00 | + |0108 30 30 00 00 10 10 35 02 00....5. | + |0110 00 00 10 10 35 02 00 00 ....5... | + |0118 1C 10 35 02 00 00 22 10 ..5...". | + |0120 35 02 00 00 28 10 35 02 5...(.5. | + |0128 00 10 35 02 00 00 32 10 ..5...2. | + |0130 35 02 00 00 38 10 35 02 5...8.5. | + |0138 00 00 3E 10 35 02 00 00 ..>.5... | + |0140 44 10 35 02 00 00 44 10 D.5...D. | + |0148 35 02 00 00 50 10 35 02 5...P.5. | + |0150 00 00 56 10 35 02 00 00 ..V.5... | + |0158 5C 10 35 02 00 00 62 10 \.5...b. | + |0160 35 02 00 00 68 10 35 02 5...h.5. | + |0168 00 00 6E 10 35 02 00 00 ..n.5... | + |CPU1 $A:RAM $D:CHR $E:RAM VIC0 $0000 | + +--------------------------------------+ + +Assembly View +~~~~~~~~~~~~~ + +Assembly view shows decoded 6510 instructions, their instruction bytes, and the memory source used for each row. + +Example: + +.. code:: text + + +--------------------------------------+ + |MONITOR ASM $E011 | + |DFF9 FF ??? [IO]| + |DFFA 00 BRK [IO]| + |DFFB 00 BRK [IO]| + |DFFC FF ??? [IO]| + |DFFD 00 BRK [IO]| + |DFFE 00 BRK [IO]| + |DFFF 00 BRK [IO]| + |E000 85 56 STA $56 [KERNAL]| + |E002 20 0F BC JSR $BC0F [KERNAL]| + |E005 A5 61 LDA $61 [KERNAL]| + |E007 C9 88 CMP #$88 [KERNAL]| + |E009 90 03 BCC $E00E [KERNAL]| + |E00B 20 D4 BA JSR $BAD4 [KERNAL]| + |E00E 20 CC BC JSR $BCCC [KERNAL]| + |E011 A5 07 LDA $07 [KERNAL]| + |E013 18 CLC [KERNAL]| + |E014 69 81 ADC #$81 [KERNAL]| + |E016 F0 F3 BEQ $E00B [KERNAL]| + |CPU7 $A:BAS $D:I/O $E:KRN VIC0 $0000 | + +--------------------------------------+ + +Binary View +~~~~~~~~~~~ + +Binary view shows each byte as eight bits, using ``.`` for a cleared bit and ``*`` for a set bit. It is useful for inspecting registers, character glyphs, sprite data, and other bit-oriented memory. + +Because C64 sprite data uses 3 bytes per row, binary view supports multiple ``W``\ idth modes for viewing bytes in different groupings. + +The top status line shows the current byte address followed by the selected bit number, for example ``$DC00/7``. Bit 7 is the most significant bit on the left, and bit 0 is the least significant bit on the right. + +Example: + +.. code:: text + + +--------------------------------------+ + |MONITOR BIN $DC00/7 | + |DC00 ........ 00 | + |DC01 ******** FF | + |DC02 ******** FF | + |DC03 ........ 00 | + |DC04 *.*..*.* A5 | + |DC05 ...**.** 1B | + |DC06 ******** FF | + |DC07 ******** FF | + |DC08 ........ 00 | + |DC09 ........ 00 | + |DC0A ........ 00 | + |DC0B *..*...* 91 | + |DC0C ........ 00 | + |DC0D *......* 81 | + |DC0E .......* 01 | + |DC0F ....*... 08 | + |DC10 ........ 00 | + |DC11 ******** FF | + |CPU7 $A:BAS $D:I/O $E:KRN VIC0 $0000 | + +--------------------------------------+ + +ASCII View +~~~~~~~~~~ + +Use ASCII view when the bytes are intended to be printable ASCII rather than C64 screen codes. + +Behavior: + +- Bytes ``$20-$7E`` are shown as their normal ASCII characters. +- All other bytes are shown as ``.``. +- Typing a printable ASCII character writes that character's byte value. +- Lowercase ASCII is preserved. + +Example: + +.. code:: text + + +--------------------------------------+ + |MONITOR ASC $A000 | + |A000 .{.CBMBASIC0.A...................| + |A020 P........:..J.,.g.U.d...#....... | + |A040 U...j..}.....:Z.A.g.U.X...}...g. | + |A060 ....d.k......|.e..............g | + |A080 yi.yR.{*.{...z.p..F..}...Z..d.EN | + |A0A0 .FO.NEX.DATA.INPUT.DIM.REA.LE | + |A0C0 .GOT.RU.I.RESTOR.GOSU.RETUR.RE.S | + |A0E0 TO.O.WAI.LOA.SAVU.VERIF.DE.POK.PR| + |A100 INT.PRIN.CON.LIS.CLR.CM.SY.OPE.CL| + |A120 OS.GE.NE.TAB.T.F.SPC.THE.NO.STE. | + |A140 .....AN.O....SG.IN.AB.US.FR.PO.S | + |A160 Q.RN.LO.EX.CO.SI.TA.AT.PEE.LE.ST | + |A180 R.VA.AS.CHR.LEFT.RIGHT.MID.G..TO | + |A1A0 D.MANY FILE.FILE OPEN.FILE NOT OP| + |A1C0 E.FILE NOT FOUND.DEVICE NOT PRESE| + |A1E0 N.NOT INPUT FIL.NOT OUTPUT FIL.M | + |A200 ISSING FILE NAM.ILLEGAL DEVICE N | + |A220 UMBE.NEXT WITHOUT FO.SYNTA.RETUR | + |CPU7 $A:BAS $D:I/O $E:KRN VIC0 $0000 | + +--------------------------------------+ + +Screen View +~~~~~~~~~~~ + +Use Screen view when the bytes represent C64 screen codes, for example when viewing screen RAM, which by default starts at ``$0400``. + +Screen view is for screen-code bytes, not PETSCII text. + +The header shows the active screen charset mode: + +- ``MONITOR SCR U/G $xxxx`` for **Uppercase/Graphics** +- ``MONITOR SCR L/U $xxxx`` for **Lowercase/Uppercase** + +The active mode is changed with ``U``; see :ref:`machine-monitor-view-modifiers`. + +Screen ``U/G`` +^^^^^^^^^^^^^^ + +- Displays ``$00`` as ``@``. +- Displays ``$01-$1A`` as ``A-Z``. +- Typing ``A-Z`` or ``a-z`` writes ``$01-$1A``. + +Screen ``L/U`` +^^^^^^^^^^^^^^ + +- Displays ``$01-$1A`` as ``a-z``. +- Displays ``$41-$5A`` as ``A-Z``. +- Typing ``a-z`` writes ``$01-$1A``. +- Typing ``A-Z`` writes ``$41-$5A``. + +Example: + +.. code:: text + + +--------------------------------------+ + |MONITOR SCR U/G $0400 | + |0400 # | + |0420 ***** COMMODORE 64 BA | + |0440 SIC V3 ***** | + |0460 64K RAM | + |0480 SYSTEM 38911 BASIC BYTES FREE | + |04A0 | + |04C0 READY. | + |04E0 | + |0500 | + |0520 | + |0540 | + |0560 | + |0580 | + |05A0 | + |05C0 | + |05E0 | + |0600 | + |0620 | + |CPU7 $A:BAS $D:I/O $E:KRN VIC0 $0000 | + +--------------------------------------+ + +Because the monitor is rendered with the firmware UI font rather than the live C64 character set, graphics bytes are shown with readable fallback glyphs instead of exact C64 glyph shapes. + +.. _machine-monitor-view-modifiers: + +View Modifiers +-------------- + +Some keys modify the current view instead of switching to another view. + +``U``: View-Specific Toggle +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``U`` is context-sensitive: + ++-------------+----------------------------------------------------------------------+ +| View | ``U`` behavior | ++=============+======================================================================+ +| Assembly | Toggles undocumented opcodes | ++-------------+----------------------------------------------------------------------+ +| Screen | Toggles the monitor-local screen charset between ``U/G`` and ``L/U`` | ++-------------+----------------------------------------------------------------------+ +| Other views | Ignored | ++-------------+----------------------------------------------------------------------+ + +In Assembly view, enabling undocumented opcodes affects how bytes are decoded and how assembly completion behaves. + +In Screen view, ``U`` changes only the monitor-local interpretation of screen codes. It does not change the live C64 character set. + +``W``: Width Mode +~~~~~~~~~~~~~~~~~ + +``W`` is view-dependent: + +======== ====================================== +View ``W`` behavior +======== ====================================== +Memory Cycles ``8 <-> 16`` bytes per row +Binary Cycles ``1 -> 2 -> 3 -> 3S -> 4 -> 1`` +ASCII Fixed-width, 32 bytes per row +Screen Fixed-width, 32 bytes per row +Assembly Variable-width, 1 to 3 bytes +======== ====================================== + +Binary width details: + +- ``1``, ``2``, and ``3`` show one, two, or three bytes as bit fields with a trailing hex preview. +- ``3S`` shows three bytes as one continuous 24-bit sprite-style row, with a hex preview. +- ``4`` shows four bytes as one continuous 32-bit row without a trailing hex preview. + +Navigation and Context +---------------------- + +- ``J``: jump to an address. +- ``G``: exit the monitor and execute from an address. +- ``F1`` or ``Shift+Space``: page up. +- ``F7`` or ``Space``: page down. +- ``Enter``: in Assembly view, follow the target of a jumpable instruction, or return to the most recent saved source location when the current instruction is not jumpable and the follow stack is non-empty. +- ``O``: cycle CPU port banking, ``CPU0``..\ ``CPU7``. +- ``Shift+O``: cycle the VIC bank override. +- ``Z``: toggle freeze when the backend supports it. +- ``P``: toggle poll mode in the local monitor. Poll mode is unavailable over telnet. + +Addresses in command prompts are hexadecimal. + +Follow/Return +~~~~~~~~~~~~~ + +Follow code flow in the Assembly view: + +- ``Enter`` follows the resolved target when the cursor is on a jumpable instruction such as ``JMP``, ``JSR``, ``BEQ``, ``BNE``, ``BCC``, ``BCS``, ``BMI``, ``BPL``, ``BVC``, or ``BVS``. +- ``Enter`` returns to the most recent saved source location when the current Assembly instruction is not jumpable and the follow stack is non-empty. +- The follow stack holds up to 10 return locations. When it is full, the oldest entry is discarded and the newest 10 are kept. +- After each successful follow or return, the bottom row shows a compact zero-based follow-stack status for about 2 seconds, for example ``F1 JMP $E000`` and ``F0 RET $A000``. + +.. _machine-monitor-cpu-vic-bank-display: + +CPU and VIC Bank Display +~~~~~~~~~~~~~~~~~~~~~~~~ + +The footer summarizes the selected CPU-visible memory configuration and VIC bank, for example: + +.. code:: text + + CPU7 $A:BAS $D:I/O $E:KRN VIC0 $0000 + +``CPU0``..\ ``CPU7`` are shorthand for the three 6510 port memory-configuration bits at ``$0001``: ``LORAM``, ``HIRAM``, and ``CHAREN``. + +In the normal no-cartridge configuration, the footer fields have these possible values: + +====== =============== ========================= +Field Address range Values +====== =============== ========================= +``$A`` ``$A000-$BFFF`` ``BAS``, ``RAM`` +``$D`` ``$D000-$DFFF`` ``I/O``, ``CHR``, ``RAM`` +``$E`` ``$E000-$FFFF`` ``KRN``, ``RAM`` +====== =============== ========================= + +======= =========================== +Value Meaning +======= =========================== +``BAS`` BASIC ROM +``I/O`` I/O registers and Color RAM +``CHR`` Character generator ROM +``KRN`` KERNAL ROM +``RAM`` RAM +======= =========================== + +``VIC0``..\ ``VIC3`` show the selected VIC bank controlled through CIA 2 port A at ``$DD00``, with base address ``$0000``, ``$4000``, ``$8000``, or ``$C000``. + +Cartridges can further affect the CPU-visible memory map through the expansion-port ``GAME`` and ``EXROM`` lines. + +Editing +------- + +All views support editing: + +- ``E``: enter edit mode. +- ``C=+E`` or ``RUN/STOP``: leave edit mode. + +Edit behavior is view-specific: + ++----------+----------------------------------------------------------------------------------+ +| View | Edit behavior | ++==========+==================================================================================+ +| Memory | Type two hex nibbles to write one byte | ++----------+----------------------------------------------------------------------------------+ +| ASCII | Type printable ASCII characters directly | ++----------+----------------------------------------------------------------------------------+ +| Screen | Type screen characters using the active Screen charset mode | ++----------+----------------------------------------------------------------------------------+ +| Binary | Type ``0`` or ``Space`` to clear the selected bit; type ``1`` or ``*`` to set it | ++----------+----------------------------------------------------------------------------------+ +| Assembly | Edit instructions inline with mnemonic completion and direct operand typing | ++----------+----------------------------------------------------------------------------------+ + +In edit mode, ``Space`` remains view-specific data entry and does not page. + +``DEL`` is logical delete, not raw backspace: + +============ =================================================== +View ``DEL`` behavior +============ =================================================== +Memory Writes ``$00`` and advances +ASCII/Screen Writes a space +Binary Clears the selected bit +Assembly Replaces the current instruction with ``NOP`` bytes +============ =================================================== + +In Assembly view, if an inline edit is already active, ``DEL`` first cancels the current line edit state. + +Selection and Clipboard +----------------------- + +- Copy the current byte with ``C=+C``. +- Paste the clipboard at the cursor with ``C=+V``. +- Toggle range mode with ``R``. + +Range mode anchors the current address. The selected span runs from the anchor address to the current cursor address, inclusive. + +While range mode is active: + +- ``C=+C`` copies the selected span. +- Pressing ``R`` again also copies the selected span and exits range mode. + +Number Tool +----------- + +- Open the number tool with ``N``. + +The number tool is a compact base-conversion and overwrite popup for the current target. It shows the same value in these forms: + +- Hex +- Decimal +- Binary +- ASCII +- Screen code + +In Assembly view, the number tool targets the operand bytes of the current instruction when possible. + +The ASCII and Screen rows in the number tool use the same mappings as the ASCII and Screen views. + +Calculator +~~~~~~~~~~ + +In the Number popup, press ``+``, ``-``, ``*``, or ``/`` to open the calculator. The expression is initialized with the current value and the selected operator. + +Press ``Return`` or ``=`` to evaluate the expression. Press ``RUN/STOP`` to cancel. On success, the popup returns to the compact conversion layout and refreshes all rows with the result. + +Expressions may contain one or more values separated by ``+``, ``-``, ``*``, or ``/``. \* and / are evaluated before + and -. Division is unsigned integer division and truncates toward zero. + +Examples: + +.. code:: text + + 42 + $1000+4 + $2000/16 + %1010*3 + 1+2/3 + 2+3*4 + +Formal EBNF grammar: + +.. code:: ebnf + + expr = term, { ("+" | "-"), term } ; + term = value, { ("*" | "/"), value } ; + value = hex | decimal | binary ; + + hex = "$", hex_digits ; + decimal = decimal_digits ; + binary = "%", binary_digits ; + +Memory Operations +----------------- + +The monitor includes direct bulk memory commands: + ++-------+----------+---------------------------------------------+-----------------------------------------------------------------------+ +| Key | Command | Syntax | Result | ++=======+==========+=============================================+=======================================================================+ +| ``F`` | Fill | ``start-end,value`` | Fill an inclusive range with one byte | ++-------+----------+---------------------------------------------+-----------------------------------------------------------------------+ +| ``T`` | Transfer | ``start-end,dest`` | Copy a range to a destination | ++-------+----------+---------------------------------------------+-----------------------------------------------------------------------+ +| ``C`` | Compare | ``start-end,dest`` | Compare a range against another location and list differing addresses | ++-------+----------+---------------------------------------------+-----------------------------------------------------------------------+ +| ``H`` | Hunt | ``start-end,bytes`` or ``start-end,"text"`` | Search for a byte sequence or quoted ASCII string | ++-------+----------+---------------------------------------------+-----------------------------------------------------------------------+ + +``Hunt`` opens a result picker: + +- ``Return``: jump to the selected match. +- ``RUN/STOP``: close the picker. + +File I/O +-------- + +- ``L``: load a file into memory. +- ``S``: save memory to a file. + +Files may exist directly in the Ultimate filesystem or inside a disk image such as ``.D64``. + +Load +~~~~ + +Load is a two-step flow: + +1. Pick a file. +2. Enter load parameters. + +In the file picker, select an existing file by pressing ``ENTER`` on it, then choosing ``Select`` from the context-sensitive menu. + +Load syntax: + +.. code:: text + + [PRG|AAAA],[Offset],[Len|AUTO] + +Default: + +.. code:: text + + PRG,0000,AUTO + +This loads the whole file to the start address stored in its first two bytes. + +Fields: + ++---------------------+---------------------------------------------------------------------------------+ +| Field | Meaning | ++=====================+=================================================================================+ +| ``PRG`` or ``AAAA`` | Use the two-byte load address from the PRG file, or load to an explicit address | ++---------------------+---------------------------------------------------------------------------------+ +| ``Offset`` | Number of bytes to skip after the PRG header | ++---------------------+---------------------------------------------------------------------------------+ +| ``Len`` or ``AUTO`` | Load the automatically determined length, or load an explicit byte count | ++---------------------+---------------------------------------------------------------------------------+ + +Examples: + ++--------------------+---------------------------------------------------------+ +| Input | Meaning | ++====================+=========================================================+ +| ``PRG`` | Load a PRG to its embedded load address | ++--------------------+---------------------------------------------------------+ +| ``0801`` | Load to ``$0801`` | ++--------------------+---------------------------------------------------------+ +| ``PRG,1000`` | Skip ``$1000`` bytes after the PRG header | ++--------------------+---------------------------------------------------------+ +| ``0801,0002,0010`` | Load ``$0010`` bytes from offset ``$0002`` to ``$0801`` | ++--------------------+---------------------------------------------------------+ + +Save +~~~~ + +Save is a two-step flow: + +1. Enter the byte range to save. +2. Pick or create the destination file. + +Save syntax: + +.. code:: text + + 0800-9FFF + +The range is inclusive. Save writes a normal PRG file with a two-byte load address header. + +In the file picker, choose one of the following: + +- Select an existing file by pressing ``ENTER`` on it, then choosing ``Select`` from the context-sensitive menu. +- Create a new file by selecting ``<< Create new file >>``. + +Bookmarks +--------- + +The monitor has 10 persistent bookmark slots. + +- List bookmarks with ``C=+B``. +- Jump directly to a slot with ``C=+0`` .. ``C=+9``. + +Each bookmark stores: + +- Label +- Address +- View ID +- View width or width mode where applicable +- CPU bank +- VIC bank + +Bookmark popup controls: + +=============== ================================================= +Key Action +=============== ================================================= +``Up``/``Down`` Select a slot +``Return`` Restore the selected slot +``S`` Store the current location into the selected slot +``L`` Edit the label +``DEL`` Reset the slot to its default +``0``..\ ``9`` Jump directly to that slot +=============== ================================================= + +Default slots are aimed at common C64 locations: + +.. code:: text + + +--------------------------------------+ + |BOOKMARKS | + | | + |0 ZERO $0000 HEX 8 CPU7 VIC0 | + |1 SCREEN $0400 SCR 32 CPU7 VIC0 | + |2 BASIC $0801 ASM CPU7 VIC0 | + |3 BASROM $A000 ASM CPU7 VIC0 | + |4 HIRAM $C000 ASM CPU7 VIC0 | + |5 VIC $D000 HEX 8 CPU7 VIC0 | + |6 SID $D400 HEX 8 CPU7 VIC0 | + |7 CIA1 $DC00 BIN 1 CPU7 VIC0 | + |8 CIA2 $DD00 BIN 1 CPU7 VIC0 | + |9 KERNAL $E000 ASM CPU7 VIC0 | + | | + |0-9/RET Jmp S Set L Label DEL Reset| + +--------------------------------------+ + +Additional Notes +---------------- + +Use **UI Freeze** mode when the monitor output must be captured in the video stream. + +Use **UI Overlay on HDMI** mode when polling is needed to observe live changes. + +To switch between UI Freeze and UI Overlay modes: + +1. Exit the monitor. +2. Press ``C=+I``. +3. Reopen the monitor. diff --git a/index.rst b/index.rst index 3f56ab6..dd90209 100644 --- a/index.rst +++ b/index.rst @@ -14,10 +14,11 @@ Cartridge Emulation Tape Emulation Modem Emulation Layer + Machine Code Monitor Command Interface Virtual Printer ReST API Reference + OpenAPI Specification Assembly64 Integration Interview By Retro Magazine FAQ by Grrrolf - From f93d540dd44cbec771052acaad162e9fb7824f01 Mon Sep 17 00:00:00 2001 From: Christian Gleissner Date: Thu, 4 Jun 2026 17:59:17 +0100 Subject: [PATCH 2/3] Address OpenAPI review feedback --- api/openapi.rst | 3 --- api/rest_api_openapi.yaml | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/api/openapi.rst b/api/openapi.rst index e64f956..2dac63c 100644 --- a/api/openapi.rst +++ b/api/openapi.rst @@ -18,6 +18,3 @@ YAML-based OpenAPI documentation is useful because it is both documentation and - API explorers and documentation tools can render it as an interactive reference. - The exact path, method, parameter, request body, response body, header, and error shapes are kept in one structured file. - Changes to the REST API can be reviewed as precise schema diffs, which makes omissions and incompatible changes easier to spot than in prose alone. - -.. literalinclude:: rest_api_openapi.yaml - :language: yaml diff --git a/api/rest_api_openapi.yaml b/api/rest_api_openapi.yaml index 31fe995..628eea8 100644 --- a/api/rest_api_openapi.yaml +++ b/api/rest_api_openapi.yaml @@ -21,6 +21,7 @@ components: type: apiKey in: header name: X-Password + description: Required only when a network password is configured on the Ultimate device. schemas: ErrorResponse: type: object @@ -383,6 +384,7 @@ components: - type: object security: + - {} - NetworkPassword: [] paths: From 50d6ceb86f153de1a4ad298247a3b5da147de910 Mon Sep 17 00:00:00 2001 From: Christian Gleissner Date: Thu, 4 Jun 2026 20:20:23 +0100 Subject: [PATCH 3/3] Add new PNG images for monitor features --- howto/machine_code_monitor.rst | 234 ++++++++---------------- media/monitor/ascii_view.png | Bin 0 -> 6931 bytes media/monitor/asm_opcode_completion.png | Bin 0 -> 5773 bytes media/monitor/assembly_view.png | Bin 0 -> 7060 bytes media/monitor/binary_sprite.png | Bin 0 -> 5491 bytes media/monitor/binary_view.png | Bin 0 -> 3887 bytes media/monitor/bookmarks.png | Bin 0 -> 5712 bytes media/monitor/calculator.png | Bin 0 -> 6200 bytes media/monitor/help_view.png | Bin 0 -> 4950 bytes media/monitor/hex_view.png | Bin 0 -> 6555 bytes media/monitor/hunt_results.png | Bin 0 -> 4607 bytes media/monitor/hunt_search.png | Bin 0 -> 6012 bytes media/monitor/layout_example.png | Bin 0 -> 7160 bytes media/monitor/load_params.png | Bin 0 -> 6479 bytes media/monitor/load_picker.png | Bin 0 -> 2114 bytes media/monitor/load_select.png | Bin 0 -> 2852 bytes media/monitor/number_tool.png | Bin 0 -> 6300 bytes media/monitor/save_filename.png | Bin 0 -> 6280 bytes media/monitor/save_picker.png | Bin 0 -> 2140 bytes media/monitor/save_range.png | Bin 0 -> 6938 bytes media/monitor/screen_view.png | Bin 0 -> 3838 bytes 21 files changed, 80 insertions(+), 154 deletions(-) create mode 100644 media/monitor/ascii_view.png create mode 100644 media/monitor/asm_opcode_completion.png create mode 100644 media/monitor/assembly_view.png create mode 100644 media/monitor/binary_sprite.png create mode 100644 media/monitor/binary_view.png create mode 100644 media/monitor/bookmarks.png create mode 100644 media/monitor/calculator.png create mode 100644 media/monitor/help_view.png create mode 100644 media/monitor/hex_view.png create mode 100644 media/monitor/hunt_results.png create mode 100644 media/monitor/hunt_search.png create mode 100644 media/monitor/layout_example.png create mode 100644 media/monitor/load_params.png create mode 100644 media/monitor/load_picker.png create mode 100644 media/monitor/load_select.png create mode 100644 media/monitor/number_tool.png create mode 100644 media/monitor/save_filename.png create mode 100644 media/monitor/save_picker.png create mode 100644 media/monitor/save_range.png create mode 100644 media/monitor/screen_view.png diff --git a/howto/machine_code_monitor.rst b/howto/machine_code_monitor.rst index 5a83548..d11a6d9 100644 --- a/howto/machine_code_monitor.rst +++ b/howto/machine_code_monitor.rst @@ -5,6 +5,8 @@ The Machine Code Monitor is a keyboard-driven tool for inspecting and editing li It supports hexadecimal, ASCII, screen-code, binary, and assembly views, plus inline editing, bulk memory operations, file load/save, and execution from a selected address. +Almost every command is a single keypress, and the monitor stays open until you exit it, so you can move freely between views and operations. If you forget a key, press ``F3`` for the on-screen help. + *Applies to: Ultimate 1541-II, Ultimate-II+, Ultimate 64* Entry and Exit @@ -17,7 +19,10 @@ To open the monitor, use one of the following: - Press ``C=+O``. - Press ``F5``, open ``Developer``, then select ``Machine Code Monitor``. -Open the built-in help with ``F3`` or ``?``. +Open the built-in help with ``F3`` or ``?``. It lists every key binding: + +.. image:: ../media/monitor/help_view.png + :alt: Monitor built-in help screen listing key bindings To close the monitor: @@ -50,15 +55,10 @@ Footer - ``VIC0``..\ ``VIC3`` identify the selected VIC bank and its base address. - When jumping to a bookmark, the footer briefly shows bookmark information. -Example layout: +Example layout, with the ``Undoc``, ``Poll``, and ``EDIT`` mode indicators active in the header: -.. code:: text - - +--------------------------------------+ - |MONITOR ASM $E011 Undoc Frz Poll EDIT| - |... | - |CPU7 $A:BAS $D:I/O $E:KRN VIC0 $0000 | - +--------------------------------------+ +.. image:: ../media/monitor/layout_example.png + :alt: Monitor screen layout showing the header, body, and footer regions Views ----- @@ -84,30 +84,8 @@ Memory view shows raw bytes in hexadecimal together with a compact printable-cha Example: -.. code:: text - - +--------------------------------------+ - |MONITOR HEX $0168 | - |00E0 85 85 85 85 85 85 86 86 ........ | - |00E8 86 86 86 86 86 87 87 87 ........ | - |00F0 87 87 87 F0 DB 00 00 00 ........ | - |00F8 00 00 00 00 00 00 00 20 ....... | - |0100 33 38 39 31 31 00 30 30 38911.00 | - |0108 30 30 00 00 10 10 35 02 00....5. | - |0110 00 00 10 10 35 02 00 00 ....5... | - |0118 1C 10 35 02 00 00 22 10 ..5...". | - |0120 35 02 00 00 28 10 35 02 5...(.5. | - |0128 00 10 35 02 00 00 32 10 ..5...2. | - |0130 35 02 00 00 38 10 35 02 5...8.5. | - |0138 00 00 3E 10 35 02 00 00 ..>.5... | - |0140 44 10 35 02 00 00 44 10 D.5...D. | - |0148 35 02 00 00 50 10 35 02 5...P.5. | - |0150 00 00 56 10 35 02 00 00 ..V.5... | - |0158 5C 10 35 02 00 00 62 10 \.5...b. | - |0160 35 02 00 00 68 10 35 02 5...h.5. | - |0168 00 00 6E 10 35 02 00 00 ..n.5... | - |CPU1 $A:RAM $D:CHR $E:RAM VIC0 $0000 | - +--------------------------------------+ +.. image:: ../media/monitor/hex_view.png + :alt: Monitor Memory / Hex view at $0168 Assembly View ~~~~~~~~~~~~~ @@ -116,30 +94,10 @@ Assembly view shows decoded 6510 instructions, their instruction bytes, and the Example: -.. code:: text +.. image:: ../media/monitor/assembly_view.png + :alt: Monitor Assembly view at $E011 - +--------------------------------------+ - |MONITOR ASM $E011 | - |DFF9 FF ??? [IO]| - |DFFA 00 BRK [IO]| - |DFFB 00 BRK [IO]| - |DFFC FF ??? [IO]| - |DFFD 00 BRK [IO]| - |DFFE 00 BRK [IO]| - |DFFF 00 BRK [IO]| - |E000 85 56 STA $56 [KERNAL]| - |E002 20 0F BC JSR $BC0F [KERNAL]| - |E005 A5 61 LDA $61 [KERNAL]| - |E007 C9 88 CMP #$88 [KERNAL]| - |E009 90 03 BCC $E00E [KERNAL]| - |E00B 20 D4 BA JSR $BAD4 [KERNAL]| - |E00E 20 CC BC JSR $BCCC [KERNAL]| - |E011 A5 07 LDA $07 [KERNAL]| - |E013 18 CLC [KERNAL]| - |E014 69 81 ADC #$81 [KERNAL]| - |E016 F0 F3 BEQ $E00B [KERNAL]| - |CPU7 $A:BAS $D:I/O $E:KRN VIC0 $0000 | - +--------------------------------------+ +Assembly view is also a full inline assembler: in edit mode it offers opcode completion as you type. See :ref:`machine-monitor-inline-assembler`. Binary View ~~~~~~~~~~~ @@ -152,30 +110,13 @@ The top status line shows the current byte address followed by the selected bit Example: -.. code:: text +.. image:: ../media/monitor/binary_view.png + :alt: Monitor Binary view at $DC00 + +Cycling the ``W`` width mode to ``3S`` makes each row span the full 24 bits of a sprite line, so 21 consecutive rows display a whole C64 sprite as a bitmap. Here a sprite stored at ``$2000``: - +--------------------------------------+ - |MONITOR BIN $DC00/7 | - |DC00 ........ 00 | - |DC01 ******** FF | - |DC02 ******** FF | - |DC03 ........ 00 | - |DC04 *.*..*.* A5 | - |DC05 ...**.** 1B | - |DC06 ******** FF | - |DC07 ******** FF | - |DC08 ........ 00 | - |DC09 ........ 00 | - |DC0A ........ 00 | - |DC0B *..*...* 91 | - |DC0C ........ 00 | - |DC0D *......* 81 | - |DC0E .......* 01 | - |DC0F ....*... 08 | - |DC10 ........ 00 | - |DC11 ******** FF | - |CPU7 $A:BAS $D:I/O $E:KRN VIC0 $0000 | - +--------------------------------------+ +.. image:: ../media/monitor/binary_sprite.png + :alt: Binary view in 3S sprite mode showing a 24 by 21 sprite bitmap ASCII View ~~~~~~~~~~ @@ -191,30 +132,8 @@ Behavior: Example: -.. code:: text - - +--------------------------------------+ - |MONITOR ASC $A000 | - |A000 .{.CBMBASIC0.A...................| - |A020 P........:..J.,.g.U.d...#....... | - |A040 U...j..}.....:Z.A.g.U.X...}...g. | - |A060 ....d.k......|.e..............g | - |A080 yi.yR.{*.{...z.p..F..}...Z..d.EN | - |A0A0 .FO.NEX.DATA.INPUT.DIM.REA.LE | - |A0C0 .GOT.RU.I.RESTOR.GOSU.RETUR.RE.S | - |A0E0 TO.O.WAI.LOA.SAVU.VERIF.DE.POK.PR| - |A100 INT.PRIN.CON.LIS.CLR.CM.SY.OPE.CL| - |A120 OS.GE.NE.TAB.T.F.SPC.THE.NO.STE. | - |A140 .....AN.O....SG.IN.AB.US.FR.PO.S | - |A160 Q.RN.LO.EX.CO.SI.TA.AT.PEE.LE.ST | - |A180 R.VA.AS.CHR.LEFT.RIGHT.MID.G..TO | - |A1A0 D.MANY FILE.FILE OPEN.FILE NOT OP| - |A1C0 E.FILE NOT FOUND.DEVICE NOT PRESE| - |A1E0 N.NOT INPUT FIL.NOT OUTPUT FIL.M | - |A200 ISSING FILE NAM.ILLEGAL DEVICE N | - |A220 UMBE.NEXT WITHOUT FO.SYNTA.RETUR | - |CPU7 $A:BAS $D:I/O $E:KRN VIC0 $0000 | - +--------------------------------------+ +.. image:: ../media/monitor/ascii_view.png + :alt: Monitor ASCII view at $A000 Screen View ~~~~~~~~~~~ @@ -247,30 +166,8 @@ Screen ``L/U`` Example: -.. code:: text - - +--------------------------------------+ - |MONITOR SCR U/G $0400 | - |0400 # | - |0420 ***** COMMODORE 64 BA | - |0440 SIC V3 ***** | - |0460 64K RAM | - |0480 SYSTEM 38911 BASIC BYTES FREE | - |04A0 | - |04C0 READY. | - |04E0 | - |0500 | - |0520 | - |0540 | - |0560 | - |0580 | - |05A0 | - |05C0 | - |05E0 | - |0600 | - |0620 | - |CPU7 $A:BAS $D:I/O $E:KRN VIC0 $0000 | - +--------------------------------------+ +.. image:: ../media/monitor/screen_view.png + :alt: Monitor Screen view at $0400 Because the monitor is rendered with the firmware UI font rather than the live C64 character set, graphics bytes are shown with readable fallback glyphs instead of exact C64 glyph shapes. @@ -351,11 +248,7 @@ Follow code flow in the Assembly view: CPU and VIC Bank Display ~~~~~~~~~~~~~~~~~~~~~~~~ -The footer summarizes the selected CPU-visible memory configuration and VIC bank, for example: - -.. code:: text - - CPU7 $A:BAS $D:I/O $E:KRN VIC0 $0000 +The footer summarizes the selected CPU-visible memory configuration and VIC bank, for example ``CPU7 $A:BAS $D:I/O $E:KRN VIC0 $0000``. ``CPU0``..\ ``CPU7`` are shorthand for the three 6510 port memory-configuration bits at ``$0001``: ``LORAM``, ``HIRAM``, and ``CHAREN``. @@ -422,6 +315,24 @@ Assembly Replaces the current instruction with ``NOP`` bytes In Assembly view, if an inline edit is already active, ``DEL`` first cancels the current line edit state. +.. _machine-monitor-inline-assembler: + +Inline Assembler +~~~~~~~~~~~~~~~~~ + +Assembly view is a full inline assembler, not just a disassembler. In edit mode, typing the first letter of a mnemonic opens an opcode completion drop-down beside the current instruction. The drop-down lists every matching opcode together with its addressing mode, and narrows as you type: + +.. image:: ../media/monitor/asm_opcode_completion.png + :alt: Opcode completion drop-down in the inline assembler + +- Each further mnemonic letter narrows the list. The drop-down header shows the typed prefix and the number of remaining matches. +- ``Up`` and ``Down`` move through the candidates. +- Once the three-letter mnemonic is complete, type the operand directly, for example ``#$00`` or ``$D020``. +- ``Return`` accepts the highlighted opcode, or the operand you typed, and writes the instruction in place. +- ``RUN/STOP`` closes the drop-down and leaves the instruction unchanged. + +Undocumented opcodes appear in the drop-down only when they are enabled with ``U``; see :ref:`machine-monitor-view-modifiers`. + Selection and Clipboard ----------------------- @@ -449,6 +360,9 @@ The number tool is a compact base-conversion and overwrite popup for the current - ASCII - Screen code +.. image:: ../media/monitor/number_tool.png + :alt: Monitor Number tool showing one byte in five forms + In Assembly view, the number tool targets the operand bytes of the current instruction when possible. The ASCII and Screen rows in the number tool use the same mappings as the ASCII and Screen views. @@ -458,6 +372,9 @@ Calculator In the Number popup, press ``+``, ``-``, ``*``, or ``/`` to open the calculator. The expression is initialized with the current value and the selected operator. +.. image:: ../media/monitor/calculator.png + :alt: Monitor Number tool calculator evaluating an expression + Press ``Return`` or ``=`` to evaluate the expression. Press ``RUN/STOP`` to cancel. On success, the popup returns to the compact conversion layout and refreshes all rows with the result. Expressions may contain one or more values separated by ``+``, ``-``, ``*``, or ``/``. \* and / are evaluated before + and -. Division is unsigned integer division and truncates toward zero. @@ -502,7 +419,15 @@ The monitor includes direct bulk memory commands: | ``H`` | Hunt | ``start-end,bytes`` or ``start-end,"text"`` | Search for a byte sequence or quoted ASCII string | +-------+----------+---------------------------------------------+-----------------------------------------------------------------------+ -``Hunt`` opens a result picker: +``Hunt`` prompts for a range followed by a byte sequence or quoted text: + +.. image:: ../media/monitor/hunt_search.png + :alt: Monitor Hunt search prompt + +Matches are listed in a result picker: + +.. image:: ../media/monitor/hunt_results.png + :alt: Monitor Hunt result picker - ``Return``: jump to the selected match. - ``RUN/STOP``: close the picker. @@ -525,6 +450,12 @@ Load is a two-step flow: In the file picker, select an existing file by pressing ``ENTER`` on it, then choosing ``Select`` from the context-sensitive menu. +.. image:: ../media/monitor/load_picker.png + :alt: Monitor Load file picker + +.. image:: ../media/monitor/load_select.png + :alt: Choosing Select from the Load context menu + Load syntax: .. code:: text @@ -539,6 +470,9 @@ Default: This loads the whole file to the start address stored in its first two bytes. +.. image:: ../media/monitor/load_params.png + :alt: Monitor Load parameters prompt + Fields: +---------------------+---------------------------------------------------------------------------------+ @@ -581,10 +515,18 @@ Save syntax: The range is inclusive. Save writes a normal PRG file with a two-byte load address header. -In the file picker, choose one of the following: +.. image:: ../media/monitor/save_range.png + :alt: Monitor Save range prompt + +In the file picker, pick an existing file to overwrite it, or choose ``<< Create new file >>`` to write a new file: -- Select an existing file by pressing ``ENTER`` on it, then choosing ``Select`` from the context-sensitive menu. -- Create a new file by selecting ``<< Create new file >>``. +.. image:: ../media/monitor/save_picker.png + :alt: Monitor Save destination picker + +Selecting ``<< Create new file >>`` prompts for the new file name: + +.. image:: ../media/monitor/save_filename.png + :alt: Monitor Save new file name prompt Bookmarks --------- @@ -618,24 +560,8 @@ Key Action Default slots are aimed at common C64 locations: -.. code:: text - - +--------------------------------------+ - |BOOKMARKS | - | | - |0 ZERO $0000 HEX 8 CPU7 VIC0 | - |1 SCREEN $0400 SCR 32 CPU7 VIC0 | - |2 BASIC $0801 ASM CPU7 VIC0 | - |3 BASROM $A000 ASM CPU7 VIC0 | - |4 HIRAM $C000 ASM CPU7 VIC0 | - |5 VIC $D000 HEX 8 CPU7 VIC0 | - |6 SID $D400 HEX 8 CPU7 VIC0 | - |7 CIA1 $DC00 BIN 1 CPU7 VIC0 | - |8 CIA2 $DD00 BIN 1 CPU7 VIC0 | - |9 KERNAL $E000 ASM CPU7 VIC0 | - | | - |0-9/RET Jmp S Set L Label DEL Reset| - +--------------------------------------+ +.. image:: ../media/monitor/bookmarks.png + :alt: Monitor bookmarks popup with default slots Additional Notes ---------------- diff --git a/media/monitor/ascii_view.png b/media/monitor/ascii_view.png new file mode 100644 index 0000000000000000000000000000000000000000..ac126cb0174884b7193b6acc5001cf936ff95fda GIT binary patch literal 6931 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 literal 0 HcmV?d00001 diff --git a/media/monitor/asm_opcode_completion.png b/media/monitor/asm_opcode_completion.png new file mode 100644 index 0000000000000000000000000000000000000000..96da23477619207496bf54fcd3621101a031df3f GIT binary patch literal 5773 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 literal 0 HcmV?d00001 diff --git a/media/monitor/binary_sprite.png b/media/monitor/binary_sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..4bc8091d72ca35649a13e31c36fd4fbdbda17142 GIT binary patch literal 5491 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 Z;Pnu{F`+R+3O}C+H?=XTJm+!ee*h{ww}Jow literal 0 HcmV?d00001 diff --git a/media/monitor/binary_view.png b/media/monitor/binary_view.png new file mode 100644 index 0000000000000000000000000000000000000000..8ff7313fffc1e9789f778a23da0c8602d42c65dd GIT binary patch literal 3887 zcmbVPc~p|w`v6tOVP%q3|7cf?RZL*)0`%>2&${e91Q&w1~?=e_qnpXGV(O~9Qxx@m**1`r6e z$@-YZ84w6e23~m?DWJ#TwSrzAE|iDs5QA(vX`v0WL%-eR!)ny^~6r(aP|z-879}iA(EoYwQC-^5?&+nesRdP za^Qz>gcUf%pRy^~kb?Z7AFrnwen1l=8~bygsS(HF&~bq+eXB}jW!CnNlX`=!U`lz( zHS-NgbjxKvV|#LCNFB70&-A4=T`-hQJoL4apd2wQ+p+oD-rLidb<}iW7}Yuet6enp z<|1Z6+-w(v-JT&T9(ZxKUn5-p4cBh5_~nmB1QMw0WT@c~zwznlg!>20z+=suGr&Kn z`TWEy!(JvCDV(3h_`(@`+lstcvC+WNtt7`Nj(S7w$VY?SDH_lHcK5C}R$qNPTBQCW zZ2G}F2UYsIWGvaV9lkZnF=-ez<*z`x1I zmJ-o;$0yt`f#MTckXZzSJ7;|HAF}7F1&ZZA_l$;25y%AV93}k5Z zV~3&8l>Nc+5-jqnAZ6PJ}Et`xnj0Zly^H6DSoVzGVK4eKi*{G z(!%bb^eZPEa(O4+MS33AEEelrP(0JR<+#j#r0=m)9I~R|U}0a*@W|?o^PhHcmpOt2 zYn1qD>g}^;#7=4D`!HiF40~kR4?h1#ZS_C0aF4Wd!$~#IbA#Rsy=u1hWY$Dgs&;1udIO{i=@e5g`DRy1eRBq%lmUi zRUi>4=sYmUHprP&tv@uI-E)r6R^{<_tgON8&qZOoTXe^yIuU!sxnpO!F(QM+qzxyQ zhDbfWAUT}8l&w&_u|bThaNhT>Cue$`v1*qIiPNUI4Yk!$3PKFqznZtKkn%-Lo$QYe z9BYbrck2$B6sM^E!QH0Cmn?Ock$_hen4B23vWqRC4~JveJgc{7blqg*5sP410L{-#8|>cDi}K2;_}YUMi-+gp@OLQbo}Wcr@5V*Hqp-Z3b# zlLNG6-~w_38;qRZa;>q{5-y*MfK8YkfO%rJR9Gn!v3$mjv@tm>t#OfNPN$G^-lsxi zJe<^E$3%m(I+Zt32vn9B-V=u^4AE}sNk$<+mpdWpzokKUJ&4p-5}^yPMMpQM8!x~f zUr;5RnYtV9h zUR^01368Vup*LU2BDjGCV69|Rk;Pchv2&|`EWlEM?S4^Ri;WSkXv#M1h(Mg(;Wwz) zHZ)H@rB@a*;!C?QZh0;;m=qJU{*2<6Th~Dw-V(89?k)%Y?pb+FS9+(UO23LQXv*dV z?BGoR!4e)c4PCUZ)PGpsdLK=TI9%?|+9lnVv@C_A$Cq!rz_0f$E^lo>Cy7C~+3FzK z0xq&I^%|w&;)mBB`IqI3-{+Llnw-zIhDV&Z=1YwQ6bRY^OX0Puo^6$!)#V}ISyIbe z@ub;VLpLcl7`zI=wDWjY#yGX~U4hgIfJ$B_lpgf~5HIg0y2#NJ)ovY1cKWz!bA zG)pQv%r!yC8N;HQZzu$wsN2j>D4Dhvq-6AL%;@n zIF3Gg^mTn#b4j!FXyBy1t*f<5ee=MC#dZ`OG3yMoz&v^yiYy2M`-Z|%Xovw^~U?tf-#x(ISs2#Af6 z)~{R-tW!Wf!?i_>J0MQ8K~a8>t4d#%N^N>o?;J&6KJ@&KoMV)``aU+;{(Qxp$=T7a z8<#%uz`pfzACq4z4Q(2QCajSgzn>c#%6SNR9CO`XfEM9F_-{==;S-lK)FK@z2 zrDJ4bZV72Mf*}~Wt%-GnB7Xf#)&^>WWX)_YE$pwVJOCnK-YNmAa4FXVh`H|>3|nLbiwB38 z!R0T1RR=wlA?j|d0(gFW;59NHN$D?qumbQCG)zY2=cdjz z+)_}8NgQ>h+KkB8L=n&2O%yAX*}zkAaFf}R>Y1vAl4890p@y3=V9bq?a9kxitx@P; z{LxlF%61-|e1YMSaP)(#I_$%UT+PcyJbLFes{yIhk#OXf%g1Rx8aVi)qK?o9Vf}q| z5&4NRw0g%Vz*UCa@|YD@Yoh6?%CM;^y~^$W(*sree1(FRmKK3RL1-J{J+866_ha9s zb@*Nk7vI+YEucZ>Up%}R1#zow&ND(XkOw*=2YWDglK~sK%#)W+g|C_FCQx+LS(lDh zL{1nU{^LC8uPyXzaQWTe)Iq`BkiD2zv~5T24oC8J(5(k40-6Declo~@HgqpsU+NHD zqL?;Cen|oVLBq80w(kP)ujhYDtj%MKe!;Q8fb89I?fFc?915Y$1i1C;_DCpJFx5P= zmAgeMYZ#Gu^V~QQTS5`B3`#u5_s{yccaB%Cp8@EOLB?GPJ5z6$COp2v7F88Ta|W5@ z^y%2|o~W_syBL9s>~5;T``Uv882YBw{7vgtH2z_#=Mo%8tsMtc9r%m|nYs(DR_Paz z(x5S%L1>}=iez1mWiT8!f`Lu$KhXhfiT>F|kp1p#x$*fugBV8lhG*MEjc!gb;^@iX zmfpX_<+b)D&aZ+)bfr>n&7%sZR`QZJ9bQZ!Vx@-WPHD z3a5c;L<2HM<~W#>I!^sn-hiV<26Pt;9`|wg0Bix)1k{)=Sq5}g_i7Ak&rj&+2}QE> z?TVy%)SfS$mLMl>nCA(jDsncToUYQ}zHDm_m;bk}Sl(n`MWN3&ond@-4JYWeZT&kP z>eS4N`0S^vlMz|ZWRntBltUi*x(XK;YbbUbYe%f&LZZ!c_Ro}~5@>2eufH!i2o54L zeH-jt;fc0=kGX?cYsrur-)bhHa9&}CaWd)8)h$|w~~x$A?tr^-%Yp5k2vP)U0O~u z2}PdVl>O|Uw=Jdo*+ogvNREvFMv83z?Ia6Y`ZS$q6?>y|j(Bj@+y1BqyUa1D2h zt36@pw9SI-CGpb@ZG6vA>Z?!RBItKpX9_N&o4fJ?15`|{O|Di}pz0RR+S@y(_`CR; zki2f2<|K=^5BQgGsTXhGGPJIUv|IFMdNv#J|V)e2&|m~l77)W zf!sEXC7Va%T}>`y|31=Bt59S&q58(>jWU7D)KZVD*1+>TMahnVNYqhJCMWpnrPTPP z%E(pVw#Jf(Nh^=Q`)JrIXd-jGPeHD_k{kTl>H$RlJ@gYhu37(r6SD_ovCvjRko6PQ z8S5!oh}4WmUVXK$kWllvND8-=UcWY;!7(#$+LG>pMUGcjdsH0($4^Ap*mrLs1S)3q zxGkUjGG@j;Gi1cPdVjy?kN5xgd_MPm?)y5QbDeX2&$+Ja^S$D2t<8l6Bn1EffbbOy zQ+oh_E9T%i%Ex^mIscDl1ppu}amCcw@j>oNUT@7jLDnpzU+%MF>Bf`Wp8X(Ewm zU0@i~dQrFC(utNMU}u_4DQO|6gz4w>>UkfFo>C>8B?lR1kwl<#6bfbOUB0#cC``kCv$DsPW&v6fm&o7n^NK zk4Vx9LWd3EKWjn?cp~oh^dOP^Vmo4r_^Ru2?OQdt$(z;UDa9jlov)im-?$qo^jO>= zyUu*x8MD3*yn||BF+Y0RpZBw@&Mo_ve zr-R-#y{4CW+T%5i-FXy zfA!d2?oMTD)>B#+;r&mQv+fMFQtwSs?p)NM>!ofH>YjK;+TQwZt&eEX>OvG&VTwY& zE-azZ+j#9fR6(#n{g^Y_=f1<$y5$%Z?ND+$frO$L0O#%DaM*ZKx|Mt>tjo{+^=(O!l zFjh!W5`bh9_wRkwmjPsTJl*ChT@U1nNk92}golR@P^KOzm|>nrB9R&bc3E`z zK4m|`ygQivCd;rronrxq_Qa=Ek4{vi)PR~#TkTFzfhq1p-nx{b&=To5UG2*|1-hNz zt<87N{9rm|s+L;4r0f*WpW4~qx1Jt^7>-T7#^&2k905%Kk_kPwHi!&{TJ=V*d7w6v zmREDqYA5?G=d4i5lc;xm4E;h3cja6GnE0{Ova>CpAo6fixhNqdNrB47VzHFn_xg5U zaZSTq^q*@Te=F|BD;CiiH>eJUAYmbl1o%hQA$ZNOVc2>nL0y90<*xshc0r`_i z4#6)Krrh2Q)T@E_ecDDn`i0DUU%~C> z8M6yyLC6i!Ea~3Q#qlkCL9faSpjxvHKhoaHdwFboA?^r<%YHLMIfMB=pGu@2%c=dG z)OJ_+UG#B;BnRBxx6KvM?-1ke*ahVceAxTq;#A_C4a_C;g@i9`;(|ddOWz~-v4JXU z^asWWpeDQs``;`45r0mFZ;!!vv7gPc`2u*y_fPDgqVzw&kC#qhj&0ECe!=koH?Q?$ zC!~)8t^$FF03#^JU^^)37R(u3{bLX-ch3R{&}E=H@Ah%F_>s7EbSrsn zdq1cK*=&Hvxp)@t18i;+c|nbjQ{^rGzM_6o+=h0vOrQ<`i1jYxbi-o zVa38_3Op{+-i#(WH0zY+Aq12O7I{#CPUd9xL2UjudM_J$kJufo*2#S{YVL{Sx7VTk zRF+&j^JmW*B;d(qJFyT?VV)q8Uha;x?Nio95A_;>ui$b?iI*dxDox!WEl^PsXjFbu zV8c(GqJmawivr&9I>t*$(~A2U?k;TJe5BQ9DunEDRi(F)^Kz$-nqx_hDI5R7W$zfT0nFh74?W;e9FLB&*MX zMpJ|x9}BeGTnTAm=WaFxTXem>8i~1;BmL+Izsk+wOKQH6R7ix)M$wTr&|BxP0VP)_ zYJuU$6HW<=pN%xC`gB)GsT^^)J5^`fTmI7Eg_uzNZH>$pQ=j&J2A%4PkuM3a=mNX* zDKLFh>$oFHAJ5MMH`7!CtMdErp(j={DVokh4rv7fHemh@Rqp9)0}*Lp@58I-D%Of9 zvNK9NcjD#dYvPo<6vKD8x5RW)F18=}NnR=Ym4*m#`MPJTTTY$H6-XIn$YqBMknEQ%6(gZ6b);Wh(?2*)q?5oUX(cqFUUu>*=PA|~YG#C0-ML7-$`--*GY zsVcQ=>YNQ78>L0n%Lp11mPWfbtem-aEohX2gLZ%8oNhWnV>_n25J%3*za!=Ub5#WD z8-L-g+uATJrJ+)MR>g&9ZLp8gEbrJb@EJBbyf24o82h>su5?#mQ4%`rV@AAx4L{SR z{wgzPfTPK|@dn7jjQ3 zR0Lv4N!W7ol~pcHYI9*CA7%5r-j*DbCGAbcd6>^Dfj_lb%(_;?X+VO2OOtTWr@U1z zSjG0%gjn=r2O%HBu__yv=Ba6XmRH~D+NFEhoK0BilJs7fs=;{4kt3f0Mu!iO5>+qE zvns9#3RqUmlKpE??)m#K&OWUxwJ&)~=-F5mgCY>&CGXx*X|%}etSSmNa<#qWTm_3+ zc8b-c)KEk`^I+GC()F$F%$bIBXZE;ffFTm|!=0sg`ENO^$_=mIxYbZs zpY3eN907kKrauoqZid?1%jpO~Ek>$$gfK#VG@FMZEi1RH*G?#O#2;Wnj*hs%5Vq|S z_dkwYod}ZOsj6`wsKhA-2+RK<^tlcg1Ms73n+s2+d zeBzgBTR)`-^*qr=RB<;(<9NsK%uO3bY@R`TNa81}>U=U&K>yOb>5s9$Y_a8}XEmuR z3az_`2{P>l05>U~fsyNE{s1SoMT zI^wjm7Np=}R2g+czE-o-2n9sG`|}S=&Ujd|Lg}WB#{%25^b|`6Vi{uc_0!|3lnSEH zzIei%!aI~3kyn#gV68}=jsoLNh^8Bea%2#p$fkzqis3mbI(YJX^V{*jhTCPlp;vj< zn&K+rN(&3+DPvI_NFFWxdSdu1S(jAQOs@sHzTuJ*`TJ_6#k&TSbicFo^HK)wH^S!& z+}~D^D(inb)m}P?pn{6W&!bheQZwu?|M(Nd6b##!8eCfmv)if9&qm~Xt-84w^TwwV zS{r#aQy{T}D^TNwx8pu<&dxfPUDBA{EJ2x-!k13U{v}Xt@Q`iw+oSvh&PaIcQb6u-VdDyp?_{HSAFx_E>d3Iywk*$#-57e!O!U5?PYFB5`Z(DQ@$@NZ3xtFAKt3Zy`XbC-if*Q*QH86CWdP zaO;TQlw=Z8q_mI<@=$oHb$aC@b5UiECYQa#i4DN!RVY`nV)3H6u@NlXrs759`EnP= z^SdlAyc^ih-i7NJAgk?r1RBqgxY}J^nH&D2rcqCZ3ezh@4itIaDbIBEt|5vrV|X+e zpyeh1IapR2O6Nm%$ma~6yNL|*i_d#F%b0KTq2ebk+&F~!gP3l68h)F-aHcXu;Ku#3 z+XH&%vd~m55X-Kkf_WW(hAfH`9(}bp#q}epw+pn?$BYRllbZUn^Ls02I$iZeZp$Zo z!U?Vk>Mk45m6DY~=o^#%N;lfOuvLw$pctfzAHnJ73{M2>s_;Vy&i03fI2cwYp|vsW zQ!y!f2SE301XcKdQgW>JiIcbl^H!ibB&jm5+bw`_dGAY7{GVhfQv~+H`~t&8y299M z+ZM9b)n)}94p~;&I}{MiCXD`=SzQz-`>mqMFY0e*@5`vlD=vD$K)`hILCC7H>6Pn9 zH-Ep>s@&QOq!ES{5N%c|#jWWIvYlp_Wi+}o-ToUd+9=Km%7=*;9mQD(n8cQgl`M!; zY+gdgdULAge6^b=jhN``6Ag#;ttEz4MZDrOhv7=KTQMf;Szp6~kvAxiZ&rk)(3``> z-kB)nSMA|-NfosB_Go+2G#q2tRpN1^mg*w*J8ZJ^<>>PmK0v6)y58RW0nVcr><%2FUw8Q?p0IL!T2+KnW$fMD9Gdj^TvXlmaA?ya=~1MSJwX!} zDY6m1GbZZH?h@5Y_<8Q!;fosjg`=AOvpfm!@hgsj&ehL#l#)Z%BEJ0ky61J+ zp>=OFc#$Knv~BASWB=1??nU6!9=Ae|D~?R}S4ViQoBf;f!vx3OjnN1&WT`??&2K0p z%RBD!`S!#}BgU`a+gu+C(neD!8h$Rx&)1o$KdlO9*bnt*vTtsp3`#+>ll$b27MTMt zy2LFD7)<}fU|Mg-v`8n{ZPFE6AnmcMTw>QRLT;2aGgIetL!Kc;#W11z2tA~Sp5C9l zevkzhM9Si;AL;35qLfxG{E>(3b#{L1P+=e9v}a!r!0dtwQWIZQrQFY*mwOd^$>grF z@0vs->gdH_;~UR9oUN36n$U{wePj~n};_Yl;r^&%SMDm}{pQdiT zwVVT3($f>|nK;^lWhRvEo{+!WKwp+qU=QW%Jg0@xv#)N&lwgR@Fv4&mhTp62%>F&+ z>KFBC`F2!-rKKJuXsqoo997R43#YJN@g2AO})(g!~~LGQGfwa$M~ zjN(@j{~9}`>niY))*RpQu&8SwQISU#qGPZ7V5HTwJHD;Lrf}aLD}}*@qt~Jzs=T`a zs2unnad8C59rGlPi#x{0Ee7BwdE#I0{P6#XI`YW8^IxieuTpUi1O=%odyvbtvcTHo z@6AY=3`qwtoE#1n--wu@VvIU|<12F6yB^ktInd~FyXdf?cyX0@}-3E3mAm{{+cNbVsP9UFz&SuZ5rEzdq4?`;XU-<3d#D;RU-f1-X11u|DfKHpM_t;E*2!FKubiG zsA-4F2a9suF|Ftuf;EPsRd_R84OX=?4!(bOVj?F{snt2U&_FaU$Yems1neT4tkF#b z>1<9Xk_}5XM?#BV7v-DjpfN7!!1o*JI6VwB(u#X^sK{4d3MFPXaHk&w^^t{mbAtV7=gn1* zWO*Gss$y*dSC5W!ZF{?NNZ)i(RJjDCJ6s3d4ty>;@og(UiE5^~sG!ib;YmZOnH$8e$*Nank6cR1RAU9j7 ziM0v5pmV}V52;6yH|<1KSV{t+>7v8SH7iata0O~7JQFe=fg{v!c{yk)Jc?4F=f}FN z5)fxy)j6>6d$4PgHxo{qVXO1SOhEd|I|ydo)3mQ&cBd*Re?T;-m=VCpKL8&P-?(kA z1Je8FQ}6H}BK+qcum=276aCX-0+X8gh1ah}M@L)3P$<+6+`LG|Yaj#LzkrVbVN`lo zdLAV{<*+H(`heXv&b~g;JI2Z4@9%2jhK7d9^&fZr9h;Jq&KunX$4L2nRg@l~sE-0} zVZJ-0sx(TGXe~2GrBKwxv)VR<-&Q)ia+&P=?zvoT?2j)}uU;aG4eQHT<%?r@G`jxG zsV!dz$rpGe_++v6laKN6(SgqyEY=5IgU$lw;S!+Mgz>5WZ2JHAZFGpkyAd-d@{1Oo Q`bYB>Gi%c-6Svs^0caNFP5=M^ literal 0 HcmV?d00001 diff --git a/media/monitor/calculator.png b/media/monitor/calculator.png new file mode 100644 index 0000000000000000000000000000000000000000..e818ee80a11808bee3382b7a38922b1c0e760121 GIT binary patch literal 6200 zcmb_ghf@74wbOGr|Hv$0>DdEz42LX{LNDmOYAYCAstJ0JngdiyoXoH^Z5{j6LI09-pU)V*sJS-4q*%iXwLudO0q%;43hn<AEqK z8SKu*Q->30y0Cc7qNoY^z(VLC3Gl2&gY8t&|KEuBI`%`KVK|^t?_@76E!{Xe0(M|_ zD`zB);w**Jt0|t?_1$l(O%-4B1->J8-}?Qakv|lkn$#^S5b~K#s?l*fJ6`fpotsg*C7t66gA8 z1biriXLsN_i6PaHX%cQf*t&qxX=iBav50**Ami7GwD94O{gCqh4x7gjNk;)LMm@-! ziIf9jvl=GGRf>W8h>X?q2Eh>vkvQ)qhn0S$`mVX-GwY;C$$nzBExxljCQTV!#zK++ z6oHR*RG2o+U?D2tuH9Z~m;J?!UtTC4-VLU2F5aM?CN!L3c zK#;=G0iJ0&9^iIen#c(6!JGq#G#%73M`{BaSXnp#{vOU3Y#tWH(T|~g{p%E|6W9q& zujV<-s;=Y*GVXfr=GA0`e z8K6&+j7TmnOhY;*{IT?7d$v*c>uMfxz{#dNOwPR+g1Yf%ITw_zufCJO3oANT^}$^T zl+be4ZZMX8rE_cP9erGn+Zr2lxwB)f#;{zx@=8Usv$ClaW86)R)Nmvwcb_^!6F3TcJ4LwS*G;YfYu} zCHH^TsZ%8V^zwHrg##Wx5#p+-A2=|qHAf*qh$8gR^{Y`N@Jdrn)M*gQ^!&a&}Gf#%P&+^3P$2> z1%3G54vsP#DJnS-u-RKa?JTtxS~Cv3Cb|q{&MqaA>^?TI%xNKd=5~A(i<>ryrM4ub<_E$5ZEIh*g&~h2p=zQ;^7WR6`y& zuFg&m(F`BOdk4LWSFEwB>@1+B^L6@okjxf=z|8*jGy`@|*{O#$p+>JH*^XE_y04wz z7aJ;IF&*pnU!EDJY7T8CaS66%93qoL1ST_M3Eok;KY&ct|;-vCknbiOo zIcfTY(5+D>w(4<+Ii4EBdO=%UE!q^p>Ed~OHQgjJV)%F97uHWioPslaS){&x3ONn7 z4Qhv*GEFbE$J97YEtpKZX8hiWEqLMmw1VD8=Y5}(qfGZnLx+8kJkk_;+N#NyYDjgA zDM7ni91B&XT(3vt z0a#KY8hGpZhw}z_V7KNoe77lk72Ex9FzHo$-jU1!o2#X%r?R*!);3+ea>iN1KHB&^ z^7a86zqZyB*5|rmYL#sT4YStN2f98f4dDIWqiA;wHYw;PgC~o7&rGRmQ%};Z$XiEo z*JPxN9L z7QVGGB1?8icpJz=3a(gx2f9TePdzW{^yYbllKg={>lNQiiJ#O&n;EUb0`x!^wyUMG z>TbgrXqnXc`oLf|iF!sWhZ5xjqySO62(jkgz0rd#L@MU--S8vg7ywtxM;?X`Fx*P2 zs-NwprE@114CXq&%B+a_5q?On>wuuNkaM$g{#D0A1V;|Fv-x?A_z%0D_(e8T&Y9@q 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 Nc;7^~UdJu*e*nFp8yNrq literal 0 HcmV?d00001 diff --git a/media/monitor/help_view.png b/media/monitor/help_view.png new file mode 100644 index 0000000000000000000000000000000000000000..1a7e5cadcf2e6534bf43e2c8ac055c78bc32afa9 GIT binary patch literal 4950 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 literal 0 HcmV?d00001 diff --git a/media/monitor/hex_view.png b/media/monitor/hex_view.png new file mode 100644 index 0000000000000000000000000000000000000000..8639b0ee839f3924828359ba61ea95eb69288463 GIT binary patch literal 6555 zcmcJUcTiL9w#I`6RH_B(L{anr3P@3ike~q(P-+mQ1OX{hr1ua|r1ODDuc3z?l-`0E z5UHUDsnUfgkU)fl05^K>`OdjB_s@GXlbP(jGw6`exGLIv$*FI+Z#!aUZ!q)KAWnMG+1EWYqH-#-HO z_I$mRk~n0~{sJ449!<2toPfc_%NqjDw3jgU*39&@-r~y~EFC4WExHx>i6jIkHxTn` zSSy??7PHz)Gr~vS?QXK0d?G@`e?ZDLAIAX*qvg(ygX$kI0x_BHLbGV^ zApem=%A5LUouFZZ<_ycc=PYtFgD>o|Um!I+Hd(q#fGG`+`O?vKzR;t@FIxshA8HmA zwp&b&a4ySFbN}NRSM~gYez#~t{**ihsETYmq&b!yMg~RwFPVTiwR(8VVOxiMc(}i5 zt#%v$`++_5com=m2$t5S3+u8YO##7uf`@2UVQ+rWFHEDXUKHxJ(*i+uDe3s0^>$9nt)WzQ0_s^gIQ3S7h7J4jO{WH^-DtX9UO+x?YSFS670dIL&K4;cyk10~J+;M@M-EtPi8p$e63fG~VBkW65l(^8 zSZ_kJcUz|GV2Or5r@jA68Md-tH8!L~^TO4L5j}n-K&Q$z( z35o6i-shZpzYb>2&%e1lY_zr$-rPsrzMSX*&9}^!kOm*jcI70Xv0=Vz(z<^^dhj69 z@watxdQ9@)w`kGGye0yc`P@rM7G;Z}DZpz%`7g#Bheg%v&SiD3>QhM~ru*;R zz%NbxMwKrqjuM-KYnB1bP@2$^GK$z{bgQljfLt_(XqRN2Dj)~iDY z6jV^0wCpk1_V2|7MW)xKAfFWMh|<_-i>iloz=`ZLwJXDwo$h&opefBKm98W9LDR}P z^O_lx29HvfiO5uXKi^wbhteym`cf;aR>No!iczZfhcTT4ZbQ@cku-O6vh3Q0@J*(Z zoGPnB1I)&0A#n??kk%39OSqn5G)gH{_Owg(xfJ6(x^IO78!~DnrpYU`m~y2YV{H&y z0q;AxoT<6#$@%?pP-^LzCHW4^)NP1Y)6(~p-A%HYI0UYXlp&;O_Jqz*-udl_%}eCm z2~6S?Xy4I=PI=OxSpEK}k>i(U@uHHL{mvphPXQUK_+D{Gf6Byy$UE>Osw7J(aF&gI`?e8mbZ(ct6XC=nT&ExXX`A$w1JoN7MP02ew`088bEwr0g^K&Zt zGsemN8%*3*hKi$>&w6Tq&hJv65{78G3wS~=7y?6LXfhpX;_>mrb>|Or46+A;MiZ8r zVjz3UmjL9DIYyeDl{MhDde4PjkS@Ov^}_Z%&2qRF1V@^AS`njpEQUxT8K}z*EN=qt z=x4!4%JUcC6ff+o-v{ao-%;fpio4+!v!vV4z8e~l{BdCV#r{@-5S-9llWRHVI0*iH zdxXpHlzDjAr0ePWt98)vqUj{uL-C^p%es5HgLwIv>U*pAh1bE=iyo)@cN|91a1YaL zu+*-{9vA3PzQx+6ESUytWX|fm879@|;kQ=Y)MSLnHn9L|(*d3qvr}Atpoq?TEX{=k znj9vKxD0W)ah}?JSpYit)wR+^Y|L9PJB(@(a;Tq>Tnk(M#MrY6Zv)HD;+6S`4f&8; zYcXG%fGIc=&9172oSvEY!)7F0LGOX|T1i#sO+}w37S-ilZ#93R&Bbr7nu6Q9C z^*bMs@@y|>xc8Mx4>gwMVB&_A-Yw5O-w0XrqrmYgR^>f~{*Zn_Nx!By6fa@uH2FLP z(Crx5RN%9Ft-Z`e8bq#y-*yqL3{7p3zNLeXiPi1bLM!wa*B48L0C}7!WN9!-m@A=e$c!Wf@yl8t-2`)d_jOC5fn0s@ zu2{H!`~p`KhAjJ64rEE9l3lN?+E`>R!Xn7n&C26@VOTX*pJX@U(*fGJfs1^$J zRCpCl^vtZHyDhrV+18>Cqt(3G@qUs?=>dUypf2Vs&{n0mJ*J27Ijoj_QCxSpG_-M_ zE=Ns}v&X#e69xC#UN@Zvzu9B@-Y%G}hxXVHUlagVn4ktynk%KmL^E|-SUOTnbwUhE zN`l6$qDWUdM8Pn6n*Z1J@SaUW3uefp$WqTDGoHX}S;uyR0RYQy!h>;fZ)C$3V@#^C z$A(QzGTZAuUmwI*O;6AkI*mMAzO2|iTmp>V$VFq+is^8W3tRX?GzcyjfgdYEi^L** zKa3gGX=nHA;KC1u2Q|fb-n~@n|9qG97tRWSV2S0vep`@84E`-_avg0a1?sHV)m~WY z?ANZ=;^>Ls{E;6VScx+mGoDnc|MP->pjL^|GHZE@YPTWK1tXPG_s^+_dGfdgE};AiLKkA?3mU-r;mSX6)4db z0$P@5^P}#o1`p+m)XC3mnKiI5SmgL_FcNW9aH!Q*`dZf6r@PjvipwCl#L0ER)nL@S za_oI$$nK*r*AIo?^1vA_`LCjSA3IBd={>%gq8zg)R~V ztqO?hja(P!i;k~+0wNua^xy3yIE3qU-h_}`+QSYUc&D2rWY*qA<&t^DllXaR7Ek71 z`N0cA)PU|o$mTi;ZD}~s%5&oczyDT|Qp)^-toP}kV|RFk8ZT5U5F{tj$R(UrDaWEh z@++?emP?A0iu92$3<|6@)~?a1&mQRdSu}Lm5ulO?HmFqX`4QeTm&ufNQ0)E4APa0> zhAYrfTgRLjH_FX#lFuTQjG;gN-4XIBY3*fZ@Thd{(B!(xzh%RIOSaD?qMEhN-;bBk z4`8b$vW{MQ4V%)(qganWB8zvh2VF*W5#|_=Uu3S`gKHN8_r{ zHW~A2tK?y~5{6>zb1?{I^=xfkQP05=_aV4uXk&!x|CErDcusri;*Zw6jTEd`OJ!j5 zy)KEiixv4YRYDwsP$Hlt>ae~fZXu};RKC{%Dh)nY#@6IT%YhrSW!M42U7gzyb`oYj`cPQc z&EL7vSD`DVa&pQ*+lixfG@Twx+6|Pv982+1>56tj@-yz4KvupqWjR|lorkHKzwCHW zQjo8Y@9lU+f-0wII`ab?2lnGYr?B`jVi}!x-7$iJhQE<9h#kYO*_JBjw4CbB4vIEq zvq)uxLQli5bG3v*neX6K*)4>7YYgAJfu)QEMH7aSvDwIIZ(sD>afg9R#Ta|MS+RRR zBM9{E(i@G8#wkleMeTraacsyXkwlIJa1y`d=Wr0LqpnCGo3-ul5>kC^(5EgT%bPF| zQNDkxFSF(0*R}fTP|Wn{XdSzdA#cECEq6v-$N=L%UZe;reP zNU0|yQ+mo?*={d}E*dkBM*@RC8sv^^PRhgnT|3x0mJTra#7~l;-|;Y4$|$D}zP9uz?IX zHnDu1@~16oX4ZtclIFZmwGPxw;{seTdyM4hcZC==E&XFs%TBXYmZxiVvfX@>=~geh zX{5=?o{+~qopH@3LG~sL%1C|sW8xFdq$b^AM+}Lt{U>iaol4dUs!EzFug47VEr;`G z89Kzo_NwHJk;o$iqv{9JkgVL<`UQ%aDdX9(dPw!|81OAdQbR|lP(fug;HX3$I@u=oBru^23xr$ z{aqJ16q7jf`vDa82VI5M_Fjzab{iP~7gasSIht?5WIDphZ`-FplW0?&)kW_S`$gfw zqo7bRBN3Zl&}El_;65bmZc&Lgs&dTok4ZU3EF09DNgvo7UH>1cknaA}jZyw;Ew;88 z?(lXUw{*SwO0HTY1N44Ke|aLsxyT6R>`q!O=+Pn3g<6;Pm1A`Ch7&T?Gb5G|Uw5KM zXN9J((fBuQxns}jva9{^B32F&I64NBdSE{<@Vq5jtCOquSRFU zTTrXKoJV>KejB;eoPDjWozpPcx^?M~`Oxeb*A{+22P_%R{c#>Q!War`ItpW-bi6TT zZt->D*JVcMWahxb4EP~>5)P%)I`DZ;w-=B}``tA}YdKL%^Ykj??!(gfgqVw_n{L3@ zV^Cf~6+jI-yT0we+y|pVz|QxhX^%iB8RnKT4EZf7r_uc|2@afQu0sDaQzJnW2tsiD zKc(cHB0yfte%>*jF)F!M{UjW}S>|!BC(asCdHZI0`NG-ofPZ1v%^=QVU`R`k;bkSa zs+$-0c4Qg;f9lQr!t-TQo_|Zr+-vr!_u|H0DQ|;P)*;MU*N%MDsC$e)OUL59u)mGJ zZ+t)g?HvDD~1|>6iZbJ)-(bCViQ4`~yIFI?iTf zJGv^VN==vk*xuQ|Rq(Fa78ysh7nla^MtMwftPJ2{UorUen|1g2otjM`OhN|ZS%F$o ztqjH<(Gx0(jN#S}x(esfC6P6po3lf8Up}lw)=>Rud-fy>^u7C~TAY5}kn0y*GDN-o zj~D%;B;(+IBiP85eAydDW%*fUt#oO%=8o(04D0866C49|ipm9=x1OxZQEhZqA%1BmOI=l!EA# zhrER+A+0DRkdfM$3R9`hu>9QWBtc+;{QT!S$}OXcq8Y1Kn3 zM?&?XD5%h(pCLG!yj454{kMjvU$p%6yOUHHZgtia}@lo&Q7pjyU> z6RpbJJ-Irg8`kf(9!_|nB!CzfkpLUoGzR$uo}5J3NI)T<+|fF!Yrchc*Lne?`N|g( z@0cA9#+RyTKCQ&1lu^17TJI`sZFa;y_?Ct}!`5H_YSq#esDVO#wkuvt%Fb-T%-0gV zs}*V~1{$ZmQr&C8t;T|ZvkIT9jqFE@#O$Qy&WVG?1D*ZdKa>ZXHN7e=XWivaPWd#t zs;g@lr8N<_s5osTvqn%KIp-{)Ia@(*u4NDTV$i*RbTVV3$p|zn9pvFHYnab}F(0=_ zpvgr@gGH%E2+e}xh8IWUv>Q9y4kP(J@_V@-k9gPsT%YY`7|>F%fC@TPd}=lewFi7$ zZ2vQv-MPrtr2@FRv^79HCUNQSiE!|$$Hp}|0IGX)t}P=GgTWl;OT-iW?1)Dj6rxfL z>P4gJ>4u0s;L)K)VdBvt>PX2#4xp!dyj|XyF{KZ%xiN?&lufH?bE@zL0(_xf0k)kx zO0gV_BL;g(HkcokdNf^b0xyJTAbl4oXwW9+(SggtG~mq;3qodeaL^@mkNfRad=v^N z$R8|C3%0X17SnZ1ew%xFefN$w+wWDsGu|BdOCc(c%=Gf%#U=2X|7BSH_kR9we|&2{ ZI(D*6;4Zk~N$>BKHPp0KEAKyh{a+(?^4kCa literal 0 HcmV?d00001 diff --git a/media/monitor/hunt_results.png b/media/monitor/hunt_results.png new file mode 100644 index 0000000000000000000000000000000000000000..9a87ab86b0d6317b29fad0c496ac081518ebb776 GIT binary patch literal 4607 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 literal 0 HcmV?d00001 diff --git a/media/monitor/hunt_search.png b/media/monitor/hunt_search.png new file mode 100644 index 0000000000000000000000000000000000000000..cf844ef1e33d7b6510fd05d3e0c46436c1e6a25a GIT binary patch literal 6012 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 IFt{D}e>3~LqW}N^ literal 0 HcmV?d00001 diff --git a/media/monitor/layout_example.png b/media/monitor/layout_example.png new file mode 100644 index 0000000000000000000000000000000000000000..6d1906fdb534987bd96f4c1260ed0d845e662f02 GIT binary patch literal 7160 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 literal 0 HcmV?d00001 diff --git a/media/monitor/load_params.png b/media/monitor/load_params.png new file mode 100644 index 0000000000000000000000000000000000000000..01eb2746604ee87bdc5a29a908ae30821b02fbc4 GIT binary patch literal 6479 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 ad)cgmRCoR5f)VLcf8gN|{|3KPgueg*2%``H literal 0 HcmV?d00001 diff --git a/media/monitor/load_select.png b/media/monitor/load_select.png new file mode 100644 index 0000000000000000000000000000000000000000..745d306b3451a771634429cd889d00dc2c91ae99 GIT binary patch literal 2852 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 literal 0 HcmV?d00001 diff --git a/media/monitor/number_tool.png b/media/monitor/number_tool.png new file mode 100644 index 0000000000000000000000000000000000000000..7e0d9b89a770b5a761cc4df8e192683b06fd26f6 GIT binary patch literal 6300 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 DWk7o@ literal 0 HcmV?d00001 diff --git a/media/monitor/save_filename.png b/media/monitor/save_filename.png new file mode 100644 index 0000000000000000000000000000000000000000..87acbd1c2a474171555ca5757965081c844c4156 GIT binary patch literal 6280 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 z z{rb$>=aFTK@0WeIoVge4*C&PKMy2JjmV0wQ=)$D)wU!(i$Z$ndJ&-|z9T?HK7{;wS zdLxZjUoL(8c86rr@@(>&Le6_D@m$5O)`3C&9k$|(nEY(3XJz+rZ<@-%pBD@;2cZ@o z6^i-&)zuNo76sbh&G%+&(vd+3CS*G}+)`d>m5I(OwLh>(uL@6XkTpoTlr9eKn=E#T z<<&JYWSjvj?~S7|yyE!Mj;4hliU_RTeb7-FKFr1I#3$PgN7k%gfK$Pcb~o1JBow zv7BqtJS&ow*4|SXfu+ffo~+|?9g*YvwOKd7Qs3A^u{mUvAH@JqO&IOMK6-l#pz>e7zy1IDvMP%CsLw{TE`~ BFeCr~ literal 0 HcmV?d00001 diff --git a/media/monitor/save_picker.png b/media/monitor/save_picker.png new file mode 100644 index 0000000000000000000000000000000000000000..c6d5e2bc5d7733792dd4d64429ce3d361c224eab GIT binary patch literal 2140 zcmeHI`&ZM46%P?83x^h4Et|;W)G<~!FynA>$X@_0RP zF(cO(|9MCaAj?-*OP@n#0L3|ld{S#2Tz@t1#k`2B&dg{MKAT>hmGplYVau$| zY8W1?t?*PWmNA_Ldl$ms*|>q>rmqlJ`Dpt~)3z7cRiunJGXU!1SU@(i{cvF)9ojA? zL`aycPnPIOlQ?0XygosD#llUVRsvOxDO6dNF+*%$OoQ*O|8AJ3S_A8DmEm zq}uCxNn+|wS7x!(yjS#iWgDFa=&li;gjLE2CBBA`8t?ketfN^9lhUvw6P}G$y>A&n zUy_6tU9nIEMa&&~XXi1=+)VEnqp@$$_NvhM*&8N?)C^tyI^~NEt5v&srZp}NGert# z4Rwze075c(n6I7?+GcB`)5JM6W)Qm5-40=UBBgUcVbp83W>Vp>7A6tutBY1G%wWAXt3>Df^Al=Qm;!v*rW0V*ynvcsByv5Mf3_Qse1;VIuBfa zflbSlb4cBYcGWjc_g)P<_l`4S_=c57!!swWN*p%z<9mIVa1~7pYJEE9`o!~7sIo7? zZ|p^J^Q=1~?b`$zDbgH4>KW3Ql#E4LJ%d`M{f&W}pKCwk9H6Ra*_3DKUR=kO-}(6X z*bu?c0jhi>>HMDbr=A+apx(B>_&)75LnrCN5A2ceuhqaaQ{feq)_;zW{*qP9-UL38 zDKZMuq=5CinlBER4i8wu`Nt0;rv%v#^U>-6BRojrN#~z|8tFfvPWCgpI}CmqAA1S5mi8?y!3UGkokC*5z!r>{c!XV+ zg*wD7tNU?nSDQ`C&ve0DFgTL}0{_X;-ThES#jhP4CtQBkDA?upUL>;S|DpeE?Em^S zOkq-om1?U=Cx5=)@iWhoGKfK|Ex2~)M;4VoL`+4#J7vquh*3_t?QO_Wla*MfckI%Y zK%@O|;smGCf5Uv^(H!ouSUCiAjQ16(> z&4#}0KGF-RL+?qan|B_NWvf@2bxg4)#{&-pt6Yz@YUCmi>nt69p1j+wbovDTCOQDe z9lo%D+i=Ab2n1=R@T0%k+P;#+$=c4_u`nqr)lz=X0)7<7w0mgyZ1_U)VT0iqhGOOA`Vix`g_kK zC_kX;<*jTH2iO18MmZECei<~+BF{~FkN3X&|Gx~)xee=xhU}nkbf>Bl-lfETmJro- I`r?g$1C8;wNB{r; literal 0 HcmV?d00001 diff --git a/media/monitor/save_range.png b/media/monitor/save_range.png new file mode 100644 index 0000000000000000000000000000000000000000..0faf150752f81a7c66a98e094de9de7661961e97 GIT binary patch literal 6938 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 cnB79jiZSch^Y