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
    Commented Feb 26, 2017 at 19:35
  • 2
    @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
    Commented Feb 27, 2017 at 1:13

7 Answers 7


I'm Linards Ticmanis, the guy who put out the CPMFAST package in 1999 that has been mentioned several times in the other answers (although I go by the nickname TeaRex on here). While creating that, I had to take a deep look into the innards of C128 CP/M, so that I think I can say that I have a rather detailed understanding of the way it works internally (or did have it over 20 years ago... I'm not excluding some failures of human memory here). I'm afraid there is some myth and half-truths in some of the other answers to this question.

Firstly, in C128 CP/M, writing to the 80-column screen does NOT go through the 8502 CPU as several other answers assert; the Z80 talks directly to the 8563 VDC (the 8502 is used by CP/M for several other things, such as disk I/O and printer output, but not for screen output and not for keyboard input either).

The reason why screen output in C128 CP/M is so slow is rather

  1. The Digital Research provided BDOS of CP/M 3.0 is much slower in doing basic character I/O than the BDOS of the more common CP/M 2.2; CP/M 3.0 does support much more complex I/O device reassignments where standard output can go to any possible set of up to 16 devices at the same time; this also means that for every character being written, it has to loop in a complicated, bit-shifting way over a 16-bit mask to determine which of 16 output device drivers to actually send the character to, and of course it does all this in pure Intel 8080 code without making use of the Z80 specific instructions and registers.
  2. The code in the C128's Commodore supplied CP/M BIOS (which for this purpose includes the 4KB of Z80 ROM code) is written in such a way that outputting normal printable characters such as letters or numbers (as opposed to control characters) follows the LONGEST path through the code (each character is compared to every possible control character before it is decided that it isn't one), even though it is the most common case by far.
  3. C128 CP/M supports the bit-banging RS232 on the userport. Unlike in native or C64 mode, the RS232 is always enabled and set to 300 baud by default, which means that the interrupt (IRQ) rate is also much higher than in native mode; and the interrupt code for the Z80 does quite a bit of things, including scanning the full keyboard at the same rate. This wastes a lot of CPU time when RS232 is not used (i.e. practically always).
  4. Bank switching between the user program (TPA in CP/M parlance) in bank 1 and the BIOS/BDOS/ROM/buffers in bank 0 happens VERY often in the C128 CP/M. Several times per character. Although the impact of this is lower than the other three points above.
  5. Access to the 80-column screen RAM is doubly indirect as indicated in other answers (you have to access the RAM indirectly through some registers of the VDC chip, which in turn are only indirectly accessible to the CPUs through a rather bottleneck-y approach - you write a register number to $D600, do a little check-for-the-readiness-flag-bit-to-be-set loop and then write a register value to $D601).
  6. The biggie is of course the fact that the VIC-IIe is not put into fast mode when the Z80 is running, so that the Z80 runs at 4MHz for two cycles (one 8502 half-cycle) and then stops for two cycles (the other 8502 half-cycle), giving it an effective speed of just 2 MHz, which is just too low for CP/M 3.0 in practice, although it would be sort of enough for CP/M 2.2. The C128 CP/M source code (which was available from Commodore back in the day when you bought the complete set of CP/M 3 manuals from them) contains multiple instances of code that switches the VIC-IIe between slow mode (for hardware access, e.g. access to the REU, and for switching between the two CPUs) and fast mode (for everything else); but it's all commented out, so it seems they aimed for that but couldn't get it working. I tried to mail the main developer, Von Ertwine, with a question about this back in the 90s, but unfortunately never got an answer.

In practice, you CAN switch the VIC-IIe into fast mode while the Z80 is running; this causes a simple timing loop with interrupts disabled to in fact run somewhat faster (though not twice as fast), but crashes the system when you do much of anything beyond this. It would be really interesting if someone could check with a logic analayzer (which I don't have access to) what exactly happens signal-wise, especially to the Z80 clock signal, when you enable fast mode while the Z80 is running.

CPMFAST adresses the first three points above by establishing several short-cuts through the code for the common case (output of a printable character, to the 80 column screen only, without RS232 use) and also increases the disk buffer area so that fewer disk accesses are needed. It cannot do anything about the points numbered 4 through 6, though.

  • 2
    TeaRex, thank you for the detailed info. I am confused on a major issue, though. You state that CP/M writes to the screen do NOT go thru the 8502 CPU, but the CP/M chapter of the C128 Programmer's Reference Guide seems to state otherwise. I quoted a section which begins with the sentence, "The 8502 is responsible for most of the low-level I/O functions." It seems very strange that they would use the word "most" yet include neither screen nor keyboard I/O in this. I am not saying you are wrong, just that if you are correct, official docs are misleading.
    – RichF
    Commented Feb 7, 2020 at 13:35
  • 2
    @RichF, maybe the C128 PRG was (partially) written before the CP/M code had been finalized? You can look at the code yourself to see what it does.
    – TeaRex
    Commented Feb 7, 2020 at 14:02
  • 2
    Thanks for helping me understand better the major issues and which ones were readily (vs. not so much) solvable. Knowing that C128 FAST mode doesn't work in CP/M explains a lot.
    – Brian H
    Commented Apr 14, 2020 at 14:58
  • 1
    CP/M Plus character device reassignment is handled in the BIOS, not the BDOS. Though it's entirely possible that Commodore simply copied the 8080 code from Digital Research's sample BIOS as printed in the CP/M 3 System Guide.
    – john_e
    Commented Mar 14, 2023 at 12:49
  • In normal mode, the VIC-IIe would perform DRAM refresh cycles during its half of some of the memory cycles on each scan line. I don't know how such cycles are handled in fast mode, would not be surprised if they fail to occur in fast mode when using the Z80. I also don't know whether DRAM rows use upper or lower address bits--or whether a sequence of 51 e.g. "LD HL,(009Ah) / LD HL,(0x009Ch) / LD (HL,0x009Eh) / etc. up to LD HL,00FEh" and a "RET" starting at byte 0 of a page could be executed every couple milliseconds to ensure every row gets hit, or whether something more like...
    – supercat
    Commented Jun 15 at 18:38

(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:

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.

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. Commented Feb 27, 2017 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
    Commented Feb 27, 2017 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
    Commented Feb 27, 2017 at 13:41
  • @scruss Thank you for the correction. That's embarrassing.
    – RichF
    Commented Feb 27, 2017 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
    Commented Feb 27, 2017 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
    Commented Mar 4, 2017 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
    Commented Mar 4, 2017 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
    Commented Mar 4, 2017 at 20:18
  • 1
    @supercat No "need". The Z80A can talk to both the 8583 and the VIC to control either the 80-col or 40-col screens. Both if you want. AFAIK, the problem with CP/M BIOS was that during development, the 8563s were very unreliable and "fixes" kept breaking other things. Their CP/M guy tried to use the 8563 directly, but in the end, the decision was made to kludge CP/M, having it call the 8502 BIOS code, which at some point the C128 folks knew would have to become rock solid. As far as I know, the only I/O value not available to the Z80 is the value of the CAPS LOCK key, fed directly to the 8502.
    – RichF
    Commented Mar 8, 2017 at 23:53
  • 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
    Commented Mar 9, 2017 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.

  • 1
    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
    Commented Feb 27, 2017 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. Commented Feb 27, 2017 at 16:06

Others have pointed out the slowness causes, but here I will point out some solutions. Firstly, switch to ZPM which is a Z80 BDOS replacement for the 8080 based CP/M BDOS. CPMFAST is another option to speed up the general OS.

From a programmers' perspective you can bypass BDOS and BIOS and drive the VDC directly as I've done in SG C Tools (also turn off 40 column display). Although this will not help existing programs such as Wordstar it does dramatically speed up programs specifically written for the C128. The C code looks like the following to draw a string at x,y:

uchar invdc(uchar RegNum)
  outp(vdcStatusReg,RegNum);                  /* internal vdc register to read */
  while ((inp(vdcStatusReg) & 0x80) == 0x00); /* wait for status bit to be set */
  return(inp(vdcDataReg));                    /* read register */

void outvdc(uchar RegNum, uchar RegVal)
  outp(vdcStatusReg,RegNum);                  /* internal vdc register to write */
  while ((inp(vdcStatusReg) & 0x80) == 0x00); /* wait for status bit to be set */
  outp(vdcDataReg,RegVal);                    /* write register */

/* fast vdc string print given x and y offset in current page */

void printstrvdc(uchar X, uchar Y, uchar Attr, char *TextStr)
  register uchar I, TextLen;
  ushort DispOfs;

  TextLen = strlen(TextStr);
  if(TextLen > 0)
  DispOfs = Y*vdcScrHorz+vdcDispMem+X; /* calc disp mem offset */
  fillattrvdc(X,Y,TextLen,Attr);       /* use block fill for attrs */
  outvdc(vdcUpdAddrHi,(uchar) (DispOfs >> 8));
  outvdc(vdcUpdAddrLo,(uchar) DispOfs); /* set addr of first char */
  for(I = 0; TextStr[I]; I++)          /* send str to vdc disp mem */
  • 1
    This is interesting information, but doesn't answer the question. Please say what each solution is solving; that way, it will address the question topic.
    – wizzwizz4
    Commented Dec 30, 2018 at 16:46
  • The question was about CP/M performance on the C128 which includes 8080 version of CP/M and BDOS/BIOD calls (answered above). I gave two solutions to the performance issues. Commented Dec 30, 2018 at 17:53
  • 1
    Which performance issues do these solve, though?
    – wizzwizz4
    Commented Dec 30, 2018 at 18:20
  • 1
    ZPM and CPMFAST both speed up the BDOS and BIOS functions most programs leverage because they use Z80 instead of 8080 op codes. Each distro also optimizes in other areas including screen output. The second suggestion is to bypass BDOS and BIOS all together and write directly to the VDC. This is handy for programmers to know. Commented Dec 30, 2018 at 21:39
  • 1
    There's an edit button.
    – wizzwizz4
    Commented Dec 30, 2018 at 22:14

As far as I know the Z80 only runs at the same 2MHz the 8502 runs at. Which, internally, works out to 2/4=0.5MHz. Which is just plain slow. Source: a guy who came to visit our desk last night and knew everything else about the machine. So take with a grain of salt and downvote as much as you like.

  • 1
    Thanks for sharing this, but I don't see why you'd divide 2MHz by 4. Where did the 4 come from?
    – wizzwizz4
    Commented Dec 28, 2018 at 17:59
  • Good question. Like I said, a guy came by and said so. I googled for "z80 clock divider" now and found at least one thing (cpcwiki.eu/forum/programming/z80-clock) where someone (2nd post) talks about a "divide by 4 circuit". Perhaps someone else can shed some light ... ?
    – Sixtyfive
    Commented Dec 28, 2018 at 18:14
  • 1
    In case it helps to dispel a myth: the shortest instruction on a Z80 takes four cycles, comprising two memory accesses (a fetch and a refresh) of two cycles each. Most other memory accesses take three cycles so the next big tranche of Z80 instructions is those that are seven cycles long, but there are fives and sixes, and various others that obviate any sort of attempt to fit everything to a pattern of 4n, or even 4 + 3n.
    – Tommy
    Commented Dec 28, 2018 at 18:14
  • 1
    @RainerVerteidiger the Amstrad is special because it does some trickery with timing signals to coerce a 6502-esque fixed memory access cadence, with memory available for video every other tick. Which does end up (approximately) rounding up every instruction to a multiple of four cycles. But other machines use various different schemes — on the Spectrum there's no rounding or other penalty while the processor is accessing RAM that video can't be in, on the MSX there's an extra cycle in every instruction fetch but everything else runs at the natural speed, etc.
    – Tommy
    Commented Dec 28, 2018 at 18:21
  • Rainer, you are both right and wrong. The z80 runs at an "effective speed of 2.04 MHz". Right. However, it is clocked at 4.08 MHz, but only half the time. That's the sort-of-wrong part. A number of early cp/m machines ran at 2 MHz, so that in itself was not unusually slow. Later 4 MHz become the common speed, though. Note that in competition with the 6502, a 2 MHz z80 was roughly equivalent to a 1 MHz 6502. (generally 4 cycles to do very basic stuff on a z80 vs 2 cycles on a 6502)
    – RichF
    Commented Dec 30, 2018 at 18:18

I am far from C128 expert of any level (HW or SW), but I think one (expensive) change could solve all those speed issues. Certainly it is not possible afterwards, but could be a design route to speed up the machine, and would keep C64 compatibility at the same time, whil Z80 could run in full 4 Mhz mode (though it does not solve the several layers and BIOS routing / slow screen update). As it was not mentioned beforehand, I write down the idea.

Reading through the descriptions and time diagrams, VIC-II need to be in 1MHz mode to update the DRAMs. And because of the 1MHz of VIC-II, the Z80 and the 8502 need to be is slow mode too. But what if there would be no DRAM in the machine, just SRAM, requires no frequent refreshes, and does not degrade content (the same as the color RAM on C64)? In that case the VIC-II 1MHz mode could be cancelled in C128 and Z80 mode, or it could run continuously in 2MHz mode. Certainly SRAMs were (and still) more expensive than DRAMs, but the speed is there. As my current C=16 64K memory expansion is based on SRAMs, I though I let you know this idea.

  • Welcome to RetroComputing, and thank you for sharing the idea, I'm guessing that implementing your idea would have been costly , and likely not as easy as it sounds.
    – RichF
    Commented May 4, 2020 at 2:25
  • Actually, the VIC-IIe refreshes the DRAMs even in 2MHz mode when the 8502 is running. So I don't think this is the reason why FAST mode and Z80 operation are (in practice) incompatible with each other.
    – TeaRex
    Commented May 4, 2020 at 9:13

You must log in to answer this question.

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