You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

7391 lines
222 KiB

<!DOCTYPE html>
<html lang="en" data-bs-theme="auto">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="../img/favicon.ico">
<title>System Guide - RomWBW Documentation V3.6</title>
<link href="../css/bootstrap.min.css" rel="stylesheet">
<link href="../css/fontawesome.min.css" rel="stylesheet">
<link href="../css/brands.min.css" rel="stylesheet">
<link href="../css/solid.min.css" rel="stylesheet">
<link href="../css/v4-font-face.min.css" rel="stylesheet">
<link href="../css/base.css" rel="stylesheet">
<link id="hljs-light" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css" disabled>
<link id="hljs-dark" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github-dark.min.css" disabled>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script>
<script>hljs.highlightAll();</script>
</head>
<body>
<div class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
<div class="container">
<a class="navbar-brand" href="..">RomWBW Documentation V3.6</a>
<!-- Expander button -->
<button type="button" class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#navbar-collapse" aria-controls="navbar-collapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<!-- Expanded navigation -->
<div id="navbar-collapse" class="navbar-collapse collapse">
<!-- Main navigation -->
<ul class="nav navbar-nav">
<li class="nav-item">
<a href="../Introduction/" class="nav-link">Introduction</a>
</li>
<li class="nav-item">
<a href="../UserGuide/" class="nav-link">User Guide</a>
</li>
<li class="nav-item">
<a href="./" class="nav-link active" aria-current="page">System Guide</a>
</li>
<li class="nav-item">
<a href="../Applications/" class="nav-link">Applications</a>
</li>
<li class="nav-item">
<a href="../Catalog/" class="nav-link">Catalog</a>
</li>
<li class="nav-item">
<a href="../Hardware/" class="nav-link">Hardware</a>
</li>
</ul>
<ul class="nav navbar-nav ms-md-auto">
<li class="nav-item">
<a href="#" class="nav-link" data-bs-toggle="modal" data-bs-target="#mkdocs_search_modal">
<i class="fa fa-search"></i> Search
</a>
</li>
<li class="nav-item">
<a rel="prev" href="../UserGuide/" class="nav-link">
<i class="fa fa-arrow-left"></i> Previous
</a>
</li>
<li class="nav-item">
<a rel="next" href="../Applications/" class="nav-link">
Next <i class="fa fa-arrow-right"></i>
</a>
</li>
<li class="nav-item">
<a href="https://github.com/wwarthen/RomWBW" class="nav-link"><i class="fa-brands fa-github"></i> GitHub</a>
</li>
<li class="nav-item dropdown">
<button id="theme-menu" aria-expanded="false" data-bs-toggle="dropdown" data-bs-display="static" aria-label="Toggle theme" class="nav-link dropdown-toggle">
<i class="fa-solid fa-circle-half-stroke fa-fw"></i>
<span class="d-lg-none ms-2">Toggle theme</span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<button class="dropdown-item d-flex align-items-center" data-bs-theme-value="light" aria-pressed="false">
<i class="fa-solid fa-sun fa-fw"></i>
<span class="ms-2">Light</span>
<i class="fa-solid fa-check ms-auto d-none"></i>
</button>
</li>
<li>
<button class="dropdown-item d-flex align-items-center" data-bs-theme-value="dark" aria-pressed="false">
<i class="fa-solid fa-moon fa-fw"></i>
<span class="ms-2">Dark</span>
<i class="fa-solid fa-check ms-auto d-none"></i>
</button>
</li>
<li>
<button class="dropdown-item d-flex align-items-center" data-bs-theme-value="auto" aria-pressed="true">
<i class="fa-solid fa-circle-half-stroke fa-fw"></i>
<span class="ms-2">Auto</span>
<i class="fa-solid fa-check ms-auto"></i>
</button>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
<script src="../js/darkmode.js"></script>
<div class="container">
<div class="row">
<div class="col-md-3"><div class="navbar-expand-md bs-sidebar hidden-print affix" role="complementary">
<div class="navbar-header">
<button type="button" class="navbar-toggler collapsed" data-bs-toggle="collapse" data-bs-target="#toc-collapse" title="Table of Contents">
<span class="fa fa-angle-down"></span>
</button>
</div>
<div id="toc-collapse" class="navbar-collapse collapse card bg-body-tertiary">
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="1"><a href="#overview" class="nav-link">Overview</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="1"><a href="#background" class="nav-link">Background</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="1"><a href="#general-design-strategy" class="nav-link">General Design Strategy</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="1"><a href="#runtime-memory-layout" class="nav-link">Runtime Memory Layout</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="2"><a href="#bank-id" class="nav-link">Bank Id</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="2"><a href="#bank-assignments" class="nav-link">Bank Assignments</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="2"><a href="#memory-managers" class="nav-link">Memory Managers</a>
<ul class="nav flex-column">
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-bs-level="1"><a href="#disk-layout" class="nav-link">Disk Layout</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="2"><a href="#floppy-disk-layout" class="nav-link">Floppy Disk Layout</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="2"><a href="#hard-disk-layout" class="nav-link">Hard Disk Layout</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="3"><a href="#modern-hard-disk-layout-hd1k" class="nav-link">Modern Hard Disk Layout (hd1k)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#classic-hard-disk-layout-hd512" class="nav-link">Classic Hard Disk Layout (hd512)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#mapping-to-media-id" class="nav-link">Mapping to Media ID</a>
<ul class="nav flex-column">
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-bs-level="1"><a href="#system-boot-process" class="nav-link">System Boot Process</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="2"><a href="#rom-boot" class="nav-link">ROM Boot</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="2"><a href="#application-boot" class="nav-link">Application Boot</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="2"><a href="#ram-boot" class="nav-link">RAM Boot</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="2"><a href="#boot-recovery" class="nav-link">Boot Recovery</a>
<ul class="nav flex-column">
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-bs-level="1"><a href="#configuration" class="nav-link">Configuration</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="2"><a href="#romwbw-nvram-configuration" class="nav-link">RomWBW NVRAM Configuration</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="3"><a href="#boot-options-nvsw_bootopts" class="nav-link">Boot Options (NVSW_BOOTOPTS)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#auto-boot-nvsw_autoboot" class="nav-link">Auto Boot (NVSW_AUTOBOOT)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#status-reset-0xff" class="nav-link">Status Reset (0xFF)</a>
<ul class="nav flex-column">
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-bs-level="1"><a href="#driver-model" class="nav-link">Driver Model</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="1"><a href="#character-emulation-video-services" class="nav-link">Character / Emulation / Video Services</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="1"><a href="#hbios-reference" class="nav-link">HBIOS Reference</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="2"><a href="#invocation" class="nav-link">Invocation</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="2"><a href="#result-codes" class="nav-link">Result Codes</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="2"><a href="#character-inputoutput-cio" class="nav-link">Character Input/Output (CIO)</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="3"><a href="#function-0x00-character-input-cioin" class="nav-link">Function 0x00 – Character Input (CIOIN)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x01-character-output-cioout" class="nav-link">Function 0x01 – Character Output (CIOOUT)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x02-character-input-status-cioist" class="nav-link">Function 0x02 – Character Input Status (CIOIST)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x03-character-output-status-cioost" class="nav-link">Function 0x03 – Character Output Status (CIOOST)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x04-character-io-initialization-cioinit" class="nav-link">Function 0x04 – Character I/O Initialization (CIOINIT)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x05-character-io-query-cioquery" class="nav-link">Function 0x05 – Character I/O Query (CIOQUERY)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x06-character-io-device-ciodevice" class="nav-link">Function 0x06 – Character I/O Device (CIODEVICE)</a>
<ul class="nav flex-column">
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-bs-level="2"><a href="#disk-inputoutput-dio" class="nav-link">Disk Input/Output (DIO)</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="3"><a href="#function-0x10-disk-status-diostatus" class="nav-link">Function 0x10 – Disk Status (DIOSTATUS)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x11-disk-reset-dioreset" class="nav-link">Function 0x11 – Disk Reset (DIORESET)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x12-disk-seek-dioseek" class="nav-link">Function 0x12 – Disk Seek (DIOSEEK)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x13-disk-read-dioread" class="nav-link">Function 0x13 – Disk Read (DIOREAD)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x14-disk-write-diowrite" class="nav-link">Function 0x14 – Disk Write (DIOWRITE)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x15-disk-verify-dioverify" class="nav-link">Function 0x15 – Disk Verify (DIOVERIFY)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x16-disk-format-dioformat" class="nav-link">Function 0x16 – Disk Format (DIOFORMAT)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x17-disk-device-diodevice" class="nav-link">Function 0x17 – Disk Device (DIODEVICE)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x18-disk-media-diomedia" class="nav-link">Function 0x18 – Disk Media (DIOMEDIA)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x19-disk-define-media-diodefmed" class="nav-link">Function 0x19 – Disk Define Media (DIODEFMED)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x1a-disk-capacity-diocapacity" class="nav-link">Function 0x1A – Disk Capacity (DIOCAPACITY)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x1b-disk-geometry-diogeometry" class="nav-link">Function 0x1B – Disk Geometry (DIOGEOMETRY)</a>
<ul class="nav flex-column">
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-bs-level="2"><a href="#real-time-clock-rtc" class="nav-link">Real Time Clock (RTC)</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="3"><a href="#function-0x20-rtc-get-time-rtcgettim" class="nav-link">Function 0x20 – RTC Get Time (RTCGETTIM)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x21-rtc-set-time-rtcsettim" class="nav-link">Function 0x21 – RTC Set Time (RTCSETTIM)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x22-rtc-get-nvram-byte-rtcgetbyt" class="nav-link">Function 0x22 – RTC Get NVRAM Byte (RTCGETBYT)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x23-rtc-set-nvram-byte-rtcsetbyt" class="nav-link">Function 0x23 – RTC Set NVRAM Byte (RTCSETBYT)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x24-rtc-get-nvram-block-rtcgetblk" class="nav-link">Function 0x24 – RTC Get NVRAM Block (RTCGETBLK)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x25-rtc-set-nvram-block-rtcsetblk" class="nav-link">Function 0x25 – RTC Set NVRAM Block (RTCSETBLK)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x26-rtc-get-alarm-rtcgetalm" class="nav-link">Function 0x26 – RTC Get Alarm (RTCGETALM)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x27-rtc-set-alarm-rtcsetalm" class="nav-link">Function 0x27 – RTC Set Alarm (RTCSETALM)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x28-rtc-device-rtcdevice" class="nav-link">Function 0x28 – RTC DEVICE (RTCDEVICE)</a>
<ul class="nav flex-column">
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-bs-level="2"><a href="#display-keypad-dsky" class="nav-link">Display Keypad (DSKY)</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="3"><a href="#function-0x30-dsky-reset-dskyreset" class="nav-link">Function 0x30 – DSKY Reset (DSKYRESET)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x31-dsky-dskystatus" class="nav-link">Function 0x31 – DSKY (DSKYSTATUS)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x32-dsky-get-key-dskygetkey" class="nav-link">Function 0x32 – DSKY Get Key (DSKYGETKEY)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x33-dsky-show-hex-rtcshowhex" class="nav-link">Function 0x33 – DSKY Show HEX (RTCSHOWHEX)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x34-dsky-show-segments-dskyshowseg" class="nav-link">Function 0x34 – DSKY Show Segments (DSKYSHOWSEG)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x35-dsky-keypad-leds-dskykeyleds" class="nav-link">Function 0x35 – DSKY Keypad LEDs (DSKYKEYLEDS)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x36-dsky-status-led-dskystatled" class="nav-link">Function 0x36 – DSKY Status LED (DSKYSTATLED)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x37-dsky-beep-dskybeep" class="nav-link">Function 0x37 – DSKY Beep (DSKYBEEP)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x38-dsky-device-dskydevice" class="nav-link">Function 0x38 – DSKY Device (DSKYDEVICE)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x39-dsky-device-dskymessage" class="nav-link">Function 0x39 – DSKY Device (DSKYMESSAGE)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x3a-dsky-device-dskyevent" class="nav-link">Function 0x3A – DSKY Device (DSKYEVENT)</a>
<ul class="nav flex-column">
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-bs-level="2"><a href="#video-display-adapter-vda" class="nav-link">Video Display Adapter (VDA)</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="3"><a href="#function-0x40-video-initialize-vdaini" class="nav-link">Function 0x40 – Video Initialize (VDAINI)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x41-video-query-vdaqry" class="nav-link">Function 0x41 – Video Query (VDAQRY)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x42-video-reset-vdares" class="nav-link">Function 0x42 – Video Reset (VDARES)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x43-video-device-vdadev" class="nav-link">Function 0x43 – Video Device (VDADEV)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x44-video-set-cursor-style-vdascs" class="nav-link">Function 0x44 – Video Set Cursor Style (VDASCS)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x45-video-set-cursor-position-vdascp" class="nav-link">Function 0x45 – Video Set Cursor Position (VDASCP)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x46-video-set-character-attribute-vdasat" class="nav-link">Function 0x46 – Video Set Character Attribute (VDASAT)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x47-video-set-character-color-vdasco" class="nav-link">Function 0x47 – Video Set Character Color (VDASCO)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x48-video-write-character-vdawrc" class="nav-link">Function 0x48 – Video Write Character (VDAWRC)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x49-video-fill-vdafil" class="nav-link">Function 0x49 – Video Fill (VDAFIL)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x4a-video-copy-vdacpy" class="nav-link">Function 0x4A – Video Copy (VDACPY)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x4b-video-scroll-vdascr" class="nav-link">Function 0x4B – Video Scroll (VDASCR)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x4c-video-keyboard-status-vdakst" class="nav-link">Function 0x4C – Video Keyboard Status (VDAKST)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x4d-video-keyboard-flush-vdakfl" class="nav-link">Function 0x4D – Video Keyboard Flush (VDAKFL)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x4e-video-keyboard-read-vdakrd" class="nav-link">Function 0x4E – Video Keyboard Read (VDAKRD)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x4f-read-a-character-at-current-video-position-vdardc" class="nav-link">Function 0x4F – Read a character at current video position (VDARDC)</a>
<ul class="nav flex-column">
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-bs-level="2"><a href="#sound-snd" class="nav-link">Sound (SND)</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="3"><a href="#function-0x50-sound-reset-sndreset" class="nav-link">Function 0x50 – Sound Reset (SNDRESET)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x51-sound-volume-sndvol" class="nav-link">Function 0x51 – Sound Volume (SNDVOL)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x52-sound-period-sndprd" class="nav-link">Function 0x52 – Sound Period (SNDPRD)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x53-sound-note-sndnote" class="nav-link">Function 0x53 – Sound Note (SNDNOTE)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x54-sound-play-sndplay" class="nav-link">Function 0x54 – Sound Play (SNDPLAY)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x55-sound-query-sndquery" class="nav-link">Function 0x55 – Sound Query (SNDQUERY)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x56-sound-duration-snddur" class="nav-link">Function 0x56 – Sound Duration (SNDDUR)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x57-sound-device-snddevice" class="nav-link">Function 0x57 – Sound Device (SNDDEVICE)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0x58-sound-beep-sndbeep" class="nav-link">Function 0x58 – Sound Beep (SNDBEEP)</a>
<ul class="nav flex-column">
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-bs-level="2"><a href="#extension-ext" class="nav-link">Extension (EXT)</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="3"><a href="#function-0xe0-calculate-slice-extslice" class="nav-link">Function 0xE0 – Calculate Slice (EXTSLICE)</a>
<ul class="nav flex-column">
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-bs-level="2"><a href="#system-sys" class="nav-link">System (SYS)</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="3"><a href="#function-0xf0-system-reset-sysreset" class="nav-link">Function 0xF0 – System Reset (SYSRESET)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0xf1-system-version-sysver" class="nav-link">Function 0xF1 – System Version (SYSVER)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0xf2-system-set-bank-syssetbnk" class="nav-link">Function 0xF2 – System Set Bank (SYSSETBNK)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0xf3-system-get-bank-sysgetbnk" class="nav-link">Function 0xF3 – System Get Bank (SYSGETBNK)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0xf4-system-set-copy-syssetcpy" class="nav-link">Function 0xF4 – System Set Copy (SYSSETCPY)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0xf5-system-bank-copy-sysbnkcpy" class="nav-link">Function 0xF5 – System Bank Copy (SYSBNKCPY)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0xf6-system-alloc-sysalloc" class="nav-link">Function 0xF6 – System Alloc (SYSALLOC)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0xf7-system-free-sysfree" class="nav-link">Function 0xF7 – System Free (SYSFREE)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0xf8-system-get-sysget" class="nav-link">Function 0xF8 – System Get (SYSGET)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0xf9-system-set-sysset" class="nav-link">Function 0xF9 – System Set (SYSSET)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0xfa-system-peek-syspeek" class="nav-link">Function 0xFA – System Peek (SYSPEEK)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0xfb-system-poke-syspoke" class="nav-link">Function 0xFB – System Poke (SYSPOKE)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#function-0xfc-system-interrupt-management-sysint" class="nav-link">Function 0xFC – System Interrupt Management (SYSINT)</a>
<ul class="nav flex-column">
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-bs-level="2"><a href="#proxy-functions" class="nav-link">Proxy Functions</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="3"><a href="#invoke-hbios-function-invoke" class="nav-link">Invoke HBIOS Function (INVOKE)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#bank-select-bnksel" class="nav-link">Bank Select (BNKSEL)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#bank-copy-bnkcpy" class="nav-link">Bank Copy (BNKCPY)</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#bank-call-bnkcall" class="nav-link">Bank Call (BNKCALL)</a>
<ul class="nav flex-column">
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-bs-level="1"><a href="#errors-and-diagnostics" class="nav-link">Errors and diagnostics</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="2"><a href="#run-time-errors" class="nav-link">Run Time Errors</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="3"><a href="#panic" class="nav-link">PANIC</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#syschk" class="nav-link">SYSCHK</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#error-level-reporting" class="nav-link">Error Level reporting</a>
<ul class="nav flex-column">
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-bs-level="2"><a href="#build-time-errors" class="nav-link">Build time errors</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="3"><a href="#build-chain-tool-errors" class="nav-link">Build chain tool errors</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#assembly-time-check-errors" class="nav-link">Assembly time check errors</a>
<ul class="nav flex-column">
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-bs-level="2"><a href="#diagnostics" class="nav-link">Diagnostics</a>
<ul class="nav flex-column">
<li class="nav-item" data-bs-level="3"><a href="#diagnostic-leds" class="nav-link">Diagnostic LEDs</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-bs-level="3"><a href="#appendix-a-driver-instance-data-fields" class="nav-link">Appendix A Driver Instance Data fields</a>
<ul class="nav flex-column">
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div></div>
<div class="col-md-9" role="main">
<p><strong>RomWBW System Guide</strong> \
Version 3.6 \
Wayne Warthen (<a href="mailto:wwarthen@gmail.com">wwarthen@gmail.com</a>) \
06 Jun 2025</p>
<h1 id="overview">Overview</h1>
<p>The objective of RomWBW is to provide firmware, operating systems, and
applications targeting the Z80 family of CPUs. The firmware, in the form
of a ROM module, acts as the hardware interface layer with a
well-defined API (the HBIOS). The associated operating systems and
applications are adapted to the HBIOS API, not specific hardware.</p>
<p>The HBIOS is modular and configurable. New hardware interfaces can be
added in the form of straightforward driver modules. Within certain
constraints, new hardware platforms can be supported by simply adjusting
values in a build configuration file.</p>
<p>RomWBW is geared toward hardware being developed in modern
retro-computing hobbyist communities, not as replacement software for
legacy hardware. As a result, RomWBW requires at least 128KB of bank
switched RAM.</p>
<p>The CP/M family of operating systems has been adapted to run under
RomWBW including CP/M 2.2, Z-System, CP/M 3, and several other variants.</p>
<p>RomWBW firmware (ROM) includes:</p>
<ul>
<li>
<p>System startup code (bootstrap) and bootloader</p>
</li>
<li>
<p>A basic system/debug monitor</p>
</li>
<li>
<p>HBIOS (Hardware BIOS) with support for most typical hardware
components used in Z80 family computers</p>
</li>
<li>
<p>Diagnostics and customizable debugging information.</p>
</li>
<li>
<p>ROM-hosted operating systems (both CP/M 2.2 and Z-System)</p>
</li>
<li>
<p>A ROM disk containing the standard OS applications and a RAM disk for
working storage.</p>
</li>
</ul>
<p>It is appropriate to note that much of the code and components that make
up a complete RomWBW package are derived from pre-existing work. Most
notably, the embedded operating systems are simply ROM-based copies of
generic CP/M or ZSDOS. Much of the hardware support code was originally
produced by other members of the RetroBrew Computers Community.</p>
<p>The remainder of this document focuses on RomWBW HBIOS which is the
fundamental basis of RomWBW.</p>
<h1 id="background">Background</h1>
<p>The Z80 CPU architecture has a limited, 64K address range. In general,
this address space must accommodate a running application, disk
operating system, and hardware support code.</p>
<p>Modern retro-computing Z80 CPU platforms provide a physical address
space that is much larger than the CPU address space (typically 512K or
1MB of physical RAM). This additional memory can be made available to
the CPU using a technique called bank switching. To achieve this, the
physical memory is divided up into chunks (banks) of 32K each. A
designated area of the CPU’s 64K address space is then reserved to “map”
any of the physical memory chunks. You can think of this as a window
that can be adjusted to view portions of the physical memory in 32K
blocks. In the case of RomWBW, the lower 32K of the CPU address space is
used for this purpose (the window). The upper 32K of CPU address space
is assigned a fixed 32K area of physical memory that never changes. The
lower 32K can be “mapped” on the fly to any of the 32K banks of physical
memory at a time. The primary constraint is that the CPU cannot be
executing code in the lower 32K of CPU address space at the time that a
bank switch is performed.</p>
<p>By utilizing the pages of physical RAM for specific purposes and
swapping in the correct page when needed, it is possible to utilize
substantially more than 64K of RAM. Because the retro-computing
community has now produced a very large variety of hardware, it has
become extremely important to implement a bank switched solution to
accommodate the maximum range of hardware devices and desired
functionality.</p>
<h1 id="general-design-strategy">General Design Strategy</h1>
<p>The design goal is to locate as much of the hardware dependent code as
possible out of normal 64KB CP/M address space and into a bank switched
area of memory. A very small code shim (proxy) is located in the top 512
bytes of CPU memory. This proxy is responsible for redirecting all
hardware BIOS (HBIOS) calls by swapping the “driver code” bank of
physical RAM into the lower 32K and completing the request. The
operating system is unaware this has occurred. As control is returned to
the operating system, the lower 32KB of memory is switched back to the
original memory bank.</p>
<p>The HBIOS functions are invoked simply by placing function parameters in
Z80 registers and calling an address within the HBIOS proxy.
Additionally, HBIOS implements a complete hardware interrupt management
framework. When a hardware interrupt occurs, control vectors through the
HBIOS proxy which saves the machine state, selects the HBIOS driver bank
into memory, and transfers control to the registered driver’s interrupt
handler. Upon completion of interrupt processing, control returns via
the HBIOS proxy, machine state is restored, and normal processing
resumes. The interrupt management framework supports Z80 interrupt modes
1, 2, and 3 (Z280).</p>
<p>HBIOS is completely agnostic with respect to the operating system (it
does not know or care what operating system is using it). The operating
system makes simple calls to HBIOS to access any desired hardware
functions. Since the HBIOS proxy occupies only 512 bytes at the top of
memory, the vast majority of the CPU memory is available to the
operating system and the running application. As far as the operating
system is concerned, all of the hardware driver code has been magically
implemented inside of the small 512 byte area at the top of the CPU
address space.</p>
<p>Unlike some other Z80 bank switching schemes, there is no attempt to
build bank switching into the operating system itself. This is
intentional so as to ensure that any operating system can easily be
adapted without requiring invasive modifications to the operating system
itself. This also keeps the complexity of memory management completely
away from the operating system and applications.</p>
<p>There are some operating systems that have built-in support for bank
switching (e.g., CP/M 3). These operating systems are allowed to make
use of the bank switched memory and are compatible with HBIOS. However,
it is necessary that the customization of these operating systems take
into account the banks of memory used by HBIOS and not attempt to use
those specific banks.</p>
<p>Note that all code and data are located in RAM memory during normal
execution. While it is possible to use ROM memory to run code, it would
require that more upper memory be reserved for data storage. It is
simpler and more memory efficient to keep everything in RAM. At startup
(boot) all required code is copied to RAM (shadowed) for subsequent
execution.</p>
<h1 id="runtime-memory-layout">Runtime Memory Layout</h1>
<p>RomWBW divides the standard 64KB Z80 address space into 2 sections. The
lower 32KB is the “banked” area. This is the area that will contain any
of the 32KB chunks of physical RAM based on which bank is currently
selected. The upper 32KB is “fixed”. This area of memory is never
swapped out and is used to contain software and operating systems that
must remain in the Z80 address space.</p>
<p>Throughout this document, this mechanism of selecting banks of memory
into the lower 32K is referred to as memory management. Achieving this
functionality requires some type of hardware which is generally referred
to as the system’s Memory Management Unit (MMU). RomWBW supports a
variety of MMUs – but they all perform the same function of swapping
in/out banks of memory in the lower 32K of CPU address space.</p>
<p>Figure 4.1 depicts the memory layout for a system running the CP/M
operating system. Applications residing in TPA invoke BDOS services of
CP/M, BDOS invokes the custom CBIOS APIs, and finally CBIOS invokes
HBIOS functions as needed by calling into the HBIOS proxy. The HBIOS
proxy swaps in the HBIOS bank as needed to perform the requested
function.</p>
<p>Additional banks of RAM are used to create a virtual disk drive.</p>
<figure>
<img src="Graphics/BankSwitchedMemory.svg" style="width:100.0%"
alt="Bank Switched Memory Layout" />
<figcaption aria-hidden="true">Bank Switched Memory Layout</figcaption>
</figure>
<h2 id="bank-id">Bank Id</h2>
<p>RomWBW utilizes a specific assignment of memory banks for dedicated
purposes. A numeric Bank Id is used to refer to the memory banks. The
Bank Id is a single byte. In general, the Bank Id simply refers to each
of the 32K banks in sequential order. In other words, Bank Id 0 is the
first physical 32K, Bank Id 1 is the second, etc. However, the high
order bit of the Bank Id has a special meaning. If it is 0, it indicates
a ROM bank is being referred to. If it is 1, it indicates a RAM bank is
being referred to.</p>
<p>For example, let’s say we have a typical system with 512KB of ROM and
512KB of RAM. The following table demonstrates how Bank Ids represent
areas of physical memory.</p>
<table>
<thead>
<tr>
<th><strong>Physical Memory</strong></th>
<th><strong>Type</strong></th>
<th><strong>Physical Bank</strong></th>
<th><strong>Bank Id</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>0x000000-0x007FFF</td>
<td>ROM</td>
<td>0</td>
<td>0x00</td>
</tr>
<tr>
<td>0x008000-0x00FFFF</td>
<td>ROM</td>
<td>1</td>
<td>0x01</td>
</tr>
<tr>
<td>0x010000-0x07FFFF</td>
<td>ROM</td>
<td>2-15</td>
<td>0x02-0x0F</td>
</tr>
<tr>
<td>0x080000-0x087FFF</td>
<td>RAM</td>
<td>16</td>
<td>0x80</td>
</tr>
<tr>
<td>0x088000-0x08FFFF</td>
<td>RAM</td>
<td>17</td>
<td>0x81</td>
</tr>
<tr>
<td>0x090000-0x0FFFFF</td>
<td>RAM</td>
<td>18-31</td>
<td>0x82-0x8F</td>
</tr>
</tbody>
</table>
<p>Note that Bank Id 0x00 is <strong>always</strong> the first bank of ROM and 0x80 is
<strong>always</strong> the first bank of RAM. If there were more banks of physical
ROM, they would be assigned Bank Ids starting with 0x10. Likewise,
additional bank of physical RAM would be assigned Bank Ids starting with
0x90.</p>
<p>The Bank Id is used in all RomWBW API functions when referring to the
mapping of banks to the lower 32K bank area of the processor. In this
way, all RomWBW functions can refer to a generic Bank Id without needing
to understand how a specific hardware platform accesses the physical
memory areas. A single routine within the HBIOS is implemented for each
memory manager that maps Bank Ids to physical memory.</p>
<h2 id="bank-assignments">Bank Assignments</h2>
<p>RomWBW requires dedicated banks of memory for specific purposes. It uses
Bank Ids via an algorithm to make these assignments. The following table
describes the way the banks are assigned. The Typical column shows the
specific values that would be assigned for a common system with 512KB of
ROM and 512KB of RAM (nROM=16, nRAM=16).</p>
<table>
<thead>
<tr>
<th><strong>Bank Id</strong></th>
<th><strong>Identity</strong></th>
<th><strong>Typical</strong></th>
<th><strong>Purpose</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>0x00</td>
<td>BID_BOOT</td>
<td>0x00</td>
<td>Boot Bank (HBIOS image)</td>
</tr>
<tr>
<td>0x01</td>
<td>BID_IMG0</td>
<td>0x01</td>
<td>Boot Loader, Monitor, ROM OSes, ROM Apps</td>
</tr>
<tr>
<td>0x02</td>
<td>BID_IMG1</td>
<td>0x02</td>
<td>ROM Apps</td>
</tr>
<tr>
<td>0x03</td>
<td>BID_IMG2</td>
<td>0x03</td>
<td>\&lt;Reserved&gt;</td>
</tr>
<tr>
<td>0x04</td>
<td>BID_ROMD0</td>
<td>0x04</td>
<td>First ROM Disk Bank</td>
</tr>
<tr>
<td>nROM - 1</td>
<td></td>
<td>0x0F</td>
<td>Last ROM Disk Bank</td>
</tr>
<tr>
<td>0x80</td>
<td>BID_BIOS</td>
<td>0x80</td>
<td>HBIOS (working copy)</td>
</tr>
<tr>
<td>0x81</td>
<td>BID_RAMD0</td>
<td>0x81</td>
<td>First RAM Disk Bank</td>
</tr>
<tr>
<td>0x80 + nRAM - 8</td>
<td></td>
<td>0x88</td>
<td>Last RAM Disk Bank</td>
</tr>
<tr>
<td>0x80 + nRAM - 7</td>
<td>BID_APP0</td>
<td>0x89</td>
<td>First Application Bank</td>
</tr>
<tr>
<td>0x80 + nRAM - 5</td>
<td></td>
<td>0x8B</td>
<td>Last Application Bank</td>
</tr>
<tr>
<td>0x80 + nRAM - 4</td>
<td>BID_BUF</td>
<td>0x8C</td>
<td>OS Disk Buffers</td>
</tr>
<tr>
<td>0x80 + nRAM - 3</td>
<td>BID_AUX</td>
<td>0x8D</td>
<td>OS Code Bank</td>
</tr>
<tr>
<td>0x80 + nRAM - 2</td>
<td>BID_USR</td>
<td>0x8E</td>
<td>User Bank (CP/M TPA)</td>
</tr>
<tr>
<td>0x80 + nRAM - 1</td>
<td>BID_COM</td>
<td>0x8F</td>
<td>Common Bank</td>
</tr>
</tbody>
</table>
<p>In this table, nROM and nRAM refer to the number of corresponding ROM
and RAM banks in the the system.</p>
<p>The contents of the banks referred to above are described in more detail
below:</p>
<p>Boot Bank:<br />
The Boot Bank receives control when a system is first powered on. It
contains a ROM (read-only) copy of the HBIOS. At boot, it does minimal
hardware initialization, then copies itself to the HBIOS bank in RAM,
then resumes execution from the RAM bank.</p>
<p>Boot Loader:<br />
The application that handles loading of ROM or Disk based applications
including operating systems. It copies itself to a RAM bank at the start
of it’s execution.</p>
<p>Monitor:<br />
The application that implements the basic system monitor functions. It
copies itself to a RAM bank at the start of it’s execution.</p>
<p>ROM OSes:<br />
Code images of CP/M 2.2 and Z-System which are copied to RAM and
executed when a ROM-based operating system is selected in the Boot
Loader.</p>
<p>ROM Applications:<br />
Various ROM-based application images such as BASIC, FORTH, etc. They can
be selected in the Boot Loader. The Boot Loader will copy the
application image to a RAM bank, then transfer control to it.</p>
<p>ROM Disk:<br />
A sequential series of banks assigned to provide the system ROM Disk
contents.</p>
<p>HBIOS:<br />
This bank hosts the running copy of the RomWBW HBIOS.</p>
<p>RAM Disk:<br />
A sequential series of banks assigned to provide the system RAM Disk.</p>
<p>Application Bank:<br />
A sequential series of banks that are available for use by applications
that wish to utilize banked memory.</p>
<p>OS Disk Buffers:<br />
This bank is used by CP/M 3 and ZPM3 for disk buffer storage.</p>
<p>OS Code Bank:<br />
This bank is used by CP/M 3 and ZPM3 as an alternate bank for code. This
allows these operating systems to make additional TPA space available
for applications.</p>
<p>User Bank:<br />
This is the default bank for applications to use. This includes the
traditional TPA space for CP/M.</p>
<p>Common Bank:<br />
This bank is mapped to the upper 32K of the processors memory space. It
is a fixed mapping that is never changed in normal RomWBW operation
hence the name “Common”.</p>
<h2 id="memory-managers">Memory Managers</h2>
<p>The following hardware memory managers are supported by RomWBW. The
operation of these memory managers is not documented here – please refer
to the documentation of your hardware provider for that.</p>
<p>Z2:<br />
Memory memory manager introduced by Sergey Kiselv in the Zeta 2 SBC.
Popular in many RCBus systems.</p>
<p>Z180:<br />
Memory manager built into the Z180 CPU</p>
<p>Z280:<br />
Memory manager built into the Z280 CPU</p>
<p>ZRC:<br />
Memory manager onboard the ZRC series of computers by Bill Shen.</p>
<p>SBC:<br />
Memory manager onboard the N8VEM SBC series of computers by Andrew
Lynch.</p>
<p>MBC:<br />
Memory manager onboard the Nhyodyne computer system by Andrew Lynch.</p>
<p>N8:<br />
Memory manager onboard the N8 SBC computer by Andrew Lynch.</p>
<p>EZ512:<br />
Memory manager onboard the EaZy80-512 Z80 CPU Module by Bill Shen.</p>
<p>RPH:<br />
Memory manager onboard the Rhyophyre computer system by Andrew Lynch.</p>
<p>The memory manager used is determined by the configuration choices that
are part of a RomWBW build process. A given ROM can only have a single
memory manager – it is not selected dynamically.</p>
<p>The configuration variable <code>MEMMGR</code> sets the memory mannager used by the
ROM build. It must be set to one of the above memory manager types. For
example, for the Z2 memory manager, <code>MEMMGR</code> should be set to <code>MM_Z2</code>.</p>
<p>Note that the term memory manager (MM) and memory management unit (MMU)
are used interchangeably in the documentation and code.</p>
<h1 id="disk-layout">Disk Layout</h1>
<h2 id="floppy-disk-layout">Floppy Disk Layout</h2>
<p>RomWBVW generally handles floppy disks in the same physical formats as
MS-DOS. However, the filesystem will normally be CP/M. The following
table lists the floppy disk formats used by RomWBW. In all cases, the
sector size is 512 bytes.</p>
<table>
<thead>
<tr>
<th><strong>HBIOS Media ID</strong></th>
<th style="text-align: right;"><strong>Capacity</strong></th>
<th style="text-align: right;"><strong>Tracks</strong></th>
<th style="text-align: right;"><strong>Heads</strong></th>
<th style="text-align: right;"><strong>Sectors</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>MID_FD720</td>
<td style="text-align: right;">720KB</td>
<td style="text-align: right;">80</td>
<td style="text-align: right;">2</td>
<td style="text-align: right;">9</td>
</tr>
<tr>
<td>MID_FD144</td>
<td style="text-align: right;">1440KB</td>
<td style="text-align: right;">80</td>
<td style="text-align: right;">2</td>
<td style="text-align: right;">18</td>
</tr>
<tr>
<td>MID_FD360</td>
<td style="text-align: right;">360KB</td>
<td style="text-align: right;">40</td>
<td style="text-align: right;">2</td>
<td style="text-align: right;">9</td>
</tr>
<tr>
<td>MID_FD120</td>
<td style="text-align: right;">1200KB</td>
<td style="text-align: right;">80</td>
<td style="text-align: right;">2</td>
<td style="text-align: right;">15</td>
</tr>
<tr>
<td>MID_FD111</td>
<td style="text-align: right;">1155KB</td>
<td style="text-align: right;">77</td>
<td style="text-align: right;">2</td>
<td style="text-align: right;">15</td>
</tr>
</tbody>
</table>
<h2 id="hard-disk-layout">Hard Disk Layout</h2>
<p>RomWBW supports the use of PC MBR hard disk partitioning (see
<a href="https://en.wikipedia.org/wiki/Disk_partitioning">https://en.wikipedia.org/wiki/Disk_partitioning</a>). When accessing a
hard disk device, HBIOS will look for a partition with type id 0x2E and
will use that partition exclusively for all storage. If a hard disk does
not have a valid partition table with a partition of type 0x2E, the
HBIOS will treat the hard disk as dedicated storage and will store data
starting at the first sector of the disk.</p>
<p>The use of a partition of type 0x2E is preferred for RomWBW and is
referred to as a “Modern” disk layout. If there is no RomWBW partition
on the disk, then the disk is designated as having a “Classic” disk
layout.</p>
<p>When a disk uses a RomWBW partition (type 0x2E) for storage (Modern
layout), the CP/M filesystems on that disk will utilize a format with
1,024 directory entries per filesystem. If there is no RomWBW partition,
the CP/M filesystems will have 512 directory entries per filesystem. As
a result, the Modern disk layout with a RomWBW partition is also
referred to as the “hd1k” layout indicating 1024 directory entries.
Similarly, the Classic disk layout (no partition of type 0x2E) is also
referred to as the “hd512” layout indicating 512 directory entries.</p>
<p>The layout type of any hard disk is simply dictated by the existence of
a RomWBW partition. This also means that if you add or remove a
partition table entry of type 0x2E on existing hard disk media, you will
lose access to any pre-existing CP/M data on the disk. If used,
partitioning should be done before putting any data on the disk.</p>
<p>WARNING: You <strong>can not</strong> mix the two hard disk layouts on one hard disk
device. You can use different layouts on different hard disk devices in
a single system though.</p>
<p>Regardless of whether a disk is Modern or Classic, RomWBW supports the
concept of CP/M filesystem slices. In general, CP/M filesystems are
limited to 8MB. Since current disk media is dramatically larger than
this, RomWBW implements a mechanism to put many (up to 256) CP/M
filesystems on a single disk. Each such filesystem is called a slice
referring to the idea that the disk has been sliced into many
independent CP/M filesystems. RomWBW allows the disk slices to be mapped
to the limited (16) drive letters of CP/M. The mapping can be modified
on-the-fly on a running system as desired.</p>
<p>If the case of a Modern disk layout (with a RomWBW partition), the
slices are contained within the defined partition area and the number of
slices is dictated by the size of the partition. In the case of a
Classic disk layout (no RomWBW partition), the slices are located at the
start of the disk (first sector). In either case, the slices are just
sequential areas of space on the hard disk.</p>
<p>RomWBW accesses all hard disks using Logical Block Addressing (pure
sector offset). When necessary, RomWBW simulates the following disk
geometry for operating systems:</p>
<ul>
<li>Sector = 512 Bytes</li>
<li>Track = 16 Sectors (8KB per Track)</li>
<li>Cylinder = 16 Tracks (256 Sectors per Cylinder, 128KB per Cylinder)</li>
</ul>
<p>If one is used, the FAT Partition must not overlap the CP/M slices. The
FAT partition does not need to start immediately after the CP/M slices
nor does it need to extend to the end of the hard disk. Its location and
size are entirely determined by its corresponding partition table entry.</p>
<p>Drive letters in CP/M are ASSIGNed to the numbered slices as desired.<br />
At boot, RomWBW automatically assigns up to 8 slices to drive letters
starting with the first available drive letter (typically C:).</p>
<p>Microsoft Windows will assign a single drive letter to the FAT partition
when the CF/SD Card is inserted. The drive letter assigned has no
relationship to the CP/M drive letters assigned to CP/M slices.</p>
<p>In general, Windows, MacOS, or Linux know nothing about the CP/M slices
and CP/M knows nothing about the FAT partition. However, the FAT
application can be run under CP/M to access the FAT partition
programmatically.</p>
<p>Before being used, A CP/M slice must be (re)initialized using the CP/M
command CLRDIR. A CP/M slice can be made bootable by copying a system
image to the System Area using SYSCOPY.</p>
<p>The FAT partition can be created from CP/M using the FDISK80
application. The FAT partition can be initialized using the FAT
application from CP/M using the command <code>FAT FORMAT n:</code> where n is the
RomWBW disk unit number containing the FAT partition to be formatted.</p>
<h3 id="modern-hard-disk-layout-hd1k">Modern Hard Disk Layout (hd1k)</h3>
<figure>
<img src="Graphics/hd1k.svg" alt="Modern Disk Layout" />
<figcaption aria-hidden="true">Modern Disk Layout</figcaption>
</figure>
<p>The CP/M filesystem on a Modern disk will accommodate 1,024 directory
entries.</p>
<p>The CP/M slices reside entirely within a hard disk partition of type
0x2E. The number of slices is determined by the number of slices that
fit within the partition spaces allocated up to the maximum of 256.</p>
<h3 id="classic-hard-disk-layout-hd512">Classic Hard Disk Layout (hd512)</h3>
<figure>
<img src="Graphics/hd512.svg" alt="Classic Disk Layout" />
<figcaption aria-hidden="true">Classic Disk Layout</figcaption>
</figure>
<p>The CP/M filesystem on a Classic disk will accommodate 512 directory
entries.</p>
<p>The CP/M slices reside on the hard disk starting at the first sector of
the hard disk. The number of CP/M slices is not explicitly recorded
anywhere on the hard disk. It is up to the system user to know how many
slices are being used based on the size of the hard disk media and/or
the start of a FAT partition.</p>
<p>A partition table may exist within the first sector of the first slice.
For Classic disks, the partition table defines only the location and
size of the FAT partition. The Partition Table does not control the
location or number of CP/M slices in any way.</p>
<p>The Partition Table resides in a sector that is shared with the System
Area of CP/M Slice 0. However, the RomWBW implementation of CP/M takes
steps to avoid changing or corrupting the Partition Table area.</p>
<p>The FAT partition can be created from CP/M using the FDISK80
application. The user is responsible for ensuring that the start of the
FAT partition does not overlap with the area they intend to use for CP/M
slices. FDISK80 has a Reserve option to assist with this.</p>
<h3 id="mapping-to-media-id">Mapping to Media ID</h3>
<p>HBIOS has a definition of “Media ID”, which defines the type and
physical properties of disk media provided by an underlying storage
device. For a complete list of Media ID’s please see <a href="#disk-inputoutput-dio">Disk Input/Output
(DIO)</a>.</p>
<p>There are two important Media ID’s relating to Hard Disk Layouts:</p>
<table>
<thead>
<tr>
<th><strong>Media</strong></th>
<th style="text-align: right;"><strong>ID</strong></th>
<th><strong>Format / Meaning</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>MID_HD</td>
<td style="text-align: right;">4</td>
<td>Classic Disk Layout (hd512) <em>–and–</em> HBIOS Hard Disk Drive</td>
</tr>
<tr>
<td>MID_HDNEW</td>
<td style="text-align: right;">10</td>
<td>Modern Disk Layout (hd1k)</td>
</tr>
</tbody>
</table>
<p>HBIOS typically does not understand the format of data on a device,
instead just treating all hard disks as raw sectors. <code>MID_HD</code> is the
typical Media ID used by HBIOS to describe high capacity hard disk media</p>
<p>When the Modern Disk Layout was added, the <code>MID_HDNEW</code>, was added to
differentiate (at the operating system level) between the Classic and
Modern layouts.</p>
<p>However HBIOS itself typically does NOT make this distinction, since the
use of these two formats is determined by the operating system based on
the partition table on the media. There are two important HBIOS
functions that deal with Media ID.</p>
<ul>
<li>
<p><a href="#function-0x18-disk-media-diomedia">Function 0x18 – Disk Media
(DIOMEDIA)</a></p>
</li>
<li>
<p><a href="#function-0xe0-calculate-slice-extslice">Function 0xE0 – Calculate Slice
(EXTSLICE)</a></p>
</li>
</ul>
<h1 id="system-boot-process">System Boot Process</h1>
<p>A multi-phase boot strategy is employed. This is necessary because at
cold start, the CPU is executing code from ROM in lower memory which is
the same area that is bank switched.</p>
<p>RomWBW supports multiple boot techniques as described below. The most
common of these is the ROM boot.</p>
<h2 id="rom-boot">ROM Boot</h2>
<p>The ROM boot process normally begins with a system cold start (power on
or hardware reset). The hardware is responsible for ensuring that the
lower 32K of CPU memory (bank window) is mapped to the initial 32K of
the ROM. The Z80 CPU begins execution at address zero which will be
address zero of the ROM.</p>
<p>The following steps occur during the ROM boot process:</p>
<ol>
<li>
<p>The ROM code performs basic hardware initialization and ensures that
the top 32K of CPU memory is mapped to the proper RAM bank.</p>
</li>
<li>
<p>The ROM code installs the HBIOS proxy code into the top 512 bytes of
the CPU memory (0xFE00-0xFFFF).</p>
</li>
<li>
<p>Using the proxy code services, the full HBIOS code is copied from
the ROM bank to the RAM bank that it will use for normal processing.</p>
</li>
<li>
<p>Again using the proxy code services, the RAM copy of HBIOS is
activated in the bank window and execution transitions to the RAM
copy of HBIOS.</p>
</li>
<li>
<p>The HBIOS initializes the system console so that output can now be
displayed to the user.</p>
</li>
<li>
<p>The HBIOS now performs the full hardware discovery and
initialization process while displaying it’s progress.</p>
</li>
<li>
<p>The HBIOS displays a final summary of the hardware device unit
assignments and various configuration information.</p>
</li>
<li>
<p>The HBIOS loads the RomWBW Boot Loader from ROM into RAM and jumps
to it.</p>
</li>
</ol>
<p>At this point, the user would normally use Boot Loader commands to
select and launch an operating system or applications from either ROM or
disk.</p>
<p>Note that the boot process is entirely operating system agnostic. It is
unaware of the operating system being loaded. The Boot Loader prompts
the user for the location of the binary image to load, but does not know
anything about what is being loaded (the image is usually an operating
system, but could be any executable code image). Once the Boot Loader
has loaded the image at the selected location, it will transfer control
to it. Assuming the typical situation where the image was an operating
system, the loaded operating system will then perform its own
initialization and begin normal operation.</p>
<h2 id="application-boot">Application Boot</h2>
<p>Once the system is running (operating system loaded), it is possible to
reboot the system from a system image (file) contained on the OS file
system. This is referred to as an “Application Boot”. The process is
similar to a ROM boot, but the HBIOS code is loaded from an image file
instead of ROM. This boot technique is useful to: 1) test a new build of
a system image before programming it to the ROM; or 2) easily switch
between system images on the fly.</p>
<p>During the RomWBW build process, one of the output files produced is an
actual CP/M application (an executable .COM program file). Like the
normal .ROM files, this file is placed in the Binary directory with the
same name as the ROM file, but with the file extension of .ROM. Once you
have a running CP/M (or compatible) system, you can upload/copy this
application file to the filesystem. By executing this file, you will
initiate an Application Boot using the system image contained in the
application file itself.</p>
<p>Upon execution, the Application Boot program is loaded into memory by
the previously running operating system starting at \$0100. Note that
the program image contains a full copy of the HBIOS to be installed and
run. Once the Application Boot program is loaded by the previous
operating system, control is passed to it and it performs a system
initialization similar to the ROM Boot, but using the image loaded in
RAM. Once the new HBIOS completes its initialization, it will launch the
Boot Loader just like a ROM boot.</p>
<p>The Application Boot program actually contains two other components
beyond the new HBIOS. It has a copy of the Boot Loader and a copy of the
Z-System OS. This is done in case the new HBIOS requires updated
versions of the Boot Loader or OS to run. The Boot Loader is aware of
this boot mode and automatically adapts it’s menu appropriately.</p>
<p>If you restart your system, then it will revert to a ROM Boot from the
currently installed ROM.</p>
<h2 id="ram-boot">RAM Boot</h2>
<p>Some hardware supported by RomWBW has a special mechanism for loading
the boot and HBIOS code. These systems have no ROM chips. However, they
have a small hardware bootstrap that loads a chunk of code from a disk
device directly into RAM at system startup.</p>
<p>The startup then proceeds very much like the Application Boot process
described above. HBIOS is installed in its operating bank and control is
passed to the Boot Loader.</p>
<h2 id="boot-recovery">Boot Recovery</h2>
<p>To assist users when driver faults or mis-configuration causes a boot
failure, RomWBW supports a limited recovery capability. This is achieved
by allowing the user to reboot their machine, loading a minimal driver
set. Implementation of this feature requires a hardware input “BOOT
RECOVERY” button to be available and appropriate software configuration
to be completed in the HBIOS.</p>
<p>When implemented, holding the “BOOT RECOVERY” button in after a reset or
power cycle will cause the normal driver load process to be skipped in
preference to a minimal set of drivers being loaded.</p>
<p>Typically this would be: Serial communication, RAM disk and parallel
port IDE interface drivers.</p>
<p>Platforms supporting this option currently are the MBC, Duodyne and
latter version of the SBC.</p>
<h1 id="configuration">Configuration</h1>
<h2 id="romwbw-nvram-configuration">RomWBW NVRAM Configuration</h2>
<p>On systems with RTC devices (that have Non-Volatile RAM), RomWBW
supports storing some limited configuration option options inside this
RAM.</p>
<p>Several configuration options are currently supported; these are known
as Switches. The following switch ID’s are defined, and described in
sections below.</p>
<table>
<thead>
<tr>
<th>Switch Number</th>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>0x00</td>
<td>-reserved-</td>
<td>Reserved</td>
</tr>
<tr>
<td>0x01</td>
<td>Boot Options</td>
<td>ROM or Disk Boot Settings</td>
</tr>
<tr>
<td>0x02</td>
<td>-n/a-</td>
<td>-n/a- high order byte of previous switch</td>
</tr>
<tr>
<td>0x03</td>
<td>Auto Boot</td>
<td>Automatically boot enabled without user input</td>
</tr>
<tr>
<td>0x04 - 0xFE</td>
<td>-future-</td>
<td>Future general usage</td>
</tr>
<tr>
<td>0xFF</td>
<td>Status Reset</td>
<td>Get Status or Reset Switches to Default</td>
</tr>
</tbody>
</table>
<p>RomWBW uses bytes located at the start of RTC NVRAM, and includes a
Parity check of the bytes in NVRAM to check for authenticity before
using the configuration.</p>
<table>
<thead>
<tr>
<th>NVRAM Byte</th>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>0x00</td>
<td>Header Byte</td>
<td>Header Signature Byte ‘W’</td>
</tr>
<tr>
<td>0x01 - 0x03</td>
<td>Switch Data</td>
<td>Actual Switch Data</td>
</tr>
<tr>
<td>0x04</td>
<td>Parity Check</td>
<td>Checksum byte to check integrity</td>
</tr>
</tbody>
</table>
<p>The above data is copied into the HBIOS Configuration Block (HCB) at
startup at the location starting at CB_SWITCHES.</p>
<h3 id="boot-options-nvsw_bootopts">Boot Options (NVSW_BOOTOPTS)</h3>
<p>16 bit Switch defining the ROM application or Disk device to boot if
automatic booting is enabled.</p>
<table>
<thead>
<tr>
<th>Bit 15</th>
<th>Bits 14-8</th>
<th>Bits 7-0</th>
</tr>
</thead>
<tbody>
<tr>
<td>1 = ROM App</td>
<td>-undefined-</td>
<td>App to Boot (Char)</td>
</tr>
<tr>
<td>0 = Disk</td>
<td>Disk Unit (0-127)</td>
<td>Disk Slice (0-255)</td>
</tr>
</tbody>
</table>
<h3 id="auto-boot-nvsw_autoboot">Auto Boot (NVSW_AUTOBOOT)</h3>
<p>8 bit Switch defining if the system should auto boot at startup.</p>
<table>
<thead>
<tr>
<th>Bits 7-6</th>
<th>Bit 5</th>
<th>Bit 4</th>
<th>Bits 3-0</th>
</tr>
</thead>
<tbody>
<tr>
<td>-unused-</td>
<td>1 = Auto Boot Enabled</td>
<td>-unused-</td>
<td>0 = Immediate Boot with no delay</td>
</tr>
<tr>
<td>-unused-</td>
<td>1 = Auto Boot Enabled</td>
<td>-unused-</td>
<td>(1-15) Timeout (seconds) before boot</td>
</tr>
<tr>
<td>-unused-</td>
<td>0 = Auto Boot Disabled</td>
<td>-unused-</td>
<td>-undefined-</td>
</tr>
</tbody>
</table>
<h3 id="status-reset-0xff">Status Reset (0xFF)</h3>
<p>The Status Reset switch is not a general purpose switch, it is a control
mechanism to allow the global status of all switches to be determined.
The meaning of the switch is different for Read (Get Status) and Write
(Reset NVRAM)</p>
<h4 id="get-get-status">GET (Get Status)</h4>
<p>The read Get Status of switches. This returns very specific values from
the function call.</p>
<table>
<thead>
<tr>
<th>Status</th>
<th>A Register</th>
<th>Z / NZ Flag</th>
</tr>
</thead>
<tbody>
<tr>
<td>NVRAM does not exist</td>
<td>A=0</td>
<td>NZ flag set</td>
</tr>
<tr>
<td>NVRAM exists, but has not been initialised</td>
<td>A=1</td>
<td>NZ flag set</td>
</tr>
<tr>
<td>NVRAM exists, and has been fully initialised</td>
<td>A=‘W’</td>
<td>Z flag set</td>
</tr>
</tbody>
</table>
<h4 id="set-reset-nvram">SET (Reset NVRAM)</h4>
<p>Reset NVRAM to default values. This will wipe any existing data and set
default values into NVRAM.</p>
<h1 id="driver-model">Driver Model</h1>
<p>The framework code for bank switching also allows hardware drivers to be
implemented mostly without concern for memory management. Drivers are
coded to simply implement the HBIOS functions appropriate for the type
of hardware being supported. When the driver code gets control, it has
already been mapped to the CPU address space and simply performs the
requested function based on parameters passed in registers. Upon return,
the bank switching framework takes care of restoring the original memory
layout expected by the operating system and application.</p>
<p>Drivers do need to be aware of the bank switching if a buffer address is
being used in the function call.</p>
<ul>
<li>
<p>If the buffer address is in the lower 32K of RAM, then the memory it
points to will be from the User Bank, not the HBIOS bank which is now
active. In this case, the driver must use an inter-bank copy to access
the data.</p>
</li>
<li>
<p>If the buffer address is in the top 32K of RAM, then the driver will
have access to it directly even after a bank switch, so no special
steps are required.</p>
</li>
</ul>
<p>For some functions, the location of the buffer is required to be in the
top 32K of RAM to simplify the operation of the driver.</p>
<p>It is usually better if the OS or application calling a buffered
function places the buffer in the top 32K because this may avoid a
double-copy operation.</p>
<p>If driver code must make calls to other code, drivers, or utilities in
the HBIOS bank, it must make those calls directly (it must not use RST
08). This is to avoid a nested bank switch which is not supported at
this time.</p>
<h1 id="character-emulation-video-services">Character / Emulation / Video Services</h1>
<p>In addition to a generic set of routines to handle typical character
input/output, HBIOS also includes functionality for managing built-in
video display adapters. To start with there is a basic set of character
input/output functions, the CIOXXX functions, which allow for simple
character data streams. These functions fully encompass routing byte
stream data to/from serial ports. Note that there is a special character
pseudo-device called “CRT”. When characters are read/written to/from the
CRT character device, the data is actually passed to a built-in terminal
emulator which, in turn, utilizes a set of VDA (Video Display Adapter)
functions (such as cursor positioning, scrolling, etc.).</p>
<p>Figure 9.1 depicts the relationship between these components of HBIOS
video processing:</p>
<figure>
<img src="Graphics/CharacterEmulationVideoServices.svg"
style="width:100.0%" alt="Character / Emulation / Video Services" />
<figcaption aria-hidden="true">Character / Emulation / Video
Services</figcaption>
</figure>
<p>Normally, the operating system will simply utilize the CIOXXX functions
to send and receive character data. The Character I/O Services will
route I/O requests to the specified physical device which is most
frequently a serial port (such as UART or ASCI). As shown above, if the
CRT device is targeted by a CIOXXX function, it will actually be routed
to the Emulation Services which implement TTY, ANSI, etc. escape
sequences. The Emulation Services subsequently rely on the Video Display
Adapter Services as an additional layer of abstraction. This allows the
emulation code to be completely unaware of the actual physical device
(device independent). Video Display Adapter (VDA) Services contains
drivers as needed to handle the available physical video adapters.</p>
<p>Note that the Emulation and VDA Services API functions are available to
be called directly. Doing so must be done carefully so as to not corrupt
the “state” of the emulation logic.</p>
<p>Before invoking CIOXXX functions targeting the CRT device, it is
necessary that the underlying layers (Emulation and VDA) be properly
initialized. The Emulation Services must be initialized to specify the
desired emulation and specific physical VDA device to target. Likewise,
the VDA Services may need to be initialized to put the specific video
hardware into the proper mode, etc.</p>
<h1 id="hbios-reference">HBIOS Reference</h1>
<h2 id="invocation">Invocation</h2>
<p>HBIOS functions are invoked by placing the required parameters in CPU
registers and executing an <code>RST 08</code> instruction. Note that HBIOS does
not preserve register values that are unused. However, the values of the
Z80 alternate registers and IX/IY will be preserved (these registers may
be used within HBIOS, but will be saved and restored internally).</p>
<p>An alternate method of invoking HBIOS functions is to use <code>CALL $FFF0</code>.
Since the <code>RST 08</code> vector exists in page zero of the CPU address space,
it may be paged out when alternate memory banks are selected. If this
may be true when you are invoking a function, you should use the <code>CALL</code>
method.</p>
<p>Normally, applications will not call HBIOS functions directly. It is
intended that the operating system makes all HBIOS function calls.
Applications that are considered system utilities may use HBIOS, but
must be careful not to modify the operating environment in any way that
the operating system does not expect.</p>
<p>In general, the desired function is placed in the B register. Register C
is frequently used to specify a sub-function or a target device unit
number. Additional registers are used as defined by the specific
function. Register A should be used to return function result
information. See below for result code definitions.</p>
<p>The character, disk, and video device functions all refer to target
devices using a logical device unit number that is passed in the C
register. Keep in mind that these unit numbers are assigned dynamically
at HBIOS initialization during the device discovery process. The
assigned unit numbers are displayed on the console at the conclusion of
device initialization. The unit assignments will never change after
HBIOS initialization. However, they can change at the next boot if there
have been hardware or BIOS customization changes. Code using HBIOS
functions should not assume fixed unit assignments.</p>
<p>Some functions utilize pointers to memory buffers. Unless otherwise
stated, such buffers can be located anywhere in the Z80 CPU 64K address
space. However, performance sensitive buffers (primarily disk I/O
buffers) will require double-buffering if the caller’s buffer is in the
lower 32K of CPU address space. For optimal performance, such buffers
should be placed in the upper 32K of CPU address space.</p>
<p>HBIOS also implements a small number of core functions in the HBIOS
proxy area at the top of RAM. These exist primarily to facilitate the
operation of normal HBIOS function calls. However, they are available to
be used by OSes and applications. These functions can only be invoked by
calling into a jump table in upper RAM.</p>
<h2 id="result-codes">Result Codes</h2>
<p>The following function result codes are defined generically for all
HBIOS functions. Most function calls will return a result in register A.</p>
<table>
<thead>
<tr>
<th style="text-align: right;"><strong>Code</strong></th>
<th><strong>Definition</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: right;">0</td>
<td>function succeeded</td>
</tr>
<tr>
<td style="text-align: right;">-1</td>
<td>undefined error</td>
</tr>
<tr>
<td style="text-align: right;">-2</td>
<td>function not implemented</td>
</tr>
<tr>
<td style="text-align: right;">-3</td>
<td>invalid function</td>
</tr>
<tr>
<td style="text-align: right;">-4</td>
<td>invalid unit number</td>
</tr>
<tr>
<td style="text-align: right;">-5</td>
<td>out of memory</td>
</tr>
<tr>
<td style="text-align: right;">-6</td>
<td>parameter out of range</td>
</tr>
<tr>
<td style="text-align: right;">-7</td>
<td>media not present</td>
</tr>
<tr>
<td style="text-align: right;">-8</td>
<td>hardware not present</td>
</tr>
<tr>
<td style="text-align: right;">-9</td>
<td>I/O error</td>
</tr>
<tr>
<td style="text-align: right;">-10</td>
<td>write request to read-only media</td>
</tr>
<tr>
<td style="text-align: right;">-11</td>
<td>device timeout</td>
</tr>
<tr>
<td style="text-align: right;">-12</td>
<td>invalid configuration</td>
</tr>
</tbody>
</table>
<h2 id="character-inputoutput-cio">Character Input/Output (CIO)</h2>
<p>Character Input/Output functions require that a Character Unit number be
specified in register C. This is the logical device unit number assigned
during the boot process that identifies all character devices uniquely.
A special value of 0x80 can be used for the Character Unit to refer to
the current console device.</p>
<p>All character units are assigned a Device Type ID which indicates the
specific hardware device driver that handles the unit. The table below
enumerates these values.</p>
<table>
<thead>
<tr>
<th><strong>Device Type</strong></th>
<th style="text-align: right;"><strong>ID</strong></th>
<th><strong>Description</strong></th>
<th><strong>Driver</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>CIODEV_UART</td>
<td style="text-align: right;">0x00</td>
<td>16C550 Family Serial Interface</td>
<td>uart.asm</td>
</tr>
<tr>
<td>CIODEV_ASCI</td>
<td style="text-align: right;">0x01</td>
<td>Z180 Built-in Serial Ports</td>
<td>asci.asm</td>
</tr>
<tr>
<td>CIODEV_TERM</td>
<td style="text-align: right;">0x02</td>
<td>Terminal</td>
<td>ansi.asm</td>
</tr>
<tr>
<td>CIODEV_PRPCON</td>
<td style="text-align: right;">0x03</td>
<td>PropIO Serial Console Interface</td>
<td>prp.asm</td>
</tr>
<tr>
<td>CIODEV_PPPCON</td>
<td style="text-align: right;">0x04</td>
<td>ParPortProp Serial Console Interface</td>
<td>ppp.asm</td>
</tr>
<tr>
<td>CIODEV_SIO</td>
<td style="text-align: right;">0x05</td>
<td>Zilog Serial Port Interface</td>
<td>sio.asm</td>
</tr>
<tr>
<td>CIODEV_ACIA</td>
<td style="text-align: right;">0x06</td>
<td>MC68B50 Asynchronous Interface</td>
<td>acia.asm</td>
</tr>
<tr>
<td>CIODEV_PIO</td>
<td style="text-align: right;">0x07</td>
<td>Zilog Parallel Interface Controller</td>
<td>pio.asm</td>
</tr>
<tr>
<td>CIODEV_UF</td>
<td style="text-align: right;">0x08</td>
<td>FT232H-based ECB USB FIFO</td>
<td>uf.asm</td>
</tr>
<tr>
<td>CIODEV_DUART</td>
<td style="text-align: right;">0x09</td>
<td>SCC2681 Family Dual UART</td>
<td>duart.asm</td>
</tr>
<tr>
<td>CIODEV_Z2U</td>
<td style="text-align: right;">0x0A</td>
<td>Zilog Z280 Built-in Serial Ports</td>
<td>z2u.asm</td>
</tr>
<tr>
<td>CIODEV_LPT</td>
<td style="text-align: right;">0x0B</td>
<td>Parallel I/O Controller</td>
<td>lpt.asm</td>
</tr>
<tr>
<td>CIODEV_ESPCON</td>
<td style="text-align: right;">0x0C</td>
<td>ESP32 VGA Console</td>
<td>esp.asm</td>
</tr>
<tr>
<td>CIODEV_ESPSER</td>
<td style="text-align: right;">0x0D</td>
<td>ESP32 Serial Port</td>
<td>esp.asm</td>
</tr>
<tr>
<td>CIODEV_SCON</td>
<td style="text-align: right;">0x0E</td>
<td>S100 Console</td>
<td>scon.asm</td>
</tr>
<tr>
<td>CIODEV_SSER</td>
<td style="text-align: right;">0x0F</td>
<td>Simple Serial Console</td>
<td>sser.asm</td>
</tr>
<tr>
<td>CIODEV_EZ80UART</td>
<td style="text-align: right;">0x10</td>
<td>eZ80 Built-in UART0 Interface</td>
<td>ez80uart.asm</td>
</tr>
</tbody>
</table>
<p>Character devices can usually be configured with line characteristics
such as speed, framing, etc. A word value (16 bit) is used to describe
the line characteristics as indicated below:</p>
<table>
<thead>
<tr>
<th style="text-align: right;"><strong>Bits</strong></th>
<th><strong>Characteristic</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: right;">15-14</td>
<td>Reserved (set to 0)</td>
</tr>
<tr>
<td style="text-align: right;">13</td>
<td>RTS</td>
</tr>
<tr>
<td style="text-align: right;">12-8</td>
<td>Baud Rate (see below)</td>
</tr>
<tr>
<td style="text-align: right;">7</td>
<td>DTR</td>
</tr>
<tr>
<td style="text-align: right;">6</td>
<td>XON/XOFF Flow Control</td>
</tr>
<tr>
<td style="text-align: right;">5</td>
<td>1 = Stick Parity(Mark/Space), 0 = Normal Parity (odd/even)</td>
</tr>
<tr>
<td style="text-align: right;">4</td>
<td>1 = Even/Space, 0 = Odd/Mark</td>
</tr>
<tr>
<td style="text-align: right;">3</td>
<td>Parity Enable (set for true)</td>
</tr>
<tr>
<td style="text-align: right;">2</td>
<td>Stop Bits (set for true)</td>
</tr>
<tr>
<td style="text-align: right;">1-0</td>
<td>Data Bits (5-8 encoded as 0-3)</td>
</tr>
</tbody>
</table>
<p>The 5-bit Baud Rate value (V) is encoded as V = 75 * 2^X * 3^Y. The
bits are defined as YXXXX.</p>
<p>Actual character values are a single byte (8 bits). The Character I/O
functions do not modify or interpret the values being sent/received so
they can be used to pass 8-bit binary data without corruption. Note that
some OSes will modify character data (truncate to 7 bits, etc.).</p>
<h3 id="function-0x00-character-input-cioin">Function 0x00 – Character Input (CIOIN)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x00</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Character Unit</td>
<td>E: Character</td>
</tr>
</tbody>
</table>
<p>Read and return a Character (E) from the specified Character Unit (C).
If no character(s) are available in the unit’s input buffer, this
function will wait indefinitely. The returned Status (A) is a standard
HBIOS result code.</p>
<h3 id="function-0x01-character-output-cioout">Function 0x01 – Character Output (CIOOUT)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x01</td>
<td>A: Status (0-OK, else error)</td>
</tr>
<tr>
<td>C: Character Unit</td>
<td></td>
</tr>
<tr>
<td>E: Character</td>
<td></td>
</tr>
</tbody>
</table>
<p>Send a Character (E) via the specified Character Unit (C). If there is
no space available in the unit’s output buffer, the function will wait
indefinitely. The returned Status (A) is a standard HBIOS result code.</p>
<h3 id="function-0x02-character-input-status-cioist">Function 0x02 – Character Input Status (CIOIST)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x02</td>
<td>A: Status / Characters Pending</td>
</tr>
<tr>
<td>C: Character Unit</td>
<td></td>
</tr>
</tbody>
</table>
<p>Return the count of Characters Pending (A) in the input buffer of the
specified Character Unit (C). If the unit has no input buffer or the
buffer utilization is not available, the function may return simply 0 or
1 where 0 means there is no character available and 1 means there is at
least one character available.</p>
<p>The value returned in register A is used as both a Status (A) code and
the return value. Negative values (bit 7 set) indicate a standard HBIOS
result (error) code. Otherwise, the return value represents the number
of characters in the input buffer.</p>
<h3 id="function-0x03-character-output-status-cioost">Function 0x03 – Character Output Status (CIOOST)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x03</td>
<td>A: Status / Space Free</td>
</tr>
<tr>
<td>C: Character Unit</td>
<td></td>
</tr>
</tbody>
</table>
<p>Return the count of buffer Space Free (A) for the specified Character
Unit (C). For example, if a 16 byte output buffer contains 6 characters
waiting to be sent out the unit’s serial interface, this function would
return 10; the number of positions available in the output buffer. If
the port has no output buffer or the buffer utilization is not
available, the function may return simply 0 or 1 where 0 means there is
no buffer space available and 1 means there is space in the output
buffer for at least one character.</p>
<p>The return value in register A is used as both a status code and the
return value. Negative values (bit 7 set) indicate a standard HBIOS
result (error) code. Otherwise, the return value represents the buffer
space available.</p>
<h3 id="function-0x04-character-io-initialization-cioinit">Function 0x04 – Character I/O Initialization (CIOINIT)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x04</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Character Unit</td>
<td></td>
</tr>
<tr>
<td>DE: Line Characteristics</td>
<td></td>
</tr>
</tbody>
</table>
<p>Condition the interface of the specified Character Unit (C) according to
the specified Line Characteristics (DE). The definition of the line
characteristics value is described above. If DE contains -1 (0xFFFF),
then the device will be reinitialized with the previous line
characteristics used (a reset) and any buffer contents will be flushed.
The Status (A) is a standard HBIOS result code.</p>
<p>Not all line characteristics are supported by all character interfaces.
It is up to the driver of the character unit to decide how to deal with
characteristics that are not available. For example, many character
drivers do not allow flow control settings (RTS/CTS, XON/XOFF) to be
modified dynamically. In most cases, these settings are ignored by the
driver in this function call.</p>
<h3 id="function-0x05-character-io-query-cioquery">Function 0x05 – Character I/O Query (CIOQUERY)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x05</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Character Unit</td>
<td>DE: Line Characteristics</td>
</tr>
</tbody>
</table>
<p>Returns the current Line Characteristics (DE) of the specified Character
Unit (C). The definition of the line characteristics value is described
above. The returned status (A) is a standard HBIOS result code.</p>
<h3 id="function-0x06-character-io-device-ciodevice">Function 0x06 – Character I/O Device (CIODEVICE)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x06</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Character Unit</td>
<td>C: Device Attributes</td>
</tr>
<tr>
<td></td>
<td>D: Device Type</td>
</tr>
<tr>
<td></td>
<td>E: Device Number</td>
</tr>
<tr>
<td></td>
<td>H: Device Mode</td>
</tr>
<tr>
<td></td>
<td>L: Device I/O Base Address</td>
</tr>
</tbody>
</table>
<p>Returns device information for the specified Character Unit (C). The
status (A) is a standard HBIOS result code.</p>
<p>The two high bits of Device Attribute (C) are: 00 = RS/232, 01 =
Terminal, 10 = Parallel. The remaining bits should be ignored and are
used internally.</p>
<p>Device Type (D) indicates the specific hardware driver that handles the
specified Character Unit. Values are listed at the start of this
section. Device Number (E) indicates the physical device number assigned
per driver. For example, a Device Type of 0x50 with a Device Number of 2
refers to the third port being handled by the SIO driver.</p>
<p>Device Mode (H) is used to indicate the variant of the chip or circuit
that is used by the specified unit. For example, for a UART, the value
indicates the chip variant. The Device I/O Base Address (L) indicates
the starting port address of the hardware interface that is servicing
the specified unit. Both of these values are considered driver specific.
Refer to the associated hardware driver for the values used.</p>
<h2 id="disk-inputoutput-dio">Disk Input/Output (DIO)</h2>
<p>Disk Input/Output functions require that a Disk Unit number be specified
in register C. This is the logical device unit number assigned during
the boot process that identifies all disk devices uniquely.</p>
<p>All character units are assigned a Device Type ID which indicates the
specific hardware device driver that handles the unit. The table below
enumerates their values.</p>
<table>
<thead>
<tr>
<th><strong>Device Type</strong></th>
<th style="text-align: right;"><strong>ID</strong></th>
<th><strong>Description</strong></th>
<th><strong>Driver</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>DIODEV_MD</td>
<td style="text-align: right;">0x00</td>
<td>Memory Disk</td>
<td>md.asm</td>
</tr>
<tr>
<td>DIODEV_FD</td>
<td style="text-align: right;">0x01</td>
<td>Floppy Disk</td>
<td>fd.asm</td>
</tr>
<tr>
<td>DIODEV_RF</td>
<td style="text-align: right;">0x02</td>
<td>RAM Floppy</td>
<td>rf.asm</td>
</tr>
<tr>
<td>DIODEV_IDE</td>
<td style="text-align: right;">0x03</td>
<td>IDE Disk</td>
<td>ide.asm</td>
</tr>
<tr>
<td>DIODEV_ATAPI</td>
<td style="text-align: right;">0x04</td>
<td>ATAPI Disk (not implemented)</td>
<td></td>
</tr>
<tr>
<td>DIODEV_PPIDE</td>
<td style="text-align: right;">0x05</td>
<td>PPIDE Disk</td>
<td>ppide.asm</td>
</tr>
<tr>
<td>DIODEV_SD</td>
<td style="text-align: right;">0x06</td>
<td>SD Card</td>
<td>sd.asm</td>
</tr>
<tr>
<td>DIODEV_PRPSD</td>
<td style="text-align: right;">0x07</td>
<td>PropIO SD Card</td>
<td>prp.asm</td>
</tr>
<tr>
<td>DIODEV_PPPSD</td>
<td style="text-align: right;">0x08</td>
<td>ParPortProp SD Card</td>
<td>ppp.asm</td>
</tr>
<tr>
<td>DIODEV_HDSK</td>
<td style="text-align: right;">0x09</td>
<td>SIMH HDSK Disk</td>
<td>hdsk.asm</td>
</tr>
<tr>
<td>DIODEV_PPA</td>
<td style="text-align: right;">0x0A</td>
<td>Iomega PPA Disk</td>
<td>ppa.asm</td>
</tr>
<tr>
<td>DIODEV_IMM</td>
<td style="text-align: right;">0x0B</td>
<td>Iomega IMM Disk</td>
<td>imm.asm</td>
</tr>
<tr>
<td>DIODEV_SYQ</td>
<td style="text-align: right;">0x0C</td>
<td>Syquest Sparq Disk</td>
<td>syq.asm</td>
</tr>
<tr>
<td>DIODEV_CHUSB</td>
<td style="text-align: right;">0x0D</td>
<td>CH375/376 USB Disk</td>
<td>ch.asm</td>
</tr>
<tr>
<td>DIODEV_CHSD</td>
<td style="text-align: right;">0x0E</td>
<td>CH375/376 SD Card</td>
<td>ch.asm</td>
</tr>
</tbody>
</table>
<p>A fixed set of media types are defined. The currently defined media
types identifiers are listed below. Each driver will support one or more
of the defined media types.</p>
<table>
<thead>
<tr>
<th><strong>Media</strong></th>
<th style="text-align: right;"><strong>ID</strong></th>
<th><strong>Format</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>MID_NONE</td>
<td style="text-align: right;">0</td>
<td>No media installed</td>
</tr>
<tr>
<td>MID_MDROM</td>
<td style="text-align: right;">1</td>
<td>ROM Drive</td>
</tr>
<tr>
<td>MID_MDRAM</td>
<td style="text-align: right;">2</td>
<td>RAM Drive</td>
</tr>
<tr>
<td>MID_RF</td>
<td style="text-align: right;">3</td>
<td>RAM Floppy (LBA)</td>
</tr>
<tr>
<td>MID_HD</td>
<td style="text-align: right;">4</td>
<td>Hard Disk (LBA) w/ 512 directory entries</td>
</tr>
<tr>
<td>MID_FD720</td>
<td style="text-align: right;">5</td>
<td>3.5” 720K Floppy</td>
</tr>
<tr>
<td>MID_FD144</td>
<td style="text-align: right;">6</td>
<td>3.5” 1.44M Floppy</td>
</tr>
<tr>
<td>MID_FD360</td>
<td style="text-align: right;">7</td>
<td>5.25” 360K Floppy</td>
</tr>
<tr>
<td>MID_FD120</td>
<td style="text-align: right;">8</td>
<td>5.25” 1.2M Floppy</td>
</tr>
<tr>
<td>MID_FD111</td>
<td style="text-align: right;">9</td>
<td>8” 1.11M Floppy</td>
</tr>
<tr>
<td>MID_HDNEW</td>
<td style="text-align: right;">10</td>
<td>Hard Disk (LBA) w/ 1024 directory entries</td>
</tr>
</tbody>
</table>
<p><strong>NOTE</strong>: HBIOS typically does not actually differentiate between MID_HD
and MID_HDNEW, it will generally only use MID_HD. See the section
<a href="#mapping-to-media-id">Mapping to Media ID</a> for information on this.</p>
<p>HBIOS supports both Cylinder/Head/Sector (CHS) and Logical Block
Addresses (CHS) when locating a sector for I/O (see DIOSEEK function).
For devices that are natively CHS (e.g., floppy disk), the HBIOS driver
can convert LBA values to CHS values according to the geometry of the
current media. For devices that are natively LBA (e.g., hard disk), the
HBIOS driver simulates CHS using a fictitious geometry provided by the
driver (typically 16 sectors per track and 16 heads per cylinder).</p>
<h3 id="function-0x10-disk-status-diostatus">Function 0x10 – Disk Status (DIOSTATUS)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x10</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Disk Unit</td>
<td></td>
</tr>
</tbody>
</table>
<p>Returns the driver specific Status (A) of the specified disk device unit
(C) based on the last operation performed.</p>
<p>The return value in register A is used as both a device status and a
standard HBIOS result code. Negative values (bit 7 set) indicate a
standard HBIOS result (error) code. Otherwise, the return value
represents a driver-specific device status. In all cases, the value 0
means OK.</p>
<h3 id="function-0x11-disk-reset-dioreset">Function 0x11 – Disk Reset (DIORESET)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x11</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Disk Unit</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function performs a device dependent reset operation on the Disk
Unit specified (C). The driver will clear any error status on the disk
unit, attempt to reset the interface, and flag the disk unit for
initialization on the next I/O function call. Any prior media
identification will be cleared. The returned Status (A) is a standard
HBIOS result code.</p>
<p>If the specified disk unit (C) is one of multiple units on a single
hardware bus, then all units on that bus will be reset. For example, if
the master disk on an IDE bus is reset, then the slave disk will also be
reset.</p>
<h3 id="function-0x12-disk-seek-dioseek">Function 0x12 – Disk Seek (DIOSEEK)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x12</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Disk Unit</td>
<td></td>
</tr>
<tr>
<td>DEHL: Sector Address</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function will set the desired sector to be used for the next I/O
operation on the specified Disk Unit (C). The returned Status (A) is a
standard HBIOS result code.</p>
<p>An actual seek operation is generally not performed on the disk hardware
by this function. The function typically just records the sector address
for subsequent I/O function calls.</p>
<p>The double-word Sector Address (DEHL) can represent either a Logical
Block Address (LBA) or a Cylinder/Head/Sector (CHS). Bit 7 of D is set
(1) for LBA mode and cleared (0) for CHS mode.</p>
<p>For LBA mode operation, the high bit is set and the rest of the
double-word is then treated as the logical sector address.</p>
<p>For CHS mode operation, the Sector Address (DEHL) registers are
interpreted as: D=Head, E=Sector, and HL=Track. All values (including
sector) are 0 relative.</p>
<p>Prior versions of the floppy driver did not accept LBA mode addresses.
However, this restriction has been removed as of HBIOS v3.1. At this
point, all disk drivers support both LBA and CHS addressing.</p>
<h3 id="function-0x13-disk-read-dioread">Function 0x13 – Disk Read (DIOREAD)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x13</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Disk Unit</td>
<td>E: Sectors Read</td>
</tr>
<tr>
<td>D: Buffer Bank ID</td>
<td></td>
</tr>
<tr>
<td>E: Sector Count</td>
<td></td>
</tr>
<tr>
<td>HL: Buffer Address</td>
<td></td>
</tr>
</tbody>
</table>
<p>Read Sector Count (E) sectors into the buffer located in Buffer Bank ID
(D) at Buffer Address (HL) starting at the Current Sector. The returned
Status (A) is a standard HBIOS result code.</p>
<p>The Current Sector is established by a prior DIOSEEK function call;
however, multiple read/write/verify function calls can be made after a
seek function. The Current Sector is incremented after each sector
successfully read. On error, the Current Sector will be the sector where
the error occurred. Sectors Read (E) indicates the number of sectors
successfully read.</p>
<p>The caller must ensure that the Buffer Address is large enough to
contain all sectors requested. Disk data transfers will be faster if the
buffer resides in the top 32K of memory because it avoids a double
buffer copy.</p>
<p>Also for buffers in the top 32K of memory the Bank ID is not strictly
required as this memory is alway mapped to the common bank. For buffers
in the bottom 32KB ram, the Bank ID is used to identify the bank to use
for the buffer. If you do not wih to use banked memory you will need to
provide the current Bank ID, which can be obtained using <a href="#function-0xf3-system-get-bank-sysgetbnk">Function 0xF3
– System Get Bank (SYSGETBNK)</a></p>
<h3 id="function-0x14-disk-write-diowrite">Function 0x14 – Disk Write (DIOWRITE)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x14</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Disk Unit</td>
<td>E: Sectors Written</td>
</tr>
<tr>
<td>D: Buffer Bank ID</td>
<td></td>
</tr>
<tr>
<td>E: Sector Count</td>
<td></td>
</tr>
<tr>
<td>HL: Buffer Address</td>
<td></td>
</tr>
</tbody>
</table>
<p>Write Sector Count (E) sectors from the buffer located in Buffer Bank ID
(D) at Buffer Address (HL) starting at the Current Sector. The returned
Status (A) is a standard HBIOS result code.</p>
<p>The Current Sector is established by a prior DIOSEEK function call;
however, multiple read/write/verify function calls can be made after a
seek function. The Current Sector is incremented after each sector
successfully written. On error, the Current Sector will be the sector
where the error occurred. Sectors Written (E) indicates the number of
sectors successfully written.</p>
<p>Disk data transfers will be faster if the buffer resides in the top 32K
of memory because it avoids a double copy.</p>
<h3 id="function-0x15-disk-verify-dioverify">Function 0x15 – Disk Verify (DIOVERIFY)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x15</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Disk Unit</td>
<td>E: Sectors Verified</td>
</tr>
<tr>
<td>E: Sector Count</td>
<td></td>
</tr>
</tbody>
</table>
<p><strong>*** Function Not Implemented ***</strong></p>
<h3 id="function-0x16-disk-format-dioformat">Function 0x16 – Disk Format (DIOFORMAT)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x16</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Disk Unit</td>
<td></td>
</tr>
<tr>
<td>D: Head</td>
<td></td>
</tr>
<tr>
<td>E: Fill Byte</td>
<td></td>
</tr>
<tr>
<td>HL: Cylinder</td>
<td></td>
</tr>
</tbody>
</table>
<p><strong>*** Function Not Implemented ***</strong></p>
<h3 id="function-0x17-disk-device-diodevice">Function 0x17 – Disk Device (DIODEVICE)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x17</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Disk Unit</td>
<td>C: Device Attributes</td>
</tr>
<tr>
<td></td>
<td>D: Device Type</td>
</tr>
<tr>
<td></td>
<td>E: Device Number</td>
</tr>
<tr>
<td></td>
<td>H: Device Unit Mode</td>
</tr>
<tr>
<td></td>
<td>L: Device I/O Base Address</td>
</tr>
</tbody>
</table>
<p>Reports device information about the specified Disk Unit (C). The Status
(A) is a standard HBIOS result code.</p>
<p>The Device Attribute (C) value returned indicates various feature
indicators related to the device being referenced by the specified Disk
Unit (C). The high 3 bits apply to all devices. The definition of the
low 5 bits depends on whether the device is a Floppy (indicated by bit
5).</p>
<p>The common bits are:</p>
<table>
<thead>
<tr>
<th style="text-align: right;"><strong>Bits</strong></th>
<th><strong>Definition</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: right;">7</td>
<td>Floppy</td>
</tr>
<tr>
<td style="text-align: right;">6</td>
<td>Removable</td>
</tr>
<tr>
<td style="text-align: right;">5</td>
<td>High Capacity (&gt;8 MB)</td>
</tr>
</tbody>
</table>
<p>The Floppy specific bits are:</p>
<table>
<thead>
<tr>
<th style="text-align: right;"><strong>Bits</strong></th>
<th><strong>Definition</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: right;">4-3</td>
<td>Form Factor: 0=8”, 1=5.25”, 2=3.5”, 3=Other</td>
</tr>
<tr>
<td style="text-align: right;">2</td>
<td>Sides: 0=SS, 1=DS</td>
</tr>
<tr>
<td style="text-align: right;">1-0</td>
<td>Density: 0=SD, 1=DD, 2=HD, 3=ED</td>
</tr>
</tbody>
</table>
<p>The non-Floppy specific bits are:</p>
<table>
<thead>
<tr>
<th style="text-align: right;"><strong>Bits</strong></th>
<th><strong>Definition</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: right;">4</td>
<td>LBA Capable</td>
</tr>
<tr>
<td style="text-align: right;">3-0</td>
<td>Media Type: 0=Hard Disk, 1=CF, 2=SD, 3=USB,</td>
</tr>
<tr>
<td style="text-align: right;"></td>
<td>4=ROM, 5=RAM, 6=FLASH, 7=RAMF, 8=CD-ROM,</td>
</tr>
<tr>
<td style="text-align: right;"></td>
<td>9=Cartridge</td>
</tr>
</tbody>
</table>
<p>Device Type (D) indicates the specific hardware driver that handles the
specified Disk Unit (C). Values are listed at the start of this section.
Device Number (E) indicates the physical device number assigned per
driver. For example, a Device Type of 0x30 with a Device Number of 1
refers to the second disk being handled by the IDE driver.</p>
<p>Device Mode (H) is used to indicate the variant of the chip or circuit
that is used by the specified unit. For example, for an IDE unit, the
value indicates the IDE circuit variant. The Device I/O Base Address (L)
indicates the starting port address of the hardware interface that is
servicing the specified unit. Both of these values are considered driver
specific. Refer to the associated hardware driver for the values used.</p>
<h3 id="function-0x18-disk-media-diomedia">Function 0x18 – Disk Media (DIOMEDIA)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x18</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Disk Unit</td>
<td>E: Media ID</td>
</tr>
<tr>
<td>E: Flags</td>
<td></td>
</tr>
</tbody>
</table>
<p>Report the Media ID (E) for the for media in the specified Disk Unit
(C). If bit 0 of Flags (E) is set, then media discovery or verification
will be performed. The Status (A) is a standard HBIOS result code. If
there is no media in device, function will return an error status.</p>
<p><strong>NOTE</strong>: This function will always return MID_HD for hard disk devices.
See the section <a href="#mapping-to-media-id">Mapping to Media ID</a> for
information on this. To determine if an HD1K formatted partition exists
on the hard disk please see the following function.</p>
<p><a href="#function-0xe0-calculate-slice-extslice">Function 0xE0 – Calculate Slice
(EXTSLICE)</a></p>
<h3 id="function-0x19-disk-define-media-diodefmed">Function 0x19 – Disk Define Media (DIODEFMED)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x19</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Disk Unit</td>
<td></td>
</tr>
<tr>
<td>E: Media ID</td>
<td></td>
</tr>
</tbody>
</table>
<p><strong>*** Function Not Implemented ***</strong></p>
<h3 id="function-0x1a-disk-capacity-diocapacity">Function 0x1A – Disk Capacity (DIOCAPACITY)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x1A</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Disk Unit</td>
<td>DEHL: Sector Count</td>
</tr>
<tr>
<td></td>
<td>BC: Block Size</td>
</tr>
</tbody>
</table>
<p>Report the current media capacity information for the specified Disk
Unit (C). The Sector Count (DEHL) is a double-word number representing
the total number of blocks on the device. Block Size (BC) contains the
block size in bytes. The Status (A) is a standard HBIOS result code. If
the media is unknown, an error will be returned.</p>
<p>This function will not attempt to discover or verify the media loaded in
the unit specified. You can use precede this function with the DIOMEDIA
function to force this if desired.</p>
<h3 id="function-0x1b-disk-geometry-diogeometry">Function 0x1B – Disk Geometry (DIOGEOMETRY)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x1B</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Disk Unit</td>
<td>D: Heads / LBA</td>
</tr>
<tr>
<td></td>
<td>E: Sectors</td>
</tr>
<tr>
<td></td>
<td>HL: Cylinder Count</td>
</tr>
<tr>
<td></td>
<td>BC: Block Size</td>
</tr>
</tbody>
</table>
<p>Report the geometry for the media in the specified Disk Unit (C). If a
device uses LBA mode addressing natively, then the drivers simulated
geometry will be returned. The Status (A) is a standard HBIOS result
code. If the media is unknown, an error will be returned.</p>
<p>LBA capability is indicated by D:7. When set, the device is capable of
LBA addressing. Refer to <a href="#function-0x12-disk-seek-dioseek">Function 0x12 – Disk Seek
(DIOSEEK)</a> for more information on
specifying LBA vs. CHS addresses.</p>
<p>Heads (D:6-0) refers to the number of heads per cylinder. Sectors (E)
refers to the number of sectors per track. Cylinder Count (HL) is the
total number of cylinders addressable for the media. Block Size (BC) is
the number of bytes in one sector.</p>
<h2 id="real-time-clock-rtc">Real Time Clock (RTC)</h2>
<p>The Real Time Clock functions provide read/write access to the clock and
related Non-Volatile RAM.</p>
<p>HBIOS only supports a single RTC device since there is no reason to have
more than one at a time. The RTC unit is assigned a Device Type ID which
indicates the specific hardware device driver that handles the unit. The
table below enumerates these values.</p>
<table>
<thead>
<tr>
<th><strong>Device Type</strong></th>
<th style="text-align: right;"><strong>ID</strong></th>
<th><strong>Description</strong></th>
<th><strong>Driver</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>RTCDEV_DS</td>
<td style="text-align: right;">0x00</td>
<td>Maxim DS1302 Real-Time Clock w/ NVRAM</td>
<td>dsrtc.asm</td>
</tr>
<tr>
<td>RTCDEV_BQ</td>
<td style="text-align: right;">0x01</td>
<td>BQ4845P Real Time Clock</td>
<td>bqrtc.asm</td>
</tr>
<tr>
<td>RTCDEV_SIMH</td>
<td style="text-align: right;">0x02</td>
<td>SIMH Simulator Real-Time Clock</td>
<td>simrtc.asm</td>
</tr>
<tr>
<td>RTCDEV_INT</td>
<td style="text-align: right;">0x03</td>
<td>Interrupt-based Real Time Clock</td>
<td>intrtc.asm</td>
</tr>
<tr>
<td>RTCDEV_DS7</td>
<td style="text-align: right;">0x04</td>
<td>Maxim DS1307 PCF I2C RTC w/ NVRAM</td>
<td>ds7rtc.asm</td>
</tr>
<tr>
<td>RTCDEV_RP5</td>
<td style="text-align: right;">0x05</td>
<td>Ricoh RPC01A Real-Time Clock w/ NVRAM</td>
<td>rp5rtc.asm</td>
</tr>
<tr>
<td>RTCDEV_EZ80</td>
<td style="text-align: right;">0x07</td>
<td>eZ80 on-chip RTC</td>
<td>ez80rtc.asm</td>
</tr>
<tr>
<td>RTCDEV_PC</td>
<td style="text-align: right;">0x08</td>
<td>MC146818/DS1285/DS12885 RTC w/ NVRAM</td>
<td>pcrtc.asm</td>
</tr>
</tbody>
</table>
<p>The time functions to get and set the time (RTCGTM and RTCSTM) require a
6 byte date/time buffer in the following format. Each byte is BCD
encoded.</p>
<table>
<thead>
<tr>
<th style="text-align: right;"><strong>Offset</strong></th>
<th><strong>Contents</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: right;">0</td>
<td>Year (00-99)</td>
</tr>
<tr>
<td style="text-align: right;">1</td>
<td>Month (01-12)</td>
</tr>
<tr>
<td style="text-align: right;">2</td>
<td>Date (01-31)</td>
</tr>
<tr>
<td style="text-align: right;">3</td>
<td>Hours (00-24)</td>
</tr>
<tr>
<td style="text-align: right;">4</td>
<td>Minutes (00-59)</td>
</tr>
<tr>
<td style="text-align: right;">5</td>
<td>Seconds (00-59)</td>
</tr>
</tbody>
</table>
<h3 id="function-0x20-rtc-get-time-rtcgettim">Function 0x20 – RTC Get Time (RTCGETTIM)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x20</td>
<td>A: Status</td>
</tr>
<tr>
<td>HL: Date/Time Buffer Address</td>
<td></td>
</tr>
</tbody>
</table>
<p>Read the current value of the real-time clock and store the date/time in
the Date/Time Buffer pointed to by HL. The Status (A) is a standard
HBIOS result code.</p>
<h3 id="function-0x21-rtc-set-time-rtcsettim">Function 0x21 – RTC Set Time (RTCSETTIM)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x21</td>
<td>A: Status</td>
</tr>
<tr>
<td>HL: Date/Time Buffer Address</td>
<td></td>
</tr>
</tbody>
</table>
<p>Set the current value of the real-time clock based on the Date/Time
Buffer pointed to by HL. The Status (A) is a standard HBIOS result code.</p>
<h3 id="function-0x22-rtc-get-nvram-byte-rtcgetbyt">Function 0x22 – RTC Get NVRAM Byte (RTCGETBYT)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x22</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Index</td>
<td>E: Value</td>
</tr>
</tbody>
</table>
<p>Read a single byte Value (E) from the Non-Volatile RAM of the RTC at the
byte offset Index (C). The Status (A) is a standard HBIOS result code.</p>
<h3 id="function-0x23-rtc-set-nvram-byte-rtcsetbyt">Function 0x23 – RTC Set NVRAM Byte (RTCSETBYT)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x23</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Index</td>
<td></td>
</tr>
<tr>
<td>E: Value</td>
<td></td>
</tr>
</tbody>
</table>
<p>Set a single byte Value (E) of the Non-Volatile RAM of the RTC at the
byte offset Index (C). The Status (A) is a standard HBIOS result code.</p>
<h3 id="function-0x24-rtc-get-nvram-block-rtcgetblk">Function 0x24 – RTC Get NVRAM Block (RTCGETBLK)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x24</td>
<td>A: Status</td>
</tr>
<tr>
<td>HL: Buffer Address</td>
<td></td>
</tr>
</tbody>
</table>
<p>Read the entire contents of the Non-Volatile RAM into to a buffer
pointed to by Buffer Address (HL). The Status (A) is a standard HBIOS
result code.</p>
<h3 id="function-0x25-rtc-set-nvram-block-rtcsetblk">Function 0x25 – RTC Set NVRAM Block (RTCSETBLK)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x25</td>
<td>A: Status</td>
</tr>
<tr>
<td>HL: Buffer Address</td>
<td></td>
</tr>
</tbody>
</table>
<p>Write the entire contents of the Non-Volatile RAM from the buffer
pointed to by Buffer Address (HL). The Status (A) is a standard HBIOS
result code.</p>
<h3 id="function-0x26-rtc-get-alarm-rtcgetalm">Function 0x26 – RTC Get Alarm (RTCGETALM)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x26</td>
<td>A: Status</td>
</tr>
<tr>
<td>HL: Date/Time Buffer Address</td>
<td></td>
</tr>
</tbody>
</table>
<p>Work in progress, documentation required…</p>
<h3 id="function-0x27-rtc-set-alarm-rtcsetalm">Function 0x27 – RTC Set Alarm (RTCSETALM)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x27</td>
<td>A: Status</td>
</tr>
<tr>
<td>HL: Date/Time Buffer Address</td>
<td></td>
</tr>
</tbody>
</table>
<p>Work in progress, documentation required…</p>
<h3 id="function-0x28-rtc-device-rtcdevice">Function 0x28 – RTC DEVICE (RTCDEVICE)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x28</td>
<td>A: Status</td>
</tr>
<tr>
<td></td>
<td>C: Device Attributes</td>
</tr>
<tr>
<td></td>
<td>D: Device Type</td>
</tr>
<tr>
<td></td>
<td>E: Device Number</td>
</tr>
<tr>
<td></td>
<td>H: Device Unit Mode</td>
</tr>
<tr>
<td></td>
<td>L: Device I/O Base Address</td>
</tr>
</tbody>
</table>
<p>Returns device information for the RTC unit. The Status (A) is a
standard HBIOS result code.</p>
<p>Device Attribute (C) values are not yet defined. Device Type (D)
indicates the specific hardware driver that handles the specified
character unit. Values are listed at the start of this section. Device
Number (E) indicates the physical device number assigned per driver
which is always 0 for RTC.</p>
<p>Device Mode (H) is used to indicate the variant of the chip or circuit
that is used by the specified unit. The Device I/O Base Address (L)
indicates the starting port address of the hardware interface that is
servicing the specified unit. Both of these values are considered driver
specific. Refer to the associated hardware driver for the values used.</p>
<h2 id="display-keypad-dsky">Display Keypad (DSKY)</h2>
<p>The Display Keypad functions provide access to a segment or LCD style
display and associated optional keypad</p>
<p>HBIOS only supports a single DSKY device since there is no reason to
have more than one at a time. If the system contains multiple DSKY
devices, only the first device discovered will be used. The DSKY unit is
assigned a Device Type ID which indicates the specific hardware device
driver that handles the unit. The table below enumerates these values.</p>
<table>
<thead>
<tr>
<th><strong>Device Type</strong></th>
<th style="text-align: right;"><strong>ID</strong></th>
<th><strong>Description</strong></th>
<th><strong>Driver</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>DSKYDEV_ICM</td>
<td style="text-align: right;">0x01</td>
<td>Original ICM7218 based DSKY</td>
<td>icm.asm</td>
</tr>
<tr>
<td>DSKYDEV_PKD</td>
<td style="text-align: right;">0x02</td>
<td>Next Gen Intel P8279 based DSKY</td>
<td>pkd.asm</td>
</tr>
<tr>
<td>DSKYDEV_GM7303</td>
<td style="text-align: right;">0x03</td>
<td>GM7303 LCD Display + Keypad</td>
<td>gm7303.asm</td>
</tr>
<tr>
<td>DSKYDEV_LCD</td>
<td style="text-align: right;">0x04</td>
<td>HD44780-based LCD Display</td>
<td>lcd.asm</td>
</tr>
</tbody>
</table>
<p>The keypad keys are identified by the following key ids. Not all keypads
will contain all keys.</p>
<table>
<thead>
<tr>
<th><strong>Key Id</strong></th>
<th><strong>Key Definition</strong></th>
<th><strong>Key Id</strong></th>
<th><strong>Key Definition</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>\$00</td>
<td>Hex Numeric 0</td>
<td>\$10</td>
<td>Forward</td>
</tr>
<tr>
<td>\$01</td>
<td>Hex Numeric 1</td>
<td>\$11</td>
<td>Backward</td>
</tr>
<tr>
<td>\$02</td>
<td>Hex Numeric 2</td>
<td>\$12</td>
<td>Clear</td>
</tr>
<tr>
<td>\$03</td>
<td>Hex Numeric 3</td>
<td>\$13</td>
<td>Enter</td>
</tr>
<tr>
<td>\$04</td>
<td>Hex Numeric 4</td>
<td>\$14</td>
<td>Deposit</td>
</tr>
<tr>
<td>\$05</td>
<td>Hex Numeric 5</td>
<td>\$15</td>
<td>Examine</td>
</tr>
<tr>
<td>\$06</td>
<td>Hex Numeric 6</td>
<td>\$16</td>
<td>Go</td>
</tr>
<tr>
<td>\$07</td>
<td>Hex Numeric 7</td>
<td>\$17</td>
<td>Boot</td>
</tr>
<tr>
<td>\$08</td>
<td>Hex Numeric 8</td>
<td>\$18</td>
<td>F4</td>
</tr>
<tr>
<td>\$09</td>
<td>Hex Numeric 9</td>
<td>\$19</td>
<td>F3</td>
</tr>
<tr>
<td>\$0A</td>
<td>Hex Numeric A</td>
<td>\$1A</td>
<td>F2</td>
</tr>
<tr>
<td>\$0B</td>
<td>Hex Numeric B</td>
<td>\$1B</td>
<td>F1</td>
</tr>
<tr>
<td>\$0C</td>
<td>Hex Numeric C</td>
<td></td>
<td></td>
</tr>
<tr>
<td>\$0D</td>
<td>Hex Numeric D</td>
<td></td>
<td></td>
</tr>
<tr>
<td>\$0E</td>
<td>Hex Numeric E</td>
<td></td>
<td></td>
</tr>
<tr>
<td>\$0F</td>
<td>Hex Numeric F</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<h3 id="function-0x30-dsky-reset-dskyreset">Function 0x30 – DSKY Reset (DSKYRESET)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x30</td>
<td>A: Status</td>
</tr>
</tbody>
</table>
<p>This function performs a device dependent reset operation on the DSKY.
The display will be cleared, keyboard queue will be flushed, and chip
will be reinitialized. The returned Status (A) is a standard HBIOS
result code.</p>
<h3 id="function-0x31-dsky-dskystatus">Function 0x31 – DSKY (DSKYSTATUS)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x31</td>
<td>A: Status / Characters Pending</td>
</tr>
</tbody>
</table>
<p>Return the count of Characters Pending (A) in the input buffer of the
DSKY. If the unit has no input buffer or the buffer utilization is not
available, the function may return simply 0 or 1 where 0 means there is
no character available and 1 means there is at least one character
available.</p>
<p>The value returned in register A is used as both a Status (A) code and
the return value. Negative values (bit 7 set) indicate a standard HBIOS
result (error) code. Otherwise, the return value represents the number
of characters in the buffer.</p>
<h3 id="function-0x32-dsky-get-key-dskygetkey">Function 0x32 – DSKY Get Key (DSKYGETKEY)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x32</td>
<td>A: Status</td>
</tr>
<tr>
<td></td>
<td>E: Character Value</td>
</tr>
</tbody>
</table>
<p>Read and return a Character (E) from the DSKY. If no character(s) are
available in the unit’s input buffer, this function will wait
indefinitely. The returned Status (A) is a standard HBIOS result code.</p>
<p>The Character Value (E) returned is not ASCII. It is a keypad key id.
The possible id values are listed at the start of this section.</p>
<h3 id="function-0x33-dsky-show-hex-rtcshowhex">Function 0x33 – DSKY Show HEX (RTCSHOWHEX)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x33</td>
<td>A: Status</td>
</tr>
<tr>
<td>DE:HL=Binary Value</td>
<td></td>
</tr>
</tbody>
</table>
<p>Display the 32-bit binary value (DE:HL) in hex on the DSKY segment
display. All decimal points of the display will be off. The Status (A)
is a standard HBIOS result code.</p>
<h3 id="function-0x34-dsky-show-segments-dskyshowseg">Function 0x34 – DSKY Show Segments (DSKYSHOWSEG)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x34</td>
<td>A: Status</td>
</tr>
<tr>
<td>HL: Buffer Address</td>
<td></td>
</tr>
</tbody>
</table>
<p>Display the segment-encoded values on the segment display. The encoding
uses a small alphabet as defined below. The actual representation of a
character is determined by the driver. The entire display is updated and
it is assumed that an 8 character buffer will be pointed to by HL. The
buffer must reside in high memory. The Status (A) is a standard HBIOS
result code.</p>
<table>
<thead>
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>0x00: ‘0’</td>
<td>0x01: ‘1’</td>
<td>0x02: ‘2’</td>
<td>0x03: ‘3’</td>
</tr>
<tr>
<td>0x04: ‘4’</td>
<td>0x05: ‘5’</td>
<td>0x06: ‘6’</td>
<td>0x07: ‘7’</td>
</tr>
<tr>
<td>0x08: ‘8’</td>
<td>0x09: ‘9’</td>
<td>0x0A: ‘A’</td>
<td>0x0B: ‘B’</td>
</tr>
<tr>
<td>0x0C: ‘C’</td>
<td>0x0D: ‘D’</td>
<td>0x0E: ‘E’</td>
<td>0x0F: ‘F’</td>
</tr>
<tr>
<td>0x10: ’ ’</td>
<td>0x11: ‘-’</td>
<td>0x12: ‘.’</td>
<td>0x13: ‘p’</td>
</tr>
<tr>
<td>0x14: ‘o’</td>
<td>0x15: ‘r’</td>
<td>0x16: ‘t’</td>
<td>0x17: ‘A’</td>
</tr>
<tr>
<td>0x18: ‘d’</td>
<td>0x19: ‘r’</td>
<td>0x1A: ‘G’</td>
<td></td>
</tr>
</tbody>
</table>
<h3 id="function-0x35-dsky-keypad-leds-dskykeyleds">Function 0x35 – DSKY Keypad LEDs (DSKYKEYLEDS)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x35</td>
<td>A: Status</td>
</tr>
<tr>
<td>HL: Buffer Address</td>
<td></td>
</tr>
</tbody>
</table>
<p>Light the LEDs for the keypad keys according to the bitmap contained in
the buffer pointed to by HL. The buffer must be located in high memory
and is assumed to be 8 bytes.</p>
<p>At this time, the bitmap is specific to the PKD hardware and will be
ignored by all other hardware.</p>
<h3 id="function-0x36-dsky-status-led-dskystatled">Function 0x36 – DSKY Status LED (DSKYSTATLED)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x36</td>
<td>A: Status</td>
</tr>
<tr>
<td>D: LED Number</td>
<td></td>
</tr>
<tr>
<td>E: LED State</td>
<td></td>
</tr>
</tbody>
</table>
<p>Set or clear the status LED specified in D. The state of the LED is
contained in E. If E=0, the LED will be turned off. If E=1, the LED will
be turned on.</p>
<p>This function is specific to the PKD hardware and will be ignored by all
other hardware. The Status (A) is a standard HBIOS result code.</p>
<h3 id="function-0x37-dsky-beep-dskybeep">Function 0x37 – DSKY Beep (DSKYBEEP)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x37</td>
<td>A: Status</td>
</tr>
</tbody>
</table>
<p>Beep the onboard speaker of the DSKY. This function is specific to the
PKD hardware. It will be ignored by the ICM hardware. The Status (A) is
a standard HBIOS result code.</p>
<h3 id="function-0x38-dsky-device-dskydevice">Function 0x38 – DSKY Device (DSKYDEVICE)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x38</td>
<td>A: Status</td>
</tr>
<tr>
<td></td>
<td>C: Device Attributes</td>
</tr>
<tr>
<td></td>
<td>D: Device Type</td>
</tr>
<tr>
<td></td>
<td>E: Device Number</td>
</tr>
<tr>
<td></td>
<td>H: Device Unit Mode</td>
</tr>
<tr>
<td></td>
<td>L: Device I/O Base Address</td>
</tr>
</tbody>
</table>
<p>Returns device information for the DSKY unit. The Status (A) is a
standard HBIOS result code.</p>
<p>Device Attribute (C) values are not yet defined. Device Type (D)
indicates the specific hardware driver that handles the specified
character unit. Values are listed at the start of this section. Device
Number (E) indicates the physical device number assigned per driver
which is always 0 for DSKY.</p>
<p>Device Mode (H) is used to indicate the variant of the chip or circuit
that is used by the specified unit. The Device I/O Base Address (L)
indicates the starting port address of the hardware interface that is
servicing the specified unit. Both of these values are considered driver
specific. Refer to the associated hardware driver for the values used.</p>
<h3 id="function-0x39-dsky-device-dskymessage">Function 0x39 – DSKY Device (DSKYMESSAGE)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x39</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Message ID</td>
<td></td>
</tr>
</tbody>
</table>
<p>Instructs the display to show a textual representation of the associated
message on the display. The IDs are defined in std.asm.</p>
<h3 id="function-0x3a-dsky-device-dskyevent">Function 0x3A – DSKY Device (DSKYEVENT)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x3A</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Event ID</td>
<td></td>
</tr>
</tbody>
</table>
<p>Instructs the display to update itself in response to an internal HBIOS
state change. At this time the the events are:</p>
<p>0: CPU Speed Change<br />
1: Disk Activity</p>
<h2 id="video-display-adapter-vda">Video Display Adapter (VDA)</h2>
<p>The VDA functions are provided as a common interface to Video Display
Adapters. Not all VDAs will include keyboard hardware. In this case, the
keyboard functions should return a failure status.</p>
<p>All video units are assigned a Device Type ID which indicates the
specific hardware device driver that handles the unit. The table below
enumerates their values.</p>
<table>
<thead>
<tr>
<th><strong>Device Type</strong></th>
<th style="text-align: right;"><strong>ID</strong></th>
<th><strong>Description</strong></th>
<th><strong>Driver</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>VDADEV_VDU</td>
<td style="text-align: right;">0x00</td>
<td>MC6845 Family Video Display Controller</td>
<td>vdu.asm</td>
</tr>
<tr>
<td>VDADEV_CVDU</td>
<td style="text-align: right;">0x01</td>
<td>MC8563-based Video Display Controller</td>
<td>cvdu.asm</td>
</tr>
<tr>
<td>VDADEV_GDC</td>
<td style="text-align: right;">0x02</td>
<td>uPD7220 Video Display Controller</td>
<td>gdc.asm</td>
</tr>
<tr>
<td>VDADEV_TMS</td>
<td style="text-align: right;">0x03</td>
<td>TMS9918/38/58 Video Display Controller</td>
<td>tms.asm</td>
</tr>
<tr>
<td>VDADEV_VGA</td>
<td style="text-align: right;">0x04</td>
<td>HD6445CP4-based Video Display Controller</td>
<td>vga.asm</td>
</tr>
<tr>
<td>VDADEV_VRC</td>
<td style="text-align: right;">0x05</td>
<td>VGARC</td>
<td>vrc.asm</td>
</tr>
<tr>
<td>VDADEV_EF</td>
<td style="text-align: right;">0x06</td>
<td>EF9345</td>
<td>ef.asm</td>
</tr>
<tr>
<td>VDADEV_FV</td>
<td style="text-align: right;">0x07</td>
<td>S100 FPGA VGA</td>
<td>fv.asm</td>
</tr>
<tr>
<td>VDADEV_XOSERA</td>
<td style="text-align: right;">0x08</td>
<td>Xosera FPGA-based Video Display Controller</td>
<td>xosera.asm</td>
</tr>
</tbody>
</table>
<p>Depending on the capabilities of the hardware, the use of colors and
attributes may or may not be supported. If the hardware does not support
these capabilities, they will be ignored.</p>
<p>Color byte values are constructed using typical RGBI
(Red/Green/Blue/Intensity) bits. The high four bits of the value
determine the background color and the low four bits determine the
foreground color. This results in 16 unique color values for both
foreground and background. The following table illustrates the color
byte value construction:</p>
<table>
<thead>
<tr>
<th> </th>
<th style="text-align: right;"><strong>Bit</strong></th>
<th><strong>Color</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>Background</td>
<td style="text-align: right;">7</td>
<td>Intensity</td>
</tr>
<tr>
<td> </td>
<td style="text-align: right;">6</td>
<td>Blue</td>
</tr>
<tr>
<td> </td>
<td style="text-align: right;">5</td>
<td>Green</td>
</tr>
<tr>
<td> </td>
<td style="text-align: right;">4</td>
<td>Red</td>
</tr>
<tr>
<td>Foreground</td>
<td style="text-align: right;">3</td>
<td>Intensity</td>
</tr>
<tr>
<td> </td>
<td style="text-align: right;">2</td>
<td>Blue</td>
</tr>
<tr>
<td> </td>
<td style="text-align: right;">1</td>
<td>Green</td>
</tr>
<tr>
<td> </td>
<td style="text-align: right;">0</td>
<td>Red</td>
</tr>
</tbody>
</table>
<p>The following table illustrates the resultant color for each of the
possible 16 values for foreground or background:</p>
<table>
<thead>
<tr>
<th><strong>Foreground</strong></th>
<th><strong>Background</strong></th>
<th><strong>Color</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>n0 nnnn0000</td>
<td>0n 0000nnnn</td>
<td>Black</td>
</tr>
<tr>
<td>n1 nnnn0001</td>
<td>1n 0001nnnn</td>
<td>Red</td>
</tr>
<tr>
<td>n2 nnnn0010</td>
<td>2n 0010nnnn</td>
<td>Green</td>
</tr>
<tr>
<td>n3 nnnn0011</td>
<td>3n 0011nnnn</td>
<td>Brown</td>
</tr>
<tr>
<td>n4 nnnn0100</td>
<td>4n 0100nnnn</td>
<td>Blue</td>
</tr>
<tr>
<td>n5 nnnn0101</td>
<td>5n 0101nnnn</td>
<td>Magenta</td>
</tr>
<tr>
<td>n6 nnnn0110</td>
<td>6n 0110nnnn</td>
<td>Cyan</td>
</tr>
<tr>
<td>n7 nnnn0111</td>
<td>7n 0111nnnn</td>
<td>White</td>
</tr>
<tr>
<td>n8 nnnn1000</td>
<td>8n 1000nnnn</td>
<td>Gray</td>
</tr>
<tr>
<td>n9 nnnn1001</td>
<td>9n 1001nnnn</td>
<td>Light Red</td>
</tr>
<tr>
<td>nA nnnn1010</td>
<td>An 1010nnnn</td>
<td>Light Green</td>
</tr>
<tr>
<td>nB nnnn1011</td>
<td>Bn 1011nnnn</td>
<td>Yellow</td>
</tr>
<tr>
<td>nC nnnn1100</td>
<td>Cn 1100nnnn</td>
<td>Light Blue</td>
</tr>
<tr>
<td>nD nnnn1101</td>
<td>Dn 1101nnnn</td>
<td>Light Magenta</td>
</tr>
<tr>
<td>nE nnnn1110</td>
<td>En 1110nnnn</td>
<td>Light Cyan</td>
</tr>
<tr>
<td>nF nnnn1111</td>
<td>Fn 1111nnnn</td>
<td>Bright White</td>
</tr>
</tbody>
</table>
<p>Attribute byte values are constructed using the following bit encoding:</p>
<table>
<thead>
<tr>
<th style="text-align: right;"><strong>Bit</strong></th>
<th><strong>Effect</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: right;">7</td>
<td>n/a (0)</td>
</tr>
<tr>
<td style="text-align: right;">6</td>
<td>n/a (0)</td>
</tr>
<tr>
<td style="text-align: right;">5</td>
<td>n/a (0)</td>
</tr>
<tr>
<td style="text-align: right;">4</td>
<td>n/a (0)</td>
</tr>
<tr>
<td style="text-align: right;">3</td>
<td>n/a (0)</td>
</tr>
<tr>
<td style="text-align: right;">2</td>
<td>Reverse</td>
</tr>
<tr>
<td style="text-align: right;">1</td>
<td>Underline</td>
</tr>
<tr>
<td style="text-align: right;">0</td>
<td>Blink</td>
</tr>
</tbody>
</table>
<p>The following codes are returned by a keyboard read to signify non-ASCII
keystrokes:</p>
<table>
<thead>
<tr>
<th style="text-align: right;"><strong>Value</strong></th>
<th><strong>Keystroke</strong></th>
<th style="text-align: right;"><strong>Value</strong></th>
<th><strong>Keystroke</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: right;">0xE0</td>
<td>F1</td>
<td style="text-align: right;">0xF0</td>
<td>Insert</td>
</tr>
<tr>
<td style="text-align: right;">0xE1</td>
<td>F2</td>
<td style="text-align: right;">0xF1</td>
<td>Delete</td>
</tr>
<tr>
<td style="text-align: right;">0xE2</td>
<td>F3</td>
<td style="text-align: right;">0xF2</td>
<td>Home</td>
</tr>
<tr>
<td style="text-align: right;">0xE3</td>
<td>F4</td>
<td style="text-align: right;">0xF3</td>
<td>End</td>
</tr>
<tr>
<td style="text-align: right;">0xE4</td>
<td>F5</td>
<td style="text-align: right;">0xF4</td>
<td>PageUp</td>
</tr>
<tr>
<td style="text-align: right;">0xE5</td>
<td>F6</td>
<td style="text-align: right;">0xF5</td>
<td>PadeDown</td>
</tr>
<tr>
<td style="text-align: right;">0xE6</td>
<td>F7</td>
<td style="text-align: right;">0xF6</td>
<td>UpArrow</td>
</tr>
<tr>
<td style="text-align: right;">0xE7</td>
<td>F8</td>
<td style="text-align: right;">0xF7</td>
<td>DownArrow</td>
</tr>
<tr>
<td style="text-align: right;">0xE8</td>
<td>F9</td>
<td style="text-align: right;">0xF8</td>
<td>LeftArrow</td>
</tr>
<tr>
<td style="text-align: right;">0xE9</td>
<td>F10</td>
<td style="text-align: right;">0xF9</td>
<td>RightArrow</td>
</tr>
<tr>
<td style="text-align: right;">0xEA</td>
<td>F11</td>
<td style="text-align: right;">0xFA</td>
<td>Power</td>
</tr>
<tr>
<td style="text-align: right;">0xEB</td>
<td>F12</td>
<td style="text-align: right;">0xFB</td>
<td>Sleep</td>
</tr>
<tr>
<td style="text-align: right;">0xEC</td>
<td>SysReq</td>
<td style="text-align: right;">0xFC</td>
<td>Wake</td>
</tr>
<tr>
<td style="text-align: right;">0xED</td>
<td>PrintScreen</td>
<td style="text-align: right;">0xFD</td>
<td>Break</td>
</tr>
<tr>
<td style="text-align: right;">0xEE</td>
<td>Pause</td>
<td style="text-align: right;">0xFE</td>
<td></td>
</tr>
<tr>
<td style="text-align: right;">0xEF</td>
<td>App</td>
<td style="text-align: right;">0xFF</td>
<td></td>
</tr>
</tbody>
</table>
<h3 id="function-0x40-video-initialize-vdaini">Function 0x40 – Video Initialize (VDAINI)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x40</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Video Unit</td>
<td></td>
</tr>
<tr>
<td>E: Video Mode</td>
<td></td>
</tr>
<tr>
<td>HL: Font Bitmap</td>
<td></td>
</tr>
</tbody>
</table>
<p>Performs a full (re)initialization of the specified Video Unit (C). The
screen is cleared and the keyboard buffer is flushed. If the specified
Video Unit (C) supports multiple video modes, a Video Mode (E) can be
specified (set to 0 for default/not specified). Video Mode (E) values
are specific to each VDA. The returned Status (A) is a standard HBIOS
result code.</p>
<p>If the hardware and driver supports it, you can specify a Font Bitmap
(HL) buffer address containing the character bitmap data to be loaded
into the video processor. The buffer <strong>must</strong> be located entirely in the
top 32K of the CPU memory space. HL must be set to zero if no character
bitmap is specified (the driver will utilize a default character
bitmap).</p>
<h3 id="function-0x41-video-query-vdaqry">Function 0x41 – Video Query (VDAQRY)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x41</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Video Unit</td>
<td>C: Video Mode</td>
</tr>
<tr>
<td>HL: Font Bitmap</td>
<td>D: Rows</td>
</tr>
<tr>
<td></td>
<td>E: Columns</td>
</tr>
<tr>
<td></td>
<td>HL: Font Bitmap</td>
</tr>
</tbody>
</table>
<p>Return information about the specified Video Unit (C). Video Mode (C)
will be set to the current video mode. Rows (D) and Columns (E) will
return the dimensions of the video display as measured in rows and
columns. Note that this is the <strong>count</strong> of rows and columns, not the
<strong>last</strong> row/column number. The returned Status (A) is a standard HBIOS
result code.</p>
<p>If the hardware and driver support it, you can specify a Font Bitmap
(HL) buffer address that will be filled with the current character
bitmap data. The buffer <strong>must</strong> be located entirely in the top 32K of
the CPU memory space. Font Bitmap (HL) <strong>must</strong> be set to zero if it
does not point to a proper buffer area or memory corruption will result.</p>
<p>If HL is not zero, it must point to a suitably sized memory buffer in
the upper 32K of CPU address space that will be filled with the current
character bitmap data. It is critical that HL be set to zero if it does
not point to a proper buffer area or memory corruption will result. If
the video device driver does not have the ability to provide character
bitmap data, then Font Bitmap (HL) will be set to zero on return.</p>
<h3 id="function-0x42-video-reset-vdares">Function 0x42 – Video Reset (VDARES)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x42</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Video Unit</td>
<td></td>
</tr>
</tbody>
</table>
<p>Performs a non-destructive reset of the specified Video Unit (C).<br />
Should re-initialize the video hardware without destroying the screen
contents or cursor position. The current video mode will not be changed.
The returned Status (A) is a standard HBIOS result code.</p>
<h3 id="function-0x43-video-device-vdadev">Function 0x43 – Video Device (VDADEV)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x43</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Video Unit</td>
<td>C: Device Attributes</td>
</tr>
<tr>
<td></td>
<td>D: Device Type</td>
</tr>
<tr>
<td></td>
<td>E: Device Number</td>
</tr>
<tr>
<td></td>
<td>H: Device Unit Mode</td>
</tr>
<tr>
<td></td>
<td>L: Device I/O Base Address</td>
</tr>
</tbody>
</table>
<p>Reports device information about the specified Video Unit (C). The
Status (A) is a standard HBIOS result code.</p>
<p>Device Attribute (C) values are not yet defined.</p>
<p>Device Type (D) indicates the specific hardware driver that handles the
specified Video Unit (C). Values are listed at the start of this
section. Device Number (E) indicates the physical device number assigned
per driver.</p>
<p>Device Mode (H) is used to indicate the variant of the chip or circuit
that is used by the specified unit. For example, for an TMS video unit,
the value indicates the TMS circuit variant. The Device I/O Base Address
(L) indicates the starting port address of the hardware interface that
is servicing the specified unit. Both of these values are considered
driver specific. Refer to the associated hardware driver for the values
used.</p>
<h3 id="function-0x44-video-set-cursor-style-vdascs">Function 0x44 – Video Set Cursor Style (VDASCS)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x44</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Video Unit</td>
<td></td>
</tr>
<tr>
<td>D: Start/End</td>
<td></td>
</tr>
<tr>
<td>E: Style</td>
<td></td>
</tr>
</tbody>
</table>
<p>If supported by the specified Video Unit (C), adjust the format of the
cursor such that the cursor starts at the pixel specified in the top
nibble of Start/End (D) and ends at the pixel specified in the bottom
nibble of Start/End (D). So, if D=0x08, a block cursor would be used
that starts at the top pixel of the character cell and ends at the ninth
pixel of the character cell. The Status (A) is a standard HBIOS result
code.</p>
<p>Style (E) is reserved to control the style of the cursor (blink,
visibility, etc.), but is not yet implemented.</p>
<p>Adjustments to the cursor style may or may not be possible for any given
video hardware and may be dependent on the active video mode.</p>
<h3 id="function-0x45-video-set-cursor-position-vdascp">Function 0x45 – Video Set Cursor Position (VDASCP)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x45</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Video Unit</td>
<td></td>
</tr>
<tr>
<td>D: Row</td>
<td></td>
</tr>
<tr>
<td>E: Column</td>
<td></td>
</tr>
</tbody>
</table>
<p>Reposition the cursor of the specified Video Unit (C) to the specified
Row (D) and Column (E). Specifying a row/column that exceeds the
boundaries of the display results in undefined behavior. Cursor
coordinates are 0 based (0,0 is the upper left corner of the display).
The Status (A) is a standard HBIOS result code.</p>
<h3 id="function-0x46-video-set-character-attribute-vdasat">Function 0x46 – Video Set Character Attribute (VDASAT)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x46</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Video Unit</td>
<td></td>
</tr>
<tr>
<td>E: Attribute</td>
<td></td>
</tr>
</tbody>
</table>
<p>Assign the specified character Attribute (E) code to be used for all
subsequent character writes/fills on the specified Video Unit (C). This
attribute is used to fill new lines generated by scroll operations. The
character attributes values are listed above. Note that a given video
display may or may not support any/all attributes. The Status (A) is a
standard HBIOS result code.</p>
<h3 id="function-0x47-video-set-character-color-vdasco">Function 0x47 – Video Set Character Color (VDASCO)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x47</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Video Unit</td>
<td></td>
</tr>
<tr>
<td>D: Scope</td>
<td></td>
</tr>
<tr>
<td>E: Color</td>
<td></td>
</tr>
</tbody>
</table>
<p>Assign the specified Color (E) code for character foreground/background.
If Scope (D) is 0, the specified color will be used for all subsequent
character writes/fills. This color is also used to fill new lines
generated by scroll operations. If Scope (D) is 1, then the specified
foreground/background color will be applied immediately to the entire
screen. Refer to the color code table above for a list of the available
color codes. Note that a given video display may or may not support
any/all colors. The Status (A) is a standard HBIOS result code.</p>
<h3 id="function-0x48-video-write-character-vdawrc">Function 0x48 – Video Write Character (VDAWRC)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x48</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Video Unit</td>
<td></td>
</tr>
<tr>
<td>E: Character</td>
<td></td>
</tr>
</tbody>
</table>
<p>Write the Character (E) value to the display of the specified Video Unit
(C). The character is written starting at the current cursor position
and the cursor is advanced. If the end of the line is encountered, the
cursor will be advanced to the start of the next line. The display will
<strong>not</strong> scroll if the end of the screen is exceeded. The Status (A) is a
standard HBIOS result code.</p>
<h3 id="function-0x49-video-fill-vdafil">Function 0x49 – Video Fill (VDAFIL)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x49</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Video Unit</td>
<td></td>
</tr>
<tr>
<td>E: Character</td>
<td></td>
</tr>
<tr>
<td>HL: Count</td>
<td></td>
</tr>
</tbody>
</table>
<p>Write the Character (E) value to the Video Unit (C) display the number
of times specified by Count (HL). Characters are written starting at the
current cursor position and the cursor is advanced by the number of
characters written. If the end of the line is encountered, the
characters will continue to be written starting at the next line as
needed. The display will <strong>not</strong> scroll if the end of the screen is
exceeded. Writing characters beyond the end of the screen results in
undefined behavior. The Status (A) is a standard HBIOS result code.</p>
<h3 id="function-0x4a-video-copy-vdacpy">Function 0x4A – Video Copy (VDACPY)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x4A</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Video Unit</td>
<td></td>
</tr>
<tr>
<td>D: Source Row</td>
<td></td>
</tr>
<tr>
<td>E: Source Column</td>
<td></td>
</tr>
<tr>
<td>L: Count</td>
<td></td>
</tr>
</tbody>
</table>
<p>Copy Count (L) bytes from the specified Video Unit (C) display Source
Row (D) and Source Column (E) to the current cursor position. The cursor
position is not updated. The maximum Count (L) value is 255. Copying
to/from overlapping areas is not supported and will have an undefined
behavior. The display will <strong>not</strong> scroll if the end of the screen is
exceeded. Copying beyond the active screen buffer area is not supported
and results in undefined behavior. The Status (A) is a standard HBIOS
result code.</p>
<h3 id="function-0x4b-video-scroll-vdascr">Function 0x4B – Video Scroll (VDASCR)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x4B</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Video Unit</td>
<td></td>
</tr>
<tr>
<td>E: Lines</td>
<td></td>
</tr>
</tbody>
</table>
<p>Scroll the video display of the specified Video Unit (C) forward or
backwards by number of Lines (E) specified. If Lines (E) is positive,
then a forward scroll is performed. If Lines (E) contains a negative
number, then a reverse scroll will be performed. This function will
scroll the entire screen contents. New lines revealed during the scroll
operation will be filled with space characters (0x20) using the active
character attribute and color. The cursor position will <strong>not</strong> be
updated. The Status (A) is a standard HBIOS result code.</p>
<h3 id="function-0x4c-video-keyboard-status-vdakst">Function 0x4C – Video Keyboard Status (VDAKST)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x4C</td>
<td>A: Status / Codes Pending</td>
</tr>
<tr>
<td>C: Video Unit</td>
<td></td>
</tr>
</tbody>
</table>
<p>Return a count of the number of key Codes Pending (A) in the keyboard
buffer for the specified Video Unit (C). If it is not possible to
determine the actual number in the buffer, it is acceptable to return 1
to indicate there are key codes available to read and 0 if there are
none available.</p>
<p>The value returned in register A is used as both a Status (A) code and
the return value. Negative values (bit 7 set) indicate a standard HBIOS
result (error) code. Otherwise, the return value represents the number
of key codes pending.</p>
<h3 id="function-0x4d-video-keyboard-flush-vdakfl">Function 0x4D – Video Keyboard Flush (VDAKFL)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x4D</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Video Unit</td>
<td></td>
</tr>
</tbody>
</table>
<p>If a keyboard buffer is in use on the Video Unit (C) specified, it
should be purged and all contents discarded. The Status (A) is a
standard HBIOS result code.</p>
<h3 id="function-0x4e-video-keyboard-read-vdakrd">Function 0x4E – Video Keyboard Read (VDAKRD)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x4E</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Video Unit</td>
<td>C: Scancode</td>
</tr>
<tr>
<td></td>
<td>D: Keystate</td>
</tr>
<tr>
<td></td>
<td>E: Keycode</td>
</tr>
</tbody>
</table>
<p>Read the next key data from keyboard of the specified Video Unit (C). If
a keyboard buffer is used, return the next Keycode in the buffer. If no
key data is available, this function will wait indefinitely for a
keypress. The Status (A) is a standard HBIOS result code.</p>
<p>The Scancode (C) value is the raw scancode from the keyboard for the
keypress. Scancodes are optional and may not be implemented by the
driver. The Scancode values are driver dependent. In the case of a PS/2
keyboard driver, they should be the PS/2 scancode. Other keyboard
drivers may return values appropriate for their specific keyboard. If
the driver does not implement this, it should return 0 in C.</p>
<p>The Keystate (D) is a bitmap representing the value of all modifier keys
and shift states as they existed at the time of the keystroke. The
bitmap is defined as:</p>
<table>
<thead>
<tr>
<th><strong>Bit</strong></th>
<th><strong>Keystate Indication</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>7</td>
<td>Key pressed was from the num pad</td>
</tr>
<tr>
<td>6</td>
<td>Caps Lock was active</td>
</tr>
<tr>
<td>5</td>
<td>Num Lock was active</td>
</tr>
<tr>
<td>4</td>
<td>Scroll Lock was active</td>
</tr>
<tr>
<td>3</td>
<td>Windows key was held down</td>
</tr>
<tr>
<td>2</td>
<td>Alt key was held down</td>
</tr>
<tr>
<td>1</td>
<td>Control key was held down</td>
</tr>
<tr>
<td>0</td>
<td>Shift key was held down</td>
</tr>
</tbody>
</table>
<p>Not all of these bits may be relevant for all keyboards. Any bit that is
not relevant should be returned as 0.</p>
<p>The Keycode (E) is generally returned as appropriate ASCII values, if
possible. Special keys, like function keys and arrows, are returned as
reserved codes as described at the start of this section.</p>
<h3 id="function-0x4f-read-a-character-at-current-video-position-vdardc">Function 0x4F – Read a character at current video position (VDARDC)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x4F</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Video Unit</td>
<td>E: Character</td>
</tr>
<tr>
<td></td>
<td>B: Color</td>
</tr>
<tr>
<td></td>
<td>E: Attribute</td>
</tr>
</tbody>
</table>
<p>This function will return the character data from the current cursor
position of the display of the specified Video Unit (C). The data
returned includes the Character (E) value, the Color (B), and the
Attribute (E) corresponding to the current cursor position. If the
display does not support colors or attributes then this function will
return color white on black with no attributes. The ability to perform
this function may not be available for all video devices. The Status (A)
is a standard HBIOS result code.</p>
<h2 id="sound-snd">Sound (SND)</h2>
<p>Sound functions require that a Sound Unit number be specified in
register C. This is the logical device unit number assigned during the
boot process that identifies all sound devices uniquely.</p>
<p>All sound units are assigned a Device Type ID which indicates the
specific hardware device driver that handles the unit. The table below
enumerates these values.</p>
<table>
<thead>
<tr>
<th><strong>Device Type</strong></th>
<th style="text-align: right;"><strong>ID</strong></th>
<th><strong>Description</strong></th>
<th><strong>Driver</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>SNDDEV_SN76489</td>
<td style="text-align: right;">\$00</td>
<td>SN76489 Programmable Sound Generator</td>
<td>sn76489.asm</td>
</tr>
<tr>
<td>SNDDEV_AY38910</td>
<td style="text-align: right;">\$01</td>
<td>AY-3-8910/YM2149 Programmable Sound Generator</td>
<td>ay38910.asm</td>
</tr>
<tr>
<td>SNDDEV_BITMODE</td>
<td style="text-align: right;">\$02</td>
<td>Bit-bang Speaker</td>
<td>spk.asm</td>
</tr>
<tr>
<td>SNDDEV_YM2612</td>
<td style="text-align: right;">\$03</td>
<td>YM2612 Programmable Sound Generator</td>
<td>ym2612.asm</td>
</tr>
</tbody>
</table>
<p>The Sound functions defer the actual programming of the sound chip until
the SNDPLAY function is called. You will call the volume and period/note
functions to preset the desired sound output, then call SNDPLAY when you
want the sound to change.</p>
<p>The Sound functions do not manage the duration of the sound played. A
sound will play indefinitely – the caller must implement an appropriate
timing mechanism to manage the playing of a series of sounds.</p>
<pre><code>HBIOS B=51 C=00 L=80 ; Set volume to half level
HBIOS B=53 C=00 HL=152 ; Select Middle C (C4)
HBIOS B=54 C=00 D=01 ; Play note on Channel 1
</code></pre>
<h3 id="function-0x50-sound-reset-sndreset">Function 0x50 – Sound Reset (SNDRESET)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x50</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Sound Unit</td>
<td></td>
</tr>
</tbody>
</table>
<p>Reset the sound chip of specified Sound Unit (C). Turn off all sounds
and set volume on all channels to silence. The returned Status (A) is a
standard HBIOS result code.</p>
<h3 id="function-0x51-sound-volume-sndvol">Function 0x51 – Sound Volume (SNDVOL)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x51</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Sound Unit</td>
<td></td>
</tr>
<tr>
<td>L: Volume</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function sets the sound chip Volume (L) for the specified Sound
Unit (C). Volume (L) is a binary value ranging from 0 (silence) to 255
(maximum). The volume will be applied when the next SNDPLAY function is
invoked. The returned Status (A) is a standard HBIOS result code.</p>
<p>Note that not all sounds chips implement 256 volume levels. The driver
will scale the volume to the closest possible level the chip provides.</p>
<h3 id="function-0x52-sound-period-sndprd">Function 0x52 – Sound Period (SNDPRD)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x52</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Sound Unit</td>
<td></td>
</tr>
<tr>
<td>HL: Period</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function sets the sound chip Period (HL) for the specified Sound
Unit (C). The period will be applied when the next SNDPLAY function is
invoked. The returned Status (A) is a standard HBIOS result code.</p>
<p>The Period (HL) value is <strong>not</strong> a standardized value. The value is
programmed directly into the period or frequency register of the sound
chip. It is therefore a hardware dependent value. To play standardized
notes, use the SNDNOTE function.</p>
<h3 id="function-0x53-sound-note-sndnote">Function 0x53 – Sound Note (SNDNOTE)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x53</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Sound Unit</td>
<td></td>
</tr>
<tr>
<td>HL: Note</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function sets the frequency generated by the sound of the specified
Sound Unit (C). The frequency is standardized and is specified by using
values that correspond to musical notes. The frequency will be applied
when the next SNDPLAY function is invoked. The returned Status (A) is a
standard HBIOS result code.</p>
<p>The Note (HL) values correspond to quarter notes. Increasing/decreasing
the value by 4 results in a full note increment/decrement.<br />
Increasing/decreasing the value by 48 results in a full octave
increment/decrement. The value 0 corresponds to Bb/A# in octave 0.</p>
<p>The sound chip resolution and its oscillator limit the range and
accuracy of the notes played. The typical range of the AY-3-8910 is six
octaves: Bb2/A#2 to A7, where each value is a unique tone. Values above
and below can still be played but each quarter tone step may not result
in a note change.</p>
<p>The following table shows the mapping of the Note (HL) value to the
corresponding octave and note.</p>
<table>
<thead>
<tr>
<th><strong>Note</strong></th>
<th><strong>Octave</strong></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td><strong>0</strong></td>
<td><strong>1</strong></td>
<td><strong>2</strong></td>
<td><strong>3</strong></td>
<td><strong>4</strong></td>
<td><strong>5</strong></td>
<td><strong>6</strong></td>
<td><strong>7</strong></td>
</tr>
<tr>
<td><strong>C</strong></td>
<td>-</td>
<td>8</td>
<td>56</td>
<td>104</td>
<td>152</td>
<td>200</td>
<td>248</td>
<td>296</td>
</tr>
<tr>
<td><strong>C#/Db</strong></td>
<td>-</td>
<td>12</td>
<td>60</td>
<td>108</td>
<td>156</td>
<td>204</td>
<td>252</td>
<td>300</td>
</tr>
<tr>
<td><strong>D</strong></td>
<td>-</td>
<td>16</td>
<td>64</td>
<td>112</td>
<td>160</td>
<td>208</td>
<td>256</td>
<td>304</td>
</tr>
<tr>
<td><strong>D#/Eb</strong></td>
<td>-</td>
<td>20</td>
<td>68</td>
<td>116</td>
<td>164</td>
<td>212</td>
<td>260</td>
<td>308</td>
</tr>
<tr>
<td><strong>E</strong></td>
<td>-</td>
<td>24</td>
<td>72</td>
<td>120</td>
<td>168</td>
<td>216</td>
<td>264</td>
<td>312</td>
</tr>
<tr>
<td><strong>F</strong></td>
<td>-</td>
<td>28</td>
<td>76</td>
<td>124</td>
<td>172</td>
<td>220</td>
<td>268</td>
<td>316</td>
</tr>
<tr>
<td><strong>F#/Gb</strong></td>
<td>-</td>
<td>32</td>
<td>80</td>
<td>128</td>
<td>176</td>
<td>224</td>
<td>272</td>
<td>320</td>
</tr>
<tr>
<td><strong>G</strong></td>
<td>-</td>
<td>36</td>
<td>84</td>
<td>132</td>
<td>180</td>
<td>228</td>
<td>276</td>
<td>324</td>
</tr>
<tr>
<td><strong>G#/Ab</strong></td>
<td>-</td>
<td>40</td>
<td>88</td>
<td>136</td>
<td>184</td>
<td>232</td>
<td>280</td>
<td>328</td>
</tr>
<tr>
<td><strong>A</strong></td>
<td>-</td>
<td>44</td>
<td>92</td>
<td>140</td>
<td>188</td>
<td>236</td>
<td>284</td>
<td>332</td>
</tr>
<tr>
<td><strong>A#/Bb</strong></td>
<td>0</td>
<td>48</td>
<td>96</td>
<td>144</td>
<td>192</td>
<td>240</td>
<td>288</td>
<td>336</td>
</tr>
<tr>
<td><strong>B</strong></td>
<td>4</td>
<td>52</td>
<td>100</td>
<td>148</td>
<td>196</td>
<td>244</td>
<td>292</td>
<td>340</td>
</tr>
</tbody>
</table>
<h3 id="function-0x54-sound-play-sndplay">Function 0x54 – Sound Play (SNDPLAY)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x54</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Sound Unit</td>
<td></td>
</tr>
<tr>
<td>D: Channel</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function applies the previously specified volume and frequency of
the specified Sound Unit (C) by programming the sound chip with the
appropriate values. The values are applied to the specified Channel (D)
of the chip. The returned Status (A) is a standard HBIOS result code.</p>
<p>Note that there is no duration for the sound output – the programmed
sound will be played indefinitely. It is up to the user to wait the
desired amount of time, then change or silence the sound output as
desired.</p>
<p>The number of channels available on a sound chip varies. It is up to the
caller to ensure that the appropriate number of channels are being
programmed.</p>
<h3 id="function-0x55-sound-query-sndquery">Function 0x55 – Sound Query (SNDQUERY)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x55</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Sound Unit</td>
<td></td>
</tr>
<tr>
<td>E: Subfunction</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function will return a variety of information for a specified Sound
Unit (C) according to the Subfunction (E) specified. The returned Status
(A) is a standard HBIOS result code.</p>
<h4 id="sndquery-subfunction-0x01-get-count-of-audio-channels-supported-sndq_chcnt">SNDQUERY Subfunction 0x01 – Get count of audio channels supported (SNDQ_CHCNT)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x55</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Sound Unit</td>
<td>B: Tone Channels</td>
</tr>
<tr>
<td>E: 0x01</td>
<td>C: Noise Channels</td>
</tr>
</tbody>
</table>
<h4 id="sndquery-subfunction-0x02-get-current-volume-setting-sndq_vol">SNDQUERY Subfunction 0x02 – Get current volume setting (SNDQ_VOL)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x55</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Sound Unit</td>
<td>L: Volume</td>
</tr>
<tr>
<td>E: 0x02</td>
<td></td>
</tr>
</tbody>
</table>
<h4 id="sndqdery-subfunction-0x03-get-current-period-setting-sndq_period">SNDQdERY Subfunction 0x03 – Get current period setting (SNDQ_PERIOD)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x55</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Sound Unit</td>
<td>HL: Period</td>
</tr>
<tr>
<td>E: 0x03</td>
<td></td>
</tr>
</tbody>
</table>
<h4 id="sndquery-subfunction-0x04-get-device-details-sndq_dev">SNDQUERY Subfunction 0x04 – Get device details (SNDQ_DEV)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x55</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Sound Unit</td>
<td>B: Driver Identity</td>
</tr>
<tr>
<td>E: 0x04</td>
<td>HL: Ports</td>
</tr>
<tr>
<td></td>
<td>DE: Ports</td>
</tr>
</tbody>
</table>
<p>This subfunction reports detailed device information for the specified
Sound Unit (C).</p>
<p>Driver Identity (B) reports the audio device type. Ports (HL &amp; DE)
return relevant port addresses for the hardware specific to each device
type.</p>
<p>The following table defines the specific port information per device
type:</p>
<table>
<thead>
<tr>
<th><em>Audio ID</em></th>
<th style="text-align: right;"><em>Value</em></th>
<th><em>Device</em></th>
<th><em>Returned Registers</em></th>
</tr>
</thead>
<tbody>
<tr>
<td>SND_SN76489</td>
<td style="text-align: right;">0x01</td>
<td>SN76489</td>
<td>E=Left channel port, L=Right channel port</td>
</tr>
<tr>
<td>SND_AY38910</td>
<td style="text-align: right;">0x02</td>
<td>AY-3-8910</td>
<td>D=Address port, E=Data port</td>
</tr>
<tr>
<td>SND_BITMODE</td>
<td style="text-align: right;">0x03</td>
<td>I/O PORT</td>
<td>D=Address port, E=Bit mask</td>
</tr>
<tr>
<td>SND_YM2612</td>
<td style="text-align: right;">0x04</td>
<td>YM2612</td>
<td>Part 0: D=Address port, E=Data port</td>
</tr>
<tr>
<td></td>
<td style="text-align: right;"></td>
<td></td>
<td>Part 1: D=Address port, L=Part 1 Data port</td>
</tr>
</tbody>
</table>
<h3 id="function-0x56-sound-duration-snddur">Function 0x56 – Sound Duration (SNDDUR)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x56</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Sound Unit</td>
<td></td>
</tr>
<tr>
<td>HL: Duration</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function sets the Duration (HL) of the note to be played in
milliseconds for the specified Sound Unit (C). This function just sets
the duration, the actual duration is applied in the SNDPLAY function.</p>
<p>If the Duration (HL) is set to zero, then the SNDPLAY function will
operate in a non-blocking mode. i.e. a tone will start playing and the
play function will return. The tone will continue to play until the next
tone is played. If the Duration (HL) is greater than zero, the sound
will play for the duration defined in HL and then return.</p>
<p>***** Function Not Implemented ****</p>
<h3 id="function-0x57-sound-device-snddevice">Function 0x57 – Sound Device (SNDDEVICE)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x57</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Sound Unit</td>
<td>C: Device Attributes</td>
</tr>
<tr>
<td></td>
<td>D: Device Type</td>
</tr>
<tr>
<td></td>
<td>E: Device Number</td>
</tr>
<tr>
<td></td>
<td>H: Device Unit Mode</td>
</tr>
<tr>
<td></td>
<td>L: Device I/O Base Address</td>
</tr>
</tbody>
</table>
<p>Reports device information about the specified Sound Unit (C). The
Status (A) is a standard HBIOS result code.</p>
<p>The Device Attributes (C) value is not yet defined.</p>
<p>Device Type (D) indicates the specific hardware driver that handles the
specified Sound Unit (C). Values are listed at the start of this
section. Device Number (E) indicates the physical device number assigned
per driver.</p>
<p>Device Mode (H) is used to indicate the variant of the chip or circuit
that is used by the specified unit. The Device I/O Base Address (L)
indicates the starting port address of the hardware interface that is
servicing the specified unit. Both of these values are considered driver
specific. Refer to the associated hardware driver for the values used.</p>
<h3 id="function-0x58-sound-beep-sndbeep">Function 0x58 – Sound Beep (SNDBEEP)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0x58</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Sound Unit</td>
<td></td>
</tr>
</tbody>
</table>
<p>Play a beep tone on the specified Sound Unit (C). The beep will normally
be about 1/3 second in duration and the tone will be approximately B5.</p>
<h2 id="extension-ext">Extension (EXT)</h2>
<p>Helper (extension) functions that are not a core part of a BIOS.</p>
<h3 id="function-0xe0-calculate-slice-extslice">Function 0xE0 – Calculate Slice (EXTSLICE)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xE0</td>
<td>A: Status</td>
</tr>
<tr>
<td>D: Disk Unit</td>
<td>B: Device Attributes</td>
</tr>
<tr>
<td>E: Slice</td>
<td>C: Media ID</td>
</tr>
<tr>
<td></td>
<td>DEHL: Sector Address</td>
</tr>
</tbody>
</table>
<p>Report the Media ID (C), and Device Attributes (B) for the for media in
the specified Disk Unit (D), and for hard disks the absolute Sector
offset to the start of the Slice (E). The Status (A) is a standard HBIOS
result code.</p>
<p>This function extends upon <a href="#function-0x18-disk-media-diomedia">Function 0x18 – Disk Media
(DIOMEDIA)</a> for hard disk media by
scanning for a partition to determine if the disk uses HD512 or HD1K,
correctly reporting MID_HD or MID_HDNEW respectively. See the following
for some background <a href="#mapping-to-media-id">Mapping to Media ID</a></p>
<p>It will also return the sector number of the first sector in the slice
if the slice number is valid. If the slice number is invalid (it wont
fix on the media) an error will be returned.</p>
<p>The slice calculation is performed by considering the partition start
(if it exists), the size of a slice for the given format type, and
ensuring that the slice fits within the media or partition size, taking
into consideration other partitions that may exist.</p>
<p>The Device Attributes (B) are the same as defined in <a href="#function-0x17-disk-device-diodevice">Function 0x17 –
Disk Device (DIODEVICE)</a></p>
<p>If the Unit specified is not a hard disk the Media ID will be returned
and the slice parameter ignored. If there is no media in device, or the
slice number is invaid (Parameter Out Of Range) the function will return
an error status.</p>
<p>**NOTE: This function was placed in HBIOS to be shared between the
diffeent CP/M varients supported by RomWBW. It is not strictly a BIOS
function, and may be moved in future.</p>
<h2 id="system-sys">System (SYS)</h2>
<h3 id="function-0xf0-system-reset-sysreset">Function 0xF0 – System Reset (SYSRESET)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF0</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Subfunction</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function performs various forms of a system reset depending on the
value of Subfunction (C):</p>
<p>Soft Reset (0x00):<br />
Perform a soft reset of HBIOS. Releases all HBIOS memory allocated by
current OS. Does not reinitialize physical devices.</p>
<p>Warm Start (0x01):<br />
Warm start the system returning to the boot loader prompt. Does not
reinitialize physical devices.</p>
<p>Cold Start (0x02):<br />
Perform a system cold start (like a power on). All devices are
reinitialized.</p>
<p>User Restart (0x03):<br />
Perform a video terminal reset. Terminal emulation and visual display
systems are reset.</p>
<p>The Status (A) is a standard HBIOS result code.</p>
<h3 id="function-0xf1-system-version-sysver">Function 0xF1 – System Version (SYSVER)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF1</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Reserved</td>
<td>DE: Version</td>
</tr>
<tr>
<td></td>
<td>L: Platform</td>
</tr>
</tbody>
</table>
<p>This function will return the HBIOS Version (DE) number and Platform (L)
identifier. The Status (A) is a standard HBIOS result code.</p>
<p>The Version (DE)number is encoded as BCD where the 4 digits are:</p>
<p>[Major Version][Minor Version][Patch Level][Build Number]</p>
<p>So, for example, a Version (DE) number of 0x3102 would indicate version
3.1.0, build 2.</p>
<p>The hardware Platform (L) is identified as follows:</p>
<table>
<thead>
<tr>
<th><strong>Name</strong></th>
<th style="text-align: right;"><strong>Id</strong></th>
<th>**Platform **</th>
</tr>
</thead>
<tbody>
<tr>
<td>PLT_SBC</td>
<td style="text-align: right;">1</td>
<td>ECB Z80 SBC</td>
</tr>
<tr>
<td>PLT_ZETA</td>
<td style="text-align: right;">2</td>
<td>ZETA Z80 SBC</td>
</tr>
<tr>
<td>PLT_ZETA2</td>
<td style="text-align: right;">3</td>
<td>ZETA Z80 V2 SBC</td>
</tr>
<tr>
<td>PLT_N8</td>
<td style="text-align: right;">4</td>
<td>N8 (HOME COMPUTER) Z180 SBC</td>
</tr>
<tr>
<td>PLT_MK4</td>
<td style="text-align: right;">5</td>
<td>MARK IV</td>
</tr>
<tr>
<td>PLT_UNA</td>
<td style="text-align: right;">6</td>
<td>UNA BIOS</td>
</tr>
<tr>
<td>PLT_RCZ80</td>
<td style="text-align: right;">7</td>
<td>RCBUS W/ Z80</td>
</tr>
<tr>
<td>PLT_RCZ180</td>
<td style="text-align: right;">8</td>
<td>RCBUS W/ Z180</td>
</tr>
<tr>
<td>PLT_EZZ80</td>
<td style="text-align: right;">9</td>
<td>EASY/TINY Z80</td>
</tr>
<tr>
<td>PLT_SCZ180</td>
<td style="text-align: right;">10</td>
<td>SMALL COMPUTER CENTRAL Z180</td>
</tr>
<tr>
<td>PLT_DYNO</td>
<td style="text-align: right;">11</td>
<td>DYNO MICRO-ATX MOTHERBOARD</td>
</tr>
<tr>
<td>PLT_RCZ280</td>
<td style="text-align: right;">12</td>
<td>RCBUS W/ Z280</td>
</tr>
<tr>
<td>PLT_MBC</td>
<td style="text-align: right;">13</td>
<td>NHYODYNE MULTI-BOARD COMPUTER</td>
</tr>
<tr>
<td>PLT_RPH</td>
<td style="text-align: right;">14</td>
<td>RHYOPHYRE GRAPHICS SBC</td>
</tr>
<tr>
<td>PLT_Z80RETRO</td>
<td style="text-align: right;">15</td>
<td>Z80 RETRO COMPUTER</td>
</tr>
<tr>
<td>PLT_S100</td>
<td style="text-align: right;">16</td>
<td>S100 COMPUTERS Z180</td>
</tr>
<tr>
<td>PLT_DUO</td>
<td style="text-align: right;">17</td>
<td>DUODYNE Z80 SYSTEM</td>
</tr>
<tr>
<td>PLT_HEATH</td>
<td style="text-align: right;">18</td>
<td>HEATHKIT H8 Z80 SYSTEM</td>
</tr>
<tr>
<td>PLT_EPITX</td>
<td style="text-align: right;">19</td>
<td>Z180 MINI-ITX</td>
</tr>
<tr>
<td>PLT_MON</td>
<td style="text-align: right;">20</td>
<td>MONSPUTER (DEPRECATED)</td>
</tr>
<tr>
<td>PLT_GMZ180</td>
<td style="text-align: right;">21</td>
<td>GENESIS Z180 SYSTEM</td>
</tr>
<tr>
<td>PLT_NABU</td>
<td style="text-align: right;">22</td>
<td>NABU PC W/ ROMWBW OPTION BOARD</td>
</tr>
<tr>
<td>PLT_FZ80</td>
<td style="text-align: right;">23</td>
<td>S100 FPGA Z80</td>
</tr>
<tr>
<td>PLT_RCEZ80</td>
<td style="text-align: right;">24</td>
<td>RCBUS W/ eZ80</td>
</tr>
</tbody>
</table>
<p>For more information on these platforms see <a href="../Hardware/">RomWBW
Hardware</a></p>
<h3 id="function-0xf2-system-set-bank-syssetbnk">Function 0xF2 – System Set Bank (SYSSETBNK)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF2</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Bank ID</td>
<td>C: Prior Bank ID</td>
</tr>
</tbody>
</table>
<p>Activates the specified memory Bank ID (C) and returns the Prior Bank ID
(C).</p>
<p>The function <strong>must</strong> be invoked from code located in the upper 32K and
the stack <strong>must</strong> be in the upper 32K. The Status (A) is a standard
HBIOS result code.</p>
<p>If the system is using interrupt mode 1 interrupts, the you <strong>must</strong>
take steps to ensure interrupts are properly handled. You generally have
two choices:</p>
<ul>
<li>Disable interrupts while the User Bank is switched out</li>
<li>Duplicate the interrupt mode 1 vector from the User Bank into the bank
you are switching to.</li>
</ul>
<p>If the User Bank has been switched out, you will not be able to invoke
the HBIOS API functions using an <code>RST 08</code> instruction. You can use the
alternative mechanism using <code>CALL $FFF0</code> as described in
<a href="#invocation">Invocation</a>.</p>
<h3 id="function-0xf3-system-get-bank-sysgetbnk">Function 0xF3 – System Get Bank (SYSGETBNK)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF3</td>
<td>A: Status</td>
</tr>
<tr>
<td></td>
<td>C: Bank ID</td>
</tr>
</tbody>
</table>
<p>Returns the currently active Bank ID (C). The Status (A) is a standard
HBIOS result code.</p>
<h3 id="function-0xf4-system-set-copy-syssetcpy">Function 0xF4 – System Set Copy (SYSSETCPY)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF4</td>
<td>A: Status</td>
</tr>
<tr>
<td>D: Destination Bank ID</td>
<td></td>
</tr>
<tr>
<td>E: Source Bank ID</td>
<td></td>
</tr>
<tr>
<td>HL: Byte Count</td>
<td></td>
</tr>
</tbody>
</table>
<p>Prepare for a subsequent interbank memory copy (SYSBNKCPY) function call
by setting the Source Bank ID (E), Destination Bank ID (D), and Byte
Count (HL) to be copied. The bank ID’s are not range checked and must be
valid for the system in use. The Status (A) is a standard HBIOS result
code.</p>
<p>No bytes are copied by this function. The SYSBNKCPY function must be
called to actually perform the copy. The values setup by this function
will remain unchanged until another call is make to this function. So,
after calling SYSSETCPY, you may make multiple calls to SYSBNKCPY as
long as you want to continue to copy between the already established
Source/Destination Banks and the same size copy is being performed.</p>
<h3 id="function-0xf5-system-bank-copy-sysbnkcpy">Function 0xF5 – System Bank Copy (SYSBNKCPY)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF5</td>
<td>A: Status</td>
</tr>
<tr>
<td>DE: Destination Address</td>
<td>DE: New Destination Address</td>
</tr>
<tr>
<td>HL: Source Address</td>
<td>HL: New Source Address</td>
</tr>
</tbody>
</table>
<p>Copy a block of memory between banks. The Source Bank, Destination Bank,
and Byte Count to copy <strong>must</strong> be established with a prior call to
SYSSETCPY. However, it is not necessary to call SYSSETCPY prior to
subsequent calls to SYSBNKCPY if the source/destination banks and copy
length do not change.</p>
<p>On return, the New Destination Address (DE) will be value of the
original Destination Address (DE) incremented by the count of bytes
copied. Likewise for the New Source Address (HL). This allows iterative
invocations of this function to continue copying where the prior
invocation left off.</p>
<p>The Status (A) is a standard HBIOS result code.</p>
<p>WARNINGS:</p>
<ul>
<li>
<p>This function is inherently dangerous and does not prevent you from
corrupting critical areas of memory. Use with <strong>extreme</strong> caution.</p>
</li>
<li>
<p>Overlapping source and destination memory ranges are not supported and
will result in undetermined behavior.</p>
</li>
<li>
<p>Copying of byte ranges that cross bank boundaries is undefined.</p>
</li>
</ul>
<h3 id="function-0xf6-system-alloc-sysalloc">Function 0xF6 – System Alloc (SYSALLOC)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF6</td>
<td>A: Status</td>
</tr>
<tr>
<td>HL: Block Size</td>
<td>HL: Block Address</td>
</tr>
</tbody>
</table>
<p>This function will attempt to allocate a Block Size (HL) bytes block of
memory from the internal HBIOS heap. The HBIOS heap resides in the HBIOS
bank in the area of memory left unused by HBIOS. If the allocation is
successful, the Block Address (HL) of the allocated memory block is
returned in HL. You will typically need to use the SYSBNKCPY function to
read/write the allocated memory. The Status (A) is a standard HBIOS
result code.</p>
<h3 id="function-0xf7-system-free-sysfree">Function 0xF7 – System Free (SYSFREE)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF7</td>
<td>A: Status</td>
</tr>
<tr>
<td>HL: Block Address</td>
<td></td>
</tr>
</tbody>
</table>
<p><strong>*** Function Not Implemented ***</strong></p>
<p>Note that all allocated memory can be freed by calling the SYSRESET
function with a subfunction code of 0x00 (Soft Reset).</p>
<h3 id="function-0xf8-system-get-sysget">Function 0xF8 – System Get (SYSGET)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Subfunction</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function will report various system information based on the
sub-function value. The following lists the subfunctions available along
with the registers/information utilized. The Status (A) is a standard
HBIOS result code.</p>
<h4 id="sysget-subfunction-0x00-get-character-device-unit-count-ciocnt">SYSGET Subfunction 0x00 – Get Character Device Unit Count (CIOCNT)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0x00</td>
<td>E: Count</td>
</tr>
</tbody>
</table>
<p>Return the Count (E) of character device units. The Status (A) is a
standard HBIOS result code.</p>
<h4 id="sysget-subfunction-0x01-get-serial-unit-function-ciofn">SYSGET Subfunction 0x01 – Get Serial Unit Function (CIOFN)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0x01</td>
<td>HL: Function Address</td>
</tr>
<tr>
<td>D: Function</td>
<td>DE: Unit Data Address</td>
</tr>
<tr>
<td>E: Unit</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function will lookup the actual driver function address and unit
data address inside the HBIOS driver. On entry, place the CIO function
number to lookup in D and the CIO unit number in E. On return, HL will
contain the address of the requested function in the HBIOS driver (in
the HBIOS bank). DE will contain the associated unit data address (also
in the HBIOS bank). See Appendix A for details. The returned Status (A)
is a standard HBIOS result code.</p>
<p>This function can be used to speed up HBIOS calls by looking up the
function and data address for a specific driver function. After this,
the caller can use interbank calls directly to the function in the
driver which bypasses the overhead of the normal function invocation
lookup.</p>
<h4 id="sysget-subfunction-0x10-get-disk-device-unit-count-diocnt">SYSGET Subfunction 0x10 – Get Disk Device Unit Count (DIOCNT)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0x10</td>
<td>E: Count</td>
</tr>
</tbody>
</table>
<p>Return the Count (E) of disk device units. The Status (A) is a standard
HBIOS result code.</p>
<h4 id="sysget-subfunction-0x11-get-disk-unit-function-diofn">SYSGET Subfunction 0x11 – Get Disk Unit Function (DIOFN)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0x11</td>
<td>HL: Function Address</td>
</tr>
<tr>
<td>D: Function</td>
<td>DE: Unit Data Address</td>
</tr>
<tr>
<td>E: Unit</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function will lookup the actual driver function address and unit
data address inside the HBIOS driver. On entry, place the DIO function
number to lookup in D and the DIO unit number in E. On return, HL will
contain the address of the requested function in the HBIOS driver (in
the HBIOS bank). DE will contain the associated unit data address (also
in the HBIOS bank). See Appendix A for details. The returned Status (A)
is a standard HBIOS result code.</p>
<p>This function can be used to speed up HBIOS calls by looking up the
function and data address for a specific driver function. After this,
the caller can use interbank calls directly to the function in the
driver which bypasses the overhead of the normal function invocation
lookup.</p>
<h4 id="sysget-subfunction-0x20-get-rtc-device-unit-count-rtccnt">SYSGET Subfunction 0x20 – Get RTC Device Unit Count (RTCCNT)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0x20</td>
<td>E: Count</td>
</tr>
</tbody>
</table>
<p>Return the Count (E) of RTC device units. The Status (A) is a standard
HBIOS result code.</p>
<h4 id="sysget-subfunction-0x40-get-video-device-unit-count-vdacnt">SYSGET Subfunction 0x40 – Get Video Device Unit Count (VDACNT)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0x40</td>
<td>E: Count</td>
</tr>
</tbody>
</table>
<p>Return the Count (E) of video device units. The Status (A) is a standard
HBIOS result code.</p>
<h4 id="sysget-subfunction-0x41-get-video-unit-function-vdafn">SYSGET Subfunction 0x41 – Get Video Unit Function (VDAFN)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0x41</td>
<td>HL: Function Address</td>
</tr>
<tr>
<td>D: Function</td>
<td>DE: Unit Data Address</td>
</tr>
<tr>
<td>E: Unit</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function will lookup the actual driver function address and unit
data address inside the HBIOS driver. On entry, place the VDA function
number to lookup in D and the VDA unit number in E. On return, HL will
contain the address of the requested function in the HBIOS driver (in
the HBIOS bank). DE will contain the associated unit data address (also
in the HBIOS bank). See Appendix A for details. The returned Status (A)
is a standard HBIOS result code.</p>
<p>This function can be used to speed up HBIOS calls by looking up the
function and data address for a specific driver function. After this,
the caller can use interbank calls directly to the function in the
driver which bypasses the overhead of the normal function invocation
lookup.</p>
<h4 id="sysget-subfunction-0x50-get-sound-device-unit-count-sndcnt">SYSGET Subfunction 0x50 – Get Sound Device Unit Count (SNDCNT)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0x50</td>
<td>E: Count</td>
</tr>
</tbody>
</table>
<p>Return the Count (E) of sound device units. The Status (A) is a standard
HBIOS result code.</p>
<h4 id="sysget-subfunction-0x51-get-sound-unit-function-sndfn">SYSGET Subfunction 0x51 – Get Sound Unit Function (SNDFN)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0x51</td>
<td>HL: Function Address</td>
</tr>
<tr>
<td>D: Function</td>
<td>DE: Unit Data Address</td>
</tr>
<tr>
<td>E: Unit</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function will lookup the actual driver function address and unit
data address inside the HBIOS driver. On entry, place the SND function
number to lookup in D and the SND unit number in E. On return, HL will
contain the address of the requested function in the HBIOS driver (in
the HBIOS bank). DE will contain the associated unit data address (also
in the HBIOS bank). See Appendix A for details. The returned Status (A)
is a standard HBIOS result code.</p>
<p>This function can be used to speed up HBIOS calls by looking up the
function and data address for a specific driver function. After this,
the caller can use interbank calls directly to the function in the
driver which bypasses the overhead of the normal function invocation
lookup.</p>
<h4 id="sysget-subfunction-0xc0-get-switches-switch">SYSGET Subfunction 0xC0 – Get Switches (SWITCH)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0xC0</td>
<td>HL: Switch Value</td>
</tr>
<tr>
<td>D: Switch Key</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function will return the current value (HL) of the switch (D) from
NVRAM.</p>
<p>Switches may be returned as a 16 bit (HL) or 8 bit (L) value. It is up
to the caller to process the returned value correctly. Note for Switch
0xFF (status) the returned value is primarily in the Status (A)
register.</p>
<p>Errors are signaled in the return by setting the NZ flag. When set the
(A) register may contain an error code, but this code does not conform
to RomWBW standard</p>
<p>Success is indicated by setting the Z flag</p>
<p>For a description of switches please see <a href="#romwbw-nvram-configuration">RomWBW NVRAM
Configuration</a></p>
<h4 id="sysget-subfunction-0xd0-get-timer-tick-count-timer">SYSGET Subfunction 0xD0 – Get Timer Tick Count (TIMER)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0xD0</td>
<td>DEHL: Tick Count</td>
</tr>
<tr>
<td></td>
<td>C: Frequency</td>
</tr>
</tbody>
</table>
<p>Return the value of the global system timer Tick Count (DEHL). This is a
double-word binary value. The frequency of the system timer in Hertz is
returned in Frequency (C). The returned Status (A) is a standard HBIOS
result code.</p>
<p>The tick count is a 32 bit binary value. It will rollover to zero if the
maximum value for a 32 bit number is reached.</p>
<p>Note that not all hardware configuration have a system timer. You can
determine if a timer exists by calling this function repeatedly to see
if it is incrementing.</p>
<h4 id="sysget-subfunction-0xd1-get-seconds-count-seconds">SYSGET Subfunction 0xD1 – Get Seconds Count (SECONDS)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0xD1</td>
<td>DEHL: Seconds Count</td>
</tr>
<tr>
<td></td>
<td>C: Remainder Ticks</td>
</tr>
</tbody>
</table>
<p>Return the Seconds Count (DEHL) with the number of seconds that have
elapsed since the system was started. This is a double-word binary
value. Additionally, Remainder Ticks (C) is returned and contains the
number of ticks that have elapsed within the current second.</p>
<p>Note that Remainder Ticks (C) will have a value from 0 to 49 since there
are 50 ticks per second. So, Remainder Ticks does not represent a
fraction of the current second. Remainder Ticks (C) can be doubled to
derive the hundredths of milliseconds elapsed within the current second.</p>
<p>The availability of the Seconds Count (DEHL) is dependent on having a
system timer active. If the hardware configuration has no system timer,
then Seconds Count (DEHL) will not increment.</p>
<h4 id="sysget-subfunction-0xe0-get-boot-information-bootinfo">SYSGET Subfunction 0xE0 – Get Boot Information (BOOTINFO)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0xE0</td>
<td>L: Boot Bank ID</td>
</tr>
<tr>
<td></td>
<td>D: Boot Disk Unit</td>
</tr>
<tr>
<td></td>
<td>E: Boot Disk Slice</td>
</tr>
</tbody>
</table>
<p>This function returns information about the most recent boot operation
performed. It includes the Boot Bank ID (L), the Boot Disk Unit (D), and
the Boot Disk Slice (E). The returned Status (A) is a standard HBIOS
result code.</p>
<h4 id="sysget-subfunction-0xf0-get-cpu-information-cpuinfo">SYSGET Subfunction 0xF0 – Get CPU Information (CPUINFO)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0xF0</td>
<td>H: Z80 CPU Variant</td>
</tr>
<tr>
<td></td>
<td>L: CPU Speed MHz</td>
</tr>
<tr>
<td></td>
<td>DE: CPU Speed KHz</td>
</tr>
<tr>
<td></td>
<td>BC: Oscillator Speed KHz</td>
</tr>
</tbody>
</table>
<p>This function returns information about the active CPU environment. The
Z80 CPU Variant (H) will be one of: 0=Z80, 1=Z180, 2=Z180-K, 3=Z180-N,
4=Z280. The current CPU speed is provided as both CPU Speed MHz (L) and
CPU Speed KHz (DE). The raw oscillator speed is provided as Oscillator
Speed KHz (BC). The returned Status (A) is a standard HBIOS result code.</p>
<h4 id="sysget-subfunction-0xf1-get-memory-information-meminfo">SYSGET Subfunction 0xF1 – Get Memory Information (MEMINFO)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0xF1</td>
<td>D: ROM Bank Count</td>
</tr>
<tr>
<td></td>
<td>E: RAM Bank Count</td>
</tr>
</tbody>
</table>
<p>This function returns the systems ROM Bank Count (D) and RAM Bank Count
(E). Each bank is 32KB by definition. The returned Status (A) is a
standard HBIOS result code.</p>
<h4 id="sysget-subfunction-0xf2-get-bank-information-bnkinfo">SYSGET Subfunction 0xF2 – Get Bank Information (BNKINFO)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0xF2</td>
<td>D: BIOS Bank ID</td>
</tr>
<tr>
<td></td>
<td>E: User Bank ID</td>
</tr>
</tbody>
</table>
<p>Certain memory banks within a RomWBW system are special. The exact bank
id for each of these varies depending on the configuration of the
system. This function can be used to determine the BIOS Bank ID (D) and
the User Bank ID (E). The returned Status (A) is a standard HBIOS result
code.</p>
<h4 id="sysget-subfunction-0xf3-get-cpu-speed-cpuspd">SYSGET Subfunction 0xF3 – Get CPU Speed (CPUSPD)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0xF3</td>
<td>L: Clock Mult</td>
</tr>
<tr>
<td></td>
<td>D: Memory Wait States</td>
</tr>
<tr>
<td></td>
<td>E: I/O Wait States</td>
</tr>
</tbody>
</table>
<p>This function will return the running CPU speed attributes of a system.
The Clock Mult (L) returned indicates the frequency multiple being
applied to the raw oscillator clock. If is defined as: 0=Half, 1=Full,
and 2=Double. The wait states for the system are also provided as Memory
Wait States (D) and I/O Wait States (E). The value of Memory Wait States
(D) is the actual number of wait states, not the number of wait states
added. The returned Status (A) is a standard HBIOS result code.</p>
<h4 id="sysget-subfunction-0xf4-get-front-panel-swithes-panel">SYSGET Subfunction 0xF4 – Get Front Panel Swithes (PANEL)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0xF4</td>
<td>L: Switches</td>
</tr>
</tbody>
</table>
<p>This function will return the current value of the switches (L) from the
front panel of the system. If no front panel is available in the system,
the returned Status (A) will indicate a No Hardware error.</p>
<h4 id="sysget-subfunction-0xf5-get-application-banks-information-appbnks">SYSGET Subfunction 0xF5 – Get Application Banks Information (APPBNKS)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF8</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0xF5</td>
<td>H: App Banks Start ID</td>
</tr>
<tr>
<td></td>
<td>L: App Banks Count</td>
</tr>
<tr>
<td></td>
<td>E: Bank Size</td>
</tr>
</tbody>
</table>
<p>HBIOS may be configured to reserve a number of RAM memory banks that
will be available for application use. This function returns information
about the RAM memory banks currently available for application use. The
function provides the bank id of the first available application bank
(H) and the count of banks available (L). It also returns the size of a
bank expressed as a number of 256-byte pages (E). The returned Status
(A) is a standard HBIOS result code.</p>
<p>The application banks are always a contiguous set of banks, so the App
Banks Start ID can be incremented to address additional banks up to the
limit indicated by App Banks Count. If the App Banks Count is zero, then
there are no application banks available (regardless of the value of App
Banks Start ID).</p>
<p>HBIOS does not provide any mechanism to reserve application banks. Any
concept of allocation of application banks must be implemented within
the OS or application.</p>
<p>This function does not change the current bank selected. You must use
<a href="#function-0xf2-system-set-bank-syssetbnk">Function 0xF2 – System Set Bank
(SYSSETBNK)</a> or the proxy
function <a href="#bank-select-bnksel">Bank Select (BNKSEL)</a> for this. Be sure
to observe the warnings in the description of this function.</p>
<h3 id="function-0xf9-system-set-sysset">Function 0xF9 – System Set (SYSSET)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF9</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Subfunction</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function will set various system parameters based on the
sub-function value. The following lists the subfunctions available along
with the registers/information utilized. The Status (A) is a standard
HBIOS result code.</p>
<h4 id="sysset-subfunction-0xc0-set-switches-switch">SYSSET Subfunction 0xC0 – Set Switches (SWITCH)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF9</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0xC0</td>
<td></td>
</tr>
<tr>
<td>D: Switch Key</td>
<td></td>
</tr>
<tr>
<td>HL: Switch Value</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function will set the value (HL) into the switch (D) and store it
into NVRAM.</p>
<p>Switches may be passed as a 16 bit (HL) or 8 bit (L) value. It is up to
the caller to send the value correctly. Note for Switch 0xFF (reset) the
value (HL) is ignored</p>
<p>Errors are signalled in the return by setting the NZ flag. When set the
(A) register may contain an error code, but this code does not conform
to RomWBW standard</p>
<p>Success is indicated by setting the Z flag</p>
<p>For a description of switches please see <a href="#romwbw-nvram-configuration">RomWBW NVRAM
Configuration</a></p>
<h4 id="sysset-subfunction-0xd0-set-timer-tick-count-timer">SYSSET Subfunction 0xD0 – Set Timer Tick Count (TIMER)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF9</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0xD0</td>
<td>DEHL: Timer Tick Count</td>
</tr>
</tbody>
</table>
<p>This function will explicitly set the system Timer Tick Count (DEHL)
value. DEHL is a double-word binary value. The Status (A) is a standard
HBIOS result code.</p>
<h4 id="sysset-subfunction-0xd1-set-seconds-count-seconds">SYSSET Subfunction 0xD1 – Set Seconds Count (SECONDS)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF9</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0xD1</td>
<td></td>
</tr>
<tr>
<td>DEHL: Seconds Count</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function will explicitly set the system Seconds Count (DEHL) value.
DEHL is a double-word binary value. The Status (A) is a standard HBIOS
result code.</p>
<h4 id="sysset-subfunction-0xe0-set-boot-information-bootinfo">SYSSET Subfunction 0xE0 – Set Boot Information (BOOTINFO)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF9</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0xE0</td>
<td></td>
</tr>
<tr>
<td>L: Boot Bank ID</td>
<td></td>
</tr>
<tr>
<td>D: Boot Disk Unit</td>
<td></td>
</tr>
<tr>
<td>E: Boot Disk Slice</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function sets information about the most recent boot operation
performed. It includes the Boot Bank ID (L), the Boot Disk Unit (D), and
the Boot Disk Slice (E). The returned Status (A) is a standard HBIOS
result code.</p>
<h4 id="sysset-subfunction-0xf3-set-cpu-speed-cpuspd">SYSSET Subfunction 0xF3 – Set CPU Speed (CPUSPD)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF9</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0xF3</td>
<td></td>
</tr>
<tr>
<td>L: Clock Mult</td>
<td></td>
</tr>
<tr>
<td>D: Memory Wait States</td>
<td></td>
</tr>
<tr>
<td>E: I/O Wait States</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function will modify the running CPU speed attributes of a system.
Note that it is frequently impossible to tell if a system is capable of
dynamic speed changes. This function makes the changes blindly. You can
specify 0xFF for either of the wait state settings to have them left
alone. If an attempt is made to change the speed of a system that is
definitely incapable of doing so, then an error result is returned. The
returned Status (A) is a standard HBIOS result code.</p>
<p>The function will attempt to set the CPU speed based on the Clock Mult
(L) value: 0=Half, 1=Full, 2=Double. Memory Wait States (D) and I/O Wait
States (E) will be set if possible. The value of Memory Wait States (D)
is the actual number of wait states, not the number of wait states
added.</p>
<p>Some peripherals are dependent on the CPU speed. For example, the Z180
ASCI baud rate and system timer are derived from the CPU speed. The Set
CPU Speed function will attempt to adjust these peripherals for correct
operation after modifying the CPU speed. However, in some cases this may
not be possible. The baud rate of ASCI ports have a limited set of
divisors. If there is no satisfactory divisor to retain the existing
baud rate under the new CPU speed, then the baud rate of the ASCI
port(s) will be affected.</p>
<h4 id="sysset-subfunction-0xf4-set-front-panel-leds-panel">SYSSET Subfunction 0xF4 – Set Front Panel LEDs (PANEL)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xF9</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0xF4</td>
<td></td>
</tr>
<tr>
<td>L: LEDs</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function will set the front panel LEDs based on the bits in L. If
no front panel is available in the system, the returned Status (A) will
indicate a No Hardware error.</p>
<h3 id="function-0xfa-system-peek-syspeek">Function 0xFA – System Peek (SYSPEEK)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xFA</td>
<td>A: Status</td>
</tr>
<tr>
<td>D: Bank ID</td>
<td>E: Byte Value</td>
</tr>
<tr>
<td>HL: Memory Address</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function retrieves and returns the Byte Value from the specified
Bank ID (D) and Memory Address (HL). The bank specified is not range
checked. The Status (A) is a standard HBIOS result code.</p>
<h3 id="function-0xfb-system-poke-syspoke">Function 0xFB – System Poke (SYSPOKE)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xFB</td>
<td>A: Status</td>
</tr>
<tr>
<td>D: Bank ID</td>
<td></td>
</tr>
<tr>
<td>HL: Memory Address</td>
<td></td>
</tr>
<tr>
<td>E: Byte Value</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function sets the Byte Value (E) in the specified Bank ID (D) and
Memory Address (HL). The bank specified is not range checked. The Status
(A) is a standard HBIOS result code.</p>
<h3 id="function-0xfc-system-interrupt-management-sysint">Function 0xFC – System Interrupt Management (SYSINT)</h3>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xFC</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: Subfunction</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function allows the caller to query information about the interrupt
configuration of the running system and allows adding or hooking
interrupt handlers dynamically. Register C is used to specify a
sub-function. Additional input and output registers may be used as
defined by the sub-function. The Status (A) is a standard HBIOS result
code.</p>
<p>Note that during interrupt processing, the lower 32K of CPU address
space will contain the RomWBW HBIOS code bank, not the lower 32K of
application TPA. As such, a dynamically installed interrupt handler does
not have access to the lower 32K of TPA and must be careful to avoid
modifying the contents of the lower 32K of memory. Invoking RomWBW HBIOS
functions within an interrupt handler is not supported.</p>
<p>Interrupt handlers are different under IM1 and IM2.</p>
<p>Interrupt Mode 1:<br />
The new interrupt handler is responsible for chaining (JP) to the
previous vector if the interrupt is not handled. If the interrupt is
handled, the new handler may simply return (RET). When chaining to the
previous interrupt handler, ZF must be set if interrupt is handled and
ZF cleared if not handled. The interrupt management framework takes care
of saving and restoring AF, BC, DE, HL, and IY. Any other registers
modified must be saved and restored by the interrupt handler.</p>
<p>Interrupt Mode 2:<br />
The new interrupt handler may either replace or hook the previous
interrupt handler. To replace the previous interrupt handler, the new
handler just returns (RET) when done. To hook the previous handler, the
new handler can chain (JP) to the previous vector. Note that initially
all IM2 interrupt vectors are set to be handled as “BAD” meaning that
the interrupt is unexpected. In most cases, you do not want to chain to
the previous vector because it will cause the interrupt to display a
“BAD INT” system panic message.</p>
<p>The interrupt framework will take care of issuing an EI and RETI
instruction. Do not put these instructions in your new handler.
Additionally, interrupt management framework takes care of saving and
restoring AF, BC, DE, HL, and IY. Any other registers modified must be
saved and restored by the interrupt handler.</p>
<p>If the caller is transient, then the caller must remove the new
interrupt handler and restore the original one prior to termination.
This is accomplished by calling this function with the Interrupt Vector
set to the Previous Vector returned in the original call.</p>
<p>The caller is responsible for disabling interrupts prior to making an
INTSET call and enabling them afterwards. The caller is responsible for
ensuring that a valid interrupt handler is installed prior to enabling
any hardware interrupts associated with the handler. Also, if the
handler is transient, the caller must disable the hardware interrupt(s)
associated with the handler prior to uninstalling it.</p>
<h4 id="sysint-subfunction-0x00-interrupt-info-intinf">SYSINT Subfunction 0x00 – Interrupt Info (INTINF)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xFC</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0x00</td>
<td>D: Interrupt Mode</td>
</tr>
<tr>
<td></td>
<td>E: IVT Size</td>
</tr>
</tbody>
</table>
<p>Return current Interrupt Mode (D) of the system. Also return the number
of Interrupt Vector Table (IVT) entries in IVT (E). For IM1, the size of
the table is the number of vectors chained together. For IM2, the size
of the table is the number of slots in the vector table. The Status (A)
is a standard HBIOS result code.</p>
<h4 id="sysint-subfunction-0x10-get-interrupt-intget">SYSINT Subfunction 0x10 – Get Interrupt (INTGET)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xFC</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0x10</td>
<td>HL: IVT Address</td>
</tr>
<tr>
<td>E: IVT Index</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function will return the IVT Address (HL) of the current interrupt
vector for the specified IVT Index (C). The Status (A) is a standard
HBIOS result code.</p>
<h4 id="sysint-subfunction-0x20-set-interrupt-intset">SYSINT Subfunction 0x20 – Set Interrupt (INTSET)</h4>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>B: 0xFC</td>
<td>A: Status</td>
</tr>
<tr>
<td>C: 0x20</td>
<td>HL: Previous Interrupt Address</td>
</tr>
<tr>
<td>E: IVT Index</td>
<td></td>
</tr>
<tr>
<td>HL: Interrupt Address</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function will set a new Interrupt Address (HL) at the IVT Index (E)
specified. On return, the Previous Interrupt Address (HL) will be
provided.</p>
<h2 id="proxy-functions">Proxy Functions</h2>
<p>The following special functions are implemented inside of the HBIOS
proxy area at the top of RAM. They do not cause a bank switch and are,
therefore, much faster than their corresponding HBIOS API functions.</p>
<p>The functions are invoked via the following dedicated jump table:</p>
<table>
<thead>
<tr>
<th><strong>Function</strong></th>
<th><strong>Address</strong></th>
<th>** Equate **</th>
</tr>
</thead>
<tbody>
<tr>
<td>Invoke HBIOS Function (INVOKE)</td>
<td>0xFFF0</td>
<td>HB_INVOKE</td>
</tr>
<tr>
<td>Bank Select (BNKSEL)</td>
<td>0xFFF3</td>
<td>HB_BNKSEL</td>
</tr>
<tr>
<td>Bank Copy (BNKCPY)</td>
<td>0xFFF6</td>
<td>HB_BNKCPY</td>
</tr>
<tr>
<td>Bank Call (BNKCALL)</td>
<td>0xFFF9</td>
<td>HB_BNKCALL</td>
</tr>
</tbody>
</table>
<p>The function addresses are also defined as equates in hbios.inc. It is
suggested that you use the equates when possible.</p>
<p>To use the functions, you may either call or jump to them. Some
examples:</p>
<pre><code> CALL $FFF0
JP $FFF3
CALL HB_BNKCPY
</code></pre>
<p>These functions are inherently dangerous and generally not value
checked. Use with extreme caution.</p>
<h3 id="invoke-hbios-function-invoke">Invoke HBIOS Function (INVOKE)</h3>
<p><strong>Address 0xFFF0</strong></p>
<p>This function is an alternate mechanism for invoking the normal HBIOS
API functions. The parameters and return values are as documented above.
To put it another way, <code>CALL $FFF0</code> is equivalent to <code>RST 08</code>, but it
can be used in any scenario when the normal bank is not selected.</p>
<h3 id="bank-select-bnksel">Bank Select (BNKSEL)</h3>
<p><strong>Address 0xFFF3</strong></p>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>A: Bank ID</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function will select the memory bank identified by Bank ID (A).
Register AF is destroyed. All other registers are preserved.</p>
<p>The warnings described in <a href="#function-0xf2-system-set-bank-syssetbnk">Function 0xF2 – System Set Bank
(SYSSETBNK)</a> should be
observed.</p>
<h3 id="bank-copy-bnkcpy">Bank Copy (BNKCPY)</h3>
<p><strong>Address 0xFFF6</strong></p>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>HL: Source Address</td>
<td>HL: Ending Source Address</td>
</tr>
<tr>
<td>DE: Destination Address</td>
<td>DE: Ending Destination Address</td>
</tr>
<tr>
<td>BC: Count</td>
<td>BC: 0</td>
</tr>
<tr>
<td>HB_SRCBNK: Source Bank ID</td>
<td></td>
</tr>
<tr>
<td>HB_DSTBNK: Destination Bank ID</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function will copy Count (BC) bytes from Source Address (HL) in
Source Bank ID (HB_SRCBNK) to Destination Address (DE) in Destination
Bank ID (HB_DSTBNK). The HB_SRCBNK and HB_DSTBNK fields are dedicated
locations in the proxy. These locations are defined in hbios.inc:</p>
<ul>
<li>Source Bank ID: <code>HB_SRCBNK</code> = \$FFE4</li>
<li>Destination Bank ID: <code>HB_DSTBNK</code> = \$FFE7</li>
</ul>
<p>The Source Bank ID and Destination Bank ID values must be populated in
the specified addresses before calling this function.</p>
<p>During processing, HL and DE, will be incremented. At termination, HL
and DE will contain the “next” source/destination addresses that would
be copied. This allows this function to be invoked repeatedly to copy
continuous blocks of data.</p>
<p>Register AF is destroyed by this function. Register BC will be 0.</p>
<h3 id="bank-call-bnkcall">Bank Call (BNKCALL)</h3>
<p><strong>Address 0xFFF9</strong></p>
<table>
<thead>
<tr>
<th><strong>Entry Parameters</strong></th>
<th><strong>Returned Values</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>A: Target Bank ID</td>
<td></td>
</tr>
<tr>
<td>IX: Target Address</td>
<td></td>
</tr>
</tbody>
</table>
<p>This function will perform a function call to a routine in another bank.
It does this by selecting the Target Bank ID (A) and then calling the
Target Address (IX). On return from the target function, the originally
active bank is selected.</p>
<p>Register usage is determined by the routine that is called.</p>
<p>Since a different bank will be selected while the target function is
active, the warnings described in <a href="#function-0xf2-system-set-bank-syssetbnk">Function 0xF2 – System Set Bank
(SYSSETBNK)</a> should be
observed.</p>
<h1 id="errors-and-diagnostics">Errors and diagnostics</h1>
<p>ROMWBW tries to provide useful information when a run time or build time
error occurs. Many sections of the code also have code blocks that can
be enable to aid in debugging and in some cases the level of reporting
detail can be customized.</p>
<h2 id="run-time-errors">Run Time Errors</h2>
<h3 id="panic">PANIC</h3>
<p>A panic error indicates a non-recoverable error. The processor status is
displayed on the console and interrupts are disabled and execution is
halted. A cold boot or reset is required to restart.</p>
<p>Example error message:</p>
<pre><code>&gt;&gt;&gt; PANIC: @06C4[DFA3:DFC3:0100:F103:04FC:0000:2B5E]
*** System Halted ***
</code></pre>
<p>The format of the information provided is</p>
<p><code>@XXXX [-AF-:-BC-:-DE-:-HL-:-SP-:-IX-:-IY-]</code></p>
<p>Where <code>@XXXX</code> is the address the panic was called from. The other
information is the CPU register contents.</p>
<p>Possible reasons a PANIC may occur are:</p>
<ul>
<li>RAM Bank range error when attempting a read or write to a RAM disk.</li>
<li>Sector read function has not been setup but a read was attempted.</li>
<li>An interrupt vector has not been set up when an interrupt was
received.</li>
<li>There was an attempt to add more devices than the device table had
room for.</li>
<li>An illegal SD card command was encountered.</li>
</ul>
<p>The <code>@XXXX</code> memory address can be cross referenced with the build source
code to identify which section of the software or hardware caused the
fault.</p>
<h3 id="syschk">SYSCHK</h3>
<p>A syschk error is identified when an internal error is detected. When
this occurs an error code is returned to the calling program in the A
register. A non-zero result indicates an error.</p>
<p>Syschk errors may be reported to the console. Whether this occurs
depends on the value of the diagnosis level equate DIAGLVL. By default
syschk errors are not reported to the console.</p>
<p>If the diagnosis level is set to display the diagnosis information, then
memory address, register dump and error code is displayed. A key
difference with the PANIC error is that execution may be continued.</p>
<p>Example error message:</p>
<p>&gt;&gt;&gt; SYSCHK: @06C4 [DFA3:DFC3:0100:F103:04FC:0000:2B5E] FD Continue
(Y/N)</p>
<p>The format of the information provided is similar the PANIC report.</p>
<p>@XXXX [-AF-:-BC-:-DE-:-HL-:-SP-:-IX-:-IY-] YY</p>
<p>The syschk error codes YY is returned in the A register.</p>
<table>
<thead>
<tr>
<th>Error</th>
<th>Code YY</th>
</tr>
</thead>
<tbody>
<tr>
<td>Success</td>
<td>0x00</td>
</tr>
<tr>
<td>Undefined Error</td>
<td>0xFF</td>
</tr>
<tr>
<td>Function Not Implemented</td>
<td>0xFE</td>
</tr>
<tr>
<td>Invalid Function</td>
<td>0xFD</td>
</tr>
<tr>
<td>Invalid Unit Number</td>
<td>0xFC</td>
</tr>
<tr>
<td>Out Of Memory</td>
<td>0xFB</td>
</tr>
<tr>
<td>Parameter Out Of Range</td>
<td>0xFA</td>
</tr>
<tr>
<td>Media Not Present</td>
<td>0xF9</td>
</tr>
<tr>
<td>Hardware Not Present</td>
<td>0xF8</td>
</tr>
<tr>
<td>I/O Error</td>
<td>0xF7</td>
</tr>
<tr>
<td>Write Request To Read-Only Media</td>
<td>0xF6</td>
</tr>
<tr>
<td>Device Timeout</td>
<td>0xF5</td>
</tr>
<tr>
<td>Invalid Configuration</td>
<td>0xF4</td>
</tr>
<tr>
<td>Internal Error</td>
<td>0xF3</td>
</tr>
</tbody>
</table>
<h3 id="error-level-reporting">Error Level reporting</h3>
<p>placeholder</p>
<h2 id="build-time-errors">Build time errors</h2>
<h3 id="build-chain-tool-errors">Build chain tool errors</h3>
<p>place holder</p>
<h3 id="assembly-time-check-errors">Assembly time check errors</h3>
<p>placeholder</p>
<h2 id="diagnostics">Diagnostics</h2>
<h3 id="diagnostic-leds">Diagnostic LEDs</h3>
<p>Progress through the boot and initialization process can be difficult to
monitor due to the lack of console or video output. Access to these
output devices does not become available until late the in the boot
process. If these output devices are also involved with the issue trying
to be resolved then trouble shooting is even more difficult.</p>
<p>ROMWBW can be configured to display boot progress with the assistance of
additional hardware. This can take the form of a front panel LED display
or LED breakout debugging board connected to an 8-bit output port. Or it
can utilize existing platform status LEDS.</p>
<p>As the boot code executes, the LED output display is updated to indicate
the execution progress.</p>
<p>Platforms that have these capabilities built in have them enabled by
default.</p>
<h4 id="front-panel-display">Front Panel display</h4>
<p>A LED front panel or breakout board needs to be connected the computers
data, reset and port select lines.</p>
<p>To enable this option the following settings can be made in the
platforms custom configuration file.</p>
<pre><code>FPLED_ENABLE .SET TRUE ; ENABLE FRONT PANEL
</code></pre>
<p>Custom hardware can be configured with :</p>
<pre><code>FPLED_IO .SET $nn ; USE PORT ADDRESS nn
FPLED_INV .SET FALSE ; INVERTED LED BITS
</code></pre>
<h4 id="platform-status-leds">Platform Status LEDS</h4>
<p>These status LEDs use preexisting status LEDs on each platform.</p>
<p>Enable using:</p>
<pre><code>LEDENABLE .SET TRUE ; ENABLES STATUS LED
</code></pre>
<p>Customize using:</p>
<pre><code>LEDMODE .SET LEDMODE_STD ; LEDMODE_[STD|SC|RTC|NABU]
LEDPORT .SET $nn ; STATUS LED PORT ADDRESS
</code></pre>
<p>The following table shows the ROMWBW process steps in relation to the
panel display.</p>
<table>
<thead>
<tr>
<th><strong>PANEL</strong></th>
<th><strong>RomWBW Processes</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><code>........</code></td>
<td>Initial boot</td>
</tr>
<tr>
<td></td>
<td>Jump to start address</td>
</tr>
<tr>
<td></td>
<td>Disable interrupts</td>
</tr>
<tr>
<td></td>
<td>Set interrupt mode</td>
</tr>
<tr>
<td></td>
<td>Initialize critical ports and baud rate</td>
</tr>
<tr>
<td><code>.......O</code></td>
<td>Setup initial stack</td>
</tr>
<tr>
<td></td>
<td>Memory manager and CPU configuration</td>
</tr>
<tr>
<td></td>
<td>Set top bank to be RAM</td>
</tr>
<tr>
<td><code>......OO</code></td>
<td>Get and save battery condition</td>
</tr>
<tr>
<td></td>
<td>Install HBIOS proxy in upper memory</td>
</tr>
<tr>
<td></td>
<td>If platform is MBC reconfigure memory manager</td>
</tr>
<tr>
<td></td>
<td>Setup “ROMLESS” HBIOS image or …</td>
</tr>
<tr>
<td></td>
<td>Copy HBIOS from ROM to RAM if RAM flag not set</td>
</tr>
<tr>
<td></td>
<td>Jump to HBIOS in RAM</td>
</tr>
<tr>
<td></td>
<td>Set running in RAM flag</td>
</tr>
<tr>
<td><code>.....OOO</code></td>
<td>Finalize configuration for running in RAM</td>
</tr>
<tr>
<td></td>
<td>Check battery condition</td>
</tr>
<tr>
<td></td>
<td>Check for recovery mode boot</td>
</tr>
<tr>
<td><code>....OOOO</code></td>
<td>Identify CPU type</td>
</tr>
<tr>
<td><code>...OOOOO</code></td>
<td>Set cpu oscillator speed</td>
</tr>
<tr>
<td></td>
<td>Setup counter-timers</td>
</tr>
<tr>
<td></td>
<td>Setup heap</td>
</tr>
<tr>
<td><code>..OOOOOO</code></td>
<td>Preconsole initialization</td>
</tr>
<tr>
<td><code>.OOOOOOO</code></td>
<td>Boot delay</td>
</tr>
<tr>
<td></td>
<td>Set boot console device</td>
</tr>
<tr>
<td></td>
<td>Bios announcement</td>
</tr>
<tr>
<td><code>OOOOOOOO</code></td>
<td>Display platform information</td>
</tr>
<tr>
<td></td>
<td>Display memory configuration</td>
</tr>
<tr>
<td></td>
<td>Display CPU family</td>
</tr>
<tr>
<td></td>
<td>Verify ROM checksum</td>
</tr>
<tr>
<td></td>
<td>Report battery condition</td>
</tr>
<tr>
<td></td>
<td>Perform device driver initialization</td>
</tr>
<tr>
<td></td>
<td>Report watchdog status</td>
</tr>
<tr>
<td></td>
<td>Mark HBIOS heap so it is preserved</td>
</tr>
<tr>
<td></td>
<td>Switch from boot console to CRT if active</td>
</tr>
<tr>
<td></td>
<td>Display device summary</td>
</tr>
<tr>
<td></td>
<td>Execute boot loader</td>
</tr>
</tbody>
</table>
<h3 id="appendix-a-driver-instance-data-fields">Appendix A Driver Instance Data fields</h3>
<p><strong>This section is a work in progress…</strong></p>
<p>The following section outlines the read only data referenced by the
<code>SYSGET</code>, subfunctions <code>xxxFN</code> for specific drivers.</p>
<h4 id="tms9918-driver">TMS9918 Driver:</h4>
<table>
<thead>
<tr>
<th><strong>Name</strong></th>
<th><strong>Offset</strong></th>
<th><strong>Bytes</strong></th>
<th><strong>Description</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>PPIA</td>
<td>0</td>
<td>1</td>
<td>PPI PORT A</td>
</tr>
<tr>
<td>PPIB</td>
<td>1</td>
<td>1</td>
<td>PPI PORT B</td>
</tr>
<tr>
<td>PPIC</td>
<td>2</td>
<td>1</td>
<td>PPI PORT C</td>
</tr>
<tr>
<td>PPIX</td>
<td>3</td>
<td>1</td>
<td>PPI CONTROL PORT</td>
</tr>
<tr>
<td>DATREG</td>
<td>4</td>
<td>1</td>
<td>IO PORT ADDRESS FOR MODE 0</td>
</tr>
<tr>
<td>CMDREG</td>
<td>5</td>
<td>1</td>
<td>IO PORT ADDRESS FOR MODE 1</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td><em>Below are the register mirror values</em></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td><em>that HBIOS used for initialisation</em></td>
</tr>
<tr>
<td>REG. 0</td>
<td>6</td>
<td>1</td>
<td>\$00 - NO EXTERNAL VID</td>
</tr>
<tr>
<td>REG. 1</td>
<td>7</td>
<td>1</td>
<td>\$50 or \$70 - SET MODE 1 and interrupt if enabled</td>
</tr>
<tr>
<td>REG. 2</td>
<td>8</td>
<td>1</td>
<td>\$00 - PATTERN NAME TABLE := 0</td>
</tr>
<tr>
<td>REG. 3</td>
<td>9</td>
<td>1</td>
<td>\$00 - NO COLOR TABLE</td>
</tr>
<tr>
<td>REG. 4</td>
<td>10</td>
<td>1</td>
<td>\$01 - SET PATTERN GENERATOR TABLE TO \$800</td>
</tr>
<tr>
<td>REG. 5</td>
<td>11</td>
<td>1</td>
<td>\$00 - SPRITE ATTRIBUTE IRRELEVANT</td>
</tr>
<tr>
<td>REG. 6</td>
<td>12</td>
<td>1</td>
<td>\$00 - NO SPRITE GENERATOR TABLE</td>
</tr>
<tr>
<td>REG. 7</td>
<td>13</td>
<td>1</td>
<td>\$F0 - WHITE ON BLACK</td>
</tr>
<tr>
<td>DCNTL*</td>
<td>14</td>
<td>1</td>
<td>Z180 DMA/WAIT CONTROL</td>
</tr>
</tbody>
</table>
<ul>
<li>ONLY PRESENT FOR Z180 BUILDS</li>
</ul></div>
</div>
</div>
<footer class="col-md-12">
<hr>
<p>Documentation built with <a href="https://www.mkdocs.org/">MkDocs</a>.</p>
</footer>
<script src="../js/bootstrap.bundle.min.js"></script>
<script>
var base_url = "..",
shortcuts = {"help": 191, "next": 78, "previous": 80, "search": 83};
</script>
<script src="../js/base.js"></script>
<script src="../search/main.js"></script>
<div class="modal" id="mkdocs_search_modal" tabindex="-1" role="dialog" aria-labelledby="searchModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="searchModalLabel">Search</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>From here you can search these documents. Enter your search terms below.</p>
<form>
<div class="form-group">
<input type="search" class="form-control" placeholder="Search..." id="mkdocs-search-query" title="Type search term here">
</div>
</form>
<div id="mkdocs-search-results" data-no-results-text="No results found"></div>
</div>
<div class="modal-footer">
</div>
</div>
</div>
</div><div class="modal" id="mkdocs_keyboard_modal" tabindex="-1" role="dialog" aria-labelledby="keyboardModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="keyboardModalLabel">Keyboard Shortcuts</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<table class="table">
<thead>
<tr>
<th style="width: 20%;">Keys</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td class="help shortcut"><kbd>?</kbd></td>
<td>Open this help</td>
</tr>
<tr>
<td class="next shortcut"><kbd>n</kbd></td>
<td>Next page</td>
</tr>
<tr>
<td class="prev shortcut"><kbd>p</kbd></td>
<td>Previous page</td>
</tr>
<tr>
<td class="search shortcut"><kbd>s</kbd></td>
<td>Search</td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
</div>
</div>
</div>
</div>
</body>
</html>