dan@rna.UUCP (12/18/84)
Hi, As a DMA version of the LP-11, you could try the parallel output of a DMF-32. If you don't want an entire DMF-32, I believe ABLE makes just the parallel output function. I also recall other third party controller manufacturers that make DMA line printer interfaces. Try MDB or DATASYSTEMS (Wespercorp). Dan
kahrs@alice.UUCP (Mark Kahrs) (12/28/84)
OK all you informed people out there; does anyone know of a DMA unibus LP-11/Centronics board. The DEC M7258 card is PIO and we'd like to pump them bits out a bit (sic) faster. Thanks for any replies, Mark.
rpw3@redwood.UUCP (Rob Warnock) (12/29/84)
+--------------- | OK all you informed people out there; does anyone know of a DMA unibus | LP-11/Centronics board. The DEC M7258 card | is PIO and we'd like to pump them bits out a bit (sic) faster. | | Thanks for any replies, | Mark. +--------------- I am posting this instead of mailing, 'cause I think it's of general interest... Hey, folks! If you're talking about a line printer (and not some other strange thingy that you might be using a Centronics interface for), going to DMA will not buy you much (if anything!) compared to a properly coded PIO-style driver, since you still have to examine/touch/maybe-modify each character anyway (to handle tabs, control characters, underlining, auto-FF, etc., -- anything the printer doesn't handle for you). If your PIO-style driver is written properly (many aren't), it will be doing all of that stuff while the printer is taking the preceeding character, and the driver will LOOP at interrupt level as long as the printer continues to take chars at full speed. But the real key is not when you do the processing (sys-call level vs. interrupt level), but how many interrupts you take per line printed. With EITHER a DMA device or a properly written PIO driver, that number should be "one" (1) per line, NOT one per character. Most printers will gobble a whole line's worth of chars as fast as you can pump them, putting them into an internal buffer until it hits some kind of action character (line-feed, carriage-return, form feed, etc.). Then it will go away and not bother you for a whole line's worth of print time. Because of this, you DON'T want to dismiss the interrupt on each character, but on each LINE. The way you do this (without knowing or caring what the printer's actions chars are), is to BUSY WAIT (yes, you heard me) or POLL on the "ready" line from the printer just long enough to see if the printer is going to take another character from you during "this line". If the busy-wait loop expires (and for most printers we are talking a SMALL wait, say 5-20 microseconds -- MUCH less than dismissing the interrupt and coming back in), then and only then do you dismiss the interrupt. In fact, the per-character overhead of using the PIO interface is not much (if any) more than the overhead of filling the DMA buffer! May I suggest as an experiment (before spending money on extra hardware), that you re-write your driver AS IF you had a DMA interface (buffer and all), and code the interrupt handler to stuff the printer buffer in a tight loop as indicated above. I have gotten burst transfer rates on a VAX-11/780 of over 50Kbytes/sec for such drivers. (Hint: DON'T use the c-list stuff.) Sample code fragment for one way to do the busy-wait poll for a "soft-DMA" driver: lprint(){ /* ... here with buffer addr/count set up... */ while (count && ( (lpr->status & LPR_DONE) || (lpr->status & LPR_DONE) /* as many of these */ || (lpr->status & LPR_DONE) /* as it takes for */ || (lpr->status & LPR_DONE) /* your printer to */ || (lpr->status & LPR_DONE) /* eat one character*/ || (lpr->status & LPR_DONE) /* in burst mode, */ || (lpr->status & LPR_DONE) /* typically 10us. */ )){ lpr->data = *buf++; --count; } if (count == 0){ lpr->status &= ~LPR_ENABLE; /* no more data -- * turn off interrupt enable */ wakeup(&lpr); /* maybe the process has more */ } return; /* dismiss interrupt */ } That's not meant to be any great coding example... it's just off the top of my head. (It assumes you are NOT doing the formatting on the fly, which you should, albeit at process level and not at interrupt level.) You can also use a while (count && waitfordone()) where "waitfordone" is something like: waitfordone(){ for(i = LPR_MAGIC; i > 0; --i) /* LPR_MAGIC is typically 10 */ if(lpr->status & LPR_DONE) return 1; return 0; } But in most cases, the in-line code is faster, since the very first test often succeeds. If you're really skeptical about this approach, you can put some metering code in "waitfordone" to measure how many loops you take for each time you enter, but be warned that the measurement code will eat the majority of the overhead! The typical number of loops is zero, that is, the "done" flag is already true on entry (plus each "line" will cost one set of LPR_MAGIC loops when the printer goes "not ready"). Finally, if your current driver already employs all of these techniques, and you still aren't satisfied, I dare say a DMA controller isn't going to buy you anything. Good luck. Rob Warnock Systems Architecture Consultant UUCP: {ihnp4,ucbvax!dual}!fortune!redwood!rpw3 DDD: (415)572-2607 USPS: 510 Trinidad Lane, Foster City, CA 94404