First Commit of my working state
[simh.git] / PDP8 / pdp8_fpp.c
CommitLineData
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
77extern int32 int_req;\r
78extern int32 sim_switches;\r
79extern int32 sim_interval;\r
80extern uint16 M[];\r
81extern int32 stop_inst;\r
82extern 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
130typedef struct {\r
131 int32 exp;\r
132 uint32 fr[FPN_NFR_EP];\r
133 } FPN;\r
134\r
135uint32 fpp_apta; /* APT pointer */\r
136uint32 fpp_aptsvf; /* APT saved field */\r
137uint32 fpp_opa; /* operand pointer */\r
138uint32 fpp_fpc; /* FP PC */\r
139uint32 fpp_bra; /* base reg pointer */\r
140uint32 fpp_xra; /* indx reg pointer */\r
141uint32 fpp_cmd; /* command */\r
142uint32 fpp_sta; /* status */\r
143uint32 fpp_flag; /* flag */\r
144FPN fpp_ac; /* FAC */\r
145static FPN fpp_zero = { 0, { 0, 0, 0, 0, 0 } };\r
146static FPN fpp_one = { 1, { 02000, 0, 0, 0, 0 } };\r
147\r
148DEVICE fpp_dev;\r
149int32 fpp55 (int32 IR, int32 AC);\r
150int32 fpp56 (int32 IR, int32 AC);\r
151void fpp_load_apt (uint32 apta);\r
152void fpp_dump_apt (uint32 apta, uint32 sta);\r
153uint32 fpp_1wd_dir (uint32 ir);\r
154uint32 fpp_2wd_dir (uint32 ir);\r
155uint32 fpp_indir (uint32 ir);\r
156uint32 fpp_ad15 (uint32 hi);\r
157uint32 fpp_adxr (uint32 ir, uint32 base_ad);\r
158t_bool fpp_add (FPN *a, FPN *b, uint32 sub);\r
159t_bool fpp_mul (FPN *a, FPN *b);\r
160t_bool fpp_div (FPN *a, FPN *b);\r
161t_bool fpp_imul (FPN *a, FPN *b);\r
162uint32 fpp_fr_add (uint32 *c, uint32 *a, uint32 *b);\r
163void fpp_fr_sub (uint32 *c, uint32 *a, uint32 *b);\r
164void fpp_fr_mul (uint32 *c, uint32 *a, uint32 *b);\r
165t_bool fpp_fr_div (uint32 *c, uint32 *a, uint32 *b);\r
166uint32 fpp_fr_neg (uint32 *a, uint32 cnt);\r
167int32 fpp_fr_cmp (uint32 *a, uint32 *b, uint32 cnt);\r
168int32 fpp_fr_test (uint32 *a, uint32 v0, uint32 cnt);\r
169uint32 fpp_fr_abs (uint32 *a, uint32 *b, uint32 cnt);\r
170void fpp_fr_fill (uint32 *a, uint32 v, uint32 cnt);\r
171void fpp_fr_lshn (uint32 *a, uint32 sc, uint32 cnt);\r
172void fpp_fr_lsh12 (uint32 *a, uint32 cnt);\r
173void fpp_fr_lsh1 (uint32 *a, uint32 cnt);\r
174void fpp_fr_rsh1 (uint32 *a, uint32 sign, uint32 cnt);\r
175void fpp_fr_algn (uint32 *a, uint32 sc, uint32 cnt);\r
176t_bool fpp_cond_met (uint32 cond);\r
177t_bool fpp_norm (FPN *a, uint32 cnt);\r
178uint32 fpp_round (FPN *a);\r
179t_bool fpp_test_xp (FPN *a);\r
180void fpp_copy (FPN *a, FPN *b);\r
181void fpp_zcopy (FPN *a, FPN *b);\r
182void fpp_read_op (uint32 ea, FPN *a);\r
183void fpp_write_op (uint32 ea, FPN *a);\r
184uint32 fpp_read (uint32 ea);\r
185void fpp_write (uint32 ea, uint32 val);\r
186uint32 apt_read (uint32 ea);\r
187void apt_write (uint32 ea, uint32 val);\r
188t_stat fpp_svc (UNIT *uptr);\r
189t_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
198DIB fpp_dib = { DEV_FPP, 2, { &fpp55, &fpp56 } };\r
199\r
200UNIT fpp_unit = { UDATA (&fpp_svc, 0, 0) };\r
201\r
202REG 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
221DEVICE 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
231int32 fpp55 (int32 IR, int32 AC)\r
232{\r
233switch (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
291return AC;\r
292}\r
293\r
294int32 fpp56 (int32 IR, int32 AC)\r
295{\r
296switch (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
307return AC;\r
308}\r
309\r
310/* Service routine */\r
311\r
312t_stat fpp_svc (UNIT *uptr)\r
313{\r
314FPN x;\r
315uint32 ir, op, op2, op3, ad, ea, wd;\r
316uint32 i;\r
317\r
318fpp_ac.exp = SEXT12 (fpp_ac.exp); /* sext AC exp */\r
319do { /* 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
684if ((fpp_sta & (FPS_RUN|FPS_PAUSE)) == FPS_RUN)\r
685 sim_activate (uptr, 1);\r
686fpp_ac.exp &= 07777; /* mask AC exp */\r
687return SCPE_OK;\r
688}\r
689\r
690/* Address decoding routines */\r
691\r
692uint32 fpp_1wd_dir (uint32 ir)\r
693{\r
694uint32 ad; \r
695\r
696ad = fpp_bra + ((ir & 0177) * 3); /* base + 3*7b off */\r
697if (fpp_sta & FPS_DP) /* dp? skip exp */\r
698 ad = ad + 1;\r
699return ad & ADDRMASK;\r
700}\r
701\r
702uint32 fpp_2wd_dir (uint32 ir)\r
703{\r
704uint32 ad;\r
705\r
706ad = fpp_ad15 (ir); /* get 15b addr */\r
707return fpp_adxr (ir, ad); /* do indexing */\r
708}\r
709\r
710uint32 fpp_indir (uint32 ir)\r
711{\r
712uint32 ad, iad, wd1, wd2;\r
713\r
714ad = fpp_bra + ((ir & 07) * 3); /* base + 3*3b off */\r
715iad = fpp_adxr (ir, ad); /* do indexing */\r
716wd1 = fpp_read (iad + 1); /* read wds 2,3 */\r
717wd2 = fpp_read (iad + 2);\r
718return ((wd1 & 07) << 12) | wd2; /* return addr */\r
719}\r
720\r
721uint32 fpp_ad15 (uint32 hi)\r
722{\r
723uint32 ad;\r
724\r
725ad = ((hi & 07) << 12) | fpp_read (fpp_fpc); /* 15b addr */\r
726fpp_fpc = (fpp_fpc + 1) & ADDRMASK; /* incr FPC */\r
727return ad; /* return addr */\r
728}\r
729\r
730uint32 fpp_adxr (uint32 ir, uint32 base_ad)\r
731{\r
732uint32 xr, wd;\r
733\r
734xr = (ir >> 3) & 07;\r
735wd = fpp_read_xr (xr); /* get xr */\r
736if (ir & 0100) { /* increment? */\r
737 wd = (wd + 1) & 07777; /* inc, rewrite */\r
738 fpp_write_xr (xr, wd);\r
739 }\r
740if (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
746else 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
753t_bool fpp_add (FPN *a, FPN *b, uint32 sub)\r
754{\r
755FPN x, y, z;\r
756uint32 ediff, c;\r
757\r
758fpp_zcopy (&x, a); /* copy opnds */\r
759fpp_zcopy (&y, b);\r
760if (sub) /* subtract? */\r
761 fpp_fr_neg (y.fr, EXACT); /* neg B, exact */\r
762if (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
769else { /* 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
799fpp_copy (a, &z); /* result is z */\r
800return FALSE;\r
801}\r
802\r
803/* Fraction/floating multiply - return true if overflow */\r
804\r
805t_bool fpp_mul (FPN *a, FPN *b)\r
806{\r
807FPN x, y, z;\r
808\r
809fpp_zcopy (&x, a); /* copy opnds */\r
810fpp_zcopy (&y, b);\r
811if (fpp_sta & FPS_DP) /* dp? */\r
812 fpp_fr_mul (z.fr, x.fr, y.fr); /* mult frac */\r
813else { /* 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
821fpp_copy (a, &z); /* result is z */\r
822return FALSE;\r
823}\r
824\r
825/* Fraction/floating divide - return true if div by zero or overflow */\r
826\r
827t_bool fpp_div (FPN *a, FPN *b)\r
828{\r
829FPN x, y, z;\r
830\r
831if (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
835if (fpp_fr_test (a->fr, 0, EXACT) == 0) /* dividend 0? */\r
836 return FALSE; /* quotient is 0 */\r
837fpp_zcopy (&x, a); /* copy opnds */\r
838fpp_zcopy (&y, b);\r
839if (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
845else { /* 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
862fpp_copy (a, &z); /* result is z */\r
863return FALSE;\r
864}\r
865\r
866/* Integer multiply - returns true if overflow */\r
867\r
868t_bool fpp_imul (FPN *a, FPN *b)\r
869{\r
870uint32 sext;\r
871FPN x, y, z;\r
872\r
873fpp_zcopy (&x, a); /* copy args */\r
874fpp_zcopy (&y, b);\r
875fpp_fr_mul (z.fr, x.fr, y.fr); /* mult fracs */\r
876sext = (z.fr[2] & FPN_FRSIGN)? 07777: 0;\r
877if (((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
882a->fr[0] = z.fr[2]; /* low 24b */\r
883a->fr[1] = z.fr[3];\r
884return FALSE;\r
885}\r
886\r
887/* Auxiliary floating point routines */\r
888\r
889t_bool fpp_cond_met (uint32 cond)\r
890{\r
891switch (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
917return 0;\r
918}\r
919\r
920/* Normalization - returns TRUE if rounding possible, FALSE if exact */\r
921\r
922t_bool fpp_norm (FPN *a, uint32 cnt)\r
923{\r
924if (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
928while (((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
933while (((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
937if (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
942return TRUE;\r
943}\r
944\r
945/* Exact fp number copy */\r
946\r
947void fpp_copy (FPN *a, FPN *b)\r
948{\r
949uint32 i;\r
950\r
951if (!(fpp_sta & FPS_DP))\r
952 a->exp = b->exp;\r
953for (i = 0; i < EXACT; i++)\r
954 a->fr[i] = b->fr[i];\r
955return;\r
956}\r
957\r
958/* Zero extended fp number copy (60b) */\r
959\r
960void fpp_zcopy (FPN *a, FPN *b)\r
961{\r
962uint32 i;\r
963\r
964a->exp = b->exp;\r
965for (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
970return;\r
971}\r
972\r
973/* Test exp for overflow or underflow, returns TRUE on trap */\r
974\r
975t_bool fpp_test_xp (FPN *a)\r
976{\r
977if (a->exp > 2047) { /* overflow? */\r
978 fpp_dump_apt (fpp_apta, FPS_FOVX); /* trap */\r
979 return TRUE;\r
980 }\r
981if (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
989return FALSE;\r
990}\r
991\r
992/* Round dp/fp value, returns carry out */\r
993\r
994uint32 fpp_round (FPN *a)\r
995{\r
996int32 i;\r
997uint32 cin, afr0_sign;\r
998\r
999if (fpp_sta & FPS_EP) /* ep? */\r
1000 return FALSE; /* don't round */\r
1001afr0_sign = a->fr[0] & FPN_FRSIGN; /* save input sign */\r
1002cin = afr0_sign? 03777: 04000;\r
1003for (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
1008if (!(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
1013return 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
1020uint32 fpp_fr_add (uint32 *c, uint32 *a, uint32 *b)\r
1021{\r
1022uint32 i, cin;\r
1023\r
1024for (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
1029return cin;\r
1030}\r
1031\r
1032void fpp_fr_sub (uint32 *c, uint32 *a, uint32 *b)\r
1033{\r
1034uint32 i, cin;\r
1035\r
1036for (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
1041return;\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
1065void fpp_fr_mul (uint32 *c, uint32 *a, uint32 *b)\r
1066{\r
1067uint32 i, cnt, lo, c_old, cin;\r
1068\r
1069fpp_fr_fill (c, 0, EXTEND); /* clr answer */\r
1070if (fpp_sta & FPS_EP) /* ep? */\r
1071 lo = FPN_NFR_EP - 1; /* test <59> */\r
1072else lo = FPN_NFR_FP - 1; /* sp, test <23> */\r
1073cnt = (lo + 1) * 12; /* # iterations */\r
1074for (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
1082if (a[0] & FPN_FRSIGN) /* mpyr negative? */\r
1083 fpp_fr_sub (c, c, a); /* adjust result */\r
1084return;\r
1085}\r
1086\r
1087/* Fraction divide */\r
1088\r
1089t_bool fpp_fr_div (uint32 *c, uint32 *a, uint32 *b)\r
1090{\r
1091uint32 i, old_c, lo, cnt, sign;\r
1092\r
1093fpp_fr_fill (c, 0, EXTEND); /* clr answer */\r
1094sign = (a[0] ^ b[0]) & FPN_FRSIGN; /* sign of result */\r
1095if (a[0] & FPN_FRSIGN) /* |a| */\r
1096 fpp_fr_neg (a, EXACT);\r
1097if (b[0] & FPN_FRSIGN); /* |b| */\r
1098 fpp_fr_neg (b, EXACT);\r
1099if (fpp_sta & FPS_EP) /* ep? 5 words */\r
1100 lo = FPN_NFR_EP - 1;\r
1101else lo = FPN_NFR_FP; /* fp, dp? 3 words */\r
1102cnt = (lo + 1) * 12;\r
1103for (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
1113old_c = c[0]; /* save ho quo */\r
1114if (sign) /* expect neg ans? */\r
1115 fpp_fr_neg (c, EXTEND); /* -quo */\r
1116if (old_c & FPN_FRSIGN) /* sign set before */\r
1117 return TRUE; /* neg? */\r
1118return FALSE;\r
1119}\r
1120\r
1121/* Negate - 24b or 60b */\r
1122\r
1123uint32 fpp_fr_neg (uint32 *a, uint32 cnt)\r
1124{\r
1125uint32 i, cin;\r
1126\r
1127for (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
1131return cin;\r
1132}\r
1133\r
1134/* Test (compare to x'0...0) - 24b or 60b */\r
1135\r
1136int32 fpp_fr_test (uint32 *a, uint32 v0, uint32 cnt)\r
1137{\r
1138uint32 i;\r
1139\r
1140if (a[0] != v0)\r
1141 return (a[0] & FPN_FRSIGN)? -1: +1;\r
1142for (i = 1; i < cnt; i++) {\r
1143 if (a[i] != 0)\r
1144 return (a[0] & FPN_FRSIGN)? -1: +1;\r
1145 }\r
1146return 0;\r
1147}\r
1148\r
1149/* Fraction compare - 24b or 60b */\r
1150\r
1151int32 fpp_fr_cmp (uint32 *a, uint32 *b, uint32 cnt)\r
1152{\r
1153uint32 i;\r
1154\r
1155if ((a[0] ^ b[0]) & FPN_FRSIGN)\r
1156 return (b[0] & FPN_FRSIGN)? +1: -1;\r
1157for (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
1163return 0;\r
1164}\r
1165\r
1166/* Fraction fill */\r
1167\r
1168void fpp_fr_fill (uint32 *a, uint32 v, uint32 cnt)\r
1169{\r
1170uint32 i;\r
1171\r
1172for (i = 0; i < cnt; i++)\r
1173 a[i] = v;\r
1174return;\r
1175}\r
1176\r
1177/* Left shift n (unsigned) */\r
1178\r
1179void fpp_fr_lshn (uint32 *a, uint32 sc, uint32 cnt)\r
1180{\r
1181uint32 i;\r
1182\r
1183if (sc >= (cnt * 12)) { /* out of range? */\r
1184 fpp_fr_fill (a, 0, cnt);\r
1185 return;\r
1186 }\r
1187while (sc >= 12) { /* word shift? */\r
1188 fpp_fr_lsh12 (a, cnt);\r
1189 sc = sc - 12;\r
1190 }\r
1191if (sc == 0) /* any more? */\r
1192 return;\r
1193for (i = 1; i < cnt; i++) /* bit shift */\r
1194 a[i - 1] = ((a[i - 1] << sc) | (a[i] >> (12 - sc))) & 07777;\r
1195a[cnt - 1] = (a[cnt - 1] << sc) & 07777;\r
1196return;\r
1197}\r
1198\r
1199/* Left shift 12b (unsigned) */\r
1200\r
1201void fpp_fr_lsh12 (uint32 *a, uint32 cnt)\r
1202{\r
1203uint32 i;\r
1204\r
1205for (i = 1; i < cnt; i++)\r
1206 a[i - 1] = a[i];\r
1207a[cnt - 1] = 0;\r
1208return;\r
1209}\r
1210\r
1211/* Left shift 1b (unsigned) */\r
1212\r
1213void fpp_fr_lsh1 (uint32 *a, uint32 cnt)\r
1214{\r
1215uint32 i;\r
1216\r
1217for (i = 1; i < cnt; i++)\r
1218 a[i - 1] = ((a[i - 1] << 1) | (a[i] >> 11)) & 07777;\r
1219a[cnt - 1] = (a[cnt - 1] << 1) & 07777;\r
1220return;\r
1221}\r
1222\r
1223/* Right shift 1b, with shift in */\r
1224\r
1225void fpp_fr_rsh1 (uint32 *a, uint32 sign, uint32 cnt)\r
1226{\r
1227uint32 i;\r
1228\r
1229for (i = cnt - 1; i > 0; i--)\r
1230 a[i] = ((a[i] >> 1) | (a[i - 1] << 11)) & 07777;\r
1231a[0] = (a[0] >> 1) | sign;\r
1232return;\r
1233}\r
1234\r
1235/* Right shift n (signed) */\r
1236\r
1237void fpp_fr_algn (uint32 *a, uint32 sc, uint32 cnt)\r
1238{\r
1239uint32 i, sign;\r
1240\r
1241sign = (a[0] & FPN_FRSIGN)? 07777: 0;\r
1242if (sc >= (cnt * 12)) { /* out of range? */\r
1243 fpp_fr_fill (a, sign, cnt);\r
1244 return;\r
1245 }\r
1246while (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
1252if (sc == 0)\r
1253 return;\r
1254for (i = cnt - 1; i > 0; i--)\r
1255 a[i] = ((a[i] >> sc) | (a[i - 1] << (12 - sc))) & 07777;\r
1256a[0] = ((a[0] >> sc) | (sign << (12 - sc))) & 07777;\r
1257return;\r
1258}\r
1259\r
1260/* Read/write routines */\r
1261\r
1262void fpp_read_op (uint32 ea, FPN *a)\r
1263{\r
1264uint32 i;\r
1265\r
1266fpp_opa = ea;\r
1267if (!(fpp_sta & FPS_DP)) {\r
1268 a->exp = fpp_read (ea++);\r
1269 a->exp = SEXT12 (a->exp);\r
1270 }\r
1271for (i = 0; i < EXACT; i++)\r
1272 a->fr[i] = fpp_read (ea + i);\r
1273return;\r
1274}\r
1275\r
1276void fpp_write_op (uint32 ea, FPN *a)\r
1277{\r
1278uint32 i;\r
1279\r
1280fpp_opa = ea;\r
1281if (!(fpp_sta & FPS_DP))\r
1282 fpp_write (ea++, a->exp);\r
1283for (i = 0; i < EXACT; i++)\r
1284 fpp_write (ea + i, a->fr[i]);\r
1285return;\r
1286}\r
1287\r
1288uint32 fpp_read (uint32 ea)\r
1289{\r
1290ea = ea & ADDRMASK;\r
1291if (fpp_cmd & FPC_FIXF)\r
1292 ea = fpp_aptsvf | (ea & 07777);\r
1293return M[ea];\r
1294}\r
1295\r
1296void fpp_write (uint32 ea, uint32 val)\r
1297{\r
1298ea = ea & ADDRMASK;\r
1299if (fpp_cmd & FPC_FIXF)\r
1300 ea = fpp_aptsvf | (ea & 07777);\r
1301if (MEM_ADDR_OK (ea))\r
1302 M[ea] = val & 07777;\r
1303return;\r
1304}\r
1305\r
1306uint32 apt_read (uint32 ea)\r
1307{\r
1308ea = ea & ADDRMASK;\r
1309return M[ea];\r
1310}\r
1311\r
1312void apt_write (uint32 ea, uint32 val)\r
1313{\r
1314ea = ea & ADDRMASK;\r
1315if (MEM_ADDR_OK (ea))\r
1316 M[ea] = val & 07777;\r
1317return;\r
1318}\r
1319\r
1320/* Utility routines */\r
1321\r
1322void fpp_load_apt (uint32 ad)\r
1323{\r
1324uint32 wd0, i;\r
1325\r
1326wd0 = apt_read (ad++);\r
1327fpp_fpc = ((wd0 & 07) << 12) | apt_read (ad++);\r
1328if (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
1336fpp_aptsvf = (ad - 1) & 070000;\r
1337fpp_sta |= FPS_RUN;\r
1338return;\r
1339}\r
1340\r
1341void fpp_dump_apt (uint32 ad, uint32 sta)\r
1342{\r
1343uint32 wd0, i;\r
1344\r
1345wd0 = (fpp_fpc >> 12) & 07;\r
1346if (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
1351apt_write (ad++, wd0);\r
1352apt_write (ad++, fpp_fpc);\r
1353if (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
1361fpp_sta = (fpp_sta | sta) & ~FPS_RUN;\r
1362fpp_flag = 1;\r
1363if (fpp_cmd & FPC_IE)\r
1364 int_req |= INT_FPP;\r
1365return;\r
1366}\r
1367\r
1368/* Reset routine */\r
1369\r
1370t_stat fpp_reset (DEVICE *dptr)\r
1371{\r
1372sim_cancel (&fpp_unit);\r
1373fpp_sta = 0;\r
1374fpp_cmd = 0;\r
1375fpp_flag = 0;\r
1376int_req &= ~INT_FPP;\r
1377if (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
1386return SCPE_OK;\r
1387}\r