1 /* sds_drm.c: SDS 940 Project Genie drum simulator
2 
3    Copyright (c) 2002-2008, Robert M. Supnik
4 
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 
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.
25 
26    drm          drum
27 
28    The drum is buffered in memory.
29 
30    Note: the Project Genie documentation and the actual monitor sources disagree
31    on the I/O instruction definitions for the drum.  The simulator follows the
32    monitor sources, as follows:
33 
34    DCC    OP      00230404B       RESET DRUM CHANNEL
35    DSC    OP      00230204B       START DRUM CHANNEL (NO CHAIN)
36    DRA    OP      00230504B       READ DRUM TIMING COUNTER INTO 21B
37    DSR    OP      04030204B       SKIP IF DRUM NOT BUSY
38    DSE    OP      04037404B       SKIP IF NO DRUM ERROR
39 */
40 
41 #include "sds_defs.h"
42 #include <math.h>
43 
44 /* Constants */
45 
46 #define DRM_N_WD        11                              /* word addr width */
47 #define DRM_V_WD        0                               /* position */
48 #define DRM_M_WD        ((1 << DRM_N_WD) - 1)           /* word mask */
49 #define DRM_NUMWD       (1 << DRM_N_WD)                 /* words/sector */
50 #define DRM_NUMGP       236                             /* gap/sector */
51 #define DRM_PHYWD       (DRM_NUMWD + DRM_NUMGP)         /* phys wds/sector */
52 #define DRM_N_SC        3                               /* sect addr width */
53 #define DRM_V_SC        (DRM_N_WD)                      /* position */
54 #define DRM_M_SC        ((1 << DRM_N_SC) - 1)           /* sector mask */
55 #define DRM_NUMSC       (1 << DRM_N_SC)                 /* sectors/track */
56 #define DRM_N_TR        7                               /* track addr width */
57 #define DRM_V_TR        (DRM_N_WD+DRM_N_SC)             /* position */
58 #define DRM_M_TR        ((1 << DRM_N_TR) - 1)           /* track mask */
59 #define DRM_NUMTR       84                              /* tracks/drum */
60 #define DRM_N_ADDR      (DRM_N_WD+DRM_N_SC+DRM_N_TR)    /* drum addr width */
61 #define DRM_SWMASK      ((1 << (DRM_N_WD+DRM_N_SC)) - 1)/* sector+word mask */
62 #define DRM_DAMASK      ((1 << DRM_N_ADDR) - 1)         /* drum addr mask */
63 #define DRM_SIZE        (DRM_NUMTR*DRM_NUMSC*DRM_NUMWD) /* words/disk */
64 #define DRM_WCMASK      037777                          /* wc mask */
65 #define DRM_GETSC(x)    (((x) >> DRM_V_SC) & DRM_M_SC)
66 
67 #define DRM_PC          020
68 #define DRM_AD          021
69 #define DRM_ADAT        (1 << (DRM_N_WD + DRM_N_SC))    /* data flag */
70 
71 #define DRM_SFET        0                               /* fetch state */
72 #define DRM_SFCA        1                               /* fetch CA */
73 #define DRM_SFDA        2                               /* fetch DA */
74 #define DRM_SXFR        3                               /* xfer */
75 
76 #define DRM_V_OP        21                              /* drum op */
77 #define DRM_M_OP        07
78 #define DRM_V_RW        20
79 #define DRM_GETOP(x)    (((x) >> DRM_V_OP) & DRM_M_OP)
80 #define DRM_GETRW(x)    (((x) >> DRM_V_RW) & 1)
81 #define  DRM_OXF        0                               /* xfer */
82 #define  DRM_OCX        1                               /* cond xfer */
83 #define  DRM_OBR        2                               /* branch */
84 #define  DRM_ORS        3                               /* reset error */
85 #define  DRM_END        4                               /* end prog */
86 #define  DRM_EIE        5                               /* end int if err */
87 #define  DRM_EIU        7                               /* end int uncond */
88 
89 #define GET_TWORD(x)    ((int32) fmod (sim_gtime() / ((double) (x)), \
90                         ((double) (DRM_NUMSC * DRM_PHYWD))))
91 
92 extern uint32 M[];                                      /* memory */
93 extern uint32 alert, int_req;
94 extern int32 stop_invins, stop_invdev, stop_inviop;
95 uint32 drm_da = 0;                                      /* disk address */
96 uint32 drm_ca = 0;                                      /* core address */
97 uint32 drm_wc = 0;                                      /* word count */
98 int32 drm_par = 0;                                      /* cumulative par */
99 int32 drm_err = 0;                                      /* error */
100 int32 drm_rw = 0;                                       /* read/write */
101 int32 drm_sta = 0;                                      /* drum state */
102 int32 drm_ftime = 3;                                    /* time to fetch */
103 int32 drm_xtime = 1;                                    /* time to xfr */
104 int32 drm_stopioe = 1;                                  /* stop on error */
105 
106 DEVICE drm_dev;
107 t_stat drm (uint32 fnc, uint32 inst, uint32 *dat);
108 t_stat drm_svc (UNIT *uptr);
109 t_stat drm_reset (DEVICE *dptr);
110 
111 /* DRM data structures
112 
113    drm_dev      device descriptor
114    drm_unit     unit descriptor
115    drm_reg      register list
116 */
117 
118 DIB drm_dib = { -1, DEV3_GDRM, 0, NULL, &drm };
119 
120 UNIT drm_unit = {
121     UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
122            DRM_SIZE)
123     };
124 
125 REG drm_reg[] = {
126     { ORDATA (DA, drm_da, DRM_N_ADDR) },
127     { ORDATA (CA, drm_ca, 16) },
128     { ORDATA (WC, drm_wc, 14) },
129     { ORDATA (PAR, drm_par, 12) },
130     { FLDATA (RW, drm_rw, 0) },
131     { FLDATA (ERR, drm_err, 0) },
132     { ORDATA (STA, drm_sta, 2) },
133     { DRDATA (FTIME, drm_ftime, 24), REG_NZ + PV_LEFT },
134     { DRDATA (XTIME, drm_xtime, 24), REG_NZ + PV_LEFT },
135     { FLDATA (STOP_IOE, drm_stopioe, 0) },
136     { NULL }
137     };
138 
139 DEVICE drm_dev = {
140     "DRM", &drm_unit, drm_reg, NULL,
141     1, 8, DRM_N_ADDR, 1, 8, 24,
142     NULL, NULL, &drm_reset,
143     NULL, NULL, NULL,
144     &drm_dib, DEV_DISABLE | DEV_DIS
145     };
146 
147 /* Drum routine -  EOM/SKS 3xx04 */
148 
drm(uint32 fnc,uint32 inst,uint32 * dat)149 t_stat drm (uint32 fnc, uint32 inst, uint32 *dat)
150 {
151 int32 t, op = inst & 07700;
152 
153 switch (fnc) {
154 
155     case IO_CONN:                                       /* connect */
156         if (op == 00400)                                /* EOM 404 = reset */
157             return drm_reset (&drm_dev);
158         if (op == 00500) {                              /* EOM 504 = read DA */
159             if (sim_is_active (&drm_unit))
160                 return SCPE_OK; /* must be idle */
161             t = GET_TWORD (drm_xtime);                  /* get position */
162             if (t < DRM_NUMGP)                          /* in gap? */
163                 M[DRM_AD] = DRM_NUMWD - t;
164             else M[DRM_AD] = (t - DRM_NUMGP) | DRM_ADAT;/* in data */
165             }
166         else if (op == 00200) {                         /* EOM 204 = start */
167             if (sim_is_active (&drm_unit))              /* must be idle */
168                 return SCPE_OK;
169             drm_sta = DRM_SFET;                         /* state = fetch */
170             sim_activate (&drm_unit, drm_ftime);        /* activate */
171             }
172         else CRETINS;
173         break;
174 
175     case IO_SKS:                                        /* SKS */
176         if (((op == 07400) && !drm_err) ||              /* 37404: no err */
177             ((op == 00200) && !sim_is_active (&drm_unit))) /* 30204: idle */
178             *dat = 1;
179         break;
180 
181     default:
182         return SCPE_IERR;
183         }
184 
185 return SCPE_OK;
186 }
187 
188 /* Unit service */
189 
drm_svc(UNIT * uptr)190 t_stat drm_svc (UNIT *uptr)
191 {
192 int32 t, rda;
193 uint32 dpc, dwd;
194 uint32 *fbuf = uptr->filebuf;
195 
196 if (drm_sta != DRM_SXFR) {                              /* fetch drum prog? */
197     dpc = M[DRM_PC];                                    /* get drum PC */
198     dwd = M[dpc & PAMASK];                              /* get drum inst */
199     M[DRM_PC] = (dpc + 1) & PAMASK;                     /* update drum PC */
200     if (drm_sta == DRM_SFCA) {                          /* fetch core addr? */
201         drm_rw = DRM_GETRW (dwd);                       /* set op */
202         drm_ca = dwd & PAMASK;                          /* set core addr */
203         drm_sta = DRM_SFDA;                             /* next is disk addr */
204         }
205     else if (drm_sta == DRM_SFDA) {                     /* fetch disk addr? */
206         drm_da = dwd & DRM_DAMASK;                      /* set disk addr */
207         drm_sta = DRM_SXFR;                             /* next is xfer */
208         drm_par = 0;                                    /* init parity */
209         rda = (drm_da & DRM_SWMASK) + (DRM_GETSC (drm_da) * DRM_NUMGP);
210         t = rda - GET_TWORD (drm_xtime);                /* difference */
211         if (t <= 0)                                     /* add trk lnt */
212             t = t + (DRM_NUMSC * DRM_PHYWD);
213         sim_activate (&drm_unit, t * drm_xtime);        /* activate */
214         }
215     else {
216         switch (DRM_GETOP (dwd)) {
217 
218         case DRM_OCX:                                   /* cond xfr */
219             if (drm_err) {                              /* error? */
220                 int_req = int_req | INT_DRM;            /* req int */
221                 return SCPE_OK;                         /* done */
222                 }
223         case DRM_OXF:                                   /* transfer */
224             drm_wc = dwd & DRM_WCMASK;                  /* save wc */
225             drm_sta = DRM_SFCA;                         /* next state */
226             break;
227 
228         case DRM_OBR:                                   /* branch */
229             M[DRM_PC] = dwd & PAMASK;                   /* new drum PC */
230             break;
231 
232         case DRM_END:                                   /* end */
233             return SCPE_OK;
234 
235         case DRM_EIE:                                   /* end, int if err */
236             if (!drm_err)
237                 return SCPE_OK;
238 
239         case DRM_EIU:                                   /* end, int uncond */
240             int_req = int_req | INT_DRM;
241             return SCPE_OK;
242             }                                           /* end switch */
243         }                                               /* end else sta */
244     sim_activate (uptr, drm_ftime);                     /* fetch next word */
245     }                                                   /* end if !xfr */
246 else {                                                  /* transfer word */
247     if ((uptr->flags & UNIT_BUF) == 0) {                /* not buffered? */
248         drm_err = 1;                                    /* error */
249         CRETIOE (drm_stopioe, SCPE_UNATT);
250         }
251     if (drm_rw) {                                       /* write? */
252         dwd = M[drm_ca];                                /* get mem word */
253         fbuf[drm_da] = dwd;                             /* write to drum */
254         if (drm_da >= uptr->hwmark)
255             uptr->hwmark = drm_da + 1;
256         }
257     else {                                              /* read */
258         dwd = fbuf[drm_da];                             /* get drum word */
259         M[drm_ca] = dwd;                                /* write to mem */
260         }
261     drm_da = drm_da + 1;                                /* inc drum addr */
262     if (drm_da >= DRM_SIZE)                             /* wrap */
263         drm_da = 0;
264     drm_ca = (drm_ca + 1) & PAMASK;                     /* inc core addr */
265     drm_wc = (drm_wc - 1) & DRM_WCMASK;                 /* dec word cnt */
266     drm_par = drm_par ^ (dwd >> 12);                    /* parity */
267     drm_par = ((drm_par << 1) | (drm_par >> 11)) & 07777;
268     drm_par = drm_par ^ (dwd & 07777);
269     if (drm_wc) {                                       /* more to do */
270         if (drm_da & DRM_M_WD)
271             sim_activate (uptr, drm_xtime);
272         else sim_activate (uptr, drm_xtime * DRM_NUMGP);
273         }
274     else {                                              /* end xfr */
275 #if defined (DRM_PAR)
276         if ((drm_da & DRM_M_WD) && drm_rw) {            /* wr end mid sector? */
277             M[drm_da] = drm_par << 12;                  /* clobber data */
278             if (drm_da >= uptr->hwmark)
279                 uptr->hwmark = drm_da + 1;
280             }
281 #endif
282         drm_sta = DRM_SFET;                             /* back to fetch */
283         sim_activate (uptr, drm_ftime);                 /* schedule */
284         }                                               /* end else end xfr */
285     }                                                   /* end else xfr */
286 return SCPE_OK;
287 }
288 
289 /* Reset routine */
290 
drm_reset(DEVICE * dptr)291 t_stat drm_reset (DEVICE *dptr)
292 {
293 drm_da = 0;                                             /* clear state */
294 drm_ca = 0;
295 drm_wc = 0;
296 drm_par = 0;
297 drm_sta = 0;
298 drm_err = 0;
299 drm_rw = 0;
300 int_req = int_req & ~INT_DRM;                           /* clear intr */
301 sim_cancel (&drm_unit);                                 /* deactivate */
302 return SCPE_OK;
303 }
304