Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* i7094_drm.c: 7289/7320A drum simulator\r |
2 | \r | |
3 | Copyright (c) 2005-2006, Robert M Supnik\r | |
4 | \r | |
5 | Permission is hereby granted, free of charge, to any person obtaining a\r | |
6 | copy of this software and associated documentation files (the "Software"),\r | |
7 | to deal in the Software without restriction, including without limitation\r | |
8 | the rights to use, copy, modify, merge, publish, distribute, sublicense,\r | |
9 | and/or sell copies of the Software, and to permit persons to whom the\r | |
10 | Software is furnished to do so, subject to the following conditions:\r | |
11 | \r | |
12 | The above copyright notice and this permission notice shall be included in\r | |
13 | all copies or substantial portions of the Software.\r | |
14 | \r | |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r | |
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r | |
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r | |
18 | ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r | |
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r | |
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r | |
21 | \r | |
22 | Except as contained in this notice, the name of Robert M Supnik shall not be\r | |
23 | used in advertising or otherwise to promote the sale, use or other dealings\r | |
24 | in this Software without prior written authorization from Robert M Supnik.\r | |
25 | \r | |
26 | drm 7289/7320A "fast" drum\r | |
27 | \r | |
28 | Very little is known about this device; the behavior simulated here is\r | |
29 | what is used by CTSS.\r | |
30 | \r | |
31 | - The drum channel/controller behaves like a hybrid of the 7607 and the 7909.\r | |
32 | It responds to SCD (like the 7909), gets its address from the channel\r | |
33 | program (like the 7909), but responds to IOCD/IOCP (like the 7607) and\r | |
34 | sets channel flags (like the 7607).\r | |
35 | - The drum channel supports at least 2 drums. The maximum is 8 or less.\r | |
36 | Physical drums are numbered from 0.\r | |
37 | - Each drum has a capacity of 192K 36b words. This is divided into 6\r | |
38 | "logical" drum of 32KW each. Each "logical" drum has 16 2048W "sectors".\r | |
39 | Logical drums are numbered from 1.\r | |
40 | - The drum's behavior if a sector boundary is crossed in mid-transfer is\r | |
41 | unknown. CTSS never does this.\r | |
42 | - The drum's behavior with record operations is unknown. CTSS only uses\r | |
43 | IOCD and IOCP.\r | |
44 | - The drum's error indicators are unknown. CTSS regards bits <0:2,13> of\r | |
45 | the returned SCD data as errors, as well as the normal 7607 trap flags.\r | |
46 | - The drum's rotational speed is unknown.\r | |
47 | \r | |
48 | Assumptions in this simulator:\r | |
49 | \r | |
50 | - Transfers may not cross a sector boundary. An attempt to do so sets\r | |
51 | the EOF flag and causes an immediate disconnect.\r | |
52 | - The hardware never sets end of record.\r | |
53 | \r | |
54 | For speed, the entire drum is buffered in memory.\r | |
55 | */\r | |
56 | \r | |
57 | #include "i7094_defs.h"\r | |
58 | #include <math.h>\r | |
59 | \r | |
60 | #define DRM_NUMDR 8 /* drums/controller */\r | |
61 | \r | |
62 | /* Drum geometry */\r | |
63 | \r | |
64 | #define DRM_NUMWDS 2048 /* words/sector */\r | |
65 | #define DRM_SCMASK (DRM_NUMWDS - 1) /* sector mask */\r | |
66 | #define DRM_NUMSC 16 /* sectors/log drum */\r | |
67 | #define DRM_NUMWDL (DRM_NUMWDS * DRM_NUMSC) /* words/log drum */\r | |
68 | #define DRM_NUMLD 6 /* log drums/phys drum */\r | |
69 | #define DRM_SIZE (DRM_NUMLD * DRM_NUMWDL) /* words/phys drum */\r | |
70 | #define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \\r | |
71 | ((double) DRM_NUMWDS)))\r | |
72 | \r | |
73 | /* Drum address from channel */\r | |
74 | \r | |
75 | #define DRM_V_PHY 30 /* physical drum sel */\r | |
76 | #define DRM_M_PHY 07\r | |
77 | #define DRM_V_LOG 18 /* logical drum sel */\r | |
78 | #define DRM_M_LOG 07\r | |
79 | #define DRM_V_WDA 0 /* word address */\r | |
80 | #define DRM_M_WDA (DRM_NUMWDL - 1)\r | |
81 | #define DRM_GETPHY(x) (((uint32) ((x) >> DRM_V_PHY)) & DRM_M_PHY)\r | |
82 | #define DRM_GETLOG(x) ((((uint32) (x)) >> DRM_V_LOG) & DRM_M_LOG)\r | |
83 | #define DRM_GETWDA(x) ((((uint32) (x)) >> DRM_V_WDA) & DRM_M_WDA)\r | |
84 | #define DRM_GETDA(x) (((DRM_GETLOG(x) - 1) * DRM_NUMWDL) + DRM_GETWDA(x))\r | |
85 | \r | |
86 | /* Drum controller states */\r | |
87 | \r | |
88 | #define DRM_IDLE 0\r | |
89 | #define DRM_1ST 1\r | |
90 | #define DRM_DATA 2\r | |
91 | #define DRM_EOS 3\r | |
92 | \r | |
93 | uint32 drm_ch = CH_G; /* drum channel */\r | |
94 | uint32 drm_da = 0; /* drum address */\r | |
95 | uint32 drm_sta = 0; /* state */\r | |
96 | uint32 drm_op = 0; /* operation */\r | |
97 | t_uint64 drm_chob = 0; /* output buf */\r | |
98 | uint32 drm_chob_v = 0; /* valid */\r | |
99 | int32 drm_time = 10; /* inter-word time */\r | |
100 | \r | |
101 | extern uint32 ind_ioc;\r | |
102 | \r | |
103 | t_stat drm_svc (UNIT *uptr);\r | |
104 | t_stat drm_reset (DEVICE *dptr);\r | |
105 | t_stat drm_chsel (uint32 ch, uint32 sel, uint32 unit);\r | |
106 | t_stat drm_chwr (uint32 ch, t_uint64 val, uint32 flags);\r | |
107 | t_bool drm_da_incr (void);\r | |
108 | \r | |
109 | /* DRM data structures\r | |
110 | \r | |
111 | drm_dev DRM device descriptor\r | |
112 | drm_unit DRM unit descriptor\r | |
113 | drm_reg DRM register list\r | |
114 | */\r | |
115 | \r | |
116 | DIB drm_dib = { &drm_chsel, &drm_chwr };\r | |
117 | \r | |
118 | UNIT drm_unit[] = {\r | |
119 | { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+\r | |
120 | UNIT_MUSTBUF+UNIT_DISABLE, DRM_SIZE) },\r | |
121 | { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+\r | |
122 | UNIT_MUSTBUF+UNIT_DISABLE, DRM_SIZE) },\r | |
123 | { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+\r | |
124 | UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) },\r | |
125 | { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+\r | |
126 | UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) },\r | |
127 | { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+\r | |
128 | UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) },\r | |
129 | { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+\r | |
130 | UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) },\r | |
131 | { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+\r | |
132 | UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) },\r | |
133 | { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+\r | |
134 | UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) }\r | |
135 | };\r | |
136 | \r | |
137 | REG drm_reg[] = {\r | |
138 | { ORDATA (STATE, drm_sta, 2) },\r | |
139 | { ORDATA (DA, drm_da, 18) },\r | |
140 | { FLDATA (OP, drm_op, 0) },\r | |
141 | { ORDATA (CHOB, drm_chob, 36) },\r | |
142 | { FLDATA (CHOBV, drm_chob_v, 0) },\r | |
143 | { DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT },\r | |
144 | { DRDATA (CHAN, drm_ch, 3), REG_HRO },\r | |
145 | { NULL }\r | |
146 | };\r | |
147 | \r | |
148 | MTAB drm_mtab[] = {\r | |
149 | { MTAB_XTD|MTAB_VDV, 0, "CHANNEL", NULL, NULL, &ch_show_chan },\r | |
150 | { 0 }\r | |
151 | };\r | |
152 | \r | |
153 | DEVICE drm_dev = {\r | |
154 | "DRM", drm_unit, drm_reg, drm_mtab,\r | |
155 | DRM_NUMDR, 8, 18, 1, 8, 36,\r | |
156 | NULL, NULL, &drm_reset,\r | |
157 | NULL, NULL, NULL,\r | |
158 | &drm_dib, DEV_DIS\r | |
159 | };\r | |
160 | \r | |
161 | /* Channel select routine */\r | |
162 | \r | |
163 | t_stat drm_chsel (uint32 ch, uint32 sel, uint32 unit)\r | |
164 | {\r | |
165 | drm_ch = ch; /* save channel */\r | |
166 | if (sel & CHSL_NDS) return ch6_end_nds (ch); /* nds? nop */\r | |
167 | \r | |
168 | switch (sel) { /* case on cmd */\r | |
169 | \r | |
170 | case CHSL_RDS: /* read */\r | |
171 | case CHSL_WRS: /* write */\r | |
172 | if (drm_sta != DRM_IDLE) return ERR_STALL; /* busy? */\r | |
173 | drm_sta = DRM_1ST; /* initial state */\r | |
174 | if (sel == CHSL_WRS) drm_op = 1; /* set read/write */\r | |
175 | else drm_op = 0; /* LCHx sends addr */\r | |
176 | break; /* wait for addr */\r | |
177 | \r | |
178 | default: /* other */\r | |
179 | return STOP_ILLIOP;\r | |
180 | }\r | |
181 | return SCPE_OK;\r | |
182 | }\r | |
183 | \r | |
184 | /* Channel write routine */\r | |
185 | \r | |
186 | t_stat drm_chwr (uint32 ch, t_uint64 val, uint32 flags)\r | |
187 | {\r | |
188 | uint32 u, l;\r | |
189 | int32 cp, dp;\r | |
190 | \r | |
191 | if (drm_sta == DRM_1ST) {\r | |
192 | u = DRM_GETPHY (val); /* get unit */\r | |
193 | l = DRM_GETLOG (val); /* get logical address */\r | |
194 | if ((u >= DRM_NUMDR) || /* invalid unit? */\r | |
195 | (drm_unit[u].flags & UNIT_DIS) || /* disabled unit? */\r | |
196 | (l == 0) || (l > DRM_NUMLD)) { /* invalid log drum? */\r | |
197 | ch6_err_disc (ch, U_DRM, CHF_TRC); /* disconnect */\r | |
198 | drm_sta = DRM_IDLE;\r | |
199 | return SCPE_OK;\r | |
200 | }\r | |
201 | drm_da = DRM_GETDA (val); /* get drum addr */\r | |
202 | cp = GET_POS (drm_time); /* current pos in sec */\r | |
203 | dp = (drm_da & DRM_SCMASK) - cp; /* delta to desired pos */\r | |
204 | if (dp <= 0) dp = dp + DRM_NUMWDS; /* if neg, add rev */\r | |
205 | sim_activate (&drm_unit[u], dp * drm_time); /* schedule */\r | |
206 | if (drm_op) ch6_req_wr (ch, U_DRM); /* if write, get word */\r | |
207 | drm_sta = DRM_DATA;\r | |
208 | drm_chob = 0; /* clr, inval buffer */\r | |
209 | drm_chob_v = 0;\r | |
210 | }\r | |
211 | else {\r | |
212 | drm_chob = val & DMASK;\r | |
213 | drm_chob_v = 1;\r | |
214 | }\r | |
215 | return SCPE_OK;\r | |
216 | }\r | |
217 | \r | |
218 | /* Unit service - this code assumes the entire drum is buffered */\r | |
219 | \r | |
220 | t_stat drm_svc (UNIT *uptr)\r | |
221 | {\r | |
222 | t_uint64 *fbuf = (t_uint64 *) uptr->filebuf;\r | |
223 | \r | |
224 | if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? */\r | |
225 | ch6_err_disc (drm_ch, U_DRM, CHF_TRC); /* set TRC, disc */\r | |
226 | drm_sta = DRM_IDLE; /* drum is idle */\r | |
227 | return SCPE_UNATT;\r | |
228 | }\r | |
229 | if (drm_da >= DRM_SIZE) { /* nx logical drum? */\r | |
230 | ch6_err_disc (drm_ch, U_DRM, CHF_EOF); /* set EOF, disc */\r | |
231 | drm_sta = DRM_IDLE; /* drum is idle */\r | |
232 | return SCPE_OK;\r | |
233 | }\r | |
234 | \r | |
235 | switch (drm_sta) { /* case on state */\r | |
236 | \r | |
237 | case DRM_DATA: /* data */\r | |
238 | if (drm_op) { /* write? */\r | |
239 | if (drm_chob_v) drm_chob_v = 0; /* valid? clear */\r | |
240 | else if (ch6_qconn (drm_ch, U_DRM)) /* no, chan conn? */\r | |
241 | ind_ioc = 1; /* io check */\r | |
242 | fbuf[drm_da] = drm_chob; /* get data */\r | |
243 | if (drm_da >= uptr->hwmark) uptr->hwmark = drm_da + 1;\r | |
244 | if (!drm_da_incr ()) ch6_req_wr (drm_ch, U_DRM);\r | |
245 | }\r | |
246 | else{ /* read */\r | |
247 | ch6_req_rd (drm_ch, U_DRM, fbuf[drm_da], 0); /* send word to channel */\r | |
248 | drm_da_incr ();\r | |
249 | }\r | |
250 | sim_activate (uptr, drm_time); /* next word */\r | |
251 | break;\r | |
252 | \r | |
253 | case DRM_EOS: /* end sector */\r | |
254 | if (ch6_qconn (drm_ch, U_DRM)) /* drum still conn? */\r | |
255 | ch6_err_disc (drm_ch, U_DRM, CHF_EOF); /* set EOF, disc */\r | |
256 | drm_sta = DRM_IDLE; /* drum is idle */\r | |
257 | break;\r | |
258 | } /* end case */\r | |
259 | \r | |
260 | return SCPE_OK;\r | |
261 | }\r | |
262 | \r | |
263 | /* Increment drum address - return true, set new state if end of sector */\r | |
264 | \r | |
265 | t_bool drm_da_incr (void)\r | |
266 | {\r | |
267 | drm_da = drm_da + 1;\r | |
268 | if (drm_da & DRM_SCMASK) return FALSE;\r | |
269 | drm_sta = DRM_EOS;\r | |
270 | return TRUE;\r | |
271 | }\r | |
272 | \r | |
273 | /* Reset routine */\r | |
274 | \r | |
275 | t_stat drm_reset (DEVICE *dptr)\r | |
276 | {\r | |
277 | uint32 i;\r | |
278 | \r | |
279 | drm_da = 0;\r | |
280 | drm_op = 0;\r | |
281 | drm_sta = DRM_IDLE;\r | |
282 | drm_chob = 0;\r | |
283 | drm_chob_v = 0;\r | |
284 | for (i = 0; i < dptr->numunits; i++) sim_cancel (dptr->units + i);\r | |
285 | return SCPE_OK;\r | |
286 | }\r |