Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* pdp10_lp20.c: PDP-10 LP20 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 | lp20 line printer\r | |
27 | \r | |
28 | 19-Jan-07 RMS Added UNIT_TEXT flag\r | |
29 | 04-Sep-05 RMS Fixed missing return (found by Peter Schorn)\r | |
30 | 07-Jul-05 RMS Removed extraneous externs\r | |
31 | 18-Mar-05 RMS Added attached test to detach routine\r | |
32 | 29-Dec-03 RMS Fixed bug in scheduling\r | |
33 | 25-Apr-03 RMS Revised for extended file support\r | |
34 | 29-Sep-02 RMS Added variable vector support\r | |
35 | Modified to use common Unibus routines\r | |
36 | New data structures\r | |
37 | 30-May-02 RMS Widened POS to 32b\r | |
38 | 06-Jan-02 RMS Added enable/disable support\r | |
39 | 30-Nov-01 RMS Added extended SET/SHOW support\r | |
40 | */\r | |
41 | \r | |
42 | #include "pdp10_defs.h"\r | |
43 | \r | |
44 | #define UNIT_DUMMY (1 << UNIT_V_UF)\r | |
45 | #define LP_WIDTH 132 /* printer width */\r | |
46 | \r | |
47 | /* DAVFU RAM */\r | |
48 | \r | |
49 | #define DV_SIZE 143 /* DAVFU size */\r | |
50 | #define DV_DMASK 077 /* data mask per byte */\r | |
51 | #define DV_TOF 0 /* top of form channel */\r | |
52 | #define DV_MAX 11 /* max channel number */\r | |
53 | \r | |
54 | /* Translation RAM */\r | |
55 | \r | |
56 | #define TX_SIZE 256 /* translation RAM */\r | |
57 | #define TX_AMASK (TX_SIZE - 1)\r | |
58 | #define TX_DMASK 07777\r | |
59 | #define TX_V_FL 8 /* flags */\r | |
60 | #define TX_M_FL 017\r | |
61 | /* define TX_INTR 04000 /* interrupt */\r | |
62 | #define TX_DELH 02000 /* delimiter */\r | |
63 | /* define TX_XLAT 01000 /* translate */\r | |
64 | /* define TX_DVFU 00400 /* DAVFU */\r | |
65 | #define TX_SLEW 00020 /* chan vs slew */\r | |
66 | #define TX_VMASK 00017 /* spacing mask */\r | |
67 | #define TX_CHR 0 /* states: pr char */\r | |
68 | #define TX_RAM 1 /* pr translation */\r | |
69 | #define TX_DVU 2 /* DAVFU action */\r | |
70 | #define TX_INT 3 /* interrupt */\r | |
71 | #define TX_GETFL(x) (((x) >> TX_V_FL) & TX_M_FL)\r | |
72 | \r | |
73 | /* LPCSRA (765400) */\r | |
74 | \r | |
75 | #define CSA_GO 0000001 /* go */\r | |
76 | #define CSA_PAR 0000002 /* parity enable NI */\r | |
77 | #define CSA_V_FNC 2 /* function */\r | |
78 | #define CSA_M_FNC 03\r | |
79 | #define FNC_PR 0 /* print */\r | |
80 | #define FNC_TST 1 /* test */\r | |
81 | #define FNC_DVU 2 /* load DAVFU */\r | |
82 | #define FNC_RAM 3 /* load translation RAM */\r | |
83 | #define FNC_INTERNAL 1 /* internal function */\r | |
84 | #define CSA_FNC (CSA_M_FNC << CSA_V_FNC)\r | |
85 | #define CSA_V_UAE 4 /* Unibus addr extension */\r | |
86 | #define CSA_UAE (03 << CSA_V_UAE)\r | |
87 | #define CSA_IE 0000100 /* interrupt enable */\r | |
88 | #define CSA_DONE 0000200 /* done */\r | |
89 | #define CSA_INIT 0000400 /* init */\r | |
90 | #define CSA_ECLR 0001000 /* clear errors */\r | |
91 | #define CSA_DELH 0002000 /* delimiter hold */\r | |
92 | #define CSA_ONL 0004000 /* online */\r | |
93 | #define CSA_DVON 0010000 /* DAVFU online */\r | |
94 | #define CSA_UNDF 0020000 /* undefined char */\r | |
95 | #define CSA_PZRO 0040000 /* page counter zero */\r | |
96 | #define CSA_ERR 0100000 /* error */\r | |
97 | #define CSA_RW (CSA_DELH | CSA_IE | CSA_UAE | CSA_FNC | CSA_PAR | CSA_GO)\r | |
98 | #define CSA_MBZ (CSA_ECLR | CSA_INIT)\r | |
99 | #define CSA_GETUAE(x) (((x) & CSA_UAE) << (16 - CSA_V_UAE))\r | |
100 | #define CSA_GETFNC(x) (((x) >> CSA_V_FNC) & CSA_M_FNC)\r | |
101 | \r | |
102 | /* LPCSRB (765402) */\r | |
103 | \r | |
104 | #define CSB_GOE 0000001 /* go error */\r | |
105 | #define CSB_DTE 0000002 /* DEM timing error NI */\r | |
106 | #define CSB_MTE 0000004 /* MSYN error (Ubus timeout) */\r | |
107 | #define CSB_RPE 0000010 /* RAM parity error NI */\r | |
108 | #define CSB_MPE 0000020 /* MEM parity error NI */\r | |
109 | #define CSB_LPE 0000040 /* LPT parity error NI */\r | |
110 | #define CSB_DVOF 0000100 /* DAVFU not ready */\r | |
111 | #define CSB_OFFL 0000200 /* offline */\r | |
112 | #define CSB_TEST 0003400 /* test mode */\r | |
113 | #define CSB_OVFU 0004000 /* optical VFU NI */\r | |
114 | #define CSB_PBIT 0010000 /* data parity bit NI */\r | |
115 | #define CSB_NRDY 0020000 /* printer error NI */\r | |
116 | #define CSB_LA180 0040000 /* LA180 printer NI */\r | |
117 | #define CSB_VLD 0100000 /* valid data NI */\r | |
118 | #define CSB_ECLR (CSB_GOE | CSB_DTE | CSB_MTE | CSB_RPE | CSB_MPE | CSB_LPE)\r | |
119 | #define CSB_ERR (CSB_ECLR | CSB_DVOF | CSB_OFFL)\r | |
120 | #define CSB_RW CSB_TEST\r | |
121 | #define CSB_MBZ (CSB_DTE | CSB_RPE | CSB_MPE | CSB_LPE | CSB_OVFU |\\r | |
122 | CSB_PBIT | CSB_NRDY | CSB_LA180 | CSB_VLD)\r | |
123 | \r | |
124 | /* LPBA (765404) */\r | |
125 | \r | |
126 | /* LPBC (765506) */\r | |
127 | \r | |
128 | #define BC_MASK 0007777 /* <15:12> MBZ */\r | |
129 | \r | |
130 | /* LPPAGC (765510) */\r | |
131 | \r | |
132 | #define PAGC_MASK 0007777 /* <15:12> MBZ */\r | |
133 | \r | |
134 | /* LPRDAT (765512) */\r | |
135 | \r | |
136 | #define RDAT_MASK 0007777 /* <15:12> MBZ */\r | |
137 | \r | |
138 | /* LPCOLC/LPCBUF (765514) */\r | |
139 | \r | |
140 | /* LPCSUM/LPPDAT (765516) */\r | |
141 | \r | |
142 | extern d10 *M; /* main memory */\r | |
143 | extern int32 int_req;\r | |
144 | \r | |
145 | int32 lpcsa = 0; /* control/status A */\r | |
146 | int32 lpcsb = 0; /* control/status B */\r | |
147 | int32 lpba = 0; /* bus address */\r | |
148 | int32 lpbc = 0; /* byte count */\r | |
149 | int32 lppagc = 0; /* page count */\r | |
150 | int32 lprdat = 0; /* RAM data */\r | |
151 | int32 lpcbuf = 0; /* character buffer */\r | |
152 | int32 lpcolc = 0; /* column count */\r | |
153 | int32 lppdat = 0; /* printer data */\r | |
154 | int32 lpcsum = 0; /* checksum */\r | |
155 | int32 dvptr = 0; /* davfu pointer */\r | |
156 | int32 dvlnt = 0; /* davfu length */\r | |
157 | int32 lp20_irq = 0; /* int request */\r | |
158 | int32 lp20_stopioe = 0; /* stop on error */\r | |
159 | int16 txram[TX_SIZE] = { 0 }; /* translation RAM */\r | |
160 | int16 davfu[DV_SIZE] = { 0 }; /* DAVFU */\r | |
161 | \r | |
162 | DEVICE lp20_dev;\r | |
163 | t_stat lp20_rd (int32 *data, int32 pa, int32 access);\r | |
164 | t_stat lp20_wr (int32 data, int32 pa, int32 access);\r | |
165 | int32 lp20_inta (void);\r | |
166 | t_stat lp20_svc (UNIT *uptr);\r | |
167 | t_stat lp20_reset (DEVICE *dptr);\r | |
168 | t_stat lp20_attach (UNIT *uptr, char *ptr);\r | |
169 | t_stat lp20_detach (UNIT *uptr);\r | |
170 | t_stat lp20_clear_vfu (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
171 | t_bool lp20_print (int32 c);\r | |
172 | t_bool lp20_adv (int32 c, t_bool advdvu);\r | |
173 | t_bool lp20_davfu (int32 c);\r | |
174 | void update_lpcs (int32 flg);\r | |
175 | \r | |
176 | /* LP data structures\r | |
177 | \r | |
178 | lp20_dev LPT device descriptor\r | |
179 | lp20_unit LPT unit descriptor\r | |
180 | lp20_reg LPT register list\r | |
181 | */\r | |
182 | \r | |
183 | DIB lp20_dib = {\r | |
184 | IOBA_LP20, IOLN_LP20, &lp20_rd, &lp20_wr,\r | |
185 | 1, IVCL (LP20), VEC_LP20, { &lp20_inta }\r | |
186 | };\r | |
187 | \r | |
188 | UNIT lp20_unit = {\r | |
189 | UDATA (&lp20_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT\r | |
190 | };\r | |
191 | \r | |
192 | REG lp20_reg[] = {\r | |
193 | { ORDATA (LPCSA, lpcsa, 16) },\r | |
194 | { ORDATA (LPCSB, lpcsb, 16) },\r | |
195 | { ORDATA (LPBA, lpba, 16) },\r | |
196 | { ORDATA (LPBC, lpbc, 12) },\r | |
197 | { ORDATA (LPPAGC, lppagc, 12) },\r | |
198 | { ORDATA (LPRDAT, lprdat, 12) },\r | |
199 | { ORDATA (LPCBUF, lpcbuf, 8) },\r | |
200 | { ORDATA (LPCOLC, lpcolc, 8) },\r | |
201 | { ORDATA (LPPDAT, lppdat, 8) },\r | |
202 | { ORDATA (LPCSUM, lpcsum, 8) },\r | |
203 | { ORDATA (DVPTR, dvptr, 7) },\r | |
204 | { ORDATA (DVLNT, dvlnt, 7), REG_RO + REG_NZ },\r | |
205 | { FLDATA (INT, int_req, INT_V_LP20) },\r | |
206 | { FLDATA (IRQ, lp20_irq, 0) },\r | |
207 | { FLDATA (ERR, lpcsa, CSR_V_ERR) },\r | |
208 | { FLDATA (DONE, lpcsa, CSR_V_DONE) },\r | |
209 | { FLDATA (IE, lpcsa, CSR_V_IE) },\r | |
210 | { DRDATA (POS, lp20_unit.pos, T_ADDR_W), PV_LEFT },\r | |
211 | { DRDATA (TIME, lp20_unit.wait, 24), PV_LEFT },\r | |
212 | { FLDATA (STOP_IOE, lp20_stopioe, 0) },\r | |
213 | { BRDATA (TXRAM, txram, 8, 12, TX_SIZE) },\r | |
214 | { BRDATA (DAVFU, davfu, 8, 12, DV_SIZE) },\r | |
215 | { ORDATA (DEVADDR, lp20_dib.ba, 32), REG_HRO },\r | |
216 | { ORDATA (DEVVEC, lp20_dib.vec, 16), REG_HRO },\r | |
217 | { NULL }\r | |
218 | };\r | |
219 | \r | |
220 | MTAB lp20_mod[] = {\r | |
221 | { UNIT_DUMMY, 0, NULL, "VFUCLEAR", &lp20_clear_vfu },\r | |
222 | { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",\r | |
223 | &set_addr, &show_addr, NULL },\r | |
224 | { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",\r | |
225 | &set_vec, &show_vec, NULL },\r | |
226 | { 0 }\r | |
227 | };\r | |
228 | \r | |
229 | DEVICE lp20_dev = {\r | |
230 | "LP20", &lp20_unit, lp20_reg, lp20_mod,\r | |
231 | 1, 10, 31, 1, 8, 8,\r | |
232 | NULL, NULL, &lp20_reset,\r | |
233 | NULL, &lp20_attach, &lp20_detach,\r | |
234 | &lp20_dib, DEV_DISABLE | DEV_UBUS\r | |
235 | };\r | |
236 | \r | |
237 | /* Line printer routines\r | |
238 | \r | |
239 | lp20_rd I/O page read\r | |
240 | lp20_wr I/O page write\r | |
241 | lp20_svc process event (printer ready)\r | |
242 | lp20_reset process reset\r | |
243 | lp20_attach process attach\r | |
244 | lp20_detach process detach\r | |
245 | */\r | |
246 | \r | |
247 | t_stat lp20_rd (int32 *data, int32 pa, int32 access)\r | |
248 | {\r | |
249 | update_lpcs (0); /* update csr's */\r | |
250 | switch ((pa >> 1) & 07) { /* case on PA<3:1> */\r | |
251 | \r | |
252 | case 00: /* LPCSA */\r | |
253 | *data = lpcsa = lpcsa & ~CSA_MBZ;\r | |
254 | break;\r | |
255 | \r | |
256 | case 01: /* LPCSB */\r | |
257 | *data = lpcsb = lpcsb & ~CSB_MBZ;\r | |
258 | break;\r | |
259 | \r | |
260 | case 02: /* LPBA */\r | |
261 | *data = lpba;\r | |
262 | break;\r | |
263 | \r | |
264 | case 03: /* LPBC */\r | |
265 | *data = lpbc = lpbc & BC_MASK;\r | |
266 | break;\r | |
267 | \r | |
268 | case 04: /* LPPAGC */\r | |
269 | *data = lppagc = lppagc & PAGC_MASK;\r | |
270 | break;\r | |
271 | \r | |
272 | case 05: /* LPRDAT */\r | |
273 | *data = lprdat = lprdat & RDAT_MASK;\r | |
274 | break;\r | |
275 | \r | |
276 | case 06: /* LPCOLC/LPCBUF */\r | |
277 | *data = (lpcolc << 8) | lpcbuf;\r | |
278 | break;\r | |
279 | \r | |
280 | case 07: /* LPCSUM/LPPDAT */\r | |
281 | *data = (lpcsum << 8) | lppdat;\r | |
282 | break;\r | |
283 | } /* end case PA */\r | |
284 | \r | |
285 | return SCPE_OK;\r | |
286 | }\r | |
287 | \r | |
288 | t_stat lp20_wr (int32 data, int32 pa, int32 access)\r | |
289 | {\r | |
290 | update_lpcs (0); /* update csr's */\r | |
291 | switch ((pa >> 1) & 07) { /* case on PA<3:1> */\r | |
292 | \r | |
293 | case 00: /* LPCSA */\r | |
294 | if (access == WRITEB) data = (pa & 1)?\r | |
295 | (lpcsa & 0377) | (data << 8): (lpcsa & ~0377) | data;\r | |
296 | if (data & CSA_ECLR) { /* error clear? */\r | |
297 | lpcsa = (lpcsa | CSA_DONE) & ~CSA_GO; /* set done, clr go */\r | |
298 | lpcsb = lpcsb & ~CSB_ECLR; /* clear err */\r | |
299 | sim_cancel (&lp20_unit); /* cancel I/O */\r | |
300 | }\r | |
301 | if (data & CSA_INIT) lp20_reset (&lp20_dev); /* init? */\r | |
302 | if (data & CSA_GO) { /* go set? */\r | |
303 | if ((lpcsa & CSA_GO) == 0) { /* not set before? */\r | |
304 | if (lpcsb & CSB_ERR) lpcsb = lpcsb | CSB_GOE;\r | |
305 | lpcsum = 0; /* clear checksum */\r | |
306 | sim_activate (&lp20_unit, lp20_unit.wait);\r | |
307 | }\r | |
308 | }\r | |
309 | else sim_cancel (&lp20_unit); /* go clr, stop DMA */\r | |
310 | lpcsa = (lpcsa & ~CSA_RW) | (data & CSA_RW);\r | |
311 | break;\r | |
312 | \r | |
313 | case 01: /* LPCSB */\r | |
314 | break; /* ignore writes to TEST */\r | |
315 | \r | |
316 | case 02: /* LPBA */\r | |
317 | if (access == WRITEB) data = (pa & 1)?\r | |
318 | (lpba & 0377) | (data << 8): (lpba & ~0377) | data;\r | |
319 | lpba = data;\r | |
320 | break;\r | |
321 | \r | |
322 | case 03: /* LPBC */\r | |
323 | if (access == WRITEB) data = (pa & 1)?\r | |
324 | (lpbc & 0377) | (data << 8): (lpbc & ~0377) | data;\r | |
325 | lpbc = data & BC_MASK;\r | |
326 | lpcsa = lpcsa & ~CSA_DONE;\r | |
327 | break;\r | |
328 | \r | |
329 | case 04: /* LPPAGC */\r | |
330 | if (access == WRITEB) data = (pa & 1)?\r | |
331 | (lppagc & 0377) | (data << 8): (lppagc & ~0377) | data;\r | |
332 | lppagc = data & PAGC_MASK;\r | |
333 | break;\r | |
334 | \r | |
335 | case 05: /* LPRDAT */\r | |
336 | if (access == WRITEB) data = (pa & 1)?\r | |
337 | (lprdat & 0377) | (data << 8): (lprdat & ~0377) | data;\r | |
338 | lprdat = data & RDAT_MASK;\r | |
339 | txram[lpcbuf & TX_AMASK] = lprdat; /* load RAM */\r | |
340 | break;\r | |
341 | \r | |
342 | case 06: /* LPCOLC/LPCBUF */\r | |
343 | if ((access == WRITEB) && (pa & 1)) /* odd byte */\r | |
344 | lpcolc = data & 0377;\r | |
345 | else {\r | |
346 | lpcbuf = data & 0377; /* even byte, word */\r | |
347 | if (access == WRITE) lpcolc = (data >> 8) & 0377;\r | |
348 | }\r | |
349 | break;\r | |
350 | \r | |
351 | case 07: /* LPCSUM/LPPDAT */\r | |
352 | break; /* read only */\r | |
353 | } /* end case PA */\r | |
354 | \r | |
355 | update_lpcs (0);\r | |
356 | return SCPE_OK;\r | |
357 | }\r | |
358 | \r | |
359 | /* Line printer service\r | |
360 | \r | |
361 | The translation RAM case table is derived from the LP20 spec and\r | |
362 | verified against the LP20 RAM simulator in TOPS10 7.04 LPTSPL.\r | |
363 | The equations are:\r | |
364 | \r | |
365 | flags := inter, delim, xlate, paper, delim_hold (from CSRA)\r | |
366 | actions : = print_input, print_xlate, davfu_action, interrupt\r | |
367 | \r | |
368 | if (inter) {\r | |
369 | if (!xlate || delim || delim_hold) interrupt;\r | |
370 | else if (paper) davfu_action;\r | |
371 | else print_xlate;\r | |
372 | }\r | |
373 | else if (paper) {\r | |
374 | if (xlate || delim || delim_hold) davfu_action;\r | |
375 | else print_input;\r | |
376 | }\r | |
377 | else {\r | |
378 | if (xlate || delim || delim_hold) print_xlate;\r | |
379 | else print_input;\r | |
380 | }\r | |
381 | */\r | |
382 | \r | |
383 | t_stat lp20_svc (UNIT *uptr)\r | |
384 | {\r | |
385 | int32 fnc, i, tbc, temp, txst;\r | |
386 | int32 dvld = -2; /* must be even */\r | |
387 | uint16 wd10;\r | |
388 | t_bool cont;\r | |
389 | a10 ba;\r | |
390 | \r | |
391 | static const uint32 txcase[32] = {\r | |
392 | TX_CHR, TX_RAM, TX_CHR, TX_DVU, TX_RAM, TX_RAM, TX_DVU, TX_DVU,\r | |
393 | TX_RAM, TX_RAM, TX_DVU, TX_DVU, TX_RAM, TX_RAM, TX_DVU, TX_DVU,\r | |
394 | TX_INT, TX_INT, TX_INT, TX_INT, TX_RAM, TX_INT, TX_DVU, TX_INT,\r | |
395 | TX_INT, TX_INT, TX_INT, TX_INT, TX_INT, TX_INT, TX_INT, TX_INT\r | |
396 | };\r | |
397 | \r | |
398 | lpcsa = lpcsa & ~CSA_GO;\r | |
399 | ba = CSA_GETUAE (lpcsa) | lpba;\r | |
400 | fnc = CSA_GETFNC (lpcsa);\r | |
401 | tbc = 010000 - lpbc;\r | |
402 | if (((fnc & FNC_INTERNAL) == 0) && ((lp20_unit.flags & UNIT_ATT) == 0)) {\r | |
403 | update_lpcs (CSA_ERR);\r | |
404 | return IORETURN (lp20_stopioe, SCPE_UNATT);\r | |
405 | }\r | |
406 | if ((fnc == FNC_PR) && (dvlnt == 0)) {\r | |
407 | update_lpcs (CSA_ERR);\r | |
408 | return SCPE_OK;\r | |
409 | }\r | |
410 | \r | |
411 | for (i = 0, cont = TRUE; (i < tbc) && cont; ba++, i++) {\r | |
412 | if (Map_ReadW (ba, 2, &wd10)) { /* get word, err? */\r | |
413 | lpcsb = lpcsb | CSB_MTE; /* set NXM error */\r | |
414 | update_lpcs (CSA_ERR); /* set done */\r | |
415 | break;\r | |
416 | }\r | |
417 | lpcbuf = (wd10 >> ((ba & 1)? 8: 0)) & 0377; /* get character */\r | |
418 | lpcsum = (lpcsum + lpcbuf) & 0377; /* add into checksum */\r | |
419 | switch (fnc) { /* switch on function */\r | |
420 | \r | |
421 | /* Translation RAM load */\r | |
422 | \r | |
423 | case FNC_RAM: /* RAM load */\r | |
424 | txram[(i >> 1) & TX_AMASK] = wd10 & TX_DMASK;\r | |
425 | break;\r | |
426 | \r | |
427 | /* DAVFU RAM load. The DAVFU RAM is actually loaded in bytes, delimited by\r | |
428 | a start (354 to 356) and stop (357) byte pair. If the number of bytes \r | |
429 | loaded is odd, or no bytes are loaded, the DAVFU is invalid.\r | |
430 | */\r | |
431 | \r | |
432 | case FNC_DVU: /* DVU load */\r | |
433 | if ((lpcbuf >= 0354) && (lpcbuf <= 0356)) /* start DVU load? */\r | |
434 | dvld = dvlnt = 0; /* reset lnt */\r | |
435 | else if (lpcbuf == 0357) { /* stop DVU load? */\r | |
436 | dvptr = 0; /* reset ptr */\r | |
437 | if (dvld & 1) dvlnt = 0; /* if odd, invalid */\r | |
438 | }\r | |
439 | else if (dvld == 0) { /* even state? */\r | |
440 | temp = lpcbuf & DV_DMASK;\r | |
441 | dvld = 1;\r | |
442 | }\r | |
443 | else if (dvld == 1) { /* odd state? */\r | |
444 | if (dvlnt < DV_SIZE) davfu[dvlnt++] = \r | |
445 | temp | ((lpcbuf & DV_DMASK) << 6);\r | |
446 | dvld = 0;\r | |
447 | }\r | |
448 | break;\r | |
449 | \r | |
450 | /* Print characters */\r | |
451 | \r | |
452 | case FNC_PR: /* print */\r | |
453 | lprdat = txram[lpcbuf]; /* get RAM char */\r | |
454 | txst = (TX_GETFL (lprdat) << 1) | /* get state */\r | |
455 | ((lpcsa & CSA_DELH)? 1: 0); /* plus delim hold */ \r | |
456 | if (lprdat & TX_DELH) lpcsa = lpcsa | CSA_DELH;\r | |
457 | else lpcsa = lpcsa & ~CSA_DELH;\r | |
458 | lpcsa = lpcsa & ~CSA_UNDF; /* assume char ok */\r | |
459 | switch (txcase[txst]) { /* case on state */\r | |
460 | \r | |
461 | case TX_CHR: /* take char */\r | |
462 | cont = lp20_print (lpcbuf);\r | |
463 | break;\r | |
464 | \r | |
465 | case TX_RAM: /* take translation */\r | |
466 | cont = lp20_print (lprdat);\r | |
467 | break;\r | |
468 | \r | |
469 | case TX_DVU: /* DAVFU action */\r | |
470 | if (lprdat & TX_SLEW)\r | |
471 | cont = lp20_adv (lprdat & TX_VMASK, TRUE);\r | |
472 | else cont = lp20_davfu (lprdat & TX_VMASK);\r | |
473 | break;\r | |
474 | \r | |
475 | case TX_INT: /* interrupt */\r | |
476 | lpcsa = lpcsa | CSA_UNDF; /* set flag */\r | |
477 | cont = FALSE; /* force stop */\r | |
478 | break;\r | |
479 | } /* end case char state */\r | |
480 | break;\r | |
481 | \r | |
482 | case FNC_TST: /* test */\r | |
483 | break;\r | |
484 | } /* end case function */\r | |
485 | } /* end for */\r | |
486 | lpba = ba & 0177777;\r | |
487 | lpcsa = (lpcsa & ~CSA_UAE) | ((ba >> (16 - CSA_V_UAE)) & CSA_UAE);\r | |
488 | lpbc = (lpbc + i) & BC_MASK;\r | |
489 | if (lpbc) update_lpcs (CSA_MBZ); /* intr, but not done */\r | |
490 | else update_lpcs (CSA_DONE); /* intr and done */\r | |
491 | if ((fnc == FNC_PR) && ferror (lp20_unit.fileref)) {\r | |
492 | perror ("LP I/O error");\r | |
493 | clearerr (uptr->fileref);\r | |
494 | return SCPE_IOERR;\r | |
495 | }\r | |
496 | return SCPE_OK;\r | |
497 | }\r | |
498 | \r | |
499 | /* Print routines\r | |
500 | \r | |
501 | lp20_print print a character\r | |
502 | lp20_adv advance n lines\r | |
503 | lp20_davfu advance to channel on VFU\r | |
504 | \r | |
505 | Return TRUE to continue printing, FALSE to stop\r | |
506 | */\r | |
507 | \r | |
508 | t_bool lp20_print (int32 c)\r | |
509 | {\r | |
510 | t_bool r = TRUE;\r | |
511 | int32 i, rpt = 1;\r | |
512 | \r | |
513 | lppdat = c & 0177; /* mask char to 7b */\r | |
514 | if (lppdat == 000) return TRUE; /* NUL? no op */\r | |
515 | if (lppdat == 012) return lp20_adv (1, TRUE); /* LF? adv carriage */\r | |
516 | if (lppdat == 014) return lp20_davfu (DV_TOF); /* FF? top of form */\r | |
517 | if (lppdat == 015) lpcolc = 0; /* CR? reset col cntr */\r | |
518 | else if (lppdat == 011) { /* TAB? simulate */\r | |
519 | lppdat = ' '; /* with spaces */\r | |
520 | if (lpcolc >= 128) {\r | |
521 | r = lp20_adv (1, TRUE); /* eol? adv carriage */\r | |
522 | rpt = 8; /* adv to col 9 */\r | |
523 | }\r | |
524 | else rpt = 8 - (lpcolc & 07); /* else adv 1 to 8 */\r | |
525 | } \r | |
526 | else {\r | |
527 | if (lppdat < 040) lppdat = ' '; /* cvt non-prnt to spc */\r | |
528 | if (lpcolc >= LP_WIDTH) /* line full? */\r | |
529 | r = lp20_adv (1, TRUE); /* adv carriage */\r | |
530 | }\r | |
531 | for (i = 0; i < rpt; i++)\r | |
532 | fputc (lppdat, lp20_unit.fileref); \r | |
533 | lp20_unit.pos = ftell (lp20_unit.fileref);\r | |
534 | lpcolc = lpcolc + rpt;\r | |
535 | return r;\r | |
536 | }\r | |
537 | \r | |
538 | t_bool lp20_adv (int32 cnt, t_bool dvuadv)\r | |
539 | {\r | |
540 | int32 i;\r | |
541 | \r | |
542 | if (cnt == 0) return TRUE;\r | |
543 | lpcolc = 0; /* reset col cntr */\r | |
544 | for (i = 0; i < cnt; i++)\r | |
545 | fputc ('\n', lp20_unit.fileref);\r | |
546 | lp20_unit.pos = ftell (lp20_unit.fileref); /* print 'n' newlines */\r | |
547 | if (dvuadv) dvptr = (dvptr + cnt) % dvlnt; /* update DAVFU ptr */\r | |
548 | if (davfu[dvptr] & (1 << DV_TOF)) { /* at top of form? */\r | |
549 | if (lppagc = (lppagc - 1) & PAGC_MASK) { /* decr page cntr */\r | |
550 | lpcsa = lpcsa & ~CSA_PZRO; /* update status */\r | |
551 | return TRUE;\r | |
552 | }\r | |
553 | else {\r | |
554 | lpcsa = lpcsa | CSA_PZRO; /* stop if zero */\r | |
555 | return FALSE;\r | |
556 | }\r | |
557 | }\r | |
558 | return TRUE;\r | |
559 | }\r | |
560 | \r | |
561 | t_bool lp20_davfu (int32 cnt)\r | |
562 | {\r | |
563 | int i;\r | |
564 | \r | |
565 | if (cnt > DV_MAX) cnt = 7; /* inval chan? */\r | |
566 | for (i = 0; i < dvlnt; i++) { /* search DAVFU */\r | |
567 | dvptr = dvptr + 1; /* adv DAVFU ptr */\r | |
568 | if (dvptr >= dvlnt) dvptr = 0; /* wrap at end */\r | |
569 | if (davfu[dvptr] & (1 << cnt)) { /* channel stop set? */\r | |
570 | if (cnt) return lp20_adv (i + 1, FALSE); /* ~TOF, adv */\r | |
571 | if (lpcolc) lp20_adv (1, FALSE); /* TOF, need newline? */\r | |
572 | fputc ('\f', lp20_unit.fileref); /* print form feed */\r | |
573 | lp20_unit.pos = ftell (lp20_unit.fileref); \r | |
574 | if (lppagc = (lppagc - 1) & PAGC_MASK) { /* decr page cntr */\r | |
575 | lpcsa = lpcsa & ~CSA_PZRO; /* update status */\r | |
576 | return TRUE;\r | |
577 | }\r | |
578 | else {\r | |
579 | lpcsa = lpcsa | CSA_PZRO; /* stop if zero */\r | |
580 | return FALSE;\r | |
581 | }\r | |
582 | }\r | |
583 | } /* end for */\r | |
584 | dvlnt = 0; /* DAVFU error */\r | |
585 | return FALSE;\r | |
586 | }\r | |
587 | \r | |
588 | /* Update LPCSA, optionally request interrupt */\r | |
589 | \r | |
590 | void update_lpcs (int32 flg)\r | |
591 | {\r | |
592 | if (flg) lp20_irq = 1; /* set int req */\r | |
593 | lpcsa = (lpcsa | flg) & ~(CSA_MBZ | CSA_ERR | CSA_ONL | CSA_DVON);\r | |
594 | lpcsb = (lpcsb | CSB_OFFL | CSB_DVOF) & ~CSB_MBZ;\r | |
595 | if (lp20_unit.flags & UNIT_ATT) {\r | |
596 | lpcsa = lpcsa | CSA_ONL;\r | |
597 | lpcsb = lpcsb & ~CSB_OFFL;\r | |
598 | }\r | |
599 | else lpcsa = lpcsa & ~CSA_DONE;\r | |
600 | if (dvlnt) {\r | |
601 | lpcsa = lpcsa | CSA_DVON;\r | |
602 | lpcsb = lpcsb & ~CSB_DVOF;\r | |
603 | }\r | |
604 | if (lpcsb & CSB_ERR) lpcsa = lpcsa | CSA_ERR;\r | |
605 | if ((lpcsa & CSA_IE) && lp20_irq) int_req = int_req | INT_LP20;\r | |
606 | else int_req = int_req & ~INT_LP20;\r | |
607 | return;\r | |
608 | }\r | |
609 | \r | |
610 | /* Acknowledge interrupt (clear internal request) */\r | |
611 | \r | |
612 | int32 lp20_inta (void)\r | |
613 | {\r | |
614 | lp20_irq = 0; /* clear int req */\r | |
615 | return lp20_dib.vec;\r | |
616 | }\r | |
617 | \r | |
618 | t_stat lp20_reset (DEVICE *dptr)\r | |
619 | {\r | |
620 | lpcsa = CSA_DONE;\r | |
621 | lpcsb = 0;\r | |
622 | lpba = lpbc = lppagc = lpcolc = 0; /* clear registers */\r | |
623 | lprdat = lppdat = lpcbuf = lpcsum = 0;\r | |
624 | lp20_irq = 0; /* clear int req */\r | |
625 | dvptr = 0; /* reset davfu ptr */\r | |
626 | sim_cancel (&lp20_unit); /* deactivate unit */\r | |
627 | update_lpcs (0); /* update status */\r | |
628 | return SCPE_OK;\r | |
629 | }\r | |
630 | \r | |
631 | t_stat lp20_attach (UNIT *uptr, char *cptr)\r | |
632 | {\r | |
633 | t_stat reason;\r | |
634 | \r | |
635 | reason = attach_unit (uptr, cptr); /* attach file */\r | |
636 | if (lpcsa & CSA_ONL) return reason; /* just file chg? */\r | |
637 | if (sim_is_active (&lp20_unit)) update_lpcs (0); /* busy? no int */\r | |
638 | else update_lpcs (CSA_MBZ); /* interrupt */\r | |
639 | return reason;\r | |
640 | }\r | |
641 | \r | |
642 | t_stat lp20_detach (UNIT *uptr)\r | |
643 | {\r | |
644 | t_stat reason;\r | |
645 | \r | |
646 | if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */\r | |
647 | reason = detach_unit (uptr);\r | |
648 | sim_cancel (&lp20_unit);\r | |
649 | lpcsa = lpcsa & ~CSA_GO;\r | |
650 | update_lpcs (CSA_MBZ);\r | |
651 | return reason;\r | |
652 | }\r | |
653 | \r | |
654 | t_stat lp20_clear_vfu (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
655 | {\r | |
656 | int i;\r | |
657 | \r | |
658 | if (!get_yn ("Clear DAVFU? [N]", FALSE)) return SCPE_OK;\r | |
659 | for (i = 0; i < DV_SIZE; i++) davfu[i] = 0;\r | |
660 | dvlnt = dvptr = 0;\r | |
661 | update_lpcs (0);\r | |
662 | return SCPE_OK;\r | |
663 | }\r |