83 KiB
$define{doc_title}{Architecture}$ $include{"Common.h"}$
Overview
RomWBW provides a complete firmware package for all of the Z80 and Z180 based systems that are available in the RetroBrew Computers Community (see http://www.retrobrewcomputers.org) as well as support for the RC2014 platform. Each of these systems provides for a fairly large ROM memory (typically, 512KB or more). RomWBW allows you to configure and build appropriate contents for such a ROM.
Typically, a computer will contain a small ROM that contains the BIOS (Basic Input/Output System) functions as well as code to start the system by booting an operating system from a disk. Since the RetroBrew Computers Projects provide a large ROM space, RomWBW provides a much more comprehensive software package. In fact, it is entirely possible to run a fully functioning RetroBrew Computers System with nothing but the ROM.
RomWBW firmware includes:
-
System startup code (bootstrap)
-
A basic system/debug monitor
-
HBIOS (Hardware BIOS) providing support for the vast majority of RetroBrew Computers I/O components
-
Diagnostics and customizable debugging information.
-
A complete operating system (either CP/M 2.2 or ZSDOS 1.1)
-
A built-in CP/M filesystem containing the basic applications and utilities for the operating system and hardware being used
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 system is simply a ROM-based copy of generic CP/M or ZSDOS. Much of the hardware support code was originally produced by other members of the RetroBrew Computers Community.
The remainder of this document will focus on the HBIOS portion of the ROM. HBIOS contains the vast majority of the custom-developed code for the RetroBrew Computers hardware platforms. It provides a formal, structured interface that allows the operating system to be hosted with relative ease.
Background
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.
All RetroBrew Computers Z80 CPU platforms provide a physical address space that is much larger than the CPU address space (typically 512K or 1MB 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 RetroBrew Computers platforms, 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 only 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.
By cleverly 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 RetroBrew Computers Project 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.
General Design Strategy
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.
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 a small 512 byte area at the top of the CPU address space.
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.
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.
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 for subsequent execution.
Runtime Memory Layout
System Boot Process
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.
Boot Phase 1 copies the phase 2 code to upper memory and jumps to it to continue the boot process. This is required because the CPU starts at address $0000 in low memory. However, low memory is used as the area for switching ROM/RAM banks in and out. Therefore, it is necessary to relocate execution to high memory in order to initialize the RAM memory banks.
Boot Phase 2 manages the setup of the RAM page banks for HBIOS operation, performs hardware initialization, and then executes the boot loader.
Boot Phase 3 is the loading of the selecting operating system (or debug monitor) by the Boot Loader. The Boot Loader is responsible for prompting the user to select a target operating system to load, loading it into RAM, then transferring control to it. The Boot Loader is capable of loading a target operating system from a variety of locations including disk drives and ROM.
Note that the entire 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 it's own initialization and begin normal operation.
There are actually two ways to perform a system boot. The first, and most commonly used, method is a "ROM Boot". This refers to booting the system directly from the startup code contained on the physical ROM chip. A ROM Boot is always performed upon power up or when a hardware reset is performed.
Once the system is running (operating system loaded), it is possible to reboot the system from a system image contained on the file system. This is referred to as an "Application Boot". This mechanism allows a temporary copy of the system to be uploaded and stored on the file system of an already running system and then used to boot the system. 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.
A more detailed explanation of these two boot processes is presented below.
ROM Boot
At power on (or hardware reset), ROM page 0 is automatically mapped to lower memory by hardware level system initialization. Page Zero (first 256 bytes of the CPU address space) is reserved to contain dispatching instructions for interrupt instructions. Address $0000 performs a jump to the start of the phase 1 code so that this first page can be reserved.
The phase 1 code now copies the phase 2 code from lower memory to upper memory and jumps to it. The phase 2 code now initializes the HBIOS by copying the ROM resident HBIOS from ROM to RAM. It subsequently calls the HBIOS initialization routine. Finally, it starts the Boot Loader which prompts the user for the location of the target system image to execute.
Once the boot loader transfers control to the target system image, all of the Phase 1, Phase 2, and Boot Loader code is abandoned and the space it occupied is normally overwritten by the operating system.
Application Boot
When a new system image is built, one of the output files produced is an actual CP/M application (an executable .COM program file). 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.
Upon execution, the Application Boot program is loaded into memory by the previously running operating system starting at $0100. Note that program image contains a 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.
Specifically, the code at $0100 (in low memory) copies phase 2 boot code to upper memory and transfers control to it. The phase 2 boot code copies the HBIOS image from application RAM to RAM, then calls the HBIOS initialization routine. At this point, the prior HBIOS code has been discarded and overwritten. Finally, the Boot Loader is invoked just like a ROM Boot.
ROM-less Boot
Some hardware supported by RomWBW has a special mechanism for loading the initial code. These systems have no ROM chips. However, they have a small hardware bootstrap that loads a chunk of code from a disk device directlly into RAM at system startup.
The startup then proceeds very much like the Application Boot process described above. HBIOS is installed in it's operating bank and control is passed to the loader.
Notes
-
Size of ROM disk and RAM disk will be decreased as needed to accommodate RAM and ROM memory bank usage for the banked BIOS.
-
There is no support for interrupt driven drivers at this time. Such support should be possible in a variety of ways, but none are yet implemented.
Driver Model
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.
However, the one constraint of hardware drivers is that any data buffers that are to be returned to the operating system or applications must be allocated in high memory. Buffers inside of the driver's memory bank will be swapped out of the CPU address space when control is returned to the operating system.
If the driver code must make calls to other code, drivers, or utilities in the driver 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.
Character / Emulation / Video Services
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.).
Figure 7.1 depicts the relationship between these components of HBIOS video processing:
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.
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.
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.
HBIOS Reference
Invocation
HBIOS functions are invoked by placing the required parameters in CPU registers and executing an RST 08 instruction. Note that HBIOS does not preserve register values that are unused. However, it will not modify the Z80 alternate registers or IX/IY (these registers may be used within HBIOS, but will be saved and restored internally).
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.
In general, the desired function is placed in the B register. Register C is frequently used to specify a subfunction 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. A=0 should indicate success, other values are function specific.
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 consoled 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.
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.
Error Codes
The following error codes are defined generically for all HBIOS functions. Most function calls will return a result in register A.
| Code | Meaning |
|---|---|
| 0 | function succeeded |
| -1 | undefined error |
| -2 | function not implemented |
| -3 | invalid function |
| -4 | invalid unit numberr |
| -5 | out of memory |
| -6 | parameter out of range |
| -7 | media not present |
| -8 | hardware not present |
| -9 | I/O error |
| -10 | write request to read-only media |
| -11 | device timeout |
| -12 | invalid configuration |
\clearpage{=latex}
Character Input/Output (CIO)
Character input/output functions require that a Character Unit be specified in the C register. This is the logical device unit number assigned during the boot process that identifies all character I/O devices uniquely. A special value of 0x80 can be used for Unit to refer to the current console device.
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:
| Bits | Function |
|---|---|
| 15-14 | Reserved (set to 0) |
| 13 | RTS |
| 12-8 | Baud Rate (see below) |
| 7 | DTR |
| 6 | XON/XOFF Flow Control |
| 5-3 | Parity (???) |
| 2 | Stop Bits (???) |
| 1-0 | Data Bits (???) |
The 5-bit baud rate value (V) is encoded as V = 75 * 2^X * 3^Y. The bits are defined as YXXXX.
Function 0x00 -- Character Input (CIOIN)
| Entry Parameters | B: 0x00 | C: Serial Device Unit Number
| Exit Results | A: Status (0=OK, else error) | E: Character Received
Read a character from the device unit specified in register C and return the character value in E. If no character(s) are available, this function will wait indefinitely.
Function 0x01 -- Character Output (CIOOUT)
| Entry Parameters | B: 0x01 | C: Serial Device Unit Number | E: Character to Send
| Exit Results | A: Status (0=OK, else error)
Send character value in register E to device specified in register C. If device is not ready to send, function will wait indefinitely.
Function 0x02 -- Character Input Status (CIOIST)
| Entry Parameters | B: 0x02 | C: Serial Device Unit Number
| Exit Results | A: Bytes Pending
Return the number of characters available to read in the input buffer of the unit specified. If the device has no input buffer, it is acceptable to return simply 0 or 1 where 0 means there is no character available to read and 1 means there is at least one character available to read.
Function 0x03 -- Character Output Status (CIOOST)
| Entry Parameters | B: 0x03 | C: Serial Device Unit Number
| Exit Results | A: Output Buffer Bytes Available
Return the space available in the output buffer expressed as a character count. If a 16 byte output buffer contained 6 characters waiting to be sent, this function would return 10, the number of positions available in the output buffer. If the port has no output buffer, it is acceptable to return simply 0 or 1 where 0 means the port is busy and 1 means the port is ready to output a character.
Function 0x04 -- Character IO Initialization (CIOINIT)
| Entry Parameters | B: 0x04 | C: Serial Device Unit Number | DE: Line Characteristics
| Exit Results | A: Status (0=OK, else error)
Setup line characteristics (baudrate, framing, etc.) of the specified unit. Register pair DE specifies line characteristics. If DE contains -1 (0xFFFF), then the device will be reinitialized with the last line characteristics used. Result of function is returned in A with zero indicating success.
Function 0x05 -- Character IO Query (CIOQUERY)
| Entry Parameters | B: 0x05 | C: Serial Device Unit Number
| Exit Results | A: Status (0=OK, else error) | DE: Line Characteristics
Reports the line characteristics (baudrate, framing, etc.) of the specified unit. Register pair DE contains the line characteristics upon return.
Function 0x06 -- Character IO Device (CIODEVICE)
| Entry Parameters | B: 0x06 | C: Serial Device Unit Number
| Exit Results | A: Status (0=OK, else error) | C: Serial Device Attributes | D: Serial Device Type | E: Serial Device Number | H: Serial Device Unit Mode | L: Serial Device Unit I/O Base Address
Reports information about the character device unit specified. Register C indicates the device attributes: 0=RS-232 and 1=Terminal. Register D indicates the device type (driver) and register E indicates the physical device number assigned by the driver.
Each character device is handled by an appropriate driver (UART, ASCI, etc.). The driver can be identified by the Device Type. The assigned Device Types are listed below.
| Id | Device Type / Driver |
|---|---|
| 0x00 | UART |
| 0x10 | ASCI |
| 0x20 | Terminal |
| 0x30 | PropIO VGA |
| 0x40 | ParPortProp VGA |
| 0x50 | SIO |
| 0x60 | ACIA |
| 0x70 | PIO |
| 0x80 | UF |
\clearpage{=latex}
Disk Input/Output (DIO)
Disk input/output functions require that a disk unit be specified in the C register. This is the logical disk unit number assigned during the boot process that identifies all disk i/o devices uniquely.
A fixed set of media types are defined. The currently defined media types are listed below. Each driver will support a subset of the defined media types.
| Media ID | Value | Format |
|---|---|---|
| MID_NONE | 0 | No media installed |
| MID_MDROM | 1 | ROM Drive |
| MID_MDRAM | 2 | RAM Drive |
| MID_RF | 3 | RAM Floppy (LBA) |
| MID_HD | 4 | Hard Disk (LBA) |
| MID_FD720 | 5 | 3.5" 720K Floppy |
| MID_FD144 | 6 | 3.5" 1.44M Floppy |
| MID_FD360 | 7 | 5.25" 360K Floppy |
| MID_FD120 | 8 | 5.25" 1.2M Floppy |
| MID_FD111 | 9 | 8" 1.11M Floppy |
| MID_HDNEW | 10 | Hard Disk with 1024 Directory entries |
Function 0x10 -- Disk Status (DIOSTATUS)
| Entry Parameters | B: 0x10 | C: Disk Device Unit ID
| Exit Results | A: Status (0=OK, else error)
Function 0x11 -- Disk Reset (DIORESET)
| Entry Parameters | B: 0x11 | C: Disk Device Unit ID
| Exit Results | A: Status (0=OK, else error)
Reset the physical interface associated with the specified unit. Flag all units associated with the interface for unit initialization at next I/O call. Clear media identified unless locked. Reset result code of all associated units of the physical interface.
Function 0x12 -- Disk Seek (DIOSEEK)
| Entry Parameters | B: 0x12 | C: Disk Device Unit ID | D7: Address Type (0=CHS, 1=LBA)
| if CHS: | D6-0: Head | E: Sector | HL: Track
| if LBA: | DE:HL: Block Address
| Exit Results | A: Status (0=OK, else error)
Update target CHS or LBA for next I/O request on designated unit. Physical seek is typically deferred until subsequent I/O operation.
Bit 7 of D indicates whether the disk seek address is specified as cylinder/head/sector (CHS) or Logical Block Address (LBA). If D:7=1, then the remaining bits of of the 32 bit register set DE:HL specify a linear, zero offset, block number. If D:7=0, then the remaining bits of D specify the head, E specifies sector, and HL specifies track.
Note that not all devices will accept both types of addresses. Specifically, floppy disk devices must have CHS addresses. All other devices will accept either CHS or LBA. The DIOGEOM function can be used to determine if the device supports LBA addressing.
Function 0x13 -- Disk Read (DIOREAD)
| Entry Parameters | B: 0x13 | C: Disk Device Unit ID | D: Bank ID | E: Block Count | HL: Buffer Address
| Exit Results | A: Status (0=OK, else error) | E: Blocks Read
Read Block Count sectors to buffer address starting at current target sector. Current sector must be established by prior seek function; however, multiple read/write/verify function calls can be made after a seek function. Current sector is incremented after each sector successfully read. On error, current sector is sector where error occurred. Blocks read indicates number of sectors successfully read.
Caller must ensure: 1) buffer address is large enough to contain data for all sectors requested, and 2) does not cross a 32k memory bank boundary.
Function 0x14 -- Disk Write (DIOWRITE)
| Entry Parameters | B: 0x14 | C: Disk Device Unit ID | D: Bank ID | E: Block Count | HL: Buffer Address
| Exit Results | A: Status (0=OK, else error) | E: Blocks Written
Write Block Count sectors to buffer address starting at current target sector. Current sector must be established by prior seek function; however, multiple read/write/verify function calls can be made after a seek function. Current sector is incremented after each sector successfully written. On error, current sector is sector where error occurred. Blocks written indicates number of sectors successfully written.
Caller must ensure the source buffer does not cross a 32k memory bank boundary.
Function 0x15 -- Disk Verify (DIOVERIFY)
| Entry Parameters | B: 0x15 | C: Disk Device Unit ID | HL: Buffer Address | E: Block Count
| Exit Results | A: Status (0=OK, else error) | E: Blocks Verified
***Not Implemented***
Function 0x16 -- Disk Format (DIOFORMAT)
| Entry Parameters | B: 0x16 | C: Disk Device Unit ID | D: Head | E: Fill Byte | HL: Cylinder
| Exit Results | A: Status (0=OK, else error)
***Not Implemented***
Function 0x17 -- Disk DEVICE (DIODEVICE)
| Entry Parameters | B: 0x17 | C: Disk Device Unit ID
| Exit Results | A: Status (0=OK, else error) | C: Attributes | D: Device Type | E: Device Number | H: Disk Device Unit Mode | L: Disk Device Unit I/O Base Address
Reports information about the character device unit specified. Register D indicates the device type (driver) and register E indicates the physical device number assigned by the driver.
Register C reports the following device attributes:
Bit 7: 1=Floppy, 0=Hard Disk (or similar, e.g. CF, SD, RAM)
| If Floppy: | Bits 6-5: Form Factor (0=8", 1=5.25", 2=3.5", 3=Other) | Bit 4: Sides (0=SS, 1=DS) | Bits 3-2: Density (0=SD, 1=DD, 2=HD, 3=ED) | Bits 1-0: Reserved
| If Hard Disk: | Bit 6: Removable | Bits: 5-3: Type (0=Hard, 1=CF, 2=SD, 3=USB, | 4=ROM, 5=RAM, 6=RAMF, 7=FLASH) | Bits 2-0: Reserved
Each disk device is handled by an appropriate driver (IDE, SD, etc.) which is identified by a device type id from the table below.
| Type ID | Disk Device Type |
|---|---|
| 0x00 | Memory Disk |
| 0x10 | Floppy Disk |
| 0x20 | RAM Floppy |
| 0x30 | IDE Disk |
| 0x40 | ATAPI Disk (not implemented) |
| 0x50 | PPIDE Disk |
| 0x60 | SD Card |
| 0x70 | PropIO SD Card |
| 0x80 | ParPortProp SD Card |
| 0x90 | SIMH HDSK Disk |
Function 0x18 -- Disk Media (DIOMEDIA)
| Entry Parameters | B: 0x18 | C: Disk Device Unit ID | E0: Enable Media Discovery
| Exit Results | A: Status (0=OK, else error) | E: Media ID
Report the media definition for media in specified unit. If bit 0 of E is set, then perform media discovery or verification. If no media in device, function will return an error status.
Function 0x19 -- Disk Define Media (DIODEFMED)
| Entry Parameters | B: 0x19 | C: Disk Device Unit ID | E: Media ID
| Exit Results | A: Status (0=OK, else error)
*** Not implemented ***
Function 0x1A -- Disk Capacity (DIOCAPACITY)
| Entry Parameters | B: 0x1A | C: Disk Device Unit ID
| Exit Results | A: Status (0=OK, else error) | DE:HL: Blocks on Device | BC: Block Size
Report current media capacity information. DE:HL is a 32 bit number representing the total number of blocks on the device. BC contains the block size. If media is unknown, an error will be returned.
Function 0x1B -- Disk Geometry (DIOGEOMETRY)
| Entry Parameters | B: 0x1B | C: Disk Device Unit ID
| Exit Results | A: Status (0=OK, else error) | HL: Cylinders | D7: LBA Capability | BC: Block Size
Report current media geometry information. If media is unknown, return error (no media).
\clearpage{=latex}
Real Time Clock (RTC)
The Real Time Clock functions provide read/write access to the clock and related Non-Volatile RAM.
The time functions (RTCGTM and RTCSTM) require a 6 byte date/time buffer of the following format. Each byte is BCD encoded.
| Offset | Contents |
|---|---|
| 0 | Year (00-99) |
| 1 | Month (01-12) |
| 2 | Date (01-31) |
| 3 | Hours (00-24) |
| 4 | Minutes (00-59) |
| 5 | Seconds (00-59) |
Function 0x20 -- RTC Get Time (RTCGETTIM)
| Entry Parameters | B: 0x20 | HL: Time Buffer Address
| Exit Results | A: Status (0=OK, else error)
Read the current value of the clock and store the date/time in the buffer pointed to by HL.
Function 0x21 -- RTC Set Time (RTCSETTIM)
| Entry Parameters | B: 0x21 | HL: Time Buffer Address
| Exit Results | A: Status (0=OK, else error)
Set the current value of the clock based on the date/time in the buffer pointed to by HL.
Function 0x22 -- RTC Get NVRAM Byte (RTCGETBYT)
| Entry Parameters | B: 0x22 | C: Index
| Exit Results | A: Status (0=OK, else error) | E: Value
Read a single byte value from the Non-Volatile RAM at the index specified by C. The value is returned in register E.
Function 0x23 -- RTC Set NVRAM Byte (RTCSETBYT)
| Entry Parameters | B: 0x23 | C: Index
| Exit Results | A: Status (0=OK, else error) | E: Value
Write a single byte value into the Non-Volatile RAM at the index specified by C. The value to be written is specified in E.
Function 0x24 -- RTC Get NVRAM Block (RTCGETBLK)
| Entry Parameters | B: 0x24 | HL: Buffer
| Exit Results | A: Status (0=OK, else error)
Read the entire contents of the Non-Volatile RAM into the buffer pointed to by HL. HL must point to a location in the top 32K of CPU address space.
Function 0x25 -- RTC Set NVRAM Block (RTCSETBLK)
| Entry Parameters | B: 0x25 | HL: Buffer
| Exit Results | A: Status (0=OK, else error)
Write the entire contents of the Non-Volatile RAM from the buffer pointed to by HL. HL must point to a location in the top 32K of CPU address space.
Function 0x26 -- RTC Get Alarm (RTCGETALM)
| Entry Parameters | B: 0x26
| Exit Results | A: Status (0=OK, else error)
Documentation required...
Function 0x27 -- RTC Set Alarm (RTCSETALM)
| Entry Parameters | B: 0x27
| Exit Results | A: Status (0=OK, else error)
Documentation required...
Function 0x28 -- RTC DEVICE (RTCDEVICE)
| Entry Parameters | B: 0x28 | C: RTC Device Unit ID
| Exit Results | A: Status (0=OK, else error) | D: Device Type | E: Device Number | H: RTC Device Unit Mode | L: RTC Device Unit I/O Base Address
Reports information about the RTC device unit specified. Register D indicates the device type (driver) and register E indicates the physical device number assigned by the driver.
Each RTC device is handled by an appropriate driver (DSRTC, BQRTC, etc.) which is identified by a device type id from the table below.
| Type ID | RTC Device Type |
|---|---|
| 0x00 | DS1302 |
| 0x10 | BQ4845P |
| 0x20 | SIMH |
| 0x30 | System Periodic Timer |
| 0x40 | DS1307 (I2C) |
\clearpage{=latex}
Video Display Adapter (VDA)
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.
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.
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:
| Bit | Color | |
|---|---|---|
| Background | 7 | Intensity |
| 6 | Blue | |
| 5 | Green | |
| 4 | Red | |
| Foreground | 3 | Intensity |
| 2 | Blue | |
| 1 | Green | |
| 0 | Red |
The following table illustrates the resultant color for each of the possible 16 values for foreground or background:
| Foreground | Background | Color |
|---|---|---|
| n0 nnnn0000 | 0n 0000nnnn | Black |
| n1 nnnn0001 | 1n 0001nnnn | Red |
| n2 nnnn0010 | 2n 0010nnnn | Green |
| n3 nnnn0011 | 3n 0011nnnn | Brown |
| n4 nnnn0100 | 4n 0100nnnn | Blue |
| n5 nnnn0101 | 5n 0101nnnn | Magenta |
| n6 nnnn0110 | 6n 0110nnnn | Cyan |
| n7 nnnn0111 | 7n 0111nnnn | White |
| n8 nnnn1000 | 8n 1000nnnn | Gray |
| n9 nnnn1001 | 9n 1001nnnn | Light Red |
| nA nnnn1010 | An 1010nnnn | Light Green |
| nB nnnn1011 | Bn 1011nnnn | Yellow |
| nC nnnn1100 | Cn 1100nnnn | Light Blue |
| nD nnnn1101 | Dn 1101nnnn | Light Magenta |
| nE nnnn1110 | En 1110nnnn | Light Cyan |
| nF nnnn1111 | Fn 1111nnnn | Bright White |
Attribute byte values are constructed using the following bit encoding:
| Bit | Effect |
|---|---|
| 7 | n/a (0) |
| 6 | n/a (0) |
| 5 | n/a (0) |
| 4 | n/a (0) |
| 3 | n/a (0) |
| 2 | Reverse |
| 1 | Underline |
| 0 | Blink |
The following codes are returned by a keyboard read to signify non-ASCII keystrokes:
| Value | Keystroke | Value | Keystroke |
|---|---|---|---|
| 0xE0 | F1 | 0xF0 | Insert |
| 0xE1 | F2 | 0xF1 | Delete |
| 0xE2 | F3 | 0xF2 | Home |
| 0xE3 | F4 | 0xF3 | End |
| 0xE4 | F5 | 0xF4 | PageUp |
| 0xE5 | F6 | 0xF5 | PadeDown |
| 0xE6 | F7 | 0xF6 | UpArrow |
| 0xE7 | F8 | 0xF7 | DownArrow |
| 0xE8 | F9 | 0xF8 | LeftArrow |
| 0xE9 | F10 | 0xF9 | RightArrow |
| 0xEA | F11 | 0xFA | Power |
| 0xEB | F12 | 0xFB | Sleep |
| 0xEC | SysReq | 0xFC | Wake |
| 0xED | PrintScreen | 0xFD | Break |
| 0xEE | Pause | 0xFE | |
| 0xEF | App | 0xFF |
Function 0x40 -- Video Initialize (VDAINI)
| Entry Parameters | B: 0x40 | C: Video Device Unit ID | E: Video Mode (device specific) | HL: Font Bitmap Buffer Address (optional)
| Exit Results | A: Status (0=OK, else error)
Performs a full (re)initialization of the specified video device. The screen is cleared and the keyboard buffer is flushed. If the specified VDA supports multiple video modes, the requested mode can be specified in E (set to 0 for default/not specified). Mode values are specific to each VDA.
HL may point to a location in memory with the character bitmap to be loaded into the VDA video processor. The location MUST be in the top 32K of the CPU memory space. HL must be set to zero if no character bitmap is specified (the VDA video processor will utilize a default character bitmap).
Function 0x41 -- Video Query (VDAQRY)
| Entry Parameters | B: 0x41 | C: Video Device Unit ID | HL: Font Bitmap Buffer Address (optional)
| Exit Results | A: Status (0=OK, else error) | C: Video Mode | D: Row Count | E: Column Count | HL: Font Bitmap Buffer Address (0 if N/A)
Return information about the specified video device. C will be set to the current video mode. DE will return the dimensions of the video display as measured in rows and columns. Note that this is the count of rows and columns, not the last row/column number.
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. The video device driver may not have the ability to provide character bitmap data. In this case, on return, HL will be set to zero.
Function 0x42 -- Video Reset (VDARES)
| Entry Parameters | B: 0x42 | C: Video Device Unit ID
| Exit Results | A: Status (0=OK, else error)
Performs a soft reset of the Video Display Adapter. Should clear the screen, home the cursor, restore active attribute and color to defaults. Keyboard should be flushed.
Function 0x43 -- Video Device (VDADEV)
| Entry Parameters | B: 0x43 | C: Video Device Unit ID
| Exit Results | A: Status (0=OK, else error) | D: Device Type | E: Device Number | H: VDA Device Unit Mode | L: VDA Device Unit I/O Base Address
Reports information about the video device unit specified.
Register D reports the video device type (see below).
Register E reports the driver relative physical device number.
The currently defined video device types are:
| VDA ID | Value | Device |
|---|---|---|
| VDA_NONE | 0x00 | No VDA |
| VDA_VDU | 0x10 | ECB VDU board |
| VDA_CVDU | 0x20 | ECB Color VDU board |
| VDA_7220 | 0x30 | ECB uPD7220 video display board |
| VDA_N8 | 0x40 | TMS9918 video display built-in to N8 |
| VDA_VGA | 0x50 | ECB VGA board |
Function 0x44 -- Video Set Cursor Style (VDASCS)
| Entry Parameters | B: 0x44 | C: Video Device Unit ID | D: Start/End Pixel Row | E: Style
| Exit Results | A: Status (0=OK, else error)
If supported by the video hardware, adjust the format of the cursor such that the cursor starts at the pixel specified in the top nibble of D and end at the pixel specified in the bottom nibble of D. So, if D=$08, 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.
Register E is reserved to control the style of the cursor (blink, visibility, etc.), but is not yet implemented.
Adjustments to the cursor style may or may not be possible for any given video hardware.
Function 0x45 -- Video Set Cursor Position (VDASCP)
| Entry Parameters | B: 0x45 | C: Video Device Unit ID | D: Row (0 indexed) | E: Column (0 indexed)
| Exit Results | A: Status (0=OK, else error)
Reposition the cursor to the specified row and column. 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).
Function 0x46 -- Video Set Character Attribute (VDASAT)
| Entry Parameters | B: 0x46 | C: Video Device Unit ID | E: Character Attribute Code
| Exit Results | A: Status (0=OK, else error)
Assign the specified character attribute code to be used for all subsequent character writes/fills. This attribute is used to fill new lines generated by scroll operations. Refer to the character attribute for a list of the available attribute codes. Note that a given video display may or may not support any/all attributes.
Function 0x47 -- Video Set Character Color (VDASCO)
| Entry Parameters | B: 0x47 | C: Video Device Unit ID | E: Character Color Code
| Exit Results | A: Status (0=OK, else error)
Assign the specified color code to be used for all subsequent character writes/fills. This color is also used to fill new lines generated by scroll operations. Refer to color code table for a list of the available color codes. Note that a given video display may or may not support any/all colors.
Function 0x48 -- Video Set Write Character (VDAWRC)
| Entry Parameters | B: 0x48 | C: Video Device Unit ID | E: Character
| Exit Results | A: Status (0=OK, else error)
Write the character specified in E. 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 not scroll if the end of the screen is exceeded.
Function 0x49 -- Video Fill (VDAFIL)
| Entry Parameters | B: 0x49 | C: Video Device Unit ID | E: Character | HL: Count
| Exit Results | A: Status (0=OK, else error)
Write the character specified in E to the display the number of times specified in 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 not scroll if the end of the screen is exceeded.
Function 0x4A -- Video Copy (VDACPY)
| Entry Parameters | B: 0x4A | C: Video Device Unit ID | D: Source Row | E: Source Column | L: Count
| Exit Results | A: Status (0=OK, else error)
Copy count (L) bytes from the source row/column (DE) to current cursor position. The cursor position is not updated. The maximum count is 255. Copying to/from overlapping areas is not supported and will have an undefined behavior. The display will not scroll if the end of the screen is exceeded. Copying beyond the active screen buffer area is not supported and results in undefined behavior.
Function 0x4B -- Video Scroll (VDASCR)
| Entry Parameters | B: 0x4B | C: Video Device Unit ID | E: Scroll Distance (Line Count)
| Exit Results | A: Status (0=OK, else error)
Scroll the video display by the number of lines specified in E. If E contains a negative number, then reverse scroll should be performed.
Function 0x4C -- Video Keyboard Status (VDAKST)
| Entry Parameters | B: 0x4C | C: Video Device Unit ID
| Exit Results | A:Count of Key Codes in Keyboard Buffer
Return a count of the number of key codes in the keyboard buffer. 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.
Function 0x4D -- Video Keyboard Flush (VDAKFL)
| Entry Parameters | B: 0x4D | C: Video Device Unit ID
| Exit Results | A: Status (0=OK, else error)
If a keyboard buffer is in use, it should be purged and all contents discarded.
Function 0x4E -- Video Keyboard Read (VDAKRD)
| Entry Parameters | B: 0x4E | C: Video Device Unit ID
| Exit Results | A: Status (0=OK, else error) | C: Scancode | D: Keystate | E: Keycode
Read next key code from keyboard. If a keyboard buffer is used, return the next key code in the buffer. If no key codes are available, wait for a keypress and return the keycode.
The scancode value is the raw scancode from the keyboard for the keypress. Scancodes are from scancode set 2 standard.
The keystate 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:
| Bit | Keystate Indication |
|---|---|
| 7 | Key pressed was from the num pad |
| 6 | Caps Lock was active |
| 5 | Num Lock was active |
| 4 | Scroll Lock was active |
| 3 | Windows key was held down |
| 2 | Alt key was held down |
| 1 | Control key was held down |
| 0 | Shift key was held down |
Keycodes are generally returned as appropriate ASCII values, if possible. Special keys, like function keys, are returned as reserved codes as described at the start of this section.
\clearpage{=latex}
Function 0x4F -- Read a character at current video position (VDARDC)
| Entry Parameters | B: 0x4F | C: Video Device Unit ID
| Exit Results | A: Status (0=OK, else error) | E: Character | B: Character Color Code | C: Character Attribute Code
Read a character from the current cursor position including it's colour and attributes. If the display does not support colours or attributes then return colour white on black and no attributes. If the device does not support the ability to read a character, return error status
\clearpage{=latex}
Sound (SND)
Function 0x50 -- Sound Reset (SNDRESET)
| Entry Parameters | B: 0x50 | C: Audio Device Unit ID
| Exit Results | A: Status (0=OK, else error)
Reset the sound chip. Turn off all sounds and set volume on all channels to silence.
Function 0x51 -- Sound Volume (SNDVOL)
| Entry Parameters | B: 0x51 | C: Audio Device Unit ID | L: Volume (00=Silence, FF=Maximum)
| Exit Results | A: Status (0=OK, else error)
This function sets the sound chip volume parameter. The volume will be applied when the next SNDPLAY function is invoked.
Note that not all sounds chips implement 256 volume levels. The driver will scale the volume to the closest possible level the chip provides.
Function 0x52 -- Sound Period (SNDPRD)
| Entry Parameters | B: 0x52 | C: Audio Device Unit ID | HL: Period
| Returned Values | A: Status (0=OK, else error)
This function sets the sound chip period parameter. The period will be applied when the next SNDPLAY function is invoked.
The period value is a driver specific value. To play standardized notes, use the SNDNOTE function. A higher value will generate a lower note. The maximum value that can be used is driver specific. If value supplied is beyond driver capabilities, register A will be set to $FF.
Function 0x53 -- Sound Note (SNDNOTE)
| Entry Parameters | B: 0x53 | C: Audio Device Unit ID | HL: Value of note to play
| Returned Values | A: Status (0=OK, else error)
This function sets the sound chip period parameter with steps of quarter of a semitone. The value of 0 (lowest) corresponds to Bb/A# in octave 0.
Increase by steps of 4 to select the next corresponding note.
Increase by steps of 48 to select the same note in next octave.
If the driver is able to generate the requested note, a success (0) is returned, otherwise a non-zero error value will be returned.
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-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.
The following table shows the mapping of the input value in HL to the corresponding octave and note.
| Note | Oct 0 | Oct 1 | Oct 2 | Oct 3 | Oct 4 | Oct 5 | Oct 6 | Oct 7 |
|---|---|---|---|---|---|---|---|---|
| C | X | 8 | 56 | 104 | 152 | 200 | 248 | 296 |
| C#/Db | X | 12 | 60 | 108 | 156 | 204 | 252 | 300 |
| D | X | 16 | 64 | 112 | 160 | 208 | 256 | 304 |
| D#/Eb | X | 20 | 68 | 116 | 164 | 212 | 260 | 308 |
| E | X | 24 | 72 | 120 | 168 | 216 | 264 | 312 |
| F | X | 28 | 76 | 124 | 172 | 220 | 268 | 316 |
| F#/Gb | X | 32 | 80 | 128 | 176 | 224 | 272 | 320 |
| G | X | 36 | 84 | 132 | 180 | 228 | 276 | 324 |
| G#/Ab | X | 40 | 88 | 136 | 184 | 232 | 280 | 328 |
| A | X | 44 | 92 | 140 | 188 | 236 | 284 | 332 |
| A#/Bb | 0 | 48 | 96 | 144 | 192 | 240 | 288 | 336 |
| B | 4 | 52 | 100 | 148 | 196 | 244 | 292 | 340 |
Function 0x54 -- Sound Play (SNDPLAY)
| Entry Parameters | B: 0x54 | C: Audio Device Unit ID | D: Channel
| Returned Values | A: Status (0=OK, else error)
This function applies the previously specified volume and period by programming the sound chip with the appropriate values. The values are applied to the specified channel of the chip.
For example, to play a specific note on Audio Device Unit 0, the following HBIOS calls would need to be made:
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
Function 0x55 -- Sound Query (SNDQUERY)
| Entry Parameters | B: 0x55 | C: Audio Device Unit ID | E: Subfunction
| Returned Values | A: Status (0=OK, else error)
This function will return the status of the current pending command or key aspects of the specific Audio Device.
SNDQUERY Subfunction 0x01 -- Get count of audio channels supported (SNDQ_CHCNT)
| Entry Parameters | B: 0x55 | E: 0x01
| Returned Values | A: Status (0=OK, else error) | B: Count of standard tone channels | C: Count of noise tone channels
SNDQUERY Subfunction 0x02 -- Get current volume setting (SNDQ_VOL)
| Entry Parameters | B: 0x55 | E: 0x02
| Returned Values | A: Status (0=OK, else error) | H: 0 | L: Current volume setting
SNDQUERY Subfunction 0x03 -- Get current period setting (SNDQ_PERIOD)
| Entry Parameters | B: 0x55 | E: 0x03
| Returned Values | A: Status (0=OK, else error) | HL: Current period setting
SNDQUERY Subfunction 0x04 -- Get device details (SNDQ_DEV)
| Entry Parameters | B: 0x55 | E: 0x04
| Returned Values | A: Status (0=OK, else error) | B: Driver identity | HL: Driver specific port settings | DE: Driver specific port settings
Reports information about the audio device unit specified.
Register B reports the audio device type (see below).
Registers HL and DE contain relevant port addresses for the hardware specific to each device type.
The currently defined audio device types are:
| AUDIO ID | Value | Device | Returned registers |
|---|---|---|---|
| SND_SN76489 | 0x01 | SN76489 | E: Left channel port, L: Right channel port |
| SND_AY38910 | 0x02 | AY-3-8910 | D: Address port, E: Data port |
| SND_BITMODE | 0x03 | I/O PORT | D: Address port, E: Bit mask |
| SND_YM2612 | 0x04 | YM2612 | D: Part 0 Address port, E: Part 0 Data port |
| H: Part 1 Address port, L: Part 1 Data port |
Function 0x56 -- Sound Duration (SNDDUR)
| Entry Parameters | B: 0x56 | C: Audio Device Unit ID | HL: Duration
| Returned Values | A: Status (0=OK, else error)
This function sets the duration of the note to be played in milliseconds.
If the duration is set to zero, then the play 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. I/O PORT are not compatible and will not play a note if the duration is zero.
For other values, when a tone is played, it will play for the duration defined in HL and then return.
Function 0x57 -- Sound Device (SNDDEVICE)
| Entry Parameters | B: 0x57 | C: Sound Device Unit Number
| Exit Results | A: Status (0=OK, else error) | D: Sound Device Type | E: Sound Device Number | H: Sound Device Unit Mode | L: Sound Device Unit I/O Base Address
Reports information about the sound device unit specified. Register D indicates the device type (driver) and register E indicates the physical device number assigned by the driver.
Each character device is handled by an appropriate driver (AY38910, SN76489, etc.). The driver can be identified by the Device Type. The assigned Device Types are listed below.
| Id | Device Type / Driver |
|---|---|
| 0x00 | SN76489 |
| 0x10 | AY38910 |
| 0x20 | BITMODE |
| 0x30 | YM2612 |
\clearpage{=latex}
System (SYS)
Function 0xF0 -- System Reset (SYSRESET)
| Entry Parameters | B: 0xF0 | C: Subfunction (see below)
| Exit Results | A: Status (0=OK, else error)
This function performs various forms of a system reset depending on the value of the subfunction. See subfunctions below.
SYSRESET Subfunction 0x00 -- Internal HBIOS Reset (RESINT)
| Entry Parameters | BC: 0xF000
| Returned Values | A: Status (0=OK, else error)
Perform a soft reset of HBIOS. Releases all HBIOS memory allocated by current OS. Does not reinitialize physical devices.
SYSRESET Subfunction 0x01 -- Warm Start System (RESWARM)
| Entry Parameters | BC: 0xF001
| Returned Values |
Warm start the system returning to the boot loader prompt. Does not reinitialize physical devices.
SYSRESET Subfunction 0x02 -- Cold Start System (RESCOLD)
| Entry Parameters | BC: 0xF002
| Returned Values |
Perform a system cold start (like a power on). All devices are reinitialized.
Function 0xF1 -- System Version (SYSVER)
| Entry Parameters | B: 0xF1 | C: Reserved (set to 0)
| Exit Results | A: Status (0=OK, else error) | DE: Version (Maj/Min/Upd/Pat) | L: Platform ID
This function will return the HBIOS version number. The version number is returned in DE. High nibble of D is the major version, low nibble of D is the minor version, high nibble of E is the patch number, and low nibble of E is the build number.
The hardware platform is identified in L:
| Id | Platform |
|---|---|
| 1 | SBC V1 or V2 |
| 2 | Zeta |
| 3 | Zeta V2 |
| 4 | N8 |
| 5 | Mark IV |
| 6 | UNA |
| 7 | RC2014 w/ Z80 |
| 8 | RC2014 w/ Z180 & banked memory module |
| 9 | RC2014 w/ Z180 & linear memory module |
| 10 | SCZ180 (SC126, SC130, SC131) |
| 11 | Dyno |
Function 0xF2 -- System Set Bank (SYSSETBNK)
| Entry Parameters | B: 0xF2 | C: Bank ID
| Exit Results | A: Status (0=OK, else error) | C: Previously Active Bank ID
Activates the Bank ID specified in C and returns the previously active Bank ID in C. The caller MUST be invoked from code located in the upper 32K and the stack must be in the upper 32K.
Function 0xF3 -- System Get Bank (SYSGETBNK)
| Entry Parameters | B: 0xF3
| Exit Results | A: Status (0=OK, else error) | C: Active Bank ID
Returns the currently active Bank ID in C.
Function 0xF4 -- System Set Copy (SYSSETCPY)
| Entry Parameters | B: 0xF4 | D: Destination Bank ID | E: Source Bank ID | HL: Count of Bytes to Copy
| Exit Results | A: Status (0=OK, else error)
Prepare for a subsequent interbank memory copy (SYSBNKCPY) function by setting the source bank, destination bank, and byte count for the copy. The bank id's are not range checked and must be valid for the system in use.
No bytes are copied by this function. The SYSBNKCPY 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 if being performed.
Function 0xF5 -- System Bank Copy (SYSBNKCPY)
| Entry Parameters | B: 0xF5 | DE: Destination Address | HL: Source Address
| Exit Results | A: Status (0=OK, else error)
Copy memory between banks. The source bank, destination bank, and byte count to copy MUST 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.
WARNINGS:
-
This function is inherently dangerous and does not prevent you from corrupting critical areas of memory. Use with extreme caution.
-
Overlapping source and destination memory ranges are not supported and will result in undetermined behavior.
-
Copying of byte ranges that cross bank boundaries is undefined.
Function 0xF6 -- System Alloc (SYSALLOC)
| Entry Parameters | B: 0xF6 | HL: Size in Bytes
| Exit Results | A: Status (0=OK, else error) | HL: Address of Allocated Memory
This function will attempt to allocate a block of memory of HL bytes 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 address of the allocated memory block is returned in HL. You will typically want to use the SYSBNKCPY function to read/write the allocated memory.
Function 0xF7 -- System Free (SYSFREE)
| Entry Parameters | B: 0xF7 | HL: Address of Memory Block to Free
| Returned Values | A: Status (0=OK, else error)
*** This function is not yet implemented ***
Function 0xF8 -- System Get (SYSGET)
| Entry Parameters | B: 0xF8 | C: Subfunction (see below)
| Returned Values | A: Status (0=OK, else error)
This function will report various system information based on the sub-function value. The following lists the subfunctions available along with the registers/information returned.
SYSGET Subfunction 0x00 -- Get Serial Device Unit Count (CIOCNT)
| Entry Parameters | BC: 0xF800
| Returned Values | A: Status (0=OK, else error) | E: Count of Serial Device Units
SYSGET Subfunction 0x01 -- Get Serial Unit Function (CIOFN)
| Entry Parameters | BC: 0xF801 | D: CIO Function | E: Unit
| Returned Values | A: Status (0=OK, else error) | HL: Driver Function Address | DE: Unit Data Address
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.
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.
SYSGET Subfunction 0x10 -- Get Disk Device Unit Count (DIOCNT)
| Entry Parameters | BC: 0xF810
| Returned Values | A: Status (0=OK, else error) | E: Count of Disk Device Units
SYSGET Subfunction 0x11 -- Get Disk Unit Function (DIOFN)
| Entry Parameters | BC: 0xF811 | D: DIO Function | E: Unit
| Returned Values | A: Status (0=OK, else error) | HL: Driver Function Address | DE: Unit Data Address
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).
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.
SYSGET Subfunction 0x20 -- Get Disk Device Unit Count (RTCCNT)
| Entry Parameters | BC: 0xF820
| Returned Values | A: Status (0=OK, else error) | E: Count of RTC Device Units
SYSGET Subfunction 0x40 -- Get Video Device Unit Count (VDACNT)
| Entry Parameters | BC: 0xF840
| Returned Values | A: Status (0=OK, else error) | E: Count of Video Device Units
SYSGET Subfunction 0x41 -- Get Video Unit Function (VDAFN)
| Entry Parameters | BC: 0xF841 | D: VDA Function | E: Unit
| Returned Values | A: Status (0=OK, else error) | HL: Driver Function Address | DE: Unit Data Address
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.
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.
SYSGET Subfunction 0x50 -- Get Sound Device Unit Count (SNDCNT)
| Entry Parameters | BC: 0xF850
| Returned Values | A: Status (0=OK, else error) | E: Count of Sound Device Units
SYSGET Subfunction 0x51 -- Get Sound Unit Function (SNDFN)
| Entry Parameters | BC: 0xF851 | D: SND Function | E: Unit
| Returned Values | A: Status (0=OK, else error) | HL: Driver Function Address | DE: Unit Data Address
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.
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.
SYSGET Subfunction 0xD0 -- Get Timer Tick Count (TIMER)
| Entry Parameters | BC: 0xF8D0
| Returned Values | A: Status (0=OK, else error) | DE:HL: Current Timer Tick Count Value | C: Tick frequency (typically 50 or 60)
SYSGET Subfunction 0xD1 -- Get Seconds Count (SECONDS)
| Entry Parameters | BC: 0xF8D1
| Returned Values | A: Status (0=OK, else error) | DE:HL: Current Seconds Count Value | C: Ticks within Second Value
SYSGET Subfunction 0xE0 -- Get Boot Information (BOOTINFO)
| Entry Parameters | BC: 0xF8E0
| Returned Values | A: Status (0=OK, else error) | L: Boot Bank ID | D: Boot Disk Device Unit ID | E: Boot Disk Slice
SYSGET Subfunction 0xF0 -- Get CPU Information (CPUINFO)
| Entry Parameters | BC: 0xF8F0
| Returned Values | A: Status (0=OK, else error) | H: Z80 CPU Variant | L: CPU Speed in MHz | DE: CPU Speed in KHz | BC: Oscillator Speed in KHz
SYSGET Subfunction 0xF1 -- Get Memory Information (MEMINFO)
| Entry Parameters | BC: 0xF8F1
| Returned Values | A: Status (0=OK, else error) | D: Count of 32K ROM Banks | E: Count of 32K RAM Banks
SYSGET Subfunction 0xF2 -- Get Bank Information (BNKINFO)
| Entry Parameters | BC: 0xF8F2
| Returned Values | A: Status (0=OK, else error) | D: BIOS Bank ID | E: User Bank ID
SYSGET Subfunction 0xF3 -- Get CPU Speed (CPUSPD)
| Entry Parameters | BC: 0xF8F3
| Returned Values | A: Status (0=OK, else error) | L: Clock Mult (0:Half, 1:Full, 2: Double) | D: Memory Wait States | E: I/O Wait States
This function will return 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 returns it's best guess. If either of the wait state settings is unknown, the function will return 0xFF.
Function 0xF9 -- System Set (SYSSET)
| Entry Parameters | B: 0xF9 | C: Subfunction (see below)
| Returned Values | A: Status (0=OK, else error)
This function will set various system parameters based on the sub-function value. The following lists the subfunctions available along with the registers/information used as input.
SYSSET Subfunction 0xD0 -- Set Timer Tick Count (TIMER)
| Entry Parameters | BC: 0xF9D0 | DE:HL: Timer Tick Count Value
| Returned Values | A: Status (0=OK, else error)
SYSSET Subfunction 0xD1 -- Set Seconds Count (SECONDS)
| Entry Parameters | BC: 0xF9D1 | DE:HL: Seconds Count Value
| Returned Values | A: Status (0=OK, else error)
SYSSET Subfunction 0xE0 -- Set Boot Information (BOOTINFO)
| Entry Parameters | BC: 0xF9E0 | L: Boot Bank ID | D: Boot Disk Device Unit ID | E: Boot Disk Slice
| Returned Values | A: Status (0=OK, else error)
SYSSET Subfunction 0xF3 -- Set CPU Speed (CPUSPD)
| Entry Parameters | BC: 0xF9F3 | L: Clock Mult (0:Half, 1:Full, 2: Double) | D: Memory Wait States | E: I/O Wait States
| Returned Values | A: Status (0=OK, else error)
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.
Some peripherals are dependant 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.
Function 0xFA -- System Peek (SYSPEEK)
| Entry Parameters | B: 0xFA | D: Bank ID | HL: Memory Address
| Returned Values | A: Status (0=OK, else error) | E: Byte Value
This function gets a single byte value at the specified bank/address. The bank specified is not range checked.
Function 0xFB -- System Poke (SYSPOKE)
| Entry Parameters | B: 0xFB | D: Bank ID | E: Value | HL: Memory Address
| Returned Values | A: Status (0=OK, else error)
This function sets a single byte value at the specified bank/address. The bank specified is not range checked.
Function 0xFC -- System Interrupt Management (SYSINT)
| Entry Parameters | B: 0xFC | C: Subfunction (see below)
| Returned Values | A: Status (0=OK, else error)
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 subfunction. Additional input and output registers may be used as defined by the sub-function.
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.
Interrupt handlers are different for IM1 or IM2.
For IM1:
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.
For IM2:
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.
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.
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.
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.
SYSINT Subfunction 0x00 -- Interrupt Info (INTINF)
| Entry Parameters | BC: 0xFC00
| Returned Values | A: Status (0=OK, else error) | D: Interrupt Mode | E: Size (# entries) of Interrupt Vector Table
Return interrupt mode in D and size of interrupt vector table in 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.
SYSINT Subfunction 0x10 -- Get Interrupt (INTGET)
| Entry Parameters | BC: 0xFC10 | E: Interrupt Vector Table Index
| Returned Values | A: Status (0=OK, else error) | HL: Current Interrupt Vector Address
On entry, register E must contain an index into the interrupt vector table. On return, HL will contain the address of the current interrupt vector at the specified index.
SYSINT Subfunction 0x20 -- Set Interrupt (INTSET)
| Entry Parameters | BC: 0xFC20 | E: Interrupt Vector Table Index | HL: Interrupt Address to be Assigned
| Returned Values | A: Status (0=OK, else error) | HL: Previous Interrupt Vector Address | DE: Interrupt Routing Engine Address (IM2)
On entry, register E must contain an index into the interrupt vector table and register HL must contain the address of the new interrupt vector to be inserted in the table at the index. On return, HL will contain the previous address in the table at the index.
\clearpage{=latex}
Errors and diagnostics
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.
Run time errors
PANIC
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.
Example error message:
>>> PANIC: @06C4[DFA3:DFC3:0100:F103:04FC:0000:2B5E]
*** System Halted ***
The format of the information provided is
@XXXX [-AF-:-BC-:-DE-:-HL-:-SP-:-IX-:-IY-]
Where @XXXX is the address the panic was called from. The other information is the CPU register contents.
Possible reasons a PANIC may occur are:
- RAM Bank range error when attempting a read or write to a RAM disk.
- Sector read function has not been setup but a read was attempted.
- An interrupt vector has not been set up when an interrupt was received.
- There was an attempt to add more devices than the device table had room for.
- An illegal SD card command was encountered.
The @XXXX memory address can be cross referenced with the build source code to identify which section of the software or hardware caused the fault.
SYSCHK
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.
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.
If the diagnosis level is set to display the diagnosis information, then memory address, register dump and error code is displayed. A key differance with the PANIC error is that execution may be continued.
Example error message:
>>> SYSCHK: @06C4[DFA3:DFC3:0100:F103:04FC:0000:2B5E] FD Continue (Y/N)
The format of the information provided is similar the PANIC report.
@XXXX [-AF-:-BC-:-DE-:-HL-:-SP-:-IX-:-IY-] YY
The syschk error codes YY is returned in the A register.
| Error | Code YY |
|---|---|
| Success | 0x00 |
| Undefined Error | 0xFF |
| Function Not Implemented | 0xFE |
| Invalid Function | 0xFD |
| Invalid Unit Number | 0xFC |
| Out Of Memory | 0xFB |
| Parameter Out Of Range | 0xFA |
| Media Not Present | 0xF9 |
| Hardware Not Present | 0xF8 |
| I/O Error | 0xF7 |
| Write Request To Read-Only Media | 0xF6 |
| Device Timeout | 0xF5 |
| Invalid Configuration | 0xF4 |
| Internal Error | 0xF3 |
Error Level reporting
placeholder
Build time errors
Build chain tool errors
place holder
Assembly time check errors
placeholder
Diagnostics
DIAG
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.
ROMWBW can be configured to display boot progress with the assistance of additional hardware. This take the form of an LED breakout debugging board connected to an 8-bit output port. As the boot code executes, the LED output display is updated.
To use a LED breakout board, it must be connected the computers data, reset and port select lines.
To enable the DIAG option the following settings must be made in the systems .ini configuration file, where 0xnn is the port address.
DIAGENABLE .SET TRUE DIAGPORT .SET 0xnn
The following table shows the ROMWBW process steps in relation to the LED display.
| LED | ROMWBW Processes |
|---|---|
........ |
Initial boot |
| Jump to start address | |
| Disable interrupts | |
| Set interrupt mode 1 | |
| Initialize critical ports and initial speed | |
.......O |
Setup initial stack |
| Memory manager and CPU configuration | |
| Set top bank to be RAM | |
......OO |
Get and save battery condition |
| Install HBIOS proxy in upper memory | |
| If platform is MBC reconfigure memory manager | |
| Setup "ROMLESS" HBIOS image or ... | |
| Copy HBIOS from ROM to RAM if RAM flag not set | |
| Jump to HBIOS in RAM | |
| Set running in RAM flag | |
.....OOO |
Finalize configuration for running in RAM |
| Check battery condition | |
| Check for recovery mode boot | |
....OOOO |
Identify CPU type |
...OOOOO |
Set cpu oscillator speed |
| Setup counter-timers | |
| Setup heap | |
..OOOOOO |
Preconsole initialization |
.OOOOOOO |
Boot delay |
| Set boot console device | |
| Bios announcement | |
OOOOOOOO |
Display platform information |
| Display memory configuration | |
| Display CPU family | |
| Verify ROM checksum | |
| Report battery condition | |
| Perform device driver initialization | |
| Report watchdog status | |
| Mark HBIOS heap so it is preserved | |
| Switch from boot console to CRT if active | |
| Display device summary | |
| Execute boot loader |
\clearpage{=latex}
Appendix A Driver Instance Data fields
The following section outlines the read only data referenced by the
SYSGET, subfunctions xxxFN for specific drivers.
TMS9918 Driver:
| Name | Offset | Bytes | Description |
|---|---|---|---|
| PPIA | 0 | 1 | PPI PORT A |
| PPIB | 1 | 1 | PPI PORT B |
| PPIC | 2 | 1 | PPI PORT C |
| PPIX | 3 | 1 | PPI CONTROL PORT |
| DATREG | 4 | 1 | IO PORT ADDRESS FOR MODE 0 |
| CMDREG | 5 | 1 | IO PORT ADDRESS FOR MODE 1 |
| Below are the register mirror values | |||
| that HBIOS used for initialisation | |||
| REG. 0 | 6 | 1 | $00 - NO EXTERNAL VID |
| REG. 1 | 7 | 1 | $50 or $70 - SET MODE 1 and interrupt if enabled |
| REG. 2 | 8 | 1 | $00 - PATTERN NAME TABLE := 0 |
| REG. 3 | 9 | 1 | $00 - NO COLOR TABLE |
| REG. 4 | 10 | 1 | $01 - SET PATTERN GENERATOR TABLE TO $800 |
| REG. 5 | 11 | 1 | $00 - SPRITE ATTRIBUTE IRRELEVANT |
| REG. 6 | 12 | 1 | $00 - NO SPRITE GENERATOR TABLE |
| REG. 7 | 13 | 1 | $F0 - WHITE ON BLACK |
| DCNTL* | 14 | 1 | Z180 DMA/WAIT CONTROL |
- ONLY PRESENT FOR Z180 BUILDS