First Commit of my working state
[simh.git] / PDP10 / pdp10_tu.c
1 /* pdp10_tu.c - PDP-10 RH11/TM03/TU45 magnetic tape simulator
2
3 Copyright (c) 1993-2007, Robert M Supnik
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
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
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
25
26 tu RH11/TM03/TU45 magtape
27
28 29-Apr-07 RMS Fixed bug in setting FCE on TMK (found by Naoki Hamada)
29 16-Feb-06 RMS Added tape capacity checking
30 16-Aug-05 RMS Fixed C++ declaration and cast problems
31 07-Jul-05 RMS Removed extraneous externs
32 31-Mar-05 RMS Fixed bug, ERASE/WREOF incorrectly clear CS1<done>
33 Fixed inaccuracies in error reporting
34 18-Mar-05 RMS Added attached test to detach routine
35 23-Oct-04 RMS Fixed setting done on non data transfers
36 01-Oct-04 RMS Modified to set FCE on read short record, eof
37 Implemented write check
38 TM03 uses only den<2> for validity test
39 TMK is cleared by new motion command, not DCLR
40 14-Sep-04 RMS Fixed RIP value
41 25-Apr-03 RMS Revised for extended file support
42 28-Mar-03 RMS Added multiformat support
43 28-Feb-03 RMS Revised for magtape library
44 27-Jan-03 RMS Changed to dynamically allocate buffer
45 21-Nov-02 RMS Fixed bug in bootstrap (reported by Michael Thompson)
46 Fixed bug in read (reported by Harris Newman)
47 29-Sep-02 RMS Added variable vector support
48 New data structures
49 28-Aug-02 RMS Added end of medium support
50 30-May-02 RMS Widened POS to 32b
51 22-Apr-02 RMS Changed record length error code
52 06-Jan-02 RMS Revised enable/disable support
53 30-Nov-01 RMS Added read only unit, extended SET/SHOW support
54 24-Nov-01 RMS Changed POS, FLG, UST to arrays
55 23-Oct-01 RMS Fixed bug in error interrupts
56 New IO page address constants
57 05-Oct-01 RMS Rewrote interrupt handling from schematics
58 30-Sep-01 RMS Fixed handling of non-existent formatters
59 28-Sep-01 RMS Fixed interrupt handling for SC/ATA
60 4-May-01 RMS Fixed bug in odd address test
61 3-May-01 RMS Fixed drive reset to clear SSC
62
63 Magnetic tapes are represented as a series of variable 8b records
64 of the form:
65
66 32b record length in bytes - exact number, sign = error
67 byte 0
68 byte 1
69 :
70 byte n-2
71 byte n-1
72 32b record length in bytes - exact number, sign = error
73
74 If the byte count is odd, the record is padded with an extra byte
75 of junk. File marks are represented by a single record length of 0.
76 End of tape is two consecutive end of file marks.
77
78 WARNING: The interupt logic of the RH11/RH70 is unusual and must be
79 simulated with great precision. The RH11 has an internal interrupt
80 request flop, CSTB INTR, which is controlled as follows:
81 - Writing IE and DONE simultaneously sets CSTB INTR
82 - Controller clear, INIT, and interrupt acknowledge clear CSTB INTR
83 (and also clear IE)
84 - A transition of DONE from 0 to 1 sets CSTB from INTR
85 The output of INTR is OR'd with the AND of RPCS1<SC,DONE,IE> to
86 create the interrupt request signal. Thus,
87 - The DONE interrupt is edge sensitive, but the SC interrupt is
88 level sensitive.
89 - The DONE interrupt, once set, is not disabled if IE is cleared,
90 but the SC interrupt is.
91 */
92
93 #include "pdp10_defs.h"
94 #include "sim_tape.h"
95
96 #define TU_NUMFM 1 /* #formatters */
97 #define TU_NUMDR 8 /* #drives */
98 #define USTAT u3 /* unit status */
99 #define UDENS u4 /* unit density */
100 #define UD_UNK 0 /* unknown */
101 #define MT_MAXFR (1 << 16) /* max data buf */
102
103 /* MTCS1 - 172440 - control/status 1 */
104
105 #define CS1_GO CSR_GO /* go */
106 #define CS1_V_FNC 1 /* function pos */
107 #define CS1_M_FNC 037 /* function mask */
108 #define CS1_N_FNC (CS1_M_FNC + 1)
109 #define CS1_FNC (CS1_M_FNC << CS1_V_FNC)
110 #define FNC_NOP 000 /* no operation */
111 #define FNC_UNLOAD 001 /* unload */
112 #define FNC_REWIND 003 /* rewind */
113 #define FNC_FCLR 004 /* formatter clear */
114 #define FNC_RIP 010 /* read in preset */
115 #define FNC_ERASE 012 /* erase tape */
116 #define FNC_WREOF 013 /* write tape mark */
117 #define FNC_SPACEF 014 /* space forward */
118 #define FNC_SPACER 015 /* space reverse */
119 #define FNC_XFER 024 /* >=? data xfr */
120 #define FNC_WCHKF 024 /* write check */
121 #define FNC_WCHKR 027 /* write check rev */
122 #define FNC_WRITE 030 /* write */
123 #define FNC_READF 034 /* read forward */
124 #define FNC_READR 037 /* read reverse */
125 #define CS1_IE CSR_IE /* int enable */
126 #define CS1_DONE CSR_DONE /* ready */
127 #define CS1_V_UAE 8 /* Unibus addr ext */
128 #define CS1_M_UAE 03
129 #define CS1_UAE (CS1_M_UAE << CS1_V_UAE)
130 #define CS1_DVA 0004000 /* drive avail NI */
131 #define CS1_MCPE 0020000 /* Mbus par err NI */
132 #define CS1_TRE 0040000 /* transfer err */
133 #define CS1_SC 0100000 /* special cond */
134 #define CS1_MBZ 0012000
135 #define CS1_DRV (CS1_FNC | CS1_GO)
136 #define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC)
137 #define GET_UAE(x) (((x) & CS1_UAE) << (16 - CS1_V_UAE))
138
139 /* MTWC - 172442 - word count */
140
141 /* MTBA - 172444 - base address */
142
143 #define BA_MBZ 0000001 /* must be zero */
144
145 /* MTFC - 172446 - frame count */
146
147 /* MTCS2 - 172450 - control/status 2 */
148
149 #define CS2_V_FMTR 0 /* formatter select */
150 #define CS2_M_FMTR 07
151 #define CS2_FMTR (CS2_M_FMTR << CS2_V_FMTR)
152 #define CS2_UAI 0000010 /* addr inhibit NI */
153 #define CS2_PAT 0000020 /* parity test NI */
154 #define CS2_CLR 0000040 /* controller clear */
155 #define CS2_IR 0000100 /* input ready */
156 #define CS2_OR 0000200 /* output ready */
157 #define CS2_MDPE 0000400 /* Mbus par err NI */
158 #define CS2_MXF 0001000 /* missed xfer NI */
159 #define CS2_PGE 0002000 /* program err */
160 #define CS2_NEM 0004000 /* nx mem err */
161 #define CS2_NEF 0010000 /* nx fmter err */
162 #define CS2_PE 0020000 /* parity err NI */
163 #define CS2_WCE 0040000 /* write chk err */
164 #define CS2_DLT 0100000 /* data late NI */
165 #define CS2_MBZ (CS2_CLR | CS2_WCE)
166 #define CS2_RW (CS2_FMTR | CS2_UAI | CS2_PAT | CS2_MXF | CS2_PE)
167 #define CS2_ERR (CS2_MDPE | CS2_MXF | CS2_PGE | CS2_NEM | \
168 CS2_NEF | CS2_PE | CS2_DLT )
169 #define GET_FMTR(x) (((x) >> CS2_V_FMTR) & CS2_M_FMTR)
170
171 /* MTFS - 172452 - formatter status
172 + indicates kept in drive status
173 ^ indicates calculated on the fly
174 */
175
176 #define FS_SAT 0000001 /* slave attention */
177 #define FS_BOT 0000002 /* ^beginning of tape */
178 #define FS_TMK 0000004 /* end of file */
179 #define FS_ID 0000010 /* ID burst detected */
180 #define FS_SLOW 0000020 /* slowing down NI */
181 #define FS_PE 0000040 /* ^PE status */
182 #define FS_SSC 0000100 /* slave stat change */
183 #define FS_RDY 0000200 /* ^formatter ready */
184 #define FS_FPR 0000400 /* formatter present */
185 #define FS_EOT 0002000 /* +end of tape */
186 #define FS_WRL 0004000 /* ^write locked */
187 #define FS_MOL 0010000 /* ^medium online */
188 #define FS_PIP 0020000 /* +pos in progress */
189 #define FS_ERR 0040000 /* ^error */
190 #define FS_ATA 0100000 /* attention active */
191 #define FS_REW 0200000 /* +rewinding */
192
193 #define FS_DYN (FS_ERR | FS_PIP | FS_MOL | FS_WRL | FS_EOT | \
194 FS_RDY | FS_PE | FS_BOT)
195
196 /* MTER - 172454 - error register */
197
198 #define ER_ILF 0000001 /* illegal func */
199 #define ER_ILR 0000002 /* illegal register */
200 #define ER_RMR 0000004 /* reg mod refused */
201 #define ER_MCP 0000010 /* Mbus cpar err NI */
202 #define ER_FER 0000020 /* format sel err */
203 #define ER_MDP 0000040 /* Mbus dpar err NI */
204 #define ER_VPE 0000100 /* vert parity err */
205 #define ER_CRC 0000200 /* CRC err NI */
206 #define ER_NSG 0000400 /* non std gap err NI */
207 #define ER_FCE 0001000 /* frame count err */
208 #define ER_ITM 0002000 /* inv tape mark NI */
209 #define ER_NXF 0004000 /* wlock or fnc err */
210 #define ER_DTE 0010000 /* time err NI */
211 #define ER_OPI 0020000 /* op incomplete */
212 #define ER_UNS 0040000 /* drive unsafe */
213 #define ER_DCK 0100000 /* data check NI */
214
215 /* MTAS - 172456 - attention summary */
216
217 #define AS_U0 0000001 /* unit 0 flag */
218
219 /* MTCC - 172460 - check character, read only */
220
221 #define CC_MBZ 0177000 /* must be zero */
222
223 /* MTDB - 172462 - data buffer */
224
225 /* MTMR - 172464 - maintenance register */
226
227 #define MR_RW 0177637 /* read/write */
228
229 /* MTDT - 172466 - drive type */
230
231 #define DT_NSA 0100000 /* not sect addr */
232 #define DT_TAPE 0040000 /* tape */
233 #define DT_PRES 0002000 /* slave present */
234 #define DT_TM03 0000040 /* TM03 formatter */
235 #define DT_OFF 0000010 /* drive off */
236 #define DT_TE16 0000011 /* TE16 */
237 #define DT_TU45 0000012 /* TU45 */
238 #define DT_TU77 0000014 /* TU77 */
239
240 /* MTSN - 172470 - serial number */
241
242 /* MTTC - 172472 - tape control register */
243
244 #define TC_V_UNIT 0 /* unit select */
245 #define TC_M_UNIT 07
246 #define TC_V_EVN 0000010 /* even parity */
247 #define TC_V_FMT 4 /* format select */
248 #define TC_M_FMT 017
249 #define TC_10C 00 /* PDP-10 core dump */
250 #define TC_IND 03 /* industry standard */
251 #define TC_V_DEN 8 /* density select */
252 #define TC_M_DEN 07
253 #define TC_800 3 /* 800 bpi */
254 #define TC_1600 4 /* 1600 bpi */
255 #define TC_AER 0010000 /* abort on error */
256 #define TC_SAC 0020000 /* slave addr change */
257 #define TC_FCS 0040000 /* frame count status */
258 #define TC_ACC 0100000 /* accelerating NI */
259 #define TC_RW 0013777
260 #define TC_MBZ 0004000
261 #define TC_RIP ((TC_800 << TC_V_DEN) || (TC_10C << TC_V_FMT))
262 #define GET_DEN(x) (((x) >> TC_V_DEN) & TC_M_DEN)
263 #define GET_FMT(x) (((x) >> TC_V_FMT) & TC_M_FMT)
264 #define GET_DRV(x) (((x) >> TC_V_UNIT) & TC_M_UNIT)
265
266 /* Mapping macros */
267
268 #define XWC_MBZ 0000001 /* wc<0> mbz */
269 #define XBA_MBZ 0000001 /* addr<0> mbz */
270 #define XBA_ODD 0000002 /* odd address */
271 #define TXFR(b,w,od) if (((b) & XBA_MBZ) || ((w) & XWC_MBZ) || \
272 (((b) & XBA_ODD) != ((od) << 1))) { \
273 tucs2 = tucs2 | CS2_NEM; \
274 ubcs[1] = ubcs[1] | UBCS_TMO; \
275 tucs1 = tucs1 & ~CS1_GO; \
276 update_tucs (CS1_DONE, drv); \
277 return SCPE_OK; \
278 }
279 #define NEWPAGE(v,m) (((v) & PAG_M_OFF) == (m))
280 #define MAPM(v,p,f) vpn = PAG_GETVPN (v); \
281 if ((vpn >= UMAP_MEMSIZE) || ((ubmap[1][vpn] & \
282 (UMAP_VLD | UMAP_DSB | UMAP_RRV)) != \
283 (UMAP_VLD | f))) { \
284 tucs2 = tucs2 | CS2_NEM; \
285 ubcs[1] = ubcs[1] | UBCS_TMO; \
286 break; \
287 } \
288 p = (ubmap[1][vpn] + PAG_GETOFF (v)) & PAMASK; \
289 if (MEM_ADDR_NXM (p)) { \
290 tucs2 = tucs2 | CS2_NEM; \
291 ubcs[1] = ubcs[1] | UBCS_TMO; \
292 break; \
293 }
294
295 extern d10 *M; /* memory */
296 extern int32 int_req;
297 extern int32 ubmap[UBANUM][UMAP_MEMSIZE]; /* Unibus map */
298 extern int32 ubcs[UBANUM];
299 extern UNIT cpu_unit;
300 extern int32 sim_switches;
301 extern FILE *sim_deb;
302
303 int32 tucs1 = 0; /* control/status 1 */
304 int32 tuwc = 0; /* word count */
305 int32 tuba = 0; /* bus address */
306 int32 tufc = 0; /* frame count */
307 int32 tucs2 = 0; /* control/status 2 */
308 int32 tufs = 0; /* formatter status */
309 int32 tuer = 0; /* error status */
310 int32 tucc = 0; /* check character */
311 int32 tudb = 0; /* data buffer */
312 int32 tumr = 0; /* maint register */
313 int32 tutc = 0; /* tape control */
314 int32 tuiff = 0; /* INTR flip/flop */
315 int32 tu_time = 10; /* record latency */
316 int32 tu_stopioe = 1; /* stop on error */
317 int32 tu_log = 0; /* debug */
318 int32 reg_in_fmtr[32] = { /* reg in formatter */
319 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1,
320 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
321 };
322 int32 reg_in_fmtr1[32] = { /* rmr if write + go */
323 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1,
324 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
325 };
326 int32 fmt_test[16] = { /* fmt bytes/10 wd */
327 5, 0, 5, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
328 };
329 static char *tu_fname[CS1_N_FNC] = {
330 "NOP", "UNLD", "2", "REW", "FCLR", "5", "6", "7",
331 "RIP", "11", "ERASE", "WREOF", "SPCF", "SPCR", "16", "17",
332 "20", "21", "22", "23", "WRCHKF", "25", "26", "WRCHKR",
333 "WRITE", "31", "32", "33", "READF", "35", "36" "READR"
334 };
335 static uint8 *xbuf = NULL; /* xfer buffer */
336
337 t_stat tu_rd (int32 *data, int32 PA, int32 access);
338 t_stat tu_wr (int32 data, int32 PA, int32 access);
339 int32 tu_inta (void);
340 t_stat tu_svc (UNIT *uptr);
341 t_stat tu_reset (DEVICE *dptr);
342 t_stat tu_attach (UNIT *uptr, char *cptr);
343 t_stat tu_detach (UNIT *uptr);
344 t_stat tu_boot (int32 unitno, DEVICE *dptr);
345 void tu_go (int32 drv);
346 void set_tuer (int32 flag);
347 void update_tucs (int32 flag, int32 drv);
348 t_stat tu_map_err (UNIT *uptr, t_stat st, t_bool qdt);
349
350 /* TU data structures
351
352 tu_dev TU device descriptor
353 tu_unit TU unit list
354 tu_reg TU register list
355 tu_mod TU modifier list
356 */
357
358 DIB tu_dib = {
359 IOBA_TU, IOLN_TU, &tu_rd, &tu_wr,
360 1, IVCL (TU), VEC_TU, { &tu_inta }
361 };
362
363 UNIT tu_unit[] = {
364 { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
365 { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
366 { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
367 { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
368 { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
369 { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
370 { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
371 { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }
372 };
373
374 REG tu_reg[] = {
375 { ORDATA (MTCS1, tucs1, 16) },
376 { ORDATA (MTWC, tuwc, 16) },
377 { ORDATA (MTBA, tuba, 16) },
378 { ORDATA (MTFC, tufc, 16) },
379 { ORDATA (MTCS2, tucs2, 16) },
380 { ORDATA (MTFS, tufs, 16) },
381 { ORDATA (MTER, tuer, 16) },
382 { ORDATA (MTCC, tucc, 16) },
383 { ORDATA (MTDB, tudb, 16) },
384 { ORDATA (MTMR, tumr, 16) },
385 { ORDATA (MTTC, tutc, 16) },
386 { FLDATA (IFF, tuiff, 0) },
387 { FLDATA (INT, int_req, INT_V_TU) },
388 { FLDATA (DONE, tucs1, CSR_V_DONE) },
389 { FLDATA (IE, tucs1, CSR_V_IE) },
390 { FLDATA (STOP_IOE, tu_stopioe, 0) },
391 { DRDATA (TIME, tu_time, 24), PV_LEFT },
392 { URDATA (UST, tu_unit[0].USTAT, 8, 17, 0, TU_NUMDR, 0) },
393 { URDATA (POS, tu_unit[0].pos, 10, T_ADDR_W, 0,
394 TU_NUMDR, PV_LEFT | REG_RO) },
395 { ORDATA (LOG, tu_log, 8), REG_HIDDEN },
396 { NULL }
397 };
398
399 MTAB tu_mod[] = {
400 { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },
401 { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },
402 { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
403 &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
404 { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY",
405 &sim_tape_set_capac, &sim_tape_show_capac, NULL },
406 { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL,
407 NULL, &show_addr, NULL },
408 { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL,
409 NULL, &show_vec, NULL },
410 { 0 }
411 };
412
413 DEVICE tu_dev = {
414 "TU", tu_unit, tu_reg, tu_mod,
415 TU_NUMDR, 10, 31, 1, 8, 8,
416 NULL, NULL, &tu_reset,
417 &tu_boot, &tu_attach, &tu_detach,
418 &tu_dib, DEV_UBUS | DEV_DEBUG
419 };
420
421 /* I/O dispatch routine, I/O addresses 17772440 - 17772472 */
422
423 t_stat tu_rd (int32 *data, int32 PA, int32 access)
424 {
425 int32 fmtr, drv, j;
426
427 fmtr = GET_FMTR (tucs2); /* get current fmtr */
428 drv = GET_DRV (tutc); /* get current drive */
429 j = (PA >> 1) & 017; /* get reg offset */
430 if (reg_in_fmtr[j] && (fmtr != 0)) { /* nx formatter */
431 tucs2 = tucs2 | CS2_NEF; /* set error flag */
432 update_tucs (CS1_SC, drv); /* request intr */
433 *data = 0;
434 return SCPE_OK;
435 }
436
437 update_tucs (0, drv); /* update status */
438 switch (j) { /* decode PA<4:1> */
439
440 case 000: /* MTCS1 */
441 if (fmtr != 0) *data = tucs1 & ~CS1_DRV;
442 else *data = tucs1;
443 break;
444
445 case 001: /* MTWC */
446 *data = tuwc;
447 break;
448
449 case 002: /* MTBA */
450 *data = tuba = tuba & ~BA_MBZ;
451 break;
452
453 case 003: /* MTFC */
454 *data = tufc;
455 break;
456
457 case 004: /* MTCS2 */
458 *data = tucs2 = (tucs2 & ~CS2_MBZ) | CS2_IR | CS2_OR;
459 break;
460
461 case 005: /* MTFS */
462 *data = tufs & 0177777; /* mask off rewind */
463 break;
464
465 case 006: /* MTER */
466 *data = tuer;
467 break;
468
469 case 007: /* MTAS */
470 *data = (tufs & FS_ATA)? AS_U0: 0;
471 break;
472
473 case 010: /* MTCC */
474 *data = tucc = tucc & ~CC_MBZ;
475 break;
476
477 case 011: /* MTDB */
478 *data = tudb;
479 break;
480
481 case 012: /* MTMR */
482 *data = tumr;
483 break;
484
485 case 013: /* MTDT */
486 *data = DT_NSA | DT_TAPE | DT_TM03 |
487 ((tu_unit[drv].flags & UNIT_DIS)? DT_OFF: (DT_PRES | DT_TU45));
488 break;
489
490 case 014: /* MTSN */
491 *data = (tu_unit[drv].flags & UNIT_DIS)? 0: 040 | (drv + 1);
492 break;
493
494 case 015: /* MTTC */
495 *data = tutc = tutc & ~TC_MBZ;
496 break;
497
498 default: /* all others */
499 set_tuer (ER_ILR);
500 update_tucs (0, drv);
501 break;
502 }
503
504 return SCPE_OK;
505 }
506
507 t_stat tu_wr (int32 data, int32 PA, int32 access)
508 {
509 int32 cs1f, fmtr, drv, j;
510
511 cs1f = 0; /* no int on cs1 upd */
512 fmtr = GET_FMTR (tucs2); /* get formatter */
513 drv = GET_DRV (tutc); /* get current unit */
514 j = (PA >> 1) & 017; /* get reg offset */
515 if (reg_in_fmtr[j] && (fmtr != 0)) { /* nx formatter */
516 tucs2 = tucs2 | CS2_NEF; /* set error flag */
517 update_tucs (CS1_SC, drv); /* request intr */
518 return SCPE_OK;
519 }
520 if (reg_in_fmtr1[j] && ((tucs1 & CS1_DONE) == 0)) { /* formatter busy? */
521 set_tuer (ER_RMR); /* won't write */
522 update_tucs (0, drv);
523 return SCPE_OK;
524 }
525
526 switch (j) { /* decode PA<4:1> */
527
528 case 000: /* MTCS1 */
529 if ((access == WRITEB) && (PA & 1)) data = data << 8;
530 if (data & CS1_TRE) { /* error clear? */
531 tucs1 = tucs1 & ~CS1_TRE; /* clr CS1<TRE> */
532 tucs2 = tucs2 & ~CS2_ERR; /* clr CS2<15:8> */
533 }
534 if ((access == WRITE) || (PA & 1)) { /* hi byte write? */
535 if (tucs1 & CS1_DONE) /* done set? */
536 tucs1 = (tucs1 & ~CS1_UAE) | (data & CS1_UAE);
537 }
538 if ((access == WRITE) || !(PA & 1)) { /* lo byte write? */
539 if ((data & CS1_DONE) && (data & CS1_IE)) /* to DONE+IE? */
540 tuiff = 1; /* set CSTB INTR */
541 tucs1 = (tucs1 & ~CS1_IE) | (data & CS1_IE);
542 if (fmtr != 0) { /* nx formatter? */
543 tucs2 = tucs2 | CS2_NEF; /* set error flag */
544 cs1f = CS1_SC; /* req interrupt */
545 }
546 else if (tucs1 & CS1_GO) { /* busy? */
547 if (tucs1 & CS1_DONE) set_tuer (ER_RMR);
548 else tucs2 = tucs2 | CS2_PGE;
549 }
550 else {
551 tucs1 = (tucs1 & ~CS1_DRV) | (data & CS1_DRV);
552 if (tucs1 & CS1_GO) tu_go (drv);
553 }
554 }
555 break;
556
557 case 001: /* MTWC */
558 if (access == WRITEB) data = (PA & 1)?
559 (tuwc & 0377) | (data << 8): (tuwc & ~0377) | data;
560 tuwc = data;
561 break;
562
563 case 002: /* MTBA */
564 if (access == WRITEB) data = (PA & 1)?
565 (tuba & 0377) | (data << 8): (tuba & ~0377) | data;
566 tuba = data & ~BA_MBZ;
567 break;
568
569 case 003: /* MTFC */
570 if (access == WRITEB) data = (PA & 1)?
571 (tufc & 0377) | (data << 8): (tufc & ~0377) | data;
572 tufc = data;
573 tutc = tutc | TC_FCS; /* set fc flag */
574 break;
575
576 case 004: /* MTCS2 */
577 if ((access == WRITEB) && (PA & 1)) data = data << 8;
578 if (data & CS2_CLR) tu_reset (&tu_dev); /* init? */
579 else {
580 if ((data & ~tucs2) & (CS2_PE | CS2_MXF))
581 cs1f = CS1_SC; /* diagn intr */
582 if (access == WRITEB) data = (tucs2 & /* merge data */
583 ((PA & 1)? 0377: 0177400)) | data;
584 tucs2 = (tucs2 & ~CS2_RW) | (data & CS2_RW) | CS2_IR | CS2_OR;
585 }
586 break;
587
588 case 007: /* MTAS */
589 if ((access == WRITEB) && (PA & 1)) break;
590 if (data & AS_U0) tufs = tufs & ~FS_ATA;
591 break;
592
593 case 011: /* MTDB */
594 if (access == WRITEB) data = (PA & 1)?
595 (tudb & 0377) | (data << 8): (tudb & ~0377) | data;
596 tudb = data;
597 break;
598
599 case 012: /* MTMR */
600 if (access == WRITEB) data = (PA & 1)?
601 (tumr & 0377) | (data << 8): (tumr & ~0377) | data;
602 tumr = (tumr & ~MR_RW) | (data & MR_RW);
603 break;
604
605 case 015: /* MTTC */
606 if (access == WRITEB) data = (PA & 1)?
607 (tutc & 0377) | (data << 8): (tutc & ~0377) | data;
608 tutc = (tutc & ~TC_RW) | (data & TC_RW) | TC_SAC;
609 drv = GET_DRV (tutc);
610 break;
611
612 case 005: /* MTFS */
613 case 006: /* MTER */
614 case 010: /* MTCC */
615 case 013: /* MTDT */
616 case 014: /* MTSN */
617 break; /* read only */
618
619 default: /* all others */
620 set_tuer (ER_ILR);
621 break;
622 } /* end switch */
623
624 update_tucs (cs1f, drv); /* update status */
625 return SCPE_OK;
626 }
627
628 /* New magtape command */
629
630 void tu_go (int32 drv)
631 {
632 int32 fnc, den;
633 UNIT *uptr;
634
635 fnc = GET_FNC (tucs1); /* get function */
636 den = GET_DEN (tutc); /* get density */
637 uptr = tu_dev.units + drv; /* get unit */
638 if (DEBUG_PRS (tu_dev)) fprintf (sim_deb,
639 ">>TU%d STRT: fnc=%s, cs1=%06o, cs2=%06o, ba=%06o, wc=%06o, fc=%06o, fs=%06o, er=%06o, pos=%d\n",
640 drv, tu_fname[fnc], tucs1, tucs2, tuba, tuwc, tufc, tufs, tuer, uptr->pos);
641 if ((fnc != FNC_FCLR) && /* not clear & err */
642 ((tufs & FS_ERR) || sim_is_active (uptr))) { /* or in motion? */
643 set_tuer (ER_ILF); /* set err, ATN */
644 tucs1 = tucs1 & ~CS1_GO; /* clear go */
645 update_tucs (CS1_SC, drv); /* request intr */
646 return;
647 }
648 tufs = tufs & ~FS_ATA; /* clear attention */
649 tutc = tutc & ~TC_SAC; /* clear addr change */
650
651 switch (fnc) { /* case on function */
652 case FNC_FCLR: /* drive clear */
653 tuer = 0; /* clear errors */
654 tutc = tutc & ~TC_FCS; /* clear fc status */
655 tufs = tufs & ~(FS_SAT | FS_SSC | FS_ID | FS_ERR);
656 sim_cancel (uptr); /* reset drive */
657 uptr->USTAT = 0;
658 case FNC_NOP:
659 tucs1 = tucs1 & ~CS1_GO; /* no operation */
660 return;
661
662 case FNC_RIP: /* read-in preset */
663 tutc = TC_RIP; /* density = 800 */
664 sim_tape_rewind (&tu_unit[0]); /* rewind unit 0 */
665 tu_unit[0].USTAT = 0;
666 tucs1 = tucs1 & ~CS1_GO;
667 tufs = tufs & ~FS_TMK;
668 return;
669
670 case FNC_UNLOAD: /* unload */
671 if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
672 set_tuer (ER_UNS);
673 break;
674 }
675 detach_unit (uptr);
676 uptr->USTAT = FS_REW;
677 sim_activate (uptr, tu_time);
678 tucs1 = tucs1 & ~CS1_GO;
679 tufs = tufs & ~FS_TMK;
680 return;
681
682 case FNC_REWIND:
683 if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
684 set_tuer (ER_UNS);
685 break;
686 }
687 uptr->USTAT = FS_PIP | FS_REW;
688 sim_activate (uptr, tu_time);
689 tucs1 = tucs1 & ~CS1_GO;
690 tufs = tufs & ~FS_TMK;
691 return;
692
693 case FNC_SPACEF:
694 if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
695 set_tuer (ER_UNS);
696 break;
697 }
698 if (sim_tape_eot (uptr) || ((tutc & TC_FCS) == 0)) {
699 set_tuer (ER_NXF);
700 break;
701 }
702 uptr->USTAT = FS_PIP;
703 goto GO_XFER;
704
705 case FNC_SPACER:
706 if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
707 set_tuer (ER_UNS);
708 break;
709 }
710 if (sim_tape_bot (uptr) || ((tutc & TC_FCS) == 0)) {
711 set_tuer (ER_NXF);
712 break;
713 }
714 uptr->USTAT = FS_PIP;
715 goto GO_XFER;
716
717 case FNC_WREOF: /* write tape mark */
718 case FNC_ERASE: /* erase */
719 if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
720 set_tuer (ER_UNS);
721 break;
722 }
723 if (sim_tape_wrp (uptr)) { /* write locked? */
724 set_tuer (ER_NXF);
725 break;
726 }
727 if (fmt_test[GET_FMT (tutc)] == 0) { /* invalid format? */
728 set_tuer (ER_FER);
729 break;
730 }
731 if (uptr->UDENS == UD_UNK) uptr->UDENS = den; /* set dens */
732 uptr->USTAT = 0;
733 goto GO_XFER;
734
735 case FNC_WCHKR: /* wchk = read */
736 case FNC_READR: /* read rev */
737 if (tufs & FS_BOT) { /* beginning of tape? */
738 set_tuer (ER_NXF);
739 break;
740 }
741 goto DATA_XFER;
742
743 case FNC_WRITE: /* write */
744 if (((tutc & TC_FCS) == 0) || /* frame cnt = 0? */
745 ((den == TC_800) && (tufc > 0777765))) { /* NRZI, fc < 13? */
746 set_tuer (ER_NXF);
747 break;
748 }
749 case FNC_WCHKF: /* wchk = read */
750 case FNC_READF: /* read */
751 DATA_XFER:
752 if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
753 set_tuer (ER_UNS);
754 break;
755 }
756 if (fmt_test[GET_FMT (tutc)] == 0) { /* invalid format? */
757 set_tuer (ER_FER);
758 break;
759 }
760 if (uptr->UDENS == UD_UNK) uptr->UDENS = den; /* set dens */
761 uptr->USTAT = 0;
762 tucs1 = tucs1 & ~CS1_DONE; /* clear done */
763 GO_XFER:
764 tucs2 = tucs2 & ~CS2_ERR; /* clear errors */
765 tucs1 = tucs1 & ~(CS1_TRE | CS1_MCPE);
766 tufs = tufs & ~(FS_TMK | FS_ID); /* clear eof, id */
767 sim_activate (uptr, tu_time);
768 return;
769
770 default: /* all others */
771 set_tuer (ER_ILF); /* not supported */
772 break;
773 } /* end case function */
774
775 tucs1 = tucs1 & ~CS1_GO; /* clear go */
776 update_tucs (CS1_SC, drv); /* set intr */
777 return;
778 }
779
780 /* Unit service
781
782 Complete movement or data transfer command
783 Unit must exist - can't remove an active unit
784 Unit must be attached - detach cancels in progress operations
785 */
786
787 t_stat tu_svc (UNIT *uptr)
788 {
789 int32 fnc, fmt, i, j, k, wc10, ba10;
790 int32 ba, fc, wc, drv, mpa10, vpn;
791 d10 val, v[4];
792 t_mtrlnt tbc;
793 t_stat st, r = SCPE_OK;
794
795 drv = (int32) (uptr - tu_dev.units); /* get drive # */
796 if (uptr->USTAT & FS_REW) { /* rewind or unload? */
797 sim_tape_rewind (uptr); /* rewind tape */
798 uptr->USTAT = 0; /* clear status */
799 tufs = tufs | FS_ATA | FS_SSC;
800 update_tucs (CS1_SC, drv); /* update status */
801 return SCPE_OK;
802 }
803
804 fnc = GET_FNC (tucs1); /* get command */
805 fmt = GET_FMT (tutc); /* get format */
806 ba = GET_UAE (tucs1) | tuba; /* get bus address */
807 wc = 0200000 - tuwc; /* get word count */
808 fc = 0200000 - tufc; /* get frame count */
809 wc10 = wc >> 1; /* 10 word count */
810 ba10 = ba >> 2; /* 10 word addr */
811 uptr->USTAT = 0; /* clear status */
812
813 switch (fnc) { /* case on function */
814
815 /* Non-data transfer commands - set ATA when done */
816
817 case FNC_SPACEF: /* space forward */
818 do {
819 tufc = (tufc + 1) & 0177777; /* incr fc */
820 if (st = sim_tape_sprecf (uptr, &tbc)) { /* space rec fwd, err? */
821 r = tu_map_err (uptr, st, 0); /* map error */
822 break;
823 }
824 } while ((tufc != 0) && !sim_tape_eot (uptr));
825 if (tufc) set_tuer (ER_FCE);
826 else tutc = tutc & ~TC_FCS;
827 tufs = tufs | FS_ATA;
828 break;
829
830 case FNC_SPACER: /* space reverse */
831 do {
832 tufc = (tufc + 1) & 0177777; /* incr wc */
833 if (st = sim_tape_sprecr (uptr, &tbc)) { /* space rec rev, err? */
834 r = tu_map_err (uptr, st, 0); /* map error */
835 break;
836 }
837 } while (tufc != 0);
838 if (tufc) set_tuer (ER_FCE);
839 else tutc = tutc & ~TC_FCS;
840 tufs = tufs | FS_ATA;
841 break;
842
843 case FNC_WREOF: /* write end of file */
844 if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */
845 r = tu_map_err (uptr, st, 0); /* map error */
846 tufs = tufs | FS_ATA;
847 break;
848
849 case FNC_ERASE:
850 if (sim_tape_wrp (uptr)) /* write protected? */
851 r = tu_map_err (uptr, MTSE_WRP, 0); /* map error */
852 tufs = tufs | FS_ATA;
853 break;
854
855 /* Data transfer commands
856
857 These commands must take into account the action of the "bit fiddler", which
858 converts between PDP-10 format and tape format. Only two tape formats are
859 supported:
860
861 PDP-10 core dump: write 36b as byte 0/byte 1/byte 2/byte 3/0000'last nibble
862 industry mode: write hi 32b as byte 0/byte 1/byte 2/byte 3
863
864 These commands must also take into account the action of the Unibus adapter,
865 which munges PDP-10 addresses through the Unibus map.
866 */
867
868 case FNC_READF: /* read */
869 case FNC_WCHKF: /* wcheck = read */
870 tufc = 0; /* clear frame count */
871 if ((uptr->UDENS == TC_1600) && sim_tape_bot (uptr))
872 tufs = tufs | FS_ID; /* PE BOT? ID burst */
873 TXFR (ba, wc, 0); /* validate transfer */
874 if (st = sim_tape_rdrecf (uptr, xbuf, &tbc, MT_MAXFR)) { /* read fwd */
875 if (st == MTSE_TMK) set_tuer (ER_FCE); /* TMK also sets FCE */
876 r = tu_map_err (uptr, st, 1); /* map error */
877 break; /* done */
878 }
879 for (i = j = 0; (i < wc10) && (j < ((int32) tbc)); i++) {
880 if ((i == 0) || NEWPAGE (ba10 + i, 0)) { /* map new page */
881 MAPM (ba10 + i, mpa10, 0);
882 }
883 for (k = 0; k < 4; k++) v[k] = xbuf[j++];
884 val = (v[0] << 28) | (v[1] << 20) | (v[2] << 12) | (v[3] << 4);
885 if (fmt == TC_10C) val = val | ((d10) xbuf[j++] & 017);
886 if (fnc == FNC_READF) M[mpa10] = val; /* read? store */
887 else if (M[mpa10] != val) { /* wchk, mismatch? */
888 tucs2 = tucs2 | CS2_WCE; /* flag, stop */
889 break;
890 }
891 mpa10 = mpa10 + 1;
892 } /* end for */
893 tufc = tbc & 0177777;
894 tuwc = (tuwc + (i << 1)) & 0177777;
895 ba = ba + (i << 2);
896 if (tuwc) set_tuer (ER_FCE); /* short record? */
897 break;
898
899 case FNC_WRITE: /* write */
900 TXFR (ba, wc, 0); /* validate transfer */
901 for (i = j = 0; (i < wc10) && (j < fc); i++) {
902 if ((i == 0) || NEWPAGE (ba10 + i, 0)) { /* map new page */
903 MAPM (ba10 + i, mpa10, 0);
904 }
905 val = M[mpa10];
906 xbuf[j++] = (uint8) ((val >> 28) & 0377);
907 xbuf[j++] = (uint8) ((val >> 20) & 0377);
908 xbuf[j++] = (uint8) ((val >> 12) & 0377);
909 xbuf[j++] = (uint8) ((val >> 4) & 0377);
910 if (fmt == TC_10C) xbuf[j++] = (uint8) (val & 017);
911 mpa10 = mpa10 + 1;
912 } /* end for */
913 if (j < fc) fc = j; /* short record? */
914 if (st = sim_tape_wrrecf (uptr, xbuf, fc)) /* write rec, err? */
915 r = tu_map_err (uptr, st, 1); /* map error */
916 else {
917 tufc = (tufc + fc) & 0177777;
918 if (tufc == 0) tutc = tutc & ~TC_FCS;
919 tuwc = (tuwc + (i << 1)) & 0177777;
920 ba = ba + (i << 2);
921 }
922 break;
923
924 case FNC_READR: /* read reverse */
925 case FNC_WCHKR: /* wcheck = read */
926 tufc = 0; /* clear frame count */
927 TXFR (ba, wc, 1); /* validate xfer rev */
928 if (st = sim_tape_rdrecr (uptr, xbuf + 4, &tbc, MT_MAXFR)) { /* read rev */
929 if (st == MTSE_TMK) set_tuer (ER_FCE); /* TMK also sets FCE */
930 r = tu_map_err (uptr, st, 1); /* map error */
931 break; /* done */
932 }
933 for (i = 0; i < 4; i++) xbuf[i] = 0;
934 for (i = 0, j = tbc + 4; (i < wc10) && (j >= 4); i++) {
935 if ((i == 0) || NEWPAGE (ba10 - i, PAG_M_OFF)) { /* map page */
936 MAPM (ba10 - i, mpa10, UMAP_RRV);
937 }
938 val = ((fmt == TC_10C)? (((d10) xbuf [--j]) & 017): 0);
939 for (k = 0; k < 4; i++) v[k] = xbuf[--j];
940 val = val | (v[0] << 4) | (v[1] << 12) | (v[2] << 20) | (v[3] << 28);
941 if (fnc == FNC_READR) M[mpa10] = val; /* read? store */
942 else if (M[mpa10] != val) { /* wchk, mismatch? */
943 tucs2 = tucs2 | CS2_WCE; /* flag, stop */
944 break;
945 }
946 mpa10 = mpa10 - 1;
947 } /* end for */
948 tufc = tbc & 0177777;
949 tuwc = (tuwc + (i << 1)) & 0177777;
950 ba = ba - (i << 2);
951 if (tuwc) set_tuer (ER_FCE); /* short record? */
952 break;
953 } /* end case */
954
955 tucs1 = (tucs1 & ~CS1_UAE) | ((ba >> (16 - CS1_V_UAE)) & CS1_UAE);
956 tuba = ba & 0177777; /* update mem addr */
957 tucs1 = tucs1 & ~CS1_GO; /* clear go */
958 if (fnc >= FNC_XFER) update_tucs (CS1_DONE, drv); /* data xfer? */
959 else update_tucs (CS1_SC, drv); /* no, set attn */
960 if (DEBUG_PRS (tu_dev)) fprintf (sim_deb,
961 ">>TU%d DONE: fnc=%s, cs1=%06o, cs2=%06o, ba=%06o, wc=%06o, fc=%06o, fs=%06o, er=%06o, pos=%d\n",
962 drv, tu_fname[fnc], tucs1, tucs2, tuba, tuwc, tufc, tufs, tuer, uptr->pos);
963 return SCPE_OK;
964 }
965
966 /* Formatter error */
967
968 void set_tuer (int32 flag)
969 {
970 tuer = tuer | flag;
971 tufs = tufs | FS_ATA;
972 tucs1 = tucs1 | CS1_SC;
973 return;
974 }
975
976 /* Controller status update
977
978 Check for done transition
979 Update drive status
980 Update MTCS1
981 Update interrupt request
982 */
983
984 void update_tucs (int32 flag, int32 drv)
985 {
986 int32 act = sim_is_active (&tu_unit[drv]);
987
988 if ((flag & ~tucs1) & CS1_DONE) /* DONE 0 to 1? */
989 tuiff = (tucs1 & CS1_IE)? 1: 0; /* CSTB INTR <- IE */
990 if (GET_FMTR (tucs2) == 0) { /* formatter present? */
991 tufs = (tufs & ~FS_DYN) | FS_FPR;
992 if (tu_unit[drv].flags & UNIT_ATT) {
993 tufs = tufs | FS_MOL | tu_unit[drv].USTAT;
994 if (tu_unit[drv].UDENS == TC_1600) tufs = tufs | FS_PE;
995 if (sim_tape_wrp (&tu_unit[drv])) tufs = tufs | FS_WRL;
996 if (!act) {
997 if (sim_tape_bot (&tu_unit[drv])) tufs = tufs | FS_BOT;
998 if (sim_tape_eot (&tu_unit[drv])) tufs = tufs | FS_EOT;
999 }
1000 }
1001 if (tuer) tufs = tufs | FS_ERR;
1002 }
1003 else tufs = 0;
1004 tucs1 = (tucs1 & ~(CS1_SC | CS1_MCPE | CS1_MBZ)) | CS1_DVA | flag;
1005 if (tucs2 & CS2_ERR) tucs1 = tucs1 | CS1_TRE | CS1_SC;
1006 else if (tucs1 & CS1_TRE) tucs1 = tucs1 | CS1_SC;
1007 if (tufs & FS_ATA) tucs1 = tucs1 | CS1_SC;
1008 if (tuiff || ((tucs1 & CS1_SC) && (tucs1 & CS1_DONE) && (tucs1 & CS1_IE)))
1009 int_req = int_req | INT_TU;
1010 else int_req = int_req & ~INT_TU;
1011 if ((tucs1 & CS1_DONE) && tufs && !act) tufs = tufs | FS_RDY;
1012 return;
1013 }
1014
1015 /* Interrupt acknowledge */
1016
1017 int32 tu_inta (void)
1018 {
1019 tucs1 = tucs1 & ~CS1_IE; /* clear int enable */
1020 tuiff = 0; /* clear CSTB INTR */
1021 return VEC_TU; /* acknowledge */
1022 }
1023
1024 /* Map tape error status */
1025
1026 t_stat tu_map_err (UNIT *uptr, t_stat st, t_bool qdt)
1027 {
1028 switch (st) {
1029
1030 case MTSE_FMT: /* illegal fmt */
1031 case MTSE_UNATT: /* not attached */
1032 set_tuer (ER_NXF); /* can't execute */
1033 if (qdt) tucs1 = tucs1 | CS1_TRE; /* data xfr? set TRE */
1034 case MTSE_OK: /* no error */
1035 return SCPE_IERR;
1036
1037 case MTSE_TMK: /* end of file */
1038 tufs = tufs | FS_TMK;
1039 break;
1040
1041 case MTSE_IOERR: /* IO error */
1042 set_tuer (ER_VPE); /* flag error */
1043 if (qdt) tucs1 = tucs1 | CS1_TRE; /* data xfr? set TRE */
1044 if (tu_stopioe) return SCPE_IOERR;
1045 break;
1046
1047 case MTSE_INVRL: /* invalid rec lnt */
1048 set_tuer (ER_VPE); /* flag error */
1049 if (qdt) tucs1 = tucs1 | CS1_TRE; /* data xfr? set TRE */
1050 return SCPE_MTRLNT;
1051
1052 case MTSE_RECE: /* record in error */
1053 set_tuer (ER_CRC); /* set crc err */
1054 if (qdt) tucs1 = tucs1 | CS1_TRE; /* data xfr? set TRE */
1055 break;
1056
1057 case MTSE_EOM: /* end of medium */
1058 set_tuer (ER_OPI); /* incomplete */
1059 if (qdt) tucs1 = tucs1 | CS1_TRE; /* data xfr? set TRE */
1060 break;
1061
1062 case MTSE_BOT: /* reverse into BOT */
1063 break;
1064
1065 case MTSE_WRP: /* write protect */
1066 set_tuer (ER_NXF); /* can't execute */
1067 if (qdt) tucs1 = tucs1 | CS1_TRE; /* data xfr? set TRE */
1068 break;
1069 }
1070
1071 return SCPE_OK;
1072 }
1073
1074 /* Reset routine */
1075
1076 t_stat tu_reset (DEVICE *dptr)
1077 {
1078 int32 u;
1079 UNIT *uptr;
1080
1081 tucs1 = CS1_DVA | CS1_DONE;
1082 tucs2 = CS2_IR | CS2_OR;
1083 tuba = 0;
1084 tuwc = 0;
1085 tufc = 0;
1086 tuer = 0;
1087 tufs = FS_FPR | FS_RDY;
1088 if (sim_switches & SWMASK ('P')) tutc = 0; /* powerup? clr TC */
1089 else tutc = tutc & ~TC_FCS; /* no, clr <fcs> */
1090 tuiff = 0; /* clear CSTB INTR */
1091 int_req = int_req & ~INT_TU; /* clear interrupt */
1092 for (u = 0; u < TU_NUMDR; u++) { /* loop thru units */
1093 uptr = tu_dev.units + u;
1094 sim_tape_reset (uptr); /* clear pos flag */
1095 sim_cancel (uptr); /* cancel activity */
1096 uptr->USTAT = 0;
1097 }
1098 if (xbuf == NULL) xbuf = (uint8 *) calloc (MT_MAXFR + 4, sizeof (uint8));
1099 if (xbuf == NULL) return SCPE_MEM;
1100 return SCPE_OK;
1101 }
1102
1103 /* Attach routine */
1104
1105 t_stat tu_attach (UNIT *uptr, char *cptr)
1106 {
1107 int32 drv = uptr - tu_dev.units;
1108 t_stat r;
1109
1110 r = sim_tape_attach (uptr, cptr);
1111 if (r != SCPE_OK) return r;
1112 uptr->USTAT = 0; /* clear unit status */
1113 uptr->UDENS = UD_UNK; /* unknown density */
1114 tufs = tufs | FS_ATA | FS_SSC; /* set attention */
1115 if ((GET_FMTR (tucs2) == 0) && (GET_DRV (tutc) == drv)) /* selected drive? */
1116 tufs = tufs | FS_SAT; /* set slave attn */
1117 update_tucs (CS1_SC, drv); /* update status */
1118 return r;
1119 }
1120
1121 /* Detach routine */
1122
1123 t_stat tu_detach (UNIT* uptr)
1124 {
1125 int32 drv = uptr - tu_dev.units;
1126
1127 if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */
1128 if (sim_is_active (uptr)) { /* unit active? */
1129 sim_cancel (uptr); /* cancel operation */
1130 tuer = tuer | ER_UNS; /* set formatter error */
1131 if ((uptr->USTAT & FS_REW) == 0) /* data transfer? */
1132 tucs1 = tucs1 | CS1_DONE | CS1_TRE; /* set done, err */
1133 }
1134 uptr->USTAT = 0; /* clear status flags */
1135 tufs = tufs | FS_ATA | FS_SSC; /* set attention */
1136 update_tucs (CS1_SC, drv); /* update status */
1137 return sim_tape_detach (uptr);
1138 }
1139
1140 /* Device bootstrap */
1141
1142 #define BOOT_START 0377000 /* start */
1143 #define BOOT_LEN (sizeof (boot_rom_dec) / sizeof (d10))
1144
1145 static const d10 boot_rom_dec[] = {
1146 0515040000003, /* boot:hrlzi 1,3 ; uba # */
1147 0201000040001, /* movei 0,40001 ; vld,pg 1 */
1148 0713001000000+(IOBA_UBMAP+1 & RMASK), /* wrio 0,763001(1); set ubmap */
1149 0435040000000+(IOBA_TU & RMASK), /* iori 1,772440 ; rh addr */
1150 0202040000000+FE_RHBASE, /* movem 1,FE_RHBASE */
1151 0201000000040, /* movei 0,40 ; ctrl reset */
1152 0713001000010, /* wrio 0,10(1) ; ->MTFS */
1153 0201100000031, /* movei 2,31 ; space f */
1154 0265740377014, /* jsp 17,tpop ; skip ucode */
1155 0201100000071, /* movei 2,71 ; read f */
1156 0265740377014, /* jsp 17,tpop ; read boot */
1157 0254000001000, /* jrst 1000 ; start */
1158 0200000000000+FE_MTFMT, /* tpop:move 0,FE_MTFMT ; den,fmt,slv */
1159 0713001000032, /* wrio 0,32(1) ; ->MTTC */
1160 0201000000011, /* movei 0,11 ; clr+go */
1161 0713001000000, /* wrio 0,0(1) ; ->MTCS1 */
1162 0201140176000, /* movei 3,176000 ; wd cnt */
1163 0201200004000, /* movei 4,4000 ; addr */
1164 0200240000000+FE_MTFMT, /* move 5,FE_MTFMT ; unit */
1165 0201300000000, /* movei 6,0 ; fmtr */
1166 0713141000002, /* wrio 3,2(1) ; ->MTWC */
1167 0713201000004, /* wrio 4,4(1) ; ->MTBA */
1168 0713301000006, /* wrio 6,6(1) ; ->MTFC */
1169 0713301000010, /* wrio 6,10(1) ; ->MTFS */
1170 0713241000032, /* wrio 5,32(1) ; ->MTTC */
1171 0713101000000, /* wrio 2,0(1) ; ->MTCS1 */
1172 0712341000012, /* rdio 7,12(1) ; read FS */
1173 0606340000200, /* trnn 7,200 ; test rdy */
1174 0254000377032, /* jrst .-2 ; loop */
1175 0606340040000, /* trnn 7,40000 ; test err */
1176 0254017000000, /* jrst 0(17) ; return */
1177 0712341000014, /* rdio 7,14(1) ; read err */
1178 0302340001000, /* caie 7,1000 ; fce? */
1179 0254200377052, /* halt */
1180 0254017000000, /* jrst 0(17) ; return */
1181 };
1182
1183 static const d10 boot_rom_its[] = {
1184 0515040000003, /* boot:hrlzi 1,3 ; uba # - not used */
1185 0201000040001, /* movei 0,40001 ; vld,pg 1 */
1186 0714000000000+(IOBA_UBMAP+1 & RMASK), /* iowri 0,763001 ; set ubmap */
1187 0435040000000+(IOBA_TU & RMASK), /* iori 1,772440 ; rh addr */
1188 0202040000000+FE_RHBASE, /* movem 1,FE_RHBASE */
1189 0201000000040, /* movei 0,40 ; ctrl reset */
1190 0714001000010, /* iowri 0,10(1) ; ->MTFS */
1191 0201100000031, /* movei 2,31 ; space f */
1192 0265740377014, /* jsp 17,tpop ; skip ucode */
1193 0201100000071, /* movei 2,71 ; read f */
1194 0265740377014, /* jsp 17,tpop ; read boot */
1195 0254000001000, /* jrst 1000 ; start */
1196 0200000000000+FE_MTFMT, /* tpop:move 0,FE_MTFMT ; den,fmt,slv */
1197 0714001000032, /* iowri 0,32(1) ; ->MTTC */
1198 0201000000011, /* movei 0,11 ; clr+go */
1199 0714001000000, /* iowri 0,0(1) ; ->MTCS1 */
1200 0201140176000, /* movei 3,176000 ; wd cnt */
1201 0201200004000, /* movei 4,4000 ; addr */
1202 0200240000000+FE_MTFMT, /* move 5,FE_MTFMT ; unit */
1203 0201300000000, /* movei 6,0 ; fmtr */
1204 0714141000002, /* iowri 3,2(1) ; ->MTWC */
1205 0714201000004, /* iowri 4,4(1) ; ->MTBA */
1206 0714301000006, /* iowri 6,6(1) ; ->MTFC */
1207 0714301000010, /* iowri 6,10(1) ; ->MTFS */
1208 0714241000032, /* iowri 5,32(1) ; ->MTTC */
1209 0714101000000, /* iowri 2,0(1) ; ->MTCS1 */
1210 0710341000012, /* iordi 7,12(1) ; read FS */
1211 0606340000200, /* trnn 7,200 ; test rdy */
1212 0254000377032, /* jrst .-2 ; loop */
1213 0606340040000, /* trnn 7,40000 ; test err */
1214 0254017000000, /* jrst 0(17) ; return */
1215 0710341000014, /* iordi 7,14(1) ; read err */
1216 0302340001000, /* caie 7,1000 ; fce? */
1217 0254200377052, /* halt */
1218 0254017000000, /* jrst 0(17) ; return */
1219 };
1220
1221 t_stat tu_boot (int32 unitno, DEVICE *dptr)
1222 {
1223 int32 i;
1224 extern a10 saved_PC;
1225
1226 M[FE_UNIT] = 0;
1227 M[FE_MTFMT] = (unitno & TC_M_UNIT) | (TC_1600 << TC_V_DEN) | (TC_10C << TC_V_FMT);
1228 tu_unit[unitno].pos = 0;
1229 for (i = 0; i < BOOT_LEN; i++)
1230 M[BOOT_START + i] = Q_ITS? boot_rom_its[i]: boot_rom_dec[i];
1231 saved_PC = BOOT_START;
1232 return SCPE_OK;
1233 }