                                  PLIP112.TXT
                          (for PLIP v11.2, June 2003)
                               by Fred C. Macall


Introduction

The first time I tried PLIP v11.1 was a pretty disappointing experience.

Well, I am here to tell you that this story has a happy ending.  Getting to
that depended, for the most part, on some fixes and enhancements I have made
in PLIP v11.2.  However, an attitude readjustment and some big discoveries
have also played roles in this success story.  The big discoveries have to do
with TELBIN and TRMPING (introduced below), a strange relationship existing
between them, and a Windows 9x configuration "secret".

At the time of this writing, at the end of June 2003, I have successfully
used PLIP v11.2 to make DOS-DOS, DOS-Linux, and DOS-Windows 9x parallel port
TCP/IP connections between PCs of widely varying vintage and speed.
I have every reason to expect that this technology also makes Linux-Linux,
Linux-Windows 9x, and Windows 9x-Windows 9x parallel port TCP/IP connections
feasible.  (The Linux kernel's plip module provides packet driver(s) for
Linux on the connections with Linux.  Linux or Windows TCP/IP applications
replace TELBIN and TRMPING in the Linux or Windows environments.)
These connections should support all of the usual TCP/IP applications and
tools nearly as well as ethernet connections do.

Meanwhile, my big disappointment came the day I tried connecting parallel
ports, on my PCs:  Booker and Sailboard, with a "LapLink parallel cable".
Booker and Sailboard were both running DOS and PLIP version 11.1, which is a
packet driver TSR for parallel ports.  One of them was running TELBIN.EXE
version CUTE:2.2D/BC-Rutgers-1.0, as a TCP/IP FTP server.  The other was
running the FTP.EXE version 0.70 TCP/IP FTP client.  I was also using tvdog's
undocumented ping.exe (45,024 octets), which I have renamed TRMPING.EXE, and
a WATTCP based PING program, which I have renamed WATPING.EXE, for testing.

This kind of setup has worked well for me with interconnected ethernet cards
and matching packet driver TSRs in place of the interconnected parallel ports
and PLIP TSRs.  With 10 M bits/second ethernet cards, this kind of setup
usually provides transfer rates around 125 K bytes/second.  So, there is the
beginning of our attitude readjustment.  That transfer rate is only about a
tenth of what we might expect from dividing 10 M bits/second by 8 bits/byte.

But, the parallel ports based setup didn't seem to work at first.
Then, after some ping testing, it started working after a fashion.  The ping
tests were reporting long response times and relatively high packet loss
rates.  I was able to transfer a file from Sailboard to Booker with TELBIN
running on Booker.  I think the transfer rate was about 2 K bytes/second.
When I tried to repeat the same transfer from Sailboard to Booker with TELBIN
running on Sailboard, Booker hung in FTP.  The system timers on both PCs lost
a lot of time during the transfers that succeeded.  Oh, and did I mention
that strangely colored digits between 0 and 7 were crawling up the right hand
column of the displays?

So, I gave LapLink version 3 a turn on Booker and Sailboard.  It seemed to
validate my parallel port hardware setup by doing my test file transfer, in
either direction, at an average rate of about 48 K bytes/second.  The DOS
INTERLNK/INTERSVR package is nearly as fast.  However, I haven't found any
software that can beat LapLink's file transfer speed, on lowest common
denominator ("4 bit") parallel ports and cabling.  So, here is some more
attitude readjustment.  The parallel ports transfer rate to beat is only
about a 25th of the rate we might have estimated at first for
10 M bits/second ethernet cards.

Although I haven't yet told you what transfer rate I was finally able to get
with PLIP and the TCP/IP FTP applications, you probably can guess by now that
it was quite a bit less than what LapLink can do.  So, before I waste your
time with the rest of this story, let me point out some things that have
become obvious:

If you've decided to use a parallel port connection to share, say, a CD-ROM
reader between two PCs that can both run DOS, you'll be better off using
something like LapLink or INTERLNK/INTERSVR.  On the other hand, if you're
looking for a low cost or temporary way to connect an odd PC running DOS into
a TCP/IP based network (and on to the internet), then read on!  If you want
better networking performance than lowest common denominator parallel ports
and PLIP will provide, you may as well put an ethernet card into your odd PC.

Your network connection will need to be made via a PC running a DOS bridge
program such as YAPCBR, Linux, or Windows 98.  Though DOS-Windows 95 parallel
port TCP/IP connections may be made, Windows 95 seems to have to be an end
point for the communications on such connections.  That is, I haven't found
any way to get Windows 95 to relay or route those communications.  It looks
as though this depends on adding an EnableRouting=1 value to the MSTCP
section of SYSTEM.INI or the registry.  When I tried this, Windows hung in
the next boot, saying:  Windows protection error.  I had to copy SYSTEM.DA0
over SYSTEM.DAT in order to restore my registry and get Windows up again.

Since performing that trial, I have found Microsoft knowledge base article
Q142543.  It confirms the behavior I experienced.  Q142543 goes on to say:
"IP routing is not a supported feature of Windows 95."  My experience is that
this limitation has been removed from Windows 98 SE.  I am not sure which
side of the IP routing limitation fence Windows 98 (first edition) falls on.
However, I haven't found a knowledge base article like Q142543 that mentions
Windows 98.


Names and References

Bashful  --  My 1994 vintage '486DX-66 based desktop PC.
             Ran DOS and NAPT with a 56 K dial modem and ethernet card
             to provide an Internet gateway for this report's trials.

Booker  --  My 1995 vintage Pentium-166 based notebook PC.
            Ran DOS for this report's trials.

Digerydo  --  My 1997 vintage Pentium-150 based desktop PC.
              Ran DOS and Windows 98 SE for this report's trials.

DosLynx v0.24b  --  DOS Web browser for lowest common denominator PCs.
http://members.nccw.net/fmacall/dlx24bin.zip

DOSPLIP  --  A package, by Mike Leonhard, including LSL.COM, PDETHER.EXE,
             PLIP.COM v11.1, and a README.TXT explaining how to set them up
             to make PLIP usable, as an "Existing ODI Driver", in Windows 9x.
             (This package's otherwise thorough document seems to omit an
             important Windows 9x configuration secret or instruction that
             had to be rediscovered during the course of work reported here.)
http://www.tamale.net/windows/dosplip.zip

EPPPD  --  DOS PPP client packet driver emulator TSR.  It is the heart of the
           DOSPPP06 package.
http://personal.redestb.es/tonilop/dosppp/dosppp06.zip

FTP v0.70  --  DOS FTP client program based on the Waterloo TCP/IP stack.
ftp://ftp.oldskool.org/pub/tvdog/internet/ftp07.zip
ftp://ftp.oldskool.org/pub/tvdog/internet/ftp07.txt

INTERLNK/INTERSVR  --  DOS file and printer sharing add on for serial and
                       parallel PC connections.
                       Included in Microsoft DOS versions 6.x and Windows 95.
                       INTERLNK is a block device driver installed in the
                       "client" machine's CONFIG.SYS.  INTERSVR is a server
                       program for the "host" machine.
http://www.microsoft.com/

LapLink  --  DOS (and, in later versions, Windows) file transfer program
             for serial and parallel PC connections.  (The latest version(s)
             of LapLink don't support parallel port connections anymore.)
http://www.laplink.com/aboutus/

LapLink Parallel Cable  --  Also known as:  Parallel Data Transfer Cable.
                            Five data outputs are connected to five sense
                            inputs, in each direction.  With a signal ground
                            lead, these make an eleven wire cable.  Some
                            Internet sites appear to be offering cables like
                            this for as little as $ 2.95 for a six footer.

NAPT  --  DOS Network Address Port Translator (Internet gateway) program, for
          use with packet drivers.  It is the heart of the Internet Extender
          package.
http://www-acc.scu.edu/~jsarich/ieweb/download.htm

PARALLEL v1.45  --  DOS Parallel Port Information Utility program.
                    This tool can tell you if your parallel port(s) are
                    better than lowest common denominator.  (With PLIP, that
                    doesn't matter.)  And, together with a simple paper clip
                    loopback jumper, it can check a port's IRQ number, IRQ
                    input level sensing polarity, and IRQ functionality.
                    The package includes a large documentation file.
ftp://ftp.lpt.com/parallel/para14.zip

parport.txt  --  A documentation file included with the Linux kernel source
                 since kernel version 2.1.33.  This file may be found at:
                 /usr/src/linux/Documentation/parport.txt in your Linux
                 system.  It explains how parport.o, parport_pc.o, and
                 parport_probe.o have to be used with lp.o, plip.o, and other
                 parallel port using modules, starting with version 2.1.33.
http://www.charmed.com/support/kernel/docs/parport.txt

PLIP v11.1  --  DOS packet driver TSR for PC parallel ports, with source.
                Portions Copyright 1992, Russell Nelson
                (The present package appears to have been published in 1995.)
ftp://ftp.crynwr.com/drivers/plip.zip

PLIP v11.2  --  Fred Macall's June 2003 update of Russell Nelson's package.
http://members.nccw.net/fmacall/PLIP112.ZIP

PLIP  --  Linux PLIP Mini How To document.
          Includes a section on using PLIP for DOS-Linux interconnection.
          (This document has fallen behind developments in the newer Linux
          kernels.  You may have to take parts of it as only a guide.
          In addition to the Linux parallel port support changes discussed in
          parport.txt, newer Linux kernels may incorporate "ipfw" or
          "ipchains" facilities that will have to be administered to enable
          TCP/IP packet forwarding.)
http://www.ibiblio.org/pub/Linux/docs/HOWTO/mini/PLIP

Q142543  --  Microsoft Knowledge Base article entitled:
             Windows 95 Hangs with TCP/IP Routing Enabled
ftp://ftp.microsoft.com/MISC/KB/en-us/142/543.HTM

Sailboard  --  My 1994 vintage '486DX-33 based desktop PC.
               Ran DOS, Linux, and Windows 95 for this report's trials.

TELBIN vCUTE:2.2D/BC-Rutgers-1.0  --  Clarkson University (DOS) TCP 
                                      Communication Package (Rutgers Interim
                                      Release).  Used as an FTP server for
                                      this report's trials.
ftp://ftp.oldskool.org/pub/tvdog/internet/cutcp-b.zip

TRMPING  --  tvdog's undocumented DOS ping.exe program, renamed.
ftp://ftp.oldskool.org/pub/tvdog/internet/ping.exe
ftp://ftp.oldskool.org/pub/tvdog/internet/ping.txt

WATPING  --  DOS PING program based on the Waterloo TCP/IP stack, renamed.
             One of a number of WATTCP applications included in:
http://www.ncf.ca/ncf/pda/computer/dos/net/watapps1.zip

YAPCBR  --  Yet Another (DOS) PC BRidge program, for use with packet drivers.
ftp://ftp.crynwr.com/drivers/ypcbr102.zip

Zeke  --  My 1988 desktop PC with switch selectable 8088 and '286 processors.
          Its 8088 processor was used for most of this report's trials.
          This machine's parallel port has inverted level interrupt sensing.
          Ran DOS v3.3 for this report's trials.


Preliminary Revisions

Since the PLIP package includes complete assembler source, I decided to have
a look and see if I could find what might be causing the poor results I was
getting.  I had noticed that the results seemed to depend on which end of the
Booker/Sailboard connection was running TELBIN.  That suggested that I was
looking for timing issue(s).  I found that all of the source goes into just
three modules, which are easy to assemble and link.  The three modules come
from HEAD.ASM, PLIP.ASM, and TAIL.ASM.  Those sources carry INCLUDEs for all
of the other .ASM files used.

Well, after reading the three assembly listings for a day or two, I had found
a number of questionable or debatable things.  That is, things that might or
might not be contributing to the poor results that I was getting.  I was able
to see these things relatively quickly because this software is so well
structured and commented.  Most of the questionable things I found were
easier to "fix" than to be proved culprits.  So, I simply fixed them to my 
liking.  I've added comments, documenting the changes I made, to the
beginning of each .ASM file that I revised.  There are only five of these.
Also, for the most part, I've used upper case assembler mnemonics on the
lines I've changed or added.

Perhaps the thing most clearly in need of fixing, that I found at this point,
had to do with how recv_byte sampled or strobed the four bit data nibbles
that it receives.  (recv_byte is located in the PLIP.ASM module.)  The packet
sender at any given time signals the presence of each new data nibble by
toggling the fifth data bit that it OUTputs in parallel with the new nibble.
recv_byte INputs the five interconnected sense lines, in a loop, while
waiting for that fifth bit to change.  The first INput nibble accompanied by
the expected fifth bit value was being taken as the received nibble.

Well, that approach depends on any skew, in the timing of the signal changes
among the five bits, being such that the fifth bit is never seen to change
until after all of the data bits have their correct values.  I don't know
that there is anything in typical parallel port interfaces or cables to
assure that.  However, if it is ever possible for the fifth bit to be seen to
change before all four data bits have their correct values, I am sure that
recv_byte would then, at least occasionally, mis-read a received nibble.

To fix that exposure, I've extended recv_byte to continue its loop until it
has INput two consecutive matching nibbles with the expected fifth bit value.
The loop timing is such that this precaution should accommodate more noise
and timing skew than will ever be experienced with cables of a reasonable
length.  With this fix, recv_byte will require at least one additional loop
cycle for each received nibble.  Clearly, I have traded a performance
reduction for a reliability improvement.  That probably makes this fix just
as debatable as my others.

I also found a couple of obvious lapses in PLIP's (debug) statistics
collecting.  send_pkt's exceptions weren't being counted in the errors_out
count.  So, that count was always zero.  And, relatively harmless "spurious
interrupts", which occur quite frequently in some environments, were being
counted along with more significant receive exceptions in the errors_in
count.  That seriously diminished the usefulness of the errors_in count.

To fix these problems, I added some code to f_send_pkt in HEAD.ASM, to count
send_pkt calls returning an exception indication, in the errors_out count.
And, I added a new count called spurioushwints.  I have revised recv, in
PLIP.ASM, to increment that count, rather than the errors_in count, when it
detects a spurious interrupt.  That leaves the errors_in count free to
report unambiguously on the other kinds of receive exceptions.


Antique Hardware Hack Command Line Option

Well, my real goal in this project was to get my oldest PC, Zeke, connected
into my home network.  Zeke has no ethernet card.  I hoped to accomplish my
objective by means of a parallel port connection to my PC, Digerydo.
Digerydo is the one PC in my home network that usually runs Windows 98 SE.
A parallel printer port is available on Digerydo because my network's printer
is connected to Sailboard.  (Unfortunately, a parallel port interconnection
will be contending with a Zip drive for use of Zeke's parallel port.)  So, my
next step was to move my LapLink parallel cable to connect Zeke and Digerydo.
This section's trials were performed with Digerydo running DOS.

With both machines running PLIP, it quickly became clear that Zeke was not
receiving much, if anything, from Digerydo.  However, INTERLNK/INTERSVR
works fine on this connection.  (When I use that software, Zeke runs INTERSVR
and Digerydo runs INTERLNK.)  For a third vote, I tried LapLink version 3.
It wouldn't work on the connection, seconding PLIP.   After a lot of head
scratching, I finally ran PARALLEL on Zeke.

I could immediately see that PARALLEL's report for Zeke was different from
the ones it had given for Booker and Sailboard.  PARALLEL reported that the
ACK line input level polarity triggering an IRQ is reversed from normal on
Zeke's parallel port!  This may stem from confusion in the early years of the
PC industry over IBM's convention for this interrupt.  I haven't opened Zeke
up to see if it might have a jumper or switch for changing this polarity.

PLIP uses the parallel port's IRQ to start its receive process when the other
end's PLIP wants to send a packet.  While idle, both PLIPs send 00000 on
their respective sets of five interconnected data lines.  When either PLIP
wants to send a packet, it changes its code to 01000 to bid for the transfer.
The changed data line in that bid code is connected to the other end's ACK
input.  A 0 to 1 transition on that line is expected to trigger an IRQ in the
PC that is to receive.  If the ACK input's interrupt polarity is reversed, a
1 to 0 transition is needed instead, on that line, to produce an IRQ.
So, Zeke wasn't getting IRQs signalling Digerydo's attempts to send.
And, that was keeping Zeke from receiving Digerydo's packets.  I decided to
see if I could fix this by changing PLIP's bid code.

An interrupt awakened PLIP responds to a sending PLIP's bid by changing the
00000 (idle code) it is sending to 00001.  Seeing that, the sending PLIP uses
1abcd to convey its first nibble of packet (length) data.  Seeing that, the
receiving PLIP sends 10000.  Seeing that, the sending PLIP uses 0efgh to
convey its second nibble of (length) data.  Seeing that, the receiving PLIP
sends the 00000 idle code again.  Seeing that, the sending PLIP uses 1jklm to
convey its third nibble.  And, so on.  At the end of the packet, the sending
PLIP returns to sending the 00000 idle code again.  I wanted to choose a new
bid arrangement that wouldn't necessitate introducing complication(s) into
that packet data transfer procedure.

I decided to provide a command line option to change PLIP's bid code to a
fairly rapidly alternating sequence of 01100 and 00100.  This sequence will
quickly produce an interrupt in the intended receive machine, whatever input
level it senses to trigger its IRQ.  The constant 1 bit in the new sequence
will allow an interrupt awakened PLIP to quickly verify that a bid is being
presented.  At the same time, an interrupt awakened PLIP also will be able to
honor the old bid code by recognizing any of the three 0xy00 codes containing
a non-zero xy.  I've designated the new command line option:  -a to suggest
the idea of an antique hardware hack.

The new -a command line option may be used freely where PLIP v11.2 is being
used at both ends of a parallel ports connection.  It has to be used in a PC
opposite one with an inverted input level sensing IRQ.  Unless timer
interrupt driven receiving is configured in the PC with the inverted IRQ.
The timer interrupt driven receiving arrangement that I've also provided is
introduced near the end of the section headed:  DOS-Windows 9x Parallel Ports
Connection, Part 1.  The -a command line option probably has to be avoided
for DOS PLIP to remain compatible with the Linux kernel's plip module (and
DOS PLIP version 11.1), until it can recognize the new bid codes.

I resumed testing with updated PLIPs in place on Zeke and Digerydo, and with
-a specified on PLIP's command line on Digerydo.  The good news was that the
connection then seemed to be "solid".  PING tests no longer showed lost pings
or real long response times.  I was using TRMPING a lot at this point.
The bad news was that my file transfer tests, for both directions, obtained
an average transfer rate of (only) about 3 K bytes/second.  That's comparable
to the maximum download (but not upload) transfer rate obtained with EPPPD on
a 56 K modem and a faster machine (Bashful).  I attribute this poor
throughput to Zeke's slowness.  (I estimate that Bashful's processor is about
forty times faster than Zeke's.)  In contrast, COPY commands for transfers in
both directions yielded an average file transfer rate of about
13 K bytes/second over a parallel port INTERLNK/INTERSVR connection between
Zeke and Digerydo.

At this point, Zeke was able to contact the Internet via Digerydo running
YAPCBR, my ethernet LAN, and Bashful running NAPT with a 56 K modem and
EPPPD.  Web surfing with DosLynx was noticeably faster than it has been with
Zeke's 19.2 K baud dial modem and EPPPD.  Of course Digerydo, running YAPCBR,
had to be dedicated to this exercise.


DOS-Linux Parallel Ports Connection

I decided that I would be leaving Zeke connected to Digerydo.  So, I got 
another LapLink parallel cable for more Booker to Sailboard testing!
I wanted to verify that the changes I was making in PLIP v11.2 weren't
disrupting its compatibility with the Linux kernel's plip module.  (With the
-a command line option not specified.)  I did my testing with Booker running
DOS and PLIP v11.2.  And, Sailboard running Linux kernel versions 2.0.30
(from Slackware Linux v3.4) or 2.2.14-5.0 (from Red Hat Linux v6.2).

The Linux PLIP mini How To instructions guided me through the arrangements I
needed to make, with the version 2.0.30 kernel, pretty well.  lp.o gets
loaded while Linux is booting.  And, both of Sailboard's parallel ports are
strapped for IRQ 7.  So, I used the following sequence to load plip.o:

rmmod lp
insmod plip io=0x278 irq=7

However, that wouldn't work with the 2.2.14-5.0 kernel.  From parport.txt, I
learned that a sequence like the following is needed with the newer kernels:

rmmod lp
rmmod parport_probe
rmmod parport_pc
rmmod parport

insmod parport
insmod parport_pc io=0x278,0x378 irq=7,none
insmod plip

(The first part of that sequence is only to undo module loading that my Linux
system performed while booting.  The

rmmod parport
insmod parport

commands aren't necessary in that case.  I've included them to make it clear
that parport.o is needed for parport_pc.o and plip.o.  Also, note that the
port(s) configuration specification has moved from plip.o to parport_pc.o.)

If you aren't sure how your modules are structured, you can command:

modinfo -adp <modulefile>

to check them out.

The use of arp in ifconfig commands is one other area that may be found
troublesome in establishing DOS-Linux or Linux-Linux parallel port TCP/IP
connections.  The rule is:  For a DOS-Linux connection specify arp in your
ifconfig up command.  For a Linux-Linux connection, don't specify arp in your
ifconfig up command.  Note that when you use ifconfig to report on the setup
you've achieved, NOARP will be reported if arp hasn't been instated.
But, with the Slackware v3.4 ifconfig at least, there won't be any mention of
arp if it has been instated!

I performed my final timing trials for this arrangement after making the
big discoveries reported in the section below headed:  Digression on TRMPING,
do_timeout, and TELBIN.  And, after finalizing PLIP v11.2.  At that time, I
had Booker running DOS, PLIP v11.2, and TELBIN, as an FTP server.
Sailboard was running Linux kernel v2.0.30, its plip module, and the
Slackware v3.4 ftp client.   With TELBIN "primed" by TRMPING, my standard
file transfer test averaged about 24.6 K bytes/second, for both directions.
Wow!  That's the fastest parallel port TCP/IP connection transfer rate I've
obtained.  

I repeated this test with Booker unchanged and Sailboard running Linux
kernel v2.2.14-5.0, its parport, parport_pc, and plip modules, and the 
Slackware v3.4 ftp client.  The transfer rate obtained in the Sailboard to
Booker direction was almost the same as with kernel v2.0.30.  However, the
transfer rate in the Booker to Sailboard direction was then a lot slower.
The average for both directions was (only) about 5.2 K bytes/second.
This wasn't a complete surprise because my Linux system feels sluggish when
running the version 2.2.14-50 kernel.  And, because the parallel port modules
were still relatively fresh from their restructuring in that version.  I can
only hope that the version 2.4+ kernels have now returned to a performance
level more like that of the trusty old version 2.0.30!


DOS-Windows 9x Parallel Ports Connection, Part 1

Mike Leonhard has provided pretty thorough instructions, in his DOSPLIP 
package, for using PLIP in Windows 9x.  The essence of his setup is that
LSL.COM and PDETHER.EXE are used together with PLIP.COM to provide the
appearance of an ODI Driver.  If you add this trio of TSRs to your
AUTOEXEC.BAT, or provide any other way to run them from DOS before starting
Windows 9x, then an "Existing ODI Driver" will appear in your Control Panel's
Network applet!  To be sure, I am using LSL.COM and PDETHER.EXE, from Mike's
package, along with the version 11.2 PLIP.COM that I'm releasing.

Mike's procedure goes on to add the Windows 9x IPX/SPX compatible protocol to
bind with the PLIP based ODI Driver.  I have found that the Windows 9x TCP/IP
protocol may be bound with this ODI Driver, instead or as well.  When this is
done, Windows adds ODIHLP.EXE to the trio of PLIP, LSL, and PDETHER, in your
AUTOEXEC.BAT.  ODIHLP.EXE comes from your Windows installation media.
The stack of "wedge" components LSL, PDETHER, and ODIHLP fit PLIP to the role
of a "Real Mode NDIS 3 Driver"!

Well, I guess I'm a little slow about Windows.  Because as soon as I tried
this arrangement out, on Digerydo, I ran into a bit of a problem that Mike's
paper hadn't prepared me for.  The tables were turned.  Now it was Digerydo
that couldn't receive packets from Zeke.  Having seen this problem the other
way around, the symptoms were unmistakable.

I learned that, as Windows 9x runs in the i386's protected mode, parallel
port IRQs will have to be "handed down to the real mode or virtual 86 mode
IRQ handler".  In this case, that's to PLIP.  That wasn't happening and I
couldn't figure out, right away, how to tell Windows to do that.  At one
point, I tried removing the existing Windows parallel port "device", lpt.vxd,
from my configuration.  But, Windows reinstalled it, all by itself, at the
next boot!  Then, I renamed it lpt.vx$.  But, PLIP still received no
interrupt(s).  I had visions of having to write a Windows .vxd to convey the
parallel port's IRQs to PLIP.

While stuck on the issue of getting Windows to give PLIP its interrupts, I
noticed that LSL hooks the timer interrupt vector (INT 008h for IRQ 0).
And, Windows does hand the timer interrupts down to the real mode TSRs.
So, I decided to augment PLIP with a timer interrupt driven receiver routine.
This also might come in handy for a DOS-Linux connection in need of an -a
option setting that the Linux plip module can't provide.  As it stood in 
version 11.1, PLIP provided no receiver routine when a <hardware_irq> value
of 0 was specified on the command line.  So, in version 11.2, I have revised
PLIP to provide the new timer interrupt driven receiver routine in that case.

Well, the new timer interrupt driven receiver routine eventually did provide
an error free, but slow, DOS-Windows 98 SE parallel port TCP/IP connection
between Zeke and Digerydo.  Before this arrangement worked for TRMPING on
Zeke, however, I also had to deal with a problem, in PLIP's do_timeout
routine, that turned out to be caused by TRMPING!

Eventually, I figured out how to get Windows to hand the parallel port's
IRQs down to PLIP.  As parallel port interrupt driven receiving is much
faster and more efficient than timer interrupt driven receiving, I'll return
to configuring Windows for that after the following digression:


Digression on TRMPING, do_timeout, and TELBIN

TRMPING was unable to send its pings from Zeke to Digerydo the first time I
tried to use a timer interrupt driven receiving routine in PLIP on Digerydo.
That was puzzling because WATPING and TELBIN didn't seem to be having any
trouble sending from Zeke!  The trouble turned out to be due to a timeout in
the send_pkt_1 loop in send_pkt in PLIP.ASM.  This loop is where a PLIP
bidding to send a packet waits for the other PLIP to respond to its bid.
The loop contains a call, to do_timeout, which checks to see if an initially
specified timeout period has elapsed.  I tried increasing the loop's initial
timeout specification temporarily, to avoid the timeout that was occurring,
and found that it had to be increased from 18 to about 90.
do_timeout's arrangements are such that this increase is expected to increase
the loop's timeout from about half a second to about 2.5 seconds.

Why should a 2.5 second timeout have to be specified to accommodate a 1/18th
second timer interrupt driven receiver response time at the other end?
Well, note that 2.5 * 18 is 45.  I realized that TRMPING must have loaded the
system timer's count latches with data that would yield a one millisecond
timer period, for measuring round trip ping time!  The system timer must be
cycling at about 56 times its normal rate when TRMPING is running.  As it
stood, do_timeout couldn't help but reflect the system timer's speed up in
its timeout determination.

do_timeout is defined in TIMEOUT.ASM, which is include(d) in PLIP.ASM.
It assumed the system timer's count latches contain zero, which specifys a
timer cycle length of 65,536.  (Anything else would specify a timer cycle
length shorter than 65,536.)  It tracked the system timer's cycles by
subtracting the timer's present count from its previous count on each call it
received.  As the system timer is counting down, those differences normally
were the call-to-call elapses in counts of 1.19 mhz reference clock cycles.

do_timeout doubled those call-to-call elapse counts and added them up, in a
16 bit word, to get a value that cycled at twice the system timer's cycle
rate.  do_timeout's sum of elapses continued to cycle at twice the system
timer's increased cycle rate when TRMPING's tampering shortened that cycle.
So, do_timeout then declared a timeout in about a 56th of the intended time.

There was nothing wrong with do_timeout's assumption.  TRMPING appears to be
altering a PC resource that is intended to be left alone.  But, I wanted to
see if I could find a way for do_timeout to tolerate that tampering.
After all, do_timeout's determination doesn't have to be very precise.
It just needs to roughly track the 1.19 mhz reference clock.
Through observations of the system timer's counts that don't depend so much
on an assumption about its cycle length.  In short, do_timeout needs to be
able to more-or-less ignore the one big elapse observed in each system timer
cycle, just after the system timer's counter has been reloaded with a
shortened count.

I realized that the one big elapse per shortened system timer cycle came from
the borrows made by the elapse calculating SUB instruction that do_timeout
used.  Get rid of those borrows, and do_timeout's elapse calculations get a
little noisey.  But, they then no longer include that big once per cycle
error pulse.  So, I've changed do_timeout's SUB instruction to an XOR
instruction!

To see how that works, suppose PLIP is running on a very fast processor.
A processor so fast that PLIP's wait loops can make a do_timeout call often
enough for it to sample every system timer count.  Then, the XOR instruction
will get 1 in the least significant bit every time the system timer count is
found changed.  For a full timer cycle, those 1s add up to 65,536.  The next
(more significant) bit will be seen to be 1 every other time the system timer
count is found changed.  Those 1s have a weight of 2 and, for a full timer
cycle, add up to 65,536, as well.  And, so on.  So, for a full timer cycle,
the XOR instruction's elapses may be seen to add up to sixteen times what the
SUB instruction's elapses added up to.  

If the system timer's count latch contents should be changed from zero, the
XOR instruction's elapses won't accumulate as fast as they did with a full
timer cycle.  Because some of the most significant bits in the XOR's elapses
may always be zero.  With tampering like TRMPING's, this slow down might be
expected to only be about 38 percent.  That's much more stable than the 56
times speed up that the SUB instruction's elapses produced in this case.

Well, what if the processor isn't so fast, you wonder?  In that case, the XOR 
instruction's elapses will tend to be missing 1s in the least significant
bit positions.  (The SUB instruction's borrows make up for those missing 1s
and keep its elapses accurate in this case.)  Again, the XOR instruction's
elapses will accumulate at a slower pace.  Again, the resulting slow down is
expected to be relatively mild.

On the basis of this analysis, I have also changed do_timeout's elapse
doubling SHL instruction to a halving SHR instruction.  This brings the
revised do_timeout's timeouts to perhaps a little less than about a quarter
of what they were.  If the effects discussed just above lengthen these
timeouts, they have a way to go before they get longer than they were.

With do_timeout's sequence of SUB and SHL instructions changed to XOR and
SHR, TRMPING worked as well as the other TCP/IP tools and utilities on the
DOS-Windows 98 SE connection, with timer interrupt driven receiving in
Windows 98's PLIP.  This connection was solid, but slow.  Using PLIP's -d
command line option on Digerydo, to get PLIP hooked into the timer interrupt
chain ahead of LSL, didn't seem to help its speed.  Windows 98's DOS window
PING command, working against TELBIN on Zeke, reported an average round trip
time of about 51 milliseconds.

While doing this work, I slowly came to realize that the effect of TRMPING's
tampering wasn't confined to the period of its own run.  I found that after
running TRMPING, and ending it with the Esc key, TELBIN tends to yield faster
transfers than it would otherwise!  I suppose TRMPING leaves the system timer
running a shortened cycle.  And, I suppose TELBIN has some system timer based
procedure(s) that get speeded up as a result.  Since changing do_timeout,
TRMPING's apparent effect on TELBIN isn't as pronounced as it was.
However, that effect remains observable.

Since making this discovery, I have been careful to always use a "priming"
TRMPING run ahead of each TELBIN run.  So, I'm reporting TELBIN transfer
rates favorably influenced by TRMPING's tampering.  TRMPING doesn't seem to
have any effect on subsequent WATPING or FTP runs.


DOS-Windows 9x Parallel Ports Connection, Part 2

Fortunately, I have learned how to get Windows 9x to hand the parallel port's
IRQs down to PLIP.  This is accomplished by first "Reserving" the needed IRQ
"Resource".  To do this, work through Windows' screens as follows:

Start
    Settings
        Control Panel
            System
                Device Manager
                    *  View Devices by Connection
                        Computer
                            Properties
                                Reserve Resources
                                    *  Interrupt Request
                                        Add
                                            Enter parallel port's IRQ number.
                                        Ok
                            Ok
            Ok

Next, remove any software "devices" already claiming the parallel port's
resources.  Once the parallel port's IRQ has been "Reserved", it won't get
reclaimed if Windows reinstalls these "devices" later.  Don't forget to
remove any Parallel Port Zip Drive device driver software you might have
installed in CONFIG.SYS or Windows!

After a reboot, you should find Windows relaying the parallel port's IRQs to
PLIP.

After changing the <hardware_irq> specified to Digerydo's PLIP command from 0
to 7, I rechecked the connection's average round trip ping time, with
Windows 98's DOS window PING command.  The reported average has improved from
51 milliseconds to 21 milliseconds.  TRMPING is reporting a round trip time
of 24 or 25 milliseconds, from Zeke's end of the connection.  My standard
file transfer test, conducted with Windows 98's DOS window FTP client on
Digerydo and TRMPING primed TELBIN, as an FTP server on Zeke, has an average
transfer rate, for both directions, of about 4 K bytes/second.  That's about
25 percent faster than what I obtained with a DOS-DOS parallel port TCP/IP
connection between these machines.

Using the ROUTE ADD . . . command, to make couple of additions to Digerydo's
route table, enabled Zeke to contact all of the systems on my LAN.  And, all
the systems on my LAN are able to contact Zeke.  I found that these additions
persist across boots and don't have to be provided from a start up batch
file.  I am able to surf the Web via DosLynx running on Zeke and my Internet
gateway on Bashful.  This works better than ever and Digerydo no longer has
to be dedicated to this activity.  My main goal has been fully attained!


Clean Display Command Line Option

The colored digits between 0 and 7, that I found appearing at the right end
of the bottom line of the display, turned out to be the result of a debug
feature left in recv_real, in PLIP.ASM.  Each new debug digit displayed
signals that a bid has been recognized and that a packet receive operation is
starting.  I became somewhat attached to seeing these once I understood what
they represent.  However, as PLIP started working better and better, they
seemed less and less appropriate.  I wondered if I wanted to see debug digits
like these from the packet drivers for my ethernet cards?  Well, I guess not.

As a finishing touch for my revision of PLIP, I've added a -c command line
option to keep recv_real's debug digits off the display.  You might think of
that as the Clean Display option.


Unresolved Issues

All but two of the unpleasant issues I recognized in my first encounter with
PLIP version 11.1, on my DOS-DOS parallel port TCP/IP connection between
Booker and Sailboard, have been resolved in PLIP version 11.2.
In particular, the connection now seems solid.  Its reliability no longer
depends on which ends of the connection are running TELBIN and FTP.
Or, on whether TRMPING has been run.

The remaining issues are:  The system timers still loose time.  And, the file
transfer rates obtained still leave a lot to be desired.  They are still poor
in comparison with LapLink.  Also, the file transfer rates still seem to be a
little sensitive to which ends of the connection are running TELBIN and FTP.
And, on whether TRMPING has been run ahead of TELBIN.

The most consistent (with respect to transfer direction) and fastest average
DOS-DOS transfer rate comes with TELBIN running on Sailboard.  Before TRMPING
has been used, an average transfer rate of just over 10 K bytes/second is
obtained for both directions with this setup.  After running TRMPING on
Sailboard, an average rate of about 11.4 K bytes/second is obtained.
Moving TELBIN to Booker brings both the fastest and the slowest DOS-DOS
transfer rates obtained.  But, the average is significantly depressed by that
slow transfer.  It is about 5.8 K bytes/second before any use of TRMPING.
And, about 6.8 K bytes/second after using TRMPING on Booker.  So, these
transfer rates range from an eighth to a quarter of the average transfer rate
delivered by LapLink version 3.  My observations are all from watch based
transfer timings, to avoid inflation due to the system timer losses.

The system timer losses are probably attributable to PLIP's keeping all 
maskable interrupts disabled during each packet's transmission.  As it was,
PLIP was leaving interrupts enabled while receiving each packet.  This meant
that the transmitter's masked periods were being extended by the receiver's
timer and other interrupt(s) processing!  In PLIP version 11.2, I've added
maskable interrupts disabling during each packet's reception.  This minimizes
the maximum duration of interrupts disabling and may have reduced the system
timer losses a little.  This may have also improved PLIP's reliablity for
connections between PCs of widely differing speeds.

fmacall@nccw.net
