2015. január 28.

How I sped up CP/M display

As I have mentioned on my earlier post, I wasn't satisfied with the speed of character display speeds in Commodore 128 CP/M. So, I have investigated the source codes on me, related to Z80 ROM, and CP/M BIOS. In the meantime, I have learned the 8080 derived Z80 mnemonic syntax (bleh, ouch, very inconsistent compared to the Z80 syntax), and begin to code... well, not really, first I needed to establish a development environment.

VICE 2.4 C=128 emulator proved to be buggy on emulating C128+1571 drive in CP/M mode, making all write attempts to disk a failure. So, I also installed VICE 2.3. I have tried to use MyZ80 as was advised for speed reasons, but failed to get a CP/M 3 version of it, so I decided to compile and test also on VICE, C128 emulator, and write the source on my laptop in Windows 8.1. To transfer single files to D71, D64 images, a DOS tool-set can be used: ctools. So, I also needed to install DosBox 0.74 to make that happen.

In VICE, running C128 I configured 3 disk drives: 8: 1571 as boot, 9: 1571 as temp/transfer, 10: 1581 to have more space for the sources and compile. The workflow was as following:
- Modify source in Notepad++
- Use ctools to copy modified source to temp.D71, under DosBox
- Boot up VICE C128, copy sources from temp.D71 to development.d81
- Compile in VICE
- Update CPM+.SYS on boot
- Reboot and test, and restore the boot.d71 on failure

But getting down to business, and modifications a made to the BIOS. Making a long story short: I have implemented a buffered, and burst output to directly to the VDC chip, leaving out the built-in ROM when needed.

Why did this speed up the display process at all? And how could I convert a char-by-char display to a buffered one? It's not that obvious as it sounds for the first time, if someone doesn't know the inner workings of the BIOS, so let's have a look at that first.

The BIOS provides only a single "chout" procedure for the BDOS, to make a single char displayed on the next cursor position. Sounds simple? Ehh, not. Since this BIOS call is redirectable, depending on the active device (a disk, printer, console, etc...), and the handling of the special chars on the console (screen), like "go to top left corner" expressed with a single car, or "go to X column and Y row", expressed by 4 chars after each other, using the proper escape sequence. The original BIOS handles those special char sequences by storing callback, continue addresses pointing to further char checks on next BIOS call. Also, the BIOS checks every time the active devices, where most of the times only the screen is active as char out device.

Making those shortcut on device checks were already introduced in '93, with the speed bios verison 6.2. I have just added a buffer, to store chars on BIOS call, and only flush to display when it is full. The "flush" procedure has the trick. It reads up all the chars stored in the buffer one after the other, and if they are normal characters meant to be displayed ordinary, it uses the feature of the VDC chip, to auto increment memory addresses where the next character is to be stored. Since most of the time the buffer contains only normal chars, it has the following consequences: 2*char-num-in-a-row+14 output instructions, compared to the contant 16 output instructions per char in the original implementation, using the BIOS. Since IO is potentially slow to communicate with the VDC chip, it is a big gain, having 92 outs for 40 char string, instead of the 640 outs in the old implementation.

Also, this way, there is no need to store multi-char-decoding continue addresses, since the algorithm simply can fetch the next byte as needed. Except if it reaches the end of the buffer, when it simply copies the 1-3 unprocessed chars to the front, and finishes running, and the system waits for an other buffer flush.

The only drawback of this approach is that, you won't see anything while you are typing, since the buffer is not full yet (most probably). However, most of the programs are spending their time waiting user input, by calling "chin" procedure in the BIOS. If no key is pressed, so the input buffer is empty, the BIOS is waiting in a loop for a new char. This loop can be used to flush the buffer, at any filled up state. This was almost good, so far, however the clever programs used instead the "chstat" procedure call, to check if there are chars waiting to input, so, no flush again... until I have added a countdown to that procedure as well, which when reached 0, called the flush. OK! Now you see "instantly" what you are typing. But the fe in compile time, when the programs do some work, and don't expect any input, never checks the input line, so even if they update the screen with information on their status, since no flush occurs, you will not see it. Or, even worse, you will see some half rows, ended in the middle of a word. That's why the disk status indicator proc also got the countdown, to be able to flush the buffer.

The results? VDO (which is a memory only text editor), displays screens, and pages of text noticeable faster! What about games? I guess action games will not work... Contact me, if you are interested in testing.

Nincsenek megjegyzések:

Megjegyzés küldése