 sttl NEC Printer Drivers
 pag

*
* NEC/Qume Parallel Printer
*
DEV_NEC
 fdb bad_cmd  0 -
 fdb necopn  1 -
 fdb neccls  2 -
 fdb nectys 3 -
 fdb nectyg 4 -
 fdb nreq_write  5 -
 fdb nwrite_data  6 -
 fdb nwrt_sc  7 -
 fdb bad_cmd  8 -
 fdb bad_cmd  9 -
 fdb bad_cmd 10 -
 fdb bad_cmd 11 -
 fdb bad_cmd 12 -
 fdb bad_cmd 13 -
 fdb bad_cmd 14 -
 fdb clock_on 15 -
 fdb nec_int
 fdb nec_init
 fdb nec_test

*
*   set up the interface and arm the interrupts
*
necopn
           pshs    cc
           seti
 jsr setuy initialize: U=data; Y=NECADR
           lda     necflg,u             get device status flag
           bita    #necnop
           beq     necdop              do the open processing
           ldb     #E_DEVBSY
           puls    cc,pc
*
*   do the open on the device
*
necdop     ora     #necnop            indicate device is open
           anda    #$7f            insure no I/O error
           sta     necflg,u             stuff into flag byte
           jsr     neclro              clear out all the buffer stuff
*
*   configure the I/O channel
*
           lda     #c_acr              set up a-side data register
           sta     cr_a,y              stuff into control register
           ldb     #c_bcr-c_ddr        select the direction register
           stb     cr_b,y              stuff into control register
           ldb     #!0                 then assign all lines as
           stb     d_msp,y             output lines on b side
           ldb     #c_bcr+c_irq        select b-side data registers
           stb     cr_b,y              by writing control register
 tst 0,y
 tst 1,y
*
*   set up initial values for the variables
*
           jsr     necclc             perform the nectys calculations
           clra                        set positions to zero now
           clrb
           std     carage,u            stuff into carage position slot
           std     nectrc,u             and also into nectrc position
           std     necfps,u            indicate we are at top of form
*
*   lift the ribbon and restore the printer
*
           lda     #c_acr+c_lift+c_irq       then lift ribbon
           sta     cr_a,y              by setting control register
           ldd     #s_rst*256+0            load a restore necstb
           jsr     necstb              send it off to the printer
           ldb #R_OPEN
           puls cc,pc
*
*   do form feed and place printer at left margin
*
neccls pshs b save device #
       bsr setuy initialize: U=data; Y=NECADR
* -- Wait for device to go idle
10 pshs cc,u,y
 seti
 tst necflg,u if I/O error - don't wait
 bmi 30f
 ldd oq_count+necinq,u
 beq 30f
 leay necinq,u
 ldb #TTYOPR
 jsr sleep
 puls cc,u,y
 bra 10b
30 puls cc,u,y
 puls a
 jsr int_all interrupt any associated tasks
           lda     necflg,u                  get the flag byte
           bita    #necnop                 see if device is open
           beq     necclx                  nope, don't need to close
           jsr     necvrt              issue a form feed
           lda     necflg,u              get status byte
           anda    #!necnop            indicate not open device
           sta     necflg,u
necclx     ldb #R_CLOSE
           rts
*
*  setuy - setup U and Y registers
*
setuy ldu NECstr point U register to variables
 ldy NECADR get I/O device address
 rts
*
*   write a buffer in either raw mode or other
*
necwrt bsr setuy initialize: U=data; Y=NECADR
           lda     necflg,u            pick up the tty flag bytes
           bita    #rawnec            check for doing raw-mode I/O
           beq     cooked (bne)             if not, enter cooked processing
*
*   process next raw mode necstb word
*
eatraw     jsr     necpass               get msp of necstb byte
           bmi     necdon                if no more, done with it
           pshs    b                   save byte on the stack
           jsr     necpass               get lsp of necstb byte
           puls    a                   get back msp from stack
           bmi     necdon                if no more, forget it
           jsr     necstb              send strobe off to necadr
           bsr     necbfc             check buffer status
           tst     necflg,u              check for I/O error
           bpl     eatraw
*
*   permanent I/O error while processing
*
necfio     ldb     #E_BADCMD ???       return failing status
neclro     clr     necbsy,u              clear out busy flag
           clr     necsct,u              zap the buffer count
           leax    necqbf,u             get the buffer address
           stx     necsfp,u              stuff fetch pointer
           stx     necssp,u              and also the store pointer
 ldd oq_buf+necinq,u
 std oq_get+necinq,u
 std oq_put+necinq,u
 ldd #0
 std oq_count+necinq,u
 pshs y
 jsr wakeup kick anybody waiting
 leay necinq,u
 jsr wakeup
 puls y,pc
*
*   process the next character from the user buffer
*
steamed    bsr     necdch              process the character
           bsr     necbfc             check for room in the queue
           tst     necflg,u              check for I/O error
           bmi     necfio              if so, terminate the write
cooked     jsr     necpass               get character from buffer
           bpl     steamed             if one exists, put on to cook
necdon     rts
*
* Get input character from queue
*
necpass pshs y,a
 leay necinq,u
 jsr get_oq fetch character
 bne 10f jump if none there
 clra return with data
 bra 90f
10 lda #$FF return - no more data
90 puls a,y,pc
*
*   check necstb buffer for room for more stuff
*
necbfw bsr setuy initialize: U=data; Y=NECADR
           ldb     #TTYOPR             load priority
           jsr     sleep               quiesce the process for now
           puls    cc
necbfc     pshs    cc
           seti                        disable interrupts
           lda     necsct,u              get the buffer count
           cmpa    #NECBSIZ/2-8         see if room left in buffer
           bhs     necbfw              nope, go wait some
           puls    cc,pc
*
*   process a character destined for the printer
*
necdch     cmpb    #sp                 check for a necspc character
           bhi     necdtt            if higher, active data character
           beq     necspc               if equal, space character
*
*   decode possible control characters
*
           cmpb    #cr                 check for carage necrtn
           beq     necrtn
           cmpb    #nl                 check for new line
           beq     necnlr
           cmpb    #vt                 check for vertical tab
           beq     necvrt
           cmpb    #bs                 check for necdbs
           beq    necdbs
           cmpb    #xo                 check for X-ON character
           lbeq    posit
           rts
*
*   data character - do positioning and print character
*
necdtt   andb    #%01111111          check for data bits
           lbsr     posit               issue the position necstb
           lslb                        shift character left one bit
           lda     #s_chr              indicate a character necstb
           jsr     necstb              issue a character print strobe
*
*   necspc character just advances horizontal position
*
necspc      ldd     necpos,u            pick up character position
           std     necold,u            store into previous position
           addb    pitch,u               add in the pitch value
           adca    #0                  add carry, if any, into msp
           std     necpos,u            store position into fcb
*
*   check to see if still on form width
*
           ldd     rtlimt,u            pick up rightmost limit
           beq     necexi                if zero, just exit here
           cmpd    necpos,u            compare to character position
           bhs     necexi                if higher, then exit
*
*   line has overflowed - see if we should issue necrtn, etc.
*
           std     necpos,u            reset to right limit
           lda     necflg,u            pick up tty flag byte
           bita    #neclof            test line overflow flag
           beq     necexi                if not, just exit here
*
*   carage necrtn function
*
necrtn     ldd     margin,u              get left margin offset
           std     necpos,u            stuff into carage position
           std     necold,u            also reset previous position
           lda     necflg,u            pick up the tty flag byte
           bita    #necnlo            check for new line option
           beq     necexi
*
*   new line function -- set vertical position offset
*
necnlr    ldb     depth,u               get character depth
           sex                         convert into a 16-bit word
           addd    necfps,u            add into vertical position
           std     necfps,u            stuff back into position
           cmpd    frmlen,u            compare against form length
           blo     necexi                if still on page, leave it
*
*   we are overflowing a page boundary, normalize things
*
           addd    normal,u              add in normalize constant
           std     necfps,u         stuff the form position
 bra necvr2
*
*   vertical tab function sets up new top of form
*
necvrt     ldd     necfps,u          get current form pos
           beq     necvrx          if at top of form, forget it
           ldd     frmlen,u          get form length word
           beq     necnlr         if zero, do a new line
           std     necfps,u         stuff the form position
 ldd margin,u reset margin, too
 std necpos,u set carriage position
 std necold,u set old position, too
necvr2     bsr     posit          issue the position strobe
           clra                        set position to zero
           clrb
           std     necfps,u            stuff into form position
           std     nectrc,u             and stuff into nectrc position
necexi
necvrx     rts
*
*   necdbs function backs up positon
*
necdbs  ldd     necold,u            pick up previous carage position
           std     necpos,u            stuff back into slot
           rts
*
*  negate - negate value in d register then 'and' with "back"
*
negate pshs d
 clra
 clrb
 subd 0,s++
 ora #back
 rts
*
*   posit function issues necstbs to position the carage
*
posit      pshs    a,b                 save data registers on stack
           ldd     necfps,u            pick up forms position
           subd    nectrc,u             compare to nectrc position
           beq     nechpz              if equal, just do horizontal position
           aslb                  multiply quantity by two
           rola
           bpl     necvpz              if positive, do vertical position
 bsr negate make motion downward direction
*
*   perform the vertical position
*
necvpz     ora     #s_pfd              indicate a paper feed necstb
           bsr     necstb              then strobe the printer
           ldd     necfps,u            stuff into file control block
           std     nectrc,u             as current nectrc position
*
*   position the carage
*
nechpz     ldd     necpos,u            get character position
           subd    carage,u            subtract from carage position
           beq     xposit              if zero, just necexi position
           bpl     necdpq             if positive, do the position
 bsr negate indicate leftwards motion
*
*   perform the carage position
*
necdpq    ora     #s_car              set carage motion necstb
           bsr     necstb              send position strobe
           ldd     necpos,u            get character position
           std     carage,u            and indicate new carage position
xposit     puls a,b,pc
*
*   place a necstb word into the strobe buffer
*
necstb     pshs    cc                  save condition flags
           seti
           ldx     necssp,u             get necstb place pointer
           std     0,x++               stuff into the buffer
           cmpx    necsnd,u              check for end of buffer
           bne     necppy             if not, just set pointer
           leax    necqbf,u          point back at the buffer
*
*   store the new output pointer and check for interrupts active
*
necppy    stx     necssp,u             stuff back the pointer
           inc     necsct,u              increment the necstb count
 tst necbsy,u
 bne necsx1
           bsr     neccup              simulate a necadr interrupt
necsx1    puls cc,pc     cc
*
*   take an interrupt from the printer interface
*
neccup lbsr setuy initialize: U=data; Y=NECADR
           clr     necbsy,u              indicate no interrupt pending
           tst     d_lsp,y             clear any pending interrupt
           tst     necsct,u              test the necstb count
           beq     nechco              if zero, no more necstb words
*
*   get the next necstb word from the strobe queue
*
           ldx     necsfp,u             get the necstb input pointer
           ldd     0,x++               pick up the necstb word
           cmpx    necsnd,u              see if at end of buffer
           bne     necpfp             if not, go set pointer
           leax    necqbf,u          point at top of buffer
necpfp     stx     necsfp,u             stuff back into pointer slot
           bsr     nectag              tag the device
           inc     necbsy,u              indicate pending interrupt
*
*   fixemup necstb counts, etc
*
           lda     necsct,u              pick up the necstb count
           deca                        decrement it by one
           sta     necsct,u              stuff back into count field
           beq     nechco              if empty, wakeup
           cmpa    #26                 check for approx 26 necstbs
           bne     nechx1               which is 200 mSec, approx.
nechco     jsr     wakeup              wake up on the necadr
nechx1     rts
*
*   check interrupt processing
*
necafu lbsr setuy initialize: U=data; Y=NECADR
           tst     d_msp,y             clear the interrupt
           clr     necbsy,u
           clr     necsct,u              clear out strobe buffer
           lda     necflg,u              fix up flag bits
           ora     #necioe
           anda    #!necnop            indicate device not open
           sta     necflg,u
*
*   hard issue a restore to the device
*
           ldd     #s_rst*256
           bsr     nectag              send strobe to device
           lda     #c_acr              quiesce the interface
           sta     cr_a,y
           jsr     wakeup             in case task sleeping
           rts
*
*   issue the necstb to the printer
*
nectag     sta     d_msp,y             stuff the data stobe word
           stb     d_lsp,y
           lda     #c_bcr-c_stb        load control necstb
           sta     cr_b,y
           lda     #c_bcr+c_irq        bring necstb high and arm IRQ
           sta     cr_b,y
           rts
*
*   nectys and nectyg processing
*
nectys lbsr setuy initialize: U=data; Y=NECADR
*
*   before altering nectys table, perform limit check on parameters
*
 leax necarg0,u
 lda #6
10 lbsr FIFO_get
 stb ,x+
 deca
 bne 10b
           ldd     necarg1,u
           cmpa    #6                  check lower pitch limit
           blo     necoop
           cmpa    #24                 check upper pitch limit
           bhi     necoop
           cmpb    #4                  check lower depth limit
           blo     necoop
           cmpb    #32                 check upper depth limit
           bhi     necoop
           std     necflg+2,u
*
*   copy rest of nectys parameters into local table
*
           ldd     necarg0,u              get first two bytes
           std     necflg,u
           ldd     necarg2,u              get last user argument
           std     necflg+4,u
*
*   perform calculations on nectys parameters
*
necclc    lda     necfrm,u             pick up the form length
           ldb     #4                  set scale offset value
           mul                         calculate form length, in units
           std     frmlen,u
           lda     neclef,u             pick up the left margin offset
           ldb     #10                 set the units scale value
           mul                         calculate offset, in horiz units
           std     margin,u
           std     necpos,u            provide for a fixed left margin
           std     necold,u
*
*   calculate maximum width parameter
*
           lda     necwid,u            pick up the form width
           ldb     #10                 set scale offset value
           mul                         calculate width, in units
           beq     necstp              if zero, just set the width
           addd    margin,u              add in the left margin value
necstp     std     rtlimt,u
*
*   calculate pitch info from nectys parms
*
           ldd     #120*256+$FF            set up initial pitch constants
necpdv     incb                        increment pitch constant
           suba    necpch,u            subtract off the pitch limit
           bcc     necpdv              loop until divided
           stb     pitch,u               stuff the pitch value
*
*   calculate depth info from nectys parms
*
           ldd     #48*256+$FF             set up initial depth constants
necddv     incb                        increment the quotient value
           suba    necdep,u            subtract out the divisor
           bcc     necddv              loop until divided out
           stb     depth,u               stuff back into depth slot
*
*   calculate form normalization constant
*
           clra                        make depth double precision
           pshs    d                   save depth value on the stack
           ldd     frmlen,u            pick up the form length
necsnm    subd    0,s                 subtract off the depth value
           bcc     necsnm             loop back if not cleared
           addd    0,s++               add back to get normalizer value
           std     normal,u              stuff into form normalizer
           ldb #R_TTY normal return
           rts
*
*   oops, some value is out of range
*
necoop    ldb     #E_BADCMD           set an error indicating out of range
           rts
*
*   for nectyg command, necrtn the information
*
nectyg     lbsr    setuy
 leax necflg,u
 lda #6
10 ldb ,x+
 lbsr FIFO_put
 deca
 bne 10b
 ldb #R_TTY
 rts
 pag

*
* nreq_write - Request permission to write data
*
nreq_write jsr setuy set up registers
 pshs cc mask interrupts while fiddling
10 seti
 tst necflg,u is the device in error?
 bmi 30f yes - get it back to UniFLEX
 ldd oq_count+necinq,u get queue length
 beq 20f only continue when empty
 pshs d,x,y,u no - save registers
 leay necinq,u
 ldb #TTYSPR
 jsr sleep
 puls d,x,y,u restore registers
 bra 10b try again
20 ldb #R_REQOK request granted code
 bra 99f
30 ldb #E_IOERR device is all screwed up...
99 puls cc,pc return

*
* nwrite_data - Write data to a printer
*
nwrite_data
 jsr setuy get printer control table pointer
 pshs y save device address
10 lda fifo_cnt any data left in FIFO?
 beq 20f no - get output started
 jsr FIFO_get go fetch character
 leay necinq,u point to input queue
 jsr put_oq put character into queue
 bra 10b
20 ldb #R_WRITE set response
 jsr fio_response
 puls y restore device address
 jsr necwrt go start getting data
 leay necinq,u wake up anybody waiting on input queue
 jsr wakeup
 leas 2,s -- abnormal (although it really is OK) return
 rts

*
* Write single character
*  -- Character passed via transaction message
*
nwrt_sc pshs cc save interrupt state
 seti
00 jsr setuy compute printer table address
 tst necflg,u device OK?
 bpl 05f
 ldb #E_IOERR no - return error code to UniFLEX
 puls cc,pc
05 ldd oq_count+necinq,u check for overrun
 beq 10f jump if OK
 leay necinq,u
 ldb #TTYOPR wait a while
 jsr sleep
 bra 00b try again
10 ldx utask fetch character
 ldb tstval,x
 pshs y
 leay necinq,u
 jsr put_oq
 puls y
 ldb #R_WRITE
 jsr fio_response
 jsr necwrt send to output queue
 puls cc
 leas 2,s clean off stack
 rts

*
* Initialize NEC device
*   B - Device number
*   X - Device address
*
nec_init pshs d,x,u,y
 lbsr setuy get control structure
 stx NECADR
* -- Initialize Control structure
 ldy NEC_IQ
 sty oq_buf+necinq,u
 sty oq_get+necinq,u
 sty oq_put+necinq,u
 ldd OBUF_SIZE
 leay d,y
 sty oq_end+necinq,u
 leay necqbf,u
 sty necssp,u
 sty necsfp,u
 leay necqnd,u
 sty necsnd,u
 lda #6
 sta neclef,u
 lda #10
 sta necpch,u
 lda #6
 sta necdep,u
 lda #132
 sta necfrm,u
 lda #168
 sta necwid,u
 lda #12
 sta pitch,u
 lda #8
 sta depth,u
 ldd #48
 std margin,u
 ldd #528
 std frmlen,u
 ldd #0
 std normal,u
 ldd #1686
 std rtlimt,u
 lda #necnlo|neclof
 sta necflg,u
 lda #$2e set up pia
 sta 2,x
 sta 3,x
 pshs d delay
 puls d
 lda 0,x
 lda 1,x
 pshs d
 puls d
 tst 2,x
 tst 3,x
 puls d,x,y,u,pc

*
* Decide if a device is an NEC
*   D - Device address
*   Y - Device table
*   CS - Device is not NEC
*
nec_test pshs d,x,u
 tfr d,u
 lda #$2E set up pia
 sta 2,u
 sta 3,u -- check both sides
 pshs d delay
 puls d
 lda 2,u must come back the same
 anda #$3F
 cmpa #$2E
 bne 10f not NEC
 lda 3,u
 anda #$3F
 cmpa #$2E
 bne 10f
 lda NUM_NEC compute device table address
 adda #MAX_TTY+MAX_PPR
 ldb #DEV_SIZE
 mul
 ldy #dev_tab
 leay d,y
 tfr u,d set up device table
 std dev_addr,y
 ldx #DEV_NEC
 stx dev_type,y
 inc NUM_NEC adjust device count
 sec
 bra 99f
*
10 clc
99 puls d,x,u,pc

*
* NEC printer interrupt routine
*  D - Device #
*  X - Device address
*  Return CS if interrupt processed
*

 if DBG_TRMI&DEBUG_CONTROL
00 fcc $d,'NEC Int, Status: ',0
 endif
nec_int pshs d,x,y,u save registers
 lda 2,x get status register
 ldb 3,x
 ldy #neccup assume normal interrupt
 bita #%10000000 any interrupt?
 bne 01f
 ldy #necafu error interrupt
 bitb #%10000000
 beq 80f no - get out
01
 if DBG_TRMI&DEBUG_CONTROL
 pshs d,x
 jsr DB_msg
 fdb DBG_TRMI,05f
 ldx #00b
 jsr DB_pdata
 ldd 0,s
 jsr DB_phex2
05 puls d,x restore registers
 endif
 ldd 0,s restore device #
 jsr 0,y go process interrupt
 bra 90f
80 clc return - no interrupt here
 bra 99f
90 sec return - interrupt processed
99 puls d,x,y,u,pc
