I have seen several claims of poor performance of the C128 when running CP/M, and would like to better understand these claims, especially in comparison to other CP/M machines of the early to mid-1980s.

The C128 has a Z80A microprocessor clocked at 4MHz for running CP/M. This is the same processor and clock speed found in, for example, the TRS-80 Model 4. Both those machines were CP/M compatible, but I have seen claims that the 4MHz clock speed was not fully utilized by the Z80A in the C128. Specifically, I have seen it stated that the C128 Z80A only runs at 4MHz half the time. Is this statement true, and why should this be the case?

Also, are there any benchmark results published to substantiate poor C128 CP/M performance when compared to similar Z80A systems?

  • 1
    Without checking: The VIC had to "steal" memory cycles from the 6502 for RAM access, so I suspect it's the same with the Z80. – dirkt Feb 26 '17 at 19:35
  • @dirkt but wouldn't you normally run CPM in 80-column mode, which bypasses the VIC and uses the 8563 VDC (or in DCR models the 8568 DVDC)? The VDC has its own video RAM which suggests it wouldn't effect performance in that mode. Maybe if you were using it in 40-column mode with the VIC due to the lack of a RGBI monitor? – mnem Feb 27 '17 at 1:13
up vote 34 down vote accepted

(2017.03.03) I have added a second answer with diagrams and more technical details. This answer is already huge and self-contained; the other focuses on the complexities due to hardware.

Why does the C128 perform poorly when running CP/M?

  1. 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. At that point, they were already 2 months into their 5-month development cycle. (see reference #3 below)
  2. 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 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.

Some of these issues were clearly not due to hardware limitations, but stemmed from a lack of optimization for the drivers used in CP/M. The engineers were on a tight schedule and implementing something that wasn't even part of the original C128 design. They would have had to rewrite the 8502 BIOS code in Z80 assembly language, but they were primarily hardware guys. I'm sure Commodore didn't want to spend extra money to optimize a feature they hadn't even asked for. So the simplest, most reliable route was to make calls to the already working and well-tested 8502 BIOS.

A 1999 update to C128 CP/M, by Linards Ticmanis, addresses some of the CP/M driver performance limitations of the original and purports to improve 80-column screen updates by 75%.


(speculation added 2017.03.01)
After fully reading reference #2, my understanding of the development bottleneck for the CP/M BIOS was clarified. The C128 team did have an excellent CP/M expert working off-site. It was never his goal to have the CP/M BIOS call the 8502 BIOS. Unfortunately the Commodore MOS group (the chip developers) had long-standing major problems delivering a working, stable, and reliable 8563 80-column video controller. This chip had been part of a Z8000 (16-bit version of Z80) Unix computer, the "C900", Commodore had once worked on, and apparently the chip had never been completed even for that use. Thus the 8563's fundamental design was based on an entirely different bus structure than the C128 offered.

The 8563 samples the C128 team received would tend to burn themselves up, arrive with documented deficiencies, and, in general, be altogether unreliable throughout most of the development process. The CP/M guy could not use current hardware. He had a board with an older 8563 revision that wouldn't burn itself up and mostly worked. (He had to keep it cool with an ice cube sat in a tray above it, though.) But ongoing changes to the chip must have kept invalidating his BIOS. My guess is at the last minute he was told something like, "Look, we'll eventually get the I/O working in house with the 8502 BIOS. You just make calls to that, and we'll make sure on our end that it eventually works right."


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.

The AEC is a signal pin of the C128's memory management unit. It is defined on pages 584 and 585 of the PRG:

AEC: Address Enable Control. Indicates whether the 8502 processor or the VIC has access to the shared bus. When low, VIC or an external DMA has the bus and VA16 have the processor bus, and no pointer or BIOS translation takes place. This signal occupies pin 16.

To put it bluntly, "It's complicated." The Z80A slowdown may be thought of as something like "wait states". Wait states are to allow a CPU running faster than memory to still operate, especially in an era before on-chip CPU caches alleviated the need for the CPU to access memory every (other) cycle. The problem on the C128 is that a 8502 CPU expects different things from its bus than a Z80 does. In the modern era, you can think of different motherboards being needed for different (yet current) '86 family CPUs. They can't just run the motherboards at slower and faster speeds and expect everything to work. Bil Herd and his team had to work with one motherboard and two entirely different CPUs.

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. IMO the perception of this mode being slow was much more to do with the I/O bottleneck than the effective 2 MHz clock rate of the Z80A. There had been lots of actual 2 MHz CP/M machines using the original Z80; there were few complaints about their speed. But imagine using a CP/M spreadsheet and actually observing   o n e   c h a r a c t e r   a t   a   t i m e   being written to the screen. It'd be kind of annoying.

Cool References

  1. THE REAL STORY OF HACKING TOGETHER THE C128 by Bil Herd, lead designer
  2. The C128 Story, aggregated CompuServe postings by Bil Herd
  3. HEY EVERYONE! IT'S BIL HERD!!! :) 1998 usenet post to comp.sys.cbm
    Bil describes why, how, and problems in adding a Z80 to the C128
  4. CP/M-cartridge for the C64, a README by Ruud Baltissen
    detailed explanation of interfacing a Z80 to a 6502 bus
  5. Platform Wiki: Commodore 128, backstory, design, and marketing for the C128
  6. CPM Z80 Cartridge for the Commodore VIC-40, (from early 1980s)
    timing and other diagrams for interfacing a Z80 to a planned successor to the VIC-20
  • 1
    This is a much better and in-depth answer than mine. – Jeff Zeitlin Feb 27 '17 at 13:26
  • Despite having a lot of respect for the C128 (I own several), it was really the classic example of not sticking to one thing and doing it well. It was neither a great Commodore 64 enhancement nor a great CP/M Z80 machine. It was a little bit of both. – cbmeeks Feb 27 '17 at 13:33
  • @JeffZeitlin Heh, thanks. Your answer complements mine, though. I saw the same quote at the Wikipedia, but as a former, self-proclaimed "C128 expert", it didn't fully satisfy me. It well describes intent, but is vague on the why. So I was stubborn and spent 3 hours answering. – RichF Feb 27 '17 at 13:41
  • @scruss Thank you for the correction. That's embarrassing. – RichF Feb 27 '17 at 13:43
  • 1
    @RichF I'm also wondering if the slow, mailbox-based, BIOS method of updating the screen was a hardware limitation. It seems that a CP/M driver optimization could have been created to access the 8563 more directly, bypassing the need to use BIOS calls that go through the 8502. Furthermore, I am aware of one third-party C128 CP/M update ("CPMFAST.ZIP") that purports to improve 80-column screen updates by 75%. Perhaps this is just such an optimization/fix? commodore.ca/manuals/funet/cpm/sys/c128/system/cpmfast.zip – Brian H Feb 27 '17 at 15:30

My first answer attempts to answer all the OP's questions without going too deep into the hardware details. Since posting that answer, I have had the pleasure of corresponding for several days with Bil Herd, the lead designer of the C128 project. In addition to what I have learned from him, I have done some additional research on my own.

This answer focuses on the hardware complexities which limited CP/M's effectiveness on the C128. It won't shy away from displaying system diagrams, timing diagrams, and etc. If you don't care about this level of detail, cool, and you have been warned. 🤖

Here is the System Diagram, taken from page 3 of the C128 Service Manual (C128SM - click to expand): C128 System Diagram Remember the big deal I made of the 80-column 8563 Video Display Controller in my first answer? That's the tiny bit in the lower left corner. It is almost completely isolated from the rest of the machine, except for the address and data buses. That is why communication with the 80-column video RAM takes place via two registers of the 8563. The 8563 has 37 registers total, allowing control of number of characters per line, number of lines, cursor position, video synch, etc.

You might be thinking, "There is a lot going on in that diagram." Yes. The C128 is essentially 4 computers in one box:

  1. a C64 with almost total compatibility, with the 8502 (upgraded 6502) running at 1 MHz and driving the 40-column VIC display
  2. a low-res C128 driving the 40-column display and running the 8502 at 1 MHz
  3. a high-res C128 driving the 80-column display and running the 8502 at 2 MHz
  4. a Z80A computer for running the CP/M operating system. It runs at 4 MHz, "half the time".

"Huh?" A diagram is in order, from page 8 of the C128SM: Z-80 Bus Timing Diagram

"Okay, I sort of get it. The Z80 clock is only running half the time. I see it, but that does not explain why?." The system clock is a 1 MHz clock provided by the VIC chip. In modes #1 and #2 it lets the 8502 run half the time, and allows itself half the time to update 40 column video RAM, move sprites, etc. One nice thing about 6502-family chips is that turning over half their time to something else costs them nothing, so they share with other stuff on the bus easily. In mode #3 it runs at 2 MHz and drives the 8502 at 2 MHz. Since the 40-column display is not active, the VIC need not worry about sprites and ignores the 40-column video RAM. Note, though, that this 2 MHz mode would not help the Z80A; at best it would simply force that chip into a semi-even 2 MHz mode.

Here is the kicker, why the VIC must keep running even when 40-column video is not active (from pg.33 of same manual):

The VIC chip contains a register which allows the C128 system to operate at 2 MHz instead of the standard 1 MHz of the C64. This operating speed, however, disallows the use of the VIC chip as a display processor. This bit is bit zero in register 48, and setting this bit enables 2 MHz mode. During 2 MHz operation, the VIC is disabled as a video processor. The µProcessor spends the cycle full time on the bus, while VIC is responsible only for dynamic RAM refresh and DMA arbitration. Clearing this bit will bring back 1 MHz operation and allow the use of the VIC as a video display chip. During refresh and I/O access, the system clock is forced to 1 MHz regardless of the setting of this bit.

(emphasis mine)
Rephrasing, if the VIC were completely shut off, the system's RAM would not be refreshed, and memory data would degrade. Also the VIC is forced to 1 MHz mode during refresh and I/O. Thus it makes no sense to use the 2 MHz VIC mode with CP/M because nothing is gained in the first place, and it would keep having to switch back to 1 MHz anyway. (The 8563 refreshes its 80-column memory asynchronously with everything else.)

There is even another reason for keeping the VIC alive during CP/M. Look again at the C128 System Diagram, focusing on the upper right corner. See the little box labeled C128 Extended Keyboard? What is that about?

C128 keyboard with C64 inset

Imagine using a business application with just the C64 keys. To get the rest, the VIC needs to be active. Well, "the rest" except the CAPS LOCK at the top of the keyboard. It operates as a simple switch, separate from the 2-dimensional keyboard matrix, and its value is fed directly to the 8502 CPU. That means the Z80A cannot read that one key directly. However, since normal CP/M I/O is indirect and utilizes the 8502 and its BIOS, that key value is available. Only a pure Z80A routine lacks access. However, such a routine would be affected by the value of the separate SHFT LOCK key.

The Display Bottleneck

Writing a character string to the 80-column screen from CP/M involves multiple layers of code:

  1. application layer - executes a printf() or other function to display a string
  2. BDOS layer - device-independent I/O handling for CP/M. BDOS can handle a full string, but must call steps 3-8 character by character.
  3. BIOS layer - sets up "memory mailboxes" so 8502 CPU can know what to do
  4. Z80A turns over control to 8502
  5. 8502 obtains command from mailbox and readies itself to make BIOS85 call
  6. 80-column screen-write call executes.
  7. 8502 returns control to Z80A
  8. BIOS returns to BDOS
  9. BDOS sends next character to step 3 or returns to application code

(Note that a native 8502 application would avoid most of these steps.)

Lets look at the heart of step #6 as an 8502 disassembly, beginning at location 0181F (not the actual BIOS85 code, just an example of what it needs to do).

0181F  A2 1F     LDX #$lF  ; 8563 R/W data register number  
01821  8E 00 D6  STX $D600 ; location of 8563 command register  
01824  2C 00 D6  BIT $D600 ; check high bit of command register value   
01827  10 FB     BPL $1824 ; loop until clear  
01829  8D 01 D6  STA $D601 ; (8563 data register) write character to screen  
0182C  60        RTS       ; return  

All 80-column screen communication occurs through the two 8563 registers, mapped to memory locations $D600 and $D601. Figure 10-2 illustrates this, from page 295 of the C128 Programmer's Reference Guide. 8563 Mapped Registers $D600 tells which of the thirty-seven 8563 registers you wish to read or write, and $D601 is the location to read or write the data. Since the 8563 is often occupied with its own memory and driving the 80-column screen, it can take time to handle the $D601 value. That's why you must always check the $D600 STATUS bit before reading from or writing to $D601. One useful feature of writing to register 31 (data register) is that the screen location auto-increments after the write. You need not manually increment it.


Don't assume the 8563 has a poor design. Normal (non-CP/M) 80-column C128 programs run with no noticeable delay in screen writes. The CP/M bottleneck is not the chip itself; it is the many layers of code through which screen writes must undergo.

It is one busy chip; everything else in this answer relates to its digital functionality. Don't forget that it drives the video as well, converting bytes in memory to a 4-channel per pixel video signal (RGBI). Most of what it is doing is invisible to the 8502/Z80A side of the board. If set to its normal 80x25 screen, that is driving:

  • 80*9 pixels per scan line
  • 25*9 scan lines (each 8x8 character can be embedded in a larger frame)
  • 60 screen refreshes per second
  • = 720 * 225 * 60 = 9.72 million pixels per second

Time is also allocated for horizontal and vertical synchronizations. Modify the synch values, and it can generate screens of more than 88 characters by 30 lines. Turn on interlace, and you can even double the number of scan lines. That's the output end.

From video RAM it must read the 80 character codes per line, read the associated byte of attributes for each character (color bits for (red, green, blue, intensity), as well as modifier bits for (alternate character set, reverse, underline, blink)). Finally it has to read the character definition RAM so that it knows what each character looks like. The 8563 character RAM is loaded during system boot-up, and both of its 256-element sets of 8x8 characters can be redefined by application programs. Internally I'm sure that some of the data is buffered within the 8563 (such as the current and maybe next character lines of data), but I don't know. The point is, no matter what's going on with the I/O ports at $D600 and $D601, the 8563 is extremely busy doing its job of displaying the screen. One more thing – because neither C128 BASIC 7 nor CP/M support it, few people realize the 8563 can also operate in a 2-color bit-mapped mode.

... not a poor design at all. I'll end with showing the 8563 register map to give you an idea of all the things this chip is handling. This is from page 37 of the C128SM. 8563 on-chip registers

  • I appreciate the diagram that shows how the pseudo-wait-state happens on the Z80A data bus access. A pictures is worth a 1000 words... – Brian H Mar 4 '17 at 17:06
  • Have you looked at the CPMFAST distribution for the C128? If I understand the modifications, it runs the 8502 in 2MHz mode during its execution of CP/M BIOS calls. – Brian H Mar 4 '17 at 17:09
  • @BrianH I read the readme.txt file and looked at cx80.asm, but I could not get a feel on how it fits with the CP/M BIOS. I had assumed until you asked this that he was talking to the 8563 directly and avoiding the 8502 BIOS calls altogether. But if he is still making the calls via the 8502, having it be in 2 MHz would only help a little. Note that during I/O access, the system clock is forced to 1 MHz. The ratio of non-IO to I/O code in the 8502 video BIOS would determine how effective 2 MHz would be. In larger picture, you still have Z80 BDOS and BIOS overhead. – RichF Mar 4 '17 at 20:18
  • @BrianH assume writing a character to screen takes 4 msec, with 1 msec in z80 cp/m BDOS, 1 msec in z80 cp/m BIOS, and 2 msec in 8502 BIOS. (Numbers chosen for simplicity; I have no idea what ratios are, and it's likely faster overall than 4 msec.) Even if you could halve the time spent in 8502 BIOS, the operation would still take 3 msec. – RichF Mar 4 '17 at 20:27
  • 1
    @RichF: That reminds me... didn't CP/M ignore the caps-lock key and use the C= key as a toggle for that purpose? – supercat Mar 9 '17 at 0:01

According to this Wikipedia article, the Z80 in the C128 was stepped down to 2MHz:

The C128 runs CP/M noticeably slower than most dedicated CP/M systems, as the Z80 processor runs at an effective speed of only 2 MHz (instead of the more common 4 MHz). From the source code of the C128 CP/M implementation, it is clear that the engineers originally planned to make it possible to run CP/M in the "fast" mode as well, with the 40-column output turned off and the Z80 running at an effective 4 MHz; however, this feature does not correctly function on the first-generation C128 hardware.

So, even though the chip was rated for 4MHz, it was never actually run at that speed in the C128.

  • Actually, it could be misleading to say the Z80A never runs at 4 MHz, since it is clocked with a 4 MHz signal from the VIC-II. It seems like, more precisely, there are wait states introduced during every set of potential Z80A bus access cycles; though, calling this "wait states" may also be wrong or misleading too :( – Brian H Feb 27 '17 at 15:56
  • 1
    @BrianH - Strictly speaking, you're right - but whatever was happening there, it left the Z80 performing as though it were actually running at 2MHz instead of 4MHz, which I assumed (and we know about that word) was enough to answer the question. – Jeff Zeitlin Feb 27 '17 at 16:06

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.