First Commit of my working state
[simh.git] / HP2100 / hp2100_lpt.c
CommitLineData
196ba1fc
PH
1/* hp2100_lpt.c: HP 2100 12845B 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 lpt 12845B 2607 line printer\r
27\r
28 22-Jan-07 RMS Added UNIT_TEXT flag\r
29 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified)\r
30 19-Nov-04 JDB Added restart when set online, etc.\r
31 29-Sep-04 JDB Added SET OFFLINE/ONLINE, POWEROFF/POWERON\r
32 Fixed status returns for error conditions\r
33 Fixed TOF handling so form remains on line 0\r
34 03-Jun-04 RMS Fixed timing (found by Dave Bryan)\r
35 26-Apr-04 RMS Fixed SFS x,C and SFC x,C\r
36 Implemented DMA SRQ (follows FLG)\r
37 25-Apr-03 RMS Revised for extended file support\r
38 24-Oct-02 RMS Cloned from 12653A\r
39\r
40 The 2607 provides three status bits via the interface:\r
41\r
42 bit 15 -- printer ready (online)\r
43 bit 14 -- paper out\r
44 bit 0 -- printer idle\r
45\r
46 The expected status returns are:\r
47\r
48 140001 -- power off or cable disconnected\r
49 100001 -- power on, paper loaded, printer ready\r
50 100000 -- power on, paper loaded, printer busy\r
51 040000 -- power on, paper out (at bottom-of-form)\r
52 000000 -- power on, paper out (not at BOF) / print button up / platen open\r
53\r
54 Manual Note: "2-33. PAPER OUT SIGNAL. [...] The signal is asserted only\r
55 when the format tape in the line printer has reached the bottom of form."\r
56\r
57 These simulator commands provide the listed printer states:\r
58\r
59 SET LPT POWEROFF --> power off or cable disconnected\r
60 SET LPT POWERON --> power on\r
61 SET LPT OFFLINE --> print button up\r
62 SET LPT ONLINE --> print button down\r
63 ATT LPT <file> --> paper loaded\r
64 DET LPT --> paper out\r
65\r
66 Reference:\r
67 - 12845A Line Printer Operating and Service Manual (12845-90001, Aug-1972)\r
68*/\r
69\r
70#include "hp2100_defs.h"\r
71\r
72#define LPT_PAGELNT 60 /* page length */\r
73\r
74#define LPT_NBSY 0000001 /* not busy */\r
75#define LPT_PAPO 0040000 /* paper out */\r
76#define LPT_RDY 0100000 /* ready */\r
77#define LPT_PWROFF LPT_RDY | LPT_PAPO | LPT_NBSY /* power-off status */\r
78\r
79#define LPT_CTL 0100000 /* control output */\r
80#define LPT_CHAN 0000100 /* skip to chan */\r
81#define LPT_SKIPM 0000077 /* line count mask */\r
82#define LPT_CHANM 0000007 /* channel mask */\r
83\r
84#define UNIT_V_POWEROFF (UNIT_V_UF + 0) /* unit powered off */\r
85#define UNIT_V_OFFLINE (UNIT_V_UF + 1) /* unit offline */\r
86#define UNIT_POWEROFF (1 << UNIT_V_POWEROFF)\r
87#define UNIT_OFFLINE (1 << UNIT_V_OFFLINE)\r
88\r
89extern uint32 PC;\r
90extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2];\r
91\r
92int32 lpt_ctime = 4; /* char time */\r
93int32 lpt_ptime = 10000; /* print time */\r
94int32 lpt_stopioe = 0; /* stop on error */\r
95int32 lpt_lcnt = 0; /* line count */\r
96static int32 lpt_cct[8] = {\r
97 1, 1, 1, 2, 3, LPT_PAGELNT/2, LPT_PAGELNT/4, LPT_PAGELNT/6\r
98 };\r
99\r
100DEVICE lpt_dev;\r
101int32 lptio (int32 inst, int32 IR, int32 dat);\r
102t_stat lpt_svc (UNIT *uptr);\r
103t_stat lpt_reset (DEVICE *dptr);\r
104t_stat lpt_restart (UNIT *uptr, int32 value, char *cptr, void *desc);\r
105t_stat lpt_attach (UNIT *uptr, char *cptr);\r
106\r
107/* LPT data structures\r
108\r
109 lpt_dev LPT device descriptor\r
110 lpt_unit LPT unit descriptor\r
111 lpt_reg LPT register list\r
112*/\r
113\r
114DIB lpt_dib = { LPT, 0, 0, 0, 0, 0, &lptio };\r
115\r
116UNIT lpt_unit = {\r
117 UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_DISABLE+UNIT_TEXT, 0)\r
118 };\r
119\r
120REG lpt_reg[] = {\r
121 { ORDATA (BUF, lpt_unit.buf, 7) },\r
122 { FLDATA (CMD, lpt_dib.cmd, 0) },\r
123 { FLDATA (CTL, lpt_dib.ctl, 0) },\r
124 { FLDATA (FLG, lpt_dib.flg, 0) },\r
125 { FLDATA (FBF, lpt_dib.fbf, 0) },\r
126 { FLDATA (SRQ, lpt_dib.srq, 0) },\r
127 { DRDATA (LCNT, lpt_lcnt, 7) },\r
128 { DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT },\r
129 { DRDATA (CTIME, lpt_ctime, 31), PV_LEFT },\r
130 { DRDATA (PTIME, lpt_ptime, 24), PV_LEFT },\r
131 { FLDATA (STOP_IOE, lpt_stopioe, 0) },\r
132 { ORDATA (DEVNO, lpt_dib.devno, 6), REG_HRO },\r
133 { NULL }\r
134 };\r
135\r
136MTAB lpt_mod[] = {\r
137 { UNIT_POWEROFF, UNIT_POWEROFF, "power off", "POWEROFF", NULL },\r
138 { UNIT_POWEROFF, 0, "power on", "POWERON", lpt_restart },\r
139 { UNIT_OFFLINE, UNIT_OFFLINE, "offline", "OFFLINE", NULL },\r
140 { UNIT_OFFLINE, 0, "online", "ONLINE", lpt_restart },\r
141 { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",\r
142 &hp_setdev, &hp_showdev, &lpt_dev },\r
143 { 0 }\r
144 };\r
145\r
146DEVICE lpt_dev = {\r
147 "LPT", &lpt_unit, lpt_reg, lpt_mod,\r
148 1, 10, 31, 1, 8, 8,\r
149 NULL, NULL, &lpt_reset,\r
150 NULL, &lpt_attach, NULL,\r
151 &lpt_dib, DEV_DISABLE\r
152 };\r
153\r
154/* IO instructions */\r
155\r
156int32 lptio (int32 inst, int32 IR, int32 dat)\r
157{\r
158int32 dev;\r
159\r
160dev = IR & I_DEVMASK; /* get device no */\r
161switch (inst) { /* case on opcode */\r
162\r
163 case ioFLG: /* flag clear/set */\r
164 if ((IR & I_HC) == 0) { setFSR (dev); } /* STF */\r
165 break;\r
166\r
167 case ioSFC: /* skip flag clear */\r
168 if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;\r
169 break;\r
170\r
171 case ioSFS: /* skip flag set */\r
172 if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;\r
173 break;\r
174\r
175 case ioOTX: /* output */\r
176 lpt_unit.buf = dat & (LPT_CTL | 0177);\r
177 break;\r
178\r
179 case ioLIX: /* load */\r
180 dat = 0; /* default sta = 0 */\r
181 case ioMIX: /* merge */\r
182 if (lpt_unit.flags & UNIT_POWEROFF) /* power off? */\r
183 dat = dat | LPT_PWROFF;\r
184 else if (!(lpt_unit.flags & UNIT_OFFLINE)) { /* online? */\r
185 if (lpt_unit.flags & UNIT_ATT) { /* paper loaded? */\r
186 dat = dat | LPT_RDY;\r
187 if (!sim_is_active (&lpt_unit)) /* printer busy? */\r
188 dat = dat | LPT_NBSY;\r
189 }\r
190 else if (lpt_lcnt == LPT_PAGELNT - 1) /* paper out, at BOF? */\r
191 dat = dat | LPT_PAPO;\r
192 }\r
193 break;\r
194\r
195 case ioCRS: /* control reset (action unverif) */\r
196 case ioCTL: /* control clear/set */\r
197 if (IR & I_CTL) { /* CLC */\r
198 clrCMD (dev); /* clear ctl, cmd */\r
199 clrCTL (dev);\r
200 }\r
201 else { /* STC */\r
202 setCMD (dev); /* set ctl, cmd */\r
203 setCTL (dev);\r
204 sim_activate (&lpt_unit, /* schedule op */\r
205 (lpt_unit.buf & LPT_CTL)? lpt_ptime: lpt_ctime);\r
206 }\r
207 break;\r
208\r
209 default:\r
210 break;\r
211 }\r
212\r
213if (IR & I_HC) { clrFSR (dev); } /* H/C option */\r
214return dat;\r
215}\r
216\r
217/* Unit service */\r
218\r
219t_stat lpt_svc (UNIT *uptr)\r
220{\r
221int32 i, skip, chan, dev;\r
222\r
223dev = lpt_dib.devno; /* get dev no */\r
224if ((uptr->flags & UNIT_ATT) == 0) /* attached? */\r
225 return IORETURN (lpt_stopioe, SCPE_UNATT);\r
226else if (uptr->flags & UNIT_OFFLINE) /* offline? */\r
227 return IORETURN (lpt_stopioe, STOP_OFFLINE);\r
228else if (uptr->flags & UNIT_POWEROFF) /* powered off? */\r
229 return IORETURN (lpt_stopioe, STOP_PWROFF);\r
230clrCMD (dev); /* clear cmd */\r
231setFSR (dev); /* set flag, fbf */\r
232if (uptr->buf & LPT_CTL) { /* control word? */\r
233 if (uptr->buf & LPT_CHAN) {\r
234 chan = uptr->buf & LPT_CHANM;\r
235 if (chan == 0) { /* top of form? */\r
236 fputc ('\f', uptr->fileref); /* ffeed */\r
237 lpt_lcnt = 0; /* reset line cnt */\r
238 skip = 0;\r
239 }\r
240 else if (chan == 1) skip = LPT_PAGELNT - lpt_lcnt - 1;\r
241 else skip = lpt_cct[chan] - (lpt_lcnt % lpt_cct[chan]);\r
242 }\r
243 else {\r
244 skip = uptr->buf & LPT_SKIPM;\r
245 if (skip == 0) fputc ('\r', uptr->fileref);\r
246 }\r
247 for (i = 0; i < skip; i++) fputc ('\n', uptr->fileref);\r
248 lpt_lcnt = (lpt_lcnt + skip) % LPT_PAGELNT;\r
249 }\r
250else fputc (uptr->buf & 0177, uptr->fileref); /* no, just add char */\r
251if (ferror (uptr->fileref)) {\r
252 perror ("LPT I/O error");\r
253 clearerr (uptr->fileref);\r
254 return SCPE_IOERR;\r
255 }\r
256lpt_unit.pos = ftell (uptr->fileref); /* update pos */\r
257return SCPE_OK;\r
258}\r
259\r
260/* Reset routine - called from SCP, flags in DIB */\r
261\r
262t_stat lpt_reset (DEVICE *dptr)\r
263{\r
264lpt_dib.cmd = lpt_dib.ctl = 0; /* clear cmd, ctl */\r
265lpt_dib.flg = lpt_dib.fbf = lpt_dib.srq = 1; /* set flg, fbf, srq */\r
266lpt_unit.buf = 0;\r
267sim_cancel (&lpt_unit); /* deactivate unit */\r
268return SCPE_OK;\r
269}\r
270\r
271/* Restart I/O routine\r
272\r
273 If I/O is started via STC, and the printer is powered off, offline,\r
274 or out of paper, the CTL and CMD flip-flops will set, a service event\r
275 will be scheduled, and the service routine will be entered. If\r
276 STOP_IOE is not set, the I/O operation will "hang" at that point\r
277 until the printer is powered on, set online, or paper is supplied\r
278 (attached).\r
279\r
280 If a pending operation is "hung" when this routine is called, it is\r
281 restarted, which clears CTL and sets FBF and FLG, completing the\r
282 original I/O request.\r
283 */\r
284\r
285t_stat lpt_restart (UNIT *uptr, int32 value, char *cptr, void *desc)\r
286{\r
287if (lpt_dib.cmd && lpt_dib.ctl && !sim_is_active (uptr))\r
288 sim_activate (uptr, 0); /* reschedule I/O */\r
289return SCPE_OK;\r
290}\r
291\r
292/* Attach routine */\r
293\r
294t_stat lpt_attach (UNIT *uptr, char *cptr)\r
295{\r
296lpt_lcnt = 0; /* top of form */\r
297lpt_restart (uptr, 0, NULL, NULL); /* restart I/O if hung */\r
298return attach_unit (uptr, cptr);\r
299}\r