Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* pdp8_fpp.c: PDP-8 floating point processor (FPP8A)\r |
2 | \r | |
3 | Copyright (c) 2007, 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 | fpp FPP8A floating point processor\r | |
27 | \r | |
28 | Floating point formats:\r | |
29 | \r | |
30 | 00 01 02 03 04 05 06 07 08 09 10 11\r | |
31 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
32 | | S| hi integer | : double precision\r | |
33 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
34 | | lo integer |\r | |
35 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
36 | \r | |
37 | 00 01 02 03 04 05 06 07 08 09 10 11\r | |
38 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
39 | | S| exponent | : floating point\r | |
40 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
41 | | S| hi fraction |\r | |
42 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
43 | | lo fraction |\r | |
44 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
45 | \r | |
46 | \r | |
47 | 00 01 02 03 04 05 06 07 08 09 10 11\r | |
48 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
49 | | S| exponent | : extended precision\r | |
50 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
51 | | S| hi fraction |\r | |
52 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
53 | | next fraction |\r | |
54 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
55 | | next fraction |\r | |
56 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
57 | | next fraction |\r | |
58 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
59 | | lo fraction |\r | |
60 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
61 | \r | |
62 | Exponents are 2's complement, as are fractions. Normalized numbers have\r | |
63 | the form:\r | |
64 | \r | |
65 | 0.0...0\r | |
66 | 0.<non-zero>\r | |
67 | 1.<non-zero>\r | |
68 | 1.1...0\r | |
69 | \r | |
70 | Note that 1.0...0 is normalized but considered illegal, since it cannot\r | |
71 | be represented as a positive number. When a result is normalized, 1.0...0\r | |
72 | is converted to 1.1...0 with exp+1.\r | |
73 | */\r | |
74 | \r | |
75 | #include "pdp8_defs.h"\r | |
76 | \r | |
77 | extern int32 int_req;\r | |
78 | extern int32 sim_switches;\r | |
79 | extern int32 sim_interval;\r | |
80 | extern uint16 M[];\r | |
81 | extern int32 stop_inst;\r | |
82 | extern UNIT cpu_unit;\r | |
83 | \r | |
84 | #define SEXT12(x) (((x) & 04000)? (x) | ~07777: (x) & 03777)\r | |
85 | \r | |
86 | /* Index registers are in memory */\r | |
87 | \r | |
88 | #define fpp_read_xr(xr) fpp_read (fpp_xra + xr)\r | |
89 | #define fpp_write_xr(xr,d) fpp_write (fpp_xra +xr, d)\r | |
90 | \r | |
91 | /* Command register */\r | |
92 | \r | |
93 | #define FPC_DP 04000 /* integer double */\r | |
94 | #define FPC_UNFX 02000 /* exit on fl undf */\r | |
95 | #define FPC_FIXF 01000 /* lock mem field */\r | |
96 | #define FPC_IE 00400 /* int enable */\r | |
97 | #define FPC_V_FAST 4 /* startup bits */\r | |
98 | #define FPC_M_FAST 017\r | |
99 | #define FPC_LOCK 00010 /* lockout */\r | |
100 | #define FPC_V_APTF 0\r | |
101 | #define FPC_M_APTF 07 /* apta field */\r | |
102 | #define FPC_STA (FPC_DP|FPC_LOCK)\r | |
103 | #define FPC_GETFAST(x) (((x) >> FPC_V_FAST) & FPC_M_FAST)\r | |
104 | #define FPC_GETAPTF(x) (((x) >> FPC_V_APTF) & FPC_M_APTF)\r | |
105 | \r | |
106 | /* Status register */\r | |
107 | \r | |
108 | #define FPS_DP (FPC_DP) /* integer double */\r | |
109 | #define FPS_TRPX 02000 /* trap exit */\r | |
110 | #define FPS_HLTX 01000 /* halt exit */\r | |
111 | #define FPS_DVZX 00400 /* div zero exit */\r | |
112 | #define FPS_IOVX 00200 /* int ovf exit */\r | |
113 | #define FPS_FOVX 00100 /* flt ovf exit */\r | |
114 | #define FPS_UNF 00040 /* underflow */\r | |
115 | #define FPS_UNFX 00020 /* undf exit */\r | |
116 | #define FPS_XXXM 00010 /* FADDM/FMULM */\r | |
117 | #define FPS_LOCK (FPC_LOCK) /* lockout */\r | |
118 | #define FPS_EP 00004 /* ext prec */\r | |
119 | #define FPS_PAUSE 00002 /* paused */\r | |
120 | #define FPS_RUN 00001 /* running */\r | |
121 | \r | |
122 | /* Floating point number: 3-6 words */\r | |
123 | \r | |
124 | #define FPN_FRSIGN 04000\r | |
125 | #define FPN_NFR_FP 2 /* std precision */\r | |
126 | #define FPN_NFR_EP 5 /* ext precision */\r | |
127 | #define EXACT (uint32)((fpp_sta & FPS_EP)? FPN_NFR_EP: FPN_NFR_FP)\r | |
128 | #define EXTEND ((uint32) FPN_NFR_EP)\r | |
129 | \r | |
130 | typedef struct {\r | |
131 | int32 exp;\r | |
132 | uint32 fr[FPN_NFR_EP];\r | |
133 | } FPN;\r | |
134 | \r | |
135 | uint32 fpp_apta; /* APT pointer */\r | |
136 | uint32 fpp_aptsvf; /* APT saved field */\r | |
137 | uint32 fpp_opa; /* operand pointer */\r | |
138 | uint32 fpp_fpc; /* FP PC */\r | |
139 | uint32 fpp_bra; /* base reg pointer */\r | |
140 | uint32 fpp_xra; /* indx reg pointer */\r | |
141 | uint32 fpp_cmd; /* command */\r | |
142 | uint32 fpp_sta; /* status */\r | |
143 | uint32 fpp_flag; /* flag */\r | |
144 | FPN fpp_ac; /* FAC */\r | |
145 | static FPN fpp_zero = { 0, { 0, 0, 0, 0, 0 } };\r | |
146 | static FPN fpp_one = { 1, { 02000, 0, 0, 0, 0 } };\r | |
147 | \r | |
148 | DEVICE fpp_dev;\r | |
149 | int32 fpp55 (int32 IR, int32 AC);\r | |
150 | int32 fpp56 (int32 IR, int32 AC);\r | |
151 | void fpp_load_apt (uint32 apta);\r | |
152 | void fpp_dump_apt (uint32 apta, uint32 sta);\r | |
153 | uint32 fpp_1wd_dir (uint32 ir);\r | |
154 | uint32 fpp_2wd_dir (uint32 ir);\r | |
155 | uint32 fpp_indir (uint32 ir);\r | |
156 | uint32 fpp_ad15 (uint32 hi);\r | |
157 | uint32 fpp_adxr (uint32 ir, uint32 base_ad);\r | |
158 | t_bool fpp_add (FPN *a, FPN *b, uint32 sub);\r | |
159 | t_bool fpp_mul (FPN *a, FPN *b);\r | |
160 | t_bool fpp_div (FPN *a, FPN *b);\r | |
161 | t_bool fpp_imul (FPN *a, FPN *b);\r | |
162 | uint32 fpp_fr_add (uint32 *c, uint32 *a, uint32 *b);\r | |
163 | void fpp_fr_sub (uint32 *c, uint32 *a, uint32 *b);\r | |
164 | void fpp_fr_mul (uint32 *c, uint32 *a, uint32 *b);\r | |
165 | t_bool fpp_fr_div (uint32 *c, uint32 *a, uint32 *b);\r | |
166 | uint32 fpp_fr_neg (uint32 *a, uint32 cnt);\r | |
167 | int32 fpp_fr_cmp (uint32 *a, uint32 *b, uint32 cnt);\r | |
168 | int32 fpp_fr_test (uint32 *a, uint32 v0, uint32 cnt);\r | |
169 | uint32 fpp_fr_abs (uint32 *a, uint32 *b, uint32 cnt);\r | |
170 | void fpp_fr_fill (uint32 *a, uint32 v, uint32 cnt);\r | |
171 | void fpp_fr_lshn (uint32 *a, uint32 sc, uint32 cnt);\r | |
172 | void fpp_fr_lsh12 (uint32 *a, uint32 cnt);\r | |
173 | void fpp_fr_lsh1 (uint32 *a, uint32 cnt);\r | |
174 | void fpp_fr_rsh1 (uint32 *a, uint32 sign, uint32 cnt);\r | |
175 | void fpp_fr_algn (uint32 *a, uint32 sc, uint32 cnt);\r | |
176 | t_bool fpp_cond_met (uint32 cond);\r | |
177 | t_bool fpp_norm (FPN *a, uint32 cnt);\r | |
178 | uint32 fpp_round (FPN *a);\r | |
179 | t_bool fpp_test_xp (FPN *a);\r | |
180 | void fpp_copy (FPN *a, FPN *b);\r | |
181 | void fpp_zcopy (FPN *a, FPN *b);\r | |
182 | void fpp_read_op (uint32 ea, FPN *a);\r | |
183 | void fpp_write_op (uint32 ea, FPN *a);\r | |
184 | uint32 fpp_read (uint32 ea);\r | |
185 | void fpp_write (uint32 ea, uint32 val);\r | |
186 | uint32 apt_read (uint32 ea);\r | |
187 | void apt_write (uint32 ea, uint32 val);\r | |
188 | t_stat fpp_svc (UNIT *uptr);\r | |
189 | t_stat fpp_reset (DEVICE *dptr);\r | |
190 | \r | |
191 | /* FPP data structures\r | |
192 | \r | |
193 | fpp_dev FPP device descriptor\r | |
194 | fpp_unit FPP unit descriptor\r | |
195 | fpp_reg FPP register list\r | |
196 | */\r | |
197 | \r | |
198 | DIB fpp_dib = { DEV_FPP, 2, { &fpp55, &fpp56 } };\r | |
199 | \r | |
200 | UNIT fpp_unit = { UDATA (&fpp_svc, 0, 0) };\r | |
201 | \r | |
202 | REG fpp_reg[] = {\r | |
203 | { ORDATA (FPACE, fpp_ac.exp, 12) },\r | |
204 | { ORDATA (FPAC0, fpp_ac.fr[0], 12) },\r | |
205 | { ORDATA (FPAC1, fpp_ac.fr[1], 12) },\r | |
206 | { ORDATA (FPAC2, fpp_ac.fr[2], 12) },\r | |
207 | { ORDATA (FPAC3, fpp_ac.fr[3], 12) },\r | |
208 | { ORDATA (FPAC4, fpp_ac.fr[4], 12) },\r | |
209 | { ORDATA (CMD, fpp_cmd, 12) },\r | |
210 | { ORDATA (STA, fpp_sta, 12) },\r | |
211 | { ORDATA (APTA, fpp_apta, 15) },\r | |
212 | { GRDATA (APTSVF, fpp_aptsvf, 8, 3, 12) },\r | |
213 | { ORDATA (FPC, fpp_fpc, 15) },\r | |
214 | { ORDATA (BRA, fpp_bra, 15) },\r | |
215 | { ORDATA (XRA, fpp_xra, 15) },\r | |
216 | { ORDATA (OPA, fpp_opa, 15) },\r | |
217 | { FLDATA (FLAG, fpp_flag, 0) },\r | |
218 | { NULL }\r | |
219 | };\r | |
220 | \r | |
221 | DEVICE fpp_dev = {\r | |
222 | "FPP", &fpp_unit, fpp_reg, NULL,\r | |
223 | 1, 10, 31, 1, 8, 8,\r | |
224 | NULL, NULL, &fpp_reset,\r | |
225 | NULL, NULL, NULL,\r | |
226 | &fpp_dib, DEV_DISABLE | DEV_DIS\r | |
227 | };\r | |
228 | \r | |
229 | /* IOT routines */\r | |
230 | \r | |
231 | int32 fpp55 (int32 IR, int32 AC)\r | |
232 | {\r | |
233 | switch (IR & 07) { /* decode IR<9:11> */\r | |
234 | \r | |
235 | case 1: /* FPINT */\r | |
236 | return (fpp_flag? IOT_SKP | AC: AC); /* skip on flag */\r | |
237 | \r | |
238 | case 2: /* FPICL */\r | |
239 | fpp_reset (&fpp_dev); /* reset device */\r | |
240 | break;\r | |
241 | \r | |
242 | case 3: /* FPCOM */\r | |
243 | if (!fpp_flag && !(fpp_sta & FPS_RUN)) { /* flag clr, !run? */\r | |
244 | fpp_cmd = AC; /* load cmd */\r | |
245 | fpp_sta = (fpp_sta & ~FPC_STA) | /* copy flags */\r | |
246 | (fpp_cmd & FPC_STA); /* to status */\r | |
247 | }\r | |
248 | break;\r | |
249 | \r | |
250 | case 4: /* FPHLT */\r | |
251 | if (fpp_sta & FPS_RUN) { /* running? */\r | |
252 | if (fpp_sta & FPS_PAUSE) /* paused? */\r | |
253 | fpp_fpc = (fpp_fpc - 1) & ADDRMASK; /* decr FPC */\r | |
254 | sim_cancel (&fpp_unit); /* stop execution */\r | |
255 | fpp_dump_apt (fpp_apta, FPS_HLTX); /* dump APT */\r | |
256 | }\r | |
257 | else sim_activate (&fpp_unit, 0); /* single step */\r | |
258 | break;\r | |
259 | \r | |
260 | case 5: /* FPST */\r | |
261 | if (!fpp_flag && !(fpp_sta & FPS_RUN)) { /* flag clr, !run? */\r | |
262 | fpp_apta = (FPC_GETAPTF (fpp_cmd) << 12) | AC;\r | |
263 | fpp_load_apt (fpp_apta); /* load APT */\r | |
264 | sim_activate (&fpp_unit, 0); /* start unit */\r | |
265 | return IOT_SKP | AC;\r | |
266 | }\r | |
267 | if ((fpp_sta & (FPS_RUN|FPS_PAUSE)) == (FPS_RUN|FPS_PAUSE)) {\r | |
268 | fpp_sta &= ~FPS_PAUSE; /* continue */\r | |
269 | sim_activate (&fpp_unit, 0); /* start unit */\r | |
270 | return (IOT_SKP | AC);\r | |
271 | }\r | |
272 | break;\r | |
273 | \r | |
274 | case 6: /* FPRST */\r | |
275 | return fpp_sta;\r | |
276 | \r | |
277 | case 7: /* FPIST */\r | |
278 | if (fpp_flag) { /* if flag set */\r | |
279 | uint32 old_sta = fpp_sta;\r | |
280 | fpp_flag = 0; /* clr flag, status */\r | |
281 | fpp_sta = 0;\r | |
282 | int_req &= ~INT_FPP; /* clr int req */\r | |
283 | return IOT_SKP | old_sta; /* ret old status */\r | |
284 | }\r | |
285 | break;\r | |
286 | \r | |
287 | default:\r | |
288 | return (stop_inst << IOT_V_REASON) | AC;\r | |
289 | } /* end switch */\r | |
290 | \r | |
291 | return AC;\r | |
292 | }\r | |
293 | \r | |
294 | int32 fpp56 (int32 IR, int32 AC)\r | |
295 | {\r | |
296 | switch (IR & 07) { /* decode IR<9:11> */\r | |
297 | \r | |
298 | case 7: /* FPEP */\r | |
299 | if ((AC & 04000) && !(fpp_sta & FPS_RUN)) /* if AC0, not run, */\r | |
300 | fpp_sta = (fpp_sta | FPS_EP) & ~FPS_DP; /* set ep */\r | |
301 | break;\r | |
302 | \r | |
303 | default:\r | |
304 | return (stop_inst << IOT_V_REASON) | AC;\r | |
305 | } /* end switch */\r | |
306 | \r | |
307 | return AC;\r | |
308 | }\r | |
309 | \r | |
310 | /* Service routine */\r | |
311 | \r | |
312 | t_stat fpp_svc (UNIT *uptr)\r | |
313 | {\r | |
314 | FPN x;\r | |
315 | uint32 ir, op, op2, op3, ad, ea, wd;\r | |
316 | uint32 i;\r | |
317 | \r | |
318 | fpp_ac.exp = SEXT12 (fpp_ac.exp); /* sext AC exp */\r | |
319 | do { /* repeat */\r | |
320 | ir = fpp_read (fpp_fpc); /* get instr */\r | |
321 | fpp_fpc = (fpp_fpc + 1) & ADDRMASK; /* incr FP PC */\r | |
322 | op = (ir >> 7) & 037; /* get op+mode */\r | |
323 | op2 = (ir >> 3) & 017; /* get subop */\r | |
324 | op3 = ir & 07; /* get field/xr */\r | |
325 | fpp_sta &= ~FPS_XXXM; /* not mem op */\r | |
326 | \r | |
327 | switch (op) { /* case on op+mode */\r | |
328 | case 000: /* operates */\r | |
329 | \r | |
330 | switch (op2) { /* case on subop */\r | |
331 | case 000: /* no-operands */\r | |
332 | switch (op3) { /* case on subsubop */\r | |
333 | \r | |
334 | case 0: /* FEXIT */\r | |
335 | fpp_dump_apt (fpp_apta, 0);\r | |
336 | break;\r | |
337 | \r | |
338 | case 1: /* FPAUSE */\r | |
339 | fpp_sta |= FPS_PAUSE;\r | |
340 | break;\r | |
341 | \r | |
342 | case 2: /* FCLA */\r | |
343 | fpp_copy (&fpp_ac, &fpp_zero); /* clear FAC */\r | |
344 | break;\r | |
345 | \r | |
346 | case 3: /* FNEG */\r | |
347 | fpp_fr_neg (fpp_ac.fr, EXACT); /* do exact length */\r | |
348 | break;\r | |
349 | \r | |
350 | case 4: /* FNORM */\r | |
351 | if (!(fpp_sta & FPS_DP)) { /* fp or ep only */\r | |
352 | fpp_copy (&x, &fpp_ac); /* copy AC */\r | |
353 | fpp_norm (&x, EXACT); /* do exact length */\r | |
354 | if (!fpp_test_xp (&x)) /* no trap? */\r | |
355 | fpp_copy (&fpp_ac, &x); /* copy back */\r | |
356 | }\r | |
357 | break;\r | |
358 | \r | |
359 | case 5: /* STARTF */\r | |
360 | if (fpp_sta & FPS_EP) { /* if ep, */\r | |
361 | fpp_copy (&x, &fpp_ac); /* copy AC */\r | |
362 | fpp_round (&x); /* round */\r | |
363 | if (!fpp_test_xp (&x)) /* no trap? */\r | |
364 | fpp_copy (&fpp_ac, &x); /* copy back */\r | |
365 | }\r | |
366 | fpp_sta &= ~(FPS_DP|FPS_EP);\r | |
367 | break;\r | |
368 | \r | |
369 | case 6: /* STARTD */\r | |
370 | fpp_sta = (fpp_sta | FPS_DP) & ~FPS_EP;\r | |
371 | break;\r | |
372 | \r | |
373 | case 7: /* JAC */\r | |
374 | fpp_fpc = ((fpp_ac.fr[0] & 07) << 12) | fpp_ac.fr[1];\r | |
375 | break;\r | |
376 | }\r | |
377 | break;\r | |
378 | \r | |
379 | case 001: /* ALN */\r | |
380 | if (op3 != 0) /* if xr, */\r | |
381 | wd = fpp_read_xr (op3); /* use val */\r | |
382 | else wd = 027; /* else 23 */\r | |
383 | if (!(fpp_sta & FPS_DP)) { /* fp or ep? */\r | |
384 | int32 t = wd - fpp_ac.exp; /* alignment */\r | |
385 | fpp_ac.exp = SEXT12 (wd); /* new exp */\r | |
386 | wd = t & 07777;\r | |
387 | }\r | |
388 | if (wd & 04000) /* left? */\r | |
389 | fpp_fr_lshn (fpp_ac.fr, 04000 - wd, EXACT);\r | |
390 | else fpp_fr_algn (fpp_ac.fr, wd, EXACT);\r | |
391 | break;\r | |
392 | \r | |
393 | case 002: /* ATX */\r | |
394 | if (fpp_sta & FPS_DP) /* dp? */\r | |
395 | fpp_write_xr (op3, fpp_ac.fr[1]); /* xr<-FAC<12:23> */\r | |
396 | else {\r | |
397 | fpp_copy (&x, &fpp_ac); /* copy AC */\r | |
398 | wd = (fpp_ac.exp - 027) & 07777; /* shift amt */\r | |
399 | if (wd & 04000) /* left? */\r | |
400 | fpp_fr_lshn (x.fr, 04000 - wd, EXACT);\r | |
401 | else fpp_fr_algn (x.fr, wd, EXACT);\r | |
402 | fpp_write_xr (op3, x.fr[1]); /* xr<-val<12:23> */\r | |
403 | }\r | |
404 | break;\r | |
405 | \r | |
406 | case 003: /* XTA */\r | |
407 | for (i = FPN_NFR_FP; i < FPN_NFR_EP; i++)\r | |
408 | x.fr[i] = 0; /* clear FOP2-4 */\r | |
409 | x.fr[1] = fpp_read_xr (op3); /* get XR value */\r | |
410 | x.fr[0] = (x.fr[1] & 04000)? 07777: 0;\r | |
411 | x.exp = 027; /* standard exp */\r | |
412 | if (!(fpp_sta & FPS_DP)) { /* fp or ep? */\r | |
413 | fpp_norm (&x, EXACT); /* normalize */\r | |
414 | if (fpp_test_xp (&x)) /* exception? */\r | |
415 | break;\r | |
416 | }\r | |
417 | fpp_copy (&fpp_ac, &x); /* result to AC */\r | |
418 | break;\r | |
419 | \r | |
420 | case 004: /* NOP */\r | |
421 | break;\r | |
422 | \r | |
423 | case 005: /* STARTE */\r | |
424 | if (!(fpp_sta & FPS_EP)) {\r | |
425 | fpp_sta = (fpp_sta | FPS_EP) & ~FPS_DP;\r | |
426 | for (i = FPN_NFR_FP; i < FPN_NFR_EP; i++)\r | |
427 | fpp_ac.fr[i] = 0; /* clear FAC2-4 */\r | |
428 | }\r | |
429 | break;\r | |
430 | \r | |
431 | case 010: /* LDX */\r | |
432 | wd = fpp_ad15 (0); /* load XR immed */\r | |
433 | fpp_write_xr (op3, wd);\r | |
434 | break;\r | |
435 | \r | |
436 | case 011: /* ADDX */\r | |
437 | wd = fpp_ad15 (0);\r | |
438 | wd = wd + fpp_read_xr (op3); /* add to XR immed */\r | |
439 | fpp_write_xr (op3, wd); /* trims to 12b */\r | |
440 | break;\r | |
441 | \r | |
442 | default:\r | |
443 | return stop_inst;\r | |
444 | } /* end case subop */\r | |
445 | break;\r | |
446 | \r | |
447 | case 001: /* FLDA */\r | |
448 | ea = fpp_1wd_dir (ir);\r | |
449 | fpp_read_op (ea, &fpp_ac);\r | |
450 | break;\r | |
451 | \r | |
452 | case 002:\r | |
453 | ea = fpp_2wd_dir (ir);\r | |
454 | fpp_read_op (ea, &fpp_ac);\r | |
455 | break;\r | |
456 | \r | |
457 | case 003:\r | |
458 | ea = fpp_indir (ir);\r | |
459 | fpp_read_op (ea, &fpp_ac);\r | |
460 | break;\r | |
461 | \r | |
462 | case 004: /* jumps and sets */\r | |
463 | ad = fpp_ad15 (op3); /* get 15b address */\r | |
464 | switch (op2) { /* case on subop */\r | |
465 | \r | |
466 | case 000: case 001: case 002: case 003: /* cond jump */\r | |
467 | case 004: case 005: case 006: case 007:\r | |
468 | if (fpp_cond_met (op2)) /* br if cond */\r | |
469 | fpp_fpc = ad;\r | |
470 | break;\r | |
471 | \r | |
472 | case 010: /* SETX */\r | |
473 | fpp_xra = ad;\r | |
474 | break;\r | |
475 | \r | |
476 | case 011: /* SETB */\r | |
477 | fpp_bra = ad;\r | |
478 | break;\r | |
479 | \r | |
480 | case 012: /* JSA */\r | |
481 | fpp_write (ad, 01030 + (fpp_fpc >> 12)); /* save return */\r | |
482 | fpp_write (ad + 1, fpp_fpc); /* trims to 12b */\r | |
483 | fpp_fpc = (ad + 2) & ADDRMASK; \r | |
484 | break;\r | |
485 | \r | |
486 | case 013: /* JSR */\r | |
487 | fpp_write (fpp_bra + 1, 01030 + (fpp_fpc >> 12));\r | |
488 | fpp_write (fpp_bra + 2, fpp_fpc); /* trims to 12b */\r | |
489 | fpp_fpc = ad;\r | |
490 | break;\r | |
491 | \r | |
492 | default:\r | |
493 | return stop_inst;\r | |
494 | } /* end case subop */\r | |
495 | break;\r | |
496 | \r | |
497 | case 005: /* FADD */\r | |
498 | ea = fpp_1wd_dir (ir);\r | |
499 | fpp_read_op (ea, &x);\r | |
500 | fpp_add (&fpp_ac, &x, 0);\r | |
501 | break;\r | |
502 | \r | |
503 | case 006:\r | |
504 | ea = fpp_2wd_dir (ir);\r | |
505 | fpp_read_op (ea, &x);\r | |
506 | fpp_add (&fpp_ac, &x, 0);\r | |
507 | break;\r | |
508 | \r | |
509 | case 007:\r | |
510 | ea = fpp_indir (ir);\r | |
511 | fpp_read_op (ea, &x);\r | |
512 | fpp_add (&fpp_ac, &x, 0);\r | |
513 | break;\r | |
514 | \r | |
515 | case 010: /* JNX */\r | |
516 | ad = fpp_ad15 (op3); /* get 15b addr */\r | |
517 | wd = fpp_read_xr (op2 & 07); /* read xr */\r | |
518 | if (ir & 00100) { /* inc? */\r | |
519 | wd = (wd + 1) & 07777;\r | |
520 | fpp_write_xr (op2 & 07, wd); /* ++xr */\r | |
521 | }\r | |
522 | if (wd != 0) /* xr != 0? */\r | |
523 | fpp_fpc = ad; /* jump */\r | |
524 | break;\r | |
525 | \r | |
526 | case 011: /* FSUB */\r | |
527 | ea = fpp_1wd_dir (ir);\r | |
528 | fpp_read_op (ea, &x);\r | |
529 | fpp_add (&fpp_ac, &x, 1);\r | |
530 | break;\r | |
531 | \r | |
532 | case 012:\r | |
533 | ea = fpp_2wd_dir (ir);\r | |
534 | fpp_read_op (ea, &x);\r | |
535 | fpp_add (&fpp_ac, &x, 1);\r | |
536 | break;\r | |
537 | \r | |
538 | case 013:\r | |
539 | ea = fpp_indir (ir);\r | |
540 | fpp_read_op (ea, &x);\r | |
541 | fpp_add (&fpp_ac, &x, 1);\r | |
542 | break;\r | |
543 | \r | |
544 | case 014: /* TRAP3 */\r | |
545 | case 020: /* TRAP4 */\r | |
546 | fpp_opa = fpp_ad15 (op3);\r | |
547 | fpp_dump_apt (fpp_apta, FPS_TRPX);\r | |
548 | break;\r | |
549 | \r | |
550 | case 015: /* FDIV */\r | |
551 | ea = fpp_1wd_dir (ir);\r | |
552 | fpp_read_op (ea, &x);\r | |
553 | fpp_div (&fpp_ac, &x);\r | |
554 | break;\r | |
555 | \r | |
556 | case 016:\r | |
557 | ea = fpp_2wd_dir (ir);\r | |
558 | fpp_read_op (ea, &x);\r | |
559 | fpp_div (&fpp_ac, &x);\r | |
560 | break;\r | |
561 | \r | |
562 | case 017:\r | |
563 | ea = fpp_indir (ir);\r | |
564 | fpp_read_op (ea, &x);\r | |
565 | fpp_div (&fpp_ac, &x);\r | |
566 | break;\r | |
567 | \r | |
568 | case 021: /* FMUL */\r | |
569 | ea = fpp_1wd_dir (ir);\r | |
570 | fpp_read_op (ea, &x);\r | |
571 | fpp_mul (&fpp_ac, &x);\r | |
572 | break;\r | |
573 | \r | |
574 | case 022:\r | |
575 | ea = fpp_2wd_dir (ir);\r | |
576 | fpp_read_op (ea, &x);\r | |
577 | fpp_mul (&fpp_ac, &x);\r | |
578 | break;\r | |
579 | \r | |
580 | case 023:\r | |
581 | ea = fpp_indir (ir);\r | |
582 | fpp_read_op (ea, &x);\r | |
583 | fpp_mul (&fpp_ac, &x);\r | |
584 | break;\r | |
585 | \r | |
586 | case 024: /* LTR */\r | |
587 | fpp_copy (&fpp_ac, (fpp_cond_met (op2 & 07)? &fpp_one: &fpp_zero));\r | |
588 | break;\r | |
589 | \r | |
590 | case 025: /* FADDM */\r | |
591 | fpp_sta |= FPS_XXXM;\r | |
592 | ea = fpp_1wd_dir (ir);\r | |
593 | fpp_read_op (ea, &x);\r | |
594 | if (!fpp_add (&x, &fpp_ac, 0)) /* no trap? */\r | |
595 | fpp_write_op (ea, &x); /* store result */\r | |
596 | break;\r | |
597 | \r | |
598 | case 026:\r | |
599 | fpp_sta |= FPS_XXXM;\r | |
600 | ea = fpp_2wd_dir (ir);\r | |
601 | fpp_read_op (ea, &x);\r | |
602 | if (!fpp_add (&x, &fpp_ac, 0)) /* no trap? */\r | |
603 | fpp_write_op (ea, &x); /* store result */\r | |
604 | break;\r | |
605 | \r | |
606 | case 027:\r | |
607 | fpp_sta |= FPS_XXXM;\r | |
608 | ea = fpp_indir (ir);\r | |
609 | fpp_read_op (ea, &x);\r | |
610 | if (!fpp_add (&x, &fpp_ac, 0)) /* no trap? */\r | |
611 | fpp_write_op (ea, &x); /* store result */\r | |
612 | break;\r | |
613 | \r | |
614 | case 030: /* IMUL/LEA */\r | |
615 | ea = fpp_2wd_dir (ir); /* 2-word direct */\r | |
616 | if (fpp_sta & FPS_DP) { /* dp? */\r | |
617 | fpp_read_op (ea, &x); /* IMUL */\r | |
618 | fpp_imul (&fpp_ac, &x);\r | |
619 | }\r | |
620 | else { /* LEA */\r | |
621 | fpp_sta = (fpp_sta | FPS_DP) & ~FPS_EP; /* set dp */\r | |
622 | fpp_ac.fr[0] = (ea >> 12) & 07;\r | |
623 | fpp_ac.fr[1] = ea & 07777;\r | |
624 | }\r | |
625 | break;\r | |
626 | \r | |
627 | case 031: /* FSTA */\r | |
628 | ea = fpp_1wd_dir (ir);\r | |
629 | fpp_write_op (ea, &fpp_ac);\r | |
630 | break;\r | |
631 | \r | |
632 | case 032:\r | |
633 | ea = fpp_2wd_dir (ir);\r | |
634 | fpp_write_op (ea, &fpp_ac);\r | |
635 | break;\r | |
636 | \r | |
637 | case 033:\r | |
638 | ea = fpp_indir (ir);\r | |
639 | fpp_write_op (ea, &fpp_ac);\r | |
640 | break;\r | |
641 | \r | |
642 | case 034: /* IMULI/LEAI */\r | |
643 | ea = fpp_indir (ir); /* 1-word indir */\r | |
644 | if (fpp_sta & FPS_DP) { /* dp? */\r | |
645 | fpp_read_op (ea, &x); /* IMUL */\r | |
646 | fpp_imul (&fpp_ac, &x);\r | |
647 | }\r | |
648 | else { /* LEA */\r | |
649 | fpp_sta = (fpp_sta | FPS_DP) & ~FPS_EP; /* set dp */\r | |
650 | fpp_ac.fr[0] = (ea >> 12) & 07;\r | |
651 | fpp_ac.fr[1] = ea & 07777;\r | |
652 | }\r | |
653 | break;\r | |
654 | \r | |
655 | case 035: /* FMULM */\r | |
656 | fpp_sta |= FPS_XXXM;\r | |
657 | ea = fpp_1wd_dir (ir);\r | |
658 | fpp_read_op (ea, &x);\r | |
659 | if (!fpp_mul (&x, &fpp_ac)) /* no trap? */\r | |
660 | fpp_write_op (ea, &x); /* store result */\r | |
661 | break;\r | |
662 | \r | |
663 | case 036:\r | |
664 | fpp_sta |= FPS_XXXM;\r | |
665 | ea = fpp_2wd_dir (ir);\r | |
666 | fpp_read_op (ea, &x);\r | |
667 | if (!fpp_mul (&x, &fpp_ac)) /* no trap? */\r | |
668 | fpp_write_op (ea, &x); /* store result */\r | |
669 | break;\r | |
670 | \r | |
671 | case 037:\r | |
672 | fpp_sta |= FPS_XXXM;\r | |
673 | ea = fpp_indir (ir);\r | |
674 | fpp_read_op (ea, &x);\r | |
675 | if (!fpp_mul (&x, &fpp_ac)) /* no trap? */\r | |
676 | fpp_write_op (ea, &x); /* store result */\r | |
677 | break;\r | |
678 | } /* end sw op+mode */\r | |
679 | \r | |
680 | if (sim_interval)\r | |
681 | sim_interval = sim_interval - 1;\r | |
682 | } while ((sim_interval > 0) &&\r | |
683 | ((fpp_sta & (FPS_RUN|FPS_PAUSE|FPS_LOCK)) == (FPS_RUN|FPS_LOCK)));\r | |
684 | if ((fpp_sta & (FPS_RUN|FPS_PAUSE)) == FPS_RUN)\r | |
685 | sim_activate (uptr, 1);\r | |
686 | fpp_ac.exp &= 07777; /* mask AC exp */\r | |
687 | return SCPE_OK;\r | |
688 | }\r | |
689 | \r | |
690 | /* Address decoding routines */\r | |
691 | \r | |
692 | uint32 fpp_1wd_dir (uint32 ir)\r | |
693 | {\r | |
694 | uint32 ad; \r | |
695 | \r | |
696 | ad = fpp_bra + ((ir & 0177) * 3); /* base + 3*7b off */\r | |
697 | if (fpp_sta & FPS_DP) /* dp? skip exp */\r | |
698 | ad = ad + 1;\r | |
699 | return ad & ADDRMASK;\r | |
700 | }\r | |
701 | \r | |
702 | uint32 fpp_2wd_dir (uint32 ir)\r | |
703 | {\r | |
704 | uint32 ad;\r | |
705 | \r | |
706 | ad = fpp_ad15 (ir); /* get 15b addr */\r | |
707 | return fpp_adxr (ir, ad); /* do indexing */\r | |
708 | }\r | |
709 | \r | |
710 | uint32 fpp_indir (uint32 ir)\r | |
711 | {\r | |
712 | uint32 ad, iad, wd1, wd2;\r | |
713 | \r | |
714 | ad = fpp_bra + ((ir & 07) * 3); /* base + 3*3b off */\r | |
715 | iad = fpp_adxr (ir, ad); /* do indexing */\r | |
716 | wd1 = fpp_read (iad + 1); /* read wds 2,3 */\r | |
717 | wd2 = fpp_read (iad + 2);\r | |
718 | return ((wd1 & 07) << 12) | wd2; /* return addr */\r | |
719 | }\r | |
720 | \r | |
721 | uint32 fpp_ad15 (uint32 hi)\r | |
722 | {\r | |
723 | uint32 ad;\r | |
724 | \r | |
725 | ad = ((hi & 07) << 12) | fpp_read (fpp_fpc); /* 15b addr */\r | |
726 | fpp_fpc = (fpp_fpc + 1) & ADDRMASK; /* incr FPC */\r | |
727 | return ad; /* return addr */\r | |
728 | }\r | |
729 | \r | |
730 | uint32 fpp_adxr (uint32 ir, uint32 base_ad)\r | |
731 | {\r | |
732 | uint32 xr, wd;\r | |
733 | \r | |
734 | xr = (ir >> 3) & 07;\r | |
735 | wd = fpp_read_xr (xr); /* get xr */\r | |
736 | if (ir & 0100) { /* increment? */\r | |
737 | wd = (wd + 1) & 07777; /* inc, rewrite */\r | |
738 | fpp_write_xr (xr, wd);\r | |
739 | }\r | |
740 | if (xr != 0) { /* indexed? */\r | |
741 | if (fpp_sta & FPS_EP) wd = wd * 6; /* scale by len */\r | |
742 | else if (fpp_sta & FPS_DP) wd = wd * 2;\r | |
743 | else wd = wd * 3;\r | |
744 | return (base_ad + wd) & ADDRMASK; /* return index */\r | |
745 | }\r | |
746 | else return base_ad & ADDRMASK; /* return addr */\r | |
747 | }\r | |
748 | \r | |
749 | /* Computation routines */\r | |
750 | \r | |
751 | /* Fraction/floating add - return true if overflow */\r | |
752 | \r | |
753 | t_bool fpp_add (FPN *a, FPN *b, uint32 sub)\r | |
754 | {\r | |
755 | FPN x, y, z;\r | |
756 | uint32 ediff, c;\r | |
757 | \r | |
758 | fpp_zcopy (&x, a); /* copy opnds */\r | |
759 | fpp_zcopy (&y, b);\r | |
760 | if (sub) /* subtract? */\r | |
761 | fpp_fr_neg (y.fr, EXACT); /* neg B, exact */\r | |
762 | if (fpp_sta & FPS_DP) { /* dp? */\r | |
763 | fpp_fr_add (z.fr, x.fr, y.fr); /* z = a + b */\r | |
764 | if ((~x.fr[0] ^ y.fr[0]) & (x.fr[0] ^ z.fr[0]) & FPN_FRSIGN) {\r | |
765 | fpp_dump_apt (fpp_apta, FPS_IOVX); /* int ovf? */\r | |
766 | return TRUE;\r | |
767 | }\r | |
768 | }\r | |
769 | else { /* fp or ep */\r | |
770 | if (fpp_fr_test (b->fr, 0, EXACT) == 0) /* B == 0? */\r | |
771 | z = x; /* result is A */\r | |
772 | else if (fpp_fr_test (a->fr, 0, EXACT) == 0) /* A == 0? */\r | |
773 | z = y; /* result is B */\r | |
774 | else { /* fp or ep */\r | |
775 | if (x.exp < y.exp) { /* |a| < |b|? */\r | |
776 | z = x; /* exchange ops */\r | |
777 | x = y;\r | |
778 | y = z;\r | |
779 | }\r | |
780 | ediff = x.exp - y.exp; /* exp diff */\r | |
781 | z.exp = x.exp; /* result exp */\r | |
782 | if (ediff <= (fpp_sta & FPS_EP)? 59: 24) { /* any add? */\r | |
783 | if (ediff != 0) /* any align? */\r | |
784 | fpp_fr_algn (y.fr, ediff, EXTEND); /* align, 60b */\r | |
785 | c = fpp_fr_add (z.fr, x.fr, y.fr); /* add fractions */\r | |
786 | if ((((x.fr[0] ^ y.fr[0]) & FPN_FRSIGN) == 0) && /* same signs? */\r | |
787 | (c || /* carry out? */\r | |
788 | ((~x.fr[0] & z.fr[0] & FPN_FRSIGN)))) { /* + to - change? */\r | |
789 | fpp_fr_rsh1 (z.fr, c << 11, EXTEND); /* rsh, insert cout */\r | |
790 | z.exp = z.exp + 1; /* incr exp */\r | |
791 | } /* end same signs */\r | |
792 | } /* end in range */\r | |
793 | } /* end ops != 0 */\r | |
794 | if (fpp_norm (&z, EXTEND)) /* norm, !exact? */\r | |
795 | fpp_round (&z); /* round */\r | |
796 | if (fpp_test_xp (&z)) /* ovf, unf? */\r | |
797 | return TRUE;\r | |
798 | } /* end else */\r | |
799 | fpp_copy (a, &z); /* result is z */\r | |
800 | return FALSE;\r | |
801 | }\r | |
802 | \r | |
803 | /* Fraction/floating multiply - return true if overflow */\r | |
804 | \r | |
805 | t_bool fpp_mul (FPN *a, FPN *b)\r | |
806 | {\r | |
807 | FPN x, y, z;\r | |
808 | \r | |
809 | fpp_zcopy (&x, a); /* copy opnds */\r | |
810 | fpp_zcopy (&y, b);\r | |
811 | if (fpp_sta & FPS_DP) /* dp? */\r | |
812 | fpp_fr_mul (z.fr, x.fr, y.fr); /* mult frac */\r | |
813 | else { /* fp or ep */\r | |
814 | z.exp = x.exp + y.exp; /* add exp */\r | |
815 | fpp_fr_mul (z.fr, x.fr, y.fr); /* mult frac */\r | |
816 | if (fpp_norm (&z, EXTEND)) /* norm, !exact? */\r | |
817 | fpp_round (&z); /* round */\r | |
818 | if (fpp_test_xp (&z)) /* ovf, unf? */\r | |
819 | return TRUE;\r | |
820 | }\r | |
821 | fpp_copy (a, &z); /* result is z */\r | |
822 | return FALSE;\r | |
823 | }\r | |
824 | \r | |
825 | /* Fraction/floating divide - return true if div by zero or overflow */\r | |
826 | \r | |
827 | t_bool fpp_div (FPN *a, FPN *b)\r | |
828 | {\r | |
829 | FPN x, y, z;\r | |
830 | \r | |
831 | if (fpp_fr_test (b->fr, 0, EXACT) == 0) { /* divisor 0? */\r | |
832 | fpp_dump_apt (fpp_apta, FPS_DVZX); /* error */\r | |
833 | return TRUE;\r | |
834 | }\r | |
835 | if (fpp_fr_test (a->fr, 0, EXACT) == 0) /* dividend 0? */\r | |
836 | return FALSE; /* quotient is 0 */\r | |
837 | fpp_zcopy (&x, a); /* copy opnds */\r | |
838 | fpp_zcopy (&y, b);\r | |
839 | if (fpp_sta & FPS_DP) { /* dp? */\r | |
840 | if (fpp_fr_div (z.fr, x.fr, y.fr)) { /* fr div, ovflo? */\r | |
841 | fpp_dump_apt (fpp_apta, FPS_IOVX); /* error */\r | |
842 | return TRUE;\r | |
843 | }\r | |
844 | }\r | |
845 | else { /* fp or ep */\r | |
846 | fpp_norm (&y, EXACT); /* norm divisor */\r | |
847 | if (fpp_fr_test (x.fr, 04000, EXACT) == 0) { /* divd 1.000...? */\r | |
848 | x.fr[0] = 06000; /* fix */\r | |
849 | x.exp = x.exp + 1;\r | |
850 | }\r | |
851 | z.exp = x.exp - y.exp; /* calc exp */\r | |
852 | if (fpp_fr_div (z.fr, x.fr, y.fr)) { /* fr div, ovflo? */\r | |
853 | uint32 cin = (a->fr[0] ^ b->fr[0]) & FPN_FRSIGN;\r | |
854 | fpp_fr_rsh1 (z.fr, cin, EXTEND); /* rsh, insert sign */\r | |
855 | z.exp = z.exp + 1; /* incr exp */\r | |
856 | }\r | |
857 | if (fpp_norm (&z, EXTEND)) /* norm, !exact? */\r | |
858 | fpp_round (&z); /* round */\r | |
859 | if (fpp_test_xp (&z)) /* ovf, unf? */\r | |
860 | return TRUE;\r | |
861 | }\r | |
862 | fpp_copy (a, &z); /* result is z */\r | |
863 | return FALSE;\r | |
864 | }\r | |
865 | \r | |
866 | /* Integer multiply - returns true if overflow */\r | |
867 | \r | |
868 | t_bool fpp_imul (FPN *a, FPN *b)\r | |
869 | {\r | |
870 | uint32 sext;\r | |
871 | FPN x, y, z;\r | |
872 | \r | |
873 | fpp_zcopy (&x, a); /* copy args */\r | |
874 | fpp_zcopy (&y, b);\r | |
875 | fpp_fr_mul (z.fr, x.fr, y.fr); /* mult fracs */\r | |
876 | sext = (z.fr[2] & FPN_FRSIGN)? 07777: 0;\r | |
877 | if (((z.fr[0] | z.fr[1] | sext) != 0) && /* hi 25b == 0 */\r | |
878 | ((z.fr[0] & z.fr[1] & sext) != 07777)) { /* or 777777774? */\r | |
879 | fpp_dump_apt (fpp_apta, FPS_IOVX);\r | |
880 | return TRUE;\r | |
881 | }\r | |
882 | a->fr[0] = z.fr[2]; /* low 24b */\r | |
883 | a->fr[1] = z.fr[3];\r | |
884 | return FALSE;\r | |
885 | }\r | |
886 | \r | |
887 | /* Auxiliary floating point routines */\r | |
888 | \r | |
889 | t_bool fpp_cond_met (uint32 cond)\r | |
890 | {\r | |
891 | switch (cond) {\r | |
892 | \r | |
893 | case 0:\r | |
894 | return (fpp_fr_test (fpp_ac.fr, 0, EXACT) == 0);\r | |
895 | \r | |
896 | case 1:\r | |
897 | return (fpp_fr_test (fpp_ac.fr, 0, EXACT) >= 0);\r | |
898 | \r | |
899 | case 2:\r | |
900 | return (fpp_fr_test (fpp_ac.fr, 0, EXACT) <= 0);\r | |
901 | \r | |
902 | case 3:\r | |
903 | return 1;\r | |
904 | \r | |
905 | case 4:\r | |
906 | return (fpp_fr_test (fpp_ac.fr, 0, EXACT) != 0);\r | |
907 | \r | |
908 | case 5:\r | |
909 | return (fpp_fr_test (fpp_ac.fr, 0, EXACT) < 0);\r | |
910 | \r | |
911 | case 6:\r | |
912 | return (fpp_fr_test (fpp_ac.fr, 0, EXACT) > 0);\r | |
913 | \r | |
914 | case 7:\r | |
915 | return (fpp_ac.exp > 027);\r | |
916 | }\r | |
917 | return 0;\r | |
918 | }\r | |
919 | \r | |
920 | /* Normalization - returns TRUE if rounding possible, FALSE if exact */\r | |
921 | \r | |
922 | t_bool fpp_norm (FPN *a, uint32 cnt)\r | |
923 | {\r | |
924 | if (fpp_fr_test (a->fr, 0, cnt) == 0) { /* zero? */\r | |
925 | a->exp = 0; /* clean exp */\r | |
926 | return FALSE; /* don't round */\r | |
927 | }\r | |
928 | while (((a->fr[0] == 0) && !(a->fr[1] & 04000)) || /* lead 13b same? */\r | |
929 | ((a->fr[0] = 07777) & (a->fr[1] & 04000))) {\r | |
930 | fpp_fr_lsh12 (a->fr, cnt); /* move word */\r | |
931 | a->exp = a->exp - 12;\r | |
932 | }\r | |
933 | while (((a->fr[0] ^ (a->fr[0] << 1)) & FPN_FRSIGN) == 0) { /* until norm */\r | |
934 | fpp_fr_lsh1 (a->fr, cnt); /* shift 1b */\r | |
935 | a->exp = a->exp - 1;\r | |
936 | }\r | |
937 | if (fpp_fr_test (a->fr, 04000, EXACT) == 0) { /* 4000...0000? */\r | |
938 | a->fr[0] = 06000; /* chg to 6000... */\r | |
939 | a->exp = a->exp + 1; /* with exp+1 */\r | |
940 | return FALSE; /* don't round */\r | |
941 | }\r | |
942 | return TRUE;\r | |
943 | }\r | |
944 | \r | |
945 | /* Exact fp number copy */\r | |
946 | \r | |
947 | void fpp_copy (FPN *a, FPN *b)\r | |
948 | {\r | |
949 | uint32 i;\r | |
950 | \r | |
951 | if (!(fpp_sta & FPS_DP))\r | |
952 | a->exp = b->exp;\r | |
953 | for (i = 0; i < EXACT; i++)\r | |
954 | a->fr[i] = b->fr[i];\r | |
955 | return;\r | |
956 | }\r | |
957 | \r | |
958 | /* Zero extended fp number copy (60b) */\r | |
959 | \r | |
960 | void fpp_zcopy (FPN *a, FPN *b)\r | |
961 | {\r | |
962 | uint32 i;\r | |
963 | \r | |
964 | a->exp = b->exp;\r | |
965 | for (i = 0; i < FPN_NFR_EP; i++) {\r | |
966 | if ((i < FPN_NFR_FP) || (fpp_sta & FPS_EP))\r | |
967 | a->fr[i] = b->fr[i];\r | |
968 | else a->fr[i] = 0;\r | |
969 | }\r | |
970 | return;\r | |
971 | }\r | |
972 | \r | |
973 | /* Test exp for overflow or underflow, returns TRUE on trap */\r | |
974 | \r | |
975 | t_bool fpp_test_xp (FPN *a)\r | |
976 | {\r | |
977 | if (a->exp > 2047) { /* overflow? */\r | |
978 | fpp_dump_apt (fpp_apta, FPS_FOVX); /* trap */\r | |
979 | return TRUE;\r | |
980 | }\r | |
981 | if (a->exp < -2048) { /* underflow? */\r | |
982 | fpp_sta |= FPS_UNF; /* set flag */\r | |
983 | if (fpp_sta & FPS_UNFX) { /* trap? */\r | |
984 | fpp_dump_apt (fpp_apta, FPS_UNFX);\r | |
985 | return TRUE;\r | |
986 | }\r | |
987 | fpp_copy (a, &fpp_zero); /* flush to 0 */\r | |
988 | }\r | |
989 | return FALSE;\r | |
990 | }\r | |
991 | \r | |
992 | /* Round dp/fp value, returns carry out */\r | |
993 | \r | |
994 | uint32 fpp_round (FPN *a)\r | |
995 | {\r | |
996 | int32 i;\r | |
997 | uint32 cin, afr0_sign;\r | |
998 | \r | |
999 | if (fpp_sta & FPS_EP) /* ep? */\r | |
1000 | return FALSE; /* don't round */\r | |
1001 | afr0_sign = a->fr[0] & FPN_FRSIGN; /* save input sign */\r | |
1002 | cin = afr0_sign? 03777: 04000;\r | |
1003 | for (i = FPN_NFR_FP; i >= 0; i--) { /* 3 words */\r | |
1004 | a->fr[i] = a->fr[i] + cin; /* add in carry */\r | |
1005 | cin = (a->fr[i] >> 12) & 1;\r | |
1006 | a->fr[i] = a->fr[i] & 07777;\r | |
1007 | }\r | |
1008 | if (!(fpp_sta & FPS_DP) && /* fp? */\r | |
1009 | (afr0_sign ^ (a->fr[0] & FPN_FRSIGN))) { /* sign change? */\r | |
1010 | fpp_fr_rsh1 (a->fr, afr0_sign, EXACT); /* rsh, insert sign */\r | |
1011 | a->exp = a->exp + 1;\r | |
1012 | }\r | |
1013 | return cin;\r | |
1014 | }\r | |
1015 | \r | |
1016 | /* N-precision integer routines */\r | |
1017 | \r | |
1018 | /* Fraction add/sub - always carried out to 60b */\r | |
1019 | \r | |
1020 | uint32 fpp_fr_add (uint32 *c, uint32 *a, uint32 *b)\r | |
1021 | {\r | |
1022 | uint32 i, cin;\r | |
1023 | \r | |
1024 | for (i = FPN_NFR_EP, cin = 0; i > 0; i--) {\r | |
1025 | c[i - 1] = a[i - 1] + b[i - 1] + cin;\r | |
1026 | cin = (c[i - 1] >> 12) & 1;\r | |
1027 | c[i - 1] = c[i - 1] & 07777;\r | |
1028 | }\r | |
1029 | return cin;\r | |
1030 | }\r | |
1031 | \r | |
1032 | void fpp_fr_sub (uint32 *c, uint32 *a, uint32 *b)\r | |
1033 | {\r | |
1034 | uint32 i, cin;\r | |
1035 | \r | |
1036 | for (i = FPN_NFR_EP, cin = 0; i > 0; i--) {\r | |
1037 | c[i - 1] = a[i - 1] - b[i - 1] - cin;\r | |
1038 | cin = (c[i - 1] >> 12) & 1;\r | |
1039 | c[i - 1] = c[i - 1] & 07777;\r | |
1040 | }\r | |
1041 | return;\r | |
1042 | }\r | |
1043 | \r | |
1044 | /* Fraction multiply - always develop 60b, multiply is\r | |
1045 | either 24b*24b or 60b*60b\r | |
1046 | \r | |
1047 | This is a signed multiply. The shift in for signed multiply is\r | |
1048 | technically ALU_N XOR ALU_V. This can be simplified as follows:\r | |
1049 | \r | |
1050 | a-sign c-sign result-sign cout overflow N XOR V = shift in\r | |
1051 | \r | |
1052 | 0 0 0 0 0 0\r | |
1053 | 0 0 1 0 1 0\r | |
1054 | 0 1 0 1 0 0\r | |
1055 | 0 1 1 0 0 1\r | |
1056 | 1 0 0 1 0 0\r | |
1057 | 1 0 1 0 0 1\r | |
1058 | 1 1 0 1 1 1\r | |
1059 | 1 1 1 1 0 1\r | |
1060 | \r | |
1061 | If a-sign == c-sign, shift-in = a-sign\r | |
1062 | If a-sign != c-sign, shift-in = result-sign\r | |
1063 | */\r | |
1064 | \r | |
1065 | void fpp_fr_mul (uint32 *c, uint32 *a, uint32 *b)\r | |
1066 | {\r | |
1067 | uint32 i, cnt, lo, c_old, cin;\r | |
1068 | \r | |
1069 | fpp_fr_fill (c, 0, EXTEND); /* clr answer */\r | |
1070 | if (fpp_sta & FPS_EP) /* ep? */\r | |
1071 | lo = FPN_NFR_EP - 1; /* test <59> */\r | |
1072 | else lo = FPN_NFR_FP - 1; /* sp, test <23> */\r | |
1073 | cnt = (lo + 1) * 12; /* # iterations */\r | |
1074 | for (i = 0; i < cnt; i++) { /* loop thru mpcd */\r | |
1075 | c_old = c[0];\r | |
1076 | if (b[lo] & 1) /* mpcd bit set? */\r | |
1077 | fpp_fr_add (c, a, c); /* add mpyr */\r | |
1078 | cin = (((a[0] ^ c_old) & FPN_FRSIGN)? c[0]: a[0]) & FPN_FRSIGN;\r | |
1079 | fpp_fr_rsh1 (c, cin, EXTEND); /* shift answer */\r | |
1080 | fpp_fr_rsh1 (b, 0, EXACT); /* shift mpcd */\r | |
1081 | }\r | |
1082 | if (a[0] & FPN_FRSIGN) /* mpyr negative? */\r | |
1083 | fpp_fr_sub (c, c, a); /* adjust result */\r | |
1084 | return;\r | |
1085 | }\r | |
1086 | \r | |
1087 | /* Fraction divide */\r | |
1088 | \r | |
1089 | t_bool fpp_fr_div (uint32 *c, uint32 *a, uint32 *b)\r | |
1090 | {\r | |
1091 | uint32 i, old_c, lo, cnt, sign;\r | |
1092 | \r | |
1093 | fpp_fr_fill (c, 0, EXTEND); /* clr answer */\r | |
1094 | sign = (a[0] ^ b[0]) & FPN_FRSIGN; /* sign of result */\r | |
1095 | if (a[0] & FPN_FRSIGN) /* |a| */\r | |
1096 | fpp_fr_neg (a, EXACT);\r | |
1097 | if (b[0] & FPN_FRSIGN); /* |b| */\r | |
1098 | fpp_fr_neg (b, EXACT);\r | |
1099 | if (fpp_sta & FPS_EP) /* ep? 5 words */\r | |
1100 | lo = FPN_NFR_EP - 1;\r | |
1101 | else lo = FPN_NFR_FP; /* fp, dp? 3 words */\r | |
1102 | cnt = (lo + 1) * 12;\r | |
1103 | for (i = 0; i < cnt; i++) { /* loop */\r | |
1104 | fpp_fr_lsh1 (c, EXTEND); /* shift quotient */\r | |
1105 | if (fpp_fr_cmp (a, b, EXTEND) >= 0) { /* sub work? */\r | |
1106 | fpp_fr_sub (a, a, b); /* divd - divr */\r | |
1107 | if (a[0] & FPN_FRSIGN) /* sign flip? */\r | |
1108 | return TRUE; /* no, overflow */\r | |
1109 | c[lo] |= 1; /* set quo bit */\r | |
1110 | }\r | |
1111 | fpp_fr_lsh1 (a, EXTEND); /* shift dividend */\r | |
1112 | }\r | |
1113 | old_c = c[0]; /* save ho quo */\r | |
1114 | if (sign) /* expect neg ans? */\r | |
1115 | fpp_fr_neg (c, EXTEND); /* -quo */\r | |
1116 | if (old_c & FPN_FRSIGN) /* sign set before */\r | |
1117 | return TRUE; /* neg? */\r | |
1118 | return FALSE;\r | |
1119 | }\r | |
1120 | \r | |
1121 | /* Negate - 24b or 60b */\r | |
1122 | \r | |
1123 | uint32 fpp_fr_neg (uint32 *a, uint32 cnt)\r | |
1124 | {\r | |
1125 | uint32 i, cin;\r | |
1126 | \r | |
1127 | for (i = cnt, cin = 1; i > 0; i--) {\r | |
1128 | a[i - 1] = (~a[i - 1] + cin) & 07777;\r | |
1129 | cin = (a[i - 1] == 0);\r | |
1130 | }\r | |
1131 | return cin;\r | |
1132 | }\r | |
1133 | \r | |
1134 | /* Test (compare to x'0...0) - 24b or 60b */\r | |
1135 | \r | |
1136 | int32 fpp_fr_test (uint32 *a, uint32 v0, uint32 cnt)\r | |
1137 | {\r | |
1138 | uint32 i;\r | |
1139 | \r | |
1140 | if (a[0] != v0)\r | |
1141 | return (a[0] & FPN_FRSIGN)? -1: +1;\r | |
1142 | for (i = 1; i < cnt; i++) {\r | |
1143 | if (a[i] != 0)\r | |
1144 | return (a[0] & FPN_FRSIGN)? -1: +1;\r | |
1145 | }\r | |
1146 | return 0;\r | |
1147 | }\r | |
1148 | \r | |
1149 | /* Fraction compare - 24b or 60b */\r | |
1150 | \r | |
1151 | int32 fpp_fr_cmp (uint32 *a, uint32 *b, uint32 cnt)\r | |
1152 | {\r | |
1153 | uint32 i;\r | |
1154 | \r | |
1155 | if ((a[0] ^ b[0]) & FPN_FRSIGN)\r | |
1156 | return (b[0] & FPN_FRSIGN)? +1: -1;\r | |
1157 | for (i = 0; i < cnt; i++) {\r | |
1158 | if (a[i] > b[i])\r | |
1159 | return (b[0] & FPN_FRSIGN)? +1: -1;\r | |
1160 | if (a[i] < b[i])\r | |
1161 | return (b[0] & FPN_FRSIGN)? -1: +1;\r | |
1162 | }\r | |
1163 | return 0;\r | |
1164 | }\r | |
1165 | \r | |
1166 | /* Fraction fill */\r | |
1167 | \r | |
1168 | void fpp_fr_fill (uint32 *a, uint32 v, uint32 cnt)\r | |
1169 | {\r | |
1170 | uint32 i;\r | |
1171 | \r | |
1172 | for (i = 0; i < cnt; i++)\r | |
1173 | a[i] = v;\r | |
1174 | return;\r | |
1175 | }\r | |
1176 | \r | |
1177 | /* Left shift n (unsigned) */\r | |
1178 | \r | |
1179 | void fpp_fr_lshn (uint32 *a, uint32 sc, uint32 cnt)\r | |
1180 | {\r | |
1181 | uint32 i;\r | |
1182 | \r | |
1183 | if (sc >= (cnt * 12)) { /* out of range? */\r | |
1184 | fpp_fr_fill (a, 0, cnt);\r | |
1185 | return;\r | |
1186 | }\r | |
1187 | while (sc >= 12) { /* word shift? */\r | |
1188 | fpp_fr_lsh12 (a, cnt);\r | |
1189 | sc = sc - 12;\r | |
1190 | }\r | |
1191 | if (sc == 0) /* any more? */\r | |
1192 | return;\r | |
1193 | for (i = 1; i < cnt; i++) /* bit shift */\r | |
1194 | a[i - 1] = ((a[i - 1] << sc) | (a[i] >> (12 - sc))) & 07777;\r | |
1195 | a[cnt - 1] = (a[cnt - 1] << sc) & 07777;\r | |
1196 | return;\r | |
1197 | }\r | |
1198 | \r | |
1199 | /* Left shift 12b (unsigned) */\r | |
1200 | \r | |
1201 | void fpp_fr_lsh12 (uint32 *a, uint32 cnt)\r | |
1202 | {\r | |
1203 | uint32 i;\r | |
1204 | \r | |
1205 | for (i = 1; i < cnt; i++)\r | |
1206 | a[i - 1] = a[i];\r | |
1207 | a[cnt - 1] = 0;\r | |
1208 | return;\r | |
1209 | }\r | |
1210 | \r | |
1211 | /* Left shift 1b (unsigned) */\r | |
1212 | \r | |
1213 | void fpp_fr_lsh1 (uint32 *a, uint32 cnt)\r | |
1214 | {\r | |
1215 | uint32 i;\r | |
1216 | \r | |
1217 | for (i = 1; i < cnt; i++)\r | |
1218 | a[i - 1] = ((a[i - 1] << 1) | (a[i] >> 11)) & 07777;\r | |
1219 | a[cnt - 1] = (a[cnt - 1] << 1) & 07777;\r | |
1220 | return;\r | |
1221 | }\r | |
1222 | \r | |
1223 | /* Right shift 1b, with shift in */\r | |
1224 | \r | |
1225 | void fpp_fr_rsh1 (uint32 *a, uint32 sign, uint32 cnt)\r | |
1226 | {\r | |
1227 | uint32 i;\r | |
1228 | \r | |
1229 | for (i = cnt - 1; i > 0; i--)\r | |
1230 | a[i] = ((a[i] >> 1) | (a[i - 1] << 11)) & 07777;\r | |
1231 | a[0] = (a[0] >> 1) | sign;\r | |
1232 | return;\r | |
1233 | }\r | |
1234 | \r | |
1235 | /* Right shift n (signed) */\r | |
1236 | \r | |
1237 | void fpp_fr_algn (uint32 *a, uint32 sc, uint32 cnt)\r | |
1238 | {\r | |
1239 | uint32 i, sign;\r | |
1240 | \r | |
1241 | sign = (a[0] & FPN_FRSIGN)? 07777: 0;\r | |
1242 | if (sc >= (cnt * 12)) { /* out of range? */\r | |
1243 | fpp_fr_fill (a, sign, cnt);\r | |
1244 | return;\r | |
1245 | }\r | |
1246 | while (sc >= 12) {\r | |
1247 | for (i = cnt - 1; i > 0; i++)\r | |
1248 | a[i] = a[i - 1];\r | |
1249 | a[0] = sign;\r | |
1250 | sc = sc - 12;\r | |
1251 | }\r | |
1252 | if (sc == 0)\r | |
1253 | return;\r | |
1254 | for (i = cnt - 1; i > 0; i--)\r | |
1255 | a[i] = ((a[i] >> sc) | (a[i - 1] << (12 - sc))) & 07777;\r | |
1256 | a[0] = ((a[0] >> sc) | (sign << (12 - sc))) & 07777;\r | |
1257 | return;\r | |
1258 | }\r | |
1259 | \r | |
1260 | /* Read/write routines */\r | |
1261 | \r | |
1262 | void fpp_read_op (uint32 ea, FPN *a)\r | |
1263 | {\r | |
1264 | uint32 i;\r | |
1265 | \r | |
1266 | fpp_opa = ea;\r | |
1267 | if (!(fpp_sta & FPS_DP)) {\r | |
1268 | a->exp = fpp_read (ea++);\r | |
1269 | a->exp = SEXT12 (a->exp);\r | |
1270 | }\r | |
1271 | for (i = 0; i < EXACT; i++)\r | |
1272 | a->fr[i] = fpp_read (ea + i);\r | |
1273 | return;\r | |
1274 | }\r | |
1275 | \r | |
1276 | void fpp_write_op (uint32 ea, FPN *a)\r | |
1277 | {\r | |
1278 | uint32 i;\r | |
1279 | \r | |
1280 | fpp_opa = ea;\r | |
1281 | if (!(fpp_sta & FPS_DP))\r | |
1282 | fpp_write (ea++, a->exp);\r | |
1283 | for (i = 0; i < EXACT; i++)\r | |
1284 | fpp_write (ea + i, a->fr[i]);\r | |
1285 | return;\r | |
1286 | }\r | |
1287 | \r | |
1288 | uint32 fpp_read (uint32 ea)\r | |
1289 | {\r | |
1290 | ea = ea & ADDRMASK;\r | |
1291 | if (fpp_cmd & FPC_FIXF)\r | |
1292 | ea = fpp_aptsvf | (ea & 07777);\r | |
1293 | return M[ea];\r | |
1294 | }\r | |
1295 | \r | |
1296 | void fpp_write (uint32 ea, uint32 val)\r | |
1297 | {\r | |
1298 | ea = ea & ADDRMASK;\r | |
1299 | if (fpp_cmd & FPC_FIXF)\r | |
1300 | ea = fpp_aptsvf | (ea & 07777);\r | |
1301 | if (MEM_ADDR_OK (ea))\r | |
1302 | M[ea] = val & 07777;\r | |
1303 | return;\r | |
1304 | }\r | |
1305 | \r | |
1306 | uint32 apt_read (uint32 ea)\r | |
1307 | {\r | |
1308 | ea = ea & ADDRMASK;\r | |
1309 | return M[ea];\r | |
1310 | }\r | |
1311 | \r | |
1312 | void apt_write (uint32 ea, uint32 val)\r | |
1313 | {\r | |
1314 | ea = ea & ADDRMASK;\r | |
1315 | if (MEM_ADDR_OK (ea))\r | |
1316 | M[ea] = val & 07777;\r | |
1317 | return;\r | |
1318 | }\r | |
1319 | \r | |
1320 | /* Utility routines */\r | |
1321 | \r | |
1322 | void fpp_load_apt (uint32 ad)\r | |
1323 | {\r | |
1324 | uint32 wd0, i;\r | |
1325 | \r | |
1326 | wd0 = apt_read (ad++);\r | |
1327 | fpp_fpc = ((wd0 & 07) << 12) | apt_read (ad++);\r | |
1328 | if (FPC_GETFAST (fpp_cmd) != 017) {\r | |
1329 | fpp_xra = ((wd0 & 00070) << 9) | apt_read (ad++);\r | |
1330 | fpp_bra = ((wd0 & 00700) << 6) | apt_read (ad++);\r | |
1331 | ad++;\r | |
1332 | fpp_ac.exp = apt_read (ad++);\r | |
1333 | for (i = 0; i < EXACT; i++)\r | |
1334 | fpp_ac.fr[i] = apt_read (ad++);\r | |
1335 | }\r | |
1336 | fpp_aptsvf = (ad - 1) & 070000;\r | |
1337 | fpp_sta |= FPS_RUN;\r | |
1338 | return;\r | |
1339 | }\r | |
1340 | \r | |
1341 | void fpp_dump_apt (uint32 ad, uint32 sta)\r | |
1342 | {\r | |
1343 | uint32 wd0, i;\r | |
1344 | \r | |
1345 | wd0 = (fpp_fpc >> 12) & 07;\r | |
1346 | if (FPC_GETFAST (fpp_cmd) != 017)\r | |
1347 | wd0 = wd0 |\r | |
1348 | ((fpp_opa >> 3) & 07000) |\r | |
1349 | ((fpp_bra >> 6) & 00700) |\r | |
1350 | ((fpp_xra >> 9) & 00070);\r | |
1351 | apt_write (ad++, wd0);\r | |
1352 | apt_write (ad++, fpp_fpc);\r | |
1353 | if (FPC_GETFAST (fpp_cmd) != 017) {\r | |
1354 | apt_write (ad++, fpp_xra);\r | |
1355 | apt_write (ad++, fpp_bra);\r | |
1356 | apt_write (ad++, fpp_opa);\r | |
1357 | apt_write (ad++, fpp_ac.exp);\r | |
1358 | for (i = 0; i < EXACT; i++)\r | |
1359 | apt_write (ad++, fpp_ac.fr[i]);\r | |
1360 | }\r | |
1361 | fpp_sta = (fpp_sta | sta) & ~FPS_RUN;\r | |
1362 | fpp_flag = 1;\r | |
1363 | if (fpp_cmd & FPC_IE)\r | |
1364 | int_req |= INT_FPP;\r | |
1365 | return;\r | |
1366 | }\r | |
1367 | \r | |
1368 | /* Reset routine */\r | |
1369 | \r | |
1370 | t_stat fpp_reset (DEVICE *dptr)\r | |
1371 | {\r | |
1372 | sim_cancel (&fpp_unit);\r | |
1373 | fpp_sta = 0;\r | |
1374 | fpp_cmd = 0;\r | |
1375 | fpp_flag = 0;\r | |
1376 | int_req &= ~INT_FPP;\r | |
1377 | if (sim_switches & SWMASK ('P')) {\r | |
1378 | fpp_apta = 0;\r | |
1379 | fpp_aptsvf = 0;\r | |
1380 | fpp_fpc = 0;\r | |
1381 | fpp_bra = 0;\r | |
1382 | fpp_xra = 0;\r | |
1383 | fpp_opa = 0;\r | |
1384 | fpp_ac = fpp_zero;\r | |
1385 | }\r | |
1386 | return SCPE_OK;\r | |
1387 | }\r |