25

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 cycles 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
    Commented Jul 26, 2022 at 9:12
  • 4
    @paxdiablo - presumably the author was living at the time...
    – Jon Custer
    Commented 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. Commented 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
    Commented Jul 26, 2022 at 15:41
  • 5
    @chthon - that was meant in jest... Should have attached a smiley face I guess.
    – Jon Custer
    Commented Jul 26, 2022 at 15:42

3 Answers 3

29

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
    Commented 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
    Commented 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
    Commented 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
    Commented 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
    Commented Jul 26, 2022 at 17:43
10
+100

CP/M was designed originally for the 8080 microprocessor. It's very likely that CP/M keeps the RST instructions free so they can instead be used by the 8080 board's interrupt circuitry. On an interrupt, a board can get the 8080 to execute one of the RST instructions with relatively simple, low-cost external circuitry. The RST routine is then actually an Interrupt Service Routine (ISR).

There's no official CP/M documentation I'm aware of that says this. However, it's clear that using RSTs for interrupts significantly simplifies the 8080's interrupt circuit. It's also clear that CP/M chose to not rely on any of the eight RST instructions being available for general software.

Incidentally, when I first looked at the CP/M source code decades ago, I saw the software didn't use RSTs and could also see the hardware cost benefits for interrupt circuitry on CP/M's 8080 boards.

I also thought that address 0005h was a very sensible choice, within the constraints of 8080 systems with little RAM (like when CP/M started out). It's the lowest address that still leaves all RST handlers as free as possible. Using 0005h lets a 3-byte JP xxxx instruction be placed at the end of the first 8-byte RST handler, RST 0. That leaves the most contiguous space in the RST 0 handler...all of 5 bytes!


Using RSTs for 8080 interrupts

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

But from an 8080 hardware design perspective, a RST instruction is valuable for calling an ISR after a particular interrupt. They simplify the extra circuitry needed to for 8080 interrupts and allow for faster interrupt response. CP/M does not know how many separate interrupt sources and ISRs 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 (a) completes any instruction being executed then (b) performs an interrupt acknowledge cycle and (c) reads a whole instruction (opcode plus further bytes) from the bus.
  • To support this, external circuitry must place an 8080 instruction opcode on the data bus, followed by any further bytes of that instruction 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 put the 3 bytes of a CALL xxxx instruction onto the bus, one after the other.

So using RSTs for interrupts brings the electronics cost down, an important factor with much more expensive 1970s parts/manufacturing.

If the board uses one interrupt, the interrupt circuit can just use pull-up resistors on the data bus to present a RST 7 (0xFF) during interrupt acknowledge. That will need address decoding to disable all memory/IO device during interrupt acknowledge.


Z80 interrupts don't need to use RSTs

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 vn from data bus D7..D0; uses vn with I register as vector address; reads vector from that memory address; does CALL vector.

So the Z80 isn't so reliant on external circuitry:

  • If a single ISR is OK to service all sources, a Z80 CP/M system can use IM 1. Needs no interrupt response circuitry.
  • If separate ISRs are needed for different sources, a Z80 system can use can use IM 2. Can use less/no polling of its interrupt sources. Each interrupt has an ISR. Needs some simple-ish external electronics'.

These Z80 interrupt schemes have no reason to involve RSTs, so RSTs are left free.

If CP/M had been originally designed for the Z80, there's certainly benefits of using a RST for BDOS calls instead of CALL 0005h:

  • 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.

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

But it was far too late to think of changing: CP/M, and all its applications using CALL 0005h, were long established by then.

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

4
  • 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
    Commented 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
    Commented 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
    Commented Jul 28, 2022 at 0:28
  • @Raffzahn, the answer's fine as it is, says what I wanted to answer. Nowhere does it say IM0/RSTs are not used on Z80 systems, though, nothing's based on anything like that. Instead it says "So it's an easier route to make RST instructions available on those systems" etc.
    – TonyM
    Commented Jul 28, 2022 at 10:14
5

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
    Commented 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 .