!lm12
!rm75
Printer Handler with FIFO Buffer................Jim Kassel
[  Jim Kassel is a subscriber from St. Paul, Minnesota.  ]

Before I get on with technical discussions, first let me say that I have had a ball using S-C Assembler II Version 4.0.  It definitely has earned a place on the list of "The Greatest Things Since Sliced Bread."  My current version incorporates the block move and copy feature described in the December '80 and January '81 issues of AAL which have been a welcome enhancement.

Now...on with the article, about a super simple programming technique that I have used extensively.  I am a hardware logic designer by trade and before the introduction of First In-First Out (FIFO) memory chips, designers had to implement that function using an input address up-counter, an output address up-counter, and an up/down counter to determine character count.  Now that the FIFO chips are available, they are still a bit expensive for home computer use.  By using the old counter method implemented in software, not only is the FIFO free but also extrememly expandable in size (within the bounds of the computer memory, of course).

I am going to give a little background into the necessity, in my case, for using this technique.  I feel that the problem I experienced may be interesting reading to others who may have had similar occurrences.

I was writing an assembly language program that would allow my Apple II to become a terminal, using the Hayes Micromodem II and Epson MX-80 printer/Orange Micro Grappler interface card.

For the sake of versatility I would have preferred to perform operations like JSR $Cx00 (x = slot number) when transferring data with these devices.  However, it became apparent that I would have to bypass the firmware on the other interface cards.  This was especially true with the printer interface card.  Because the printer takes 1-2 seconds to print out a line of characters, the interface becomes unavailable for storage.  Since the modem wants to supply characters at a rate of up to 30 cps, at least that many characters were being "dropped on the floor" while the printer interface card kept program control.

I finally had to get the schematics and/or firmware disassemblies of the other interface cards.  From them I figured out the addresses of, and the methods of communications for, the various control, data, and (most important) status registers.  This allowed me to check for printer busy, modem transmit register not yet empty and modem receive register not yet full.  Now I could do other things when no data could be transferred.  No longer would I have to be a slave to the equipment that is used for support!

The only other problem, then, was to be able to save the print characters in a FIFO print buffer so they would not be forgotten while the printer was busy printing the previous line of characters.  In my version I allow a whole page of memory ($94) to be used for the buffer space.  As long as there is not a horribly long burst of received carriage returns (the slowest printer operation), 256 locations is more than adequate because the MX-80 prints at least twice as fast as the modem data rate.  Plus non-control characters are transferred into the printer line buffer much faster than incoming modem characters and the FIFO almost always stays empty because of this.

As characters arrive from the modem they are placed into the FIFO (by executing a JSR PRINT.FIFO.INPUT), then the input index (PBII) and the character counter (PBCC) are incremented.  Whenever the program is in a wait loop (keyboard entries, modem data transfers, etc.) there are no less than 33 milliseconds (300 baud/30 cps) to do non-critical operations.  This is more than enough time to execute a JSR PRINT.FIFO.OUTPUT.1 instruction during each "round trip" of the wait loops.  If the printer is busy, the program is returned to with no data transferred; if the printer is not busy, the program is returned to after the next FIFO output character is sent, the output index (PBOI) is incremented, and the character counter (PBCC) is decremented.  In any case, the program does not depend on the outcome of the subroutine results.  The subroutines maintain their independence by correctly updating and monitoring the character counter (PBCC).

In my version, I must append a line feed (<LF>) character to every carriage return (<CR>) that is sent.  I check every FIFO input character to see if it is a <CR>.  If so, I store a <LF> into the next FIFO input location.  Note that if I had decided to send the <LF> directly to the printer by monitoring for the <CR> in the FIFO output subroutine, I would again have been a slave to the printer while waiting for it to become unbusy with the <CR> operation.

By making PRINT.FIFO.OUTPUT.2 a separate subroutine, I could write it for any printer interface card with data and status registers and still not require any changes to subroutines PRINT.FIFO.INPUT and PRINT.FIFO.OUTPUT.1.  This provided some versatility for converting the program for some friends with different interfaces.
