21

CP/M, the operating system for Intel 8080 and Z80 (and others as well, but later) used to call 0005h for syscalls. The application would load the syscall number into a specific register (I think it was C) and then do call 0005h.

But why? Both the Intel 8080 and the Z80 have these very handy rst instructions for jumping to a hard coded address early in the address space, and that's apparently for exactly this kind of purpose.

I'm proposing that CP/M could have used rst 8 or something, instead of call 0005h. This would have meant a saving of 2 bytes and six tacts per syscall, just by using the mechanism that the CPUs provide as standard. And it fits in with the scheme of using rst 0 for a warm reboot, and rst 56 for the debugging.

11
  • 2
    The original CP/M was written in PL/M and cross-compiled on a Fortran system. It had to have BIOS/BDOS combined on a single paper tape and loaded that way. It may not have generated anything more than the most basic 8080 code. And it's possible that, when rewriting BIOS in real ASM, the same call method was used. All supposition of course, especially given the non-living nature of the author (no insult intended, just stating facts).
    – paxdiablo
    Jul 26, 2022 at 9:12
  • 3
    @paxdiablo - presumably the author was living at the time...
    – Jon Custer
    Jul 26, 2022 at 13:48
  • 1
    It is hard today to imagine how simple an operating system CP/M could be and still be widely successful. It is primarily providing well-defined I/O byte operations on various ports (serial, parallel, etc) and translating files into floppy sectors. Plus some standard utilities and a command line. That's about it :) For 2.2 that was. CP/M-3 and MP/M had a lot more tricks up their sleeve. Jul 26, 2022 at 14:10
  • 4
    @JonCuster: I think he means that you can't ask all the reasons for these things any more to Gary Kildall
    – chthon
    Jul 26, 2022 at 15:41
  • 5
    @chthon - that was meant in jest... Should have attached a smiley face I guess.
    – Jon Custer
    Jul 26, 2022 at 15:42

3 Answers 3

27

CP/M, the operating system for Intel 8080 and Z80 (and others as well, but later)

CP/M is an 8080 operating system. Like DOS is an 8086 system. That other CPUs may as well execute it due to close compatibility with the 8080 is not CP/M's fault.

used to call 0005h for syscalls. [...]

It's the lowest memory address that can be assumed to be usable without giving up much functionality of the target system (or any at all).

CP/M, unlike developer-specific OSes, where machine and OS were developed in step, is an add-on product meant to be applicable to as many different designs as possible. As such it's important to be as unintrusive and adaptable as possible.

Address 5 is a great choice:

  • Existing hardware interrupts can (continue to) use any RST
  • Software can use all RST for whatever function it needs
  • Only the last 3 bytes of RST 0 are reserved
  • CP/M uses (has to use) RST 0 anyway

The last point is quite important, as RST 0 also dubs as warm start entry point for CP/M due being the RESET entry point (*1), so CP/M is already in control of these 8 bytes. It only needs the first 3 to jump to its warm boot code, leaving 5 bytes for other use ... like using 3 for a generic call interface without spending a rare RST resource (*1).

I'm proposing that CP/M could have used rst 8 or something,

There are only 8 RST locations available. Each the OS takes is one hardware and applications can't use.

This would have meant a saving of 2 bytes and six tacts per syscall, just by using the mechanism that the CPUs provide as standard.

"Six tacts per call" is not really a considerable benefit with syscalls usually taking at least several hundred to many thousands.

And it fits in with the scheme of using rst 0 for a warm reboot,

Using RST 0 for warm boot is a way of reusing RESET (*2).

rst 56 for the debugging.

I guess you mean RST 7? (*3) That's already a good example how a user program is benefiting from CP/M keeping its hands off RST instructions as much as possible.


Bottom line: Using address 5 comes with the least cost in terms of predefined system resources CP/M requires from a system to be ported to.


*1 - In fact, the other two bytes are used in a similar way, address 3 holds the I/O byte and 4 the disk byte. Cramping all RAM needs into the first 256 bytes, when a quarter (64 Bytes) is already reserved for the RST table and a whopping half (128 Bytes) for the file buffer, is a tough job.

*2 - It's all about how the system is built. RESET does start, like RST 0, execution at address 0. On a cold start an 8080 system needs to have some ROM there to start up. Since CP/M (usually) wants RAM at that location, that ROM will be mapped out at some point.

Thus CP/M can now (re)use that entry point as warm restart, so if any application executes an RST 0, it ends up in CP/M's warm start routine, while a follow-up RESET (usually) would start again from ROM code.

Even better, if the hardware somehow distinguishes between power-up reset and later reset, it may execute from address 0 in RAM instead, making RESET go direct to CP/M warm start.

What a nice way to kill (at least) two birds with one stone.

*3 - As 8080 software using Intel notation may be more appropriate - not to mention that it avoids any confusion about which addresses are legal or not.

8
  • I wonder what factors favored the use of a single jump vector at address 5, versus reserving space in low RAM for a jump table, or having BIOS called handled via jump table at an arbitrary address versus reserving an area of RAM for such a jump table which both the OS and user programs could use to make BIOS calls? If CP/M required that the computer-vendor-handled part of the boot process place a BIOS vector table in RAM, along with the top-of-RAM address at a certain spot, load a particular disk sector at e.g. 0x200, and jump there, and if Digital Research were to designate a particular...
    – supercat
    Jul 26, 2022 at 15:58
  • ...sector that each CPU vendor should use as its boot location, then it would be practical for software vendors to release software on disks that could boot on multiple machines interchangeably.
    – supercat
    Jul 26, 2022 at 16:03
  • 2
    @supercat As always: Need for a small RAM footprint (CP/M needs only 256 Bytes), advantage of a single entry point and most of all: No space to code any of such complex matters. Those were the 70s. No system builder wants to take a 3 week course to get CP/M booting on his system. He'd have written the needed OS parts by himself in that time. Remember CP/M is not just for Desktop, but intended as well for systems with RAM as small as a single KiB or even less.
    – Raffzahn
    Jul 26, 2022 at 16:40
  • How did the costs of RAM and ROM compare? Mask ROM would of course have a high setup code while being very cheap per unit, but what about bipolar PROMs, UV EPROMS, or OTPROMs? I would think that if one wanted to run CP/M from ROM, having a version that was machine-independent except for a choice of 0xC000 or 0xE000 start address would for many CPU makers be cheaper than having to have a machine-specific version of CP/M in ROM.
    – supercat
    Jul 26, 2022 at 17:07
  • 2
    @supercat What RAM? The ROM was needed anyway for the application. And what kind of ROM doesn't matter for the principle. Also, CP/M was always machine specific due the BIOS. The point of CP/M is just to encapsulate machine specific details there..
    – Raffzahn
    Jul 26, 2022 at 17:43
6

It's very likely because CP/M was designed for the 8080 microprocessor and appears to have chosen to keep RST instructions free for the interrupt circuitry.

CP/M chose to not rely on any of the eight RST instructions being available. It left them all for interrupt service routines or other functions. There's no official CP/M documentation I'm aware of that says this but it's pretty clear of its advantages in simplifying the system's electronics circuit.

From a purely software perspective, using a 1-byte RST restart instruction instead of the 3-byte CALL 0005h needed would indeed appear to be the better solution.

However, CP/M was originally written for the Intel 8080 microprocessor. For the hardware design, RST instructions are valuable for interrupt handlers: they simplify the circuitry needed for 8080 interrupts and allow for faster interrupt response. CP/M does not know how many interrupt sources a system might need RSTs for, so it uses none of them.

The 8080 has a single interrupt request pin, /INTR, and a basic interrupt handling scheme:

  • Interrupts are maskable.
  • When enabled and a valid LOW is detected on /INTR, the 8080 completes any instruction execution then performs an interrupt acknowledge cycle and reads an instruction from the bus.
  • External circuitry must then place a valid 8080 instruction opcode on the data bus, followed by any further instruction bytes in subsequent cycles.

Interrupt acknowledge response circuitry to drive a 1-byte RST instruction onto the data bus is much simpler with 1970s parts than circuitry to drive a 3-byte CALL xxxx instruction onto the bus. This brings the electronics cost down, an important factor with much more expensive 1970s parts and manufacturing.

For a single interrupt, the interrupt response circuit can even just use permanent pull-up resistors to present a RST 7 during an 8080 interrupt acknowledge cycle. Simple address decoding can support that by disabling reads of all memory and I/O devices during that interrupt acknowledge.

Moving on from the 8080, the later Z80 has a more powerful maskable interrupt scheme with three Interrupt Modes:

  • Z80 IM 0: same as 8080 (see above)
  • Z80 IM 1: does CALL 0038h, needs no external electronics
  • Z80 IM 2: reads vector number from data bus D7..D1, uses it and I register to read a vector from a memory address, does CALL vectorAddress.

So a Z80 CP/M system can be built using IM 1 for a single ISR that polls interrupting devices, needing no interrupt response electronics and leaving all RST instructions free. Or it could be built using IM 2 with less/no polling and an ISR for each interrupt, but needing some external electronics and leaving all RST instructions free. However, CP/M, and all its applications based around CALL 0005h, were long established by then and did not change for the Z80.

Note that the address 0005h is most likely used because each RST instruction CALLs an address on an 8-byte multiple and 0005h allows a 3-byte JP xxxx instruction to be placed in the final 3 bytes of the first 8-byte RST handler space, RST 0. That leaves the most space remaining in the RST 0 handler...all of 5 bytes!

If CP/M had been created later and for Z80 systems, there certainly would be benefits from using a restart instruction for BDOS calls instead of CALL 0005h:

  • The RST is more compact. The three extra RAM bytes used to push up the BIOS handler from 0005h to 0008h are outweighed by all of the 2-byte shorter RST 1 BIOS calls in the CP/M application programs. Most programs would have a lot more than two BIOS calls.

  • The RST is faster. Even this small speed improvement is always worthwhile in such slow systems. It can become very significant for repeatedly-invoked calls, such as for text display, byte-at-a-time file handling etc.

Many of the Z80 systems that arrived well after CP/M considered their RST instructions to be a precious resource for allocating with care. For example, the ZX Spectrum ROM used them for error handling, printing characters, BASIC line character fetching, its floating-point calculator, workspace RAM and the regular IM 1 interrupt.

6
  • 3
    If this is an answer to "why?" then it's saying "I don't know". Which may in fact be the best answer available. Perhaps it simply didn't occur to Kildall to do otherwise. "To call an OS service, use CALL". Jul 27, 2022 at 3:48
  • Thanks @MarkWilliams but it was probably because I was half-asleep after long days away and what was there was a wrong answer :-) I've now rewritten it completely, after a ton of sleep and clarity.
    – TonyM
    Jul 27, 2022 at 18:41
  • You're aware that the same RST can be used with Z80 interrupt handling? Interrupt mode 0 is fully 8080 compatible, thus as well based on injecting an instruction. Usually an RST, thus they are for Z80 systems a resource as precious as for 8080.
    – Raffzahn
    Jul 27, 2022 at 21:17
  • @Raffzahn, very aware of IM0 but not relevant here. A Z80 can use IM1 as said, for polled interrupts with a shared vector and no external circuitry. Or IM2 for separate interrupt vectors with less external circuitry than IM0 and no use of RSTs. IM2 does need a RAM table of 2..256 bytes: a word for each interrupt source. More expensive Z80 systems can keep that table in external RAM to free the Z80 address map.
    – TonyM
    Jul 27, 2022 at 21:47
  • @TonyM No need to tell me. I did use more thanone Z80 by now, inculding several in systems base on IM0. Point is that you base part on the answr on the claim that RST are not used with Z80, which is simply not true. I do not intend to argue, but to help improve your answer.
    – Raffzahn
    Jul 28, 2022 at 0:28
4

One additional point... if you write an application that's specific to one particular CP/M system and you know that there's an unused RST on the machine, it's super easy to copy the three bytes from 0005h to that vector and then use RST for your syscalls.

1
  • Jup, neat trick. Except you also had do convince the compiler to generate that RST instead of a call 5. Easy with Assembler, less easy with any other language. Usually not worth the effort.
    – Raffzahn
    Jul 30, 2022 at 10:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .