b8dd52ee9def3eecf3c95eb43142dbc81cb3ea34
1 /* sds_lp.c: SDS 940 line printer simulator
3 Copyright (c) 2001-2007, Robert M. Supnik
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
28 19-Jan-07 RMS Added UNIT_TEXT flag
29 25-Apr-03 RMS Revised for extended file support
36 #define LPT_GETLN(x) (((x) >> LPT_V_LN) & LPT_M_LN)
37 #define CHP(ch,val) ((val) & (1 << (ch))) /* CCL chan test */
38 #define SET_XFR 1 /* set xfr */
39 #define SET_EOR 2 /* print, set eor */
40 #define SET_SPC 4 /* space */
42 extern char sds_to_ascii
[64];
43 extern uint32 xfr_req
;
44 extern int32 stop_invins
, stop_invdev
, stop_inviop
;
45 int32 lpt_spc
= 0; /* space instr */
46 int32 lpt_sta
= 0; /* timeout state */
47 int32 lpt_bptr
= 0; /* line buf ptr */
48 int32 lpt_err
= 0; /* error */
49 int32 lpt_ccl
= 1, lpt_ccp
= 0; /* cctl lnt, ptr */
50 int32 lpt_ctime
= 10; /* char time */
51 int32 lpt_ptime
= 1000; /* print time */
52 int32 lpt_stime
= 10000; /* space time */
53 int32 lpt_stopioe
= 1; /* stop on err */
54 char lpt_buf
[LPT_WIDTH
+ 1] = { 0 }; /* line buffer */
55 uint8 lpt_cct
[CCT_LNT
] = { 0377 }; /* car ctl tape */
56 DSPT lpt_tplt
[] = { /* template */
62 t_stat
lpt_svc (UNIT
*uptr
);
63 t_stat
lpt_reset (DEVICE
*dptr
);
64 t_stat
lpt_attach (UNIT
*uptr
, char *cptr
);
65 t_stat
lpt_crctl (int32 ch
);
66 t_stat
lpt_status (UNIT
*uptr
);
67 t_stat
lpt_bufout (UNIT
*uptr
);
68 void lpt_end_op (int32 fl
);
69 t_stat
lpt (uint32 fnc
, uint32 inst
, uint32
*dat
);
71 /* LPT data structures
73 lpt_dev LPT device descriptor
74 lpt_unit LPT unit descriptor
75 lpt_reg LPT register list
78 DIB lpt_dib
= { CHAN_W
, DEV_LPT
, XFR_LPT
, lpt_tplt
, &lpt
};
81 UDATA (&lpt_svc
, UNIT_SEQ
+UNIT_ATTABLE
+UNIT_TEXT
, 0)
85 { BRDATA (BUF
, lpt_buf
, 8, 8, LPT_WIDTH
) },
86 { DRDATA (BPTR
, lpt_bptr
, 8), PV_LEFT
},
87 { FLDATA (XFR
, xfr_req
, XFR_V_LPT
) },
88 { FLDATA (ERR
, lpt_err
, 0) },
89 { ORDATA (STA
, lpt_sta
, 3) },
90 { BRDATA (CCT
, lpt_cct
, 8, 8, CCT_LNT
) },
91 { DRDATA (CCTP
, lpt_ccp
, 8), PV_LEFT
},
92 { DRDATA (CCTL
, lpt_ccl
, 8), REG_RO
+ PV_LEFT
},
93 { ORDATA (SPCINST
, lpt_spc
, 24) },
94 { DRDATA (POS
, lpt_unit
.pos
, T_ADDR_W
), PV_LEFT
},
95 { DRDATA (CTIME
, lpt_ctime
, 24), REG_NZ
+ PV_LEFT
},
96 { DRDATA (PTIME
, lpt_ptime
, 24), REG_NZ
+ PV_LEFT
},
97 { DRDATA (STIME
, lpt_stime
, 24), REG_NZ
+ PV_LEFT
},
98 { FLDATA (STOP_IOE
, lpt_stopioe
, 0) },
103 { MTAB_XTD
|MTAB_VDV
, 0, "CHANNEL", "CHANNEL",
104 &set_chan
, &show_chan
, NULL
},
109 "LPT", &lpt_unit
, lpt_reg
, lpt_mod
,
111 NULL
, NULL
, &lpt_reset
,
112 NULL
, &lpt_attach
, NULL
,
113 &lpt_dib
, DEV_DISABLE
116 /* Line printer routine
118 conn - inst = EOM0, dat = NULL
119 eom1 - inst = EOM1, dat = NULL
120 sks - inst = SKS, dat = ptr to result
121 disc - inst = device number, dat = NULL
122 wreor - inst = device number, dat = NULL
123 read - inst = device number, dat = ptr to data
124 write - inst = device number, dat = ptr to result
126 The line printer is an asynchronous output device, that is, it
127 can never set the channel rate error flag.
130 t_stat
lpt (uint32 fnc
, uint32 inst
, uint32
*dat
)
135 switch (fnc
) { /* case function */
137 case IO_CONN
: /* connect */
138 new_ch
= I_GETEOCH (inst
); /* get new chan */
139 if (new_ch
!= lpt_dib
.chan
) return SCPE_IERR
; /* wrong chan? */
140 for (i
= 0; i
< LPT_WIDTH
; i
++) lpt_buf
[i
] = 0; /* clr buffer */
141 lpt_bptr
= 0; /* clr buf ptr */
142 lpt_err
= 0; /* err = 0 */
143 xfr_req
= xfr_req
& ~XFR_LPT
; /* clr xfr flag */
144 lpt_sta
= lpt_sta
| SET_XFR
; /* need xfr */
145 sim_activate (&lpt_unit
, lpt_ctime
); /* start timer */
148 case IO_EOM1
: /* EOM mode 1 */
149 new_ch
= I_GETEOCH (inst
); /* get new chan */
150 if (new_ch
!= lpt_dib
.chan
) CRETIOP
; /* wrong chan? */
151 if (inst
& 0400) { /* space? */
152 lpt_spc
= inst
; /* save instr */
153 lpt_sta
= lpt_sta
| SET_SPC
; /* need space */
154 sim_cancel (&lpt_unit
); /* cancel timer */
155 sim_activate (&lpt_unit
, lpt_stime
); /* start timer */
159 case IO_DISC
: /* disconnect */
160 lpt_end_op (0); /* normal term */
161 return lpt_bufout (&lpt_unit
); /* dump output */
163 case IO_WREOR
: /* write eor */
164 lpt_sta
= (lpt_sta
| SET_EOR
) & ~SET_XFR
; /* need eor */
165 sim_activate (&lpt_unit
, lpt_ptime
); /* start timer */
168 case IO_SKS
: /* SKS */
169 new_ch
= I_GETSKCH (inst
); /* sks chan */
170 if (new_ch
!= lpt_dib
.chan
) return SCPE_IERR
; /* wrong chan? */
171 t
= I_GETSKCND (inst
); /* sks cond */
172 if (((t
== 020) && (!CHP (7, lpt_cct
[lpt_ccp
]))) || /* 14062: !ch 7 */
173 ((t
== 010) && (lpt_unit
.flags
& UNIT_ATT
)) || /* 12062: !online */
174 (t
== 004) && !lpt_err
) *dat
= 1; /* 11062: !err */
177 case IO_WRITE
: /* write */
178 asc
= sds_to_ascii
[(*dat
) & 077]; /* convert data */
179 xfr_req
= xfr_req
& ~XFR_LPT
; /* clr xfr flag */
180 if (lpt_bptr
< LPT_WIDTH
) lpt_buf
[lpt_bptr
++] = asc
;/* store data */
181 lpt_sta
= lpt_sta
| SET_XFR
; /* need xfr */
182 sim_activate (&lpt_unit
, lpt_ctime
); /* start ch timer */
192 /* Unit service and write */
194 t_stat
lpt_svc (UNIT
*uptr
)
197 static const char *lpt_stabl
[] = {
198 "\r", "\n", "\n\n", "\n\n\n",
199 "\n\n\n\n", "\n\n\n\n\n",
200 "\n\n\n\n\n\n", "\n\n\n\n\n\n\n"
203 if (lpt_sta
& SET_XFR
) chan_set_ordy (lpt_dib
.chan
); /* need lpt xfr? */
204 if (lpt_sta
& SET_EOR
) { /* printing? */
205 chan_set_flag (lpt_dib
.chan
, CHF_EOR
); /* set eor flg */
206 r
= lpt_bufout (uptr
); /* output buf */
208 if (lpt_sta
& SET_SPC
) { /* spacing? */
209 if (uptr
->flags
& UNIT_ATT
) { /* attached? */
210 int32 ln
= LPT_GETLN (lpt_spc
); /* get lines, ch */
211 if (lpt_spc
& 0200) /* n lines? */
212 fputs (lpt_stabl
[ln
], uptr
->fileref
); /* upspace */
213 else lpt_crctl (ln
); /* carriage ctl */
215 r
= lpt_status (uptr
); /* update status */
217 lpt_sta
= 0; /* clear state */
221 /* Trim and output buffer */
223 t_stat
lpt_bufout (UNIT
*uptr
)
227 if ((uptr
->flags
& UNIT_ATT
) && lpt_bptr
) { /* attached? */
228 for (i
= LPT_WIDTH
- 1; (i
>= 0) && (lpt_buf
[i
] == ' '); i
--)
229 lpt_buf
[i
] = 0; /* trim line */
230 fputs (lpt_buf
, uptr
->fileref
); /* write line */
233 return lpt_status (uptr
); /* return status */
236 /* Status update after I/O */
238 t_stat
lpt_status (UNIT
*uptr
)
240 if (uptr
->flags
& UNIT_ATT
) { /* attached? */
241 uptr
->pos
= ftell (uptr
->fileref
); /* update position */
242 if (ferror (uptr
->fileref
)) { /* I/O error? */
243 lpt_end_op (CHF_EOR
| CHF_ERR
); /* set err, disc */
244 perror ("LPT I/O error"); /* print msg */
245 clearerr (uptr
->fileref
);
246 return SCPE_IOERR
; /* ret error */
250 lpt_end_op (CHF_EOR
| CHF_ERR
); /* set err, disc */
251 CRETIOE (lpt_stopioe
, SCPE_UNATT
); /* ret error */
256 /* Terminate LPT operation */
258 void lpt_end_op (int32 fl
)
260 if (fl
) chan_set_flag (lpt_dib
.chan
, fl
); /* set flags */
261 xfr_req
= xfr_req
& ~XFR_LPT
; /* clear xfr */
262 sim_cancel (&lpt_unit
); /* stop */
263 if (fl
& CHF_ERR
) { /* error? */
264 chan_disc (lpt_dib
.chan
); /* disconnect */
265 lpt_err
= 1; /* set lpt err */
270 /* Carriage control */
272 t_stat
lpt_crctl (int32 ch
)
276 if ((ch
== 1) && CHP (ch
, lpt_cct
[0])) { /* top of form? */
277 fputs ("\f\n", lpt_unit
.fileref
); /* ff + nl */
278 lpt_ccp
= 0; /* top of page */
281 for (i
= 1; i
< lpt_ccl
+ 1; i
++) { /* sweep thru cct */
282 lpt_ccp
= (lpt_ccp
+ 1) %lpt_ccl
; /* adv pointer */
283 if (CHP (ch
, lpt_cct
[lpt_ccp
])) { /* chan punched? */
284 for (j
= 0; j
< i
; j
++) fputc ('\n', lpt_unit
.fileref
);
288 return STOP_CCT
; /* runaway channel */
293 t_stat
lpt_reset (DEVICE
*dptr
)
295 chan_disc (lpt_dib
.chan
); /* disconnect */
296 lpt_spc
= 0; /* clr state */
298 xfr_req
= xfr_req
& ~XFR_LPT
; /* clr xfr flag */
299 sim_cancel (&lpt_unit
); /* deactivate */
305 t_stat
lpt_attach (UNIT
*uptr
, char *cptr
)
307 lpt_ccp
= 0; /* top of form */
308 return attach_unit (uptr
, cptr
);