1 /* hp3000_lp.c: HP 3000 30209A Line Printer Interface simulator
2
3 Copyright (c) 2016-2021, J. David Bryan
4
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
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 THE
18 AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of the author shall not be used
23 in advertising or otherwise to promote the sale, use or other dealings in
24 this Software without prior written authorization from the author.
25
26 LP HP 30209A Line Printer Interface
27
28 01-Apr-21 JDB Changed VFU type from "uint16" to "uint32"
29 25-Mar-21 JDB Converted ftell to position increment for pipes
30 09-Dec-19 JDB Replaced debugging macros with tracing macros
31 01-Oct-19 JDB DETACH -F now flushes the print buffer if not empty
32 27-Dec-18 JDB Revised fall through comments to comply with gcc 7
33 07-Sep-17 JDB Changed PCHR and UPCHR registers to PUNCHR and UNPCHR
34 Changed PRTBUF, OVPCHR, PUNCHR, and UNPCHR to REG_A
35 05-Sep-17 JDB Changed REG_A (permit any symbolic override) to REG_X
36 20-Jul-17 JDB Added a forced detach option (-F switch) to "lp_detach"
37 24-Jun-17 JDB Added "report_error", fixed "lp_set_model" times bug
38 22-Jun-17 JDB Moved deferred offline/detach cancel to SET ONLINE
39 26-Apr-17 JDB Fixed "lp_service" return for VFU channel not punched
40 Restricted auto-print on buffer full to the 2607
41 Paper fault is now delayed until the TOF for the 2607
42 Changed "activate_unit" to schedule zero-length delays
43 12-Sep-16 JDB Changed DIB register macro usage from SRDATA to DIB_REG
44 03-Sep-16 JDB Added power-fail detection
45 08-Jul-16 JDB Added REG entry to save the transfer unit wait field
46 Extended "lp_show_vfu" to show the VFU channel definitions
47 01-Jul-16 JDB First release version
48 27-Apr-16 JDB Passes the On-Line HP Line Printers Verification (D466A)
49 19-Apr-16 JDB Passes the universal interface diagnostic (D435A)
50 24-Mar-16 JDB Created
51
52 References:
53 - 30051A Universal Interface (Differential) Maintenance Manual
54 (30051-90001, May 1976)
55 - Installation and Service Manual for Line Printer Subsystems
56 (30209-90006, May 1976)
57 - Line Printer Operating and Programming Manual
58 (30209-90008, June 1976)
59 - HP 3000 Series III Engineering Diagrams Set
60 (30000-90141, April 1980)
61
62
63 The HP 30118A, 30127A, 30128A, and 30133A Line Printer Subsystems connect the
64 2607A, 2613A, 2618A, and 2617A printers, respectively, to the HP 3000. Each
65 subsystem consists of a 30209A Line Printer Controller, employing a 30051A
66 Universal Interface (Differential) and interconnecting cable, and an HP
67 2607A (200 lines per minute), HP 2613 (300 lpm), HP 2617 (600 lpm), or HP
68 2618 (1250 lpm) line printer. These subsystems employ the Multiplexer
69 Channel to achieve a 360 KB/second transfer rate from the CPU.
70
71 This module simulates three hardware devices:
72
73 - the HP 30051A Universal Interface (Differential)
74 - the HP 30049C Diagnostic Hardware Assembly
75 - the HP 2607A/13A/17A/18A line printer and 30209-60004 printer cable
76
77 Available with either differential or TTL I/O logic levels, the Universal
78 Interface (UI) provides a 16-bit bidirectional parallel connection between a
79 device and the HP 3000 system. Both direct and programmed I/O via the
80 Multiplexer Channel are supported, word or byte transfers may be selected,
81 and byte packing and unpacking is available. In addition to the 16-bit data
82 path, a five-bit control word is supplied to the device, and an eight-bit
83 status word is returned. Flexible configuration of interface operation is
84 provided via ten jumpers, and eight different interrupt sources are
85 available. The Universal Interface is also used to connect the paper tape
86 reader, punch, and card reader to the HP 3000.
87
88 The Diagnostic Hardware Assembly (DHA) connects to the UI device connectors
89 and provides a programmable loopback and configuration capability. Five LEDs
90 continuously display the device control word, and test points are provided to
91 monitor the state of the 16-bit data path, the ten programmable jumper
92 settings, and the Device Command, Device Flag, and Device End signals.
93 Enabling the diagnostic mode simulates the installation of the DHA in place
94 of the printer device cable.
95
96 The interface supports a single line printer. The supported printers are
97 configured with Option 001, which provides a 128 (2607) or 96 (2613/17/18)
98 character set. Two output modes are provided: an expanded mode that is
99 suitable for retaining printer output as a text file, and a compact mode that
100 is suitable for sending the printer output to a host-connected physical
101 printer. An 8-channel (2607) or 12-channel (2613/17/18) Vertical Format Unit
102 is supported, and custom VFU tape images may be loaded from properly
103 formatted host-system text files.
104
105 The printer supports realistic and optimized (fast) timing modes. Realistic
106 timing attempts to model the print buffer load and print-and-space operation
107 delays inherent in the physical hardware. For example, in REALTIME mode,
108 output of longer lines takes more time than output of shorter lines, and
109 spacing six lines takes approximately six times longer than spacing one line.
110 In FASTTIME mode, all timings are reduced to be "just long enough" to satisfy
111 MPE software driver requirements.
112
113
114 In hardware, the ten UI configuration jumpers perform these functions:
115
116 Jumper Interpretation when removed Interpretation when installed
117 ------ ------------------------------- ------------------------------
118 W1 SR set by PCONTSTB SR set by Device Status bit 11
119
120 W2 Flag asserts on leading edge Flag asserts on trailing edge
121
122 W3 Command uses response mode Command uses pulse mode
123
124 W4 inhibit IRQ on Device Status enable IRQ on Device Status
125 bit 8 leading edge bit 8 leading edge
126
127 W5 DATA IN latched on Flag DATA IN always transparent
128
129 W6 Flag denies on trailing edge Flag denies on leading edge
130
131 W7 normal byte-mode write transfer test byte-mode write transfer
132
133 W8 inhibit IRQ on Device Status enable IRQ on Device Status
134 bit 9 leading edge bit 9 leading edge
135
136 W9 inhibit IRQ on Device Status enable IRQ on Device Status
137 bit 10 trailing edge bit 10 trailing edge
138
139 W10 DEV CMD polarity is normal DEV CMD polarity is inverted
140
141 The line printer cable is wired with this configuration:
142
143 Interface Connection Printer Connection
144 ---------------------------------------- ------------------
145 Data Out bit 15 DATA 1
146 Data Out bit 14 DATA 2
147 Data Out bit 13 DATA 3
148 Data Out bit 12 DATA 4
149 Data Out bit 11 DATA 5
150 Data Out bit 10 DATA 6
151 Data Out bit 9 DATA 7
152 Device Command STROBE
153 Device Flag ~DEMAND
154 Control Word bit 10 PAPER INSTRUCTION
155 Device Status bit 9 ONLINE
156 Device Status bit 10 ONLINE
157 Device Status bit 11 ~READY
158 Device Status bit 12 VFU CHANNEL 12
159 Device Status bit 13 VFU CHANNEL 9
160 Device End ~ONLINE
161 Set Transfer Error Flip-Flop (no connection)
162 Master Clear MASTER CLEAR
163
164 Internal Connection Action
165 ---------------------------------------- --------------------------------
166 300 pF across the Write Delay One-Shot sets 1.2 uS pulse width
167 1500 pF across the Master Clear One-Shot sets 5.1 uS pulse width
168 jumper W4 shorted none (Status 8 is not connected)
169 jumper W8 shorted enables IRQ when ONLINE asserts
170 jumper W9 shorted enables IRQ when ONLINE denies
171
172 DEMAND is wired inversely to Device Flag, so DEMAND assertion is Device Flag
173 denial and vice versa. DEMAND dropping after STROBE assertion corresponds
174 with Device Flag asserting after Device Command asserts, and DEMAND asserting
175 after the printer is ready corresponds to Device Flag denying.
176
177 Similarly, ONLINE is wired inversely to Device End, so the printer going
178 offline asserts Device End, and READY is wired inversely to Device Status bit
179 11, so bit 11 is asserted when the printer is not ready (either powered off
180 or out of paper).
181
182 The READY and ONLINE signals indicate the current state of the printer.
183 READY asserts when printer power is on, no alarm condition (paper out, tape
184 format error) exits, and the VFU has been initialized. ONLINE asserts when
185 READY is asserted and the Online button is pressed. Therefore:
186
187 ~ONLINE * ~READY = paper out or VFU error
188 ~ONLINE * READY = paper loaded and offline
189 ONLINE * ~READY = (prohibited)
190 ONLINE * READY = paper loaded and online
191
192 The printer DEMAND signal asserts when the printer is ready for data and
193 denies when it is printing or slewing. It also denies when the printer goes
194 offline. DEMAND is cross-connected to the Device Flag differential input,
195 so that DEV FLAG is the complement of DEMAND, i.e., it asserts when the
196 printer is busy and denies when the printer is available.
197
198 The normal sequence starts with DEMAND asserted (i.e., DEV FLAG denied). The
199 interface asserts STROBE (DEV CMD), the printer denies DEMAND (asserts DEV
200 FLAG), the interface denies STROBE (DEV CMD), and the printer then asserts
201 DEMAND (denies DEV FLAG) when the character data is accepted or the print
202 operation is complete.
203
204 When the ON/OFFLINE button on the printer is pressed, the printer will not go
205 offline (i.e., deny the ONLINE signal) if there are characters in the print
206 buffer. Instead, the offline condition is held off until an internal "allow
207 offline" signal asserts. This occurs when the print buffer is empty and the
208 print cycle is inactive. When ONLINE denies, DEMAND is inhibited, so the
209 interface waits at the end of the handshake sequence for DEV FLAG to deny.
210 Note that this holds off SR to the Multiplexer Channel, so the channel
211 program waits. When the printer is put back online, DEMAND asserts, so DEV
212 FLAG denies, the handshake completes, SR asserts, and the interface returns
213 to the idle condition to await the next command.
214
215 This has implications for the SET OFFLINE and DETACH commands if they are
216 issued while the print buffer contains data or the printer unit is busy
217 executing a print action.
218
219 The SET LP OFFLINE and DETACH LP commands check for data in the print buffer
220 or a print operation in progress. If either condition is true, they set
221 their respective deferred-action flags and display "Command not completed."
222 A SHOW LP will show that the device is still online and attached. Once
223 simulation is resumed and the print operation completes, the printer is set
224 offline or detached as requested. No console message reports this, as it is
225 assumed that the executing program will detect the condition and report
226 accordingly. A subsequent SHOW LP will indicate the new status.
227
228 A SET LP ONLINE command when a deferred-action flag is set simply clears the
229 flag, which cancels the pending offline or detach condition.
230
231 A RESET LP command also clears the deferred-action flags and so clears any
232 pending offline or detach. However, it also clears the print buffer and
233 terminates any print action in progress, so a SET LP OFFLINE or DETACH LP
234 will succeed if issued subsequently.
235
236
237 The Universal Interface responds to both direct I/O and programmed I/O from
238 the Multiplexer Channel, as follows:
239
240 Control Word Format (CIO and SIO Control word 2):
241
242 0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15
243 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
244 | M | R | irq reset | A | device control | X | S | B | I | T | device
245 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
246 | M | R | irq reset | A | function | E | X | S | B | I | T | DHA
247 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
248 | M | R | irq reset | A | - - - - | F | X | S | B | I | T | printer
249 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
250
251 Where:
252
253 M = programmed master clear
254 R = reset interrupts
255 A = acquire data from device
256 E = enable diagnostic hardware assembly function
257 F = printer output character/format (0/1) code
258 X = enable data transfer interrupt
259 S = interrupt/device (0/1) status
260 B = word/byte (0/1) transfer
261 I = enable interrupts
262 T = enable transfer timer
263
264 IRQ Reset:
265
266 000 = none
267 001 = transfer timer and transfer error
268 010 = I/O system
269 011 = clear interface
270 100 = data transfer completion
271 101 = line ready (device status bit 8)
272 110 = ready (device status bit 9)
273 111 = not ready (device status bit 10)
274
275 DHA Function:
276
277 0000 = clear configuration registers (installs jumpers)
278 0001 = remove jumper J2W2
279 0010 = assert DEV END
280 0011 = remove jumper J2W8
281 0100 = set Transfer Error flip-flop
282 0101 = remove jumper J2W4
283 0110 = remove jumper J2W10
284 0111 = remove jumper J2W6
285 1000 = DEV FLAG follows DEV CMD or Control 6 (0/1)
286 1001 = remove jumper J2W5
287 1010 = assert CLEAR INTERFACE
288 1011 = remove jumper J2W9
289 1100 = Status 8-10 follow Control 6-8
290 or master clear, power on, and power fail (0/1)
291 1101 = remove jumper J2W1
292 1110 = remove jumper J2W3
293 1111 = remove jumper J2W7
294
295 Bits 6-10 are the device control bits. For the DHA, control bit 10 enables
296 the function decoder. The decoder is combinatorial and the registers are
297 "ones-catching," so the function field must be set and then maintained while
298 bit 10 is asserted and then denied. For the line printer, control bit 10
299 indicates whether character data (0) or format commands (1) will be output.
300 Programmed control word 1 (IOCW) is not used.
301
302 Setting control bit 15 starts (or restarts) the five-second transfer timer.
303 Issuing a Reset Transfer Timer and Transfer Error Interrupts, a Master Reset,
304 or a Reset Interrupts command stops the timer. If the timer expires, a
305 Transfer Timer interrupt occurs.
306
307
308 Status Word Format (TIO and SIO Status):
309
310 0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15
311 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
312 | S | D | I | seqct | F | 0 | 0 | dev irq | X | C | Y | E | T | interrupt
313 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
314 | S | D | I | seqct | F | 1 | 0 | device status | device
315 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
316 | S | D | I | seqct | F | 1 | 0 | - | L | L | N | V | U | - | - | printer
317 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
318
319 Where:
320
321 S = SIO OK
322 D = direct I/O OK
323 I = interrupt pending
324 F = device flag
325 X = data transfer interrupt
326 C = clear interface interrupt
327 Y = I/O system interrupt
328 E = transfer error interrupt
329 T = transfer timer interrupt
330 L = online
331 N = not ready
332 V = VFU channel 12
333 U = VFU channel 9
334
335 Sequence Counter:
336
337 00 = idle
338 10 = request to device issued for word or 1st byte
339 11 = device operation started
340 01 = request to device issued for 2nd byte
341
342 Device Interrupt Request Bits:
343
344 8 = device status bit 8 interrupt (not used by the printer)
345 9 = device status bit 9 interrupt (printer went online)
346 10 = device status bit 10 interrupt (printer went offline)
347
348 Control word bit 12 determines whether the interrupt status word (0) or the
349 device status word (1) is returned.
350
351 A transfer error occurs when the channel asserts XFERERROR to abort a
352 transfer for a parity error or memory address out of bounds. Device status
353 bits assume the logic 1 state with the inputs disconnected (e.g., power off).
354
355
356 Output Data Word Format (WIO and SIO Write):
357
358 0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15
359 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
360 | - | 1st ASCII character | - | 2nd ASCII character | byte mode
361 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
362 | - - - - - - - - | - | ASCII character | word mode
363 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
364 | - - - - - - - - | - | format word | format
365 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
366
367 The printer only uses seven data bits, so the MSB of each byte is ignored.
368 If the printer's line length is exceeded during write operations, the
369 buffered line will be printed, the paper will be advanced one line, and the
370 buffer will be cleared to accept the character causing the overflow.
371
372
373 Implementation notes:
374
375 1. The Clear Interface Logic (CLRIL) signal inhibits SIO OK status. The
376 Card Reader/Punch Interface version of the UI does not assert the CLRIL
377 signal in response to external CLEAR INTERFACE assertion; only a transfer
378 error does. Therefore, the SIO OK signal is not inhibited while the
379 clear interface interrupt is present. For this version, the external
380 Clear Interface signal sets the CLR INF flip-flop, which sets the (C) bit
381 in the status register and generates an interrupt, but otherwise has no
382 effect on the interface logic.
383
384 The standard version of the UI asserts CLRIL, and therefore inhibits SIO
385 OK, for both the clear interface and transfer error conditions.
386
387 2. Because the interface uses differential interface logic, the external
388 sense of a signal may be inverted by exchanging the + and - connections.
389 To accommodate this in simulation, separate variables are used for the
390 internal and external states. For example, "device_command" represents
391 the internal state, while "device_command_out" represents the external
392 state (which may be inverted from the internal state if jumper J2W10 is
393 installed).
394
395 3. The Universal Interface supports terminating channel transfers by
396 asserting DEVEND, and the line printer cable connects the ONLINE output
397 inversely to the Device End input, so that it is asserted when the
398 printer is offline. However, when the printer goes offline, it holds its
399 DEMAND line denied, which keeps Device Flag asserted. This hangs the
400 transfer handshake in the Device_Flag_1/2 state until the printer goes
401 online again. As the interface recognizes Device End only in the
402 Device_Command_1/2 state, DEVEND will never be asserted to terminate a
403 channel transfer.
404
405 4. In hardware, a paper-out condition is noted, but the line printer does
406 not go offline until the top of the next form is reached. This ensures
407 that the current page is completed first. By contrast, a torn-paper
408 condition causes the printer to go offline at the completion of the
409 current line. In simulation, a DETACH is handled as a torn-paper
410 condition.
411
412 5. Slewing in expanded mode is performed by appending CR LF pairs to the
413 character buffer and then writing the combined buffer to the printer
414 output file. The size of the buffer must accommodate the largest print
415 line (136 characters) plus the largest possible slew (144 lines * 2
416 characters per line).
417 */
418
419
420
421 #include "hp3000_defs.h"
422 #include "hp3000_io.h"
423
424
425
426 /* Interface program constants */
427
428 #define PULSE_TIME uS (8) /* device command pulse = 8 microseconds */
429 #define XFER_TIME S (5) /* transfer timeout = 5 seconds */
430
431 /* Printer program constants */
432
433 #define CR '\r' /* carriage return */
434 #define LF '\n' /* line feed */
435 #define FF '\f' /* form feed */
436 #define DEL '\177' /* delete */
437
438 #define DATA_MASK 0177u /* printer uses only 7 bits for data */
439 #define FORMAT_VFU 0100u /* printer VFU selector */
440 #define FORMAT_MASK 0117u /* printer format command mask for 12-channel VFU */
441 #define FORMAT_VFU_8_MASK 0107u /* printer format command mask for 8-channel VFU */
442
443 #define FORMAT_SUPPRESS 0000u /* format code to slew 0 lines */
444 #define FORMAT_VFU_CHAN_1 0100u /* format code to slew to VFU channel 1 */
445 #define FORMAT_VFU_BIAS 0077u /* bias converting from format code to channel number */
446
447 #define VFU_MAX 144 /* maximum number of VFU form lines */
448 #define VFU_SIZE (VFU_MAX + 1) /* size of the VFU array */
449 #define LINE_SIZE 256 /* size of the character array used to read the VFU file */
450
451 #define VFU_WIDTH 12 /* maximum number of VFU channels */
452
453 #define VFU_CHANNEL_1 04000u /* top of form */
454 #define VFU_CHANNEL_2 02000u /* bottom of form */
455 #define VFU_CHANNEL_3 01000u /* single space */
456 #define VFU_CHANNEL_4 00400u /* double space */
457 #define VFU_CHANNEL_5 00200u /* triple space */
458 #define VFU_CHANNEL_6 00100u /* half page */
459 #define VFU_CHANNEL_7 00040u /* quarter page */
460 #define VFU_CHANNEL_8 00020u /* sixth page */
461 #define VFU_CHANNEL_9 00010u /* bottom of form */
462 #define VFU_CHANNEL_10 00004u /* (unassigned) */
463 #define VFU_CHANNEL_11 00002u /* (unassigned) */
464 #define VFU_CHANNEL_12 00001u /* (unassigned) */
465
466 #define CHARS_MAX 136 /* maximum number of characters buffered by the printers */
467
468 #define BUFFER_SIZE (CHARS_MAX + VFU_MAX * 2) /* max chars + max VFU * 2 (CR LF) */
469
470 #define PRINTER_JUMPERS (W4 | W8 | W9) /* jumpers J2W4, J2W8, and J2W9 are installed */
471
472
473 /* Debug flags */
474
475 #define DEB_CMD (1u << 0) /* trace controller commands */
476 #define DEB_CSRW (1u << 1) /* trace command initiations and completions */
477 #define DEB_STATE (1u << 2) /* trace device handshake state changes */
478 #define DEB_SERV (1u << 3) /* trace channel service scheduling calls */
479 #define DEB_XFER (1u << 4) /* trace data transmissions */
480 #define DEB_IOB (1u << 5) /* trace I/O bus signals and data words */
481
482
483 /* Device flags */
484
485 #define DEV_DIAG_SHIFT (DEV_V_UF + 0) /* Diagnostic Hardware Assembly is installed */
486 #define DEV_REALTIME_SHIFT (DEV_V_UF + 1) /* timing mode is realistic */
487
488 #define DEV_DIAG (1u << DEV_DIAG_SHIFT) /* diagnostic mode flag */
489 #define DEV_REALTIME (1u << DEV_REALTIME_SHIFT) /* realistic timing flag */
490
491
492 /* Printer unit flags.
493
494 UNIT_V_UF + 7 6 5 4 3 2 1 0
495 +---+---+---+---+---+---+---+---+
496 | - | - | - | O | E | model |
497 +---+---+---+---+---+---+---+---+
498
499 Where:
500
501 O = offline
502 E = expanded output
503 */
504
505 #define UNIT_MODEL_SHIFT (UNIT_V_UF + 0) /* printer model ID */
506 #define UNIT_EXPAND_SHIFT (UNIT_V_UF + 3) /* printer uses expanded output */
507 #define UNIT_OFFLINE_SHIFT (UNIT_V_UF + 4) /* printer is offline */
508
509 #define UNIT_MODEL_MASK 0000007u /* model ID mask */
510
511 #define UNIT_MODEL (UNIT_MODEL_MASK << UNIT_MODEL_SHIFT)
512 #define UNIT_EXPAND (1u << UNIT_EXPAND_SHIFT)
513 #define UNIT_OFFLINE (1u << UNIT_OFFLINE_SHIFT)
514 #define UNIT_ONLINE 0
515
516 #define UNIT_2607 (HP_2607 << UNIT_MODEL_SHIFT)
517 #define UNIT_2613 (HP_2613 << UNIT_MODEL_SHIFT)
518 #define UNIT_2617 (HP_2617 << UNIT_MODEL_SHIFT)
519 #define UNIT_2618 (HP_2618 << UNIT_MODEL_SHIFT)
520
521
522 /* Unit flags accessor */
523
524 #define GET_MODEL(f) ((PRINTER_TYPE) (((f) >> UNIT_MODEL_SHIFT) & UNIT_MODEL_MASK))
525
526
527 /* Unit references */
528
529 #define xfer_unit lp_unit [0] /* transfer handshake unit */
530
531 #define xfer_uptr (&lp_unit [0]) /* transfer handshake unit pointer */
532 #define pulse_uptr (&lp_unit [1]) /* pulse timer unit pointer */
533 #define timer_uptr (&lp_unit [2]) /* transfer timer unit pointer */
534
535 static const char *const unit_name [] = { /* unit names, indexed by unit number */
536 "Transfer",
537 "Pulse",
538 "Watchdog"
539 };
540
541
542 /* Printer types */
543
544 typedef enum {
545 HP_2607, /* HP 2607A */
546 HP_2613, /* HP 2613A */
547 HP_2617, /* HP 2617A */
548 HP_2618 /* HP 2618A */
549 } PRINTER_TYPE;
550
551
552 /* Printer locality states */
553
554 typedef enum {
555 Offline, /* printer is going offline */
556 Online /* printer is going online */
557 } LOCALITY;
558
559
560 /* Printer properties table.
561
562 This table contains the characteristics that vary between printer models.
563 The "char_set" field values reflect printer Option 001, 96/128-character set.
564 The "not_ready" field indicates whether a paper fault sets a separate
565 not-ready status or simply takes the printer offline. The "fault_at_eol"
566 field indicates whether a paper fault is reported at the end of any line or
567 only at the top of the next form.
568 */
569
570 typedef struct {
571 uint32 line_length; /* the maximum number of print positions */
572 uint32 char_set; /* the size of the character set */
573 uint32 vfu_channels; /* the number of VFU channels */
574 t_bool not_ready; /* TRUE if the printer reports a separate not ready status */
575 t_bool overprints; /* TRUE if the printer supports overprinting */
576 t_bool autoprints; /* TRUE if the printer automatically prints on buffer overflow */
577 t_bool fault_at_eol; /* TRUE if a paper fault is reported at the end of any line */
578 } PRINTER_PROPS;
579
580 static const PRINTER_PROPS print_props [] = { /* printer properties, indexed by PRINTER_TYPE */
581 /* line char VFU not over auto fault */
582 /* length set channels ready prints prints at EOL */
583 /* ------ ----- -------- ------ ------ ------ ------ */
584 { 132, 128, 8, FALSE, FALSE, TRUE, FALSE }, /* HP_2607 */
585 { 136, 96, 12, TRUE, TRUE, FALSE, TRUE }, /* HP_2613 */
586 { 136, 96, 12, TRUE, TRUE, FALSE, TRUE }, /* HP_2617 */
587 { 132, 96, 12, TRUE, TRUE, FALSE, TRUE } /* HP_2618 */
588 };
589
590
591 /* Delay properties table.
592
593 To support the realistic timing mode, the delay properties table contains
594 timing specifications for the supported printers. The times represent the
595 delays for mechanical and electronic operations. Delay values are in event
596 tick counts; macros are used to convert from times to ticks.
597
598
599 Implementation notes:
600
601 1. Although all of the printers operate more slowly with a 96/128-character
602 set installed than with a 64-character set, the times reflect the smaller
603 set size. Also, some models provide different print rates, depending on
604 how many and/or which characters are printed. These variations are not
605 simulated.
606 */
607
608 typedef struct {
609 int32 buffer_load; /* per-character transfer time */
610 int32 print; /* print time */
611 int32 advance; /* paper advance time per line */
612 } DELAY_PROPS;
613
614 static const DELAY_PROPS real_times [] = { /* real-time delays, indexed by PRINTER_TYPE */
615 /* buffer paper */
616 /* load print advance */
617 /* --------- -------- --------- */
618 { uS (12.6), mS (260), mS (40.1) }, /* HP_2607 200 lines per minute */
619 { uS (1.75), mS (183), mS (8.33) }, /* HP_2613 300 lines per minute */
620 { uS (1.75), mS ( 86), mS (6.67) }, /* HP_2617 600 lines per minute */
621 { uS (1.75), mS ( 38), mS (4.76) } /* HP_2618 1250 lines per minute */
622 };
623
624 #define LP_BUFFER_LOAD uS (1) /* fast per-character transfer time */
625 #define LP_PRINT mS (1) /* fast print time */
626 #define LP_ADVANCE uS (50) /* fast paper advance time per line */
627
628 static DELAY_PROPS fast_times = /* FASTTIME delays */
629 { LP_BUFFER_LOAD,
630 LP_PRINT,
631 LP_ADVANCE
632 };
633
634
635 /* Data transfer handshake sequencer.
636
637 The sequencer controls the handshake that transfers data between the
638 interface and the device.
639 */
640
641 typedef enum {
642 Idle, /* the device is idle */
643 Device_Command_1, /* device command is asserted for a word or first byte */
644 Device_Flag_1, /* device flag is asserted for a word or first byte */
645 Device_Command_2, /* device command is asserted for the second byte */
646 Device_Flag_2 /* device flag is asserted for the second byte */
647 } SEQ_STATE;
648
649 static const char *const state_name [] = { /* sequencer state names, indexed by SEQ_STATE */
650 "Idle",
651 "Device Command 1",
652 "Device Flag 1",
653 "Device Command 2",
654 "Device Flag 2"
655 };
656
657
658 /* Configuration jumpers.
659
660 Various aspects of interface operation are configured by installing or
661 removing jumpers contained within the connector hood of the device
662 interconnection cable. Jumpers are simulated by bits in the "jumper_set"
663 word, with a 1 value representing "installed" and a 0 value representing
664 "removed" (although in hardware installing a jumper pulls the corresponding
665 signal down to 0).
666
667 The Diagnostic Hardware Assembly provides programmatic configuration of the
668 jumpers. All jumpers are installed by executing a "clear registers" command,
669 and then individual jumpers may be removed by executing the corresponding
670 "remove jumper J2Wn" commands. This is simulated by setting all of the bits
671 in the "jumper_set" word and then selectively ANDing the word with
672 complemented constants from the "jumper_map" table, thereby clearing
673 individual bits.
674
675
676 Implementation notes:
677
678 1. In simulation, jumper W5 is not used. The DATA IN signals are always
679 latched when DEV FLAG asserts. Always-transparent operation is not
680 provided.
681
682 2. In hardware, DHA control word bits 6-9 are wired to decoder input bits
683 0-3. As the 3000 uses decreasing bit-number significance, while the
684 decoder chip uses increasing bit-number significance, the order of the
685 functions in the "jumper_map" table reflect the reversed bit order of the
686 index. For example, index 0001 contains the function for decoder output
687 8 (1000).
688 */
689
690 #define W1 (1u << 0) /* SR set by PCONTSTB/Device Status bit 11 */
691 #define W2 (1u << 1) /* +/- edge of Device Flag advances sequence counter from 1 to 2 */
692 #define W3 (1u << 2) /* Device Command operates in response/pulse mode */
693 #define W4 (1u << 3) /* inhibit/enable interrupt on STAT8 + edge */
694 #define W5 (1u << 4) /* Data In latched on sequence count 1 and 3/always transparent */
695 #define W6 (1u << 5) /* -/+ edge of Device Flag advances sequence counter from 2 to 3 */
696 #define W7 (1u << 6) /* normal/test write transfer */
697 #define W8 (1u << 7) /* inhibit/enable interrupt on STAT9 + edge */
698 #define W9 (1u << 8) /* inhibit/enable interrupt on STAT10 - edge */
699 #define W10 (1u << 9) /* Device Command same/inverted polarity as Data Out */
700
701 #define J2W1_INSTALLED ((jumper_set & W1) != 0)
702 #define J2W2_INSTALLED ((jumper_set & W2) != 0)
703 #define J2W3_INSTALLED ((jumper_set & W3) != 0)
704 #define J2W4_INSTALLED ((jumper_set & W4) != 0)
705 #define J2W5_INSTALLED ((jumper_set & W5) != 0)
706 #define J2W6_INSTALLED ((jumper_set & W6) != 0)
707 #define J2W7_INSTALLED ((jumper_set & W7) != 0)
708 #define J2W8_INSTALLED ((jumper_set & W8) != 0)
709 #define J2W9_INSTALLED ((jumper_set & W9) != 0)
710 #define J2W10_INSTALLED ((jumper_set & W10) != 0)
711
712 static const uint32 jumper_map [16] = { /* jumper removal map, indexed by CN_DHA_FN */
713 0, /* 0000 = (unaffected) */
714 ~W2, /* 0001 = remove jumper J2W2 */
715 0, /* 0010 = (unaffected) */
716 ~W8, /* 0011 = remove jumper J2W8 */
717 0, /* 0100 = (unaffected) */
718 ~W4, /* 0101 = remove jumper J2W4 */
719 ~W10, /* 0110 = remove jumper J2W10 */
720 ~W6, /* 0111 = remove jumper J2W6 */
721 0, /* 1000 = (unaffected) */
722 ~W5, /* 1001 = remove jumper J2W5 */
723 0, /* 1010 = (unaffected) */
724 ~W9, /* 1011 = remove jumper J2W9 */
725 0, /* 1100 = (unaffected) */
726 ~W1, /* 1101 = remove jumper J2W1 */
727 ~W3, /* 1110 = remove jumper J2W3 */
728 ~W7 /* 1111 = remove jumper J2W7 */
729 };
730
731
732 /* Diagnostic Hardware Assembly control register.
733
734 0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15
735 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
736 | M | F | S | - - - | jumpers J2W10-J2W1 |
737 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
738
739 Where:
740
741 M = master reset has occurred
742 F = device flag follows device command/control 6 (0/1)
743 S = status 8-10 follow control 6-8/master clear-power on-power fail (0/1)
744
745
746 Implementation notes:
747
748 1. Jumper bits are defined as 0 = removed and 1 = installed. This is
749 the opposite of the DHA hardware, for which a zero output "installs" a
750 jumper.
751
752 2. Jumpers J2W10-J2W1, which are stored in the "jumpers" array, are mirrored
753 in the jumper control register to allow the diagnostic to test the full
754 set of jumpers with single assertions. Otherwise, ten assertions would
755 be necessary for each test.
756 */
757
758 #define DHA_MR 0100000u /* (M) a master reset has occurred */
759 #define DHA_FLAG_SEL 0040000u /* (F) device flag follows control 6 */
760 #define DHA_STAT_SEL 0020000u /* (S) status 8-10 follow master clear-power on-power fail */
761 #define DHA_JUMPER_MASK 0001777u /* J2Wx jumpers mask */
762 #define DHA_CLEAR 0001777u /* control register clear value (all jumpers installed) */
763
764
765 /* Interface control word.
766
767 0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15
768 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
769 | M | R | irq reset | A | device control | X | S | B | I | T | device
770 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
771 | M | R | irq reset | A | function | E | X | S | B | I | T | DHA
772 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
773 */
774
775 #define CN_MR 0100000u /* (M) master reset */
776 #define CN_RIN 0040000u /* (R) reset interrupt */
777 #define CN_RIN_MASK 0034000u /* reset interrupt request selector mask */
778 #define CN_RIN_XFR_TMR 0004000u /* reset watchdog timer and transfer error interrupts */
779 #define CN_ACQUIRE 0002000u /* (A) acquire data from device */
780 #define CN_DHA_FN_MASK 0001700u /* diagnostic hardware assembly function mask */
781 #define CN_DHA_ST_MASK 0001600u /* diagnostic hardware assembly status mask */
782 #define CN_DHA_FLAG 0001000u /* diagnostic hardware assembly device flag value */
783 #define CN_DHA_FN_ENABLE 0000040u /* (E) enable diagnostic hardware assembly function */
784 #define CN_XFR_IRQ_ENABLE 0000020u /* (X) enable data transfer interrupt */
785 #define CN_DEVSTAT 0000010u /* (S) interrupt/device (0/1) status */
786 #define CN_BYTE_XFER 0000004u /* (B) word/byte (0/1) transfer */
787 #define CN_IRQ_ENABLE 0000002u /* (I) enable interrupts */
788 #define CN_XFR_TMR_ENABLE 0000001u /* (T) enable data transfer timer */
789
790 #define CN_RIN_SHIFT 11 /* reset interrupt request alignment shift */
791 #define CN_DHA_ST_SHIFT 7 /* diagnostic hardware assembly status alignment shift */
792 #define CN_DHA_FN_SHIFT 6 /* diagnostic hardware assembly function alignment shift */
793
794 #define CN_RESET(c) (((c) & CN_RIN_MASK) >> CN_RIN_SHIFT)
795 #define CN_DHA_ST(c) (((c) & CN_DHA_ST_MASK) >> CN_DHA_ST_SHIFT)
796 #define CN_DHA_FN(c) (((c) & CN_DHA_FN_MASK) >> CN_DHA_FN_SHIFT)
797
798 static const char *const dha_fn_name [16] = { /* DHA function names, indexed by CN_DHA_FN */
799 "clear registers", /* 0000 = clear registers (installs jumpers) */
800 "remove J2W2", /* 0001 = remove jumper J2W2 */
801 "assert DEVEND", /* 0010 = assert Device End */
802 "remove J2W8", /* 0011 = remove jumper J2W8 */
803 "set transfer error", /* 0100 = set Transfer Error flip-flop */
804 "remove J2W4", /* 0101 = remove jumper J2W4 */
805 "remove J2W10", /* 0110 = remove jumper J2W10 */
806 "remove J2W6", /* 0111 = remove jumper J2W6 */
807 "control 6 drives device flag", /* 1000 = connect device flag to control bit 6 */
808 "remove J2W5", /* 1001 = remove jumper J2W5 */
809 "assert CLRIF", /* 1010 = assert Clear Interface */
810 "remove J2W9", /* 1011 = remove jumper J2W9 */
811 "CLR/PON/PF drive status 8-10", /* 1100 = connect status 8-10 to master clear/power on/power fail */
812 "remove J2W1", /* 1101 = remove jumper J2W1 */
813 "remove J2W3", /* 1110 = remove jumper J2W3 */
814 "remove J2W7" /* 1111 = remove jumper J2W7 */
815 };
816
817 static const char *const reset_irq_name [8] = { /* reset interrupt request names, indexed by CN_RESET */
818 "", /* 000 = none */
819 " | reset timer/xfer error irq", /* 001 = watchdog timer and transfer error */
820 " | reset I/O system irq", /* 010 = I/O system */
821 " | reset clear interface irq", /* 011 = clear interface */
822 " | reset data xfer irq", /* 100 = data transfer completion */
823 " | reset status 8 irq", /* 101 = device status 8 */
824 " | reset status 9 irq", /* 110 = device status 9 */
825 " | reset status 10 irq" /* 111 = device status 10 */
826 };
827
828 static const BITSET_NAME dha_control_names [] = { /* DHA control word names */
829 "master clear", /* bit 0 */
830 "clear interrupts", /* bit 1 */
831 NULL, /* bit 2 */
832 NULL, /* bit 3 */
833 NULL, /* bit 4 */
834 "acquire data", /* bit 5 */
835 "DC6", /* bit 6 */
836 "DC7", /* bit 7 */
837 "DC8", /* bit 8 */
838 "DC9", /* bit 9 */
839 "enable function", /* bit 10 */
840 "enable data xfer interrupt", /* bit 11 */
841 "\1device status\0interrupt status", /* bit 12 */
842 "\1byte xfer\0word xfer", /* bit 13 */
843 "enable interrupts", /* bit 14 */
844 "enable transfer timer" /* bit 15 */
845 };
846
847 static const BITSET_FORMAT dha_control_format = /* names, offset, direction, alternates, bar */
848 { FMT_INIT (dha_control_names, 0, msb_first, has_alt, no_bar) };
849
850
851 /* Printer control word.
852
853 0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15
854 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
855 | M | R | irq reset | - - - - - | F | X | S | B | I | T | printer
856 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
857 */
858
859 #define CN_FORMAT 0000040u /* printer output character/format (0/1) code */
860
861 static const BITSET_NAME prt_control_names [] = { /* Printer control word names */
862 "master clear", /* bit 0 */
863 "clear interrupts", /* bit 1 */
864 NULL, /* bit 2 */
865 NULL, /* bit 3 */
866 NULL, /* bit 4 */
867 "acquire data", /* bit 5 */
868 NULL, /* bit 6 */
869 NULL, /* bit 7 */
870 NULL, /* bit 8 */
871 NULL, /* bit 9 */
872 "\1format\0character", /* bit 10 */
873 "enable data xfer interrupt", /* bit 11 */
874 "\1device status\0interrupt status", /* bit 12 */
875 "\1byte xfer\0word xfer", /* bit 13 */
876 "enable interrupts", /* bit 14 */
877 "enable transfer timer" /* bit 15 */
878 };
879
880 static const BITSET_FORMAT prt_control_format = /* names, offset, direction, alternates, bar */
881 { FMT_INIT (prt_control_names, 0, msb_first, has_alt, no_bar) };
882
883
884 /* Interface status word.
885
886 0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15
887 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
888 | S | D | I | seqct | F | 0 | 0 | dev irq | X | C | Y | E | T | interrupt
889 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
890 | S | D | I | seqct | F | 1 | 0 | device status | device
891 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
892
893
894 Implementation notes:
895
896 1. The entry for bit 6 of the interrupt status names formatting array is
897 given in the alternate form to print the "interrupt status" string when
898 the bit is zero.
899 */
900
901 #define ST_SIO_OK 0100000u /* (S) SIO OK to use */
902 #define ST_DIO_OK 0040000u /* (D) direct I/O OK to use */
903 #define ST_IRQ_PENDING 0020000u /* (I) interrupt pending */
904 #define ST_SEQ_COUNT_0 0000000u /* sequence count 0 (00) */
905 #define ST_SEQ_COUNT_1 0010000u /* sequence count 1 (10) */
906 #define ST_SEQ_COUNT_2 0014000u /* sequence count 2 (11) */
907 #define ST_SEQ_COUNT_3 0004000u /* sequence count 3 (01) */
908 #define ST_DEVFLAG 0002000u /* (F) device flag */
909 #define ST_DEVSTAT 0001000u /* interrupt/device (0/1) status */
910 #define ST_DEVIRQ_MASK 0000340u /* device interrupt request mask */
911 #define ST_ST8_IRQ 0000200u /* device status 8 interrupt */
912 #define ST_DHA_MR 0000200u /* diagnostic hardware assembly status 8 (master clear) */
913 #define ST_ST9_IRQ 0000100u /* device status 9 interrupt */
914 #define ST_DHA_PON 0000100u /* diagnostic hardware assembly status 9 (power on) */
915 #define ST_ST10_IRQ 0000040u /* device status 10 interrupt */
916 #define ST_DHA_NOT_PF 0000040u /* diagnostic hardware assembly status 10 (~power fail) */
917 #define ST_DHA_DEVSTAT_MASK 0000037u /* diagnostic hardware assembly status 11-15 mask */
918 #define ST_XFR_IRQ 0000020u /* (X) data transfer interrupt */
919 #define ST_ST11_SR 0000020u /* device status 11 service request */
920 #define ST_CLRIF_IRQ 0000010u /* (C) clear interface interrupt */
921 #define ST_IOSYS_IRQ 0000004u /* (Y) I/O system interrupt */
922 #define ST_XFERERR_IRQ 0000002u /* (E) transfer error interrupt */
923 #define ST_XFR_TMR_IRQ 0000001u /* (T) transfer timer interrupt */
924
925 #define ST_DEVIRQ_SHIFT 5 /* device status 8-10 interrupt request alignment shift */
926
927 #define ST_DEVIRQ(n) ((n) << ST_DEVIRQ_SHIFT & ST_DEVIRQ_MASK)
928
929 #define ST_CLRIL (ST_CLRIF_IRQ | ST_XFERERR_IRQ) /* conditions that assert the CLRIL signal */
930
931 static const uint32 sequence_counter [] = { /* externally visible sequencer values, indexed by SEQ_STATE */
932 ST_SEQ_COUNT_0, /* 00 = Idle */
933 ST_SEQ_COUNT_1, /* 10 = Device_Command_1 */
934 ST_SEQ_COUNT_2, /* 11 = Device_Flag_1 */
935 ST_SEQ_COUNT_3, /* 01 = Device_Command_2 */
936 ST_SEQ_COUNT_0 /* 00 = Device_Flag_2 */
937 };
938
939 static const uint32 reset_irq [8] = { /* selective reset irq mask values, indexed by CN_RESET */
940 ~0u, /* 000 = none */
941 ~(ST_XFR_TMR_IRQ | ST_XFERERR_IRQ), /* 001 = watchdog timer and transfer error */
942 ~ST_IOSYS_IRQ, /* 010 = I/O system */
943 ~ST_CLRIF_IRQ, /* 011 = clear interface */
944 ~ST_XFR_IRQ, /* 100 = data transfer completion */
945 ~ST_ST8_IRQ, /* 101 = device status 8 */
946 ~ST_ST9_IRQ, /* 110 = device status 9 */
947 ~ST_ST10_IRQ /* 111 = device status 10 */
948 };
949
950 static const BITSET_NAME int_status_names [] = { /* Interrupt status word names */
951 "SIO OK", /* bit 0 */
952 "DIO OK", /* bit 1 */
953 "interrupt", /* bit 2 */
954 "SEQ 1", /* bit 3 */
955 "SEQ 2", /* bit 4 */
956 "device flag", /* bit 5 */
957 "\1\0interrupt status", /* bit 6 */
958 NULL, /* bit 7 */
959 "status 8", /* bit 8 */
960 "status 9", /* bit 9 */
961 "status 10", /* bit 10 */
962 "data xfer", /* bit 11 */
963 "clear interface", /* bit 12 */
964 "system", /* bit 13 */
965 "transfer error", /* bit 14 */
966 "transfer timeout" /* bit 15 */
967 };
968
969 static const BITSET_NAME dev_status_names [] = { /* Device status word names */
970 "SIO OK", /* bit 0 */
971 "DIO OK", /* bit 1 */
972 "interrupt", /* bit 2 */
973 "SEQ 1", /* bit 3 */
974 "SEQ 2", /* bit 4 */
975 "device flag", /* bit 5 */
976 "device status", /* bit 6 */
977 NULL, /* bit 7 */
978 "DS8", /* bit 8 */
979 "DS9", /* bit 9 */
980 "DS10", /* bit 10 */
981 "DS11", /* bit 11 */
982 "DS12", /* bit 12 */
983 "DS13", /* bit 13 */
984 "DS14", /* bit 14 */
985 "DS15" /* bit 15 */
986 };
987
988 static const BITSET_FORMAT int_status_format = /* names, offset, direction, alternates, bar */
989 { FMT_INIT (int_status_names, 0, msb_first, has_alt, no_bar) };
990
991 static const BITSET_FORMAT dev_status_format = /* names, offset, direction, alternates, bar */
992 { FMT_INIT (dev_status_names, 0, msb_first, no_alt, no_bar) };
993
994
995 /* Printer status word.
996
997 0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15
998 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
999 | S | D | I | seqct | F | 1 | 0 | - | L | L | N | V | U | - | - | printer
1000 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1001 */
1002
1003 #define ST_ONLINE 0000140u /* online */
1004 #define ST_NOT_READY 0000020u /* not ready */
1005 #define ST_VFU_12 0000010u /* VFU channel 12 */
1006 #define ST_VFU_9 0000004u /* VFU channel 9 */
1007
1008 static const BITSET_NAME prt_status_names [] = { /* Printer status word names */
1009 "SIO OK", /* bit 0 */
1010 "DIO OK", /* bit 1 */
1011 "interrupt", /* bit 2 */
1012 "SEQ 1", /* bit 3 */
1013 "SEQ 2", /* bit 4 */
1014 "device flag", /* bit 5 */
1015 "device status", /* bit 6 */
1016 NULL, /* bit 7 */
1017 NULL, /* bit 8 */
1018 "\1online\0offline", /* bit 9 */
1019 NULL, /* bit 10 */
1020 "\1not ready\0ready", /* bit 11 */
1021 "VFU 12", /* bit 12 */
1022 "VFU 9" /* bit 13 */
1023 };
1024
1025 static const BITSET_FORMAT prt_status_format = /* names, offset, direction, alternates, bar */
1026 { FMT_INIT (prt_status_names, 2, msb_first, has_alt, no_bar) };
1027
1028
1029 /* Interface state */
1030
1031 static HP_WORD control_word = 0; /* control word */
1032 static HP_WORD int_status_word = 0; /* interrupt status word (bits 8-15) */
1033 static HP_WORD dev_status_word = 0; /* device status word (bits 8-15) */
1034 static HP_WORD read_word = 0; /* read word */
1035 static HP_WORD write_word = 0; /* write word */
1036
1037 static SEQ_STATE sequencer = Idle; /* data transfer handshake sequencer */
1038 static uint32 jumper_set = PRINTER_JUMPERS; /* set of configuration jumpers */
1039
1040 static FLIP_FLOP sio_busy = CLEAR; /* SIO busy flip-flop */
1041 static FLIP_FLOP channel_sr = CLEAR; /* channel service request flip-flop */
1042 static FLIP_FLOP device_sr = CLEAR; /* device service request flip-flop */
1043 static FLIP_FLOP input_xfer = CLEAR; /* input transfer flip-flop */
1044 static FLIP_FLOP output_xfer = CLEAR; /* output transfer flip-flop */
1045 static FLIP_FLOP read_xfer = CLEAR; /* read transfer flip-flop */
1046 static FLIP_FLOP write_xfer = CLEAR; /* write transfer flip-flop */
1047 static FLIP_FLOP interrupt_mask = SET; /* interrupt mask flip-flop */
1048
1049 static FLIP_FLOP device_command = CLEAR; /* device command flip-flop */
1050 static FLIP_FLOP device_flag = CLEAR; /* device flag flip-flop */
1051 static FLIP_FLOP device_end = CLEAR; /* device end flip-flop */
1052
1053 static HP_WORD data_out = 0; /* external DATA OUT signal bus */
1054 static t_bool device_command_out = FALSE; /* external DEV CMD signal state */
1055
1056 static HP_WORD data_in = 0; /* external DATA IN signal bus */
1057 static t_bool device_flag_in = FALSE; /* external DEV FLAG signal state */
1058 static t_bool device_end_in = FALSE; /* external DEV END signal state */
1059
1060
1061 /* Diagnostic Hardware Assembly state */
1062
1063 static HP_WORD dha_control_word = 0; /* Diagnostic Hardware Assembly control word */
1064 static t_bool power_warning = FALSE; /* PFWARN is not asserted to the DHA */
1065
1066
1067 /* Printer state */
1068
1069 static t_bool paper_fault = TRUE; /* TRUE if the printer is out of paper */
1070 static t_bool tape_fault = FALSE; /* TRUE if there is no punch in a commanded VFU channel */
1071 static t_bool offline_pending = FALSE; /* TRUE if an offline request is waiting for the printer to finish */
1072 static uint32 overprint_char = DEL; /* character to use if overprinted */
1073 static uint32 current_line = 1; /* current form line */
1074 static uint32 buffer_index = 0; /* current index into the print buffer */
1075
1076 static uint32 form_length; /* form length in lines */
1077 static uint8 buffer [BUFFER_SIZE]; /* character and paper advance buffer */
1078 static uint32 VFU [VFU_SIZE]; /* vertical format unit tape */
1079 static char vfu_title [LINE_SIZE]; /* descriptive title of the tape currently in the VFU */
1080
1081 static int32 punched_char = 'O'; /* character to display if VFU channel is punched */
1082 static int32 unpunched_char = '.'; /* character to display if VFU channel is not punched */
1083
1084 static const DELAY_PROPS *dlyptr = &fast_times; /* pointer to the event delay times to use */
1085
1086
1087 /* Interface local SCP support routines */
1088
1089 static CNTLR_INTRF ui_interface;
1090 static t_stat xfer_service (UNIT *uptr);
1091 static t_stat pulse_service (UNIT *uptr);
1092 static t_stat timer_service (UNIT *uptr);
1093 static t_stat ui_reset (DEVICE *dptr);
1094
1095
1096 /* Interface local utility routines */
1097
1098 static t_stat master_reset (t_bool programmed_clear);
1099 static void clear_interface_logic (void);
1100 static void activate_unit (UNIT *uptr);
1101 static void report_error (FILE *stream);
1102 static OUTBOUND_SET set_interrupt (uint32 interrupt);
1103 static OUTBOUND_SET set_device_status (uint32 status_mask, uint32 new_status_word);
1104 static OUTBOUND_SET handshake_xfer (void);
1105
1106
1107 /* Diagnostic Hardware Assembly local SCP support routines */
1108
1109 static t_stat diag_service (UNIT *uptr);
1110
1111
1112 /* Diagnostic Hardware Assembly local utility routines */
1113
1114 static t_stat diag_reset (t_bool programmed_clear);
1115 static OUTBOUND_SET diag_control (uint32 control_word);
1116
1117
1118 /* Printer local SCP support routines */
1119
1120 static t_stat lp_service (UNIT *uptr);
1121 static t_stat lp_attach (UNIT *uptr, char *cptr);
1122 static t_stat lp_detach (UNIT *uptr);
1123
1124 static t_stat lp_set_mode (UNIT *uptr, int32 value, char *cptr, void *desc);
1125 static t_stat lp_set_model (UNIT *uptr, int32 value, char *cptr, void *desc);
1126 static t_stat lp_set_on_offline (UNIT *uptr, int32 value, char *cptr, void *desc);
1127 static t_stat lp_set_vfu (UNIT *uptr, int32 value, char *cptr, void *desc);
1128 static t_stat lp_show_mode (FILE *st, UNIT *uptr, int32 value, void *desc);
1129 static t_stat lp_show_vfu (FILE *st, UNIT *uptr, int32 value, void *desc);
1130
1131
1132 /* Printer local utility routines */
1133
1134 static t_stat lp_reset (t_bool programmed_clear);
1135 static OUTBOUND_SET lp_control (uint32 control_word);
1136 static t_bool lp_set_alarm (UNIT *uptr);
1137 static t_bool lp_set_locality (UNIT *uptr, LOCALITY printer_state);
1138 static t_stat lp_load_vfu (UNIT *uptr, FILE *vf);
1139 static int32 lp_read_line (FILE *vf, char *line, uint32 size);
1140
1141
1142 /* Interface SCP data structures */
1143
1144
1145 /* Device information block */
1146
1147 static DIB lp_dib = {
1148 &ui_interface, /* device interface */
1149 14, /* device number */
1150 11, /* service request number */
1151 18, /* interrupt priority */
1152 INTMASK_E /* interrupt mask */
1153 };
1154
1155
1156 /* Unit list */
1157
1158 #define UNIT_FLAGS (UNIT_ATTABLE | UNIT_SEQ | UNIT_EXPAND | UNIT_OFFLINE)
1159
1160 static UNIT lp_unit [] = {
1161 { UDATA (&xfer_service, UNIT_FLAGS | UNIT_2617, 0), 0 },
1162 { UDATA (&pulse_service, UNIT_DIS, 0), PULSE_TIME },
1163 { UDATA (&timer_service, UNIT_DIS, 0), XFER_TIME }
1164 };
1165
1166
1167 /* Register list.
1168
1169 The list consists of the interface registers followed by the Diagnostic
1170 Hardware Assembly registers and then the printer registers.
1171
1172
1173 Implementation notes:
1174
1175 1. The DHA hardware buffers control word bits 6-10 to LEDs. Inspection and
1176 user confirmation of the control word state is required by the interface
1177 diagnostic. In simulation, bits 6-10 of the control word are presented
1178 as the CNLED register to allow an ASSERT command to test this subrange of
1179 bits with single commands.
1180 */
1181
1182 static REG lp_reg [] = {
1183 /* Macro Name Location Radix Width Offset Depth Flags */
1184 /* ------ ------ ------------------------ ----- ------------ ------ ------------- ------------------ */
1185 { FLDATA (SIOBSY, sio_busy, 0) },
1186 { FLDATA (CHANSR, channel_sr, 0) },
1187 { FLDATA (DEVSR, device_sr, 0) },
1188 { FLDATA (INXFR, input_xfer, 0) },
1189 { FLDATA (OUTXFR, output_xfer, 0) },
1190 { FLDATA (RDXFR, read_xfer, 0) },
1191 { FLDATA (WRXFR, write_xfer, 0) },
1192 { FLDATA (INTMSK, interrupt_mask, 0) },
1193
1194 { FLDATA (DEVCMD, device_command, 0) },
1195 { FLDATA (DEVFLG, device_flag, 0) },
1196 { FLDATA (DEVEND, device_end, 0) },
1197
1198 { DRDATA (SEQSTA, sequencer, 8), PV_LEFT },
1199 { ORDATA (CNTL, control_word, 16), PV_RZRO },
1200 { ORDATA (ISTAT, int_status_word, 16), PV_RZRO },
1201 { ORDATA (DSTAT, dev_status_word, 16), PV_RZRO },
1202 { ORDATA (READ, read_word, 16), PV_RZRO | REG_X },
1203 { ORDATA (WRITE, write_word, 16), PV_RZRO | REG_X },
1204 { YRDATA (J2WX, jumper_set, 10), PV_RZRO },
1205
1206 { ORDATA (DATOUT, data_out, 16), PV_RZRO | REG_X },
1207 { ORDATA (DATIN, data_in, 16), PV_RZRO | REG_X },
1208
1209 { FLDATA (DCOUT, device_command_out, 0) },
1210 { FLDATA (DFIN, device_flag_in, 0) },
1211 { FLDATA (DENDIN, device_end_in, 0) },
1212
1213 DIB_REGS (lp_dib),
1214
1215 { ORDATA (DIAGCN, dha_control_word, 16), PV_RZRO },
1216 { GRDATA (CNLED, control_word, 2, 5, 5), PV_RZRO },
1217 { FLDATA (PFWARN, power_warning, 0) },
1218
1219 { FLDATA (PFAULT, paper_fault, 0) },
1220 { FLDATA (TFAULT, tape_fault, 0) },
1221 { FLDATA (OLPEND, offline_pending, 0) },
1222
1223 { DRDATA (PRLINE, current_line, 8), PV_LEFT },
1224 { DRDATA (BUFIDX, buffer_index, 8), PV_LEFT },
1225 { BRDATA (PRTBUF, buffer, 8, 8, BUFFER_SIZE), PV_RZRO | REG_A },
1226 { ORDATA (OVPCHR, overprint_char, 8), PV_RZRO | REG_A },
1227
1228 { DRDATA (FORMLN, form_length, 8), PV_LEFT | REG_RO },
1229 { BRDATA (TITLE, vfu_title, 8, 8, LINE_SIZE), REG_HRO },
1230 { BRDATA (VFU, VFU, 2, VFU_WIDTH, VFU_SIZE), PV_RZRO | REG_RO },
1231 { ORDATA (PUNCHR, punched_char, 8), PV_RZRO | REG_A },
1232 { ORDATA (UNPCHR, unpunched_char, 8), PV_RZRO | REG_A },
1233
1234 { DRDATA (BTIME, fast_times.buffer_load, 24), PV_LEFT | REG_NZ },
1235 { DRDATA (PTIME, fast_times.print, 24), PV_LEFT | REG_NZ },
1236 { DRDATA (STIME, fast_times.advance, 24), PV_LEFT | REG_NZ },
1237 { DRDATA (POS, lp_unit [0].pos, T_ADDR_W), PV_LEFT },
1238 { DRDATA (UWAIT, lp_unit [0].wait, 32), PV_LEFT | REG_HRO },
1239
1240 { NULL }
1241 };
1242
1243
1244 /* Modifier list */
1245
1246 typedef enum { /* Device modes */
1247 Fast_Time, /* use optimized timing */
1248 Real_Time, /* use realistic timing */
1249 Printer, /* connect to the printer */
1250 Diagnostic /* connect to the DHA */
1251 } DEVICE_MODES;
1252
1253 static MTAB lp_mod [] = {
1254 /* Mask Value Match Value Print String Match String Validation Display Descriptor */
1255 /* ------------ ------------ ----------------- ------------ ------------------ ------- ---------- */
1256 { UNIT_MODEL, UNIT_2607, "2607", "2607", &lp_set_model, NULL, NULL },
1257 { UNIT_MODEL, UNIT_2613, "2613", "2613", &lp_set_model, NULL, NULL },
1258 { UNIT_MODEL, UNIT_2617, "2617", "2617", &lp_set_model, NULL, NULL },
1259 { UNIT_MODEL, UNIT_2618, "2618", "2618", &lp_set_model, NULL, NULL },
1260
1261 { UNIT_OFFLINE, UNIT_OFFLINE, "offline", "OFFLINE", &lp_set_on_offline, NULL, NULL },
1262 { UNIT_OFFLINE, 0, "online", "ONLINE", &lp_set_on_offline, NULL, NULL, },
1263
1264 { UNIT_EXPAND, UNIT_EXPAND, "expanded output", "EXPAND", NULL, NULL, NULL },
1265 { UNIT_EXPAND, 0, "compact output", "COMPACT", NULL, NULL, NULL, },
1266
1267 /* Entry Flags Value Print String Match String Validation Display Descriptor */
1268 /* ------------------- ----------- ------------ ------------ ------------ ------------- ---------------- */
1269 { MTAB_XDV, Fast_Time, NULL, "FASTTIME", &lp_set_mode, NULL, NULL },
1270 { MTAB_XDV, Real_Time, NULL, "REALTIME", &lp_set_mode, NULL, NULL },
1271 { MTAB_XDV, Printer, NULL, "PRINTER", &lp_set_mode, NULL, NULL },
1272 { MTAB_XDV, Diagnostic, NULL, "DIAGNOSTIC", &lp_set_mode, NULL, NULL },
1273 { MTAB_XDV, 0, "MODES", NULL, NULL, &lp_show_mode, NULL },
1274
1275 { MTAB_XDV, VAL_DEVNO, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &lp_dib },
1276 { MTAB_XDV, VAL_INTMASK, "INTMASK", "INTMASK", &hp_set_dib, &hp_show_dib, (void *) &lp_dib },
1277 { MTAB_XDV, VAL_INTPRI, "INTPRI", "INTPRI", &hp_set_dib, &hp_show_dib, (void *) &lp_dib },
1278 { MTAB_XDV, VAL_SRNO, "SRNO", "SRNO", &hp_set_dib, &hp_show_dib, (void *) &lp_dib },
1279
1280 { MTAB_XDV | MTAB_NMO, 1, "VFU", NULL, NULL, &lp_show_vfu, NULL },
1281 { MTAB_XDV | MTAB_NC, 0, "VFU", "VFU", &lp_set_vfu, &lp_show_vfu, NULL },
1282
1283 { 0 }
1284 };
1285
1286
1287 /* Debugging trace list */
1288
1289 static DEBTAB lp_deb [] = {
1290 { "CMD", DEB_CMD }, /* controller commands */
1291 { "CSRW", DEB_CSRW }, /* interface control, status, read, and write actions */
1292 { "SERV", DEB_SERV }, /* controller unit service scheduling calls */
1293 { "XFER", DEB_XFER }, /* controller data reads and writes */
1294 { "STATE", DEB_STATE }, /* handshake execution state changes */
1295 { "IOBUS", DEB_IOB }, /* interface I/O bus signals and data words */
1296 { NULL, 0 }
1297 };
1298
1299
1300 /* Device descriptor */
1301
1302 DEVICE lp_dev = {
1303 "LP", /* device name */
1304 lp_unit, /* unit array */
1305 lp_reg, /* register array */
1306 lp_mod, /* modifier array */
1307 3, /* number of units */
1308 10, /* address radix */
1309 32, /* address width = 4 GB */
1310 1, /* address increment */
1311 8, /* data radix */
1312 8, /* data width */
1313 NULL, /* examine routine */
1314 NULL, /* deposit routine */
1315 &ui_reset, /* reset routine */
1316 NULL, /* boot routine */
1317 &lp_attach, /* attach routine */
1318 &lp_detach, /* detach routine */
1319 &lp_dib, /* device information block pointer */
1320 DEV_DISABLE | DEV_DEBUG, /* device flags */
1321 0, /* debug control flags */
1322 lp_deb, /* debug flag name array */
1323 NULL, /* memory size change routine */
1324 NULL /* logical device name */
1325 };
1326
1327
1328
1329 /* Interface local SCP support routines */
1330
1331
1332
1333 /* Universal interface.
1334
1335 The universal interface is installed on the IOP and Multiplexer Channel buses
1336 and receives direct and programmed I/O commands from the IOP and Multiplexer
1337 Channel, respectively. In simulation, the asserted signals on the buses are
1338 represented as bits in the inbound_signals set. Each signal is processed
1339 sequentially in numerical order, and a set of similar outbound_signals is
1340 assembled and returned to the caller, simulating assertion of the
1341 corresponding backplane signals.
1342
1343 After setting the control mode to establish word or byte mode, SIO data
1344 transfer between the interface and the connected device is initiated by a
1345 PWRITESTB or READNEXTWD order. For direct I/O, a DWRITESTB or a DCONTSTB
1346 with the "acquire" bit set initiates a transfer.
1347
1348 A sequencer governs the generation of the device handshake signals. The
1349 handshake begins with the assertion of the Device Control signal. In
1350 response, the device asserts the Device Flag signal. The interface then
1351 denies Device Control, and the device denies Device Flag. For a byte
1352 transfer, this sequence repeats automatically for the second byte. Byte
1353 packing and unpacking is provided by the interface.
1354
1355 Eight interrupt sources are provided and may be individually set by their
1356 associated conditions. A master interrupt enable is provided by setting the
1357 appropriate control word bit, and the requesting sources may be cleared
1358 independently. An interrupt acknowledgement from the IOP clears the master
1359 interrupt enable to prevent multiple sources from interrupting
1360 simultaneously.
1361
1362 The status word returned by a DSTATSTB or PSTATSTB signal consists of
1363 interface status in the upper byte and either interrupt or device status in
1364 the lower byte, as selected by a control word bit.
1365
1366
1367 Implementation notes:
1368
1369 1. In a hardware transfer abort, READNEXTWD or PWRITESTB causes the
1370 sequencer to transition to the Device_Command_1 state and set the Device
1371 End flip-flop, which asserts DEVEND to the multiplexer channel, and then
1372 the Device End flip-flop is cleared by ACKSR. In simulation, ACKSR
1373 occurs before the PREADSTB or PWRITESTB that asserts DEVEND, so the state
1374 of the Device End flip-flop is saved in the ACKSR handler and is then
1375 checked in a subsequent PREADSTB or PWRITESTB to assert DEVEND.
1376
1377 2. In hardware, the SETJMP signal is ignored, and the JMPMET signal is
1378 asserted continuously when enabled by CHANSO.
1379
1380 3. In hardware, a power fail warning (PFWARN) is asserted continuously from
1381 detection until power is lost. In simulation, the "power_warning" flag
1382 is set by a PFWARN assertion and is cleared by a power-on reset. PFWARN
1383 is used only by the DHA.
1384 */
1385
ui_interface(DIB * dibptr,INBOUND_SET inbound_signals,HP_WORD inbound_value)1386 static SIGNALS_DATA ui_interface (DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value)
1387 {
1388 INBOUND_SIGNAL signal;
1389 INBOUND_SET working_set = inbound_signals;
1390 HP_WORD outbound_value = 0;
1391 OUTBOUND_SET outbound_signals = NO_SIGNALS;
1392 t_bool abort_transfer = FALSE;
1393
1394 tprintf (lp_dev, DEB_IOB, "Received data %06o with signals %s\n",
1395 inbound_value, fmt_bitset (inbound_signals, inbound_format));
1396
1397 while (working_set) {
1398 signal = IONEXTSIG (working_set); /* isolate the next signal */
1399
1400 switch (signal) { /* dispatch an I/O signal */
1401
1402 case INTPOLLIN:
1403 if (dibptr->interrupt_request) { /* if a request is pending */
1404 dibptr->interrupt_request = CLEAR; /* then clear it */
1405 dibptr->interrupt_active = SET; /* and mark it now active */
1406
1407 outbound_signals |= INTACK; /* acknowledge the interrupt */
1408 outbound_value = dibptr->device_number; /* and return our device number */
1409
1410 control_word &= ~(CN_DEVSTAT | CN_IRQ_ENABLE); /* clear the device status and IRQ enable flip-flops */
1411 }
1412
1413 else /* otherwise the request has been reset */
1414 outbound_signals |= INTPOLLOUT; /* so let the IOP know to cancel it */
1415 break;
1416
1417
1418 case SETINT:
1419 case DSETINT:
1420 outbound_signals |= set_interrupt (ST_IOSYS_IRQ); /* set the I/O system interrupt flip-flop */
1421 break;
1422
1423
1424 case DRESETINT:
1425 dibptr->interrupt_active = CLEAR; /* reset the interrupt active flip-flop */
1426 outbound_signals |= set_interrupt (0); /* and check whether another IRQ is pending */
1427 break;
1428
1429
1430 case DSETMASK:
1431 if (dibptr->interrupt_mask == INTMASK_E) /* if the mask is always enabled */
1432 interrupt_mask = SET; /* then set the mask flip-flop */
1433 else /* otherwise */
1434 interrupt_mask = D_FF (dibptr->interrupt_mask /* set the mask flip-flop if the mask bit */
1435 & inbound_value); /* is present in the mask value */
1436
1437 outbound_signals |= set_interrupt (0); /* check whether an IRQ is pending */
1438 break;
1439
1440
1441 case PCONTSTB:
1442 if (! J2W1_INSTALLED) /* if W1 (SR set by Device Status) is not installed */
1443 device_sr = SET; /* then set the device service request flip-flop */
1444
1445 /* fall through into the DCONTSTB case */
1446
1447 case DCONTSTB:
1448 tprintf (lp_dev, DEB_CSRW,
1449 (lp_dev.flags & DEV_DIAG && inbound_value & CN_DHA_FN_ENABLE
1450 ? "Control is %s%s | %s\n"
1451 : "Control is %s%s\n"),
1452 fmt_bitset (inbound_value,
1453 (lp_dev.flags & DEV_DIAG
1454 ? dha_control_format
1455 : prt_control_format)),
1456 reset_irq_name [CN_RESET (inbound_value)],
1457 dha_fn_name [CN_DHA_FN (inbound_value)]);
1458
1459 if (inbound_value & CN_MR) /* if the programmed master reset bit is set */
1460 master_reset (TRUE); /* then reset the interface and the control word */
1461
1462 else if (inbound_value & CN_RIN) { /* otherwise if the reset interrupt bit is set */
1463 dibptr->interrupt_request = CLEAR; /* then clear the interrupt request */
1464 int_status_word = 0; /* and all interrupt sources */
1465
1466 sim_cancel (timer_uptr); /* cancel the transfer timer */
1467 control_word = inbound_value; /* and set the control word */
1468 }
1469
1470 else { /* otherwise */
1471 int_status_word &= reset_irq [CN_RESET (inbound_value)]; /* clear the specified IRQ source */
1472
1473 if ((inbound_value & CN_RIN_MASK) == CN_RIN_XFR_TMR) /* if the timer interrupt was cleared */
1474 sim_cancel (timer_uptr); /* then stop the timer too */
1475
1476 else if (CN_XFR_TMR_ENABLE /* otherwise if the transfer timer */
1477 & ~control_word & inbound_value) { /* is enabled with a 0-to-1 transition */
1478 sim_cancel (timer_uptr); /* then retrigger */
1479 activate_unit (timer_uptr); /* the timer */
1480 }
1481
1482 control_word = inbound_value; /* set the control word */
1483 }
1484
1485 if (control_word & CN_ACQUIRE) { /* if the next word is requested */
1486 device_command = SET; /* then set the device command flip-flop */
1487 read_xfer = SET; /* and the read transfer flip-flop */
1488 outbound_signals |= handshake_xfer (); /* and start the device handshake */
1489 }
1490
1491 if (lp_dev.flags & DEV_DIAG) /* if the DHA is installed */
1492 outbound_signals |= diag_control (control_word); /* then process the DHA-specific controls */
1493 else /* otherwise */
1494 outbound_signals |= lp_control (control_word); /* process the device-specific controls */
1495
1496 break;
1497
1498
1499 case PSTATSTB:
1500 case DSTATSTB:
1501 outbound_value = sequence_counter [sequencer]; /* start with the sequence counter value */
1502
1503 if (sio_busy == CLEAR /* if the interface is inactive */
1504 && (int_status_word & ST_CLRIL) == 0) /* and the clear interface logic IRQ is denied */
1505 outbound_value |= ST_SIO_OK; /* then programmed I/O is enabled */
1506
1507 if (sequencer == Idle) /* if the device is inactive */
1508 outbound_value |= ST_DIO_OK; /* then direct I/O is enabled */
1509
1510 if (int_status_word) /* if any interrupt requests are pending */
1511 outbound_value |= ST_IRQ_PENDING; /* then set the status bit */
1512
1513 if (device_flag_in) /* if the device flag is asserted */
1514 outbound_value |= ST_DEVFLAG; /* then set the status bit */
1515
1516 if (control_word & CN_DEVSTAT) /* if the device status flip-flop is set */
1517 outbound_value |= ST_DEVSTAT | dev_status_word; /* then return the device status */
1518 else /* otherwise */
1519 outbound_value |= int_status_word; /* return the interrupt status */
1520
1521 tprintf (lp_dev, DEB_CSRW, "Status is %s\n",
1522 fmt_bitset (outbound_value,
1523 (control_word & CN_DEVSTAT
1524 ? (lp_dev.flags & DEV_DIAG
1525 ? dev_status_format
1526 : prt_status_format)
1527 : int_status_format)));
1528 break;
1529
1530
1531 case DREADSTB:
1532 outbound_value = (HP_WORD) read_word; /* return the data input register value */
1533 break;
1534
1535
1536 case DWRITESTB:
1537 write_word = (uint32) inbound_value; /* store the value in the data output register */
1538
1539 device_command = SET; /* set the device command flip-flop */
1540 write_xfer = SET; /* and the write transfer flip-flop */
1541 outbound_signals |= handshake_xfer (); /* and start the device handshake */
1542 break;
1543
1544
1545 case DSTARTIO:
1546 tprintf (lp_dev, DEB_CSRW, "Channel program started\n");
1547
1548 sio_busy = SET; /* set the SIO busy flip-flop */
1549
1550 mpx_assert_REQ (dibptr); /* request the channel */
1551
1552 channel_sr = SET; /* set the service request flip-flop */
1553 outbound_signals |= SRn; /* and assert a service request */
1554 break;
1555
1556
1557 case ACKSR:
1558 device_sr = CLEAR; /* acknowledge the service request */
1559
1560 abort_transfer = (t_bool) device_end; /* TRUE if the transfer is to be aborted */
1561 device_end = CLEAR; /* clear the device end flip-flop */
1562 break;
1563
1564
1565 case TOGGLESR:
1566 TOGGLE (channel_sr); /* set or clear the channel service request flip-flop */
1567 break;
1568
1569
1570 case TOGGLESIOOK:
1571 TOGGLE (sio_busy); /* set or clear the SIO busy flip-flop */
1572
1573 if (sio_busy == CLEAR)
1574 tprintf (lp_dev, DEB_CSRW, "Channel program ended\n");
1575 break;
1576
1577
1578 case TOGGLEINXFER:
1579 TOGGLE (input_xfer); /* set or clear the input transfer flip-flop */
1580
1581 device_end_in = FALSE; /* clear the external device end condition */
1582 break;
1583
1584
1585 case TOGGLEOUTXFER:
1586 TOGGLE (output_xfer); /* set or clear the output transfer flip-flop */
1587
1588 if (output_xfer == SET) /* if starting an output transfer */
1589 device_sr = SET; /* request the first word to write */
1590
1591 device_end_in = FALSE; /* clear the external device end condition */
1592 break;
1593
1594
1595 case PCMD1:
1596 device_sr = SET; /* request the second control word */
1597 break;
1598
1599
1600 case READNEXTWD:
1601 device_command = SET; /* set the device command flip-flop */
1602 read_xfer = SET; /* and the read transfer flip-flop */
1603 outbound_signals |= handshake_xfer (); /* and start the device handshake */
1604 break;
1605
1606
1607 case PREADSTB:
1608 if (abort_transfer) { /* if the transfer has been aborted */
1609 outbound_value = dibptr->device_number * 4; /* then return the DRT address */
1610 outbound_signals |= DEVEND; /* and indicate a device abort */
1611 }
1612
1613 else /* otherwise the transfer continues */
1614 outbound_value = (HP_WORD) read_word; /* so return the data input register value */
1615 break;
1616
1617
1618 case PWRITESTB:
1619 if (abort_transfer) { /* if the transfer has been aborted */
1620 outbound_value = dibptr->device_number * 4; /* then return the DRT address */
1621 outbound_signals |= DEVEND; /* and indicate a device abort */
1622 }
1623
1624 else { /* otherwise the transfer continues */
1625 write_word = (uint32) inbound_value; /* so store the value in the data output register */
1626
1627 device_command = SET; /* set the device command flip-flop */
1628 write_xfer = SET; /* and the write transfer flip-flop */
1629 outbound_signals |= handshake_xfer (); /* and start the device handshake */
1630 }
1631 break;
1632
1633
1634 case DEVNODB:
1635 outbound_value = dibptr->device_number * 4; /* return the DRT address */
1636 break;
1637
1638
1639 case XFERERROR:
1640 tprintf (lp_dev, DEB_CSRW, "Channel program aborted\n");
1641
1642 clear_interface_logic (); /* clear the interface to abort the transfer */
1643
1644 outbound_signals |= set_interrupt (ST_XFERERR_IRQ); /* set the transfer error interrupt flip-flop */
1645 break;
1646
1647
1648 case CHANSO:
1649 if (channel_sr | device_sr) /* if the interface has requested service */
1650 outbound_signals |= SRn; /* then assert SRn to the channel */
1651
1652 outbound_signals |= JMPMET; /* JMPMET is tied active on this interface */
1653 break;
1654
1655
1656 case EOT:
1657 if (inbound_signals & PREADSTB) /* if this is the end of a read transfer */
1658 device_sr = SET; /* then request channel service */
1659 break;
1660
1661
1662 case PFWARN:
1663 power_warning = TRUE; /* system power is in the process of failing */
1664 break;
1665
1666
1667 case SETJMP: /* not used by this interface */
1668 break;
1669 }
1670
1671 IOCLEARSIG (working_set, signal); /* remove the current signal from the set */
1672 }
1673
1674
1675 tprintf (lp_dev, DEB_IOB, "Returned data %06o with signals %s\n",
1676 outbound_value, fmt_bitset (outbound_signals, outbound_format));
1677
1678 return IORETURN (outbound_signals, outbound_value); /* return the outbound signals and value */
1679 }
1680
1681
1682 /* Service the transfer handshake.
1683
1684 This service routine is called once for each state of the device transfer
1685 handshake. The handshake sequencer schedules the transfer events with the
1686 appropriate delays.
1687
1688 Jumper W10 determines the output polarity of the DEV CMD signal to the
1689 device, and jumpers W2 and W6 determine the input edges of the DEV FLAG
1690 signal from the device used to assert and deny the Device Flag, as follows:
1691
1692 Jumper Interpretation when removed Interpretation when installed
1693 ------ ----------------------------- -----------------------------
1694 W10 DEV CMD polarity is normal DEV CMD polarity is inverted
1695
1696 W2 Flag asserts on leading edge Flag asserts on trailing edge
1697
1698 W6 Flag denies on trailing edge Flag denies on leading edge
1699
1700 Note that if jumpers W2 and W6 are not installed or removed in pairs, the
1701 Device Flag asserts and denies on the same edge of the DEV FLAG signal. In
1702 this case, the service routine sets the flag on the first call and clears the
1703 flag on the second call without requiring a change in the incoming signal.
1704
1705
1706 Implementation notes:
1707
1708 1. The "device_command_out" and "device_flag_in" variables represent the
1709 states of the DEV CMD and DEV FLAG signal lines. Edge detection for the
1710 Device Flag is accomplished by comparing the current state to the prior
1711 state.
1712
1713 2. As the routine was entered by an event timer expiration, the handshake
1714 sequencer must be called explicitly, and any returned backplane signals
1715 must be asserted explicitly.
1716
1717 3. This routine may be called with a NULL "uptr" parameter to update the
1718 saved last state of the "device_flag_in" variable. The NULL value
1719 indicates that this is not part of the normal handshake sequence.
1720 */
1721
xfer_service(UNIT * uptr)1722 static t_stat xfer_service (UNIT *uptr)
1723 {
1724 static t_bool device_flag_last = FALSE;
1725 t_stat result;
1726 OUTBOUND_SET signals;
1727
1728 device_command_out = device_command ^ J2W10_INSTALLED; /* set device command out; invert if W10 is installed */
1729
1730 if (lp_dev.flags & DEV_DIAG) /* if the DHA is connected */
1731 result = diag_service (uptr); /* then service the diagnostic hardware */
1732 else /* otherwise */
1733 result = lp_service (uptr); /* service the connected device */
1734
1735 if (sequencer == Device_Command_1 /* if Device Command */
1736 || sequencer == Device_Command_2) { /* is asserted */
1737 if (device_flag_last != device_flag_in /* then if the flag input has changed */
1738 && J2W2_INSTALLED ^ device_flag_in) /* and jumper W2 is in and 1 -> 0 or W2 is out and 0 -> 1 */
1739 device_flag = SET; /* then Device Flag sets */
1740 }
1741
1742 else /* otherwise Device Command is denied */
1743 if (J2W2_INSTALLED != J2W6_INSTALLED /* so if W2 installation differs from W6 installation */
1744 || (device_flag_last != device_flag_in /* or if the flag input has changed */
1745 && J2W6_INSTALLED ^ device_flag_last)) /* and jumper W6 is in and 0 -> 1 or W6 is out and 1 -> 0 */
1746 device_flag = CLEAR; /* then Device Flag clears */
1747
1748 device_flag_last = device_flag_in; /* save the current state of the flag */
1749
1750 signals = handshake_xfer (); /* continue the handshake */
1751
1752 if (signals & INTREQ) /* if an interrupt request was generated */
1753 iop_assert_INTREQ (&lp_dib); /* then assert the INTREQ signal */
1754
1755 if (signals & SRn) /* if a service request was generated */
1756 mpx_assert_SRn (&lp_dib); /* then assert the SRn signal */
1757
1758 return result; /* return the result of the service call */
1759 }
1760
1761
1762 /* Service the device command pulse timer.
1763
1764 In pulse mode, the DEV CMD signal asserts for 8 microseconds. This service
1765 routine is entered to deny DEV CMD. The transfer service is called directly
1766 to notify it of Device Command clearing, and the handshake sequencer is then
1767 called in case the transfer service altered the Device Flag in response.
1768 */
1769
pulse_service(UNIT * uptr)1770 static t_stat pulse_service (UNIT *uptr)
1771 {
1772 t_stat status;
1773
1774 tprintf (lp_dev, DEB_SERV, "Pulse service entered\n");
1775
1776 device_command = CLEAR; /* clear the device command flip-flop */
1777
1778 status = xfer_service (xfer_uptr); /* let the device know that command has denied */
1779 handshake_xfer (); /* and continue the handshake */
1780
1781 return status;
1782 }
1783
1784
1785 /* Service the transfer timer.
1786
1787 Setting the appropriate bit in the control word starts the five-second
1788 transfer timer. If it expires, this routine is entered. The transfer timer
1789 interrupt is set, and if interrupts are enabled, INTREQ is asserted to the
1790 IOP. As a convenience to the user, the file attached to the device unit is
1791 flushed.
1792 */
1793
timer_service(UNIT * uptr)1794 static t_stat timer_service (UNIT *uptr)
1795 {
1796 tprintf (lp_dev, DEB_SERV, "Watchdog service entered\n");
1797
1798 if (set_interrupt (ST_XFR_TMR_IRQ) == INTREQ) /* set the transfer timer interrupt flip-flop */
1799 iop_assert_INTREQ (&lp_dib); /* and assert the INTREQ signal if enabled */
1800
1801 if (xfer_unit.flags & UNIT_ATT) /* if the transfer unit is attached */
1802 fflush (xfer_unit.fileref); /* then flush any partial output */
1803
1804 return SCPE_OK; /* return success */
1805 }
1806
1807
1808 /* Device reset routine.
1809
1810 This routine is called for a RESET or RESET LP command. It is the simulation
1811 equivalent of the IORESET signal, which is asserted by the front panel LOAD
1812 and DUMP switches.
1813
1814 For this interface, IORESET is identical to the Programmed Master Clear
1815 invoked by setting bit 0 of the control word.
1816
1817
1818 Implementation notes:
1819
1820 1. Calling "master_reset" with a FALSE parameter indicates that this is a
1821 commanded reset. This allows the connected device-specific reset
1822 routines to distinguish from a Programmed Master Clear.
1823 */
1824
ui_reset(DEVICE * dptr)1825 static t_stat ui_reset (DEVICE *dptr)
1826 {
1827 return master_reset (FALSE); /* perform a non-programmed master reset */
1828 }
1829
1830
1831
1832 /* Interface local utility routines */
1833
1834
1835
1836 /* Master reset.
1837
1838 A master reset is generated either by an I/O Reset signal or a Programmed
1839 Master Clear (CIO bit 0). It sets the interrupt mask, clears any pending or
1840 active interrupt, clears all interrupt sources, clears the control word,
1841 clears the read and write registers, resets the handshake sequencer to its
1842 idle state, clears the interface logic flip-flops, and cancels all active
1843 event timers. It also calls pulses the MASTER CLEAR signal line to the
1844 device for a preset time.
1845
1846
1847 Implementation notes:
1848
1849 1. Calling the reset routine for the connected device simulates asserting
1850 the MASTER CLEAR signal.
1851 */
1852
master_reset(t_bool programmed_clear)1853 static t_stat master_reset (t_bool programmed_clear)
1854 {
1855 interrupt_mask = SET; /* set the interrupt mask flip-flop */
1856
1857 lp_dib.interrupt_request = CLEAR; /* clear any current */
1858 lp_dib.interrupt_active = CLEAR; /* interrupt request */
1859
1860 int_status_word = 0; /* clear all interrupt request sources */
1861
1862 control_word = 0; /* clear the control word */
1863 write_word = 0; /* and the output data register */
1864 read_word = 0; /* and the input data register */
1865
1866 sequencer = Idle; /* clear the handshake sequencer to the idle state */
1867
1868 read_xfer = CLEAR; /* clear the read transfer */
1869 write_xfer = CLEAR; /* and write transfer flip-flops */
1870
1871 device_command = CLEAR; /* clear the device command */
1872 device_flag = CLEAR; /* and device flag flip-flops */
1873
1874 data_out = 0; /* clear the external state */
1875 data_in = 0; /* of the I/O lines */
1876 device_end_in = FALSE; /* and the external device end line */
1877
1878 clear_interface_logic (); /* clear the interface to abort any transfer in progress */
1879
1880 sim_cancel (xfer_uptr); /* cancel */
1881 sim_cancel (pulse_uptr); /* any pending */
1882 sim_cancel (timer_uptr); /* event timers */
1883
1884 if (lp_dev.flags & DEV_DIAG) /* if the DHA is installed */
1885 return diag_reset (programmed_clear); /* then reset the diagnostic hardware */
1886 else /* otherwise */
1887 return lp_reset (programmed_clear); /* reset the device */
1888 }
1889
1890
1891 /* Clear the interface logic.
1892
1893 The clear interface logic signal is asserted when the channel indicates a
1894 transfer failure by asserting XFERERROR, or when the device asserts the CLEAR
1895 INTERFACE signal. It clears the SIO Busy, Channel and Device Service
1896 Request, Input Transfer, Output Transfer, and Device End flip-flops.
1897 */
1898
clear_interface_logic(void)1899 static void clear_interface_logic (void)
1900 {
1901 sio_busy = CLEAR; /* clear the SIO busy flip-flop */
1902 channel_sr = CLEAR; /* and the channel service request flip-flop */
1903 device_sr = CLEAR; /* and the device service request flip-flop */
1904 input_xfer = CLEAR; /* and the input transfer flip-flop */
1905 output_xfer = CLEAR; /* and the output transfer flip-flop */
1906 device_end = CLEAR; /* and the device end flip-flop */
1907
1908 return;
1909 }
1910
1911
1912 /* Activate the unit.
1913
1914 The specified unit is activated using the unit's "wait" time. If tracing
1915 is enabled, the activation is logged to the debug file.
1916
1917
1918 Implementation notes:
1919
1920 1. A zero-length delay is scheduled, rather than calling the service routine
1921 directly, so that the status return value from the event service routine
1922 is correctly passed back to SCP.
1923 */
1924
activate_unit(UNIT * uptr)1925 static void activate_unit (UNIT *uptr)
1926 {
1927 tprintf (lp_dev, DEB_SERV, "%s delay %u service scheduled\n",
1928 unit_name [uptr - lp_unit], uptr->wait);
1929
1930 sim_activate (uptr, uptr->wait); /* activate the unit */
1931
1932 return;
1933 }
1934
1935
1936 /* Report a stream I/O error to the console.
1937
1938 If a stream I/O error has been detected, this routine will print an error
1939 message to the simulation console and clear the stream's error indicator.
1940 */
1941
report_error(FILE * stream)1942 static void report_error (FILE *stream)
1943 {
1944 cprintf ("%s simulator printer I/O error: %s\n", /* report the error to the console */
1945 sim_name, strerror (errno));
1946
1947 clearerr (stream); /* clear the error */
1948
1949 return;
1950 }
1951
1952
1953 /* Set an interrupt.
1954
1955 The interrupt bit specified is set in the interrupt status word. If enabled,
1956 INTREQ is returned to request an interrupt.
1957
1958 The routine is also called with a zero "interrupt" parameter value to check
1959 whether an interrupt should be requested.
1960 */
1961
set_interrupt(uint32 interrupt)1962 static OUTBOUND_SET set_interrupt (uint32 interrupt)
1963 {
1964 int_status_word |= interrupt; /* set the specified interrupt flip-flop */
1965
1966 if (int_status_word /* if an interrupt request is present */
1967 && control_word & CN_IRQ_ENABLE /* and the IRQ enable flip-flop is set */
1968 && lp_dib.interrupt_active == CLEAR /* and no interrupt is currently active */
1969 && interrupt_mask == SET) { /* and the interrupt mask is satisfied */
1970 lp_dib.interrupt_request = SET; /* then request an interrupt */
1971 return INTREQ; /* and assert the INTREQ signal */
1972 }
1973
1974 else /* otherwise an interrupt request */
1975 return NO_SIGNALS; /* cannot be made at this time */
1976 }
1977
1978
1979 /* Set the device status.
1980
1981 The device status word is masked with the supplied "status_mask" and then the
1982 corresponding bits of the "new_status_word" are merged in. If enabled by the
1983 associated jumpers and the required edge transitions, interrupts for status
1984 bits 8-10 may be generated.
1985 */
1986
set_device_status(uint32 status_mask,uint32 new_status_word)1987 static OUTBOUND_SET set_device_status (uint32 status_mask, uint32 new_status_word)
1988 {
1989 OUTBOUND_SET outbound_signals = NO_SIGNALS;
1990
1991 if (status_mask & ST_DEVIRQ_MASK) { /* if a status interrupt is possible */
1992 if (J2W4_INSTALLED /* then if jumper J4 is installed to enable */
1993 && ~dev_status_word & new_status_word & ST_ST8_IRQ) /* and a 0 -> 1 transition occurred on status 8 */
1994 outbound_signals |= set_interrupt (ST_ST8_IRQ); /* then set the status 8 interrupt flip-flop */
1995
1996 if (J2W8_INSTALLED /* if jumper J8 is installed to enable */
1997 && ~dev_status_word & new_status_word & ST_ST9_IRQ) /* and a 0 -> 1 transition occurred on status 9 */
1998 outbound_signals |= set_interrupt (ST_ST9_IRQ); /* then set the status 9 interrupt flip-flop */
1999
2000 if (J2W9_INSTALLED /* if jumper J9 is installed to enable */
2001 && dev_status_word & ~new_status_word & ST_ST10_IRQ) /* and a 1 -> 0 transition occurred on status 10 */
2002 outbound_signals |= set_interrupt (ST_ST10_IRQ); /* then set the status 10 interrupt flip-flop */
2003 }
2004
2005 dev_status_word = dev_status_word & ~status_mask /* clear the old device status */
2006 | new_status_word & status_mask; /* and set the new status */
2007
2008 return outbound_signals; /* return INTREQ if any interrupts were requested */
2009 }
2010
2011
2012 /* Start or continue the data transfer handshake.
2013
2014 This routine implements the two-wire data transfer handshake with the device.
2015 For each word or byte transferred, the Device Command signal from the
2016 interface and the Device Flag signal from the device assume these states:
2017
2018 Command Flag State Next State
2019 State State Action Transition
2020 -------- -------- ---------------- --------------
2021 denied denied device idle Command sets
2022 asserted denied device started Flag sets
2023 asserted asserted device completed Command clears
2024 denied asserted interface idle Flag clears
2025
2026 In hardware, a two-bit gray counter implements a four-state sequencer, with
2027 three states assigned as follows for a word transfer:
2028
2029 Command Flag
2030 State State Action State State Next State Transition
2031 ----- ------------------ -------- -------- ---------------------
2032 0 0 idle denied denied read or write command
2033 1 0 word requested asserted denied Flag sets
2034 1 1 word started denied asserted Flag clears
2035 0 0 word completed denied denied ---
2036
2037 For a two-byte transfer, the states are:
2038
2039 Command Flag
2040 State State Action State State Next State Transition
2041 ----- ------------------ -------- -------- ---------------------
2042 0 0 idle denied denied read or write command
2043 1 0 1st byte requested asserted denied Flag sets
2044 1 1 1st byte started denied asserted Flag clears
2045 1 0 1st byte completed asserted denied Flag sets
2046 2nd byte requested
2047 0 0 2nd byte started denied asserted Flag clears
2048 0 0 2nd byte completed denied denied ---
2049
2050 The presence of the asserted Device Flag when the count is 00 differentiates
2051 between the "2nd byte started" and "operation completed" conditions.
2052
2053 In simulation, these last two conditions are assigned to separate states, as
2054 follows:
2055
2056 Hdwe Simulation Command Flag
2057 State State State State
2058 ----- ---------------- -------- --------
2059 0 0 Idle denied denied
2060 1 0 Device_Command_1 asserted denied
2061 1 1 Device_Flag_1 denied asserted
2062 1 0 Device_Command_2 asserted denied
2063 0 0 Device_Flag_2 denied asserted
2064 0 0 Idle denied denied
2065
2066 To provide the proper values to appear in the Sequence Counter field of the
2067 status word, a mapping array is used to supply the value 00 for the
2068 Device_Flag_2 state.
2069
2070 The device service is scheduled after each state transition, except the
2071 return to the idle state, to detect the change in the Device Command signal
2072 or to schedule the change in the Device Flag. The device determines whether
2073 the service will be entered immediately (at the next poll) or after a delay
2074 time expires.
2075
2076 For the diagnostic device, the service routine is entered immediately for all
2077 transitions. For the printer device, the service routine is entered
2078 immediately for Device Flag assertions, but flag denials are scheduled with a
2079 delay corresponding to the printer operation time. The operations are as
2080 follows:
2081
2082 Diagnostic Service Diagnostic Service
2083 State Printer Service Flag follows Cmd Flag follows cont.6
2084 ---------------- ---------------- ------------------ -------------------
2085 Device_Command_1 set Flag set Flag wait for Control.6
2086 Device_Flag_1 wait for service clear Flag wait for Control.6
2087 Device_Command_2 set Flag set Flag wait for Control.6
2088 Device_Flag_2 wait for service clear Flag wait for Control.6
2089
2090 If the device asserts the DEV END signal in response to Device Command, the
2091 Device End flip-flop is set, and the sequencer is reset back to the Idle
2092 state to abort the transfer. DEV END assertion in any other state is ignored
2093 until Device Command is set.
2094
2095 If jumper W3 is installed, DEV CMD is pulsed for 8 microseconds by asserting
2096 Device Command and scheduling the pulse timer to deny it when the event timer
2097 expires.
2098
2099 A DWRITESTB or PWRITESTB signal stores a 16-bit value in the data output
2100 register. In word mode, the value is presented continuously on the 16 DATA
2101 OUT lines. In byte mode, the upper byte in the data output register is
2102 presented on both bytes of the DATA OUT lines until the Device Flag sets to
2103 indicate that the device has accepted the first byte, whereupon the full
2104 16-bit value is presented on the DATA OUT lines. The result is that the
2105 upper byte and then the lower byte appears on the lower byte of the DATA OUT
2106 lines.
2107
2108 During byte-mode read cycles, the previously stored full 16-bit output value
2109 is presented on the DATA OUT lines if J2W7 is removed. If J2W7 is installed,
2110 the upper byte and then the lower byte appears on the lower byte. In other
2111 words, a byte read with J2W7 installed causes the DATA OUT lines to assume
2112 the same values in sequence that occur during a byte write. This is used by
2113 the diagnostic to test the DATA OUT multiplexer.
2114
2115 A read is initiated by the READNEXTWD signal or by setting the Acquire bit in
2116 the control word. Device Command sets in response. While Device Command is
2117 set, the data input register is transparent and passes the value on the Data
2118 In lines through. When Device Flag sets, the value on the DATA IN lines is
2119 latched in the register. A DREADSTB or PREADSTB signal then enables the
2120 register onto the IOP Data bus. With J2W5 installed, the data in register is
2121 always transparent, and a DREADSTB or PREADSTB signal presents the current
2122 value on the DATA IN lines to the IOP Data bus.
2123
2124 In word mode with J2W5 removed, 16-bit data presented at the DATA IN lines is
2125 passed through the data input register while Device Command is set and is
2126 latched when the Device Flag sets. In byte mode with J2W5 removed, the value
2127 presented on the lower byte of the DATA IN lines is presented to both bytes
2128 of the data input register, passed through while Device Command is set, and
2129 latched into both bytes of the register when the Device Flag sets to indicate
2130 that the device has supplied the first byte. When Device Command sets for
2131 the second byte, the value presented on the lower byte of the DATA IN lines
2132 is presented to the lower byte of the data input register, passed through
2133 while Device Command is set, and latched into the lower byte when the Device
2134 Flag sets to indicate that the device has supplied the second byte. The
2135 result is that the data input register presents the first byte in both bytes
2136 of the register and then the second byte presents as the lower byte of the
2137 register, resulting in a packed 16-bit value.
2138
2139
2140 Implementation notes:
2141
2142 1. In hardware, the sequencer moves from state 2 through state 3 to state 0
2143 when the device flag denies at the end of a word transfer. For a packed
2144 byte transfer, the sequencer moves from state 3 to state 0 when the
2145 device flag asserts for the second byte, with logic holding off the
2146 "operation done" signal until the flag denies.
2147
2148 In simulation, the sequencer moves on flag denial directly from
2149 Device_Flag_1 to Idle for a word transfer and on flag assertion from
2150 Device_Command_2 to Device_Flag_2 and then on flag denial to Idle for a
2151 second byte transfer. The sequence count reported in a status return is
2152 0 for Device_Flag_2, preserving the appearance of returning to state 0
2153 while the internal Device_Flag_2 state holds off the "operation done"
2154 signal.
2155
2156 2. In hardware, a DEV END signal asserts the Q2 and Q3 qualifiers, enabling
2157 the sequence counter to proceed through the state sequence back to the
2158 idle state. In simulation, the sequencer state is set directly back to
2159 Idle.
2160
2161 3. In hardware, with jumper W5 out, the DATA IN latches are transparent in
2162 the Device_Command_1 and Device_Command_2 states and are latched
2163 otherwise, i.e., when Device Flag asserts. With jumper W5 in, the
2164 latches are transparent always, and a read gets the real-time state of
2165 the DATA IN lines. In simulation, the read register is set when Device
2166 Flag asserts; transparency is not simulated.
2167
2168 4. The diagnostic tests the byte unpacking and packing multiplexers on the
2169 DATA OUT and DATA IN lines, so we must simulate the multiplexing
2170 accurately with respect to the intermediate values before the handshake
2171 is complete.
2172
2173 5. The sequencer loop is used only during a device end assertion to move
2174 from Idle to Device_Command_1 and back to Idle. All other transitions
2175 involve unit activation and so exit this routine after the sequence state
2176 is changed.
2177 */
2178
handshake_xfer(void)2179 static OUTBOUND_SET handshake_xfer (void)
2180 {
2181 const SEQ_STATE entry_state = sequencer; /* the state of the sequencer at entry */
2182 t_bool reset = FALSE; /* TRUE if the sequencer is reset */
2183 OUTBOUND_SET outbound_signals = NO_SIGNALS;
2184 SEQ_STATE last_state;
2185
2186 do { /* run the sequencer as long as it advances */
2187 last_state = sequencer; /* save the last state to see if it changes */
2188
2189 if (sequencer < Device_Command_2 /* if this is the first byte */
2190 && control_word & CN_BYTE_XFER /* of a byte transfer */
2191 && (J2W7_INSTALLED || write_xfer)) /* and W7 is installed or it's a write transfer */
2192 data_out = write_word & ~D8_MASK /* then the upper 8 bits appear */
2193 | UPPER_BYTE (write_word); /* in both bytes */
2194 else /* otherwise */
2195 data_out = write_word; /* the full 16 bits appear */
2196
2197
2198 switch (sequencer) { /* dispatch the current state */
2199
2200 case Idle:
2201 if (device_command == SET) { /* if device command has been set */
2202 sequencer = Device_Command_1; /* then proceed to the next state */
2203
2204 if (device_end_in /* if external device end asserts */
2205 && (read_xfer || write_xfer)) /* during a transfer */
2206 device_command = CLEAR; /* then device command is inhibited */
2207
2208 else { /* otherwise */
2209 if (J2W3_INSTALLED) /* if jumper W3 (pulse mode) is installed */
2210 activate_unit (pulse_uptr); /* then schedule device command denial */
2211
2212 activate_unit (xfer_uptr); /* schedule device flag assertion */
2213 }
2214 }
2215 break;
2216
2217
2218 case Device_Command_1:
2219 if (device_end_in) /* if external device end asserts */
2220 if (read_xfer || write_xfer) { /* then if a transfer is in progress */
2221 device_end = SET; /* then set the Device End flip-flop to abort */
2222
2223 device_command = CLEAR; /* clear the device command */
2224 read_xfer = CLEAR; /* and read transfer */
2225 write_xfer = CLEAR; /* and write transfer flip-flops */
2226
2227 sequencer = Idle; /* idle the sequencer */
2228 reset = TRUE; /* and indicate that it was reset */
2229
2230 device_sr = SET; /* request channel service */
2231 break;
2232 }
2233
2234 else /* otherwise no transfer is in progress */
2235 device_end_in = FALSE; /* so clear the signal */
2236
2237 if (device_flag == SET) { /* if the device flag has been set */
2238 sequencer = Device_Flag_1; /* then proceed to the next state */
2239 device_command = CLEAR; /* and deny device command */
2240
2241 activate_unit (xfer_uptr); /* schedule device flag denial */
2242
2243 if (control_word & CN_BYTE_XFER) /* if this is a byte transfer */
2244 read_word = TO_WORD (data_in, data_in); /* then the lower 8 bits appear in both bytes */
2245 else /* otherwise */
2246 read_word = data_in; /* the full 16 bits appear */
2247
2248 if (J2W1_INSTALLED && sio_busy /* if jumper W1 (status drives SR) is installed */
2249 && dev_status_word & ST_ST11_SR) /* and a transfer is in progress with status 11 set */
2250 device_sr = SET; /* then request channel service */
2251 }
2252 break;
2253
2254
2255 case Device_Flag_1:
2256 if (device_flag == CLEAR) /* if the device flag has been cleared */
2257 if (control_word & CN_BYTE_XFER) { /* then if this is a byte transfer */
2258 sequencer = Device_Command_2; /* then proceed to the next state */
2259 device_command = SET; /* and assert device command for the second byte */
2260
2261 data_out = write_word; /* latch the output word */
2262
2263 activate_unit (xfer_uptr); /* schedule device flag assertion */
2264 }
2265
2266 else { /* otherwise the transfer is complete */
2267 read_xfer = CLEAR; /* so clear the read transfer */
2268 write_xfer = CLEAR; /* and write transfer flip-flops */
2269
2270 sequencer = Idle; /* idle the sequencer */
2271 device_sr = SET; /* and request channel service */
2272
2273 if (control_word & CN_XFR_IRQ_ENABLE) /* if a transfer interrupt is requested */
2274 outbound_signals |= set_interrupt (ST_XFR_IRQ); /* then set the transfer interrupt flip-flop */
2275 }
2276 break;
2277
2278
2279 case Device_Command_2:
2280 if (device_flag == SET || device_end_in) { /* if the device flag or external device end has been set */
2281 sequencer = Device_Flag_2; /* then proceed to the next state */
2282 device_command = CLEAR;
2283
2284 activate_unit (xfer_uptr); /* schedule device flag denial */
2285
2286 read_word &= ~D8_MASK; /* clear the lower byte */
2287
2288 if (device_end_in == FALSE) /* if the transfer succeeded */
2289 read_word |= LOWER_BYTE (data_in); /* then merge the received lower byte */
2290 }
2291 break;
2292
2293
2294 case Device_Flag_2:
2295 if (device_flag == CLEAR) { /* if the device flag was cleared */
2296 read_xfer = CLEAR; /* then clear the read transfer */
2297 write_xfer = CLEAR; /* and write transfer flip-flops */
2298
2299 sequencer = Idle; /* idle the sequencer */
2300 device_sr = SET; /* and request channel service */
2301
2302 if (control_word & CN_XFR_IRQ_ENABLE) /* if a transfer interrupt is requested */
2303 outbound_signals |= set_interrupt (ST_XFR_IRQ); /* then set the transfer interrupt flip-flop */
2304 }
2305 break;
2306 } /* end of state dispatching */
2307 }
2308 while (sequencer != last_state); /* continue as long as the sequence is progressing */
2309
2310
2311 if (TRACING (lp_dev, DEB_STATE))
2312 if (sequencer != entry_state)
2313 hp_trace (&lp_dev, DEB_STATE, "Sequencer transitioned from the %s state to the %s state\n",
2314 state_name [entry_state], state_name [sequencer]);
2315
2316 else if (reset && device_end)
2317 hp_trace (&lp_dev, DEB_STATE, "Sequencer reset by device end\n");
2318
2319 if (device_sr && sio_busy) /* if the interface has requested service */
2320 outbound_signals |= SRn; /* then assert SRn to the channel */
2321
2322 return outbound_signals; /* return the accumulated signals */
2323 }
2324
2325
2326
2327 /* Diagnostic Hardware Assembly local SCP support routines */
2328
2329
2330
2331 /* Service the transfer handshake for the Diagnostic Hardware Assembly.
2332
2333 The DHA loops the data out lines back to the data in lines, with bits 11-15
2334 also connecting to bits 11-15 of the status in lines. The DHA also may be
2335 configured to connect either the DEV CMD output or the CONT 6 output to the
2336 DEV FLAG input.
2337
2338
2339 Implementation notes:
2340
2341 1. The DHA transfer service is called with a null pointer to update the
2342 potential change in the flag state.
2343 */
2344
diag_service(UNIT * uptr)2345 static t_stat diag_service (UNIT *uptr)
2346 {
2347 if (uptr) /* trace only if this is a handshake entry */
2348 tprintf (lp_dev, DEB_SERV, "%s state transfer service entered\n",
2349 state_name [sequencer]);
2350
2351 if (dha_control_word & DHA_FLAG_SEL) /* if in "flag follows control 6" mode */
2352 device_flag_in = (control_word & CN_DHA_FLAG) != 0; /* then set the flag from control word bit 6 */
2353 else /* otherwise */
2354 device_flag_in = device_command_out; /* device flag is connected to device command */
2355
2356 data_in = data_out; /* data in is connected to data out */
2357
2358 set_device_status (ST_DHA_DEVSTAT_MASK, data_out); /* status bits 11-15 are connected to data out */
2359
2360 return SCPE_OK;
2361 }
2362
2363
2364
2365 /* Diagnostic Hardware Assembly local utility routines */
2366
2367
2368
2369 /* Diagnostic hardware assembly reset.
2370
2371 When the MASTER CLEAR signal is asserted to the DHA, the master reset bit in
2372 the DHA control word is set. In addition, the status bits connected to the
2373 DATA OUT lines from the interface are cleared, as the interface has cleared
2374 its output register.
2375
2376 If this reset was caused by a RESET or RESET LP command, the set of installed
2377 jumpers in the DHA control word is updated. This picks up any jumper changes
2378 made at the user interface.
2379
2380
2381 Implementation notes:
2382
2383 1. The DHA transfer service is called with a null pointer to update the
2384 potential change in the DEV FLAG state that may have occurred by a change
2385 to the DEV CMD state if the lines are connected.
2386 */
2387
diag_reset(t_bool programmed_clear)2388 static t_stat diag_reset (t_bool programmed_clear)
2389 {
2390 if (programmed_clear) { /* if this is a programmed master clear */
2391 dha_control_word |= DHA_MR; /* then record the master reset */
2392
2393 set_device_status (ST_DHA_DEVSTAT_MASK, data_out); /* clear the status bits connected to data out */
2394
2395 xfer_service (NULL); /* update the current device flag state */
2396 }
2397
2398 else /* otherwise this is a commanded reset */
2399 dha_control_word = dha_control_word & DHA_JUMPER_MASK /* so refresh the DHA control word */
2400 | jumper_set; /* from the jumpers */
2401
2402 return SCPE_OK;
2403 }
2404
2405
2406 /* Process the diagnostic hardware assembly control word.
2407
2408 This routine is called when a DCONTSTB or PCONTSTB assertion indicates that
2409 the control word is to be set. If bit 10 is set, then bits 6-9 represent an
2410 encoded action to be taken by the DHA. Two of the actions potentially change
2411 the state of the device status lines, which may also generate an interrupt if
2412 properly configured and enabled. In addition, the DEV FLAG signal may
2413 change, depending on the state of the "flag follows control bit 6" action,
2414 which may cause the handshake sequencer to change states.
2415
2416
2417 Implementation notes:
2418
2419 1. The jumpers part of the DHA control word is "cleared" to all ones, which
2420 corresponds to installing all of the jumpers.
2421
2422 2. The DHA transfer service is called with a null pointer to update the
2423 potential change in the flag state.
2424
2425 3. Setting bit 2 of the DHA control word reflects the current state of the
2426 PON and ~PFWARN signals in status bits 9 and 10, respectively. Status 9
2427 is always set, as PON is always active while the machine is operating.
2428 Status 10 is normally set to indicate that PFWARN is denied. However, if
2429 the system power is failing, PFWARN is asserted from detection until
2430 power is lost.
2431 */
2432
diag_control(uint32 control_word)2433 static OUTBOUND_SET diag_control (uint32 control_word)
2434 {
2435 uint32 new_status;
2436 OUTBOUND_SET outbound_signals = NO_SIGNALS;
2437
2438 if (control_word & CN_DHA_FN_ENABLE) /* if the decoder is enabled */
2439 switch (CN_DHA_FN (control_word)) { /* then decode the DHA command */
2440
2441 case 0: /* clear the registers */
2442 dha_control_word = DHA_CLEAR; /* initialize the DHA control word */
2443 jumper_set = DHA_CLEAR & DHA_JUMPER_MASK; /* and install all of the jumpers */
2444 break;
2445
2446 case 2: /* assert the Device End signal */
2447 device_end_in = TRUE; /* set the external device end line */
2448 break;
2449
2450 case 4: /* set the Transfer Error flip-flop */
2451 outbound_signals = set_interrupt (ST_XFERERR_IRQ); /* set the transfer error interrupt flip-flop */
2452 break;
2453
2454 case 8: /* connect the device flag to control bit 6 */
2455 dha_control_word |= DHA_FLAG_SEL; /* set the "flag follows control 6" bit */
2456 break;
2457
2458 case 10: /* assert the Clear Interface signal */
2459 clear_interface_logic (); /* clear the interface logic */
2460 outbound_signals = set_interrupt (ST_CLRIF_IRQ); /* and set the clear interface interrupt flip-flop */
2461 break;
2462
2463 case 12: /* connect status 8-10 to master clear/power on/power fail */
2464 dha_control_word |= DHA_STAT_SEL; /* set the "status follows master clear-power on-power fail" bit */
2465 break;
2466
2467 default: /* remove a jumper */
2468 dha_control_word &= jumper_map [CN_DHA_FN (control_word)]; /* clear the specified control register bit */
2469 jumper_set = dha_control_word & DHA_JUMPER_MASK; /* and remove the indicated jumper */
2470 break;
2471 }
2472
2473
2474 if (dha_control_word & DHA_STAT_SEL) { /* if status follows master clear/power on/power fail */
2475 new_status = ST_DHA_PON; /* then indicate that power is on */
2476
2477 if (power_warning == FALSE) /* if we have seen a PFWARN signal */
2478 new_status |= ST_DHA_NOT_PF; /* then indicate that power has not failed */
2479
2480 if (dha_control_word & DHA_MR) /* if a master reset is requested */
2481 new_status |= ST_DHA_MR; /* then indicate a master clear */
2482 }
2483
2484 else /* otherwise set the device status */
2485 new_status = ST_DEVIRQ (CN_DHA_ST (control_word)); /* from the connected DHA control bits */
2486
2487 outbound_signals |= set_device_status (ST_DEVIRQ_MASK, new_status); /* set the status and test for IRQs */
2488
2489 xfer_service (NULL); /* record the current device flag state */
2490
2491 outbound_signals |= handshake_xfer (); /* check for a device handshake transition */
2492
2493 return outbound_signals; /* return INTREQ if any interrupts were requested */
2494 }
2495
2496
2497
2498 /* Printer local SCP support routines */
2499
2500
2501
2502 /* Service the transfer handshake for the printer.
2503
2504 The printer transfer service is called to output a character to the printer
2505 buffer or to output a format command that causes the buffered line to be
2506 printed with specified paper movement.
2507
2508 In hardware, the interface places a character or format code on the lower
2509 seven data out lines and asserts STROBE (DEV CMD) to the printer. The
2510 printer responds by denying DEMAND (asserting DEV FLAG). The interface then
2511 denies STROBE and waits for the printer to reassert DEMAND (deny DEV FLAG) to
2512 indicate that the buffer load or print operation is complete.
2513
2514 In simulation, this service routine is called twice for each transfer. It is
2515 called immediately with Device Command set and then after a variable delay
2516 with Device Command clear. In response to the former call, the routine sets
2517 the Device Flag, loads the character buffer or prints the buffered line, and
2518 then sets up an event delay corresponding to the operation performed. In
2519 response to the latter call, the routine clears the Device Flag and then
2520 clears the event delay time, so that the routine will be reentered
2521 immediately when Device Command sets again.
2522
2523 If a SET LP OFFLINE command or a DETACH LP command simulating an out-of-paper
2524 condition is given, the printer will not honor the command immediately if
2525 data exists in the print buffer or the printer is currently printing a line.
2526 In this case, the action is deferred until the service routine is entered to
2527 complete a print operation. At that point, the printer goes offline with
2528 DEMAND denied. This leaves the transfer handshake incomplete. When the
2529 printer is placed back online, this routine is called to assert DEMAND and
2530 conclude the handshake.
2531
2532 Control word bit 10 determines whether the code on the data out lines is
2533 interpreted as a character (0) or a format command (1). If there is room in
2534 the print buffer, the character is loaded. If not, then depending on the
2535 model, the printer either discards the character or automatically prints the
2536 buffer contents, advances the paper one line, and stores the new character in
2537 the empty buffer. If a control character is sent but the printer cannot
2538 print it, a space is loaded in its place.
2539
2540 A format command causes the current buffer to be printed, and then the paper
2541 is advanced by a prescribed amount. Two output modes are provided: compact
2542 and expanded.
2543
2544 In compact mode, a printed line is terminated by a CR LF pair, but subsequent
2545 line spacing is performed by LFs alone. Also, a top-of-form request will
2546 emit a FF character instead of the number of LFs required to reach the top of
2547 the next form, and overprinting is handled by emitting a lone CR at the end
2548 of the line. This mode is used when the printer output file will be sent to
2549 a physical printer connected to the host.
2550
2551 In expanded mode, paper advance is handled solely by emitting CR LF pairs.
2552 Overprinting is handled by merging characters in the buffer. This mode is
2553 used where the printer output file will be saved or manipulated as a text
2554 file.
2555
2556 The format commands recognized by the printer are:
2557
2558 0 x x 0 0 0 0 -- slew 0 lines (suppress spacing) after printing
2559 ...
2560 0 x x 1 1 1 1 -- slew 15 lines after printing
2561
2562 and:
2563
2564 1 x x 0 0 0 0 -- slew to VFU channel 1 after printing
2565 ...
2566 1 x x 1 0 1 1 -- slew to VFU channel 12 after printing
2567
2568 A command to slew to a VFU channel that is not punched or to a VFU channel
2569 other than those defined for the printer will cause a tape fault, and the
2570 printer will go offline; setting the printer back online will clear the
2571 fault. Otherwise, LFs or a FF (compact mode) or CR LF pairs (expanded mode)
2572 will be added to the buffer to advance the paper the required number of
2573 lines.
2574
2575 Not all printers can overprint. A request to suppress spacing on a printer
2576 that cannot (e.g., the HP 2607) is treated as a request for single spacing.
2577
2578 If the stream write fails, an error message is displayed on the simulation
2579 console, a printer alarm condition is set (which takes the printer offline),
2580 and SCPE_IOERR is returned to cause a simulation stop to give the user the
2581 opportunity to fix the problem. Simulation may then be resumed, either with
2582 the printer set back online if the problem is fixed, or with the printer
2583 remaining offline if the problem is uncorrectable.
2584
2585
2586 Implementation notes:
2587
2588 1. When a paper-out condition is detected, the 2607 printer goes offline
2589 only when the next top-of-form is reached. The 2613/17/18 printers go
2590 offline as soon as the current line completes.
2591
2592 2. Because attached files are opened in binary mode, newline translation
2593 (i.e., from LF to CR LF) is not performed by the host system. Therefore,
2594 we write explicit CR LF pairs to end lines, even in compact mode, as
2595 required for fidelity to HP peripherals. If bare LFs are used by the
2596 host system, the printer output file must be postprocessed to remove the
2597 CRs.
2598
2599 3. Overprinting in expanded mode is simulated by merging the lines in the
2600 buffer. A format command to suppress spacing resets the buffer index but
2601 saves the previous buffer length as a "high water mark" that will be
2602 extended if the overlaying line is longer. This process may be repeated
2603 as many times as desired before issuing a format command that prints the
2604 buffer.
2605
2606 When overlaying characters, if a space overlays a printing character, a
2607 printing character overlays a space, or a printing character overlays
2608 itself, then the printing character is retained. Otherwise, an
2609 "overprint character" (which defaults to DEL, but can be changed by the
2610 user) replaces the character in the buffer.
2611
2612 4. Printers that support 12-channel VFUs treat the VFU format command as
2613 modulo 16. Printers that support 8-channel VFUs treat the command as
2614 modulo 8.
2615
2616 5. As a convenience to the user, the printer output file is flushed when a
2617 TOF operation is performed. This permits inspection of the output file
2618 from the SCP command prompt while output is ongoing.
2619
2620 6. The user may examine the TFAULT and PFAULT registers to determine why the
2621 printer went offline.
2622
2623 7. The transfer service may be called with a null pointer to update the
2624 potential change in the flag state.
2625
2626 8. If printing is attempted with the printer offline, this routine will be
2627 called with STROBE asserted (device_command_in TRUE) and DEMAND denied
2628 (device_flag_in TRUE). The printer ignores STROBE if DEMAND is not
2629 asserted, so we simply return in this case. This will hang the handshake
2630 until the printer is set online, and we are reentered with DEMAND
2631 asserted. As a consequence, explicit protection against "uptr->fileref"
2632 being NULL is not required.
2633
2634 9. Explicit tests for lowercase and control characters are much faster and
2635 are used rather than calls to "islower" and "iscntrl", which must
2636 consider the current locale.
2637 */
2638
lp_service(UNIT * uptr)2639 static t_stat lp_service (UNIT *uptr)
2640 {
2641 const t_bool printing = ((control_word & CN_FORMAT) != 0); /* TRUE if a print command was received */
2642 static uint32 overprint_index = 0;
2643 PRINTER_TYPE model;
2644 uint8 data_byte, format_byte;
2645 uint32 channel, line_count, slew_count, vfu_status;
2646
2647 if (uptr == NULL) /* if we're called for a state update */
2648 return SCPE_OK; /* then return with no other action */
2649 else /* otherwise */
2650 model = GET_MODEL (uptr->flags); /* get the printer type */
2651
2652 tprintf (lp_dev, DEB_SERV, "%s state printer service entered\n",
2653 state_name [sequencer]);
2654
2655 if (device_command_out == FALSE) { /* if STROBE has denied */
2656 if (printing) { /* then if printing occurred */
2657 buffer_index = 0; /* then clear the buffer */
2658
2659 if (paper_fault) { /* if an out-of-paper condition is pending */
2660 if (print_props [model].fault_at_eol /* then if the printer faults at the end of any line */
2661 || current_line == 1) /* or the printer is at the top of the form */
2662 return lp_detach (uptr); /* then complete it now with the printer offline */
2663 }
2664
2665 else if (tape_fault) { /* otherwise if a referenced VFU channel was not punched */
2666 tprintf (lp_dev, DEB_CMD, "Commanded VFU channel is not punched\n");
2667 lp_set_alarm (uptr); /* then set an alarm condition that takes the printer offline */
2668 return SCPE_OK;
2669 }
2670
2671 else if (offline_pending) { /* otherwise if a non-alarm offline request is pending */
2672 lp_set_locality (uptr, Offline); /* then take the printer offline now */
2673 return SCPE_OK;
2674 }
2675 }
2676
2677 device_flag_in = FALSE; /* assert DEMAND to complete the handshake */
2678 uptr->wait = 0; /* and request direct entry when STROBE next asserts */
2679 }
2680
2681 else if (device_flag_in == FALSE) { /* otherwise if STROBE has asserted while DEMAND is asserted */
2682 device_flag_in = TRUE; /* then deny DEMAND */
2683
2684 data_byte = (uint8) (data_out & DATA_MASK); /* only the lower 7 bits are connected */
2685
2686 if (printing == FALSE) { /* if loading the print buffer */
2687 if (data_byte > '_' /* then if the character is "lowercase" */
2688 && print_props [model].char_set == 64) /* but the printer doesn't support it */
2689 data_byte = data_byte - 040; /* then shift it to "uppercase" */
2690
2691 if ((data_byte < ' ' || data_byte == DEL) /* if the character is a control character */
2692 && print_props [model].char_set != 128) /* but the printer doesn't support it */
2693 data_byte = ' '; /* then substitute a space */
2694
2695 if (buffer_index < print_props [model].line_length) { /* if there is room in the buffer */
2696 if (overprint_index == 0 /* then if not overprinting */
2697 || buffer_index >= overprint_index /* or past the current buffer limit */
2698 || buffer [buffer_index] == ' ') /* or overprinting a blank */
2699 buffer [buffer_index] = data_byte; /* then store the character */
2700
2701 else if (data_byte != ' ' /* otherwise if we're overprinting a character */
2702 && data_byte != buffer [buffer_index]) /* with a different character */
2703 buffer [buffer_index] = (uint8) overprint_char; /* then substitute the overprint character */
2704
2705 buffer_index++; /* increment the buffer index */
2706
2707 uptr->wait = dlyptr->buffer_load; /* schedule the buffer load delay */
2708
2709 tprintf (lp_dev, DEB_XFER, "Character %s sent to printer\n",
2710 fmt_char (data_byte));
2711 }
2712
2713 else if (print_props [model].autoprints) { /* otherwise if a buffer overflow auto-prints */
2714 tprintf (lp_dev, DEB_CMD, "Buffer overflow printed %u characters on line %u\n",
2715 buffer_index, current_line);
2716
2717 buffer [buffer_index++] = CR; /* tie off */
2718 buffer [buffer_index++] = LF; /* the current buffer */
2719
2720 uptr->pos += sizeof buffer [0] /* write the buffer to the printer file */
2721 * (t_addr) fwrite (buffer, sizeof buffer [0], /* and update the file position */
2722 buffer_index, uptr->fileref);
2723
2724 current_line = current_line + 1; /* move the paper one line */
2725
2726 if (current_line > form_length) /* if the current line is beyond the end of the form */
2727 current_line = 1; /* then reset to the top of the next form */
2728
2729 tprintf (lp_dev, DEB_CMD, "Printer advanced 1 line to line %u\n",
2730 current_line);
2731
2732 overprint_index = 0; /* clear any accumulated overprint index */
2733
2734 buffer [0] = data_byte; /* store the character */
2735 buffer_index = 1; /* in the empty buffer */
2736
2737 uptr->wait = dlyptr->print /* schedule the print delay */
2738 + dlyptr->advance /* plus the paper advance delay */
2739 + dlyptr->buffer_load; /* plus the buffer load delay */
2740
2741 tprintf (lp_dev, DEB_XFER, "Character %s sent to printer\n",
2742 fmt_char (data_byte));
2743 }
2744
2745 else {
2746 uptr->wait = dlyptr->buffer_load; /* schedule the buffer load delay */
2747
2748 tprintf (lp_dev, DEB_CMD, "Buffer overflow discards character %s\n",
2749 fmt_char (data_byte));
2750 }
2751 }
2752
2753 else { /* otherwise this is a print format command */
2754 tprintf (lp_dev, DEB_XFER, "Format code %03o sent to printer\n",
2755 data_byte);
2756
2757 format_byte = data_byte & FORMAT_MASK; /* format commands ignore bits 10-11 */
2758
2759 if (overprint_index > buffer_index) /* if the overprinted line is longer than the current line */
2760 buffer_index = overprint_index; /* then extend the current buffer index */
2761
2762 if (buffer_index > 0 && format_byte != FORMAT_SUPPRESS) /* if printing will occur, then trace it */
2763 tprintf (lp_dev, DEB_CMD, "Printed %u character%s on line %u\n",
2764 buffer_index, (buffer_index == 1 ? "" : "s"), current_line);
2765
2766 if (format_byte == FORMAT_SUPPRESS /* if this is a "suppress space" request */
2767 && print_props [model].overprints) { /* and the printer is capable of overprinting */
2768 slew_count = 0; /* then do not slew after printing */
2769
2770 if (uptr->flags & UNIT_EXPAND) { /* if the printer is in expanded mode */
2771 if (buffer_index > overprint_index) /* then if the current line is longer than the overprinted line */
2772 overprint_index = buffer_index; /* then extend the overprinted line */
2773
2774 buffer_index = 0; /* reset the buffer index to overprint the next line */
2775 }
2776
2777 else /* otherwise the printer is in compact mode */
2778 buffer [buffer_index++] = CR; /* so overprint by emitting a CR without a LF */
2779
2780 tprintf (lp_dev, DEB_CMD, "Printer commanded to suppress spacing on line %u\n",
2781 current_line);
2782 }
2783
2784 else if (format_byte & FORMAT_VFU) { /* otherwise if this is a VFU command */
2785 if (print_props [model].vfu_channels == 8) /* then if it's an 8-channel VFU */
2786 format_byte &= FORMAT_VFU_8_MASK; /* then only three bits are significant */
2787
2788 channel = VFU_CHANNEL_1 >> (format_byte - FORMAT_VFU_BIAS - 1); /* set the requested channel */
2789
2790 tprintf (lp_dev, DEB_CMD, "Printer commanded to slew to VFU channel %u from line %u\n",
2791 format_byte - FORMAT_VFU_BIAS, current_line);
2792
2793 tape_fault = (channel & VFU [0]) == 0; /* a tape fault occurs if there is no punch in this channel */
2794
2795 slew_count = 0; /* initialize the slew counter */
2796
2797 do { /* the VFU always slews at least one line */
2798 slew_count++; /* increment the slew counter */
2799 current_line++; /* and the line counter */
2800
2801 if (current_line > form_length) /* if the current line is beyond the end of the form */
2802 current_line = 1; /* then reset to the top of the next form */
2803 }
2804 while (!tape_fault && (channel & VFU [current_line]) == 0); /* continue until a punch is seen */
2805 }
2806
2807 else { /* otherwise it must be a slew command */
2808 slew_count = format_byte; /* get the number of lines to slew */
2809
2810 if (format_byte == FORMAT_SUPPRESS) /* if the printer cannot overprint */
2811 slew_count = 1; /* then the paper advances after printing */
2812
2813 tprintf (lp_dev, DEB_CMD, "Printer commanded to slew %u line%s from line %u\n",
2814 slew_count, (slew_count == 1 ? "" : "s"), current_line);
2815
2816 current_line = current_line + slew_count; /* move the current line */
2817
2818 if (current_line > form_length) /* if the current line is beyond the end of the form */
2819 current_line = current_line - form_length; /* then it extends onto the next form */
2820 }
2821
2822 if (format_byte == FORMAT_VFU_CHAN_1 /* if a TOF was requested */
2823 && !(uptr->flags & UNIT_EXPAND) /* and the printer is in compact mode */
2824 && slew_count > 1) { /* and more than one line is needed to reach the TOF */
2825 if (buffer_index > 0) { /* then if the buffer not empty */
2826 buffer [buffer_index++] = CR; /* then print */
2827 buffer [buffer_index++] = LF; /* the current line */
2828 }
2829
2830 buffer [buffer_index++] = FF; /* emit a FF to move to the TOF */
2831 }
2832
2833 else if (slew_count > 0) { /* otherwise a slew is needed */
2834 buffer [buffer_index++] = CR; /* then emit a CR LF */
2835 buffer [buffer_index++] = LF; /* to print the current line */
2836
2837 line_count = slew_count; /* get the number of lines to slew */
2838
2839 while (--line_count > 0) { /* while movement is needed */
2840 if (uptr->flags & UNIT_EXPAND) /* if the printer is in expanded mode */
2841 buffer [buffer_index++] = CR; /* then blank lines are CR LF pairs */
2842
2843 buffer [buffer_index++] = LF; /* otherwise just LFs are used */
2844 }
2845 }
2846
2847 if (buffer_index > 0) { /* if the buffer is not empty */
2848 uptr->pos += sizeof buffer [0] /* then write the buffer to the printer file */
2849 * (t_addr) fwrite (buffer, sizeof buffer [0], /* and update the file position */
2850 buffer_index, uptr->fileref);
2851
2852 overprint_index = 0; /* clear any existing overprint index */
2853 }
2854
2855 vfu_status = 0; /* assume no punches for channels 9 and 12 */
2856
2857 if (print_props [model].vfu_channels > 8) { /* if the printer VFU has more than 8 channels */
2858 if (VFU [current_line] & VFU_CHANNEL_9) /* then if channel 9 is punched for this line */
2859 vfu_status |= ST_VFU_9; /* then report it in the device status */
2860
2861 if (VFU [current_line] & VFU_CHANNEL_12) /* if channel 12 is punched for this line */
2862 vfu_status |= ST_VFU_12; /* then report it in the device status */
2863 }
2864
2865 set_device_status (ST_VFU_9 | ST_VFU_12, vfu_status); /* set the VFU status */
2866
2867 if (format_byte == FORMAT_VFU_CHAN_1) /* if a TOF request was performed */
2868 fflush (uptr->fileref); /* then flush the file buffer for inspection */
2869
2870 uptr->wait = dlyptr->print /* schedule the print delay */
2871 + slew_count * dlyptr->advance; /* plus the paper advance delay */
2872
2873 if (slew_count > 0)
2874 tprintf (lp_dev, DEB_CMD, "Printer advanced %u line%s to line %u\n",
2875 slew_count, (slew_count == 1 ? "" : "s"), current_line);
2876 }
2877
2878 if (ferror (uptr->fileref)) { /* if a host file system error occurred */
2879 report_error (uptr->fileref); /* then report the error to the console */
2880
2881 lp_set_alarm (uptr); /* set an alarm condition */
2882 return SCPE_IOERR; /* and stop the simulator */
2883 }
2884 }
2885
2886 return SCPE_OK; /* return event service success */
2887 }
2888
2889
2890 /* Attach the printer image file.
2891
2892 The specified file is attached to the indicated unit. This is the simulation
2893 equivalent of loading paper into the printer and pressing the ONLINE button.
2894 The transition from offline to online causes an interrupt.
2895
2896 A new image file may be requested by giving the "-N" switch to the ATTACH
2897 command. If an existing file is specified with "-N", it will be cleared; if
2898 specified without "-N", printer output will be appended to the end of the
2899 existing file content. In all cases, the paper is positioned at the top of
2900 the form.
2901
2902
2903 Implementation notes:
2904
2905 1. If we are called during a RESTORE command to reattach a file previously
2906 attached when the simulation was SAVEd, the device status and file
2907 position are not altered.
2908
2909 2. The pointer to the appropriate event delay times is set in case we are
2910 being called during a RESTORE command (the assignment is redundant
2911 otherwise).
2912 */
2913
lp_attach(UNIT * uptr,char * cptr)2914 static t_stat lp_attach (UNIT *uptr, char *cptr)
2915 {
2916 t_stat result;
2917
2918 result = attach_unit (uptr, cptr); /* attach the specified printer image file */
2919
2920 if (result == SCPE_OK /* if the attach was successful */
2921 && not (sim_switches & SIM_SW_REST)) { /* and we are not being called during a RESTORE command */
2922 set_device_status (ST_NOT_READY, 0); /* then clear not-ready status */
2923
2924 current_line = 1; /* reset the line counter to the top of the form */
2925
2926 tprintf (lp_dev, DEB_CMD, "Printer paper loaded\n");
2927
2928 lp_set_locality (uptr, Online); /* set the printer online */
2929 }
2930
2931 paper_fault = FALSE; /* clear any existing paper fault */
2932
2933 if (lp_dev.flags & DEV_REALTIME) /* if the printer is in real-time mode */
2934 dlyptr = &real_times [GET_MODEL (uptr->flags)]; /* then point at the times for the current model */
2935 else /* otherwise */
2936 dlyptr = &fast_times; /* point at the fast times */
2937
2938 return result; /* return the result of the attach */
2939 }
2940
2941
2942 /* Detach the printer image file.
2943
2944 The specified file is detached from the indicated unit. This is the
2945 simulation equivalent of running out of paper or unloading the paper from the
2946 printer. The out-of-paper condition cause a paper fault alarm, and the
2947 printer goes offline. The transition from online to offline causes an
2948 interrupt.
2949
2950 When the printer runs out of paper, it will not go offline until characters
2951 present in the buffer are printed and paper motion stops. In addition, the
2952 2607 printer waits until the paper reaches the top-of-form position before
2953 going offline.
2954
2955 In simulation, entering a DETACH LP command while the printer is busy will
2956 defer the file detach until print operations reach the top of the next form
2957 (2607) or until the current print operation completes (2613/17/18). An
2958 immediate detach may be forced by adding the -F switch to the DETACH command.
2959 This simulates physically removing the paper from the printer and succeeds
2960 regardless of the current printer state.
2961
2962
2963 Implementation notes:
2964
2965 1. During simulator shutdown, this routine is called for all three units,
2966 not just the printer unit. The printer must be detached, even if a
2967 detach has been deferred, to ensure that the file is closed properly. We
2968 do this in response to a detach request with the SIM_SW_SHUT switch
2969 present.
2970
2971 2. The DETACH ALL command will fail if any detach routine returns a status
2972 other than SCPE_OK. Because a deferred detach is not fatal, we must
2973 return SCPE_OK, but we still want to print a warning to the user.
2974
2975 3. Because the 2607 only paper faults at TOF, we must explicitly set the
2976 offline_pending flag, as lp_set_alarm may not have been called.
2977 */
2978
lp_detach(UNIT * uptr)2979 static t_stat lp_detach (UNIT *uptr)
2980 {
2981 const PRINTER_TYPE model = GET_MODEL (uptr->flags); /* the printer model number */
2982
2983 if (uptr->flags & UNIT_ATTABLE) /* if we're being called for the printer unit */
2984 if ((uptr->flags & UNIT_ATT) == 0) /* then if the unit is not currently attached */
2985 return SCPE_UNATT; /* then report it */
2986
2987 else { /* otherwise */
2988 if (sim_switches & (SWMASK ('F') | SIM_SW_SHUT)) { /* if this is a forced detach or shut down request */
2989 if (buffer_index != 0) { /* then if the buffer is not empty */
2990 if (buffer [buffer_index - 1] != LF /* then if the last buffer character */
2991 && buffer [buffer_index - 1] != FF) { /* is not a line feed or form feed */
2992 buffer [buffer_index++] = CR; /* then tie off */
2993 buffer [buffer_index++] = LF; /* the current buffer */
2994 }
2995
2996 fwrite (buffer, sizeof buffer [0], /* write the partial buffer to the printer file */
2997 buffer_index, uptr->fileref);
2998
2999 buffer_index = 0; /* clear the buffer index to permit detaching */
3000 }
3001
3002 current_line = 1; /* reset the printer to TOF to enable detaching */
3003 sim_cancel (uptr); /* and terminate */
3004 device_command_out = FALSE; /* any print action in progress */
3005 }
3006
3007 if ((print_props [model].fault_at_eol /* if the printer faults at the end of any line */
3008 || current_line == 1) /* or the printer is at the top of the form */
3009 && lp_set_alarm (uptr)) { /* and a paper alarm is accepted */
3010 paper_fault = TRUE; /* then set the out-of-paper condition */
3011
3012 tprintf (lp_dev, DEB_CMD, "Printer is out of paper\n");
3013
3014 return detach_unit (uptr); /* detach the unit */
3015 }
3016
3017 else { /* otherwise the alarm was rejected at this time */
3018 paper_fault = TRUE; /* so set the out-of-paper condition */
3019 offline_pending = TRUE; /* but defer the detach */
3020
3021 tprintf (lp_dev, DEB_CMD, "Paper out request deferred until print completes\n");
3022
3023 cprintf ("%s\n", sim_error_text (SCPE_INCOMP)); /* report that the actual detach must be deferred */
3024 return SCPE_OK; /* until the buffer has been printed */
3025 }
3026 }
3027
3028 else /* otherwise */
3029 return SCPE_UNATT; /* we've been called for the wrong unit */
3030 }
3031
3032
3033 /* Set the device modes.
3034
3035 This validation routine is entered with the "value" parameter set to one of
3036 the DEVICE_MODES values. The device flag implied by the value is set or
3037 cleared. The unit, character, and descriptor pointers are not used.
3038
3039
3040 Implementation notes:
3041
3042 1. Switching between printer and diagnostic mode sets the configuration
3043 jumpers accordingly.
3044
3045 2. Switching between printer and diagnostic mode clears the event delay.
3046 This is necessary in case the command was entered while an event was
3047 queued.
3048 */
3049
lp_set_mode(UNIT * uptr,int32 value,char * cptr,void * desc)3050 static t_stat lp_set_mode (UNIT *uptr, int32 value, char *cptr, void *desc)
3051 {
3052 switch ((DEVICE_MODES) value) { /* dispatch the mode to set */
3053
3054 case Fast_Time: /* entering optimized timing mode */
3055 lp_dev.flags &= ~DEV_REALTIME; /* so clear the real-time flag */
3056 dlyptr = &fast_times; /* and point at the fast times */
3057 break;
3058
3059
3060 case Real_Time: /* entering realistic timing mode */
3061 lp_dev.flags |= DEV_REALTIME; /* so set the real-time flag */
3062 dlyptr = &real_times [GET_MODEL (uptr->flags)]; /* and point at the times for the current model */
3063 break;
3064
3065
3066 case Printer: /* entering printer mode */
3067 lp_dev.flags &= ~DEV_DIAG; /* so clear the diagnostic flag */
3068 xfer_unit.wait = 0; /* and clear any event delay that had been set */
3069
3070 jumper_set = PRINTER_JUMPERS; /* set the jumpers for printer operation */
3071 break;
3072
3073
3074 case Diagnostic: /* entering diagnostic mode */
3075 lp_dev.flags |= DEV_DIAG; /* so set the diagnostic flag */
3076 xfer_unit.wait = 0; /* and clear any event delay that had been set */
3077
3078 jumper_set = dha_control_word & DHA_JUMPER_MASK; /* set the jumpers for DHA operation */
3079 break;
3080 }
3081
3082 return SCPE_OK; /* mode changes always succeed */
3083 }
3084
3085
3086 /* Set the printer model.
3087
3088 This validation routine is called to set the model of the printer. The
3089 "value" parameter is one of the UNIT_26nn constants that indicates the new
3090 model. Validation isn't necessary, except to detect a model change and alter
3091 the real-time delays accordingly.
3092 */
3093
lp_set_model(UNIT * uptr,int32 value,char * cptr,void * desc)3094 static t_stat lp_set_model (UNIT *uptr, int32 value, char *cptr, void *desc)
3095 {
3096 if (lp_dev.flags & DEV_REALTIME) /* if the printer is in real-time mode */
3097 dlyptr = &real_times [GET_MODEL (value)]; /* then use the times for the new model */
3098
3099 return SCPE_OK; /* allow the reassignment to proceed */
3100 }
3101
3102
3103 /* Set the printer online or offline.
3104
3105 This validation routine is called to set the printer online or offline. The
3106 "value" parameter is UNIT_OFFLINE if the printer is going offline and is zero
3107 if the printer is going online. This simulates pressing the ON/OFFLINE
3108 button on the printer. The unit must be attached (i.e., paper must be
3109 loaded), before the printer may be set online or offline.
3110
3111 If the printer is being taken offline, the buffer is checked to see if any
3112 characters are present. If they are, or if the printer unit is currently
3113 scheduled (i.e., executing a print operation), the offline request is
3114 deferred until printing completes, and the routine returns "Command not
3115 complete" status to inform the user. Otherwise, the unit is set offline,
3116 DEMAND is denied, and DEV END is asserted to indicate that the printer is not
3117 ready.
3118
3119 If the printer is being put online and paper is present, the unit is set
3120 online, and any paper or tape fault present is cleared. If the sequencer
3121 indicates an incomplete handshake, as would occur if paper ran out while
3122 printing, the transfer service is called to complete the handshake by
3123 asserting DEMAND. Otherwise, DEMAND is asserted explicitly, and DEV END is
3124 denied.
3125
3126 As a special case, a detach (out-of-paper condition) or offline request that
3127 has been deferred until printing completes may be cancelled by setting the
3128 printer online. No other action is taken, because the printer has never
3129 transitioned to the offline state.
3130
3131 Transitions between the offline and online state cause interrupts, and INTREQ
3132 is asserted to the IOP if a transition occurred (but not, e.g., for a SET LP
3133 OFFLINE command where the printer is already offline).
3134
3135
3136 Implementation notes:
3137
3138 1. Although a deferred offline request is not fatal, we return SCPE_INCOMP
3139 to prevent "set_cmd" from setting the UNIT_OFFLINE bit in the unit flags
3140 before the printer actually goes offline.
3141 */
3142
lp_set_on_offline(UNIT * uptr,int32 value,char * cptr,void * desc)3143 static t_stat lp_set_on_offline (UNIT *uptr, int32 value, char *cptr, void *desc)
3144 {
3145 if ((uptr->flags & UNIT_ATT) == 0) /* if the printer is detached */
3146 return SCPE_UNATT; /* then it can't be set online or offline */
3147
3148 else if (value == UNIT_ONLINE) /* otherwise if this is an online request */
3149 if (paper_fault && offline_pending) { /* then if an out-of-paper condition is deferred */
3150 paper_fault = FALSE; /* then cancel the request */
3151 offline_pending = FALSE; /* leaving the file attached */
3152 }
3153
3154 else /* otherwise it's a normal online request */
3155 lp_set_locality (uptr, Online); /* so set the printer online */
3156
3157 else if (lp_set_locality (uptr, Offline) == FALSE) { /* otherwise if it cannot be set offline now */
3158 tprintf (lp_dev, DEB_CMD, "Offline request deferred until print completes\n");
3159 return SCPE_INCOMP; /* then let the user know */
3160 }
3161
3162 return SCPE_OK; /* return operation success */
3163 }
3164
3165
3166 /* Set the VFU tape.
3167
3168 This validation routine is entered to set up the VFU on the printer. It is
3169 invoked by one of two commands:
3170
3171 SET LP VFU
3172 SET LP VFU=<filename>
3173
3174 The first form loads the standard 66-line tape into the VFU. The second form
3175 loads the VFU with the tape image specified by the filename. The format of
3176 the tape image is described in the comments for the "lp_load_vfu" routine.
3177
3178 On entry, "uptr" points at the printer unit, "cptr" points to the first
3179 character after the "VFU" keyword, and the "value" and "desc" parameters are
3180 unused. If "cptr" is NULL, then the first command form was given, and the
3181 "lp_load_vfu" routine is called with a NULL file stream pointer to indicate
3182 that the standard VFU tape should be used. Otherwise, the second command
3183 form was given, and "cptr" points to the supplied filename. The file is
3184 opened, and the "lp_load_vfu" routine is called with the stream pointer to
3185 load the VFU tape image contained therein.
3186 */
3187
lp_set_vfu(UNIT * uptr,int32 value,char * cptr,void * desc)3188 static t_stat lp_set_vfu (UNIT *uptr, int32 value, char *cptr, void *desc)
3189 {
3190 FILE *vfu_stream;
3191 t_stat result;
3192
3193 if (cptr == NULL) /* if a VFU reset is requested */
3194 result = lp_load_vfu (uptr, NULL); /* then reload the standard VFU tape */
3195
3196 else if (*cptr == '\0') /* otherwise if the filename was omitted */
3197 return SCPE_MISVAL; /* then report the missing argument */
3198
3199 else { /* otherwise the filename was specified */
3200 vfu_stream = fopen (cptr, "r"); /* so attempt to open it */
3201
3202 if (vfu_stream == NULL) /* if the open failed */
3203 return SCPE_OPENERR; /* then report the error */
3204
3205 result = lp_load_vfu (uptr, vfu_stream); /* load the VFU tape from the file */
3206
3207 fclose (vfu_stream); /* close the file */
3208 }
3209
3210 return result; /* return the result of the load */
3211 }
3212
3213
3214 /* Show the device modes.
3215
3216 This display routine is called to show the device modes for the printer. The
3217 output stream is passed in the "st" parameter, and the other parameters are
3218 ignored. The timing mode and connection mode are printed.
3219 */
3220
lp_show_mode(FILE * st,UNIT * uptr,int32 value,void * desc)3221 static t_stat lp_show_mode (FILE *st, UNIT *uptr, int32 value, void *desc)
3222 {
3223 fprintf (st, "%s timing, %s mode", /* print the timing and connection modes */
3224 (lp_dev.flags & DEV_REALTIME ? "realistic" : "fast"),
3225 (lp_dev.flags & DEV_DIAG ? "diagnostic" : "printer"));
3226
3227 return SCPE_OK;
3228 }
3229
3230
3231 /* Show the VFU tape.
3232
3233 This display routine is called to show the content of the tape currently
3234 loaded in the printer's VFU. The "value" parameter indicates how the routine
3235 was called. It is 0 if a SHOW LP command was given and 1 if a SHOW LP VFU
3236 command was issued. For the former, only the VFU title is displayed. The
3237 latter displays the VFU title, followed by a header labelling each of the
3238 channel columns and then one line for each line of the form consisting of
3239 punch and no-punch characters, according to the VFU definition.
3240
3241 The output stream is passed in the "st" parameter, and the "uptr" and "desc"
3242 parameters are ignored.
3243
3244
3245 Implementation notes:
3246
3247 1. Setting the string precision for the header lines trims them to the
3248 appropriate number of channels.
3249 */
3250
lp_show_vfu(FILE * st,UNIT * uptr,int32 value,void * desc)3251 static t_stat lp_show_vfu (FILE *st, UNIT *uptr, int32 value, void *desc)
3252 {
3253 static const char header_1 [] = " Ch 1 Ch 2 Ch 3 Ch 4 Ch 5 Ch 6 Ch 7 Ch 8 Ch 9 Ch10 Ch11 Ch12";
3254 static const char header_2 [] = " ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----";
3255
3256 const PRINTER_TYPE model = GET_MODEL (uptr->flags); /* the printer model number */
3257 const uint32 channel_count = print_props [model].vfu_channels; /* the count of VFU channels */
3258 uint32 chan, line, current_channel;
3259
3260 if (value == 0) /* if we're called for a summary display */
3261 fputs (vfu_title, st); /* then output only the VFU title */
3262
3263 else { /* otherwise the full VFU definition is requested */
3264 fprintf (st, "\n%s tape is loaded.\n\n", vfu_title); /* so start by displaying the VFU title */
3265
3266 fprintf (st, "Line %.*s\n", channel_count * 5, header_1); /* display the */
3267 fprintf (st, "---- %.*s\n", channel_count * 5, header_2); /* channel headers */
3268
3269 for (line = 1; line <= form_length; line++) { /* loop through the VFU array */
3270 fprintf (st, "%3d ", line); /* display the current form line number */
3271
3272 current_channel = VFU_CHANNEL_1; /* start with channel 1 */
3273
3274 for (chan = 1; chan <= channel_count; chan++) { /* loop through the defined channels */
3275 fputs (" ", st); /* add some space */
3276
3277 if (VFU [line] & current_channel) /* if the current channel is punched for this line */
3278 fputc (punched_char, st); /* then display a punched location */
3279 else /* otherwise */
3280 fputc (unpunched_char, st); /* display an unpunched location */
3281
3282 current_channel = current_channel >> 1; /* move to the next channel */
3283 }
3284
3285 fputc ('\n', st); /* end the line */
3286 }
3287 }
3288
3289 return SCPE_OK;
3290 }
3291
3292
3293
3294 /* Printer local utility routines */
3295
3296
3297
3298 /* Printer reset.
3299
3300 This routine is called when the MASTER CLEAR signal is asserted to the
3301 printer. The "programmed_clear" parameter is TRUE if the routine is called
3302 for a Programmed Master Clear or IORESET assertion, and FALSE if the routine
3303 is called for a RESET or RESET LP command. In the latter case, the presence
3304 of the "-P" switch indicates that this is a power-on reset. In either case,
3305 the interface reset has already been performed; this routine is responsible
3306 for resetting the printer only.
3307
3308 In hardware, asserting MASTER CLEAR:
3309
3310 - clears the input buffer without printing
3311 - finishes printing the current line and performs any stored VFU action
3312 - inhibits DEMAND for approximately three milliseconds
3313
3314 In simulation, the buffer index is reset, a tape fault is cleared, a paper
3315 fault is determined by the paper status, and any deferred offline command is
3316 cleared. Printing is always "complete" at the point of entry, as the actual
3317 file write is instantaneous from the simulation perspective. DEMAND is not
3318 altered, as the printer is "ready" as soon as the command completes. DEV END
3319 is reset to the offline status (asserted if the printer is offline, denied if
3320 online).
3321
3322 In addition, if a power-on reset (RESET -P) is done, the original FASTTIME
3323 settings are restored, the standard VFU tape is loaded, and the power failure
3324 warning is cleared.
3325 */
3326
lp_reset(t_bool programmed_clear)3327 static t_stat lp_reset (t_bool programmed_clear)
3328 {
3329 const PRINTER_TYPE model = GET_MODEL (xfer_unit.flags); /* the printer model number */
3330 OUTBOUND_SET signals;
3331 uint32 new_status = 0;
3332 t_stat result = SCPE_OK;
3333
3334 if (! programmed_clear && (sim_switches & SWMASK ('P'))) { /* if this is a commanded power-on reset */
3335 fast_times.buffer_load = LP_BUFFER_LOAD; /* then reset the per-character transfer time, */
3336 fast_times.print = LP_PRINT; /* the print and advance-one-line time, */
3337 fast_times.advance = LP_ADVANCE; /* and the slew additional lines time */
3338
3339 result = lp_load_vfu (xfer_uptr, NULL); /* load the standard VFU tape */
3340
3341 power_warning = FALSE; /* clear the power failure warning */
3342 }
3343
3344 buffer_index = 0; /* clear the buffer without printing */
3345
3346 offline_pending = FALSE; /* cancel any pending offline request */
3347
3348 tape_fault = FALSE; /* clear any tape fault */
3349 paper_fault = ! (xfer_unit.flags & UNIT_ATT); /* and set paper fault if out of paper */
3350
3351 if (paper_fault && print_props [model].not_ready) /* if paper is out and the printer reports it separately */
3352 new_status |= ST_NOT_READY; /* then set not-ready status */
3353
3354 if (xfer_unit.flags & UNIT_OFFLINE) { /* if the printer is offline */
3355 device_flag_in = TRUE; /* then DEMAND denies while the printer is not ready */
3356 device_end_in = TRUE; /* and DEV END asserts while the printer is offline */
3357 }
3358
3359 else { /* otherwise the printer is online */
3360 new_status |= ST_ONLINE; /* so set online status */
3361
3362 device_flag_in = FALSE; /* DEMAND asserts when the printer is ready */
3363 device_end_in = FALSE; /* and DEV END denies when the printer is online */
3364 }
3365
3366 xfer_service (NULL); /* tell the data transfer service that signals have changed */
3367
3368 signals = set_device_status (ST_ONLINE | ST_NOT_READY, /* set the new device status */
3369 new_status);
3370
3371 if (signals & INTREQ) /* if the status change caused an interrupt */
3372 iop_assert_INTREQ (&lp_dib); /* then assert the INTREQ signal */
3373
3374 return result; /* return the result of the reset */
3375 }
3376
3377
3378 /* Process the printer control word.
3379
3380 This routine is called when a DCONTSTB or PCONTSTB assertion indicates that
3381 the control word is to be set. No direct action is taken by the printer in
3382 response, so the routine simply returns.
3383 */
3384
lp_control(uint32 control_word)3385 static OUTBOUND_SET lp_control (uint32 control_word)
3386 {
3387 return NO_SIGNALS; /* no special control action is needed */
3388 }
3389
3390
3391 /* Set an alarm condition.
3392
3393 This routine is called when an alarm condition exists. An alarm occurs when
3394 paper is out (paper fault) or a VFU command addresses a channel that does not
3395 contain a punch (tape fault). In response, the printer goes offline and,
3396 for all models except the 2607, becomes not-ready.
3397
3398 On entry, the routine attempts to set the printer offline. If this succeeds,
3399 the printer is set not-ready. If it fails (for reasons explained in the
3400 comments for the "lp_set_on_offline" routine), it will be set offline and
3401 not-ready when printing completes.
3402 */
3403
lp_set_alarm(UNIT * uptr)3404 static t_bool lp_set_alarm (UNIT *uptr)
3405 {
3406 const PRINTER_TYPE model = GET_MODEL (uptr->flags); /* the printer model number */
3407
3408 if (lp_set_locality (uptr, Offline)) { /* if the printer went offline */
3409 if (print_props [model].not_ready) /* then if the printer reports ready status separately */
3410 set_device_status (ST_NOT_READY, ST_NOT_READY); /* then set the printer not-ready */
3411
3412 return TRUE; /* return completion success */
3413 }
3414
3415 else /* otherwise the offline request is pending */
3416 return FALSE; /* so return deferral status */
3417 }
3418
3419
3420 /* Set the printer locality.
3421
3422 This routine is called to set the printer online or offline and returns TRUE
3423 if the request succeeded or FALSE if it was deferred. An online request
3424 always succeeds, so it is up to the caller to ensure that going online is
3425 permissible (e.g., that paper is loaded into the printer). An offline
3426 request succeeds only if the printer is idle. If characters are present in
3427 the print buffer, or if the printer is printing or slewing, then the request
3428 is deferred until the current line is complete.
3429
3430 The printer cable inversely connects DEMAND to the Device Flag input and
3431 ONLINE to the Device End input. As both deny when the printer goes offline
3432 and assert when the printer goes online, Device Flag and Device End assert
3433 and deny, respectively.
3434
3435 If the printer goes offline with an operation in progress, Device Flag will
3436 remain asserted, and the handshake sequencer will remain in the Device_Flag_1
3437 or Device_Flag_2 state until the printer is set online again. The transfer
3438 service routine is informed of these state changes, so that the handshake can
3439 complete when the printer is again set online.
3440
3441
3442 Implementation notes:
3443
3444 1. When called with a NULL parameter, the transfer service routine will
3445 update its internal device flag state but will take no other action.
3446 When called with a unit pointer, the routine continues the handshake
3447 sequence.
3448 */
3449
lp_set_locality(UNIT * uptr,LOCALITY printer_state)3450 static t_bool lp_set_locality (UNIT *uptr, LOCALITY printer_state)
3451 {
3452 OUTBOUND_SET signals;
3453
3454 if (printer_state == Offline) { /* if the printer is going offline */
3455 if (buffer_index == 0 /* then if the buffer is empty */
3456 && sim_is_active (uptr) == FALSE) { /* and the printer is idle */
3457 uptr->flags |= UNIT_OFFLINE; /* then set the printer offline now */
3458
3459 signals = set_device_status (ST_ONLINE, 0); /* update the printer status */
3460
3461 device_flag_in = TRUE; /* DEMAND denies while the printer is offline */
3462 device_end_in = TRUE; /* DEV END asserts while the printer is offline */
3463
3464 xfer_service (NULL); /* inform the service routine of the signal changes */
3465 }
3466
3467 else { /* otherwise the request must wait */
3468 offline_pending = TRUE; /* until the line is printed */
3469 return FALSE; /* and the command is not complete */
3470 }
3471 }
3472
3473 else { /* otherwise the printer is going online */
3474 uptr->flags &= ~UNIT_OFFLINE; /* so clear the unit flag */
3475
3476 paper_fault = FALSE; /* clear any paper fault */
3477 tape_fault = FALSE; /* and any tape fault */
3478
3479 signals = set_device_status (ST_ONLINE | ST_NOT_READY, /* set online status */
3480 ST_ONLINE); /* and clear not ready status */
3481
3482 device_flag_in = FALSE; /* DEMAND asserts when the printer is online */
3483 device_end_in = FALSE; /* and DEV END denies when the printer is online */
3484
3485 if (sequencer != Idle) /* if the transfer handshake is in progress */
3486 xfer_service (uptr); /* then complete the suspended operation */
3487 else /* otherwise */
3488 xfer_service (NULL); /* inform the service routine of the signal changes */
3489 }
3490
3491 tprintf (lp_dev, DEB_CMD, "Printer set %s\n",
3492 (printer_state == Offline ? "offline" : "online"));
3493
3494 if (signals & INTREQ) /* if the transition caused an interrupt */
3495 iop_assert_INTREQ (&lp_dib); /* then assert the INTREQ signal */
3496
3497 offline_pending = FALSE; /* the operation completed */
3498 return TRUE; /* successfully */
3499 }
3500
3501
3502 /* Load the VFU.
3503
3504 The printer VFU is loaded either with a custom tape image stored in the file
3505 associated with the stream "vf" or with the standard 66-line tape if the
3506 stream is NULL. The "uptr" parameter points to the printer unit.
3507
3508 The standard VFU tape (02607-80024 for the 8-channel HP 2607 and 02613-80001
3509 for the 12-channel HP 2613, 2617, and 2618) defines the channels as:
3510
3511 Chan Description
3512 ---- --------------
3513 1 Top of form
3514 2 Bottom of form
3515 3 Single space
3516 4 Double space
3517 5 Triple space
3518 6 Half page
3519 7 Quarter page
3520 8 Sixth page
3521 9 Bottom of form
3522
3523 ...with channels 10-12 uncommitted.
3524
3525 A custom tape file starts with a VFU definition line and then contains one
3526 channel-definition line for each line of the form. The number of lines
3527 establishes the form length. Channel 1 must be dedicated to the top-of-form,
3528 but the other channels may be defined as desired.
3529
3530 A semicolon appearing anywhere on a line begins a comment, and the semicolon
3531 and all following characters are ignored. Zero-length lines, including lines
3532 beginning with a semicolon, are ignored.
3533
3534 Note that a line containing one or more blanks is not a zero-length line, so,
3535 for example, the line " ; a comment starting in column 2" is not ignored.
3536
3537 The first (non-ignored) line in the file is a VFU definition line of this
3538 exact form:
3539
3540 VFU=<punch characters>,<no-punch character>{,<title>}
3541
3542 ...where:
3543
3544 Parameter Description
3545 ------------------ -------------------------------------------------------
3546 punch characters a string of one or more characters used interchangeably
3547 to represent a punched location
3548
3549 no-punch character a single character representing a non-punched location
3550
3551 title an optional descriptive string printed by the SHOW LP
3552 VFU command ("Custom VFU" is used by default)
3553
3554 If the "VFU" line is missing or not of the correct form, then "Format error"
3555 status is returned, and the VFU tape is not changed.
3556
3557 The remaining (non-ignored) lines define the channels punched for each line
3558 of the printed form. The line format consists of a sequence of punch,
3559 no-punch, and "other" characters in channel order. Each punch or no-punch
3560 character defines a channel state, starting with channel 1 and proceeding
3561 left-to-right until all channels for the VFU are defined; if the line
3562 terminates before all channels are defined, the remaining channels are set to
3563 the no-punch state. Any "other" characters (i.e., neither a punch character
3564 nor a no-punch character) are ignored and may be used freely to delineate the
3565 tape channels.
3566
3567 Examples using the standard 66-line tape definition for an 8-channel VFU:
3568
3569
3570 ; the VFU definition | VFU=1234578, ; no-punch is a ' '
3571 VFU=1,0,a binary tape image |
3572 | 1 ; top of form
3573 ; the channel definitions | 345 ; form line 1
3574 | 3 ; form line 2
3575 10111111 ; top of form | 34 ; form line 3
3576 00100000 ; single space | 3 5 ; form line 4
3577 0011 ; channels 5-8 no-punch | 34 ; form line 5
3578 |
3579 -------------------------------------+-------------------------------------
3580 |
3581 VFU=X,-,blanks are "others" | VFU=TO,.,brackets are "others"
3582 | ; 1 2 3 4 5 6 7 8
3583 X - X X X X X X ; line 1 | ;--- --- --- --- --- --- --- ---
3584 - - X - - - - - ; line 2 | [T] . [O] [O] [O] [O] [O] [O]
3585 - - X X - - - - ; line 3 | . . [O] . . . . .
3586 | . . [O] [O] . . . .
3587
3588
3589 On entry, the "vf" parameter determines whether the standard tape or a custom
3590 tape is to be loaded. If "vf" is NULL, a standard 66-line tape is generated
3591 and stored in the tape buffer. Otherwise, a custom tape file is read,
3592 parsed, and assembled VFU entries are stored in the tape buffer. After
3593 generation or a successful tape load, the buffer is copied to the VFU array,
3594 the form length is set, the current line is reset to the top-of-form, and the
3595 state of VFU channels 9 and 12 are set into the device status.
3596
3597
3598 Implementation notes:
3599
3600 1. VFU array entries 1-n correspond to form print lines 1-n. Entry 0 is the
3601 logical OR of all of the other entries and is used during VFU format
3602 command processing to determine if a punch is present somewhere in a
3603 given channel.
3604 */
3605
lp_load_vfu(UNIT * uptr,FILE * vf)3606 static t_stat lp_load_vfu (UNIT *uptr, FILE *vf)
3607 {
3608 const PRINTER_TYPE model = GET_MODEL (uptr->flags); /* the printer model number */
3609 uint32 line, channel, vfu_status;
3610 int32 len;
3611 char buffer [LINE_SIZE], punch [LINE_SIZE], no_punch;
3612 char *bptr, *tptr;
3613 uint32 tape [VFU_SIZE] = { 0 };
3614
3615 if (vf == NULL) { /* if the standard VFU is requested */
3616 tape [ 1] = VFU_CHANNEL_1; /* then punch channel 1 for the top of form */
3617 tape [60] = VFU_CHANNEL_2 | VFU_CHANNEL_9; /* and channels 2 and 9 for the bottom of form */
3618
3619 for (line = 1; line <= 60; line++) { /* load each of the 60 printable lines */
3620 tape [line] |= VFU_CHANNEL_3 /* punch channel 3 for single space */
3621 | (line % 2 == 1 ? VFU_CHANNEL_4 : 0) /* punch channel 4 for double space */
3622 | (line % 3 == 1 ? VFU_CHANNEL_5 : 0) /* punch channel 5 for triple space */
3623 | (line % 30 == 1 ? VFU_CHANNEL_6 : 0) /* punch channel 6 for next half page */
3624 | (line % 15 == 1 ? VFU_CHANNEL_7 : 0) /* punch channel 7 for next quarter page */
3625 | (line % 10 == 1 ? VFU_CHANNEL_8 : 0); /* punch channel 8 for next sixth page */
3626
3627 tape [0] |= tape [line]; /* accumulate the channel punches */
3628 }
3629
3630 form_length = 66; /* set the form length */
3631 strcpy (vfu_title, "Standard VFU"); /* and set the title */
3632 }
3633
3634 else { /* otherwise load a custom VFU from the file */
3635 len = lp_read_line (vf, buffer, sizeof buffer); /* read the first line */
3636
3637 if (len <= 0 /* if there isn't one */
3638 || strncmp (buffer, "VFU=", strlen ("VFU=")) != 0) { /* or it's not a VFU definition statement */
3639 cputs ("Missing VFU definition line\n"); /* then complain to the console */
3640 return SCPE_FMT; /* and fail with a format error */
3641 }
3642
3643 bptr = buffer + strlen ("VFU="); /* point at the first control argument */
3644
3645 tptr = strtok (bptr, ","); /* parse the punch token */
3646
3647 if (tptr == NULL) { /* if it's missing */
3648 cputs ("Missing punch field in the VFU control line\n"); /* then complain to the console */
3649 return SCPE_FMT; /* and fail with a format error */
3650 }
3651
3652 strcpy (punch, tptr); /* save the set of punch characters */
3653
3654 tptr = strtok (NULL, ","); /* parse the no-punch token */
3655
3656 if (tptr == NULL){ /* if it's missing */
3657 cputs ("Missing no-punch field in the VFU control line\n"); /* then complain to the console */
3658 return SCPE_FMT; /* and fail with a format error */
3659 }
3660
3661 no_punch = *tptr; /* save the no-punch character */
3662
3663 tptr = strtok (NULL, ","); /* parse the optional title */
3664
3665 if (tptr != NULL) /* if it's present */
3666 strcpy (vfu_title, tptr); /* then save the user's title */
3667 else /* otherwise */
3668 strcpy (vfu_title, "Custom VFU"); /* use a generic title */
3669
3670
3671 for (line = 1; line <= VFU_MAX; line++) { /* load up to the maximum VFU tape length */
3672 len = lp_read_line (vf, buffer, sizeof buffer); /* read a tape definition line */
3673
3674 if (len <= 0) /* if at the EOF or an error occurred */
3675 break; /* then the load is complete */
3676
3677 tptr = buffer; /* point at the first character of the line */
3678
3679 channel = VFU_CHANNEL_1; /* set the channel 1 indicator */
3680
3681 while (channel != 0 && *tptr != '\0') { /* loop until the channel or definition is exhausted */
3682 if (strchr (punch, *tptr) != NULL) { /* if the character is in the punch set */
3683 tape [line] |= channel; /* then punch the current channel */
3684 channel = channel >> 1; /* and move to the next one */
3685 }
3686
3687 else if (*tptr == no_punch) /* otherwise if the character is the no-punch character */
3688 channel = channel >> 1; /* then move to the next channel */
3689
3690 tptr++; /* otherwise the character is neither, so ignore it */
3691 }
3692
3693 tape [0] |= tape [line]; /* accumulate the channel punches */
3694 }
3695
3696
3697 if ((tape [1] & VFU_CHANNEL_1) == 0) { /* if there is no channel 1 punch in the first line */
3698 cputs ("Missing punch in channel 1 of line 1\n"); /* then complain to the console */
3699 return SCPE_FMT; /* and fail with a format error */
3700 }
3701
3702 form_length = line - 1; /* set the form length */
3703 }
3704
3705 memcpy (VFU, tape, sizeof VFU); /* copy the tape buffer to the VFU array */
3706
3707 current_line = 1; /* reset the line counter to the top of the form */
3708
3709 vfu_status = 0; /* assume no punches for channels 9 and 12 */
3710
3711 if (print_props [model].vfu_channels > 8) { /* if the printer VFU has more than 8 channels */
3712 if (VFU [1] & VFU_CHANNEL_9) /* then if channel 9 is punched for this line */
3713 vfu_status |= ST_VFU_9; /* then report it in the device status */
3714
3715 if (VFU [1] & VFU_CHANNEL_12) /* if channel 12 is punched for this line */
3716 vfu_status |= ST_VFU_12; /* then report it in the device status */
3717 }
3718
3719 set_device_status (ST_VFU_9 | ST_VFU_12, vfu_status); /* set the VFU status */
3720
3721 return SCPE_OK; /* the VFU was successfully loaded */
3722 }
3723
3724
3725 /* Read a line from the VFU file.
3726
3727 This routine reads a line from the VFU tape image file designated by the file
3728 stream parameter "vf", stores the data in the string buffer pointed to by
3729 "line" and whose size is given by "size", and returns the length of that
3730 string. Comments are stripped from lines that are read, and the routine
3731 continues to read until a non-zero-length line is found. If the end of the
3732 file was reached, the return value is 0. If a file error occurred, the
3733 return value is -1.
3734
3735
3736 Implementation notes:
3737
3738 1. The routine assumes that the file was opened in text mode, so that
3739 automatic CRLF-to-LF conversion is done if needed. This simplifies
3740 the end-of-line removal.
3741 */
3742
lp_read_line(FILE * vf,char * line,uint32 size)3743 static int32 lp_read_line (FILE *vf, char *line, uint32 size)
3744 {
3745 char *result;
3746 int32 len = 0;
3747
3748 while (len == 0) {
3749 result = fgets (line, size, vf); /* get the next line from the file */
3750
3751 if (result == NULL) /* if an error occurred */
3752 if (feof (vf)) /* then if the end of file was seen */
3753 return 0; /* then return an EOF indication */
3754
3755 else { /* otherwise */
3756 report_error (vf); /* report the error to the console */
3757 return -1; /* and return an error indication */
3758 }
3759
3760 len = strlen (line); /* get the current line length */
3761
3762 if (len > 0 && line [len - 1] == '\n') /* if the last character is a newline */
3763 line [--len] = '\0'; /* then remove it and decrease the length */
3764
3765 result = strchr (line, ';'); /* search for a comment indicator */
3766
3767 if (result != NULL) { /* if one was found */
3768 *result = '\0'; /* then truncate the line at that point */
3769 len = (int32) (result - line); /* and recalculate the line length */
3770 }
3771 }
3772
3773 return len;
3774 }
3775