First Commit of my working state
[simh.git] / I7094 / i7094_drm.c
CommitLineData
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
93uint32 drm_ch = CH_G; /* drum channel */\r
94uint32 drm_da = 0; /* drum address */\r
95uint32 drm_sta = 0; /* state */\r
96uint32 drm_op = 0; /* operation */\r
97t_uint64 drm_chob = 0; /* output buf */\r
98uint32 drm_chob_v = 0; /* valid */\r
99int32 drm_time = 10; /* inter-word time */\r
100\r
101extern uint32 ind_ioc;\r
102\r
103t_stat drm_svc (UNIT *uptr);\r
104t_stat drm_reset (DEVICE *dptr);\r
105t_stat drm_chsel (uint32 ch, uint32 sel, uint32 unit);\r
106t_stat drm_chwr (uint32 ch, t_uint64 val, uint32 flags);\r
107t_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
116DIB drm_dib = { &drm_chsel, &drm_chwr };\r
117\r
118UNIT 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
137REG 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
148MTAB drm_mtab[] = {\r
149 { MTAB_XTD|MTAB_VDV, 0, "CHANNEL", NULL, NULL, &ch_show_chan },\r
150 { 0 }\r
151 };\r
152\r
153DEVICE 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
163t_stat drm_chsel (uint32 ch, uint32 sel, uint32 unit)\r
164{\r
165drm_ch = ch; /* save channel */\r
166if (sel & CHSL_NDS) return ch6_end_nds (ch); /* nds? nop */\r
167\r
168switch (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
181return SCPE_OK;\r
182}\r
183\r
184/* Channel write routine */\r
185\r
186t_stat drm_chwr (uint32 ch, t_uint64 val, uint32 flags)\r
187{\r
188uint32 u, l;\r
189int32 cp, dp;\r
190\r
191if (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
211else {\r
212 drm_chob = val & DMASK;\r
213 drm_chob_v = 1;\r
214 }\r
215return SCPE_OK;\r
216}\r
217\r
218/* Unit service - this code assumes the entire drum is buffered */\r
219\r
220t_stat drm_svc (UNIT *uptr)\r
221{\r
222t_uint64 *fbuf = (t_uint64 *) uptr->filebuf;\r
223\r
224if ((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
229if (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
235switch (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
260return SCPE_OK;\r
261}\r
262\r
263/* Increment drum address - return true, set new state if end of sector */\r
264\r
265t_bool drm_da_incr (void)\r
266{\r
267drm_da = drm_da + 1;\r
268if (drm_da & DRM_SCMASK) return FALSE;\r
269drm_sta = DRM_EOS;\r
270return TRUE;\r
271}\r
272\r
273/* Reset routine */\r
274\r
275t_stat drm_reset (DEVICE *dptr)\r
276{\r
277uint32 i;\r
278\r
279drm_da = 0;\r
280drm_op = 0;\r
281drm_sta = DRM_IDLE;\r
282drm_chob = 0;\r
283drm_chob_v = 0;\r
284for (i = 0; i < dptr->numunits; i++) sim_cancel (dptr->units + i);\r
285return SCPE_OK;\r
286}\r