Parallel Printer Driver


A basic understanding of how the TSX parallel printer driver sends data to the printer is necessary before you consider adjusting TSGEN parameters to solve a problem. Here we will discuss the polled mode, which is the default unless you specify a /INTERRUPT qualifier on the DEVICE=LP line in the TSX32.GEN file.

The first thing to realize is that TSX calls the the parallel printer service routine on a clock driven basis, whenever any printing is active. This clock driven service occurs every clock tick, 100 times per second.

Each time the service routine is called it wants to send multiple bytes of data to the printer, up to a maximum which is specified by the /LOOP4 unit parameter. The default for this is 50, so this means that a maximum of 5,000 characters per second will be sent to the printer.

Before any data can be sent to the printer, the printer must state through its control register that it's ready to accept another byte. At the top of its main loop, the printer driver insists that the ready bit be high, the noerror bit be high, and the error bit be low. If these conditions are not met at this point we wait until the next clock tick.

Now that the printer is ready to accept another character, the data byte is written to the printer's data port. After doing this, a delay of at least a half a microsecond is required to give the printer time to see the character. The duration of this delay is controlled by the /LOOP1 parameter, whose default value is zero. This may seem counterintuitive but just entering the "delay" subroutine in TSX and returning should take a half a microsecond. If your printer is not printing at all, you might want to try to set LOOP1 to some small value such as 5. The unit here, as with all /LOOP values, is in microseconds.

Next the strobe signal must be set low for a period of time. This is done by writing a pattern of bits to the printer control port whose value can be set with the /ST1 unit parameter. The default value for this is 13; a discussion of the individual bits of the printer control port is not presented here.

After setting the strobe signal low, the printer driver must delay a second short time; the length of this delay, whose default value is 1, can be controlled by the /LOOP2 gen parameter. Again, if your printer won't respond at all, you might try a generous experimental increase of /LOOP2, say to 50.

Once the strobe signal has been low for this period of time the strobe signal is set high again by writing a second value to the printer control port. This bit pattern, whose default value is 12, can be set with the /ST2 gen parameter. The only reason to play with ST1 and ST2 would normally be if the printer does not print at all, and if you have determined values which work by using the PTEST program.

The next thing that happens is critical in terms of being able to muck around with the printer driver to make it work faster. The driver must wait a little while for the printer to become ready to accept another data byte. If the printer fails to become ready within this period, the service routine will exit and the process starts again with the next clock tick. Hence, if this process always failed to wait long enough for the printer to be ready for another data byte, TSX would only send 100 characters per second to the printer. To accomplish this task the driver computes a loop count as follows:

/*
 * Compute number of loops based on CPU speed
 */
        limit = (ppd_d3*nops100micro)/10;

The "ppd_d3" value here is controlled by the /LOOP3 gen parameter, whose default value is 20. An attempt is made to compensate for the speed of the CPU by taking "nops100micro" into account; this is the number of "NOOP" instructions which your CPU can execute in 100 microseconds. This value can be seen in the SYSMON "System Information" screen; it is reported as the CPU rating. If your printer is going very slow, it is possible that you can make it faster by increasing /LOOP3, but read on!

The printer driver now enters a tight loop, checking the printer status byte, hoping that soon the printer will declare it's ready for the next data byte. The maximum number of times the driver will check the status byte is the "limit" value computed as shown above.

This process is so critical that upon exit from the loop, the driver maintains statistics on the number of times it had to go through the loop; these statistics can be viewed in the SYSMON "LPT Printer Activity" screen. The right half of this screen, "Response speed (LOOP3)", displays these statistics. You can think of these values as counters of the total number of times the driver was able to exit the loop in 0-5 iterations, 6-10, and so forth (go look at the screen now). Actually, the iteration count is adjusted after loop exit, before the statistics are maintained, to try to take the CPU speed back into account, as follows:

    delayvalue = (delayvalue*10) / nops100micro;

If the result value is less than or equal to 5, this counts as an occurance of the printer becoming ready in 0-5 iterations through the loop. If the resulting delayvalue is 6 to 10, this counts as an occurance of the printer becoming ready in 6-10 iterations, and so forth.

What we want to see on this statistics screen is that the printer became ready a reasonable majority of the time in just a few executions of the delay loop. Of course, if the printer buffer is full and it's ejecting a page of paper, the loop count will be exhausted so it's not alarming to see some entries in the high ranges.

There are also counters for the total number of times that the printer did, within the specified delay period, become ready for another character, as opposed to the delay loop being completely exhausted forcing the driver to give up for the current clock tick. The value shown in SYSMON as "Printer ready in LOOP3" is the total number of times that the LOOP3 value was sufficient to continue printing, and the value shown as "Not ready for next chr" indicates the number of times that this failed.

If your printer is slow, you can probably make it faster by increasing the LOOP3 value, but you should first look in SYSMON and see if the "Not ready for next chr" value is very high, compared to a very low "Printer ready in LOOP3" value. The purpose of the statistics showing how many times various ranges of execution of the loop is to give you some feel for how much you should increase LOOP3 and a way to determine whether that has helped.

The downside of increasing the LOOP3 value very high would be that the system would become bogged when printing is active by having the printer driver wait an inordinate time before feeding another character to the printer. Since printers do occasionally need to do their job and have the operating system wait before feeding more data, setting LOOP3 very high would make TSX waste CPU resources waiting for the printer during these times.