Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* hp2100_lps.c: HP 2100 12653A/2767 line printer simulator\r |
2 | \r | |
3 | Copyright (c) 1993-2007, Robert M. Supnik\r | |
4 | \r | |
5 | Permission is hereby granted, free of charge, to any person obtaining a\r | |
6 | copy of this software and associated documentation files (the "Software"),\r | |
7 | to deal in the Software without restriction, including without limitation\r | |
8 | the rights to use, copy, modify, merge, publish, distribute, sublicense,\r | |
9 | and/or sell copies of the Software, and to permit persons to whom the\r | |
10 | Software is furnished to do so, subject to the following conditions:\r | |
11 | \r | |
12 | The above copyright notice and this permission notice shall be included in\r | |
13 | all copies or substantial portions of the Software.\r | |
14 | \r | |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r | |
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r | |
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r | |
18 | ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r | |
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r | |
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r | |
21 | \r | |
22 | Except as contained in this notice, the name of Robert M Supnik shall not be\r | |
23 | used in advertising or otherwise to promote the sale, use or other dealings\r | |
24 | in this Software without prior written authorization from Robert M Supnik.\r | |
25 | \r | |
26 | lps 12653A 2767 line printer\r | |
27 | 12566B microcircuit interface with loopback diagnostic connector\r | |
28 | \r | |
29 | 10-May-07 RMS Added UNIT_TEXT flag\r | |
30 | 11-Jan-07 JDB CLC cancels I/O event if DIAG (jumper W9 in "A" pos)\r | |
31 | Added ioCRS state to I/O decoders\r | |
32 | 19-Nov-04 JDB Added restart when set online, etc.\r | |
33 | Fixed col count for non-printing chars\r | |
34 | 01-Oct-04 JDB Added SET OFFLINE/ONLINE, POWEROFF/POWERON\r | |
35 | Fixed status returns for error conditions\r | |
36 | Fixed handling of non-printing characters\r | |
37 | Fixed handling of characters after column 80\r | |
38 | Improved timing model accuracy for RTE\r | |
39 | Added fast/realistic timing\r | |
40 | Added debug printouts\r | |
41 | 03-Jun-04 RMS Fixed timing (found by Dave Bryan)\r | |
42 | 26-Apr-04 RMS Fixed SFS x,C and SFC x,C\r | |
43 | Implemented DMA SRQ (follows FLG)\r | |
44 | 25-Apr-03 RMS Revised for extended file support\r | |
45 | 24-Oct-02 RMS Added microcircuit test features\r | |
46 | 30-May-02 RMS Widened POS to 32b\r | |
47 | 03-Dec-01 RMS Changed DEVNO to use extended SET/SHOW\r | |
48 | 07-Sep-01 RMS Moved function prototypes\r | |
49 | 21-Nov-00 RMS Fixed flag, fbf power up state\r | |
50 | Added command flop\r | |
51 | 15-Oct-00 RMS Added variable device number support\r | |
52 | \r | |
53 | This module simulates two different devices. In "diagnostic mode," it\r | |
54 | simulates a 12566B microcircuit interface card with a loopback connector and\r | |
55 | the jumpers set as required for execution of the General Purpose Register\r | |
56 | diagnostic. In non-diagnostic mode, it simulates a 12653A line printer\r | |
57 | interface card and a 2767 line printer.\r | |
58 | \r | |
59 | The 12566B interface with the loopback connector ties the device command\r | |
60 | output to the device flag input. Setting control therefore causes device\r | |
61 | flag to set almost immediately. Device command is active only during that\r | |
62 | interim. Under simulation, the loopback occurs within the STC handler, and\r | |
63 | CMD is never set.\r | |
64 | \r | |
65 | The 2767 impact printer has a rotating drum with 80 columns of 64 raised\r | |
66 | characters. ASCII codes 32 through 95 (SPACE through "_") form the print\r | |
67 | repertoire. The printer responds to the control characters FF, LF, and CR.\r | |
68 | \r | |
69 | The 80 columns are divided into four zones of 20 characters each that are\r | |
70 | addressed sequentially. Received characters are buffered in a 20-character\r | |
71 | memory. When the 20th printable character is received, the current zone is\r | |
72 | printed, and the memory is reset. In the absence of print command\r | |
73 | characters, a zone print operation will commence after each group of 20\r | |
74 | printable characters is transmitted to the printer.\r | |
75 | \r | |
76 | The print command characters have these actions:\r | |
77 | \r | |
78 | * CR -- print the characters in the current zone, reset to zone 1, and clear\r | |
79 | the buffer memory.\r | |
80 | * LF -- same as CR, plus advances the paper one line.\r | |
81 | * FF -- same as CR, plus advances the paper to the top of the next form.\r | |
82 | \r | |
83 | The 2767 provides two status bits via the interface:\r | |
84 | \r | |
85 | bit 15 -- printer not ready\r | |
86 | bit 0 -- printer busy\r | |
87 | \r | |
88 | The expected status returns are:\r | |
89 | \r | |
90 | 100001 -- power off or cable disconnected\r | |
91 | 100001 -- initial power on, then changes to 000001 within sixty\r | |
92 | seconds of initial power on\r | |
93 | 000001 -- power on, paper unloaded or printer offline or not idle\r | |
94 | 000000 -- power on, paper loaded and printer online and idle\r | |
95 | \r | |
96 | These simulator commands provide the listed printer states:\r | |
97 | \r | |
98 | SET LPS POWEROFF --> power off or cable disconnected\r | |
99 | SET LPS POWERON --> power on\r | |
100 | SET LPS OFFLINE --> printer offline\r | |
101 | SET LPS ONLINE --> printer online\r | |
102 | ATT LPS <file> --> paper loaded\r | |
103 | DET LPS --> paper out\r | |
104 | \r | |
105 | References:\r | |
106 | - 2767A Line Printer Operating and Service Manual (02767-90002, Oct-1973)\r | |
107 | - 12566B, 12566B-001, 12566B-002, 12566B-003 Microcircuit Interface Kits\r | |
108 | Operating and Service Manual (12566-90015, Apr-1976)\r | |
109 | \r | |
110 | The following implemented behaviors have been inferred from secondary sources\r | |
111 | (diagnostics, operating system drivers, etc.), due to absent or contradictory\r | |
112 | authoritative information; future correction may be needed:\r | |
113 | \r | |
114 | 1. Paper out sets BUSY instead of NOT READY.\r | |
115 | 2. Print operation in progress sets BUSY instead of NOT READY.\r | |
116 | 3. Characters not in the print repertoire are replaced with blanks.\r | |
117 | 4. The 81st and succeeding characters overprint the current line.\r | |
118 | */\r | |
119 | \r | |
120 | #include "hp2100_defs.h"\r | |
121 | #include "hp2100_cpu.h"\r | |
122 | \r | |
123 | #define LPS_ZONECNT 20 /* zone char count */\r | |
124 | #define LPS_PAGECNT 80 /* page char count */\r | |
125 | #define LPS_PAGELNT 60 /* page line length */\r | |
126 | #define LPS_FORMLNT 66 /* form line length */\r | |
127 | \r | |
128 | /* Printer power states */\r | |
129 | \r | |
130 | #define LPS_ON 0 /* power is on */\r | |
131 | #define LPS_OFF 1 /* power is off */\r | |
132 | #define LPS_TURNING_ON 2 /* power is turning on */\r | |
133 | \r | |
134 | #define LPS_BUSY 0000001 /* busy status */\r | |
135 | #define LPS_NRDY 0100000 /* not ready status */\r | |
136 | #define LPS_PWROFF LPS_BUSY | LPS_NRDY /* power-off status */\r | |
137 | \r | |
138 | #define UNIT_V_DIAG (UNIT_V_UF + 0) /* diagnostic mode */\r | |
139 | #define UNIT_V_POWEROFF (UNIT_V_UF + 1) /* unit powered off */\r | |
140 | #define UNIT_V_OFFLINE (UNIT_V_UF + 2) /* unit offline */\r | |
141 | #define UNIT_DIAG (1 << UNIT_V_DIAG)\r | |
142 | #define UNIT_POWEROFF (1 << UNIT_V_POWEROFF)\r | |
143 | #define UNIT_OFFLINE (1 << UNIT_V_OFFLINE)\r | |
144 | \r | |
145 | extern uint32 PC;\r | |
146 | extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2];\r | |
147 | extern FILE *sim_deb;\r | |
148 | \r | |
149 | int32 lps_ccnt = 0; /* character count */\r | |
150 | int32 lps_lcnt = 0; /* line count */\r | |
151 | int32 lps_stopioe = 0; /* stop on error */\r | |
152 | int32 lps_sta = 0; /* printer status */\r | |
153 | int32 lps_timing = 1; /* timing type */\r | |
154 | uint32 lps_power = LPS_ON; /* power state */\r | |
155 | \r | |
156 | /* Hardware timing:\r | |
157 | (based on 1580 instr/msec) instr msec calc msec\r | |
158 | ------------------------\r | |
159 | - character transfer time : ctime = 2 2 us\r | |
160 | - per-zone printing time : ptime = 55300 35 40\r | |
161 | - per-line paper slew time : stime = 17380 11 13\r | |
162 | - power-on ready delay time : rtime = 158000 100\r | |
163 | \r | |
164 | NOTE: the printer acknowledges before the print motion has stopped to allow\r | |
165 | for continuous slew, so the set times are a bit less than the calculated\r | |
166 | operation time from the manual.\r | |
167 | \r | |
168 | NOTE: the 2767 diagnostic checks completion times, so the realistic timing\r | |
169 | must be used. Because simulator timing is in instructions, and because the\r | |
170 | diagnostic uses the TIMER instruction (~1580 executions per millisecond) when\r | |
171 | running on a 1000-E/F but a software timing loop (~400-600 executions per\r | |
172 | millisecond) when running on anything else, realistic timings are decreased by\r | |
173 | three-fourths when not executing on an E/F.\r | |
174 | */\r | |
175 | \r | |
176 | int32 lps_ctime = 0; /* char xfer time */\r | |
177 | int32 lps_ptime = 0; /* zone printing time */\r | |
178 | int32 lps_stime = 0; /* paper slew time */\r | |
179 | int32 lps_rtime = 0; /* power-on ready time */\r | |
180 | \r | |
181 | typedef int32 TIMESET[4]; /* set of controller times */\r | |
182 | \r | |
183 | int32 *const lps_timers[] = { &lps_ctime, &lps_ptime, &lps_stime, &lps_rtime };\r | |
184 | \r | |
185 | const TIMESET lps_times[2] = {\r | |
186 | { 2, 55300, 17380, 158000 }, /* REALTIME */\r | |
187 | { 2, 1000, 1000, 1000 } /* FASTTIME */\r | |
188 | };\r | |
189 | \r | |
190 | DEVICE lps_dev;\r | |
191 | int32 lpsio (int32 inst, int32 IR, int32 dat);\r | |
192 | t_stat lps_svc (UNIT *uptr);\r | |
193 | t_stat lps_reset (DEVICE *dptr);\r | |
194 | t_stat lps_restart (UNIT *uptr, int32 value, char *cptr, void *desc);\r | |
195 | t_stat lps_poweroff (UNIT *uptr, int32 value, char *cptr, void *desc);\r | |
196 | t_stat lps_poweron (UNIT *uptr, int32 value, char *cptr, void *desc);\r | |
197 | t_stat lps_attach (UNIT *uptr, char *cptr);\r | |
198 | t_stat lps_set_timing (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
199 | t_stat lps_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc);\r | |
200 | \r | |
201 | /* LPS data structures\r | |
202 | \r | |
203 | lps_dev LPS device descriptor\r | |
204 | lps_unit LPS unit descriptor\r | |
205 | lps_reg LPS register list\r | |
206 | */\r | |
207 | \r | |
208 | DIB lps_dib = { LPS, 0, 0, 0, 0, 0, &lpsio };\r | |
209 | \r | |
210 | UNIT lps_unit = {\r | |
211 | UDATA (&lps_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_DISABLE+UNIT_TEXT, 0)\r | |
212 | };\r | |
213 | \r | |
214 | REG lps_reg[] = {\r | |
215 | { ORDATA (BUF, lps_unit.buf, 16) },\r | |
216 | { ORDATA (STA, lps_sta, 16) },\r | |
217 | { ORDATA (POWER, lps_power, 2), REG_RO },\r | |
218 | { FLDATA (CMD, lps_dib.cmd, 0) },\r | |
219 | { FLDATA (CTL, lps_dib.ctl, 0) },\r | |
220 | { FLDATA (FLG, lps_dib.flg, 0) },\r | |
221 | { FLDATA (FBF, lps_dib.fbf, 0) },\r | |
222 | { FLDATA (SRQ, lps_dib.srq, 0) },\r | |
223 | { DRDATA (CCNT, lps_ccnt, 7), PV_LEFT },\r | |
224 | { DRDATA (LCNT, lps_lcnt, 7), PV_LEFT },\r | |
225 | { DRDATA (POS, lps_unit.pos, T_ADDR_W), PV_LEFT },\r | |
226 | { DRDATA (CTIME, lps_ctime, 24), PV_LEFT },\r | |
227 | { DRDATA (PTIME, lps_ptime, 24), PV_LEFT },\r | |
228 | { DRDATA (STIME, lps_stime, 24), PV_LEFT },\r | |
229 | { DRDATA (RTIME, lps_rtime, 24), PV_LEFT },\r | |
230 | { FLDATA (TIMING, lps_timing, 0), REG_HRO },\r | |
231 | { FLDATA (STOP_IOE, lps_stopioe, 0) },\r | |
232 | { ORDATA (DEVNO, lps_dib.devno, 6), REG_HRO },\r | |
233 | { NULL }\r | |
234 | };\r | |
235 | \r | |
236 | MTAB lps_mod[] = {\r | |
237 | { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL },\r | |
238 | { UNIT_DIAG, 0, "printer mode", "PRINTER", NULL },\r | |
239 | { UNIT_POWEROFF, UNIT_POWEROFF, "power off", "POWEROFF", lps_poweroff },\r | |
240 | { UNIT_POWEROFF, 0, "power on", "POWERON", lps_poweron },\r | |
241 | { UNIT_OFFLINE, UNIT_OFFLINE, "offline", "OFFLINE", NULL },\r | |
242 | { UNIT_OFFLINE, 0, "online", "ONLINE", lps_restart },\r | |
243 | { MTAB_XTD | MTAB_VDV, 0, NULL, "REALTIME",\r | |
244 | &lps_set_timing, NULL, NULL },\r | |
245 | { MTAB_XTD | MTAB_VDV, 1, NULL, "FASTTIME",\r | |
246 | &lps_set_timing, NULL, NULL },\r | |
247 | { MTAB_XTD | MTAB_VDV, 0, "TIMING", NULL,\r | |
248 | NULL, &lps_show_timing, NULL },\r | |
249 | { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",\r | |
250 | &hp_setdev, &hp_showdev, &lps_dev },\r | |
251 | { 0 }\r | |
252 | };\r | |
253 | \r | |
254 | DEVICE lps_dev = {\r | |
255 | "LPS", &lps_unit, lps_reg, lps_mod,\r | |
256 | 1, 10, 31, 1, 8, 8,\r | |
257 | NULL, NULL, &lps_reset,\r | |
258 | NULL, &lps_attach, NULL,\r | |
259 | &lps_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG\r | |
260 | };\r | |
261 | \r | |
262 | /* IO instructions */\r | |
263 | \r | |
264 | int32 lpsio (int32 inst, int32 IR, int32 dat)\r | |
265 | {\r | |
266 | int32 dev, sched;\r | |
267 | \r | |
268 | dev = IR & I_DEVMASK; /* get device no */\r | |
269 | switch (inst) { /* case on opcode */\r | |
270 | \r | |
271 | case ioFLG: /* flag clear/set */\r | |
272 | if ((IR & I_HC) == 0) { setFSR (dev); } /* STF */\r | |
273 | break;\r | |
274 | \r | |
275 | case ioSFC: /* skip flag clear */\r | |
276 | if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;\r | |
277 | break;\r | |
278 | \r | |
279 | case ioSFS: /* skip flag set */\r | |
280 | if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;\r | |
281 | break;\r | |
282 | \r | |
283 | case ioOTX: /* output */\r | |
284 | if (DEBUG_PRS (lps_dev))\r | |
285 | fprintf (sim_deb, ">>LPS OTx: Character %06o output\n", dat);\r | |
286 | lps_unit.buf = dat;\r | |
287 | break;\r | |
288 | \r | |
289 | case ioLIX: /* load */\r | |
290 | dat = 0; /* default sta = 0 */\r | |
291 | case ioMIX: /* merge */\r | |
292 | if ((lps_unit.flags & UNIT_DIAG) == 0) { /* real lpt? */\r | |
293 | if (lps_power == LPS_ON) { /* power on? */\r | |
294 | if (((lps_unit.flags & UNIT_ATT) == 0) || /* paper out? */\r | |
295 | (lps_unit.flags & UNIT_OFFLINE) || /* offline? */\r | |
296 | sim_is_active (&lps_unit)) lps_sta = LPS_BUSY;\r | |
297 | else lps_sta = 0;\r | |
298 | }\r | |
299 | else lps_sta = LPS_PWROFF;\r | |
300 | }\r | |
301 | dat = dat | lps_sta; /* diag, rtn status */\r | |
302 | if (DEBUG_PRS (lps_dev))\r | |
303 | fprintf (sim_deb, ">>LPS LIx: Status %06o returned\n", dat);\r | |
304 | break;\r | |
305 | \r | |
306 | case ioCRS: /* control reset */\r | |
307 | clrCTL (dev); /* clear control */\r | |
308 | clrCMD (dev); /* clear command */\r | |
309 | sim_cancel (&lps_unit); /* deactivate unit */\r | |
310 | break;\r | |
311 | \r | |
312 | case ioCTL: /* control clear/set */\r | |
313 | if (IR & I_CTL) { /* CLC */\r | |
314 | clrCTL (dev); /* clear control */\r | |
315 | if (lps_unit.flags & UNIT_DIAG) { /* diagnostic mode? */\r | |
316 | clrCMD (dev); /* clear command (jumper W9-A) */\r | |
317 | if (IR & I_HC) /* clear flag too? */\r | |
318 | sim_cancel (&lps_unit); /* prevent FLG/SRQ */\r | |
319 | }\r | |
320 | }\r | |
321 | else { /* STC */\r | |
322 | setCTL (dev); /* set ctl */\r | |
323 | setCMD (dev); /* set cmd */\r | |
324 | if (lps_unit.flags & UNIT_DIAG) { /* diagnostic? */\r | |
325 | lps_sta = lps_unit.buf; /* loop back data */\r | |
326 | sim_activate (&lps_unit, 2); /* schedule flag */\r | |
327 | }\r | |
328 | else { /* real lpt, sched */\r | |
329 | if (DEBUG_PRS (lps_dev)) fprintf (sim_deb,\r | |
330 | ">>LPS STC: Character %06o scheduled for line %d, column %d, ",\r | |
331 | lps_unit.buf, lps_lcnt + 1, lps_ccnt + 1);\r | |
332 | if ((lps_unit.buf != '\f') &&\r | |
333 | (lps_unit.buf != '\n') &&\r | |
334 | (lps_unit.buf != '\r')) { /* normal char */\r | |
335 | lps_ccnt = lps_ccnt + 1; /* incr char counter */\r | |
336 | if (lps_ccnt % LPS_ZONECNT == 0) /* end of zone? */\r | |
337 | sched = lps_ptime; /* print zone */\r | |
338 | else sched = lps_ctime; /* xfer char */\r | |
339 | }\r | |
340 | else { /* print cmd */\r | |
341 | if (lps_ccnt % LPS_ZONECNT == 0) /* last zone printed? */\r | |
342 | sched = lps_ctime; /* yes, so just char time */\r | |
343 | else sched = lps_ptime; /* no, so print needed */\r | |
344 | lps_ccnt = 0; /* reset char counter */\r | |
345 | if (lps_unit.buf == '\n') { /* line advance */\r | |
346 | lps_lcnt = (lps_lcnt + 1) % LPS_PAGELNT;\r | |
347 | if (lps_lcnt > 0) sched = sched + lps_stime;\r | |
348 | else sched = sched + /* allow for perf skip */\r | |
349 | lps_stime * (LPS_FORMLNT - LPS_PAGELNT);\r | |
350 | }\r | |
351 | else if (lps_unit.buf == '\f') { /* form advance */\r | |
352 | sched = sched + lps_stime * (LPS_FORMLNT - lps_lcnt);\r | |
353 | lps_lcnt = 0;\r | |
354 | }\r | |
355 | }\r | |
356 | sim_activate (&lps_unit, sched);\r | |
357 | if (DEBUG_PRS (lps_dev))\r | |
358 | fprintf (sim_deb, "time = %d\n", sched);\r | |
359 | }\r | |
360 | }\r | |
361 | break;\r | |
362 | \r | |
363 | default:\r | |
364 | break;\r | |
365 | }\r | |
366 | \r | |
367 | if (IR & I_HC) { clrFSR (dev); } /* H/C option */\r | |
368 | return dat;\r | |
369 | }\r | |
370 | \r | |
371 | /* Unit service */\r | |
372 | \r | |
373 | t_stat lps_svc (UNIT *uptr)\r | |
374 | {\r | |
375 | int32 dev;\r | |
376 | int32 c = uptr->buf & 0177;\r | |
377 | \r | |
378 | if (lps_power == LPS_TURNING_ON) { /* printer warmed up? */\r | |
379 | lps_power = LPS_ON; /* change state */\r | |
380 | lps_restart (uptr, 0, NULL, NULL); /* restart I/O if hung */\r | |
381 | if (DEBUG_PRS (lps_dev))\r | |
382 | fputs (">>LPS svc: Power state is ON\n", sim_deb);\r | |
383 | return SCPE_OK; /* done */\r | |
384 | }\r | |
385 | dev = lps_dib.devno; /* get dev no */\r | |
386 | if (uptr->flags & UNIT_DIAG) { /* diagnostic? */\r | |
387 | clrCMD (dev); /* clear cmd */\r | |
388 | setFSR (dev); /* set flag, fbf */\r | |
389 | return SCPE_OK; /* done */\r | |
390 | }\r | |
391 | if ((uptr->flags & UNIT_ATT) == 0) /* attached? */\r | |
392 | return IORETURN (lps_stopioe, SCPE_UNATT);\r | |
393 | else if (uptr->flags & UNIT_OFFLINE) /* offline? */\r | |
394 | return IORETURN (lps_stopioe, STOP_OFFLINE);\r | |
395 | else if (uptr->flags & UNIT_POWEROFF) /* powered off? */\r | |
396 | return IORETURN (lps_stopioe, STOP_PWROFF);\r | |
397 | clrCMD (dev); /* clear cmd */\r | |
398 | setFSR (dev); /* set flag, fbf */\r | |
399 | if (((c < ' ') || (c > '_')) && /* non-printing char? */\r | |
400 | (c != '\f') && (c != '\n') && (c != '\r')) {\r | |
401 | if (DEBUG_PRS (lps_dev))\r | |
402 | fprintf (sim_deb, ">>LPS svc: Character %06o erased\n", c);\r | |
403 | c = ' '; /* replace with blank */\r | |
404 | }\r | |
405 | if (lps_ccnt > LPS_PAGECNT) { /* 81st character? */\r | |
406 | fputc ('\r', uptr->fileref); /* return to line start */\r | |
407 | uptr->pos = uptr->pos + 1; /* update pos */\r | |
408 | lps_ccnt = 1; /* reset char counter */\r | |
409 | if (DEBUG_PRS (lps_dev))\r | |
410 | fputs (">>LPS svc: Line wraparound to column 1\n", sim_deb);\r | |
411 | }\r | |
412 | fputc (c, uptr->fileref); /* "print" char */\r | |
413 | uptr->pos = uptr->pos + 1; /* update pos */\r | |
414 | if (DEBUG_PRS (lps_dev))\r | |
415 | fprintf (sim_deb, ">>LPS svc: Character %06o printed\n", c);\r | |
416 | if ((lps_lcnt == 0) && (c == '\n')) { /* LF did TOF? */\r | |
417 | fputc ('\f', uptr->fileref); /* do perf skip */\r | |
418 | uptr->pos = uptr->pos + 1; /* update pos */\r | |
419 | if (DEBUG_PRS (lps_dev))\r | |
420 | fputs (">>LPS svc: Perforation skip to TOF\n", sim_deb);\r | |
421 | }\r | |
422 | if (ferror (uptr->fileref)) {\r | |
423 | perror ("LPS I/O error");\r | |
424 | clearerr (uptr->fileref);\r | |
425 | return SCPE_IOERR;\r | |
426 | }\r | |
427 | return SCPE_OK;\r | |
428 | }\r | |
429 | \r | |
430 | /* Reset routine - called from SCP, flags in DIB */\r | |
431 | \r | |
432 | t_stat lps_reset (DEVICE *dptr)\r | |
433 | {\r | |
434 | lps_dib.cmd = lps_dib.ctl = 0; /* clear cmd, ctl */\r | |
435 | lps_dib.flg = lps_dib.fbf = lps_dib.srq = 1; /* set flg, fbf, srq */\r | |
436 | lps_sta = lps_unit.buf = 0;\r | |
437 | lps_power = LPS_ON; /* power is on */\r | |
438 | sim_cancel (&lps_unit); /* deactivate unit */\r | |
439 | lps_set_timing (NULL, lps_timing, NULL, NULL); /* init timing set */\r | |
440 | return SCPE_OK;\r | |
441 | }\r | |
442 | \r | |
443 | /* Restart I/O routine\r | |
444 | \r | |
445 | If I/O is started via STC, and the printer is powered off, offline,\r | |
446 | or out of paper, the CTL and CMD flip-flops will set, a service event\r | |
447 | will be scheduled, and the service routine will be entered. If\r | |
448 | STOP_IOE is not set, the I/O operation will "hang" at that point\r | |
449 | until the printer is powered on, set online, or paper is supplied\r | |
450 | (attached).\r | |
451 | \r | |
452 | If a pending operation is "hung" when this routine is called, it is\r | |
453 | restarted, which clears CTL and sets FBF and FLG, completing the\r | |
454 | original I/O request.\r | |
455 | */\r | |
456 | \r | |
457 | t_stat lps_restart (UNIT *uptr, int32 value, char *cptr, void *desc)\r | |
458 | {\r | |
459 | if (lps_dib.cmd && lps_dib.ctl && !sim_is_active (uptr))\r | |
460 | sim_activate (uptr, 0); /* reschedule I/O */\r | |
461 | return SCPE_OK;\r | |
462 | }\r | |
463 | \r | |
464 | /* Printer power off */\r | |
465 | \r | |
466 | t_stat lps_poweroff (UNIT *uptr, int32 value, char *cptr, void *desc)\r | |
467 | {\r | |
468 | lps_power = LPS_OFF; /* change state */\r | |
469 | if (DEBUG_PRS (lps_dev)) fputs (">>LPS set: Power state is OFF\n", sim_deb);\r | |
470 | return SCPE_OK;\r | |
471 | }\r | |
472 | \r | |
473 | /* Printer power on */\r | |
474 | \r | |
475 | t_stat lps_poweron (UNIT *uptr, int32 value, char *cptr, void *desc)\r | |
476 | {\r | |
477 | if (lps_unit.flags & UNIT_DIAG) { /* diag mode? */\r | |
478 | lps_power = LPS_ON; /* no delay */\r | |
479 | if (DEBUG_PRS (lps_dev))\r | |
480 | fputs (">>LPS set: Power state is ON\n", sim_deb);\r | |
481 | }\r | |
482 | else {\r | |
483 | lps_power = LPS_TURNING_ON; /* change state */\r | |
484 | lps_unit.flags |= UNIT_OFFLINE; /* set offline */\r | |
485 | sim_activate (&lps_unit, lps_rtime); /* schedule ready */\r | |
486 | if (DEBUG_PRS (lps_dev)) fprintf (sim_deb,\r | |
487 | ">>LPS set: Power state is TURNING ON, scheduled time = %d\n",\r | |
488 | lps_rtime );\r | |
489 | }\r | |
490 | return SCPE_OK;\r | |
491 | }\r | |
492 | \r | |
493 | /* Attach routine */\r | |
494 | \r | |
495 | t_stat lps_attach (UNIT *uptr, char *cptr)\r | |
496 | {\r | |
497 | lps_ccnt = lps_lcnt = 0; /* top of form */\r | |
498 | lps_restart (uptr, 0, NULL, NULL); /* restart I/O if hung */\r | |
499 | return attach_unit (uptr, cptr);\r | |
500 | }\r | |
501 | \r | |
502 | /* Set printer timing\r | |
503 | \r | |
504 | Realistic timing is factored, depending on CPU model, to account for the\r | |
505 | timing method employed by the diagnostic. */\r | |
506 | \r | |
507 | t_stat lps_set_timing (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
508 | {\r | |
509 | uint32 i, factor = 1;\r | |
510 | \r | |
511 | lps_timing = (val != 0); /* determine choice */\r | |
512 | if ((lps_timing == 0) && /* calc speed factor */\r | |
513 | (UNIT_CPU_MODEL != UNIT_1000_E) &&\r | |
514 | (UNIT_CPU_MODEL != UNIT_1000_F))\r | |
515 | factor = 4;\r | |
516 | for (i = 0; i < (sizeof (lps_timers) / sizeof (lps_timers[0])); i++)\r | |
517 | *lps_timers[i] = lps_times[lps_timing][i] / factor; /* assign times */\r | |
518 | return SCPE_OK;\r | |
519 | }\r | |
520 | \r | |
521 | /* Show printer timing */\r | |
522 | \r | |
523 | t_stat lps_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
524 | {\r | |
525 | if (lps_timing) fputs ("fast timing", st);\r | |
526 | else fputs ("realistic timing", st);\r | |
527 | return SCPE_OK;\r | |
528 | }\r |