1 /* s3_lp.c: IBM 1403 line printer simulator
3 Copyright (c) 2001-2005, Charles E. Owen
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 Charles E. Owen 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 Charles E. Owen.
28 25-Apr-03 RMS Revised for extended file support
29 08-Oct-02 RMS Added impossible function catcher
35 extern char bcd_to_ascii
[64];
36 extern int32 iochk
, ind
[64];
37 int32 cct
[CCT_LNT
] = { 03 };
38 int32 cctlnt
= 66, cctptr
= 0, lines
= 0, lflag
= 0;
39 t_stat
lpt_reset (DEVICE
*dptr
);
40 t_stat
lpt_attach (UNIT
*uptr
, char *cptr
);
41 t_stat
write_line (int32 ilnt
, int32 mod
);
42 t_stat
space (int32 lines
, int32 lflag
);
43 t_stat
carriage_control (int32 action
, int32 mod
);
44 extern unsigned char ebcdic_to_ascii
[256];
46 #define UNIT_V_PCHAIN (UNIT_V_UF + 0)
47 #define UNIT_M_PCHAIN 03
48 #define M_UCS 00 /* Universal */
49 #define M_PCF 00 /* full */
50 #define M_PCA 01 /* business */
51 #define M_PCH 02 /* Fortran */
52 #define UNIT_PCHAIN (UNIT_M_PCHAIN << UNIT_V_PCHAIN)
53 #define UCS (M_UCS << UNIT_V_PCHAIN)
54 #define PCF (M_PCF << UNIT_V_PCHAIN)
55 #define PCA (M_PCA << UNIT_V_PCHAIN)
56 #define PCH (M_PCH << UNIT_V_PCHAIN)
57 #define GET_PCHAIN(x) (((x) >> UNIT_V_PCHAIN) & UNIT_M_PCHAIN)
58 #define CHP(ch,val) ((val) & (1 << (ch)))
60 int32 LPDAR
; /* Data Address */
61 int32 LPFLR
; /* Forms Length */
62 int32 LPIAR
; /* Image address */
63 int32 linectr
; /* current line # */
68 /* LPT data structures
70 lpt_dev LPT device descriptor
71 lpt_unit LPT unit descriptor
72 lpt_reg LPT register list
75 UNIT lpt_unit
= { UDATA (NULL
, UNIT_SEQ
+UNIT_ATTABLE
, 0) };
78 { FLDATA (ERR
, lpterror
, 0) },
79 { HRDATA (LPDAR
, LPDAR
, 16) },
80 { HRDATA (LPFLR
, LPFLR
, 8) },
81 { HRDATA (LPIAR
, LPIAR
, 16) },
82 { DRDATA (LINECT
, linectr
, 8) },
83 { DRDATA (POS
, lpt_unit
.pos
, T_ADDR_W
), PV_LEFT
},
84 { BRDATA (CCT
, cct
, 8, 32, CCT_LNT
) },
85 { DRDATA (LINES
, lines
, 8), PV_LEFT
},
86 { DRDATA (CCTP
, cctptr
, 8), PV_LEFT
},
87 { DRDATA (CCTL
, cctlnt
, 8), REG_RO
+ PV_LEFT
},
88 { GRDATA (CHAIN
, lpt_unit
.flags
, 10, 2, UNIT_V_PCHAIN
), REG_HRO
},
93 { UNIT_PCHAIN
, UCS
, "UCS", "UCS", NULL
},
94 { UNIT_PCHAIN
, PCA
, "A chain", "PCA", NULL
},
95 { UNIT_PCHAIN
, PCH
, "H chain", "PCH", NULL
},
100 "LPT", &lpt_unit
, lpt_reg
, lpt_mod
,
102 NULL
, NULL
, &lpt_reset
,
107 /* -------------------------------------------------------------------- */
109 /* Printer: master routine */
111 int32
lpt (int32 op
, int32 m
, int32 n
, int32 data
)
115 case 0: /* SIO 1403 */
119 case 0x00: /* Spacing only */
120 if (data
> 0 && data
< 4)
121 iodata
= carriage_control(2, data
);
123 case 0x02: /* Print & space */
124 iodata
= write_line(0, 0);
125 if (data
> 3) data
= 0;
126 if (iodata
== SCPE_OK
)
127 iodata
= carriage_control(2, data
);
129 case 0x04: /* Skip only */
130 iodata
= carriage_control(4, data
);
132 case 0x06: /* Print and skip */
133 iodata
= write_line(0, 0);
134 if (iodata
== SCPE_OK
)
135 iodata
= carriage_control(4, data
);
141 case 1: /* LIO 1403 */
143 case 0x00: /* LPFLR */
144 LPFLR
= (data
>> 8) & 0xff;
147 LPIAR
= data
& 0xffff;
150 LPDAR
= data
& 0xffff;
156 case 2: /* TIO 1403 */
159 case 0x00: /* Not ready/check */
162 if ((lpt_unit
.flags
& UNIT_ATT
) == 0)
165 case 0x02: /* Buffer Busy */
168 case 0x04: /* Carriage Busy */
171 case 0x06: /* Printer busy */
175 return (STOP_INVDEV
<< 16);
177 return ((SCPE_OK
<< 16) | iodata
);
178 case 3: /* SNS 1403 */
180 case 0x00: /* Line count */
181 iodata
= (linectr
<< 8);
183 case 0x02: /* Timing data */
186 case 0x03: /* Check data */
189 case 0x04: /* LPIAR */
192 case 0x06: /* LPDAR */
196 return (STOP_INVDEV
<< 16);
198 return ((SCPE_OK
<< 16) | iodata
);
199 case 4: /* APL 1403 */
201 return ((SCPE_OK
<< 16) | iodata
);
205 printf (">>LPT non-existent function %d\n", op
);
212 Modifiers have been checked by the caller
213 S = suppress automatic newline
216 t_stat
write_line (int32 ilnt
, int32 mod
)
219 static char lbuf
[LPT_WIDTH
+ 1]; /* + null */
221 if ((lpt_unit
.flags
& UNIT_ATT
) == 0)
225 lc
= LPDAR
; /* clear error */
226 for (i
= 0; i
< LPT_WIDTH
; i
++) { /* convert print buf */
228 lbuf
[i
] = ebcdic_to_ascii
[t
& 0xff];
229 M
[lc
] = 0x40; /* HJS MOD */
232 for (i
= LPT_WIDTH
- 1; (i
>= 0) && (lbuf
[i
] == ' '); i
--) lbuf
[i
] = 0;
233 fputs (lbuf
, lpt_unit
.fileref
); /* write line */
234 if (lines
) space (lines
, lflag
); /* cc action? do it */
235 else if (mod
== 0) space (1, FALSE
); /* default? 1 line */
237 fputc ('\r', lpt_unit
.fileref
); /* sup -> overprint */
238 lpt_unit
.pos
= ftell (lpt_unit
.fileref
); /* update position */
240 lines
= lflag
= 0; /* clear cc action */
241 if (ferror (lpt_unit
.fileref
)) { /* error? */
242 perror ("Line printer I/O error");
243 clearerr (lpt_unit
.fileref
);
249 /* Carriage control routine
252 action = 00, skip to channel now
253 = 01, space lines after
254 = 02, space lines now
255 = 03, skip to channel after
256 = 04, skip to line number
257 mod = number of lines or channel number or line number
260 t_stat
carriage_control (int32 action
, int32 mod
)
264 if ((lpt_unit
.flags
& UNIT_ATT
) == 0)
268 case 0: /* to channel now */
269 if ((mod
== 0) || (mod
> 12) || CHP (mod
, cct
[cctptr
])) return SCPE_OK
;
270 for (i
= 1; i
< cctlnt
+ 1; i
++) { /* sweep thru cct */
271 if (CHP (mod
, cct
[(cctptr
+ i
) % cctlnt
]))
272 return space (i
, TRUE
);
274 return STOP_INVDEV
; /* runaway channel */
275 case 1: /* space after */
277 lines
= mod
; /* save # lines */
278 lflag
= FALSE
; /* flag spacing */
282 case 2: /* space now */
283 if (mod
<= 3) return space (mod
, FALSE
);
285 case 3: /* to channel after */
286 if ((mod
== 0) || (mod
> 12)) return SCPE_OK
; /* check channel */
288 for (i
= 1; i
< cctlnt
+ 1; i
++) { /* sweep thru cct */
289 if (CHP (mod
, cct
[(cctptr
+ i
) % cctlnt
])) {
290 lines
= i
; /* save # lines */
291 lflag
= TRUE
; /* flag skipping */
296 case 4: /* To line # */
298 fputs ("\n\f", lpt_unit
.fileref
); /* nl, ff */
301 if (mod
<= linectr
) {
302 fputs ("\n\f", lpt_unit
.fileref
);
316 /* Space routine - space or skip n lines
319 count = number of lines to space or skip
320 sflag = skip (TRUE) or space (FALSE)
323 t_stat
space (int32 count
, int32 sflag
)
327 if ((lpt_unit
.flags
& UNIT_ATT
) == 0) return SCPE_UNATT
;
328 cctptr
= (cctptr
+ count
) % cctlnt
; /* adv cct, mod lnt */
329 if (sflag
&& CHP (0, cct
[cctptr
])) { /* skip, top of form? */
330 fputs ("\n\f", lpt_unit
.fileref
); /* nl, ff */
333 for (i
= 0; i
< count
; i
++) fputc ('\n', lpt_unit
.fileref
);
335 lpt_unit
.pos
= ftell (lpt_unit
.fileref
); /* update position */
336 CC9
= CHP (9, cct
[cctptr
]) != 0; /* set indicators */
337 CC12
= CHP (12, cct
[cctptr
]) != 0;
346 t_stat
lpt_reset (DEVICE
*dptr
)
348 cctptr
= 0; /* clear cct ptr */
349 lines
= linectr
= lflag
= 0; /* no cc action */
356 t_stat
lpt_attach (UNIT
*uptr
, char *cptr
)
358 cctptr
= 0; /* clear cct ptr */
359 lines
= 0; /* no cc action */
362 return attach_unit (uptr
, cptr
);