diff --git a/_posts/2017-07-15-flickery-fakery.md b/_posts/2017-07-15-flicker-fakery.md similarity index 98% rename from _posts/2017-07-15-flickery-fakery.md rename to _posts/2017-07-15-flicker-fakery.md index c12c2ff58..91e928344 100644 --- a/_posts/2017-07-15-flickery-fakery.md +++ b/_posts/2017-07-15-flicker-fakery.md @@ -1,11 +1,11 @@ --- layout: post -title: Flickery Fakery +title: Flicker Fakery date: 2017-07-15 10:00:00 permalink: /blog/2017/07/15/ --- -For years, one of my pet peeves about PC emulators has been their obsession with raw speed, and how hard they +One of my long-standing pet peeves about PC emulators has been their obsession with raw speed, and how hard they try to squeeze every last drop of performance out of their instruction execution loop, on the assumption that everyone wants an 8088 that runs at, say, 500Mhz, as opposed to the stately 4.77Mhz of the original IBM PC. diff --git a/_posts/2017-07-21-retroreview-speedup.md b/_posts/2017-07-21-retroreview-speedup.md new file mode 100644 index 000000000..0e8141667 --- /dev/null +++ b/_posts/2017-07-21-retroreview-speedup.md @@ -0,0 +1,244 @@ +--- +layout: post +title: RetroReview: SPEEDUP +date: 2017-07-21 10:00:00 +permalink: /blog/2017/07/21/ +machines: + - id: pcsig08 + type: pcx86 + resume: 1 + config: /disks/pcx86/shareware/pcsig08/debugger/machine.xml + autoMount: + A: + name: PC-DOS 1.00 + B: + name: PCSIG08: DISK0011 +--- + +While browsing the June/July 1982 issue of PC Magazine (Vol. 1, No. 3), I found the following +[User-To-User](https://books.google.com/books?id=w_OhaFDePS4C&lpg=RA3-PA151&ots=cXovjlDNc8&pg=RA3-PA151#v=onepage&q&f=false) +article about an intriguing little program called `SPEEDUP`. Unfortunately, the first time I tried it, +it immediately hung my test machine. Here's the original article, followed by my analysis of the program +and why it hung. + +> ### Disk Speedup + +> The undisputed celebrity of this month’s user tips is SPEEDUP--14 lines of BASIC program code that will make your +disk drives perform their chores in half the time. The program popped up on Wes Merchant's Annandale, Virginia IBM +Bulletin Board Service (see Club News). It was sent there by Chris Carson of Aurora, Colorado, who found the program +circulating in the Denver area. Good news travels fast. Here it is: + + 05 REM SPEEDUP DISK-ZAP + 10 FOR I=1 TO 37:READ N:C=C+N + 15 NEXT:READ N:IF N<>C THEN 40 + 20 RESTORE:OPEN "R",1,"SPEEDUP.COM",1 + 25 FIELD 1,1 AS N$:FOR I=1 TO 37 + 30 READ N:LSET N$=CHR$(N):PUT 1 + 35 NEXT:CLOSE:PRINT "Created":END + 40 PRINT "** ERROR - Verify Data **":END + 45 DATA 186,18,0,184,30,37,205,33,139 + 50 DATA 250,190,26,1,185,11,0,243,164 + 55 DATA 51,192,205,19,139,215,205,39 + 60 DATA 223,2,37,2,8,42,255,80,246,0,4 + 65 DATA 3866 + 70 END + +> Even if you've never touched BASIC, the gem is too good to pass up. To create the program, place the PC-DOS +disk into your A: drive and load BASIC by typing *BASIC* and hitting *Enter*. Then type each of the lines above, +exactly as written. Hit *Enter* after each line. When you've *Enter* following line 70, hit the *F2* key to run +this short program. + +> If you get a message saying "\*\* ERROR - Verify Data \*\*" then you've made a mistake copying the numbers in line +45 through 60. Otherwise, you will have created a new file on your PC-DOS disk called SPEEDUP.COM. + +> Go back into PC-DOS by typing *system* and *Enter* and run the new program by typing *speedup* and *Enter*. Now +load and run any program or PC-DOS utility and be amazed. Your disk drives will miraculously zip along at almost +double speed, singing instead of groaning. + +> Exactly how much faster? Well, for example, to format a new disk with the /S option: 25 seconds instead of 45 +seconds. To copy the PC-DOS disk via the "DISKCOPY" command: 42 seconds instead of 83. To copy the entire PC-DOS +disk with "COPY \*.\*": 139 seconds instead of 206. If you're a speed and performance fanatic (who isn't), you've +just made up to a 100 percent improvement in your disk operations. + +> According to Chris Carson, the program works its magic by reloading the diskette parameters table in PC-DOS. +IBM programmed the step rate for the machine's Tandon disk drives at eight milliseconds; SPEEDUP shortens this to +six, still within the Tandon-rated minimum of five milliseconds. The program also sets the head settle rate to +zero milliseconds, which is the Tandon minimum rating (IBM's conservative default setting is 25). + +Fortunately, we don't have to type the program in. If you skim our archived copy of the +[PC-SIG Library 8th Edition CD-ROM (April 1990)](/disks/pcx86/shareware/pcsig08/), you'll see `SPEEDUP.BAS` +in the [Directory of PCSIG08: DISK0011](/disks/pcx86/shareware/pcsig08/#directory-of-pcsig08-disk0011). + +So, fire up the [PC-SIG Machine (with Debugger)](/disks/pcx86/shareware/pcsig08/debugger/). Or use the machine +below, which has conveniently pre-loaded "PC-DOS 1.00" in drive A and "PCSIG80: DISK0011" in drive B. + +At the DOS prompt, run `BASIC` and type `LOAD "B:SPEEDUP.BAS"`. + +{% include machine.html id="pcsig08" %} + +When you `LIST` the program to the serial port: + + LIST,"COM1:" + +you'll see that the program is virtually identical to the PC Magazine listing: + + 10 FOR I = 1 TO 37 + 11 READ N + 12 C = C + N + 15 NEXT + 16 READ N + 17 IF N <> C THEN 40 + 20 RESTORE + 21 OPEN "R",1,"SPEEDUP.COM",1 + 25 FIELD 1 , 1 AS N$ + 26 FOR I = 1 TO 37 + 30 READ N + 31 LSET N$ = CHR$(N) + 32 PUT 1 + 35 NEXT + 36 CLOSE + 37 PRINT "created" + 38 END + 40 PRINT "** error. Verify DATA" + 41 END + 45 DATA 186,18,0,184,30,37,205,33,139 + 50 DATA 250,190,26,1,185,11,0,243,164 + 55 DATA 51,192,205,19,139,215,205,39 + 60 DATA 223,2,37,2,8,42,255,80,246,0,4 + 65 DATA 3866 + +If you `RUN` it, it should report "created". Type `SYSTEM` to exit BASIC and then type `DIR SPEEDUP.COM` +to verify that the program was created: + + SPEEDUP COM 128 07-21-17 + +You'll notice that BASIC created a 128-byte file, even though it wrote only 37 bytes. This is an +artifact of PC-DOS 1.00 and BASIC Version D1.00, which were limited to File Control Block (FCB) DOS +functions that operated on files using 128-byte "records". + +Alternatively, if we boot from "PC-DOS 2.00 (Disk 1)" and run BASIC Version D2.00, loading and running +`SPEEDUP.BAS` will produce the following `SPEEDUP.COM`: + + Volume in drive A has no label + Directory of A:\ + + SPEEDUP COM 37 7-21-17 12:00a + 1 File(s) 30720 bytes free + +Let's take a closer look at this 37-byte program, using the `DEBUG` program on "PC-DOS 2.00 (Disk 2)": + + A>B:DEBUG SPEEDUP.COM + -u100 + 0913:0100 BA1200 MOV DX,0012 + 0913:0103 B81E25 MOV AX,251E + 0913:0106 CD21 INT 21 + 0913:0108 8BFA MOV DI,DX + 0913:010A BE1A01 MOV SI,011A + 0913:010D B90B00 MOV CX,000B + 0913:0110 F3 REPZ + 0913:0111 A4 MOVSB + 0913:0112 33C0 XOR AX,AX + 0913:0114 CD13 INT 13 + 0913:0116 8BD7 MOV DX,DI + 0913:0118 CD27 INT 27 + -d 11a lb + 0913:011A DF 02 25 02 08 2A FF 50 F6 00 04 + +The program uses the DOS Set Vector function (INT 21h, AH=25h) to modify interrupt vector 1Eh (the Diskette +Parameter Table vector) to point DS:0012, inside the program's Program Segment Prefix (PSP). It then copies +0Bh bytes from offset 011Ah into the PSP at offset 0012h, issues a BIOS Disk Reset (INT 13h, AH=00h), and +then executes a Terminate and Stay Resident (TSR) request (INT 27h) with DX set to 1Dh, retaining the first 12h +bytes of the PSP plus an additional 0Bh bytes containing the new diskette parameter values. + +Note that this TSR program doesn't actually want to retain the first 12h bytes of the PSP, but it must leave +those bytes in place so that the program will exit correctly. + +In PC-DOS 1.00 (August 1981), the first 12h bytes of the PSP were used as follows: + + 00h-01h 2 bytes (code) CP/M exit (always contains INT 20h) + 02h-03h 2 bytes Segment of the first byte beyond the memory allocated to the program + 04h 1 byte Reserved + 05h-09h 5 bytes (code) Far call to CP/M compatibility code within DOS + 0Ah-0Dh 4 bytes Terminate address of previous program (old INT 22h) + 0Eh-11h 4 bytes Break address of previous program (old INT 23h) + +with bytes 12h-5Bh marked "Reserved" and the remaining PSP bytes defined as: + + 5Ch-6Bh 16 bytes Unopened Standard FCB 1 + 6Ch-7Fh 20 bytes Unopened Standard FCB 2 (overwritten if FCB 1 is opened) + 80h 1 byte Number of bytes on command-line + 81h-FFh 127 bytes Command-line tail (terminated by a 0Dh) + + NOTE: The 128 bytes at offset 80h are also used as the default DOS Disk Transfer Area (DTA). + +In May 1982, PC-DOS 1.10 added: + + 12h-15h 4 bytes Critical error address of previous program (old INT 24h) + 16h-17h 2 bytes Parent's PSP segment (usually COMMAND.COM - internal) + +In March 1983, PC-DOS 2.00 added: + + 18h-2Bh 20 bytes Job File Table (JFT) (internal) + 2Ch-2Dh 2 bytes Environment segment + 2Eh-31h 4 bytes SS:SP on entry to last INT 21h call (internal) + +And in August 1984, PC-DOS 3.00 added: + + 32h-33h 2 bytes JFT size (internal) + 34h-37h 4 bytes Pointer to JFT (internal) + +This explains why, when I first ran `SPEEDUP` on PC-DOS 2.00, it crashed. In fact, the *only* version +of DOS that supports `SPEEDUP` is version 1.00. It crashes on all other versions of DOS because it "trashes" +critical PSP bytes; specifically, the Parent's PSP segment at offset 16h. The author of `SPEEDUP` ignored IBM's +warning that PSP bytes at offset 12h and higher were "reserved" and used them anyway. + +> NOTE: Other sites, like [PC DOS Retro](https://sites.google.com/site/pcdosretro/doshist), suggest that +the "Parent's PSP segment" at offset 16h wasn't introduced until PC-DOS 2.00, but that's incorrect. Even though +the PC-DOS 1.10 Manual (p. E-6) mentions only the addition of the "Critical Error Exit Address" at offset 12h, +both fields were in fact added in PC-DOS 1.10. + +Sadly, the history of the IBM PC and DOS is littered with examples of programmers ignoring the "reserved" +admonitions of others -- even IBM, when they designed the IBM PC to use interrupt vectors that Intel had "reserved" +for future use. This is apparently normal human thinking: "If something isn't a problem today, then let's punt +any foreseeable problems to future generations, because we've got more important things to do." + +And on PC-DOS 1.00, does `SPEEDUP` actually speed things up? In the real world, it presumably did, but in +the world of emulation, there isn't any measurable difference, because hardware features like stepping rates and +head settling times are rarely simulated. As I suggested in my [last blog post](/blog/2017/07/15/), this is a +degree of authenticity that all emulators should strive for, and PCjs is no exception to that rule -- I just haven't +gotten around to it yet. + +### Epilogue + +There were some nice side benefits to debugging the problems introduced by `SPEEDUP`. + +First, when attempting to `LIST` a BASIC program to a serial port, I discovered that BASIC depends on the port +generating a "Transmitter Holding Register Empty" interrupt after outputting each byte, and that I had never actually +implemented that interrupt. Only the "Received Data Available" and "Modem Status" interrupts had been implemented, +largely for serial mouse support. That has since been fixed, although "Line Status" interrupts still need to be +implemented, along with the proper queuing of all *four* possible types of serial port interrupts. + +NOTE: Serial I/O from DOS (ie, redirection to or from a COM port) already worked because DOS performs polled I/O +rather than interrupt-driven I/O. Additionally, when DOS terminates a line, it outputs both CR (0Dh) and LF (0Ah) +bytes, whereas BASIC outputs only CR; so, when a machine uses a <textarea> control for serial I/O, we +automatically convert transform stand-alone CR bytes into LF bytes. + +Second, when `SPEEDUP` crashed on newer versions of DOS, an invalid stack pointer would be loaded, and I noticed +that I had neglected to fully implement stack wrap-around on 8086/8088 processors; specifically, in the case where the +stack pointer is *odd*. + +Normally, when the stack pointer is *even*, it will smoothly auto-decrement from 0000h to FFFEh or auto-increment +from FFFEh to 0000h. However, when the stack pointer is *odd* and it reaches 0001h, the next PUSH on a 8086/8088 must +automatically store the high byte at 0000h and the low byte at FFFFh; similarly, when the stack pointer is FFFFh, +the next POP must fetch the low byte from FFFFh and the high byte from 0000h. + +Most emulators simulating an 8086/8088 in real-mode actually use V86-mode, which doesn't support stack operands that +wrap around the top of the stack segment; V86-mode will throw an exception, and the machine is toast. PCjs makes more +of an effort simulate real-mode, so any PUSH or POP should work smoothly, regardless whether the stack pointer is even +or odd. + +PCjs is still far from perfect. For example, instruction fetches that cross a 64K boundary are supposed to wrap around +to 0000h as well. That's not implemented yet, but stay tuned. + +*[@jeffpar](http://twitter.com/jeffpar)* +*Jul 21, 2017* diff --git a/disks/pcx86/shareware/pcsig08/debugger/machine.xml b/disks/pcx86/shareware/pcsig08/debugger/machine.xml index 94225c90c..4ffa5e78c 100644 --- a/disks/pcx86/shareware/pcsig08/debugger/machine.xml +++ b/disks/pcx86/shareware/pcsig08/debugger/machine.xml @@ -8,7 +8,7 @@ -