Fixed serial port transmitter interrupts, and added a new blog post (RetroReview: SPEEDUP)
This commit is contained in:
parent
b7e424a46c
commit
a85662632c
8 changed files with 810 additions and 541 deletions
|
|
@ -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.
|
||||
|
||||
244
_posts/2017-07-21-retroreview-speedup.md
Normal file
244
_posts/2017-07-21-retroreview-speedup.md
Normal file
|
|
@ -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*
|
||||
Loading…
Reference in a new issue