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