Pseudo-device “simh-pseudo”
This device is originally implemented as permanently connected to 88-SIO device in simh emulator. It listens to custom, non-standard commands from operating system thus simplifies communication between emulator (host) and running guest system. This device is required if you want to run CP/M operating system images made for simh emulator.
Programming
SIMH-pseudo device can be pretty useful also for users of emuStudio. Z80 or 8080 programs communicate with it via port 0xFE
.
Some commands sent to the port require parameters, in which case there must be sent multiple bytes. If a command returns anything, the returned value can be read using IN
instruction.
List of commands
In case of multibyte parameters or return value, if it’s a numeric value it’s always in a form of little endian.
Command | Parameters | Return value | Description |
---|---|---|---|
0 | N/A | N/A | print the current time on stdout, in milliseconds |
1 | N/A | N/A | start a new timer on the top of the timer stack |
2 | N/A | N/A | stop timer on top of timer stack and print time difference on stdout, in milliseconds |
3 | N/A | N/A | reset the PTR device (NOT IMPLEMENTED) |
4 | N/A | N/A | attach the PTR device (NOT IMPLEMENTED) |
5 | N/A | N/A | detach the PTR device (NOT IMPLEMENTED) |
6 | N/A | 8 bytes ("SIMH004\0" ) | get the current version of the SIMH pseudo device |
7 | N/A | 6 bytes | get the current time in ZSDOS format, all BCD values: byte 0: year modulo 100, byte 1: month, byte 2: day, byte 3: hour, byte 4: minute, byte 5: second |
8 | 2 bytes (address of a 6-byte block in memory representing ZSDOS time in format YY MM DD HH MM SS) | N/A | set the current time in ZSDOS format: reads the time from given address |
9 | N/A | 5 bytes | get the current time in CP/M 3 format, all BCD values: bytes 0-1: days since 1 Jan 1978 (low byte), byte 2: hour, byte 3: minute, byte 4: second |
10 | 2 bytes (address of a 5-byte block in memory representing CP/M 3 time in format: 0-1: days since 31 Dec 77, 2: HH, 3: MM, 4: SS) | N/A | set the current time in CP/M 3 format: reads the time from given address |
11 | N/A | 1 byte | get the selected bank |
12 | 1 byte | N/A | set the selected bank |
13 | N/A | 2 bytes | get the base address of the common memory segment |
14 | N/A | N/A | reset the SIMH-pseudo device (clears “undefined” state) |
15 | N/A | N/A | show time difference to timer on top of stack |
16 | N/A | 1 byte | attach PTP device to the file with name at beginning of CP/M command line (NOT IMPLEMENTED) |
17 | N/A | N/A | detach PTP device (NOT IMPLEMENTED) |
18 | N/A | 1 byte | determines whether machine has banked memory (returns number of memory banks) |
19 | N/A | N/A | set the CPU to a Z80 (NOT IMPLEMENTED) |
20 | N/A | N/A | set the CPU to an 8080 (NOT IMPLEMENTED) |
21 | N/A | N/A | start timer interrupts |
22 | N/A | N/A | stop timer interrupts |
23 | 2 bytes | N/A | set the timer interval in which interrupts occur |
24 | 2 bytes | N/A | set the address to call by timer interrupts |
25 | N/A | N/A | reset the millisecond stop watch |
26 | N/A | 2 bytes | read the millisecond stop watch |
27 | N/A | N/A | let emulation sleep for 1000 milliseconds |
28 | N/A | 1 byte | obtain the file path separator of the OS under which emuStudio runs |
29 | N/A | file names separated by 0, ends with double 0 | perform wildcard expansion and obtain list of file names |
30 | URL (N bytes terminated with 0) | max 1024 byte pairs (URL content) in form availability, data (when availability is 1 the data byte is valid) until availability is 0 | read the contents of a URL |
31 | N/A | 2 bytes | get the clock frequency of the CPU |
32 | 2 bytes | N/A | set the clock frequency of the CPU. To make effect, CPU must be paused/run again. |
33 | 2 bytes (byte 0: (unused) interrupt vector, byte 1: interrupt data byte, an RST instruction) | N/A | generate interrupt |
How to call a command
Calling a command always starts with an OUT
instruction:
ld a, <cmd> ; replace "<cmd>" with command number
out (0xFE), a
Then, if a command requires a parameter, it must be supplied with additional OUT
instruction(s), depending on how many bytes are expected, as follows:
ld a, <param0> ; replace "<param0>" with parameter byte 0
out (0xFE), a
ld a, <param1> ; replace "<param1>" with parameter byte 1
out (0xFE), a
... ; etc.
After last parameter is recognized by SIMH-pseudo device, the command is executed. Then, if the command returns a result, it must be read with IN
instructions, depending on how many bytes are to be returned, as follows:
in a, (0xFE) ; register A contains first byte of result
... ; save the byte somewhere
in a, (0xFE) ; register A contains second byte of result
Note: The program must send/receive all bytes. Otherwise, the device will stay in a state when it “expects” the rest of parameter bytes, or result bytes to be read. It is however possible to “reset” the device by sending a reset command to the device (command 14).