Wow, I thought I knew the C128 pretty well. I still needed to search the internet for several hours to answer this.
Why does the Commodore C128 perform poorly when running CP/M?
- The Z80A was sort of an after-thought in the C128 design. Before release it had been touted as "fully C64 compatible" (which the earlier C= Plus/4 was not). However, the C64 had a Z80 cartridge allowing it to run CP/M. For whatever reason the cartridge could not work on the C128, so they added the Z80 directly to the motherboard.
- I/O was doubly indirect. Actions such as reading from the keyboard and writing to the screen first went thru the CP/M BIOS layer. Then it had to switch CPUs! From the Commodore 128 Programmer's Reference Guide (PRG), page 500:
The 8502 is responsible for most of the low-level I/O functions. The request for these functions is made through a set of mailboxes. Once the mailboxes are set up, the Z80 shuts down and the 8502 starts up (BIOS85). The 8502 looks at the command in the mailbox and performs the required task, sets the command status and shuts down. The Z80 is re-enabled; it then looks at the command status and takes the appropriate actions. 3. Updates to the screen were s-l-o-w. I believe this was due to the impact #2 had on interacting with the 8563 video controller. Although a block mode character transfer was possible, apparently the complexity of the dual-BIOS layers led to only one character being written to the screen per BIOS call. To write a character, two 16-bit 8563 registers needed to be updated, which were the hardware pipeline to the 80-column video memory. That all amounts to a heckuva lot of overhead per character. 4. Some users only had the classic C64 model 1541 disk drive. This was already known for being very slow (to be fair, "faster than cassette"). The newer 1571 drive, released with the C128, was three to six times faster, had double the capacity, and supported several CP/M formats used by other manufacturers.
Z80A only runs at 4MHz half the time. Why should this be the case?
From page 575 of the PRG:
SYSTEM DESCRIPTION
The Z80A, a 4MHz version of Zilog's standard Z80 processor, is included as an alternate processor in the C128 system. This allows the C128 to run the CPM 3.0 operating system at an effective speed of 2 MHz. The Z80 is interfaced to the 8502 bus interface and can access all the devices that the Z80 can access. The bus interface for the Z80 (the most complex part of the Z80 implementation) is described in this section, along with Z80's operation as a coprocessor in the C128 system.
BUS INTERFACE
Because a Z80 bus cycle is much different than a 65xx family bus cycle, a certain amount of interfacing is required for a Z80 to control a 65xx-type bus. Since the Z80 has built-in bus arbitration control lines, it is possible to isolate the Z80 by tri-stating its address lines. Thus, both the Z80 and the 8502 share common address lines.
The interfacing of the data lines is more complex. Because of the shared nature of the bus during Z80 mode, the Z80 must be isolated from the bus during AEC low. Thus, a tri-statable buffer must drive the processor bus during Z80 data writes. The reverse situation occurs during a Z80 read—the Z80 must not read things that are going on during AEC low; it must latch the data that was present during AEC high. Thus, a transparent latch drives the data input to the Z80. It is gated by the Z80 read-enable output, and latched when the 1 MHz clock is low. It will be seen that the Z80 actually runs during AEC low, but that the data bus interfaces with it only during AEC high.
I.e., "It's complicated." 🤖
Performance benchmarks?
I was not able to find actual benchmarks. There were several accounts of users lamenting the C128's CP/M speed, and especially its screen updating.
Cool References
- THE REAL STORY OF HACKING TOGETHER THE C128 by Bil Herd, lead designer
- Platform Wiki: Commodore 128
- The C128 Story, aggregated CompuServe postings by Bil Herd