1
/* pdp11_tc.c: PDP-11 DECtape simulator
3
Copyright (c) 1993-2004, Robert M Supnik
5
Permission is hereby granted, free of charge, to any person obtaining a
6
copy of this software and associated documentation files (the "Software"),
7
to deal in the Software without restriction, including without limitation
8
the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
and/or sell copies of the Software, and to permit persons to whom the
10
Software is furnished to do so, subject to the following conditions:
12
The above copyright notice and this permission notice shall be included in
13
all copies or substantial portions of the Software.
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
Except as contained in this notice, the name of Robert M Supnik shall not
23
be used in advertising or otherwise to promote the sale, use or other dealings
24
in this Software without prior written authorization from Robert M Supnik.
28
25-Jan-04 RMS Revised for device debug support
29
09-Jan-04 RMS Changed sim_fsize calling sequence, added STOP_OFFR
30
29-Dec-03 RMS Changed initial status to disabled (in Qbus system)
31
18-Oct-03 RMS Fixed reverse checksum in read all
32
Added DECtape off reel message
34
25-Apr-03 RMS Revised for extended file support
35
14-Mar-03 RMS Fixed variable size interaction with save/restore
36
29-Sep-02 RMS Added variable address support to bootstrap
37
Added vector change/display support
38
Added 16b format support
40
30-May-02 RMS Widened POS to 32b
41
26-Jan-02 RMS Revised bootstrap to conform to M9312
42
06-Jan-02 RMS Revised enable/disable support
43
30-Nov-01 RMS Added read only unit, extended SET/SHOW support
44
24-Nov-01 RMS Converted POS, STATT, LASTT to arrays
45
09-Nov-01 RMS Added bus map support
46
15-Sep-01 RMS Integrated debug logging
47
27-Sep-01 RMS Fixed interrupt after stop for RSTS/E
48
07-Sep-01 RMS Revised device disable and interrupt mechanisms
49
29-Aug-01 RMS Added casts to PDP-8 unpack routine
50
17-Jul-01 RMS Moved function prototype
51
11-May-01 RMS Fixed bug in reset
52
26-Apr-01 RMS Added device enable/disable support
53
18-Apr-01 RMS Changed to rewind tape before boot
54
16-Mar-01 RMS Fixed bug in interrupt after stop
55
15-Mar-01 RMS Added 129th word to PDP-8 format
57
PDP-11 DECtapes are represented in memory by fixed length buffer of 32b words.
58
Three file formats are supported:
60
18b/36b 256 words per block [256 x 18b]
61
16b 256 words per block [256 x 16b]
62
12b 129 words per block [129 x 12b]
64
When a 16b or 12b DECtape file is read in, it is converted to 18b/36b format.
66
DECtape motion is measured in 3b lines. Time between lines is 33.33us.
67
Tape density is nominally 300 lines per inch. The format of a DECtape (as
68
taken from the TD8E formatter) is:
70
reverse end zone 8192 reverse end zone codes ~ 10 feet
71
reverse buffer 200 interblock codes
75
forward buffer 200 interblock codes
76
forward end zone 8192 forward end zone codes ~ 10 feet
78
A block consists of five 18b header words, a tape-specific number of data
79
words, and five 18b trailer words. All systems except the PDP-8 use a
80
standard block length of 256 words; the PDP-8 uses a standard block length
81
of 86 words (x 18b = 129 words x 12b).
83
Because a DECtape file only contains data, the simulator cannot support
84
write timing and mark track and can only do a limited implementation
85
of read all and write all. Read all assumes that the tape has been
86
conventionally written forward:
89
header word 1 block number (for forward reads)
91
header word 4 checksum (for reverse reads)
93
trailer word 4 checksum (for forward reads)
95
trailer word 1 block number (for reverse reads)
98
Write all writes only the data words and dumps the interblock words in the
102
#include "pdp11_defs.h"
104
#define DT_NUMDR 8 /* #drives */
105
#define DT_M_NUMDR (DT_NUMDR - 1)
106
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
107
#define UNIT_V_8FMT (UNIT_V_UF + 1) /* 12b format */
108
#define UNIT_V_11FMT (UNIT_V_UF + 2) /* 16b format */
109
#define UNIT_WLK (1 << UNIT_V_WLK)
110
#define UNIT_8FMT (1 << UNIT_V_8FMT)
111
#define UNIT_11FMT (1 << UNIT_V_11FMT)
112
#define STATE u3 /* unit state */
113
#define LASTT u4 /* last time update */
114
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
116
/* System independent DECtape constants */
118
#define DT_LPERMC 6 /* lines per mark track */
119
#define DT_BLKWD 1 /* blk no word in h/t */
120
#define DT_CSMWD 4 /* checksum word in h/t */
121
#define DT_HTWRD 5 /* header/trailer words */
122
#define DT_EZLIN (8192 * DT_LPERMC) /* end zone length */
123
#define DT_BFLIN (200 * DT_LPERMC) /* buffer length */
124
#define DT_BLKLN (DT_BLKWD * DT_LPERMC) /* blk no line in h/t */
125
#define DT_CSMLN (DT_CSMWD * DT_LPERMC) /* csum line in h/t */
126
#define DT_HTLIN (DT_HTWRD * DT_LPERMC) /* header/trailer lines */
128
/* 16b, 18b, 36b DECtape constants */
130
#define D18_WSIZE 6 /* word size in lines */
131
#define D18_BSIZE 256 /* block size in 18b */
132
#define D18_TSIZE 578 /* tape size */
133
#define D18_LPERB (DT_HTLIN + (D18_BSIZE * DT_WSIZE) + DT_HTLIN)
134
#define D18_FWDEZ (DT_EZLIN + (D18_LPERB * D18_TSIZE))
135
#define D18_CAPAC (D18_TSIZE * D18_BSIZE) /* tape capacity */
136
#define D16_FILSIZ (D18_TSIZE * D18_BSIZE * sizeof (int16))
138
/* 12b DECtape constants */
140
#define D8_WSIZE 4 /* word size in lines */
141
#define D8_BSIZE 86 /* block size in 18b */
142
#define D8_TSIZE 1474 /* tape size */
143
#define D8_LPERB (DT_HTLIN + (D8_BSIZE * DT_WSIZE) + DT_HTLIN)
144
#define D8_FWDEZ (DT_EZLIN + (D8_LPERB * D8_TSIZE))
145
#define D8_CAPAC (D8_TSIZE * D8_BSIZE) /* tape capacity */
147
#define D8_NBSIZE ((D8_BSIZE * D18_WSIZE) / D8_WSIZE)
148
#define D8_FILSIZ (D8_NBSIZE * D8_TSIZE * sizeof (int16))
150
/* This controller */
152
#define DT_CAPAC D18_CAPAC /* default */
153
#define DT_WSIZE D18_WSIZE
155
/* Calculated constants, per unit */
157
#define DTU_BSIZE(u) (((u)->flags & UNIT_8FMT)? D8_BSIZE: D18_BSIZE)
158
#define DTU_TSIZE(u) (((u)->flags & UNIT_8FMT)? D8_TSIZE: D18_TSIZE)
159
#define DTU_LPERB(u) (((u)->flags & UNIT_8FMT)? D8_LPERB: D18_LPERB)
160
#define DTU_FWDEZ(u) (((u)->flags & UNIT_8FMT)? D8_FWDEZ: D18_FWDEZ)
161
#define DTU_CAPAC(u) (((u)->flags & UNIT_8FMT)? D8_CAPAC: D18_CAPAC)
163
#define DT_LIN2BL(p,u) (((p) - DT_EZLIN) / DTU_LPERB (u))
164
#define DT_LIN2OF(p,u) (((p) - DT_EZLIN) % DTU_LPERB (u))
165
#define DT_LIN2WD(p,u) ((DT_LIN2OF (p,u) - DT_HTLIN) / DT_WSIZE)
166
#define DT_BLK2LN(p,u) (((p) * DTU_LPERB (u)) + DT_EZLIN)
167
#define DT_QREZ(u) (((u)->pos) < DT_EZLIN)
168
#define DT_QFEZ(u) (((u)->pos) >= ((uint32) DTU_FWDEZ (u)))
169
#define DT_QEZ(u) (DT_QREZ (u) || DT_QFEZ (u))
171
/* TCST - 177340 - status register */
173
#define STA_END 0100000 /* end zone */
174
#define STA_PAR 0040000 /* parity err */
175
#define STA_MRK 0020000 /* mark trk err */
176
#define STA_ILO 0010000 /* illegal op */
177
#define STA_SEL 0004000 /* select err */
178
#define STA_BLKM 0002000 /* block miss err */
179
#define STA_DATM 0001000 /* data miss err */
180
#define STA_NXM 0000400 /* nx mem err */
181
#define STA_UPS 0000200 /* up to speed */
182
#define STA_V_XD 0 /* extended data */
184
#define STA_ALLERR (STA_END | STA_PAR | STA_MRK | STA_ILO | \
185
STA_SEL | STA_BLKM | STA_DATM | STA_NXM )
186
#define STA_RWERR (STA_END | STA_PAR | STA_MRK | \
187
STA_BLKM | STA_DATM | STA_NXM )
188
#define STA_RW 0000003
189
#define STA_GETXD(x) (((x) >> STA_V_XD) & STA_M_XD)
191
/* TCCM - 177342 - command register */
193
/* #define CSR_ERR 0100000 */
194
#define CSR_MNT 0020000 /* maint (unimpl) */
195
#define CSR_INH 0010000 /* delay inhibit */
196
#define CSR_DIR 0004000 /* reverse */
197
#define CSR_V_UNIT 8 /* unit select */
198
#define CSR_M_UNIT 07
199
#define CSR_UNIT (CSR_M_UNIT << CSR_V_UNIT)
200
/* #define CSR_DONE 0000200 */
201
/* #define CSR_IE 0000100 */
202
#define CSR_V_MEX 4 /* mem extension */
204
#define CSR_MEX (CSR_M_MEX << CSR_V_MEX)
205
#define CSR_V_FNC 1 /* function */
207
#define FNC_STOP 00 /* stop all */
208
#define FNC_SRCH 01 /* search */
209
#define FNC_READ 02 /* read */
210
#define FNC_RALL 03 /* read all */
211
#define FNC_SSEL 04 /* stop selected */
212
#define FNC_WMRK 05 /* write */
213
#define FNC_WRIT 06 /* write all */
214
#define FNC_WALL 07 /* write timing */
215
/* define CSR_GO 0000001 */
216
#define CSR_RW 0117576 /* read/write */
218
#define CSR_GETUNIT(x) (((x) >> CSR_V_UNIT) & CSR_M_UNIT)
219
#define CSR_GETMEX(x) (((x) >> CSR_V_MEX) & CSR_M_MEX)
220
#define CSR_GETFNC(x) (((x) >> CSR_V_FNC) & CSR_M_FNC)
221
#define CSR_INCMEX(x) (((x) & ~CSR_MEX) | (((x) + (1 << CSR_V_MEX)) & CSR_MEX))
223
/* TCWC - 177344 - word count */
225
/* TCBA - 177346 - bus address */
227
/* TCDT - 177350 - data */
231
#define DTS_V_MOT 3 /* motion */
233
#define DTS_STOP 0 /* stopped */
234
#define DTS_DECF 2 /* decel, fwd */
235
#define DTS_DECR 3 /* decel, rev */
236
#define DTS_ACCF 4 /* accel, fwd */
237
#define DTS_ACCR 5 /* accel, rev */
238
#define DTS_ATSF 6 /* @speed, fwd */
239
#define DTS_ATSR 7 /* @speed, rev */
240
#define DTS_DIR 01 /* dir mask */
241
#define DTS_V_FNC 0 /* function */
243
#define DTS_OFR FNC_WMRK /* "off reel" */
244
#define DTS_GETMOT(x) (((x) >> DTS_V_MOT) & DTS_M_MOT)
245
#define DTS_GETFNC(x) (((x) >> DTS_V_FNC) & DTS_M_FNC)
246
#define DTS_V_2ND 6 /* next state */
247
#define DTS_V_3RD (DTS_V_2ND + DTS_V_2ND) /* next next */
248
#define DTS_STA(y,z) (((y) << DTS_V_MOT) | ((z) << DTS_V_FNC))
249
#define DTS_SETSTA(y,z) uptr->STATE = DTS_STA (y, z)
250
#define DTS_SET2ND(y,z) uptr->STATE = (uptr->STATE & 077) | \
251
((DTS_STA (y, z)) << DTS_V_2ND)
252
#define DTS_SET3RD(y,z) uptr->STATE = (uptr->STATE & 07777) | \
253
((DTS_STA (y, z)) << DTS_V_3RD)
254
#define DTS_NXTSTA(x) (x >> DTS_V_2ND)
262
#define DT_SETDONE tccm = tccm | CSR_DONE; \
263
if (tccm & CSR_IE) SET_INT (DTA)
264
#define DT_CLRDONE tccm = tccm & ~CSR_DONE; \
266
#define ABS(x) (((x) < 0)? (-(x)): (x))
268
extern uint16 *M; /* memory */
269
extern int32 int_req[IPL_HLVL];
270
extern int32 int_vec[IPL_HLVL][32];
271
extern UNIT cpu_unit;
272
extern int32 sim_switches;
273
extern FILE *sim_deb;
275
int32 tcst = 0; /* status */
276
int32 tccm = 0; /* command */
277
int32 tcwc = 0; /* word count */
278
int32 tcba = 0; /* bus address */
279
int32 tcdt = 0; /* data */
280
int32 dt_ctime = 100; /* fast cmd time */
281
int32 dt_ltime = 12; /* interline time */
282
int32 dt_dctime = 40000; /* decel time */
283
int32 dt_substate = 0;
285
int32 dt_stopoffr = 0;
288
t_stat dt_rd (int32 *data, int32 PA, int32 access);
289
t_stat dt_wr (int32 data, int32 PA, int32 access);
290
t_stat dt_svc (UNIT *uptr);
291
t_stat dt_svcdone (UNIT *uptr);
292
t_stat dt_reset (DEVICE *dptr);
293
t_stat dt_attach (UNIT *uptr, char *cptr);
294
t_stat dt_detach (UNIT *uptr);
295
t_stat dt_boot (int32 unitno, DEVICE *dptr);
296
void dt_deselect (int32 oldf);
297
void dt_newsa (int32 newf);
298
void dt_newfnc (UNIT *uptr, int32 newsta);
299
t_bool dt_setpos (UNIT *uptr);
300
void dt_schedez (UNIT *uptr, int32 dir);
301
void dt_seterr (UNIT *uptr, int32 e);
302
void dt_stopunit (UNIT *uptr);
303
int32 dt_comobv (int32 val);
304
int32 dt_csum (UNIT *uptr, int32 blk);
305
int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos);
306
extern int32 sim_is_running;
308
/* DT data structures
310
dt_dev DT device descriptor
312
dt_reg DT register list
313
dt_mod DT modifier list
316
DIB dt_dib = { IOBA_TC, IOLN_TC, &dt_rd, &dt_wr,
317
1, IVCL (DTA), VEC_DTA, { NULL } };
320
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
321
UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) },
322
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
323
UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) },
324
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
325
UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) },
326
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
327
UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) },
328
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
329
UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) },
330
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
331
UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) },
332
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
333
UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) },
334
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
335
UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) },
336
{ UDATA (&dt_svcdone, UNIT_DIS, 0) } };
338
#define DT_TIMER (DT_NUMDR)
341
{ ORDATA (TCST, tcst, 16) },
342
{ ORDATA (TCCM, tccm, 16) },
343
{ ORDATA (TCWC, tcwc, 16) },
344
{ ORDATA (TCBA, tcba, 16) },
345
{ ORDATA (TCDT, tcdt, 16) },
346
{ FLDATA (INT, IREQ (DTA), INT_V_DTA) },
347
{ FLDATA (ERR, tccm, CSR_V_ERR) },
348
{ FLDATA (DONE, tccm, CSR_V_DONE) },
349
{ FLDATA (IE, tccm, CSR_V_DONE) },
350
{ DRDATA (CTIME, dt_ctime, 31), REG_NZ },
351
{ DRDATA (LTIME, dt_ltime, 31), REG_NZ },
352
{ DRDATA (DCTIME, dt_dctime, 31), REG_NZ },
353
{ ORDATA (SUBSTATE, dt_substate, 1) },
354
{ DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN },
355
{ URDATA (POS, dt_unit[0].pos, 10, T_ADDR_W, 0,
356
DT_NUMDR, PV_LEFT | REG_RO) },
357
{ URDATA (STATT, dt_unit[0].STATE, 8, 18, 0,
359
{ URDATA (LASTT, dt_unit[0].LASTT, 10, 32, 0,
360
DT_NUMDR, REG_HRO) },
361
{ FLDATA (STOP_OFFR, dt_stopoffr, 0) },
362
{ ORDATA (DEVADDR, dt_dib.ba, 32), REG_HRO },
363
{ ORDATA (DEVVEC, dt_dib.vec, 16), REG_HRO },
367
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
368
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
369
{ UNIT_8FMT + UNIT_11FMT, 0, "18b", NULL, NULL },
370
{ UNIT_8FMT + UNIT_11FMT, UNIT_8FMT, "12b", NULL, NULL },
371
{ UNIT_8FMT + UNIT_11FMT, UNIT_11FMT, "16b", NULL, NULL },
372
{ MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",
373
&set_addr, &show_addr, NULL },
374
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
375
&set_vec, &show_vec, NULL },
379
{ "MOTION", LOG_MS },
385
"TC", dt_unit, dt_reg, dt_mod,
386
DT_NUMDR + 1, 8, 24, 1, 8, 18,
387
NULL, NULL, &dt_reset,
388
&dt_boot, &dt_attach, &dt_detach,
389
&dt_dib, DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG, 0,
390
dt_deb, NULL, NULL };
392
/* IO dispatch routines, I/O addresses 17777340 - 17777350 */
394
t_stat dt_rd (int32 *data, int32 PA, int32 access)
396
int32 j, unum, mot, fnc;
398
j = (PA >> 1) & 017; /* get reg offset */
399
unum = CSR_GETUNIT (tccm); /* get drive */
402
mot = DTS_GETMOT (dt_unit[unum].STATE); /* get motion */
403
if (mot >= DTS_ATSF) tcst = tcst | STA_UPS; /* set/clr speed */
404
else tcst = tcst & ~STA_UPS;
408
if (tcst & STA_ALLERR) tccm = tccm | CSR_ERR; /* set/clr error */
409
else tccm = tccm & ~CSR_ERR;
419
fnc = DTS_GETFNC (dt_unit[unum].STATE); /* get function */
420
if (fnc == FNC_RALL) { /* read all? */
421
DT_CLRDONE; } /* clear done */
427
t_stat dt_wr (int32 data, int32 PA, int32 access)
429
int32 i, j, unum, old_tccm, fnc;
432
j = (PA >> 1) & 017; /* get reg offset */
435
if ((access == WRITEB) && (PA & 1)) break;
436
tcst = (tcst & ~STA_RW) | (data & STA_RW);
439
old_tccm = tccm; /* save prior */
440
if (access == WRITEB) data = (PA & 1)?
441
(tccm & 0377) | (data << 8): (tccm & ~0377) | data;
442
if ((data & CSR_IE) == 0) CLR_INT (DTA);
443
else if ((((tccm & CSR_IE) == 0) && (tccm & CSR_DONE)) ||
444
(data & CSR_DONE)) SET_INT (DTA);
445
tccm = (tccm & ~CSR_RW) | (data & CSR_RW);
446
if ((data & CSR_GO) && (tccm & CSR_DONE)) { /* new cmd? */
447
tcst = tcst & ~STA_ALLERR; /* clear errors */
448
tccm = tccm & ~(CSR_ERR | CSR_DONE); /* clear done, err */
449
CLR_INT (DTA); /* clear int */
450
if ((old_tccm ^ tccm) & CSR_UNIT) dt_deselect (old_tccm);
451
unum = CSR_GETUNIT (tccm); /* get drive */
452
fnc = CSR_GETFNC (tccm); /* get function */
453
if (fnc == FNC_STOP) { /* stop all? */
454
sim_activate (&dt_dev.units[DT_TIMER], dt_ctime);
455
for (i = 0; i < DT_NUMDR; i++)
456
dt_stopunit (dt_dev.units + i); /* stop unit */
458
uptr = dt_dev.units + unum;
459
if (uptr->flags & UNIT_DIS) /* disabled? */
460
dt_seterr (uptr, STA_SEL); /* select err */
461
if ((fnc == FNC_WMRK) || /* write mark? */
462
((fnc == FNC_WALL) && (uptr->flags & UNIT_WPRT)) ||
463
((fnc == FNC_WRIT) && (uptr->flags & UNIT_WPRT)))
464
dt_seterr (uptr, STA_ILO); /* illegal op */
465
if (!(tccm & CSR_ERR)) dt_newsa (tccm); }
466
else if ((tccm & CSR_ERR) == 0) { /* clear err? */
467
tcst = tcst & ~STA_RWERR;
468
if (tcst & STA_ALLERR) tccm = tccm | CSR_ERR; }
471
tcwc = data; /* word write only! */
474
tcba = data; /* word write only! */
477
unum = CSR_GETUNIT (tccm); /* get drive */
478
fnc = DTS_GETFNC (dt_unit[unum].STATE); /* get function */
479
if (fnc == FNC_WALL) { /* write all? */
480
DT_CLRDONE; } /* clear done */
481
tcdt = data; /* word write only! */
488
void dt_deselect (int32 oldf)
490
int32 old_unit = CSR_GETUNIT (oldf);
491
UNIT *uptr = dt_dev.units + old_unit;
492
int32 old_mot = DTS_GETMOT (uptr->STATE);
494
if (old_mot >= DTS_ATSF) /* at speed? */
495
dt_newfnc (uptr, DTS_STA (old_mot, DTS_OFR));
496
else if (old_mot >= DTS_ACCF) /* accelerating? */
497
DTS_SET2ND (DTS_ATSF | (old_mot & DTS_DIR), DTS_OFR);
502
1. If function = stop
503
- if not already stopped or decelerating, schedule deceleration
504
- schedule command completion
505
2. If change in direction,
506
- if not decelerating, schedule deceleration
507
- set accelerating (other dir) as next state
508
- set function as next next state
509
3. If not accelerating or at speed,
510
- schedule acceleration
511
- set function as next state
512
4. If not yet at speed,
513
- set function as next state
515
- set function as current state, schedule function
518
void dt_newsa (int32 newf)
520
int32 new_unit, prev_mot, new_fnc;
521
int32 prev_dir, new_dir;
524
new_unit = CSR_GETUNIT (newf); /* new, old units */
525
uptr = dt_dev.units + new_unit;
526
if ((uptr->flags & UNIT_ATT) == 0) { /* new unit attached? */
527
dt_seterr (uptr, STA_SEL); /* no, error */
529
prev_mot = DTS_GETMOT (uptr->STATE); /* previous motion */
530
prev_dir = prev_mot & DTS_DIR; /* previous dir */
531
new_fnc = CSR_GETFNC (newf); /* new function */
532
new_dir = (newf & CSR_DIR) != 0; /* new di? */
534
if (new_fnc == FNC_SSEL) { /* stop unit? */
535
sim_activate (&dt_dev.units[DT_TIMER], dt_ctime); /* sched done */
536
dt_stopunit (uptr); /* stop unit */
539
if (prev_mot == DTS_STOP) { /* start? */
540
if (dt_setpos (uptr)) return; /* update pos */
541
sim_cancel (uptr); /* stop current */
542
sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* sched accel */
543
DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */
544
DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */
547
if (prev_dir ^ new_dir) { /* dir chg? */
548
dt_stopunit (uptr); /* stop unit */
549
DTS_SET2ND (DTS_ACCF | new_dir, 0); /* next = accel */
550
DTS_SET3RD (DTS_ATSF | new_dir, new_fnc); /* next next = fnc */
553
if (prev_mot < DTS_ACCF) { /* not accel/at speed? */
554
if (dt_setpos (uptr)) return; /* update pos */
555
sim_cancel (uptr); /* cancel cur */
556
sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* sched accel */
557
DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */
558
DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */
561
if (prev_mot < DTS_ATSF) { /* not at speed? */
562
DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */
565
dt_newfnc (uptr, DTS_STA (DTS_ATSF | new_dir, new_fnc));/* state = fnc */
569
/* Schedule new DECtape function
571
This routine is only called if
572
- the selected unit is attached
573
- the selected unit is at speed (forward or backward)
576
- updates the selected unit's position
577
- updates the selected unit's state
578
- schedules the new operation
581
void dt_newfnc (UNIT *uptr, int32 newsta)
583
int32 fnc, dir, blk, unum, relpos, newpos;
586
oldpos = uptr->pos; /* save old pos */
587
if (dt_setpos (uptr)) return; /* update pos */
588
uptr->STATE = newsta; /* update state */
589
fnc = DTS_GETFNC (uptr->STATE); /* set variables */
590
dir = DTS_GETMOT (uptr->STATE) & DTS_DIR;
591
unum = uptr - dt_dev.units;
592
if (oldpos == uptr->pos)
593
uptr->pos = uptr->pos + (dir? -1: 1);
594
blk = DT_LIN2BL (uptr->pos, uptr);
596
if (dir? DT_QREZ (uptr): DT_QFEZ (uptr)) { /* wrong ez? */
597
dt_seterr (uptr, STA_END); /* set ez flag, stop */
599
dt_substate = 0; /* substate = normal */
600
sim_cancel (uptr); /* cancel cur op */
601
switch (fnc) { /* case function */
602
case DTS_OFR: /* off reel */
603
if (dir) newpos = -1000; /* rev? < start */
604
else newpos = DTU_FWDEZ (uptr) + DT_EZLIN + 1000; /* fwd? > end */
606
case FNC_SRCH: /* search */
607
if (dir) newpos = DT_BLK2LN ((DT_QFEZ (uptr)?
608
DTU_TSIZE (uptr): blk), uptr) - DT_BLKLN - DT_WSIZE;
609
else newpos = DT_BLK2LN ((DT_QREZ (uptr)?
610
0: blk + 1), uptr) + DT_BLKLN + (DT_WSIZE - 1);
611
if (DEBUG_PRI (dt_dev, LOG_MS)) fprintf (sim_deb, ">>DT%d: searching %s\n",
612
unum, (dir? "backward": "forward"));
614
case FNC_WRIT: /* write */
615
case FNC_READ: /* read */
616
if (DT_QEZ (uptr)) { /* in "ok" end zone? */
617
if (dir) newpos = DTU_FWDEZ (uptr) - DT_HTLIN - DT_WSIZE;
618
else newpos = DT_EZLIN + DT_HTLIN + (DT_WSIZE - 1);
620
relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */
621
if ((relpos >= DT_HTLIN) && /* in data zone? */
622
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
623
dt_seterr (uptr, STA_BLKM);
625
if (dir) newpos = DT_BLK2LN (((relpos >= (DTU_LPERB (uptr) - DT_HTLIN))?
626
blk + 1: blk), uptr) - DT_HTLIN - DT_WSIZE;
627
else newpos = DT_BLK2LN (((relpos < DT_HTLIN)?
628
blk: blk + 1), uptr) + DT_HTLIN + (DT_WSIZE - 1);
629
if (DEBUG_PRI (dt_dev, LOG_RW) ||
630
(DEBUG_PRI (dt_dev, LOG_BL) && (blk == dt_logblk)))
631
fprintf (sim_deb, ">>DT%d: %s block %d %s\n",
632
unum, ((fnc == FNC_READ)? "read": "write"),
633
blk, (dir? "backward": "forward"));
635
case FNC_RALL: /* read all */
636
case FNC_WALL: /* write all */
637
if (DT_QEZ (uptr)) { /* in "ok" end zone? */
638
if (dir) newpos = DTU_FWDEZ (uptr) - DT_WSIZE;
639
else newpos = DT_EZLIN + (DT_WSIZE - 1); }
641
relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */
642
if (dir? (relpos < (DTU_LPERB (uptr) - DT_CSMLN)): /* switch in time? */
643
(relpos >= DT_CSMLN)) {
644
dt_seterr (uptr, STA_BLKM);
646
if (dir) newpos = DT_BLK2LN (blk + 1, uptr) - DT_CSMLN - DT_WSIZE;
647
else newpos = DT_BLK2LN (blk, uptr) + DT_CSMLN + (DT_WSIZE - 1); }
648
if (fnc == FNC_WALL) sim_activate /* write all? */
649
(&dt_dev.units[DT_TIMER], dt_ctime); /* sched done */
650
if (DEBUG_PRI (dt_dev, LOG_RW) ||
651
(DEBUG_PRI (dt_dev, LOG_BL) && (blk == dt_logblk)))
652
fprintf (sim_deb, ">>DT%d: read all block %d %s\n",
653
unum, blk, (dir? "backward": "forward"));
656
dt_seterr (uptr, STA_SEL); /* bad state */
658
sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime);
662
/* Update DECtape position
664
DECtape motion is modeled as a constant velocity, with linear
665
acceleration and deceleration. The motion equations are as follows:
667
t = time since operation started
668
tmax = time for operation (accel, decel only)
669
v = at speed velocity in lines (= 1/dt_ltime)
672
at speed dist = t * v
673
accel dist = (t^2 * v) / (2 * tmax)
674
decel dist = (((2 * t * tmax) - t^2) * v) / (2 * tmax)
676
This routine uses the relative (integer) time, rather than the absolute
677
(floating point) time, to allow save and restore of the start times.
680
t_bool dt_setpos (UNIT *uptr)
682
uint32 new_time, ut, ulin, udelt;
683
int32 mot = DTS_GETMOT (uptr->STATE);
686
new_time = sim_grtime (); /* current time */
687
ut = new_time - uptr->LASTT; /* elapsed time */
688
if (ut == 0) return FALSE; /* no time gone? exit */
689
uptr->LASTT = new_time; /* update last time */
690
switch (mot & ~DTS_DIR) { /* case on motion */
691
case DTS_STOP: /* stop */
694
case DTS_DECF: /* slowing */
695
ulin = ut / (uint32) dt_ltime;
696
udelt = dt_dctime / dt_ltime;
697
delta = ((ulin * udelt * 2) - (ulin * ulin)) / (2 * udelt);
699
case DTS_ACCF: /* accelerating */
700
ulin = ut / (uint32) dt_ltime;
701
udelt = (dt_dctime - (dt_dctime >> 2)) / dt_ltime;
702
delta = (ulin * ulin) / (2 * udelt);
704
case DTS_ATSF: /* at speed */
705
delta = ut / (uint32) dt_ltime;
707
if (mot & DTS_DIR) uptr->pos = uptr->pos - delta; /* update pos */
708
else uptr->pos = uptr->pos + delta;
709
if (((int32) uptr->pos < 0) ||
710
((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) {
711
detach_unit (uptr); /* off reel? */
712
uptr->STATE = uptr->pos = 0;
713
unum = uptr - dt_dev.units;
714
if ((unum == CSR_GETUNIT (tccm)) && (CSR_GETFNC (tccm) != FNC_STOP))
715
dt_seterr (uptr, STA_SEL); /* error */
720
/* Command timer service after stop - set done */
722
t_stat dt_svcdone (UNIT *uptr)
730
Unit must be attached, detach cancels operation
733
t_stat dt_svc (UNIT *uptr)
735
int32 mot = DTS_GETMOT (uptr->STATE);
736
int32 dir = mot & DTS_DIR;
737
int32 fnc = DTS_GETFNC (uptr->STATE);
738
int32 *fbuf = uptr->filebuf;
739
int32 blk, wrd, relpos, dat;
744
Decelerating - if next state != stopped, must be accel reverse
745
Accelerating - next state must be @speed, schedule function
746
At speed - do functional processing
750
case DTS_DECF: case DTS_DECR: /* decelerating */
751
if (dt_setpos (uptr)) /* upd pos; off reel? */
752
return IORETURN (dt_stopoffr, STOP_DTOFF);
753
uptr->STATE = DTS_NXTSTA (uptr->STATE); /* advance state */
754
if (uptr->STATE) /* not stopped? */
755
sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* reversing */
757
case DTS_ACCF: case DTS_ACCR: /* accelerating */
758
dt_newfnc (uptr, DTS_NXTSTA (uptr->STATE)); /* adv state, sched */
760
case DTS_ATSF: case DTS_ATSR: /* at speed */
761
break; /* check function */
763
dt_seterr (uptr, STA_SEL); /* state error */
768
Search - transfer block number, schedule next block
769
Off reel - detach unit (it must be deselected)
772
if (dt_setpos (uptr)) /* upd pos; off reel? */
773
return IORETURN (dt_stopoffr, STOP_DTOFF);
774
if (DT_QEZ (uptr)) { /* in end zone? */
775
dt_seterr (uptr, STA_END); /* end zone error */
777
blk = DT_LIN2BL (uptr->pos, uptr); /* get block # */
779
switch (fnc) { /* at speed, check fnc */
780
case FNC_SRCH: /* search */
781
tcdt = blk; /* set block # */
782
dt_schedez (uptr, dir); /* sched end zone */
783
DT_SETDONE; /* set done */
785
case DTS_OFR: /* off reel */
786
detach_unit (uptr); /* must be deselected */
787
uptr->STATE = uptr->pos = 0; /* no visible action */
792
If wc ovf has not occurred, inc ma, wc and copy word from tape to memory
794
If not end of block, schedule next word
795
If end of block and not wc ovf, schedule next block
796
If end of block and wc ovf, set done, schedule end zone
799
case FNC_READ: /* read */
800
wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */
801
if (!dt_substate) { /* !wc ovf? */
802
tcwc = tcwc & DMASK; /* incr MA, WC */
804
ma = (CSR_GETMEX (tccm) << 16) | tcba; /* form 18b addr */
805
if (!Map_Addr (ma, &mma) || /* map addr */
806
!ADDR_IS_MEM (mma)) { /* nx mem? */
807
dt_seterr (uptr, STA_NXM);
809
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
810
M[mma >> 1] = tcdt = fbuf[ba] & DMASK; /* read word */
811
tcwc = (tcwc + 1) & DMASK; /* incr MA, WC */
812
tcba = (tcba + 2) & DMASK;
813
if (tcba <= 1) tccm = CSR_INCMEX (tccm);
814
if (tcwc == 0) dt_substate = 1; }
815
if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1)) /* not end blk? */
816
sim_activate (uptr, DT_WSIZE * dt_ltime);
817
else if (dt_substate) { /* wc ovf? */
818
dt_schedez (uptr, dir); /* sched end zone */
819
DT_SETDONE; } /* set done */
820
else sim_activate (uptr, ((2 * DT_HTLIN) + DT_WSIZE) * dt_ltime);
825
If wc ovf has not occurred, inc ma, wc
826
Copy word from memory (or 0, to fill block) to tape
828
If not end of block, schedule next word
829
If end of block and not wc ovf, schedule next block
830
If end of block and wc ovf, set done, schedule end zone
833
case FNC_WRIT: /* write */
834
wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */
835
if (dt_substate) tcdt = 0; /* wc ovf? fill */
837
ma = (CSR_GETMEX (tccm) << 16) | tcba; /* form 18b addr */
838
if (!Map_Addr (ma, &mma) || /* map addr */
839
!ADDR_IS_MEM (mma)) { /* nx mem? */
840
dt_seterr (uptr, STA_NXM);
842
else tcdt = M[mma >> 1]; /* get word */
843
tcwc = (tcwc + 1) & DMASK; /* incr MA, WC */
844
tcba = (tcba + 2) & DMASK;
845
if (tcba <= 1) tccm = CSR_INCMEX (tccm); }
846
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
847
fbuf[ba] = tcdt; /* write word */
848
if (ba >= uptr->hwmark) uptr->hwmark = ba + 1;
849
if (tcwc == 0) dt_substate = 1;
850
if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1)) /* not end blk? */
851
sim_activate (uptr, DT_WSIZE * dt_ltime);
852
else if (dt_substate) { /* wc ovf? */
853
dt_schedez (uptr, dir); /* sched end zone */
855
else sim_activate (uptr, ((2 * DT_HTLIN) + DT_WSIZE) * dt_ltime);
858
/* Read all - read current header or data word */
861
if (tccm & CSR_DONE) { /* done set? */
862
dt_seterr (uptr, STA_DATM); /* data miss */
864
relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */
865
if ((relpos >= DT_HTLIN) && /* in data zone? */
866
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
867
wrd = DT_LIN2WD (uptr->pos, uptr);
868
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
869
dat = fbuf[ba]; } /* get tape word */
870
else dat = dt_gethdr (uptr, blk, relpos); /* get hdr */
871
if (dir) dat = dt_comobv (dat); /* rev? comp obv */
872
tcdt = dat & DMASK; /* low 16b */
873
tcst = (tcst & ~STA_M_XD) | ((dat >> 16) & STA_M_XD);
874
sim_activate (uptr, DT_WSIZE * dt_ltime);
875
DT_SETDONE; /* set done */
878
/* Write all - write current header or data word */
881
if (tccm & CSR_DONE) { /* done set? */
882
dt_seterr (uptr, STA_DATM); /* data miss */
884
relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */
885
if ((relpos >= DT_HTLIN) && /* in data zone? */
886
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
887
wrd = DT_LIN2WD (uptr->pos, uptr);
888
dat = (STA_GETXD (tcst) << 16) | tcdt; /* get data word */
889
if (dir) dat = dt_comobv (dat); /* rev? comp obv */
890
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
891
fbuf[ba] = dat; /* write word */
892
if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; }
893
/* else /* ignore hdr */
894
sim_activate (uptr, DT_WSIZE * dt_ltime);
895
DT_SETDONE; /* set done */
898
dt_seterr (uptr, STA_SEL); /* impossible state */
903
/* Utility routines */
907
void dt_seterr (UNIT *uptr, int32 e)
909
int32 mot = DTS_GETMOT (uptr->STATE);
911
tcst = tcst | e; /* set error flag */
912
tccm = tccm | CSR_ERR;
913
if (!(tccm & CSR_DONE)) { /* not done? */
915
if (mot >= DTS_ACCF) { /* ~stopped or stopping? */
916
sim_cancel (uptr); /* cancel activity */
917
if (dt_setpos (uptr)) return; /* update position */
918
sim_activate (uptr, dt_dctime); /* sched decel */
919
DTS_SETSTA (DTS_DECF | (mot & DTS_DIR), 0); } /* state = decel */
925
void dt_stopunit (UNIT *uptr)
927
int32 mot = DTS_GETMOT (uptr->STATE);
928
int32 dir = mot & DTS_DIR;
930
if (mot == DTS_STOP) return; /* already stopped? */
931
if ((mot & ~DTS_DIR) != DTS_DECF) { /* !already stopping? */
932
if (dt_setpos (uptr)) return; /* update pos */
933
sim_cancel (uptr); /* stop current */
934
sim_activate (uptr, dt_dctime); } /* schedule decel */
935
DTS_SETSTA (DTS_DECF | dir, 0); /* state = decel */
939
/* Schedule end zone */
941
void dt_schedez (UNIT *uptr, int32 dir)
945
if (dir) newpos = DT_EZLIN - DT_WSIZE; /* rev? rev ez */
946
else newpos = DTU_FWDEZ (uptr) + DT_WSIZE; /* fwd? fwd ez */
947
sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime);
951
/* Complement obverse routine (18b) */
953
int32 dt_comobv (int32 dat)
955
dat = dat ^ 0777777; /* compl obverse */
956
dat = ((dat >> 15) & 07) | ((dat >> 9) & 070) |
957
((dat >> 3) & 0700) | ((dat & 0700) << 3) |
958
((dat & 070) << 9) | ((dat & 07) << 15);
962
/* Checksum routine */
964
int32 dt_csum (UNIT *uptr, int32 blk)
966
int32 *fbuf = uptr->filebuf;
967
int32 ba = blk * DTU_BSIZE (uptr);
970
csum = 077; /* init csum */
971
for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */
972
wrd = fbuf[ba + i] ^ 0777777; /* get ~word */
973
csum = csum ^ (wrd >> 12) ^ (wrd >> 6) ^ wrd; }
977
/* Get header word (18b) */
979
int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos)
981
int32 wrd = relpos / DT_WSIZE;
983
if (wrd == DT_BLKWD) return blk; /* fwd blknum */
984
if (wrd == DT_CSMWD) return 077; /* rev csum */
985
if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */
986
return (dt_csum (uptr, blk) << 12);
987
if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_BLKWD - 1)) /* rev blkno */
988
return dt_comobv (blk);
989
return 0; /* all others */
994
t_stat dt_reset (DEVICE *dptr)
999
for (i = 0; i < DT_NUMDR; i++) { /* stop all activity */
1000
uptr = dt_dev.units + i;
1001
if (sim_is_running) { /* RESET? */
1002
prev_mot = DTS_GETMOT (uptr->STATE); /* get motion */
1003
if ((prev_mot & ~DTS_DIR) > DTS_DECF) { /* accel or spd? */
1004
if (dt_setpos (uptr)) continue; /* update pos */
1006
sim_activate (uptr, dt_dctime); /* sched decel */
1007
DTS_SETSTA (DTS_DECF | (prev_mot & DTS_DIR), 0);
1010
sim_cancel (uptr); /* sim reset */
1012
uptr->LASTT = sim_grtime (); } }
1013
tcst = tcwc = tcba = tcdt = 0; /* clear reg */
1015
CLR_INT (DTA); /* clear int req */
1019
/* Device bootstrap */
1021
#define BOOT_START 02000 /* start */
1022
#define BOOT_ENTRY (BOOT_START + 002) /* entry */
1023
#define BOOT_UNIT (BOOT_START + 010) /* unit number */
1024
#define BOOT_CSR (BOOT_START + 020) /* CSR */
1025
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
1027
static const uint16 boot_rom[] = {
1029
0012706, BOOT_START, /* MOV #boot_start, SP */
1030
0012700, 0000000, /* MOV #unit, R0 ; unit number */
1031
0010003, /* MOV R0, R3 */
1032
0000303, /* SWAB R3 */
1033
0012701, 0177342, /* MOV #TCCM, R1 ; csr */
1034
0012702, 0004003, /* RW: MOV #4003, R2 ; rev+rnum+go */
1035
0050302, /* BIS R3, R2 */
1036
0010211, /* MOV R2, (R1) ; load csr */
1037
0032711, 0100200, /* BIT #100200, (R1) ; wait */
1038
0001775, /* BEQ .-4 */
1039
0100370, /* BPL RW ; no err, cont */
1040
0005761, 0177776, /* TST -2(R1) ; end zone? */
1041
0100036, /* BPL ER ; no, err */
1042
0012702, 0000003, /* MOV #3, R2 ; rnum+go */
1043
0050302, /* BIS R3, R2 */
1044
0010211, /* MOV R2, (R1) ; load csr */
1045
0032711, 0100200, /* BIT #100200, (R1) ; wait */
1046
0001775, /* BEQ .-4 */
1047
0100426, /* BMI ER ; err, die */
1048
0005761, 0000006, /* TST 6(R1) ; blk 0? */
1049
0001023, /* BNE ER ; no, die */
1050
0012761, 0177000, 0000002, /* MOV #-256.*2, 2(R1) ; load wc */
1051
0005061, 0000004, /* CLR 4(R1) ; clear ba */
1052
0012702, 0000005, /* MOV #READ+GO, R2 ; read & go */
1053
0050302, /* BIS R3, R2 */
1054
0010211, /* MOV R2, (R1) ; load csr */
1055
0005002, /* CLR R2 */
1056
0005003, /* CLR R3 */
1057
0012704, BOOT_START+020, /* MOV #START+20, R4 */
1058
0005005, /* CLR R5 */
1059
0032711, 0100200, /* BIT #100200, (R1) ; wait */
1060
0001775, /* BEQ .-4 */
1061
0100401, /* BMI ER ; err, die */
1062
0005007, /* CLR PC */
1063
0012711, 0000001, /* ER: MOV #1, (R1) ; stop all */
1067
t_stat dt_boot (int32 unitno, DEVICE *dptr)
1070
extern int32 saved_PC;
1072
dt_unit[unitno].pos = DT_EZLIN;
1073
for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i];
1074
M[BOOT_UNIT >> 1] = unitno & DT_M_NUMDR;
1075
M[BOOT_CSR >> 1] = (dt_dib.ba & DMASK) + 02;
1076
saved_PC = BOOT_ENTRY;
1082
Determine 12b, 16b, or 18b/36b format
1084
If 12b, read 12b format and convert to 18b in buffer
1085
If 16b, read 16b format and convert to 18b in buffer
1086
If 18b/36b, read data into buffer
1089
t_stat dt_attach (UNIT *uptr, char *cptr)
1091
uint16 pdp8b[D8_NBSIZE];
1092
uint16 pdp11b[D18_BSIZE];
1093
uint32 ba, sz, k, *fbuf;
1094
int32 u = uptr - dt_dev.units;
1097
r = attach_unit (uptr, cptr); /* attach */
1098
if (r != SCPE_OK) return r; /* fail? */
1099
if ((sim_switches & SIM_SW_REST) == 0) { /* not from rest? */
1100
uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT; /* default 16b */
1101
if (sim_switches & SWMASK ('R')) /* att 12b? */
1102
uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT;
1103
else if (sim_switches & SWMASK ('T')) /* att 18b? */
1104
uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT);
1105
else if (!(sim_switches & SWMASK ('S')) && /* autosize? */
1106
((sz = sim_fsize (uptr->fileref)) > D16_FILSIZ)) {
1107
if (sz <= D8_FILSIZ)
1108
uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT;
1109
else uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); } }
1110
uptr->capac = DTU_CAPAC (uptr); /* set capacity */
1111
uptr->filebuf = calloc (uptr->capac, sizeof (int32));
1112
if (uptr->filebuf == NULL) { /* can't alloc? */
1115
fbuf = uptr->filebuf; /* file buffer */
1116
printf ("%s%d: ", sim_dname (&dt_dev), u);
1117
if (uptr->flags & UNIT_8FMT) printf ("12b format");
1118
else if (uptr->flags & UNIT_11FMT) printf ("16b format");
1119
else printf ("18b/36b format");
1120
printf (", buffering file in memory\n");
1121
if (uptr->flags & UNIT_8FMT) { /* 12b? */
1122
for (ba = 0; ba < uptr->capac; ) { /* loop thru file */
1123
k = fxread (pdp8b, sizeof (int16), D8_NBSIZE, uptr->fileref);
1125
for ( ; k < D8_NBSIZE; k++) pdp8b[k] = 0;
1126
for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop thru blk */
1127
fbuf[ba] = ((uint32) (pdp8b[k] & 07777) << 6) |
1128
((uint32) (pdp8b[k + 1] >> 6) & 077);
1129
fbuf[ba + 1] = ((pdp8b[k + 1] & 077) << 12) |
1130
((uint32) (pdp8b[k + 2] & 07777));
1131
ba = ba + 2; } /* end blk loop */
1132
} /* end file loop */
1133
uptr->hwmark = ba; } /* end if */
1134
else if (uptr->flags & UNIT_11FMT) { /* 16b? */
1135
for (ba = 0; ba < uptr->capac; ) { /* loop thru file */
1136
k = fxread (pdp11b, sizeof (int16), D18_BSIZE, uptr->fileref);
1138
for ( ; k < D18_BSIZE; k++) pdp11b[k] = 0;
1139
for (k = 0; k < D18_BSIZE; k++)
1140
fbuf[ba++] = pdp11b[k]; }
1141
uptr->hwmark = ba; } /* end elif */
1142
else uptr->hwmark = fxread (uptr->filebuf, sizeof (int32),
1143
uptr->capac, uptr->fileref);
1144
uptr->flags = uptr->flags | UNIT_BUF; /* set buf flag */
1145
uptr->pos = DT_EZLIN; /* beyond leader */
1146
uptr->LASTT = sim_grtime (); /* last pos update */
1152
Cancel in progress operation
1153
If 12b, convert 18b buffer to 12b and write to file
1154
If 16b, convert 18b buffer to 16b and write to file
1155
If 18b/36b, write buffer to file
1159
t_stat dt_detach (UNIT* uptr)
1161
uint16 pdp8b[D8_NBSIZE];
1162
uint16 pdp11b[D18_BSIZE];
1163
uint32 ba, k, *fbuf;
1164
int32 u = uptr - dt_dev.units;
1166
if (!(uptr->flags & UNIT_ATT)) return SCPE_OK;
1167
if (sim_is_active (uptr)) { /* active? cancel op */
1169
if ((u == CSR_GETUNIT (tccm)) && ((tccm & CSR_DONE) == 0)) {
1170
tcst = tcst | STA_SEL;
1171
tccm = tccm | CSR_ERR | CSR_DONE;
1172
if (tccm & CSR_IE) SET_INT (DTA); }
1173
uptr->STATE = uptr->pos = 0; }
1174
fbuf = uptr->filebuf; /* file buffer */
1175
if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */
1176
printf ("%s%d: writing buffer to file\n", sim_dname (&dt_dev), u);
1177
rewind (uptr->fileref); /* start of file */
1178
if (uptr->flags & UNIT_8FMT) { /* 12b? */
1179
for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */
1180
for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop blk */
1181
pdp8b[k] = (fbuf[ba] >> 6) & 07777;
1182
pdp8b[k + 1] = ((fbuf[ba] & 077) << 6) |
1183
((fbuf[ba + 1] >> 12) & 077);
1184
pdp8b[k + 2] = fbuf[ba + 1] & 07777;
1185
ba = ba + 2; } /* end loop blk */
1186
fxwrite (pdp8b, sizeof (int16), D8_NBSIZE, uptr->fileref);
1187
if (ferror (uptr->fileref)) break; } /* end loop file */
1189
else if (uptr->flags & UNIT_11FMT) { /* 16b? */
1190
for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */
1191
for (k = 0; k < D18_BSIZE; k++) /* loop blk */
1192
pdp11b[k] = fbuf[ba++] & DMASK;
1193
fxwrite (pdp11b, sizeof (int16), D18_BSIZE, uptr->fileref);
1194
if (ferror (uptr->fileref)) break; } /* end loop file */
1196
else fxwrite (uptr->filebuf, sizeof (int32), /* write file */
1197
uptr->hwmark, uptr->fileref);
1198
if (ferror (uptr->fileref)) perror ("I/O error"); } /* end if hwmark */
1199
free (uptr->filebuf); /* release buf */
1200
uptr->flags = uptr->flags & ~UNIT_BUF; /* clear buf flag */
1201
uptr->filebuf = NULL; /* clear buf ptr */
1202
uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT; /* default fmt */
1203
uptr->capac = DT_CAPAC; /* default size */
1204
return detach_unit (uptr);