First Commit of my working state
[simh.git] / PDP11 / pdp11_ke.c
1 /* pdp11_ke.c: PDP-11/20 extended arithmetic element
2
3 Copyright (c) 1993-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 ke_ACTION OF CONTRke_ACT, 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 This code draws on prior work by Tim Shoppa and Brad Parker. My thanks for
27 to them for letting me use their work.
28
29 EAE PDP-11/20 extended arithmetic element
30 */
31
32 #include "pdp11_defs.h"
33
34 #define GET_SIGN_L(v) (((v) >> 31) & 1)
35 #define GET_SIGN_W(v) (((v) >> 15) & 1)
36 #define GET_SIGN_B(v) (((v) >> 7) & 1)
37
38 /* KE11A I/O address offsets 0177300 - 0177316 */
39
40 #define KE_DIV 000 /* divide */
41 #define KE_AC 002 /* accumulator */
42 #define KE_MQ 004 /* MQ */
43 #define KE_MUL 006 /* multiply */
44 #define KE_SC 010 /* step counter */
45 #define KE_NOR 012 /* normalize */
46 #define KE_LSH 014 /* logical shift */
47 #define KE_ASH 016 /* arithmetic shift */
48
49 /* Status register */
50
51 #define KE_SR_C 0001 /* carry */
52 #define KE_SR_SXT 0002 /* AC<15:0> = MQ<15> */
53 #define KE_SR_Z 0004 /* AC = MQ = 0 */
54 #define KE_SR_MQZ 0010 /* MQ = 0 */
55 #define KE_SR_ACZ 0020 /* AC = 0 */
56 #define KE_SR_ACM1 0040 /* AC = 177777 */
57 #define KE_SR_N 0100 /* last op negative */
58 #define KE_SR_NXV 0200 /* last op ovf XOR N */
59 #define KE_SR_DYN (KE_SR_SXT|KE_SR_Z|KE_SR_MQZ|KE_SR_ACZ|KE_SR_ACM1)
60
61 /* Visible state */
62
63 uint32 ke_AC = 0;
64 uint32 ke_MQ = 0;
65 uint32 ke_SC = 0;
66 uint32 ke_SR = 0;
67
68 DEVICE ke_dev;
69 t_stat ke_rd (int32 *data, int32 PA, int32 access);
70 t_stat ke_wr (int32 data, int32 PA, int32 access);
71 t_stat ke_reset (DEVICE *dptr);
72 uint32 ke_set_SR (void);
73
74 DIB ke_dib = { IOBA_KE, IOLN_KE, &ke_rd, &ke_wr, 0 };
75
76 UNIT ke_unit = {
77 UDATA (NULL, UNIT_DISABLE, 0)
78 };
79
80 REG ke_reg[] = {
81 { ORDATA (AC, ke_AC, 16) },
82 { ORDATA (MQ, ke_MQ, 16) },
83 { ORDATA (SC, ke_SC, 6) },
84 { ORDATA (SR, ke_SR, 8) },
85 { NULL }
86 };
87
88 MTAB ke_mod[] = {
89 { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL,
90 NULL, &show_addr, NULL },
91 { 0 }
92 };
93
94 DEVICE ke_dev = {
95 "KE", &ke_unit, ke_reg, ke_mod,
96 1, 10, 31, 1, 8, 8,
97 NULL, NULL, &ke_reset,
98 NULL, NULL, NULL,
99 &ke_dib, DEV_DISABLE | DEV_DIS | DEV_UBUS
100 };
101
102 /* KE read - reads are always 16b, to even addresses */
103
104 t_stat ke_rd (int32 *data, int32 PA, int32 access)
105 {
106 switch (PA & 016) { /* decode PA<3:1> */
107
108 case KE_AC: /* AC */
109 *data = ke_AC;
110 break;
111
112 case KE_MQ: /* MQ */
113 *data = ke_MQ;
114 break;
115
116 case KE_NOR: /* norm (SC) */
117 *data = ke_SC;
118 break;
119
120 case KE_SC: /* SR/SC */
121 *data = (ke_set_SR () << 8) | ke_SC;
122 break;
123
124 default:
125 *data = 0;
126 break;
127 }
128
129 return SCPE_OK;
130 }
131
132 /* KE write - writes trigger actual arithmetic */
133
134 t_stat ke_wr (int32 data, int32 PA, int32 access)
135 {
136 int32 quo, t32, sout, sign;
137 uint32 absd, absr;
138
139 switch (PA & 017) { /* decode PA<3:0> */
140
141 case KE_DIV: /* divide */
142 if ((access == WRITEB) && GET_SIGN_B (data)) /* byte write? */
143 data |= 0177400; /* sext data to 16b */
144 ke_SR = 0; /* N = V = C = 0 */
145 t32 = (ke_AC << 16) | ke_MQ; /* 32b divd */
146 if (GET_SIGN_W (ke_AC)) /* sext (divd) */
147 t32 = t32 | ~017777777777;
148 if (GET_SIGN_W (data)) /* sext (divr) */
149 data = data | ~077777;
150 absd = abs (t32);
151 absr = abs (data);
152 if ((absd >> 16) >= absr) { /* divide fails? */
153
154 /* Based on the documentation, here's what has happened:
155
156 SC = 16.
157 SR<c> = (AC<15> == data<15>)
158 AC'MQ = (AC'MQ << 1) | SR<c>
159 AC = SR<c>? AC - data: AC + data
160 SR<c> = (AC<15> == data<15>)
161 SC = SC - 1
162 stop
163 */
164
165 sign = GET_SIGN_W (ke_AC ^ data) ^ 1; /* 1 if signs match */
166 ke_AC = (ke_AC << 1) | (ke_MQ >> 15);
167 ke_AC = (sign? ke_AC - data: ke_AC + data) & DMASK;
168 ke_MQ = ((ke_MQ << 1) | sign) & DMASK;
169 if (GET_SIGN_W (ke_AC ^ data) == 0) /* 0 if signs match */
170 ke_SR |= KE_SR_C;
171 ke_SC = 15; /* SC clocked once */
172 ke_SR |= KE_SR_NXV; /* set overflow */
173 }
174 else {
175 ke_SC = 0;
176 quo = t32 / data;
177 ke_MQ = quo & DMASK; /* MQ has quo */
178 ke_AC = (t32 % data) & DMASK; /* AC has rem */
179 if ((quo > 32767) || (quo < -32768)) /* quo overflow? */
180 ke_SR |= KE_SR_NXV; /* set overflow */
181 }
182 if (GET_SIGN_W (ke_MQ)) /* result negative? */
183 ke_SR ^= (KE_SR_N | KE_SR_NXV); /* N = 1, compl NXV */
184 break;
185
186 case KE_AC: /* AC */
187 if ((access == WRITEB) && GET_SIGN_B (data)) /* byte write? */
188 data |= 0177400; /* sext data to 16b */
189 ke_AC = data;
190 break;
191
192 case KE_AC + 1: /* AC odd byte */
193 ke_AC = (ke_AC & 0377) | (data << 8);
194 break;
195
196 case KE_MQ: /* MQ */
197 if ((access == WRITEB) && GET_SIGN_B (data)) /* byte write? */
198 data |= 0177400; /* sext data to 16b */
199 ke_MQ = data;
200 if (GET_SIGN_W (ke_MQ)) /* sext MQ to AC */
201 ke_AC = 0177777;
202 else ke_AC = 0;
203 break;
204
205 case KE_MQ + 1: /* MQ odd byte */
206 ke_MQ = (ke_MQ & 0377) | (data << 8);
207 if (GET_SIGN_W (ke_MQ)) /* sext MQ to AC */
208 ke_AC = 0177777;
209 else ke_AC = 0;
210 break;
211
212 case KE_MUL: /* multiply */
213 if ((access == WRITEB) && GET_SIGN_B (data)) /* byte write? */
214 data |= 0177400; /* sext data to 16b */
215 ke_SC = 0;
216 if (GET_SIGN_W (data)) /* sext operands */
217 data |= ~077777;
218 t32 = ke_MQ;
219 if (GET_SIGN_W (t32))
220 t32 |= ~077777;
221 t32 = t32 * data;
222 ke_AC = (t32 >> 16) & DMASK;
223 ke_MQ = t32 & DMASK;
224 if (GET_SIGN_W (ke_AC)) /* result negative? */
225 ke_SR = KE_SR_N | KE_SR_NXV; /* N = 1, V = C = 0 */
226 else ke_SR = 0; /* N = 0, V = C = 0 */
227 break;
228
229 case KE_SC: /* SC */
230 if (access == WRITEB) /* ignore byte writes */
231 return SCPE_OK;
232 ke_SR = (data >> 8) & (KE_SR_NXV|KE_SR_N|KE_SR_C);
233 ke_SC = data & 077;
234 break;
235
236 case KE_NOR: /* normalize */
237 for (ke_SC = 0; ke_SC < 31; ke_SC++) { /* max 31 shifts */
238 if (((ke_AC == 0140000) && (ke_MQ == 0)) || /* special case? */
239 (GET_SIGN_W (ke_AC ^ (ke_AC << 1)))) /* AC<15> != AC<14>? */
240 break;
241 ke_AC = ((ke_AC << 1) | (ke_MQ >> 15)) & DMASK;
242 ke_MQ = (ke_MQ << 1) & DMASK;
243 }
244 if (GET_SIGN_W (ke_AC)) /* result negative? */
245 ke_SR = KE_SR_N | KE_SR_NXV; /* N = 1, V = C = 0 */
246 else ke_SR = 0; /* N = 0, V = C = 0 */
247 break;
248
249 case KE_LSH: /* logical shift */
250 ke_SC = 0;
251 ke_SR = 0; /* N = V = C = 0 */
252 data = data & 077; /* 6b shift count */
253 if (data != 0) {
254 t32 = (ke_AC << 16) | ke_MQ; /* 32b operand */
255 if (sign = GET_SIGN_W (ke_AC)) /* sext operand */
256 t32 = t32 | ~017777777777;
257 if (data < 32) { /* [1,31] - left */
258 sout = (t32 >> (32 - data)) | (-sign << data);
259 t32 = ((uint32) t32) << data; /* do shift (zext) */
260 if (sout != (GET_SIGN_L (t32)? -1: 0)) /* bits lost = sext? */
261 ke_SR |= KE_SR_NXV; /* no, V = 1 */
262 if (sout & 1) /* last bit lost = 1? */
263 ke_SR |= KE_SR_C; /* yes, C = 1 */
264 }
265 else { /* [32,63] = -32,-1 */
266 if ((t32 >> (63 - data)) & 1) /* last bit lost = 1? */
267 ke_SR |= KE_SR_C; /* yes, C = 1*/
268 t32 = (data != 32)? ((uint32) t32) >> (64 - data): 0;
269 }
270 ke_AC = (t32 >> 16) & DMASK;
271 ke_MQ = t32 & DMASK;
272 }
273 if (GET_SIGN_W (ke_AC)) /* result negative? */
274 ke_SR ^= (KE_SR_N | KE_SR_NXV); /* N = 1, compl NXV */
275 break;
276
277 /* EAE ASH differs from EIS ASH and cannot use the same overflow test */
278
279 case KE_ASH: /* arithmetic shift */
280 ke_SC = 0;
281 ke_SR = 0; /* N = V = C = 0 */
282 data = data & 077; /* 6b shift count */
283 if (data != 0) {
284 t32 = (ke_AC << 16) | ke_MQ; /* 32b operand */
285 if (sign = GET_SIGN_W (ke_AC)) /* sext operand */
286 t32 = t32 | ~017777777777;
287 if (data < 32) { /* [1,31] - left */
288 sout = (t32 >> (31 - data)) | (-sign << data);
289 t32 = (t32 & 020000000000) | ((t32 << data) & 017777777777);
290 if (sout != (GET_SIGN_L (t32)? -1: 0)) /* bits lost = sext? */
291 ke_SR |= KE_SR_NXV; /* no, V = 1 */
292 if (sout & 1) /* last bit lost = 1? */
293 ke_SR |= KE_SR_C; /* yes, C = 1 */
294 }
295 else { /* [32,63] = -32,-1 */
296 if ((t32 >> (63 - data)) & 1) /* last bit lost = 1? */
297 ke_SR |= KE_SR_C; /* yes, C = 1 */
298 t32 = (data != 32)? /* special case 32 */
299 (((uint32) t32) >> (64 - data)) | (-sign << (data - 32)):
300 -sign;
301 }
302 ke_AC = (t32 >> 16) & DMASK;
303 ke_MQ = t32 & DMASK;
304 }
305 if (GET_SIGN_W (ke_AC)) /* result negative? */
306 ke_SR ^= (KE_SR_N | KE_SR_NXV); /* N = 1, compl NXV */
307 break;
308
309 default: /* all others ignored */
310 return SCPE_OK;
311 } /* end switch PA */
312
313 ke_set_SR ();
314 return SCPE_OK;
315 }
316
317 /* Update status register based on current AC, MQ */
318
319 uint32 ke_set_SR (void)
320 {
321 ke_SR &= ~KE_SR_DYN; /* clr dynamic bits */
322 if (ke_MQ == 0) /* MQ == 0? */
323 ke_SR |= KE_SR_MQZ;
324 if (ke_AC == 0) { /* AC == 0? */
325 ke_SR |= KE_SR_ACZ;
326 if (GET_SIGN_W (ke_MQ) == 0) /* MQ positive? */
327 ke_SR |= KE_SR_SXT;
328 if (ke_MQ == 0) /* MQ zero? */
329 ke_SR |= KE_SR_Z;
330 }
331 if (ke_AC == 0177777) { /* AC == 177777? */
332 ke_SR |= KE_SR_ACM1;
333 if (GET_SIGN_W (ke_MQ) == 1) /* MQ negative? */
334 ke_SR |= KE_SR_SXT;
335 }
336 return ke_SR;
337 }
338
339 /* Reset routine */
340
341 t_stat ke_reset (DEVICE *dptr)
342 {
343 ke_SR = 0;
344 ke_SC = 0;
345 ke_AC = 0;
346 ke_MQ = 0;
347 return SCPE_OK;
348 }