1 /* i7094_drm.c: 7289/7320A drum simulator
3 Copyright (c) 2005-2006, 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 be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
26 drm 7289/7320A "fast" drum
28 Very little is known about this device; the behavior simulated here is
31 - The drum channel/controller behaves like a hybrid of the 7607 and the 7909.
32 It responds to SCD (like the 7909), gets its address from the channel
33 program (like the 7909), but responds to IOCD/IOCP (like the 7607) and
34 sets channel flags (like the 7607).
35 - The drum channel supports at least 2 drums. The maximum is 8 or less.
36 Physical drums are numbered from 0.
37 - Each drum has a capacity of 192K 36b words. This is divided into 6
38 "logical" drum of 32KW each. Each "logical" drum has 16 2048W "sectors".
39 Logical drums are numbered from 1.
40 - The drum's behavior if a sector boundary is crossed in mid-transfer is
41 unknown. CTSS never does this.
42 - The drum's behavior with record operations is unknown. CTSS only uses
44 - The drum's error indicators are unknown. CTSS regards bits <0:2,13> of
45 the returned SCD data as errors, as well as the normal 7607 trap flags.
46 - The drum's rotational speed is unknown.
48 Assumptions in this simulator:
50 - Transfers may not cross a sector boundary. An attempt to do so sets
51 the EOF flag and causes an immediate disconnect.
52 - The hardware never sets end of record.
54 For speed, the entire drum is buffered in memory.
57 #include "i7094_defs.h"
60 #define DRM_NUMDR 8 /* drums/controller */
64 #define DRM_NUMWDS 2048 /* words/sector */
65 #define DRM_SCMASK (DRM_NUMWDS - 1) /* sector mask */
66 #define DRM_NUMSC 16 /* sectors/log drum */
67 #define DRM_NUMWDL (DRM_NUMWDS * DRM_NUMSC) /* words/log drum */
68 #define DRM_NUMLD 6 /* log drums/phys drum */
69 #define DRM_SIZE (DRM_NUMLD * DRM_NUMWDL) /* words/phys drum */
70 #define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
71 ((double) DRM_NUMWDS)))
73 /* Drum address from channel */
75 #define DRM_V_PHY 30 /* physical drum sel */
77 #define DRM_V_LOG 18 /* logical drum sel */
79 #define DRM_V_WDA 0 /* word address */
80 #define DRM_M_WDA (DRM_NUMWDL - 1)
81 #define DRM_GETPHY(x) (((uint32) ((x) >> DRM_V_PHY)) & DRM_M_PHY)
82 #define DRM_GETLOG(x) ((((uint32) (x)) >> DRM_V_LOG) & DRM_M_LOG)
83 #define DRM_GETWDA(x) ((((uint32) (x)) >> DRM_V_WDA) & DRM_M_WDA)
84 #define DRM_GETDA(x) (((DRM_GETLOG(x) - 1) * DRM_NUMWDL) + DRM_GETWDA(x))
86 /* Drum controller states */
93 uint32 drm_ch
= CH_G
; /* drum channel */
94 uint32 drm_da
= 0; /* drum address */
95 uint32 drm_sta
= 0; /* state */
96 uint32 drm_op
= 0; /* operation */
97 t_uint64 drm_chob
= 0; /* output buf */
98 uint32 drm_chob_v
= 0; /* valid */
99 int32 drm_time
= 10; /* inter-word time */
101 extern uint32 ind_ioc
;
103 t_stat
drm_svc (UNIT
*uptr
);
104 t_stat
drm_reset (DEVICE
*dptr
);
105 t_stat
drm_chsel (uint32 ch
, uint32 sel
, uint32 unit
);
106 t_stat
drm_chwr (uint32 ch
, t_uint64 val
, uint32 flags
);
107 t_bool
drm_da_incr (void);
109 /* DRM data structures
111 drm_dev DRM device descriptor
112 drm_unit DRM unit descriptor
113 drm_reg DRM register list
116 DIB drm_dib
= { &drm_chsel
, &drm_chwr
};
119 { UDATA (&drm_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_BUFABLE
+
120 UNIT_MUSTBUF
+UNIT_DISABLE
, DRM_SIZE
) },
121 { UDATA (&drm_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_BUFABLE
+
122 UNIT_MUSTBUF
+UNIT_DISABLE
, DRM_SIZE
) },
123 { UDATA (&drm_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_BUFABLE
+
124 UNIT_MUSTBUF
+UNIT_DISABLE
+UNIT_DIS
, DRM_SIZE
) },
125 { UDATA (&drm_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_BUFABLE
+
126 UNIT_MUSTBUF
+UNIT_DISABLE
+UNIT_DIS
, DRM_SIZE
) },
127 { UDATA (&drm_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_BUFABLE
+
128 UNIT_MUSTBUF
+UNIT_DISABLE
+UNIT_DIS
, DRM_SIZE
) },
129 { UDATA (&drm_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_BUFABLE
+
130 UNIT_MUSTBUF
+UNIT_DISABLE
+UNIT_DIS
, DRM_SIZE
) },
131 { UDATA (&drm_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_BUFABLE
+
132 UNIT_MUSTBUF
+UNIT_DISABLE
+UNIT_DIS
, DRM_SIZE
) },
133 { UDATA (&drm_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_BUFABLE
+
134 UNIT_MUSTBUF
+UNIT_DISABLE
+UNIT_DIS
, DRM_SIZE
) }
138 { ORDATA (STATE
, drm_sta
, 2) },
139 { ORDATA (DA
, drm_da
, 18) },
140 { FLDATA (OP
, drm_op
, 0) },
141 { ORDATA (CHOB
, drm_chob
, 36) },
142 { FLDATA (CHOBV
, drm_chob_v
, 0) },
143 { DRDATA (TIME
, drm_time
, 24), REG_NZ
+ PV_LEFT
},
144 { DRDATA (CHAN
, drm_ch
, 3), REG_HRO
},
149 { MTAB_XTD
|MTAB_VDV
, 0, "CHANNEL", NULL
, NULL
, &ch_show_chan
},
154 "DRM", drm_unit
, drm_reg
, drm_mtab
,
155 DRM_NUMDR
, 8, 18, 1, 8, 36,
156 NULL
, NULL
, &drm_reset
,
161 /* Channel select routine */
163 t_stat
drm_chsel (uint32 ch
, uint32 sel
, uint32 unit
)
165 drm_ch
= ch
; /* save channel */
166 if (sel
& CHSL_NDS
) return ch6_end_nds (ch
); /* nds? nop */
168 switch (sel
) { /* case on cmd */
170 case CHSL_RDS
: /* read */
171 case CHSL_WRS
: /* write */
172 if (drm_sta
!= DRM_IDLE
) return ERR_STALL
; /* busy? */
173 drm_sta
= DRM_1ST
; /* initial state */
174 if (sel
== CHSL_WRS
) drm_op
= 1; /* set read/write */
175 else drm_op
= 0; /* LCHx sends addr */
176 break; /* wait for addr */
184 /* Channel write routine */
186 t_stat
drm_chwr (uint32 ch
, t_uint64 val
, uint32 flags
)
191 if (drm_sta
== DRM_1ST
) {
192 u
= DRM_GETPHY (val
); /* get unit */
193 l
= DRM_GETLOG (val
); /* get logical address */
194 if ((u
>= DRM_NUMDR
) || /* invalid unit? */
195 (drm_unit
[u
].flags
& UNIT_DIS
) || /* disabled unit? */
196 (l
== 0) || (l
> DRM_NUMLD
)) { /* invalid log drum? */
197 ch6_err_disc (ch
, U_DRM
, CHF_TRC
); /* disconnect */
201 drm_da
= DRM_GETDA (val
); /* get drum addr */
202 cp
= GET_POS (drm_time
); /* current pos in sec */
203 dp
= (drm_da
& DRM_SCMASK
) - cp
; /* delta to desired pos */
204 if (dp
<= 0) dp
= dp
+ DRM_NUMWDS
; /* if neg, add rev */
205 sim_activate (&drm_unit
[u
], dp
* drm_time
); /* schedule */
206 if (drm_op
) ch6_req_wr (ch
, U_DRM
); /* if write, get word */
208 drm_chob
= 0; /* clr, inval buffer */
212 drm_chob
= val
& DMASK
;
218 /* Unit service - this code assumes the entire drum is buffered */
220 t_stat
drm_svc (UNIT
*uptr
)
222 t_uint64
*fbuf
= (t_uint64
*) uptr
->filebuf
;
224 if ((uptr
->flags
& UNIT_BUF
) == 0) { /* not buf? */
225 ch6_err_disc (drm_ch
, U_DRM
, CHF_TRC
); /* set TRC, disc */
226 drm_sta
= DRM_IDLE
; /* drum is idle */
229 if (drm_da
>= DRM_SIZE
) { /* nx logical drum? */
230 ch6_err_disc (drm_ch
, U_DRM
, CHF_EOF
); /* set EOF, disc */
231 drm_sta
= DRM_IDLE
; /* drum is idle */
235 switch (drm_sta
) { /* case on state */
237 case DRM_DATA
: /* data */
238 if (drm_op
) { /* write? */
239 if (drm_chob_v
) drm_chob_v
= 0; /* valid? clear */
240 else if (ch6_qconn (drm_ch
, U_DRM
)) /* no, chan conn? */
241 ind_ioc
= 1; /* io check */
242 fbuf
[drm_da
] = drm_chob
; /* get data */
243 if (drm_da
>= uptr
->hwmark
) uptr
->hwmark
= drm_da
+ 1;
244 if (!drm_da_incr ()) ch6_req_wr (drm_ch
, U_DRM
);
247 ch6_req_rd (drm_ch
, U_DRM
, fbuf
[drm_da
], 0); /* send word to channel */
250 sim_activate (uptr
, drm_time
); /* next word */
253 case DRM_EOS
: /* end sector */
254 if (ch6_qconn (drm_ch
, U_DRM
)) /* drum still conn? */
255 ch6_err_disc (drm_ch
, U_DRM
, CHF_EOF
); /* set EOF, disc */
256 drm_sta
= DRM_IDLE
; /* drum is idle */
263 /* Increment drum address - return true, set new state if end of sector */
265 t_bool
drm_da_incr (void)
268 if (drm_da
& DRM_SCMASK
) return FALSE
;
275 t_stat
drm_reset (DEVICE
*dptr
)
284 for (i
= 0; i
< dptr
->numunits
; i
++) sim_cancel (dptr
->units
+ i
);