Trailing-Edge
-
PDP-10 Archives
-
decuslib10-12
-
43,50547/pltlib/sprout/ptc6.mac
There is 1 other file named ptc6.mac in the archive. Click here to see a list.
tITLE PTC6 - Interface for PTC-6 Plotter Controller
SUBTTL Joe Smith, 1983 at CSM
SEARCH MACTEN
SALL
SPINCH:: ^D500 ;Steps per inch, 400 or 500 (decimal)
; Commands sent to the PTC-6 are formatted as follows:
; !----------------------!-------------------!------------------!
; ! HEADER ! PLOT DATA ! PROMPT !
; !----------------------!-------------------!------------------!
; !<CRLF> # <Byte Count> ! Record/Record ! Prompt/Inquire !
; !----------------------!-------------------!------------------!
; ! 2 1 2 Bytes ! Max 510 Bytes ! 1 Byte for ASCIZ !
; !----------------------!-------------------!------------------!
; ! 1 Word ! 102 Words ! 1 Word !
; !----------------------!-------------------!------------------!
;
;CPS/6 - Command Structure Protocol for PTC-6
; @-H Vector Magnitude Descriptor, see table at VCCLEN
; I Symbol Command, with Height, Aspect, T/S/O, Rotation, Count, Text
; J Symbol Command, using only Count and Text
; K Circle Command, 3 bytes of Radius follow
; L Arc Command, 3 bytes of Radius, 2 of Beginning Angle, 2 of End Angle
; M Hatch Command, Pattern, 2 bytes Spacing, Width, Height
; N Rectangle Command, 1 to 3 bytes Width, 1 to 3 bytes Height
; P Pen Up Command
; Q Pen Down Command
; R Select Pen, next byte is a digit from 1 to 4
; X Download Command, 1 byte Register Number, 2 bytes Data
; Y Negative Y Inhibit Command
; Z Set Maximum Speed Command, 1 byte Speed
;O,S,T,U,V,W are not used by controller, this routine uses @-H and P-R only
;By Joe Smith, with assistance from Todd Frauenhoff
; Table of Contents for PTC-6 Plotter Controller
;
;
; Section Page
;
; 1. Definitions . . . . . . . . . . . . . . . . . . . . . 2
; 2. PTCINI - Initialize plotter controller . . . . . . . . 3
; 3. PTCOUT - Output rest of buffer . . . . . . . . . . . . 4
; 4. PTCMOR - Finish a move longer than 40 inches . . . . . 5
; 5. PTCMOV - Convert moves to character string . . . . . . 5
; 6. PTCFIN - Finish up and deselect plotter controller . . 8
; 7. PTCPEN - Change to different pen . . . . . . . . . . . 8
; 8. Data Section . . . . . . . . . . . . . . . . . . . . . 9
SUBTTL Definitions
;AC Definitions
TF=0 ;TRUE/FALSE
S1=1 ;Temp
S2=2 ;(not preserved)
T1=3 ;X coordinate
T2=4 ;Y coordinate
T3=5 ;Pen up/down code
T4=6 ;Unused
J=14 ;Base of job parameters
P=17 ;Stack Pointer
;Limit Definitions
MAXDAT==^D510 ;Absolute max number of data bytes
;Max X is 128K=16K*8; 8 long moves are 6 bytes each, +1 for VMD and +1 up/down
ND BUFFUL,MAXDAT-<8*6>-2;Buffer is considerred full after 460 bytes
%16K=^D<16*1024> ;Max offset in 15-1 bits
%512=^D512 ;Max offset in 10-1 bits
%16=^D16 ;Max offset in 5-1 bits
;Miscellaneous Definitions
LF=12 ;Linefeed - Command if "#" follows
CR=15 ;Carriage Return
XON=21 ;DC1 - Prompt code for PTC6
$100=100 ;64 decimal
$40=40 ;Offset to printing characters
SUBTTL PTCINI - Initialize plotter controller
;Routine to initialize plotter controller
;Call: MOVEI T1,^D<+45> ;Number of step-times to raise/lower pen
; PUSHJ P,PTCINI## ;(T1 negative to use XON/XOFF flow control)
; OUTSTR (T1) ;Output init string to TTY
; PUSHJ WAIT ;Wait for controller to send a CR
PTCINI::MOVMM T1,UPINCS(J) ;Time to raise/lower pen
SKIPGE T1 ;Positive means use CR
SKIPA T1,[INIXON] ;Negative means use XON
MOVEI T1,INICR ;Use CR as handshake
JRST UNBUF1 ;Reset variables and return T1 nonzero
;"P" raises pens, "R1" selects #1, controller sends "0C<CR>" when ready
INICR: BYTE (7) CR,LF,";","#",CR,LF,"#",$40+0,$40+3,"P","R","1",XON,0
;"X501" sets register 5 to 01 to use XON/XOFF handshaking
INIXON: BYTE (7) CR,LF,";","#",CR,LF,"#",$40+0,$40+7,"P"
BYTE (7) "R","1","X","5","0","1",XON,0
SUBTTL PTCOUT - Output rest of buffer
;Routine to dump internal buffer
;Call: PUSHJ P,PTCOUT##
; OUTSTR (T1) ;Output last buffer to TTY
; PUSHJ WAIT ;Wait for controller to send a CR (time in S1)
PTCOUT::MOVEI S1,"P" ;Get pen-up command
PUSHJ P,OUTBYT ;Send it and fall into UNBUF
;Return pointer to completed string (called if zero in T3 or buffer full)
UNBUF: SKIPN T1,BYTCNT(J) ;Get byte count if any
POPJ P, ;Nothing there, return zero in T1
MOVE S1,[BYTE(7)CR,LF,"#",$40,$40]
MOVEM S1,HEADER(J) ;Start of block, number of bytes
IDIVI T1,$100 ;Separate into 6-bit fields
ADDI T1,$40 ;High order
DPB T1,[POINT 7,HEADER(J),27]
ADDI T2,$40 ;Low order
DPB T2,[POINT 7,HEADER(J),34]
MOVEI S1,XON ;Prompt code
IDPB S1,PNTR(J)
MOVEI S1,0 ;End with null byte
IDPB S1,PNTR(J) ; for ASCIZ
MOVEI T1,HEADER(J) ;Return T1 nonzero as signal to dump buffer
UNBUF1: SETZM OLDVMD(J) ;Make no assumptions about previous commands
SETZM OLDPEN(J) ; ...
MOVE S1,[POINT 7,PLDATA(J)]
MOVEM S1,PNTR(J) ;Reset to start
SETZB S1,BYTCNT(J) ; ...
EXCH S1,INCS+0(J) ;Clear counter
EXCH S1,INCS+1(J) ;Move previous count down
EXCH S1,INCS+2(J)
EXCH S1,INCS+3(J)
ADD S1,INCS+3(J) ;Accumulate total incs for last 4 buffers
ADD S1,INCS+2(J)
ADD S1,INCS+1(J) ;Return count in S1
POPJ P, ; and addr in T1
SUBTTL PTCMOV -- Check pen up/down status before moving
;Call: MOVE T1,<delta-X>
; MOVE T2,<delta-Y>
; MOVEI T3,2 (or MOVEI T3,3)
; PUSHJ P,PTCMOV## ;Convert to PTC-6 commands
; JUMPE T1,CPOPJ ;Done unless PTCMOV returned data
; OUTSTR (T1) ;Send output to terminal
; PUSHJ P,WAIT ;Wait for controller to send a CR (time in S1)
;Set pen up/down condition -- 1 = Same, 2 = Lower, 3 = Raise pen
PTCMOV::SKIPLE T3 ;Reset if zero or negative,
CAILE T3,3 ; or out of range positive,
PJRST PTCOUT ; raise pen and dump buffer (ignoring T1 & T2)
SKIPN S1,PENCOM-1(T3) ;Get pen up or pen down command
MOVE S1,OLDPEN(J) ;Use previous status if T3 contains 1
CAMN S1,OLDPEN(J) ;If new position is the same,
JRST MOVE1 ; don't change it
MOVEM S1,OLDPEN(J) ;Set new status
PUSHJ P,OUTBYT ;Tell the controller
MOVE S1,UPINCS(J) ;Time required to raise/lower pen
ADDM S1,INCS+0(J)
MOVE1: SKIPN T1 ;If no delta movement,
JUMPE T2,MOVE9 ; just return
;Convert movements from 400 steps per inch to 500 steps per inch
;T1 has X, T2 has Y, T3 is scratch
;Note that if SPINCH contains ^D400, this routine is a long no-op (trashes T3)
KLUDGE::PUSH P,T2 ;Save because of IDIVI
IMUL T1,SPINCH ;Multiply by 500
ADD T1,REM.X(J) ;(with rounding)
IDIVI T1,^D400 ;Divide by 400 (ratio of 500/400)
MOVEM T2,REM.X(J) ;Save remainder for rounding next time
POP P,T2
IMUL T2,SPINCH ;Actual Steps Per INCH
ADD T2,REM.Y(J)
IDIVI T2,^D400
MOVEM T3,REM.Y(J)
;Continue at BIGCHK
SUBTTL PTCMOV -- Split giant moves into smaller ones
;Check to see if X and Y increments within limits
BIGCHK: DMOVEM T1,OLD.X(J) ;Save original X and Y
MOVM S1,T1 ;Get abs(X)
MOVM S2,T2 ;Get abs(Y)
CAMGE S1,S2 ;Put larger in S1
MOVE S1,S2
MOVE T3,S1 ;Number of increments that will be in buffer
;Any vector more than 40 (32) inches long has to be split into 2 or more moves.
IDIVI S1,%16K ;Determine how many times over
JUMPE S1,MOVEOK ;Go plot if T1 and T2 now within range
;If S1=2 then vector must be split into 3 pieces
ADDI S1,1 ;Round up (assume 3 in S1 in the comments below)
IDIV T1,S1 ;Split X (wipes out T2)
MOVE T2,OLD.Y(J) ;Restore Y
IDIV T2,S1 ;Split Y (wipes out T3)
MOVN S1,T1 ;Get negative 1/3 of distance
MOVN S2,T2
ADDM S1,OLD.X(J) ;2/3 left to go
ADDM S2,OLD.Y(J)
;Update INCS so that SPROUT can be told to expect a long delay
MOVM S1,T1 ;Get abs of the new X and Y
MOVM S2,T2
CAMGE S1,S2 ;Put larger in T3
MOVE S1,S2
ADDM S1,INCS(J) ;For elapsed time calculations
PUSHJ P,XY2STG ;Do part of vector from T1 & T2
DMOVE T1,OLD.X(J)
JRST BIGCHK ;Do rest of movement
;T1 and T2 have delta-X and delta-Y, which are less than 16K increments each
MOVEOK: ADDM T3,INCS(J) ;Predict elapsed time
PUSHJ P,XY2STG ;Convert to character string
;Check if it is time to dump the buffer
MOVE9: MOVE S1,BYTCNT(J) ;Get the byte count
CAIL S1,BUFFUL ;Almost full?
PJRST UNBUF ;Yes, return addr of string in T1
SETZB S1,T1 ;No, return with zero in T1
POPJ P,
SUBTTL PTCMOV -- Convert (X,Y) to ASCII string
;Find out number of bytes needed to represent X increments
XY2STG: MOVEI S1,"@" ;Assume 1 byte needed to output X
CAXL T1,-%16 ;If more than 4 bits
CAXLE T1,%16-1
MOVEI S1,"C" ;Use 2 bytes
CAXL T1,-%512 ;If more than 9 bits
CAXLE T1,%512-1
MOVEI S1,"F" ;Use 3 bytes
;Find out number of bytes needed to represent Y increments
CAXL T2,-%16 ;If more than 4 bits
CAXLE T2,%16-1
ADDI S1,1 ;Use 2 bytes
CAXL T2,-%512 ;If more than 9 bits
CAXLE T2,%512-1
ADDI S1,1 ;Use 3 bytes
CAME S1,OLDVMD(J) ;Same as previous?
PUSHJ P,OUTBYT ;No, send VMD (Vector Magnitude Descriptor)
MOVEM S1,OLDVMD(J)
;Change X and Y increments into ASCII characters for plot controller.
HLRZ T3,VCCLEN-"@"(S1);Number of characters to make X incs into vector string
PUSHJ P,OUTCOR ;Make X coordinate
MOVE T1,T2 ;Get Y coordinate
MOVE S1,OLDVMD(J) ;Reset S1
HRRZ T3,VCCLEN-"@"(S1);Number of characters to make Y incs into vector string
;Fall into OUTCOR and return
;Routine to translate coordinate change to characters
;Call with bit pattern in T1, number of bytes in T3
OUTCOR: MOVE S2,[POINT 5,T1,30 ;1 byte
POINT 5,T1,25 ;2 bytes
POINT 5,T1,20]-1(T3);3 bytes
OUTC1: ILDB S1,S2 ;Get 5 bits
ADDI S1,$40 ;Make printing
PUSHJ P,OUTBYT ;Send it
SOJG T3,OUTC1 ;Do all
POPJ P,
;Routine to output a byte in S1 and count it
OUTBYT: IDPB S1,PNTR(J) ;Save the character
AOS BYTCNT(J) ;Count it
POPJ P, ;Return
SUBTTL PTCFIN - Finish up and deselect plotter controller
;Routine to release plotter controller
;Call: PUSHJ P,PTCFIN##
; OUTSTR (T1) ;Output end string to TTY
PTCFIN::MOVEI T1,DESLCT ;Deselect plotter controller
POPJ P, ;Return with addr in T1
DESLCT: ASCIZ /
# (PTC-6 deselected)
/ ;LF,"#",$40,$40 does it, rest is comment
SUBTTL PTCPEN - Change to different pen
;Routine to change pens, call with number from 1 to 3 in S2
PTCPEN::MOVEI S1,"R" ;Change pens
PUSHJ P,OUTBYT
MOVEI S1,"0"(S2) ;Pen number
PJRST OUTBYT
;This assumes that a call to PLTMOV will be made before the 510 byte limit
SUBTTL Data Section
;Constants
PENCOM: EXP 0,"Q","P" ;1 = No change, 2 = lower pen, 3 = raise pen
;Bytes needed for X and Y ranges
VCCLEN: XWD 1,1 ; -16 <= X <= 15 15 => Y => -16
XWD 1,2 ; -16 <= X <= 15 511 => Y => -512
XWD 1,3 ; -16 <= X <= 15 16383 => Y => -16384
XWD 2,1 ; -512 <= X <= 511 15 => Y => -16
XWD 2,2 ; -512 <= X <= 511 511 => Y => -512
XWD 2,3 ; -512 <= X <= 511 16383 => Y => -16384
XWD 3,1 ; -16384 <= X <= 16383 15 => Y => -16
XWD 3,2 ; -16384 <= X <= 16383 511 => Y => -512
XWD 3,3 ; -16384 <= X <= 16383 16383 => Y => -16384
;Variables
IFG <BUFFUL-^D510>,<PRINTX ?PTC-6 cannot handle more than 510 bytes>
DATSIZ==<MAXDAT/5>+1
EXTERN PTC6BF,J$$END ;For .ASSIGN
DEFINE LP(NAME,SIZE),< NAME=PTC6BF+<..=J$$.>
J$$.==J$$.+SIZE
..==..>
J$$.==0
LP PNTR, 1 ;Byte pointer into PLDATA
LP BYTCNT, 1 ;Count of characters in array
LP OLDPEN, 1 ;Last pen up/down command sent
LP OLDVMD, 1 ;Last Vector Magnitude Descriptor
LP OLD.X, 2 ;For doing long vectors
OLD.Y=OLD.X+1
LP UPINCS, 1 ;Number of increments to raise/lower pen
LP INCS, 4 ;Accumulated increments for 4 buffers
LP REM.X, 1 ;Kludge for 500 vs 400 increments
LP REM.Y, 1
LP HEADER, 1 ;Header block, must be at PLDATA-1
LP PLDATA, DATSIZ ;Buffer where data is stored
..==J$$.
.ASSIGN PTC6BF,J$$END,J$$. ;PTC6BF=J$$END, J$$END=J$$END+J$$.
PTC6..=:J$$END-1 ;Last data loc used by this routine
PURGE ..
LITS: END