blob: 3083a76a7827550052b2f92145911f863e9119de [file] [log] [blame] [raw]
Bob Supnik2c2dd5e2002-11-17 15:54:00 -08001/* pdp1_dt.c: 18b DECtape simulator
2
Bob Supnik9c4779c2009-02-08 09:06:00 -08003 Copyright (c) 1993-2008, Robert M Supnik
Bob Supnik2c2dd5e2002-11-17 15:54:00 -08004
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
Bob Supnikb7c1eae2005-09-09 18:09:00 -070022 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
Bob Supnik2c2dd5e2002-11-17 15:54:00 -080024 in this Software without prior written authorization from Robert M Supnik.
25
Bob Supnikb7c1eae2005-09-09 18:09:00 -070026 dt Type 550/555 DECtape
Bob Supnik2c2dd5e2002-11-17 15:54:00 -080027
Bob Supnik53d02f72007-02-03 14:59:00 -080028 21-Dec-06 RMS Added 16-channel SBS support
Bob Supnik15919a22006-07-20 13:36:00 -070029 23-Jun-06 RMS Fixed conflict in ATTACH switches
30 Revised header format
Bob Supnikb7c1eae2005-09-09 18:09:00 -070031 16-Aug-05 RMS Fixed C++ declaration and cast problems
32 25-Jan-04 RMS Revised for device debug support
33 09-Jan-04 RMS Changed sim_fsize calling sequence, added STOP_OFFR
34 26-Oct-03 RMS Cleaned up buffer copy code
35 18-Oct-03 RMS Added DECtape off reel message, simplified timing
36 25-Apr-03 RMS Revised for extended file support
37 14-Mar-03 RMS Fixed variable size interaction with save/restore
38 17-Oct-02 RMS Fixed bug in end of reel logic
39 06-Oct-02 RMS Added device disable support
40 13-Aug-02 RMS Cloned from pdp18b_dt.c
Bob Supnik2c2dd5e2002-11-17 15:54:00 -080041
42 18b DECtapes are represented in memory by fixed length buffer of 32b words.
43 Three file formats are supported:
44
Bob Supnikb7c1eae2005-09-09 18:09:00 -070045 18b/36b 256 words per block [256 x 18b]
46 16b 256 words per block [256 x 16b]
47 12b 129 words per block [129 x 12b]
Bob Supnik2c2dd5e2002-11-17 15:54:00 -080048
49 When a 16b or 12b DECtape file is read in, it is converted to 18b/36b format.
50
51 DECtape motion is measured in 3b lines. Time between lines is 33.33us.
Bob Supnik1da2d942003-12-31 11:49:00 -080052 Tape density is nominally 300 lines per inch. The format of a DECtape (as
53 taken from the TD8E formatter) is:
Bob Supnik2c2dd5e2002-11-17 15:54:00 -080054
Bob Supnikb7c1eae2005-09-09 18:09:00 -070055 reverse end zone 8192 reverse end zone codes ~ 10 feet
56 reverse buffer 200 interblock codes
57 block 0
58 :
59 block n
60 forward buffer 200 interblock codes
61 forward end zone 8192 forward end zone codes ~ 10 feet
Bob Supnik2c2dd5e2002-11-17 15:54:00 -080062
63 A block consists of five 18b header words, a tape-specific number of data
64 words, and five 18b trailer words. All systems except the PDP-8 use a
65 standard block length of 256 words; the PDP-8 uses a standard block length
Bob Supnik15919a22006-07-20 13:36:00 -070066 of 86 words (x 18b = 129 words x 12b).
Bob Supnik2c2dd5e2002-11-17 15:54:00 -080067
68 Because a DECtape file only contains data, the simulator cannot support
69 write timing and mark track and can only do a limited implementation
70 of read all and write all. Read all assumes that the tape has been
71 conventionally written forward:
72
Bob Supnikb7c1eae2005-09-09 18:09:00 -070073 header word 0 0
74 header word 1 block number (for forward reads)
75 header words 2,3 0
76 header word 4 checksum (for reverse reads)
77 :
78 trailer word 4 checksum (for forward reads)
79 trailer words 3,2 0
80 trailer word 1 block number (for reverse reads)
81 trailer word 0 0
Bob Supnik2c2dd5e2002-11-17 15:54:00 -080082
83 Write all writes only the data words and dumps the interblock words in the
84 bit bucket.
85
Bob Supnik15919a22006-07-20 13:36:00 -070086 The Type 550 controller has a 4b unit select field, for units 1-8. The code
Bob Supnik2c2dd5e2002-11-17 15:54:00 -080087 assumes that the GETUNIT macro returns a unit number in the range of 0-7,
88 with 8 represented as 0, and an invalid unit as -1.
89*/
90
91#include "pdp1_defs.h"
92
Bob Supnikb7c1eae2005-09-09 18:09:00 -070093#define DT_NUMDR 8 /* #drives */
94#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
95#define UNIT_V_8FMT (UNIT_V_UF + 1) /* 12b format */
96#define UNIT_V_11FMT (UNIT_V_UF + 2) /* 16b format */
97#define UNIT_WLK (1 << UNIT_V_WLK)
98#define UNIT_8FMT (1 << UNIT_V_8FMT)
99#define UNIT_11FMT (1 << UNIT_V_11FMT)
100#define STATE u3 /* unit state */
101#define LASTT u4 /* last time update */
102#define DT_WC 030 /* word count */
103#define DT_CA 031 /* current addr */
104#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800105
106/* System independent DECtape constants */
107
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700108#define DT_LPERMC 6 /* lines per mark track */
109#define DT_BLKWD 1 /* blk no word in h/t */
110#define DT_CSMWD 4 /* checksum word in h/t */
111#define DT_HTWRD 5 /* header/trailer words */
112#define DT_EZLIN (8192 * DT_LPERMC) /* end zone length */
113#define DT_BFLIN (200 * DT_LPERMC) /* buffer length */
114#define DT_BLKLN (DT_BLKWD * DT_LPERMC) /* blk no line in h/t */
115#define DT_CSMLN (DT_CSMWD * DT_LPERMC) /* csum line in h/t */
116#define DT_HTLIN (DT_HTWRD * DT_LPERMC) /* header/trailer lines */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800117
118/* 16b, 18b, 36b DECtape constants */
119
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700120#define D18_WSIZE 6 /* word size in lines */
121#define D18_BSIZE 256 /* block size in 18b */
122#define D18_TSIZE 578 /* tape size */
123#define D18_LPERB (DT_HTLIN + (D18_BSIZE * DT_WSIZE) + DT_HTLIN)
124#define D18_FWDEZ (DT_EZLIN + (D18_LPERB * D18_TSIZE))
125#define D18_CAPAC (D18_TSIZE * D18_BSIZE) /* tape capacity */
126#define D11_FILSIZ (D18_CAPAC * sizeof (int16))
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800127
128/* 12b DECtape constants */
129
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700130#define D8_WSIZE 4 /* word size in lines */
131#define D8_BSIZE 86 /* block size in 18b */
132#define D8_TSIZE 1474 /* tape size */
133#define D8_LPERB (DT_HTLIN + (D8_BSIZE * DT_WSIZE) + DT_HTLIN)
134#define D8_FWDEZ (DT_EZLIN + (D8_LPERB * D8_TSIZE))
135#define D8_CAPAC (D8_TSIZE * D8_BSIZE) /* tape capacity */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800136
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700137#define D8_NBSIZE ((D8_BSIZE * D18_WSIZE) / D8_WSIZE)
138#define D8_FILSIZ (D8_NBSIZE * D8_TSIZE * sizeof (int16))
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800139
140/* This controller */
141
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700142#define DT_CAPAC D18_CAPAC /* default */
143#define DT_WSIZE D18_WSIZE
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800144
145/* Calculated constants, per unit */
146
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700147#define DTU_BSIZE(u) (((u)->flags & UNIT_8FMT)? D8_BSIZE: D18_BSIZE)
148#define DTU_TSIZE(u) (((u)->flags & UNIT_8FMT)? D8_TSIZE: D18_TSIZE)
149#define DTU_LPERB(u) (((u)->flags & UNIT_8FMT)? D8_LPERB: D18_LPERB)
150#define DTU_FWDEZ(u) (((u)->flags & UNIT_8FMT)? D8_FWDEZ: D18_FWDEZ)
151#define DTU_CAPAC(u) (((u)->flags & UNIT_8FMT)? D8_CAPAC: D18_CAPAC)
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800152
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700153#define DT_LIN2BL(p,u) (((p) - DT_EZLIN) / DTU_LPERB (u))
154#define DT_LIN2OF(p,u) (((p) - DT_EZLIN) % DTU_LPERB (u))
155#define DT_LIN2WD(p,u) ((DT_LIN2OF (p,u) - DT_HTLIN) / DT_WSIZE)
156#define DT_BLK2LN(p,u) (((p) * DTU_LPERB (u)) + DT_EZLIN)
157#define DT_QREZ(u) (((u)->pos) < DT_EZLIN)
158#define DT_QFEZ(u) (((u)->pos) >= ((uint32) DTU_FWDEZ (u)))
159#define DT_QEZ(u) (DT_QREZ (u) || DT_QFEZ (u))
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800160
161/* Status register A */
162
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700163#define DTA_V_UNIT 12 /* unit select */
164#define DTA_M_UNIT 017
165#define DTA_UNIT (DTA_M_UNIT << DTA_V_UNIT)
166#define DTA_V_MOT 4 /* motion */
167#define DTA_M_MOT 03
168#define DTA_V_FNC 0 /* function */
169#define DTA_M_FNC 07
170#define FNC_MOVE 00 /* move */
171#define FNC_SRCH 01 /* search */
172#define FNC_READ 02 /* read */
173#define FNC_WRIT 03 /* write */
174#define FNC_RALL 05 /* read all */
175#define FNC_WALL 06 /* write all */
176#define FNC_WMRK 07 /* write timing */
177#define DTA_STSTP (1u << (DTA_V_MOT + 1))
178#define DTA_FWDRV (1u << DTA_V_MOT)
179#define DTA_MODE 0 /* not implemented */
180#define DTA_RW 077
181#define DTA_GETUNIT(x) map_unit[(((x) >> DTA_V_UNIT) & DTA_M_UNIT)]
182#define DT_UPDINT if (dtsb & (DTB_DTF | DTB_BEF | DTB_ERF)) \
Bob Supnik9c4779c2009-02-08 09:06:00 -0800183 dev_req_int (dt_sbs);
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800184
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700185#define DTA_GETMOT(x) (((x) >> DTA_V_MOT) & DTA_M_MOT)
186#define DTA_GETFNC(x) (((x) >> DTA_V_FNC) & DTA_M_FNC)
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800187
188/* Status register B */
189
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700190#define DTB_V_DTF 17 /* data flag */
191#define DTB_V_BEF 16 /* block end flag */
192#define DTB_V_ERF 15 /* error flag */
193#define DTB_V_END 14 /* end of tape */
194#define DTB_V_TIM 13 /* timing err */
195#define DTB_V_REV 12 /* reverse */
196#define DTB_V_GO 11 /* go */
197#define DTB_V_MRK 10 /* mark trk err */
198#define DTB_V_SEL 9 /* select err */
199#define DTB_DTF (1u << DTB_V_DTF)
200#define DTB_BEF (1u << DTB_V_BEF)
201#define DTB_ERF (1u << DTB_V_ERF)
202#define DTB_END (1u << DTB_V_END)
203#define DTB_TIM (1u << DTB_V_TIM)
204#define DTB_REV (1u << DTB_V_REV)
205#define DTB_GO (1u << DTB_V_GO)
206#define DTB_MRK (1u << DTB_V_MRK)
207#define DTB_SEL (1u << DTB_V_SEL)
208#define DTB_ALLERR (DTB_END | DTB_TIM | DTB_MRK | DTB_SEL)
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800209
210/* DECtape state */
211
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700212#define DTS_V_MOT 3 /* motion */
213#define DTS_M_MOT 07
214#define DTS_STOP 0 /* stopped */
215#define DTS_DECF 2 /* decel, fwd */
216#define DTS_DECR 3 /* decel, rev */
217#define DTS_ACCF 4 /* accel, fwd */
218#define DTS_ACCR 5 /* accel, rev */
219#define DTS_ATSF 6 /* @speed, fwd */
220#define DTS_ATSR 7 /* @speed, rev */
221#define DTS_DIR 01 /* dir mask */
222#define DTS_V_FNC 0 /* function */
223#define DTS_M_FNC 07
224#define DTS_OFR 7 /* "off reel" */
225#define DTS_GETMOT(x) (((x) >> DTS_V_MOT) & DTS_M_MOT)
226#define DTS_GETFNC(x) (((x) >> DTS_V_FNC) & DTS_M_FNC)
227#define DTS_V_2ND 6 /* next state */
228#define DTS_V_3RD (DTS_V_2ND + DTS_V_2ND) /* next next */
229#define DTS_STA(y,z) (((y) << DTS_V_MOT) | ((z) << DTS_V_FNC))
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800230#define DTS_SETSTA(y,z) uptr->STATE = DTS_STA (y, z)
231#define DTS_SET2ND(y,z) uptr->STATE = (uptr->STATE & 077) | \
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700232 ((DTS_STA (y, z)) << DTS_V_2ND)
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800233#define DTS_SET3RD(y,z) uptr->STATE = (uptr->STATE & 07777) | \
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700234 ((DTS_STA (y, z)) << DTS_V_3RD)
235#define DTS_NXTSTA(x) (x >> DTS_V_2ND)
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800236
237/* Operation substates */
238
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700239#define DTO_WCO 1 /* wc overflow */
240#define DTO_SOB 2 /* start of block */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800241
242/* Logging */
243
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700244#define LOG_MS 001 /* move, search */
245#define LOG_RW 002 /* read write */
246#define LOG_BL 004 /* block # lblk */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800247
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700248#define ABS(x) (((x) < 0)? (-(x)): (x))
249
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800250extern int32 M[];
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800251extern int32 stop_inst;
252extern UNIT cpu_unit;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800253
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700254int32 dtsa = 0; /* status A */
255int32 dtsb = 0; /* status B */
256int32 dtdb = 0; /* data buffer */
Bob Supnik53d02f72007-02-03 14:59:00 -0800257int32 dt_sbs = 0; /* SBS level */
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700258int32 dt_ltime = 12; /* interline time */
259int32 dt_dctime = 40000; /* decel time */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800260int32 dt_substate = 0;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800261int32 dt_logblk = 0;
Bob Supnik26aa6de2004-04-06 05:17:00 -0700262int32 dt_stopoffr = 0;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700263static const int32 map_unit[16] = { /* Type 550 unit map */
264 -1, 1, 2, 3, 4, 5, 6, 7,
265 0, -1, -1, -1, -1, -1, -1, -1
266 };
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800267
268t_stat dt_svc (UNIT *uptr);
269t_stat dt_reset (DEVICE *dptr);
270t_stat dt_attach (UNIT *uptr, char *cptr);
271t_stat dt_detach (UNIT *uptr);
272void dt_deselect (int32 oldf);
273void dt_newsa (int32 newf);
274void dt_newfnc (UNIT *uptr, int32 newsta);
275t_bool dt_setpos (UNIT *uptr);
276void dt_schedez (UNIT *uptr, int32 dir);
277void dt_seterr (UNIT *uptr, int32 e);
278int32 dt_comobv (int32 val);
279int32 dt_csum (UNIT *uptr, int32 blk);
280int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos);
281
282/* DT data structures
283
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700284 dt_dev DT device descriptor
285 dt_unit DT unit list
286 dt_reg DT register list
287 dt_mod DT modifier list
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800288*/
289
290UNIT dt_unit[] = {
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700291 { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
292 UNIT_ROABLE, DT_CAPAC) },
293 { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
294 UNIT_ROABLE, DT_CAPAC) },
295 { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
296 UNIT_ROABLE, DT_CAPAC) },
297 { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
298 UNIT_ROABLE, DT_CAPAC) },
299 { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
300 UNIT_ROABLE, DT_CAPAC) },
301 { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
302 UNIT_ROABLE, DT_CAPAC) },
303 { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
304 UNIT_ROABLE, DT_CAPAC) },
305 { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
306 UNIT_ROABLE, DT_CAPAC) }
307 };
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800308
309REG dt_reg[] = {
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700310 { ORDATA (DTSA, dtsa, 18) },
311 { ORDATA (DTSB, dtsb, 18) },
312 { ORDATA (DTDB, dtdb, 18) },
313 { FLDATA (DTF, dtsb, DTB_V_DTF) },
314 { FLDATA (BEF, dtsb, DTB_V_BEF) },
315 { FLDATA (ERF, dtsb, DTB_V_ERF) },
316 { DRDATA (LTIME, dt_ltime, 31), REG_NZ },
317 { DRDATA (DCTIME, dt_dctime, 31), REG_NZ },
318 { ORDATA (SUBSTATE, dt_substate, 2) },
319 { DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN },
320 { URDATA (POS, dt_unit[0].pos, 10, T_ADDR_W, 0,
321 DT_NUMDR, PV_LEFT | REG_RO) },
322 { URDATA (STATT, dt_unit[0].STATE, 8, 18, 0,
323 DT_NUMDR, REG_RO) },
324 { URDATA (LASTT, dt_unit[0].LASTT, 10, 32, 0,
325 DT_NUMDR, REG_HRO) },
326 { FLDATA (STOP_OFFR, dt_stopoffr, 0) },
Bob Supnik53d02f72007-02-03 14:59:00 -0800327 { DRDATA (SBSLVL, dt_sbs, 4), REG_HRO },
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700328 { NULL }
329 };
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800330
331MTAB dt_mod[] = {
Bob Supnik53d02f72007-02-03 14:59:00 -0800332 { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL",
333 &dev_set_sbs, &dev_show_sbs, (void *) &dt_sbs },
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700334 { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
335 { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
336 { UNIT_8FMT + UNIT_11FMT, 0, "18b", NULL, NULL },
337 { UNIT_8FMT + UNIT_11FMT, UNIT_8FMT, "12b", NULL, NULL },
338 { UNIT_8FMT + UNIT_11FMT, UNIT_11FMT, "16b", NULL, NULL },
339 { 0 }
340 };
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800341
Bob Supnik26aa6de2004-04-06 05:17:00 -0700342DEBTAB dt_deb[] = {
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700343 { "MOTION", LOG_MS },
344 { "DATA", LOG_RW },
345 { "BLOCK", LOG_BL },
346 { NULL, 0 }
347 };
Bob Supnik26aa6de2004-04-06 05:17:00 -0700348
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800349DEVICE dt_dev = {
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700350 "DT", dt_unit, dt_reg, dt_mod,
351 DT_NUMDR, 8, 24, 1, 8, 18,
352 NULL, NULL, &dt_reset,
353 NULL, &dt_attach, &dt_detach,
354 NULL, DEV_DISABLE | DEV_DEBUG, 0,
355 dt_deb, NULL, NULL
356 };
357
358/* IOT routine */
359
Bob Supnikf9564b82003-07-31 16:17:00 -0700360int32 dt (int32 IR, int32 dev, int32 dat)
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800361{
362int32 pulse = (IR >> 6) & 037;
363int32 fnc, mot, unum;
364UNIT *uptr = NULL;
365
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700366if (dt_dev.flags & DEV_DIS) /* disabled? */
367 return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */
368unum = DTA_GETUNIT (dtsa); /* get unit no */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800369if (unum >= 0) /* get unit */
370 uptr = dt_dev.units + unum;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800371
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700372if (pulse == 003) { /* MSE */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800373 if ((dtsa ^ dat) & DTA_UNIT) /* new unit? */
374 dt_deselect (dtsa);
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700375 dtsa = (dtsa & ~DTA_UNIT) | (dat & DTA_UNIT);
376 dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR);
377 }
378if (pulse == 004) { /* MLC */
379 dtsa = (dtsa & ~DTA_RW) | (dat & DTA_RW); /* load dtsa */
380 dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR);
381 fnc = DTA_GETFNC (dtsa); /* get fnc */
382 if ((uptr == NULL) || /* invalid? */
383 ((uptr->flags) & UNIT_DIS) || /* disabled? */
384 (fnc >= FNC_WMRK) || /* write mark? */
385 ((fnc == FNC_WRIT) && (uptr->flags & UNIT_WLK)) ||
386 ((fnc == FNC_WALL) && (uptr->flags & UNIT_WLK)))
387 dt_seterr (uptr, DTB_SEL); /* select err */
388 else dt_newsa (dtsa);
389 }
390if (pulse == 005) { /* MRD */
391 dat = (dat & ~DMASK) | dtdb;
392 dtsb = dtsb & ~(DTB_DTF | DTB_BEF);
393 }
394if (pulse == 006) { /* MWR */
395 dtdb = dat & DMASK;
396 dtsb = dtsb & ~(DTB_DTF | DTB_BEF);
397 }
398if (pulse == 007) { /* MRS */
399 dtsb = dtsb & ~(DTB_REV | DTB_GO); /* clr rev, go */
400 if (uptr) { /* valid unit? */
401 mot = DTS_GETMOT (uptr->STATE); /* get motion */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800402 if (mot & DTS_DIR) /* rev? set */
403 dtsb = dtsb | DTB_REV;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700404 if ((mot >= DTS_ACCF) || (uptr->STATE & 0777700))
405 dtsb = dtsb | DTB_GO; /* accel? go */
406 }
407 dat = (dat & ~DMASK) | dtsb;
408 }
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800409DT_UPDINT;
Bob Supnikf9564b82003-07-31 16:17:00 -0700410return dat;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800411}
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700412
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800413/* Unit deselect */
414
415void dt_deselect (int32 oldf)
416{
417int32 old_unit, old_mot;
418UNIT *uptr;
419
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700420old_unit = DTA_GETUNIT (oldf); /* get unit no */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800421if (old_unit < 0) /* invalid? */
422 return;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700423uptr = dt_dev.units + old_unit; /* get unit */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800424old_mot = DTS_GETMOT (uptr->STATE);
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700425if (old_mot >= DTS_ATSF) /* at speed? */
426 dt_newfnc (uptr, DTS_STA (old_mot, DTS_OFR));
427else if (old_mot >= DTS_ACCF) /* accelerating? */
428 DTS_SET2ND (DTS_ATSF | (old_mot & DTS_DIR), DTS_OFR);
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800429return;
430}
431
432/* Command register change
433
434 1. If change in motion, stop to start
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700435 - schedule acceleration
436 - set function as next state
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800437 2. If change in motion, start to stop
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700438 - if not already decelerating (could be reversing),
439 schedule deceleration
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800440 3. If change in direction,
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700441 - if not decelerating, schedule deceleration
442 - set accelerating (other dir) as next state
443 - set function as next next state
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800444 4. If not accelerating or at speed,
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700445 - schedule acceleration
446 - set function as next state
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800447 5. If not yet at speed,
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700448 - set function as next state
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800449 6. If at speed,
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700450 - set function as current state, schedule function
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800451*/
452
453void dt_newsa (int32 newf)
454{
455int32 new_unit, prev_mot, new_fnc;
456int32 prev_mving, new_mving, prev_dir, new_dir;
457UNIT *uptr;
458
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700459new_unit = DTA_GETUNIT (newf); /* new unit */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800460if (new_unit < 0) /* invalid? */
461 return;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800462uptr = dt_dev.units + new_unit;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700463if ((uptr->flags & UNIT_ATT) == 0) { /* new unit attached? */
464 dt_seterr (uptr, DTB_SEL); /* no, error */
465 return;
466 }
467prev_mot = DTS_GETMOT (uptr->STATE); /* previous motion */
468prev_mving = prev_mot != DTS_STOP; /* previous moving? */
469prev_dir = prev_mot & DTS_DIR; /* previous dir? */
470new_mving = (newf & DTA_STSTP) != 0; /* new moving? */
471new_dir = (newf & DTA_FWDRV) != 0; /* new dir? */
472new_fnc = DTA_GETFNC (newf); /* new function? */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800473
Bob Supnik9c4779c2009-02-08 09:06:00 -0800474if ((prev_mving | new_mving) == 0) /* stop to stop */
475 return;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800476
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700477if (new_mving & ~prev_mving) { /* start? */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800478 if (dt_setpos (uptr)) /* update pos */
479 return;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700480 sim_cancel (uptr); /* stop current */
481 sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* sched accel */
482 DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */
483 DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */
484 return;
485 }
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800486
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700487if (prev_mving & ~new_mving) { /* stop? */
488 if ((prev_mot & ~DTS_DIR) != DTS_DECF) { /* !already stopping? */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800489 if (dt_setpos (uptr)) /* update pos */
490 return;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700491 sim_cancel (uptr); /* stop current */
492 sim_activate (uptr, dt_dctime); /* schedule decel */
493 }
494 DTS_SETSTA (DTS_DECF | prev_dir, 0); /* state = decel */
495 return;
496 }
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800497
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700498if (prev_dir ^ new_dir) { /* dir chg? */
499 if ((prev_mot & ~DTS_DIR) != DTS_DECF) { /* !already stopping? */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800500 if (dt_setpos (uptr)) /* update pos */
501 return;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700502 sim_cancel (uptr); /* stop current */
503 sim_activate (uptr, dt_dctime); /* schedule decel */
504 }
505 DTS_SETSTA (DTS_DECF | prev_dir, 0); /* state = decel */
506 DTS_SET2ND (DTS_ACCF | new_dir, 0); /* next = accel */
507 DTS_SET3RD (DTS_ATSF | new_dir, new_fnc); /* next next = fnc */
508 return;
509 }
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800510
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700511if (prev_mot < DTS_ACCF) { /* not accel/at speed? */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800512 if (dt_setpos (uptr)) /* update pos */
513 return;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700514 sim_cancel (uptr); /* cancel cur */
515 sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* sched accel */
516 DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */
517 DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */
518 return;
519 }
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800520
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700521if (prev_mot < DTS_ATSF) { /* not at speed? */
522 DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */
523 return;
524 }
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800525
526dt_newfnc (uptr, DTS_STA (DTS_ATSF | new_dir, new_fnc));/* state = fnc */
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700527return;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800528}
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700529
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800530/* Schedule new DECtape function
531
532 This routine is only called if
533 - the selected unit is attached
534 - the selected unit is at speed (forward or backward)
535
536 This routine
537 - updates the selected unit's position
538 - updates the selected unit's state
539 - schedules the new operation
540*/
541
542void dt_newfnc (UNIT *uptr, int32 newsta)
543{
544int32 fnc, dir, blk, unum, newpos;
545uint32 oldpos;
546
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700547oldpos = uptr->pos; /* save old pos */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800548if (dt_setpos (uptr)) /* update pos */
549 return;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700550uptr->STATE = newsta; /* update state */
551fnc = DTS_GETFNC (uptr->STATE); /* set variables */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800552dir = DTS_GETMOT (uptr->STATE) & DTS_DIR;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700553unum = (int32) (uptr - dt_dev.units);
554if (oldpos == uptr->pos) /* bump pos */
555 uptr->pos = uptr->pos + (dir? -1: 1);
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800556blk = DT_LIN2BL (uptr->pos, uptr);
557
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700558if (dir? DT_QREZ (uptr): DT_QFEZ (uptr)) { /* wrong ez? */
559 dt_seterr (uptr, DTB_END); /* set ez flag, stop */
560 return;
561 }
562sim_cancel (uptr); /* cancel cur op */
563dt_substate = DTO_SOB; /* substate = block start */
564switch (fnc) { /* case function */
565
566 case DTS_OFR: /* off reel */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800567 if (dir) /* rev? < start */
568 newpos = -1000;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700569 else newpos = DTU_FWDEZ (uptr) + DT_EZLIN + 1000; /* fwd? > end */
570 break;
571
572 case FNC_MOVE: /* move */
573 dt_schedez (uptr, dir); /* sched end zone */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800574 if (DEBUG_PRI (dt_dev, LOG_MS))
575 fprintf (sim_deb, ">>DT%d: moving %s\n", unum,
576 (dir? "backward": "forward"));
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700577 return; /* done */
578
579 case FNC_SRCH: /* search */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800580 if (dir)
581 newpos = DT_BLK2LN ((DT_QFEZ (uptr)? DTU_TSIZE (uptr): blk), uptr) -
582 DT_BLKLN - DT_WSIZE;
583 else newpos = DT_BLK2LN ((DT_QREZ (uptr)? 0: blk + 1), uptr) +
584 DT_BLKLN + (DT_WSIZE - 1);
585 if (DEBUG_PRI (dt_dev, LOG_MS))
586 fprintf (sim_deb, ">>DT%d: searching %s\n", unum,
587 (dir? "backward": "forward"));
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700588 break;
589
590 case FNC_WRIT: /* write */
591 case FNC_READ: /* read */
592 case FNC_RALL: /* read all */
593 case FNC_WALL: /* write all */
594 if (DT_QEZ (uptr)) { /* in "ok" end zone? */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800595 if (dir)
596 newpos = DTU_FWDEZ (uptr) - DT_WSIZE;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700597 else newpos = DT_EZLIN + (DT_WSIZE - 1);
598 }
599 else {
600 newpos = ((uptr->pos) / DT_WSIZE) * DT_WSIZE;
Bob Supnik9c4779c2009-02-08 09:06:00 -0800601 if (!dir)
602 newpos = newpos + (DT_WSIZE - 1);
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700603 }
604 if (DEBUG_PRI (dt_dev, LOG_RW) ||
605 (DEBUG_PRI (dt_dev, LOG_BL) && (blk == dt_logblk)))
606 fprintf (sim_deb, ">>DT%d: read all block %d %s%s\n",
607 unum, blk, (dir? "backward": "forward"),
608 ((dtsa & DTA_MODE)? " continuous": " "));
609 break;
610
611 default:
612 dt_seterr (uptr, DTB_SEL); /* bad state */
613 return;
614 }
615
616if ((fnc == FNC_WRIT) || (fnc == FNC_WALL)) { /* write function? */
617 dtsb = dtsb | DTB_DTF; /* set data flag */
618 DT_UPDINT;
619 }
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800620sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime);
621return;
622}
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700623
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800624/* Update DECtape position
625
626 DECtape motion is modeled as a constant velocity, with linear
627 acceleration and deceleration. The motion equations are as follows:
628
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700629 t = time since operation started
630 tmax = time for operation (accel, decel only)
631 v = at speed velocity in lines (= 1/dt_ltime)
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800632
633 Then:
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700634 at speed dist = t * v
635 accel dist = (t^2 * v) / (2 * tmax)
636 decel dist = (((2 * t * tmax) - t^2) * v) / (2 * tmax)
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800637
638 This routine uses the relative (integer) time, rather than the absolute
639 (floating point) time, to allow save and restore of the start times.
640*/
641
642t_bool dt_setpos (UNIT *uptr)
643{
644uint32 new_time, ut, ulin, udelt;
645int32 mot = DTS_GETMOT (uptr->STATE);
646int32 unum, delta;
647
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700648new_time = sim_grtime (); /* current time */
649ut = new_time - uptr->LASTT; /* elapsed time */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800650if (ut == 0) /* no time gone? exit */
651 return FALSE;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700652uptr->LASTT = new_time; /* update last time */
653switch (mot & ~DTS_DIR) { /* case on motion */
654
655 case DTS_STOP: /* stop */
656 delta = 0;
657 break;
658
659 case DTS_DECF: /* slowing */
660 ulin = ut / (uint32) dt_ltime;
661 udelt = dt_dctime / dt_ltime;
662 delta = ((ulin * udelt * 2) - (ulin * ulin)) / (2 * udelt);
663 break;
664
665 case DTS_ACCF: /* accelerating */
666 ulin = ut / (uint32) dt_ltime;
667 udelt = (dt_dctime - (dt_dctime >> 2)) / dt_ltime;
668 delta = (ulin * ulin) / (2 * udelt);
669 break;
670
671 case DTS_ATSF: /* at speed */
672 delta = ut / (uint32) dt_ltime;
673 break;
674 }
675
Bob Supnik9c4779c2009-02-08 09:06:00 -0800676if (mot & DTS_DIR) /* update pos */
677 uptr->pos = uptr->pos - delta;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800678else uptr->pos = uptr->pos + delta;
679if (((int32) uptr->pos < 0) ||
680 ((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) {
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700681 detach_unit (uptr); /* off reel? */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800682 uptr->STATE = uptr->pos = 0;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700683 unum = (int32) (uptr - dt_dev.units);
684 if (unum == DTA_GETUNIT (dtsa)) /* if selected, */
685 dt_seterr (uptr, DTB_SEL); /* error */
686 return TRUE;
687 }
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800688return FALSE;
689}
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700690
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800691/* Unit service
692
693 Unit must be attached, detach cancels operation
694*/
695
696t_stat dt_svc (UNIT *uptr)
697{
698int32 mot = DTS_GETMOT (uptr->STATE);
699int32 dir = mot & DTS_DIR;
700int32 fnc = DTS_GETFNC (uptr->STATE);
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700701int32 *fbuf = (int32 *) uptr->filebuf;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800702int32 blk, wrd, ma, relpos;
Bob Supnik4ffd3be2003-06-25 09:20:00 -0700703uint32 ba;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800704
705/* Motion cases
706
707 Decelerating - if next state != stopped, must be accel reverse
708 Accelerating - next state must be @speed, schedule function
709 At speed - do functional processing
710*/
711
712switch (mot) {
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700713
714 case DTS_DECF: case DTS_DECR: /* decelerating */
715 if (dt_setpos (uptr)) /* upd pos; off reel? */
716 return IORETURN (dt_stopoffr, STOP_DTOFF);
717 uptr->STATE = DTS_NXTSTA (uptr->STATE); /* advance state */
718 if (uptr->STATE) /* not stopped? */
719 sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* reversing */
720 return SCPE_OK;
721
722 case DTS_ACCF: case DTS_ACCR: /* accelerating */
723 dt_newfnc (uptr, DTS_NXTSTA (uptr->STATE)); /* adv state, sched */
724 return SCPE_OK;
725
726 case DTS_ATSF: case DTS_ATSR: /* at speed */
727 break; /* check function */
728
729 default: /* other */
730 dt_seterr (uptr, DTB_SEL); /* state error */
731 return SCPE_OK;
732 }
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800733
734/* Functional cases
735
736 Move - must be at end zone
737 Search - transfer block number, schedule next block
738 Off reel - detach unit (it must be deselected)
739*/
740
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700741if (dt_setpos (uptr)) /* upd pos; off reel? */
742 return IORETURN (dt_stopoffr, STOP_DTOFF);
743if (DT_QEZ (uptr)) { /* in end zone? */
744 dt_seterr (uptr, DTB_END); /* end zone error */
745 return SCPE_OK;
746 }
747blk = DT_LIN2BL (uptr->pos, uptr); /* get block # */
748
749switch (fnc) { /* at speed, check fnc */
750
751 case FNC_MOVE: /* move */
752 dt_seterr (uptr, DTB_END); /* end zone error */
753 return SCPE_OK;
754
755 case DTS_OFR: /* off reel */
756 detach_unit (uptr); /* must be deselected */
757 uptr->STATE = uptr->pos = 0; /* no visible action */
758 break;
759
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800760/* Search */
761
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700762 case FNC_SRCH: /* search */
763 if (dtsb & DTB_DTF) { /* DTF set? */
764 dt_seterr (uptr, DTB_TIM); /* timing error */
765 return SCPE_OK;
766 }
767 sim_activate (uptr, DTU_LPERB (uptr) * dt_ltime);/* sched next block */
768 dtdb = blk; /* store block # */
769 dtsb = dtsb | DTB_DTF; /* set DTF */
770 break;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800771
772/* Read and read all */
773
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700774 case FNC_READ: case FNC_RALL:
775 if (dtsb & DTB_DTF) { /* DTF set? */
776 dt_seterr (uptr, DTB_TIM); /* timing error */
777 return SCPE_OK;
778 }
779 sim_activate (uptr, DT_WSIZE * dt_ltime); /* sched next word */
780 relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */
781 if ((relpos >= DT_HTLIN) && /* in data zone? */
782 (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
783 wrd = DT_LIN2WD (uptr->pos, uptr);
784 ba = (blk * DTU_BSIZE (uptr)) + wrd;
785 dtdb = fbuf[ba]; /* get tape word */
786 dtsb = dtsb | DTB_DTF; /* set flag */
787 }
788 else {
789 ma = (2 * DT_HTWRD) + DTU_BSIZE (uptr) - DT_CSMWD - 1;
790 wrd = relpos / DT_WSIZE; /* hdr start = wd 0 */
Bob Supnik15919a22006-07-20 13:36:00 -0700791#if defined (OLD_TYPE550)
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700792 if ((wrd == 0) || /* skip 1st, last */
793 (wrd == ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - 1))) break;
Bob Supnik15919a22006-07-20 13:36:00 -0700794#endif
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700795 if ((fnc == FNC_READ) && /* read, skip if not */
796 (wrd != DT_CSMWD) && /* fwd, rev cksum */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800797 (wrd != ma))
798 break;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700799 dtdb = dt_gethdr (uptr, blk, relpos);
800 if (wrd == (dir? DT_CSMWD: ma)) /* at end csum? */
801 dtsb = dtsb | DTB_BEF; /* end block */
802 else dtsb = dtsb | DTB_DTF; /* else next word */
803 }
Bob Supnik9c4779c2009-02-08 09:06:00 -0800804 if (dir)
805 dtdb = dt_comobv (dtdb);
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700806 break;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800807
808/* Write and write all */
809
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700810 case FNC_WRIT: case FNC_WALL:
811 if (dtsb & DTB_DTF) { /* DTF set? */
812 dt_seterr (uptr, DTB_TIM); /* timing error */
813 return SCPE_OK;
814 }
815 sim_activate (uptr, DT_WSIZE * dt_ltime); /* sched next word */
816 relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */
817 if ((relpos >= DT_HTLIN) && /* in data zone? */
818 (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
819 wrd = DT_LIN2WD (uptr->pos, uptr);
820 ba = (blk * DTU_BSIZE (uptr)) + wrd;
Bob Supnik9c4779c2009-02-08 09:06:00 -0800821 if (dir) /* get data word */
822 fbuf[ba] = dt_comobv (dtdb);
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700823 else fbuf[ba] = dtdb;
Bob Supnik9c4779c2009-02-08 09:06:00 -0800824 if (ba >= uptr->hwmark)
825 uptr->hwmark = ba + 1;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700826 if (wrd == (dir? 0: DTU_BSIZE (uptr) - 1))
827 dtsb = dtsb | DTB_BEF; /* end block */
828 else dtsb = dtsb | DTB_DTF; /* else next word */
829 }
830 else {
831 wrd = relpos / DT_WSIZE; /* hdr start = wd 0 */
Bob Supnik15919a22006-07-20 13:36:00 -0700832#if defined (OLD_TYPE550)
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700833 if ((wrd == 0) || /* skip 1st, last */
834 (wrd == ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - 1))) break;
Bob Supnik15919a22006-07-20 13:36:00 -0700835#endif
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700836 if ((fnc == FNC_WRIT) && /* wr, skip if !csm */
837 (wrd != ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - DT_CSMWD - 1)))
838 break;
839 dtsb = dtsb | DTB_DTF; /* set flag */
840 }
841 break;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800842
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700843 default:
844 dt_seterr (uptr, DTB_SEL); /* impossible state */
845 break;
846 }
847
848DT_UPDINT; /* update interrupts */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800849return SCPE_OK;
850}
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700851
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800852/* Utility routines */
853
854/* Set error flag */
855
856void dt_seterr (UNIT *uptr, int32 e)
857{
858int32 mot = DTS_GETMOT (uptr->STATE);
859
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700860dtsa = dtsa & ~DTA_STSTP; /* clear go */
861dtsb = dtsb | DTB_ERF | e; /* set error flag */
862if (mot >= DTS_ACCF) { /* ~stopped or stopping? */
863 sim_cancel (uptr); /* cancel activity */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800864 if (dt_setpos (uptr)) /* update position */
865 return;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700866 sim_activate (uptr, dt_dctime); /* sched decel */
867 DTS_SETSTA (DTS_DECF | (mot & DTS_DIR), 0); /* state = decel */
868 }
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800869DT_UPDINT;
870return;
871}
872
873/* Schedule end zone */
874
875void dt_schedez (UNIT *uptr, int32 dir)
876{
877int32 newpos;
878
Bob Supnik9c4779c2009-02-08 09:06:00 -0800879if (dir) /* rev? rev ez */
880 newpos = DT_EZLIN - DT_WSIZE;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700881else newpos = DTU_FWDEZ (uptr) + DT_WSIZE; /* fwd? fwd ez */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800882sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime);
883return;
884}
885
886/* Complement obverse routine */
887
888int32 dt_comobv (int32 dat)
889{
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700890dat = dat ^ 0777777; /* compl obverse */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800891dat = ((dat >> 15) & 07) | ((dat >> 9) & 070) |
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700892 ((dat >> 3) & 0700) | ((dat & 0700) << 3) |
893 ((dat & 070) << 9) | ((dat & 07) << 15);
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800894return dat;
895}
896
897/* Checksum routine */
898
899int32 dt_csum (UNIT *uptr, int32 blk)
900{
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700901int32 *fbuf = (int32 *) uptr->filebuf;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800902int32 ba = blk * DTU_BSIZE (uptr);
903int32 i, csum, wrd;
904
905csum = 0777777;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700906for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */
907 wrd = fbuf[ba + i]; /* get word */
908 csum = csum + wrd; /* 1's comp add */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800909 if (csum > 0777777)
910 csum = (csum + 1) & 0777777;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700911 }
912return (csum ^ 0777777); /* 1's comp res */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800913}
914
915/* Get header word */
916
917int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos)
918{
919int32 wrd = relpos / DT_WSIZE;
920
Bob Supnik9c4779c2009-02-08 09:06:00 -0800921if (wrd == DT_BLKWD) /* fwd blknum */
922 return blk;
923if (wrd == DT_CSMWD) /* rev csum */
924 return 0777777;
925if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700926 return (dt_csum (uptr, blk));
Bob Supnik9c4779c2009-02-08 09:06:00 -0800927if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_BLKWD - 1)) /* rev blkno */
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700928 return dt_comobv (blk);
929return 0; /* all others */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800930}
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700931
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800932/* Reset routine */
933
934t_stat dt_reset (DEVICE *dptr)
935{
936int32 i, prev_mot;
937UNIT *uptr;
938
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700939for (i = 0; i < DT_NUMDR; i++) { /* stop all drives */
940 uptr = dt_dev.units + i;
941 if (sim_is_running) { /* CAF? */
942 prev_mot = DTS_GETMOT (uptr->STATE); /* get motion */
943 if ((prev_mot & ~DTS_DIR) > DTS_DECF) { /* accel or spd? */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800944 if (dt_setpos (uptr)) /* update pos */
945 continue;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700946 sim_cancel (uptr);
947 sim_activate (uptr, dt_dctime); /* sched decel */
948 DTS_SETSTA (DTS_DECF | (prev_mot & DTS_DIR), 0);
949 }
950 }
951 else {
952 sim_cancel (uptr); /* sim reset */
953 uptr->STATE = 0;
954 uptr->LASTT = sim_grtime ();
955 }
956 }
957dtsa = dtsb = 0; /* clear status */
958DT_UPDINT; /* reset interrupt */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800959return SCPE_OK;
960}
961
962/* IORS routine */
963
964int32 dt_iors (void)
965{
966#if defined IOS_DTA
967return ((dtsb & (DTB_ERF | DTB_DTF))? IOS_DTA: 0);
968#else
969return 0;
970#endif
971}
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700972
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800973/* Attach routine
974
975 Determine 12b, 16b, or 18b/36b format
976 Allocate buffer
977 If 12b, read 12b format and convert to 18b in buffer
978 If 16b, read 16b format and convert to 18b in buffer
979 If 18b/36b, read data into buffer
980*/
981
982t_stat dt_attach (UNIT *uptr, char *cptr)
983{
984uint16 pdp8b[D8_NBSIZE];
985uint16 pdp11b[D18_BSIZE];
Bob Supnik1da2d942003-12-31 11:49:00 -0800986uint32 ba, sz, k, *fbuf;
Bob Supnik4ffd3be2003-06-25 09:20:00 -0700987int32 u = uptr - dt_dev.units;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800988t_stat r;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800989
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700990r = attach_unit (uptr, cptr); /* attach */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800991if (r != SCPE_OK) /* error? */
992 return r;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700993if ((sim_switches & SIM_SW_REST) == 0) { /* not from rest? */
994 uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); /* default 18b */
Bob Supnik15919a22006-07-20 13:36:00 -0700995 if (sim_switches & SWMASK ('T')) /* att 12b? */
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700996 uptr->flags = uptr->flags | UNIT_8FMT;
997 else if (sim_switches & SWMASK ('S')) /* att 16b? */
998 uptr->flags = uptr->flags | UNIT_11FMT;
Bob Supnik15919a22006-07-20 13:36:00 -0700999 else if (!(sim_switches & SWMASK ('A')) && /* autosize? */
Bob Supnikb7c1eae2005-09-09 18:09:00 -07001000 (sz = sim_fsize (uptr->fileref))) {
1001 if (sz == D8_FILSIZ)
1002 uptr->flags = uptr->flags | UNIT_8FMT;
1003 else if (sz == D11_FILSIZ)
1004 uptr->flags = uptr->flags | UNIT_11FMT;
1005 }
1006 }
1007uptr->capac = DTU_CAPAC (uptr); /* set capacity */
1008uptr->filebuf = calloc (uptr->capac, sizeof (uint32));
1009if (uptr->filebuf == NULL) { /* can't alloc? */
1010 detach_unit (uptr);
1011 return SCPE_MEM;
1012 }
1013fbuf = (uint32 *) uptr->filebuf; /* file buffer */
Bob Supnik4ffd3be2003-06-25 09:20:00 -07001014printf ("%s%d: ", sim_dname (&dt_dev), u);
Bob Supnik9c4779c2009-02-08 09:06:00 -08001015if (uptr->flags & UNIT_8FMT)
1016 printf ("12b format");
1017else if (uptr->flags & UNIT_11FMT)
1018 printf ("16b format");
Bob Supnik4ffd3be2003-06-25 09:20:00 -07001019else printf ("18b/36b format");
Bob Supnik2c2dd5e2002-11-17 15:54:00 -08001020printf (", buffering file in memory\n");
Bob Supnikb7c1eae2005-09-09 18:09:00 -07001021if (uptr->flags & UNIT_8FMT) { /* 12b? */
1022 for (ba = 0; ba < uptr->capac; ) { /* loop thru file */
1023 k = fxread (pdp8b, sizeof (uint16), D8_NBSIZE, uptr->fileref);
Bob Supnik9c4779c2009-02-08 09:06:00 -08001024 if (k == 0)
1025 break;
1026 for ( ; k < D8_NBSIZE; k++)
1027 pdp8b[k] = 0;
Bob Supnikb7c1eae2005-09-09 18:09:00 -07001028 for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop thru blk */
1029 fbuf[ba] = ((uint32) (pdp8b[k] & 07777) << 6) |
1030 ((uint32) (pdp8b[k + 1] >> 6) & 077);
1031 fbuf[ba + 1] = ((uint32) (pdp8b[k + 1] & 077) << 12) |
1032 ((uint32) pdp8b[k + 2] & 07777);
1033 ba = ba + 2;
1034 } /* end blk loop */
1035 } /* end file loop */
1036 uptr->hwmark = ba;
1037 } /* end if */
1038else if (uptr->flags & UNIT_11FMT) { /* 16b? */
1039 for (ba = 0; ba < uptr->capac; ) { /* loop thru file */
1040 k = fxread (pdp11b, sizeof (uint16), D18_BSIZE, uptr->fileref);
Bob Supnik9c4779c2009-02-08 09:06:00 -08001041 if (k == 0)
1042 break;
1043 for ( ; k < D18_BSIZE; k++)
1044 pdp11b[k] = 0;
Bob Supnikb7c1eae2005-09-09 18:09:00 -07001045 for (k = 0; k < D18_BSIZE; k++)
1046 fbuf[ba++] = pdp11b[k];
1047 }
1048 uptr->hwmark = ba; /* end elif */
1049 }
1050else uptr->hwmark = fxread (uptr->filebuf, sizeof (uint32),
1051 uptr->capac, uptr->fileref);
1052uptr->flags = uptr->flags | UNIT_BUF; /* set buf flag */
1053uptr->pos = DT_EZLIN; /* beyond leader */
1054uptr->LASTT = sim_grtime (); /* last pos update */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -08001055return SCPE_OK;
1056}
1057
1058/* Detach routine
1059
1060 Cancel in progress operation
1061 If 12b, convert 18b buffer to 12b and write to file
1062 If 16b, convert 18b buffer to 16b and write to file
1063 If 18b/36b, write buffer to file
1064 Deallocate buffer
1065*/
1066
1067t_stat dt_detach (UNIT* uptr)
1068{
1069uint16 pdp8b[D8_NBSIZE];
1070uint16 pdp11b[D18_BSIZE];
Bob Supnik1da2d942003-12-31 11:49:00 -08001071uint32 ba, k, *fbuf;
Bob Supnik4ffd3be2003-06-25 09:20:00 -07001072int32 u = uptr - dt_dev.units;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -08001073
Bob Supnik9c4779c2009-02-08 09:06:00 -08001074if (!(uptr->flags & UNIT_ATT)) /* attached? */
1075 return SCPE_OK;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -08001076if (sim_is_active (uptr)) {
Bob Supnikb7c1eae2005-09-09 18:09:00 -07001077 sim_cancel (uptr);
1078 if ((u == DTA_GETUNIT (dtsa)) && (dtsa & DTA_STSTP)) {
1079 dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF;
1080 DT_UPDINT;
1081 }
1082 uptr->STATE = uptr->pos = 0;
1083 }
1084fbuf = (uint32 *) uptr->filebuf; /* file buffer */
1085if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */
1086 printf ("%s%d: writing buffer to file\n", sim_dname (&dt_dev), u);
1087 rewind (uptr->fileref); /* start of file */
1088 if (uptr->flags & UNIT_8FMT) { /* 12b? */
1089 for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */
1090 for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop blk */
1091 pdp8b[k] = (fbuf[ba] >> 6) & 07777;
1092 pdp8b[k + 1] = ((fbuf[ba] & 077) << 6) |
1093 ((fbuf[ba + 1] >> 12) & 077);
1094 pdp8b[k + 2] = fbuf[ba + 1] & 07777;
1095 ba = ba + 2;
1096 } /* end loop blk */
1097 fxwrite (pdp8b, sizeof (uint16), D8_NBSIZE, uptr->fileref);
Bob Supnik9c4779c2009-02-08 09:06:00 -08001098 if (ferror (uptr->fileref))
1099 break;
Bob Supnikb7c1eae2005-09-09 18:09:00 -07001100 } /* end loop file */
1101 } /* end if 12b */
1102 else if (uptr->flags & UNIT_11FMT) { /* 16b? */
1103 for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */
1104 for (k = 0; k < D18_BSIZE; k++) /* loop blk */
1105 pdp11b[k] = fbuf[ba++] & 0177777;
1106 fxwrite (pdp11b, sizeof (uint16), D18_BSIZE, uptr->fileref);
Bob Supnik9c4779c2009-02-08 09:06:00 -08001107 if (ferror (uptr->fileref))
1108 break;
Bob Supnikb7c1eae2005-09-09 18:09:00 -07001109 } /* end loop file */
1110 } /* end if 16b */
1111 else fxwrite (uptr->filebuf, sizeof (uint32), /* write file */
1112 uptr->hwmark, uptr->fileref);
Bob Supnik9c4779c2009-02-08 09:06:00 -08001113 if (ferror (uptr->fileref))
1114 perror ("I/O error");
Bob Supnikb7c1eae2005-09-09 18:09:00 -07001115 } /* end if hwmark */
1116free (uptr->filebuf); /* release buf */
1117uptr->flags = uptr->flags & ~UNIT_BUF; /* clear buf flag */
1118uptr->filebuf = NULL; /* clear buf ptr */
1119uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); /* default fmt */
1120uptr->capac = DT_CAPAC; /* default size */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -08001121return detach_unit (uptr);
1122}