;*************************** AMUS Program Label ******************************
; Filename: OK393.M68                                       Date: 10/16/89
; Category: PDV          Hash Code: 054-012-117-566      Version: 1.0(204)
; Initials: AMI/AM       Name: AMI BAR-YADIN
; Company:                                         Telephone #:
; Related Files: OK393.DOC, OKI400.M68, OPST01.M68, OSCT01.M68
; Min. Op. Sys.:                               Expertise Level: INT
; Special:
; Description: AlphaWRITE printer driver for Oki393 printer. See OK393.DOC
; for more details.
;
;*****************************************************************************
;* Updated on 15-Sep-89 at 2:39 PM by Ami Bar-Yadin; edit time: 15:52:55 *;
if ne,0
                      Printer Driver for Okidata 393
                             By Ami Bar-Yadin
                               AMUS: AMI/AM

   This driver was developed by using AM301.M68 as the starting point.

Support tables:
       OKI400.M68 -- "messages" table (ie "colors" -> "justify")
               assemble as WRT:MSG400.USA
       OPST01.M68 -- proportional width table
               assemble as WRT:DPST01.USA
       OSCT01.M68 -- special chracters table
               assemble as WRT:NSCT01.USA

               (WRT: is DSK0:[7,12])
endc

       VMAJOR=1.
       VMINOR=0.
       VEDIT=204.

;***************************************************************************
;*                                                                         *
;*  To enable special print features use the following AlphaWrite keys:    *
;*                                                                         *
;*      Function        Key Sequence    Notes                              *
;*      --------        ------------    -----                              *
;*                                                                         *
;*      The following are accessed using standard AlphaWRITE commands      *
;*                                                                         *
;*      Lines per inch          |                                          *
;*      Chars per inch          |                                          *
;*      Proportional Chars      |                                          *
;*                      MARGIN          MARGIN menu (also document header) *
;*      Underline       UNDERLINE                                          *
;*                                                                         *
;*      The following are accessed using AlphaWRITE FONT command           *
;*                                                                         *
;*      Bold            FONT 1          standard command                   *
;*      Subscripts      FONT C          toggle on/off                      *
;*      Superscripts    FONT D          toggle on/off                      *
;*      Normal chars    FONT 6 0        | custom commands                  *
;*      Italics         FONT 6 1        |                                  *
;*      Graphics        FONT 6 2        |                                  *
;*                                                                         *
;*      The justification modes are accessed via the "colors" selection    *
;*      (if OKI400.M68 is assembled into MSG400.USA, proper prompts will   *
;*      be displayed.)                                                     *
;*                                                                         *
;*      For Justify Right and Full the right margin of the Oki393          *
;*      MUST be set using "/OUT 27,81,n" where n is the actual right margin*
;*      including left paper offset (if not 0).                            *
;*      Unfortunatly, I have not discovered any way for the PDV to access  *
;*      The current right margin directly.                                 *
;*                                                                         *
;*      Justify Off     FONT A 1                                           *
;*      Justify Left    FONT A 2        in practice, same as off           *
;*      Justify Center  FONT A 3                                           *
;*      Justify Right   FONT A 4                                           *
;*      Justify Full    FONT A 5        gives even left and right margins  *
;*                                                                         *
;*      The following are toggles (on/off) for misc. things                *
;*                                                                         *
;*      Utility mode    FONT A 6        for rough drafts (faster than LQ)  *
;*      Debug mode      FONT A 7        (does nothing at the moment)       *
;*      Control Shift   FONT A 8        chracters "@".."_" to control chars*
;*                                                                         *
;***************************************************************************
;
       SEARCH  SYS
       SEARCH  SYSSYM
       COPY    PDVSYM

; define SSFLAG flag bits
SS$SUB = 1              ; subscripts
SS%SUB = 0
SS$SUP = 2              ; superscripts
SS%SUP = 1

; define 2nd flags byte OK.FLG (in user's section of PDV's impure area)
OK$GRP = 1              ; graphic font enabled
OK%GRP = 0
OK$CTL = 2              ; control char
OK%CTL = 1              ;  (shifts '@'..'_' characters 64 down)
OK$UTL = 4              ; utility (draft) mode on (else LQ mode is on)
OK%UTL = 2
OK$DBG = 8.             ; debug mode (does nothing for now)
OK%DBG = 3
OK$JST = 16.            ; justication mode changed in middle of current line
OK%JST = 4              ; and needs update at start of next line.

; define user's section of PDV impure area (RESVUS,50.)
       .OFINI  RESVUS
       .OFDEF  JUSTFY,1        ; justify mode 0..4=off,left,center,right,full
       .OFDEF  OK.FLG,1        ; another 8 bit flags
       .OFDEF  OKFONT,2        ; number of Oki393 font currently selected
       .OFDEF  LPIVMI,2        ; VMI set by last LPI
       .OFDEF  CPIHMI,2        ; HMI set by last CPI
       .OFDEF  ADJHMI,2        ; Horizontal Adjustement needed for HMI
       .OFSIZ  OKIMP

       OBJNAM  .PDV

;Edit History:
;[204]  06-Apr-89 /aby
;       The Oki393 seems to only accept jutification mode changes at the
;       begining of a line.  The driver will therefore keep track of the
;       justification mode and update it at the next line if needed.
;[203]  01-Apr-89 /aby
;       added LQ/utility mode and debug on/off toggles as colors 6 and 7.
;       (debug is a NO-OP for now.)
;       added Control Shift toggle as color 8.
;[202]  28-Mar-89 /aby
;       hardware sub/superscripts toggles as user 2 and 3.
;         uses SSFLAG 1st byte as flags byte.
;         Toggle is trapped at PDCTL.
;       hardware justification (off,left,center,right,full)
;         as color selections 1-5 (6-8 disabled).
;         right margin MUST be set using /OUT 27,81,n
;[201] 16 March 1989 /aby
;       general cleanup
;       cleaned up PDINI, PDCLS, PDMLPO, PDMAHT, PDCHR, PDECHR
;       seperated init and close string, close string clears LQ mode
;       removed special effects routines since Oki393 does it all in hardware
;       support for fonts 0,1,2,3=normal,italics,graphic I,graphic II
;       implemented new flag to support graphic fonts
;               PDCHR will add 128 to all characters
;               while either graphics font is selected (OK%GRP bit set)
;[200] 23 August 1988 /aby
;       copied from AM301.M68 (edit level [101])
;

;************************
;*      PDV entry       *
;************************
;  A3 indexes the impure area defined above on entry to the driver.
;
;  see    MAC:PDVSYM.M68    for AlphaWRITE printer driver impure layout
;
;
;
PDV:    PHDR    -1,0,PH$REE!PH$REU
       LWORD   PD$VAR!PD$PRO           ; proportional, variable
       JMP     PDINI                   ; PDINI,  initialize printer
       JMP     PDCLS                   ; PDCLS,  shut down printer
       JMP     PDCHR                   ; PDCHR,  output a character in D1
       JMP     PDCTL                   ; PDCTL,  output control string indexed by D1
       JMP     PDSPL                   ; PDSPL,  output special string & character
       JMP     PDMNLN                  ; PDMNLN, move to next line & start new line
       JMP     PDMTOF                  ; PDMTOF, move to Top of Form & setup for new page
       JMP     PDPSON                  ; PDPSON, enable proportional
       JMP     PDPSOF                  ; PDPSOF, disable proportional
       JMP     PDUNDR                  ; PDUNDR, toggle underscore
       JMP     PDBOLD                  ; PDBOLD, toggle bold
       JMP     PDSTRK                  ; PDSTRK, toggle strikeout
       JMP     PDBAR                   ; PDBAR,  toggle over-bar
       JMP     PDSLPI                  ; PDSLPI, set Lines Per Inch
       JMP     PDSHMI                  ; PDSHMI, set Horizontal Motion Index
       JMP     PDSCPI                  ; PDSCPI, set Characters Per Inch
       JMP     PDSTM                   ; PDSTM,  set Top Margin
       JMP     PDMTM                   ; PDMTM,  move to Top Margin
       JMP     PDSLPO                  ; PDSLPO, set Left Paper Offset
       JMP     PDMLPO                  ; PDMLPO, move to Left Paper Offset
       JMP     PDSLPP                  ; PDSLPP, set Lines per Page
       JMP     PDSLSP                  ; PDSLSP, set line spacing (in 1/2 lines)
       JMP     PDOVRP                  ; PDOVRP, setup to overprint last char.
       JMP     PDLF                    ; PDLF,   output LFs per count in D2
       JMP     PDDBL                   ; PDDBL,  toggle double underscore flag
       JMP     PDFONT                  ; PDFONT, select font # in D1
       JMP     PDECHR                  ; PDECHR, output Extended Characters
       JMP     IGNORE                  ;   ENTRY RESERVED FOR ALPHA MICRO
       JMP     IGNORE                  ;   ENTRY RESERVED FOR ALPHA MICRO
       JMP     IGNORE                  ;   ENTRY RESERVED FOR ALPHA MICRO
       JMP     IGNORE                  ;   ENTRY RESERVED FOR ALPHA MICRO
       JMP     IGNORE                  ;   ENTRY RESERVED FOR ALPHA MICRO
       JMP     IGNORE                  ;   ENTRY RESERVED FOR USER DEFINITION
       JMP     IGNORE                  ;   ENTRY RESERVED FOR USER DEFINITION
       JMP     IGNORE                  ;   ENTRY RESERVED FOR USER DEFINITION
       JMP     IGNORE                  ;   ENTRY RESERVED FOR USER DEFINITION
       JMP     IGNORE                  ;   ENTRY RESERVED FOR USER DEFINITION
       JMP     IGNORE                  ;   ENTRY RESERVED FOR USER DEFINITION
       JMP     IGNORE                  ;   ENTRY RESERVED FOR USER DEFINITION
       JMP     IGNORE                  ;   ENTRY RESERVED FOR USER DEFINITION

PAGE
;************************
;*      PDSPL           *
;************************
; Output a control string & then the byte in D2
;  String number is in D1.
;
PDSPL:  CMPB    D1,#1                   ; ABS HORIZ TAB?
       JEQ     PDMAHT                  ; Execute special conversion
       BCALL   PDCTL                   ; output the string
       MOVB    D2,D1
       JMP     CHROUT

PAGE
;************************
;*      PDCTL           *
;************************
; Output a control string.
;  String index is in D1
;
; Strings 18 and 19 (user 2 and 3) are trapped and dispatched
; to sub/superscript toggles.
;
; Strings 7-10,21-24 (colors) are trapped and dispatched to
; justify toggles.
;

PDCTL:  CMPB    D1,#MAXCDE              ; valid special code ?
       BHIS    99$                     ;   no, ignore it
       ADDW    D1,D1                   ; make index into word offset
       MOVW    CTLTBL[~D1],D1          ; get string offset
       BMI     10$                     ; execute code?
       LEA     A6,CTLTBL[~D1]          ; no, compute string address
       JMP     STROUT                  ; and output string

10$:    BCLR    #15.,D1                 ; clear the high bit
       LEA     A6,CTLTBL[~D1]          ; compute code address
       JMP     @A6                     ; execute routine

99$:    RTN

; Printer control string table
; CAUTION: Do Not Change the order of the string table.
;          If the string is not implemented put a length of zero at the label.
;
DEFINE STRING  TAG
       WORD    TAG-CTLTBL
ENDM

DEFINE EXCODE  TAG
       WORD    TAG-CTLTBL!^H8000
ENDM

CTLTBL: STRING  CHOME                   ; 00 return carriage home
       STRING  MOVAHT                  ; 01 move to absolute horizontal tab
       STRING  ROLUP                   ; 02 roll up a partial line
       STRING  ROLDWN                  ; 03 roll down a partial line
       STRING  NEGLF                   ; 04 output negative line feed
       STRING  SPLPT0                  ; 05 special print position 0
       STRING  SPLPT1                  ; 06 special print position 1
       EXCODE  JUSTLF                  ; 07 justify left
       EXCODE  JUSTCN                  ; 08 justify center
       EXCODE  JUSTRT                  ; 09 justify right
       EXCODE  JUSTOF                  ; 10 justify off
       STRING  FEDTR1                  ; 11 select Feeder tray 1
       STRING  FEDTR2                  ; 12 select Feeder tray 2
       STRING  FEDTR3                  ; 13 select Feeder tray 3
       STRING  FEDTR4                  ; 14 select Feeder tray 4
       STRING  FEDTGL                  ; 15 select Feeder tray 1 & then tray 2
       STRING  FEDEJT                  ; 16 select Feeder eject
       STRING  NULL                    ; 17 user function 1
       EXCODE  PDSUBT                  ; 18 subscript toggle
       EXCODE  PDSUPT                  ; 19 superscript toggle
       STRING  NULL                    ; 20 user function 4
       EXCODE  JUSTFL                  ; 21 justify full
       EXCODE  LQUTLT                  ; 22 Utility mode toggle
       EXCODE  DEBUGT                  ; 23 DEBUG mode toggle
       EXCODE  CTLSFT                  ; 24 Control shift toggle
TBLEND:                                 ; end of table

MAXCDE  =       <<TBLEND-CTLTBL>/2.>    ; maximum special code

PAGE
;************************
;*      PDCHR           *
;************************
; Output the character in D1 with special effects
;  [201] All special effects are done automatically by the hardware.
;        However, we need to add 128 to all chars to support graphics font
;
PDCHR:  BTST    #OK%CTL,OK.FLG(A3)      ; Control shift active?
       BEQ     10$                     ; no
       CMPB    D1,#'@                  ; Check range
       BLO     10$
       CMPB    D1,#'_
       BHI     10$
       SUBB    #64.,D1                 ; make it a control character
10$:    BTST    #OK%GRP,OK.FLG(A3)      ; graphics font selected?
       BEQ     20$                     ; no
       ORB     #^H80,D1                ; set hi bit (add 128)
20$:
OUTCHR: CALL    CHROUT
       INCW    CURCOL(A3)              ; increment column counter
       TSTW    ADJHMI(A3)              ; Horizontal movement adjustment?
       BEQ     10$                     ; no, none needed
       TSTB    JUSTFY(A3)              ; justify mode on?
       BNE     10$                     ; yes, no adjustments
       BTST    #FM%PRO,FM.FLG(A3)      ; Proportional spacing?
       BEQ     5$                      ; no, go ahead and adjust
       CMPB    D1,#$SPC                ; in proportional, adjust only
       BNE     10$                     ; the SPACE character
5$:     CALL    ADJHRZ                  ; adjust horizontal position
10$:    RTN

CHROUT: FILOTB  PTDDB(A3)               ; output the character
IGNORE: RTN                             ; just return to caller of .PDV

FINADJ: BYTE    2,$ESC,'\       ; fine farriage adjustment
       EVEN

ADJHRZ: PUSH    D1
       LEA     A6,FINADJ
       CALL    STROUT
       MOVW    ADJHMI(A3),D6           ; get adjustment 1/120"
       MOVW    D6,D7
       ASRW    D7,#1                   ; divide D7 by two
       ADDW    D7,D6
       MOVB    D6,D1                   ; get low
       RORW    D6,#8.                  ; get high (swap bytes)
       PUSHB   D6                      ; save high
; TELTYP.TDV expands the TAB chracter (ASCII 9) to spaces
; therefor the following code traps a 9 and converts to a 1+8
; in both the high and low bytes.
       CMPB    D6,#9.                  ; high=tab, adjust
       BNE     10$
       PUSHB   D1                      ; save low
       CLRB    D1
       CALL    CHROUT
       INC     D1
       CALL    CHROUT                  ; output $100
       LEA     A6,FINADJ               ; re-introduce
       CALL    STROUT
       POPB    D1
       DEC     @SP                     ; adjust high
10$:    CMPB    D1,#9.                  ; low=tab, adjust
       BNE     20$
       MOVB    #1,D1
       CALL    CHROUT
       CLR     D1
       CALL    CHROUT                  ; output $1
       LEA     A6,FINADJ               ; re-introduce
       CALL    STROUT
       MOVB    #8.,D1
20$:    CALL    CHROUT                  ; output low
       POPB    D1                      ; get high
       CALL    CHROUT                  ; output high
       TSTW    ADJHMI(A3)              ; negative adjustment?
       BMI     90$                     ; yes, no underscore fix needed
; if forward adjustement, underscore will be broken up
; if underscoring, backspace and print another underline character
; to maintain a continous underline
       BTST    #FM%UND,FM.FLG(A3)      ; test underscore                       [101]
       BEQ     90$
       MOVB    #$BS,D1                 ; if underlining,
       CALL    CHROUT                  ; backspace and
       MOVB    #'_,D1                  ; underline again
       CALL    CHROUT
90$:    POP     D1
       RTN



;************************
;*      PDECHR          *
;************************
; Output the character in D1 (EXTENDED CHARACTER)
; Special characters are printed from Oki393's IBM II graphics font
;
PDECHR: BSET    #7.,D1                  ; set hi bit
       CMPW    OKFONT(A3),#3.          ; correct font active?
       BNE     10$                     ; no, got to save/switch/restore
       JMP     OUTCHR                  ; yes, just output char
10$:
       PUSHW   OKFONT(A3)              ; save current font
       PUSHB   D1                      ; save character
       MOVB    #3.,D1
       CALL    PDFONT                  ; select font #3
       POPB    D1                      ; restore character
       CALL    OUTCHR                  ; output character
       POPW    D1                      ; get current active font
       JMP     PDFONT                  ; restore active font


;************************
;*      STROUT          *
;************************
; Output string indexed by A6 to DDB indexed by A3
;
STROUT: SAVE    A0,D1,D2                ; save registers
       MOV     A6,A0
       CLR     D2
       MOVB    (A0)+,D2                ; get string length
       BEQ     99$
       DEC     D2                      ; for DBx
10$:    MOVB    (A0)+,D1                ; get byte from string
       FILOTB  PTDDB(A3)               ; output it
       DBF     D2,10$                  ; loop until all characters output
99$:    REST    A0,D1,D2                ; restore registers
       RTN

PAGE
;************************
;*      PDINI           *
;************************
; Initialize the printer
;
PDINI:  MOVW    #-1,HMISAV(A3)          ; no HMI yet
       MOVW    #-1,LPISAV(A3)          ; no LPI yet
       MOVW    #-1,CPISAV(A3)          ; no CPI yet
       MOVW    #-1,TPMSAV(A3)          ; no top margin yet
       MOVW    #-1,LPOSAV(A3)          ; no left paper offset yet
       CLRB    FM.FLG(A3)              ; Clear flags
       CLRB    OK.FLG(A3)              ; Clear flags extension byte
       CLRW    CURCOL(A3)              ; at column 0
       CLR     CURLIN(A3)              ; at line 0
       CLRB    JUSTFY(A3)              ; Clear justify mode
       CLRW    OKFONT(A3)              ; Start with normal font
       CLRW    LPIVMI(A3)
       CLRW    CPIHMI(A3)
       CLRW    ADJHMI(A3)
       LEA     A6,PRTINI               ; index the initialization string
       CALL    STROUT
       LEA     A6,BLDOFF               ; bold off
       JMP     STROUT

; Printer initialization [200]
; return to home position, reset, LQ mode ON
PRTINI: BYTE    6,$CR,$ESC,'@,$ESC,'x,1
       EVEN

;************************
;*      PDCLS           *
;************************
; Shut down the printer
;
PDCLS:  LEA     A6,PRTCLS               ; index the shutdown string             [101]
       CALL    STROUT
       LEA     A6,BLDOFF               ; bold off
       JMP     STROUT

; Printer shutdown [200]
; return to home position, reset, LQ mode OFF
PRTCLS: BYTE    6,$CR,$ESC,'@,$ESC,'x,0
       EVEN

PAGE
;************************
;*      PDSTM           *
;************************
; Set Top Margin.
;  D2 contains the number of lines required in Top Margin
;
PDSTM:  CMPW    D2,TPMSAV(A3)           ; new top margin the same as old ?
       BEQ     99$                     ;   yes, just return
       MOVW    D2,TPMSAV(A3)           ; save new value
99$:    RTN

;************************
;*      PDMTM           *
;************************
; Move to Top Margin
;
PDMTM:  PUSH    D2
       MOVW    TPMSAV(A3),D2           ; get number of lines in top margin
       BEQ     99$                     ;   and do nothing if zero
       CALL    PDLF                    ; output lines in top margin
99$:    POP     D2
       RTN

;************************
;*      PDLF            *
;************************
; Output Line feeds per count in D2
;
PDLF:   AND     #^H7F,D2                ; not more than 127
       CMPB    D2,#1                   ; check
       BLO     90$                     ;    for zero - exit
       BHI     10$                     ;    for many - output string
       ADD     #2,CURLIN(A3)
       MOVB    #$LF,D1                 ; for one  - output LF
       BR      20$
10$:    LEA     A6,LNFEED               ; many line feeds
       CALL    STROUT
       ADD     D2,CURLIN(A3)
       ADD     D2,CURLIN(A3)
       MOVB    D2,D1
20$:    CALL    CHROUT

90$:    RTN

LNFEED: BYTE    3,$ESC,'f,1     ; line feeds x times
       EVEN

;************************
;*      PDSLPO          *
;************************
; Set Left Paper Offset
;  D2 contains the number of spaces to move over
;
PDSLPO: CMPW
       D2,LPOSAV(A3)           ; new lpo same as old ?
       JEQ     99$                     ;   yes, just return
       MOVW    D2,LPOSAV(A3)           ;  and save it
       LEA     A6,LFTMRG
       CALL    STROUT
       MOVB    D2,D1
       JMP     CHROUT

99$:    RTN

LFTMRG: BYTE    2,$ESC,'l       ; set left margin n
       EVEN

;************************
;*      PDMLPO          *
;************************
; Move to Left Paper Offset (margin)
;
PDMLPO:
;       TSTB    JUSTFY(A3)              ; if justify on
;       BNE     99$                     ;   exit
       MOVB    #$CR,D1
       JMP     CHROUT
99$:    RTN

PAGE
;************************
;*      PDSLPP          *
;************************
; Set lines per page
;  D2 contains the form length in number of lines
;
PDSLPP: CMPW    D2,LPPSAV(A3)           ; new lpp same as old ?
       JEQ     99$                     ;   yes
       MOVW    D2,LPPSAV(A3)           ; save for later
99$:    RTN

PAGE
;************************
;*      PDSLSP          *
;************************
; Set line spacing
;  D2 contains the number of 1/2 lines
;
PDSLSP: MOVW    D2,LSPSAV(A3)           ; save for later
       RTN

PAGE
;************************
;*      PDMTOF          *
;************************
; Move to Top of Form and setup for new page
;
PDMTOF: CMP     CURLIN(A3),#1           ; on first line
       BLOS    10$                     ; if current line <= 1
       CLR     D7
       MOVW    LPPSAV(A3),D7           ; get lines per page
       ADD     D7,D7                   ; convert to number of 1/2 lines
       CMP     D7,CURLIN(A3)           ; are we already at new page ?
       BEQ     10$                     ;   yes, don't output a Form Feed
       PUSHB   D1                      ; save register
       MOVB    #$FF,D1
       FILOTB  PTDDB(A3)               ; output a Form Feed
       POPB    D1                      ; restore register
10$:    CLR     CURLIN(A3)              ; at start of page
       RTN

PAGE
;************************
;*      PDMNLN          *
;************************
; Move to Next Line and setup for new line
;
PDMNLN:
       SAVE    D1,D2
       MOVB    #$CR,D1
       FILOTB  PTDDB(A3)               ; output the carriage return
       CLRW    CURCOL(A3)              ; clear the current cursor column
       BTST    #OK%JST,OK.FLG(A3)      ; need to update justify mode?
       BEQ     10$
       MOVB    JUSTFY(A3),D1           ; get justification mode active
       BEQ     5$                      ; if zero leave as is
       DEC     D1                      ; else subtract one (see SETJUS)
5$:     CALL    OKIJUS                  ; send mode change to printer
       BCLR    #OK%JST,OK.FLG(A3)      ; clear justification pending flag
10$:    MOVW    LSPSAV(A3),D2           ; get current line spacing
       LSR     D2,#1                   ; convert to number of whole LFs
       SSTS    -(SP)                   ; save shift status
       CALL    PDLF                    ; output line feeds
       LCC     (SP)+                   ; get shift status back
       BCC     90$                     ;   and exit if no carry
       INC     CURLIN(A3)              ; bump current line number by 1/2 line
       LEA     A6,ROLUP                ;   yes, index the string
       CALL    STROUT
90$:    REST    D1,D2
99$:    RTN

PAGE
;************************
;*      PDSLPI          *
;************************
; Set Lines per Inch
;  D2 contains the number of lines per inch required
;
PDSLPI: CMPW    D2,LPISAV(A3)           ; new LPI the same as old ?
       JEQ     99$                     ;   yes, just return
       MOVW    D2,LPISAV(A3)           ; save requested LPI
       MOV     #60.,D7                 ; get a full inch's worth
       MOV     D2,D6                   ; convert LPI to Vert Motion Idx
       DIV     D7,D6                   ; Oki393's VMI is in 1/60 inch units
       MOVW    D7,LPIVMI(A3)           ; save VMI
       LEA     A6,LPITBL               ; address LPI<->control string table
       CLR     D7
10$:    MOVW    (A6)+,D6                ; get next LPI index
       BEQ     20$                     ; NO MATCH, set normal height and VMI
       MOVW    (A6)+,D7                ; Get offset to string
       CMPW    D2,D6
       BHI     10$                     ; Not right entry, loop for next
19$:    TSTW    D7                      ; If D7=0 invalid
       BEQ     20$                     ; set VMI and normal height
       LEA     A6,LPITBL[~D7]
       BR      25$
20$:    LEA     A6,LPINML               ; set normal height
25$:    CALL    STROUT
       LEA     A6,SETVMI               ; output "set VMI" leader
       CALL    STROUT
       MOVW    LPIVMI(A3),D1           ; output requested VMI
       JMP     CHROUT

99$:    RTN

DEFINE LPIENT  IDX,STR=        WORD    IDX,STR-LPITBL

LPITBL:
       LPIENT  2,2$
       LPIENT  3,3$
       LPIENT  6,6$
       LPIENT  8.,8$
       LPIENT  12.,12$
       LPIENT  15.,15$
       LWORD   0
                                               ; "ls"=line spacing
2$:     BYTE    8.,$ESC,'A,30.,$ESC,'T,$ESC,$US,2  ; ls 1/2", triple height
3$:     BYTE    8.,$ESC,'A,20.,$ESC,'T,$ESC,$US,1  ; ls 1/3", double height
6$:     BYTE    7,$ESC,'2,$ESC,'T,$ESC,$US,0    ; ls 1/6",   single height
8$:     BYTE    7,$ESC,'0,$ESC,'T,$ESC,$US,0    ; ls 1/8",   single height
12$:    BYTE    6,$ESC,'A,5,$ESC,'S,1           ; ls 1/12",  subscripts
15$:    BYTE    6,$ESC,'A,4,$ESC,'S,1           ; ls 1/15",  subscripts

; redundant definition; LPINML could be set equal to 6$ above
LPINML: BYTE    7,$ESC,'2,$ESC,'T,$ESC,$US,0    ; ls 1/6",   single height

SETVMI: BYTE    2,$ESC,'A       ; set Vetical motion idex
       EVEN

;************************
;*      PDSHMI          *
;************************
; Set HMI (Horizontal Motion Index)
;  (at 1/120 of an inch)
PDSHMI: CMPW    D2,HMISAV(A3)           ; new HMI the same as old HMI ?
       JEQ     10$                     ;   yes, don't change it
       MOVW    D2,HMISAV(A3)
10$:    CMPW    D2,CPIHMI(A3)           ; adjustment needed?
       BEQ     20$
       SUBW    CPIHMI(A3),D2
       MOVW    D2,ADJHMI(A3)
       BR      99$
20$:    CLRW    ADJHMI(A3)              ; clear HMI adjustment
99$:    RTN

PAGE
;************************
;*      PDSCPI          *
;************************
; Set Characters Per Inch
;  D2 contains the number of characters per inch (pitch)
;
PDSCPI: CMPW    D2,CPISAV(A3)           ; new CPI the same as old ?
       BEQ     99$                     ;   yes, just return
       MOVW    D2,CPISAV(A3)           ; save as current CPI
       CALL    PDXCPI                  ; set printer's CPI
       MOV     #120.,D6                ; compute HMI for requested CPI
       DIV     D6,D2                   ;
       MOV     D6,D2                   ; OK!
       CALL    PDSHMI                  ; set HMI as per CPI requested
99$:    RTN

PDXCPI: CLR     D7
       LEA     A6,CPITBL               ; address CPI<->control string table
10$:    TSTW    @A6                     ; search table
       BEQ     19$                     ; End of table, use highest
       MOVW    (A6)+,D6                ; get next CPI index
       MOVW    (A6)+,D7                ; Get offset to string
       CMPW    D2,D6
       BHI     10$                     ; Not right entry, loop for next
19$:    TSTW    D7                      ; If D7=0 invalid
       BEQ     99$
       LEA     A6,CPITBL[~D7]
       MOV     #120.,D7
       DIV     D7,D6                   ;
       MOVW    D7,CPIHMI(A3)           ; save true HMI
       CALL    STROUT                  ; output it
99$:    RTN

; String to set Horizontal Motion Index (HMI)
;
DEFINE CPIENT  IDX,STR=        WORD    IDX,STR-CPITBL

CPITBL:
       CPIENT  3,3$
       CPIENT  4,4$
       CPIENT  5,5$
       CPIENT  6,6$
       CPIENT  7,7$
       CPIENT  10.,10$
       CPIENT  12.,12$
       CPIENT  15.,15$
       CPIENT  17.,17$
       CPIENT  20.,20$
       LWORD   0

3$:     BYTE    5,$ESC,'P,18.,$ESC,'m   ; Pica (10 cpi),  triple width
4$:     BYTE    5,$ESC,'M,18.,$ESC,'m   ; Elite (12 cpi), triple width
5$:     BYTE    6,$ESC,'P,18.,$ESC,'W,1 ; Pica (10 cpi),  double width
6$:     BYTE    6,$ESC,'M,18.,$ESC,'W,1 ; Elite (12 cpi), double width
7$:     BYTE    6,$ESC,'g,18.,$ESC,'W,1 ; Tiny (15 cpi),  double width
10$:    BYTE    6,$ESC,'P,18.,$ESC,'W,0 ; Pica (10 cpi),  normal width
12$:    BYTE    6,$ESC,'M,18.,$ESC,'W,0 ; Elite (12 cpi), normal width
15$:    BYTE    6,$ESC,'g,18.,$ESC,'W,0 ; Tiny (15 cpi),  normal width
17$:    BYTE    6,$ESC,'P,15.,$ESC,'W,0 ; Pica (10 cpi),  compressed
20$:    BYTE    6,$ESC,'M,15.,$ESC,'W,0 ; Elite (12 cpi), compressed
       EVEN

PAGE
;************************
;*      PDPSON          *
;************************
; Enable Proportional spacing

PDPSON: BSET    #FM%PRO,FM.FLG(A3)      ; indicate proportional enabled
       JNE     IGNORE
       LEA     A6,PSON
       JMP     STROUT

;************************
;*      PDPSOF          *
;************************
; Disable Proportional spacing
;
PDPSOF: BCLR    #FM%PRO,FM.FLG(A3)      ; indicate proportional disabled
       JEQ     IGNORE
       LEA     A6,PSOFF
       JMP     STROUT

PSON:   BYTE    3,$ESC,'p,1     ; Enable proportional spacing
PSOFF:  BYTE    3,$ESC,'p,0     ; Disable proportional spacing
       EVEN

;************************
;*      PDUNDR          *
;************************
; Toggle Underscore
;
PDUNDR: LEA     A6,UNDON                ; assume we are enabling underscore     [101]
       BCHG    #FM%UND,FM.FLG(A3)      ; toggle underscore                     [101]
       BEQ     10$                     ;  off, turn it on                      [101]
       LEA     A6,UNDOFF               ; turn it off                           [101]
10$:    JMP     STROUT                  ;                                       [101]

UNDON:  BYTE    3,$ESC,'-,1             ; Enable Auto Underscore
UNDOFF: BYTE    3,$ESC,'-,0             ; Disable Auto Underscore
       EVEN

;************************
;*      PDDBL           *
;************************
; Toggle Double Underscore
;       (not really supported by this OK393 driver,  real soon now)
;
PDDBL:  BCHG    #FM%DBL,FM.FLG(A3)      ; toggle double underscore
       RTN

;************************
;*      PDBOLD          *
;************************
; Toggle Bold
;
PDBOLD: LEA     A6,BLDON                ; assume we are enabling bold
       BCHG    #FM%BLD,FM.FLG(A3)      ; toggle bold
       BEQ     10$                     ;  off, turn it on                      [101]
       LEA     A6,BLDOFF               ; turn it off                           [101]
10$:    JMP     STROUT                  ;                                       [101]

BLDON:  BYTE    4,$ESC,'G,$ESC,'E       ; Enable Auto Bold
BLDOFF: BYTE    4,$ESC,'H,$ESC,'F       ; Disable Auto Bold
       EVEN

;************************
;*      PDSTRK          *
;************************
; Toggle Strikeout
;
PDSTRK: BCHG    #FM%STK,FM.FLG(A3)      ; toggle strikeout flag
       MOVB    D1,STKCHR(A3)           ; save strikeout character
       RTN

;************************
;*      PDOVRP          *
;************************
; Setup to overprint the last character
;
PDOVRP: PUSHB   D1
       MOVB    #$BS,D1                 ; get backspace
       FILOTB  PTDDB(A3)
       POPB    D1
       DECW    CURCOL(A3)
       RTN

;************************
;*      PDBAR           *
;************************
; Toggle Overbar
;
PDBAR:  BCHG    #FM%BAR,FM.FLG(A3)      ; toggle overbar flag
       RTN

;*********************
;* Carriage Movement *
;*********************

; move to Absolute Horizontal Tab
; d2=position (assume in characters at 10 cpi)
PDMAHT:
       MOV     D2,D7
       MUL     D7,#6.                  ; Convert to tab value (60dpi/10cpi)
       MOVB    D7,D1
       LSR     D7,#8.
       PUSHB   D7                      ; Save high byte
       PUSHB   D1                      ; Save low byte
       LEA     A6,MOVAHT
       CALL    STROUT
       POPB    D1                      ; Get low byte
       FILOTB  PTDDB(A3)               ; output it
       POPB    D1                      ; Get high byte
       FILOTB  PTDDB(A3)               ; output it
       RTN

MOVAHT: BYTE    2,$ESC,'$       ; Move to Absolute Horizontal Tab
CHOME:  BYTE    1,$CR           ; Return carriage home
       EVEN

;******************
;* Paper Movement *
;******************

NEGLF:  BYTE    3,$ESC,'j,30.   ; Output a negative line feed
ROLUP:  BYTE    3,$ESC,'J,15.   ; Roll up a half line (positive)
ROLDWN: BYTE    3,$ESC,'j,15.   ; Roll down a half line (negative)
       EVEN

PAGE
;************************
;*   Justify support    *
;************************

JUSTOF: CLRB    D1                      ; justify off
       CALL    SETJUS
       CLRB    JUSTFY(A3)
;       JMP     PDMNLN                  ; start a new line
       RTN

JUSTLF: CLRB    D1                      ; justify left
       BR      SETJUS
JUSTCN: MOVB    #1,D1                   ; justify center
       BR      SETJUS
JUSTRT: MOVB    #2,D1                   ; justify right
       BR      SETJUS
JUSTFL: MOVB    #3,D1                   ; justify full
       BR      SETJUS

SETJUS:
       CALL    OKIJUS
       INCB    D1
       MOVB    D1,JUSTFY(A3)
       TSTW    CURCOL(A3)              ; at start of a line?
       BEQ     10$                     ; yes, printer accepted mode change
       BSET    #OK%JST,OK.FLG(A3)      ; no, mode needs updating next line.
10$:    RTN

; send justify mode command to printer
; D1 is 0..3 for justification mode wanted.
OKIJUS:
       LEA     A6,JUSTIF
       CALL    STROUT
       JMP     CHROUT

JUSTIF: BYTE    2,$ESC,'a       ; set auto justify mode
       EVEN

;************************
;*     misc support     *
;************************

; toggle debug mode
DEBUGT: BCHG    #OK%DBG,OK.FLG(A3)      ; toggle double underscore
       RTN

; toggle control shift mode
CTLSFT: BCHG    #OK%CTL,OK.FLG(A3)      ; toggle double underscore
       RTN

; toggle between LQ and utility mode
LQUTLT: LEA     A6,UTLON                ; assume we are setting utility mode
       BCHG    #OK%UTL,OK.FLG(A3)      ; toggle utility mode
       BEQ     10$                     ;  off, turn it on                      [101]
       LEA     A6,UTLOFF               ; turn it off (set LQ mode)
10$:    JMP     STROUT                  ;                                       [101]

UTLON:  BYTE    3,$ESC,'x,0     ; utility mode on
UTLOFF: BYTE    3,$ESC,'x,1     ; utility mode off (LQ mode on)
       EVEN

PAGE
;************************
;*    Fonts support     *
;************************
; set font, D1 contains font code number
;       font 0-normal (italics off, graphics off)
;       font 1-italics
;       font 2-graphics (IBM set I),
;       font 3-graphics (IBM set II),
;               set OK%GRP for adding 128 to all chars
;               whenever either graphics font is selected
;
PDFONT: AND     #^H7F,D1                ; mask off hi bytes
       CMPB    D1,#MAXFNT              ; valid font code ?
       BHIS    99$                     ;   no, ignore it
       CMPW    D1,OKFONT(A3)           ; font already selected?
       BEQ     99$                     ; yes, ignore command

       BCLR    #OK%GRP,OK.FLG(A3)      ; assume this is NOT graphics font
       CMPB    D1,#3
       BHI     10$
       CMPB    D1,#2
       BLO     10$
       BSET    #OK%GRP,OK.FLG(A3)      ; graphics font selected
10$:
       MOVW    D1,OKFONT(A3)           ; remember font selected
       ADDW    D1,D1                   ; make index into word offset
       MOVW    FNTTBL[~D1],D1          ; get string offset
       LEA     A6,FNTTBL[~D1]
       JMP     STROUT                  ; go output it

99$:    RTN


DEFINE  FNTSTR  TAG
       WORD    TAG-FNTTBL
ENDM

FNTTBL:
       FNTSTR  FNTNOR
       FNTSTR  FNTITL
       FNTSTR  FNTGRP
       FNTSTR  FNTGR2
FNTEND:

MAXFNT  =       <<FNTEND-FNTTBL>/2.>    ; maximum special code

FNTNOR: BYTE    7,$ESC,'t,0,$ESC,'5,$ESC,'7
FNTITL: BYTE    5,$ESC,'t,0,$ESC,'4
FNTGRP: BYTE    5,$ESC,'t,1,$ESC,'7
FNTGR2: BYTE    5,$ESC,'t,1,$ESC,'6
       EVEN

PAGE
;*****************************
;* Sub/superscript Functions *
;*****************************
;
; Toggle Subscripts mode
PDSUBT:
       LEA     A6,SUBSON               ; assume we are enabling subscript
       BCHG    #SS%SUB,SSFLAG(A3)      ; toggle subscript
       BEQ     10$                     ; was off, turn it on                   [101]
       LEA     A6,SUBOFF               ; turning subscript off
       BTST    #SS%SUP,SSFLAG(A3)      ; are superscript on?
       BEQ     10$                     ; no, just clear subscript mode
       LEA     A6,SUPSON               ; change from sub to superscript
10$:    JMP     STROUT                  ;                                       [101]

; Toggle Superscripts mode
PDSUPT:
       LEA     A6,SUPSON               ; assume we are enabling superscript
       BCHG    #SS%SUP,SSFLAG(A3)      ; toggle superscript
       BEQ     10$                     ; was off, turn it on                   [101]
       LEA     A6,SUBOFF               ; turning superscripts off
       BTST    #SS%SUB,SSFLAG(A3)      ; are subscripts on?
       BEQ     10$                     ; no, just clear superscript mode
       LEA     A6,SUBSON               ; change from super to subscript
10$:    JMP     STROUT                  ;                                       [101]


SUBSON: BYTE    3,$ESC,'S,1             ; set subscript mode
SUPSON: BYTE    3,$ESC,'S,0             ; set superscript mode
SUBOFF: BYTE    2,$ESC,'T               ; clear sub/superscript modes
       EVEN

PAGE
;**************************
;* Unimplemnted Functions *
;**************************
;
USR1:           ; User function 1
USR2:           ;   2
USR3:           ;   3
USR4:           ;   4
SPLPT0:         ; Output character at special print position 0
SPLPT1:         ; Output character at special print position 1
FEDTR1:         ; Select feeder tray 1
FEDTR2:         ; Select feeder tray 2
FEDTR3:         ; Select feeder tray 3
FEDTR4:         ; Select feeder tray 4
FEDTGL:         ; Select feeder tray 1 & then tray 2 thereafter
FEDEJT:         ; Select feeder eject
NULL:
       BYTE    0.                      ; string length
       EVEN                            ; module must end of word boundary

       END