First Commit of my working state
[simh.git] / HP2100 / hp2100_cpu7.c
CommitLineData
196ba1fc
PH
1/* hp2100_cpu7.c: HP 1000 VIS and SIGNAL/1000 microcode\r
2\r
3 Copyright (c) 2006, J. David Bryan\r
4 Copyright (c) 2008, Holger Veit\r
5\r
6 Permission is hereby granted, free of charge, to any person obtaining a\r
7 copy of this software and associated documentation files (the "Software"),\r
8 to deal in the Software without restriction, including without limitation\r
9 the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
10 and/or sell copies of the Software, and to permit persons to whom the\r
11 Software is furnished to do so, subject to the following conditions:\r
12\r
13 The above copyright notice and this permission notice shall be included in\r
14 all copies or substantial portions of the Software.\r
15\r
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
19 THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
20 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
22\r
23 Except as contained in this notice, the name of the authors shall not be\r
24 used in advertising or otherwise to promote the sale, use or other dealings\r
25 in this Software without prior written authorization from the authors.\r
26\r
27 CPU7 Vector Instruction Set and SIGNAL firmware\r
28\r
29 30-Apr-08 JDB Updated SIGNAL code from Holger\r
30 24-Apr-08 HV Implemented SIGNAL\r
31 20-Apr-08 JDB Updated comments\r
32 26-Feb-08 HV Implemented VIS\r
33\r
34 Primary references:\r
35 - HP 1000 M/E/F-Series Computers Technical Reference Handbook\r
36 (5955-0282, Mar-1980)\r
37 - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation\r
38 (92851-90001, Mar-1981)\r
39 - Macro/1000 Reference Manual (92059-90001, Dec-1992)\r
40\r
41 Additional references are listed with the associated firmware\r
42 implementations, as are the HP option model numbers pertaining to the\r
43 applicable CPUs.\r
44*/\r
45\r
46#include "hp2100_defs.h"\r
47#include "hp2100_cpu.h"\r
48#include "hp2100_cpu1.h"\r
49\r
50#if defined (HAVE_INT64) /* int64 support available */\r
51\r
52#include "hp2100_fp1.h"\r
53\r
54\r
55t_stat cpu_vis (uint32 IR, uint32 intrq); /* Vector Instruction Set */\r
56t_stat cpu_signal (uint32 IR, uint32 intrq); /* SIGNAL/1000 Instructions */\r
57\r
58static const OP zero = { { 0, 0, 0, 0, 0 } }; /* DEC 0.0D0 */\r
59\r
60\r
61/* Vector Instruction Set\r
62\r
63 The VIS provides instructions that operate on one-dimensional arrays of\r
64 floating-point values. Both single- and double-precision operations are\r
65 supported. VIS uses the F-Series floating-point processor to handle the\r
66 floating-point math.\r
67\r
68 Option implementation by CPU was as follows:\r
69\r
70 2114 2115 2116 2100 1000-M 1000-E 1000-F\r
71 ------ ------ ------ ------ ------ ------ ------\r
72 N/A N/A N/A N/A N/A N/A 12824A\r
73\r
74 The routines are mapped to instruction codes as follows:\r
75\r
76 Single-Precision Double-Precision\r
77 Instr. Opcode Subcod Instr. Opcode Subcod Description\r
78 ------ ------ ------ ------ ------ ------ -----------------------------\r
79 VADD 101460 000000 DVADD 105460 004002 Vector add\r
80 VSUB 101460 000020 DVSUB 105460 004022 Vector subtract\r
81 VMPY 101460 000040 DVMPY 105460 004042 Vector multiply\r
82 VDIV 101460 000060 DVDIV 105460 004062 Vector divide\r
83 VSAD 101460 000400 DVSAD 105460 004402 Scalar-vector add\r
84 VSSB 101460 000420 DVSSB 105460 004422 Scalar-vector subtract\r
85 VSMY 101460 000440 DVSMY 105460 004442 Scalar-vector multiply\r
86 VSDV 101460 000460 DVSDV 105460 004462 Scalar-vector divide\r
87 VPIV 101461 0xxxxx DVPIV 105461 0xxxxx Vector pivot\r
88 VABS 101462 0xxxxx DVABS 105462 0xxxxx Vector absolute value\r
89 VSUM 101463 0xxxxx DVSUM 105463 0xxxxx Vector sum\r
90 VNRM 101464 0xxxxx DVNRM 105464 0xxxxx Vector norm\r
91 VDOT 101465 0xxxxx DVDOT 105465 0xxxxx Vector dot product\r
92 VMAX 101466 0xxxxx DVMAX 105466 0xxxxx Vector maximum value\r
93 VMAB 101467 0xxxxx DVMAB 105467 0xxxxx Vector maximum absolute value\r
94 VMIN 101470 0xxxxx DVMIN 105470 0xxxxx Vector minimum value\r
95 VMIB 101471 0xxxxx DVMIB 105471 0xxxxx Vector minimum absolute value\r
96 VMOV 101472 0xxxxx DVMOV 105472 0xxxxx Vector move\r
97 VSWP 101473 0xxxxx DVSWP 105473 0xxxxx Vector swap\r
98 .ERES 101474 -- -- -- -- Resolve array element address\r
99 .ESEG 101475 -- -- -- -- Load MSEG maps\r
100 .VSET 101476 -- -- -- -- Vector setup\r
101 [test] -- -- -- 105477 -- [self test]\r
102\r
103 Instructions use IR bit 11 to select single- or double-precision format. The\r
104 double-precision instruction names begin with "D" (e.g., DVADD vs. VADD).\r
105 Most VIS instructions are two words in length, with a sub-opcode immediately\r
106 following the primary opcode.\r
107\r
108 Notes:\r
109\r
110 1. The .VECT (101460) and .DVCT (105460) opcodes preface a single- or\r
111 double-precision arithmetic operation that is determined by the\r
112 sub-opcode value. The remainder of the dual-precision sub-opcode values\r
113 are "don't care," except for requiring a zero in bit 15.\r
114\r
115 2. The VIS uses the hardware FPP of the F-Series. FPP malfunctions are\r
116 detected by the VIS firmware and are indicated by a memory-protect\r
117 violation and setting the overflow flag. Under simulation,\r
118 malfunctions cannot occur.\r
119\r
120 Additional references:\r
121 - 12824A Vector Instruction Set User's Manual (12824-90001, Jun-1979).\r
122 - VIS Microcode Source (12824-18059, revision 3).\r
123*/\r
124\r
125/* implemented in hp2100_cpu5.c (RTE-IV EMA functions) */\r
126extern t_stat cpu_ema_eres(uint32* rtn,uint32 dtbl,uint32 atbl, t_bool debug);\r
127extern t_stat cpu_ema_eseg(uint32* rtn,uint32 ir,uint32 tbl, t_bool debug);\r
128extern t_stat cpu_ema_vset(uint32* rtn,OPS op, t_bool debug);\r
129\r
130static const OP_PAT op_vis[16] = {\r
131 OP_N, OP_AAKAKAKK,OP_AKAKK, OP_AAKK, /* .VECT VPIV VABS VSUM */\r
132 OP_AAKK, OP_AAKAKK, OP_AAKK, OP_AAKK, /* VNRM VDOT VMAX VMAB */\r
133 OP_AAKK, OP_AAKK, OP_AKAKK, OP_AKAKK, /* VMIN VMIB VMOV VSWP */\r
134 OP_AA, OP_A, OP_AAACCC,OP_N /* .ERES .ESEG .VSET [test] */\r
135 };\r
136\r
137static const t_bool op_ftnret[16] = {\r
138 FALSE, TRUE, TRUE, TRUE,\r
139 TRUE, TRUE, TRUE, TRUE,\r
140 TRUE, TRUE, TRUE, TRUE,\r
141 FALSE, TRUE, TRUE, FALSE,\r
142 };\r
143\r
144\r
145/* handle the scalar/vector base ops */\r
146static void vis_svop(uint32 subcode, OPS op, OPSIZE opsize)\r
147{\r
148OP v1,v2;\r
149int16 delta = opsize==fp_f ? 2 : 4;\r
150OP s = ReadOp(op[0].word,opsize);\r
151uint32 v1addr = op[1].word;\r
152int16 ix1 = INT16(op[2].word) * delta;\r
153uint32 v2addr = op[3].word;\r
154int16 ix2 = INT16(op[4].word) * delta;\r
155int16 i, n = INT16(op[5].word);\r
156uint32 fpuop = (subcode & 060) | (opsize==fp_f ? 0 : 2);\r
157\r
158if (n <= 0) return;\r
159for (i=0; i<n; i++) {\r
160 v1 = ReadOp(v1addr, opsize);\r
161 (void)fp_exec(fpuop, &v2, s ,v1);\r
162 WriteOp(v2addr, v2, opsize);\r
163 v1addr += ix1;\r
164 v2addr += ix2;\r
165 }\r
166}\r
167\r
168/* handle the vector/vector base ops */\r
169static void vis_vvop(uint32 subcode, OPS op,OPSIZE opsize)\r
170{\r
171OP v1,v2,v3;\r
172int16 delta = opsize==fp_f ? 2 : 4;\r
173uint32 v1addr = op[0].word;\r
174int32 ix1 = INT16(op[1].word) * delta;\r
175uint32 v2addr = op[2].word;\r
176int32 ix2 = INT16(op[3].word) * delta;\r
177uint32 v3addr = op[4].word;\r
178int32 ix3 = INT16(op[5].word) * delta;\r
179int16 i, n = INT16(op[6].word);\r
180uint32 fpuop = (subcode & 060) | (opsize==fp_f ? 0 : 2);\r
181\r
182if (n <= 0) return;\r
183for (i=0; i<n; i++) {\r
184 v1 = ReadOp(v1addr, opsize);\r
185 v2 = ReadOp(v2addr, opsize);\r
186 (void)fp_exec(fpuop, &v3, v1 ,v2);\r
187 WriteOp(v3addr, v3, opsize);\r
188 v1addr += ix1;\r
189 v2addr += ix2;\r
190 v3addr += ix3;\r
191 }\r
192}\r
193\r
194#define GET_MSIGN(op) ((op)->fpk[0] & 0100000)\r
195\r
196static void vis_abs(OP* in, uint32 opsize)\r
197{\r
198uint32 sign = GET_MSIGN(in); /* get sign */\r
199if (sign) (void)fp_pcom(in, opsize); /* if negative, make positive */\r
200}\r
201\r
202static void vis_minmax(OPS op,OPSIZE opsize,t_bool domax,t_bool doabs)\r
203{\r
204OP v1,vmxmn,res;\r
205int16 delta = opsize==fp_f ? 2 : 4;\r
206uint32 mxmnaddr = op[0].word;\r
207uint32 v1addr = op[1].word;\r
208int16 ix1 = INT16(op[2].word) * delta;\r
209int16 n = INT16(op[3].word);\r
210int16 i,mxmn,sign;\r
211int32 subop = 020 | (opsize==fp_f ? 0 : 2);\r
212\r
213if (n <= 0) return;\r
214mxmn = 0; /* index of maxmin element */\r
215vmxmn = ReadOp(v1addr,opsize); /* initialize with first element */\r
216if (doabs) vis_abs(&vmxmn,opsize); /* ABS(v[1]) if requested */\r
217\r
218for (i = 0; i<n; i++) {\r
219 v1 = ReadOp(v1addr,opsize); /* get v[i] */\r
220 if (doabs) vis_abs(&v1,opsize); /* build ABS(v[i]) if requested */\r
221 (void)fp_exec(subop,&res,vmxmn,v1); /* subtract vmxmn - v1[i] */\r
222 sign = GET_MSIGN(&res); /* !=0 if vmxmn < v1[i] */\r
223 if ((domax && sign) || /* new max value found */\r
224 (!domax && !sign)) { /* new min value found */\r
225 mxmn = i;\r
226 vmxmn = v1; /* save the new max/min value */\r
227 }\r
228 v1addr += ix1; /* point to next element */\r
229 }\r
230res.word = mxmn+1; /* adjust to one-based FTN array */\r
231WriteOp(mxmnaddr, res, in_s); /* save result */\r
232}\r
233\r
234static void vis_vpiv(OPS op, OPSIZE opsize)\r
235{\r
236OP s,v1,v2,v3;\r
237int16 delta = opsize==fp_f ? 2 : 4;\r
238uint32 saddr = op[0].word;\r
239uint32 v1addr = op[1].word;\r
240int16 ix1 = INT16(op[2].word) * delta;\r
241uint32 v2addr = op[3].word;\r
242int16 ix2 = INT16(op[4].word) * delta;\r
243uint32 v3addr = op[5].word;\r
244int16 ix3 = INT16(op[6].word) * delta;\r
245int16 i, n = INT16(op[7].word);\r
246int16 oplen = opsize==fp_f ? 0 : 2;\r
247\r
248if (n <= 0) return;\r
249s = ReadOp(saddr,opsize);\r
250/* calculates v3[k] = s * v1[i] + v2[j] for incrementing i,j,k */\r
251for (i=0; i<n; i++) {\r
252 v1 = ReadOp(v1addr, opsize);\r
253 (void)fp_exec(040+oplen, ACCUM, s ,v1); /* ACCU := s*v1 */\r
254 v2 = ReadOp(v2addr, opsize);\r
255 (void)fp_exec(004+oplen,&v3,v2,NOP); /* v3 := v2 + s*v1 */\r
256 WriteOp(v3addr, v3, opsize); /* write result */\r
257 v1addr += ix1; /* forward to next array elements */\r
258 v2addr += ix2;\r
259 v3addr += ix3;\r
260 }\r
261}\r
262\r
263static void vis_vabs(OPS op, OPSIZE opsize)\r
264{\r
265OP v1;\r
266int16 delta = opsize==fp_f ? 2 : 4;\r
267uint32 v1addr = op[0].word;\r
268int16 ix1 = INT16(op[1].word) * delta;\r
269uint32 v2addr = op[2].word;\r
270int32 ix2 = INT16(op[3].word) * delta;\r
271int16 i,n = INT16(op[4].word);\r
272\r
273if (n <= 0) return;\r
274/* calculates v2[j] = ABS(v1[i]) for incrementing i,j */\r
275for (i=0; i<n; i++) {\r
276 v1 = ReadOp(v1addr, opsize);\r
277 vis_abs(&v1,opsize); /* make absolute value */\r
278 WriteOp(v2addr, v1, opsize); /* write result */\r
279 v1addr += ix1; /* forward to next array elements */\r
280 v2addr += ix2;\r
281 }\r
282}\r
283\r
284static void vis_trunc(OP* out, OP in)\r
285{\r
286/* Note there is fp_trun(), but this doesn't seem to do the same conversion\r
287 * as the original code does */\r
288out->fpk[0] = in.fpk[0];\r
289out->fpk[1] = (in.fpk[1] & 0177400) | (in.fpk[3] & 0377);\r
290}\r
291\r
292static void vis_vsmnm(OPS op,OPSIZE opsize,t_bool doabs)\r
293{\r
294uint32 fpuop;\r
295OP v1,sumnrm = zero;\r
296int16 delta = opsize==fp_f ? 2 : 4;\r
297uint32 saddr = op[0].word;\r
298uint32 v1addr = op[1].word;\r
299int16 ix1 = INT16(op[2].word) * delta;\r
300int16 i,n = INT16(op[3].word);\r
301\r
302if (n <= 0) return;\r
303/* calculates sumnrm = sumnrm + DBLE(v1[i]) resp DBLE(ABS(v1[i])) for incrementing i */\r
304for (i=0; i<n; i++) {\r
305 v1 = ReadOp(v1addr, opsize);\r
306 if (opsize==fp_f) (void)fp_cvt(&v1,fp_f,fp_t); /* cvt to DBLE(v1) */\r
307 fpuop = (doabs && GET_MSIGN(&v1)) ? 022 : 002; /* use subtract for NRM && V1<0 */\r
308 (void)fp_exec(fpuop,&sumnrm, sumnrm, v1); /* accumulate */\r
309 v1addr += ix1; /* forward to next array elements */\r
310 }\r
311if (opsize==fp_f)\r
312 (void)vis_trunc(&sumnrm,sumnrm); /* truncate to SNGL(sumnrm) */\r
313WriteOp(saddr, sumnrm, opsize); /* write result */\r
314}\r
315\r
316static void vis_vdot(OPS op,OPSIZE opsize)\r
317{\r
318OP v1,v2,dot = zero;\r
319int16 delta = opsize==fp_f ? 2 : 4;\r
320uint32 daddr = op[0].word;\r
321uint32 v1addr = op[1].word;\r
322int16 ix1 = INT16(op[2].word) * delta;\r
323uint32 v2addr = op[3].word;\r
324int16 ix2 = INT16(op[4].word) * delta;\r
325int16 i,n = INT16(op[5].word);\r
326\r
327if (n <= 0) return;\r
328/* calculates dot = dot + v1[i]*v2[j] for incrementing i,j */\r
329for (i=0; i<n; i++) {\r
330 v1 = ReadOp(v1addr, opsize);\r
331 if (opsize==fp_f) (void)fp_cvt(&v1,fp_f,fp_t); /* cvt to DBLE(v1) */\r
332 v2 = ReadOp(v2addr, opsize);\r
333 if (opsize==fp_f) (void)fp_cvt(&v2,fp_f,fp_t); /* cvt to DBLE(v2) */\r
334 (void)fp_exec(042,ACCUM, v1, v2); /* ACCU := v1 * v2 */\r
335 (void)fp_exec(006,&dot,dot,NOP); /* dot := dot + v1*v2 */\r
336 v1addr += ix1; /* forward to next array elements */\r
337 v2addr += ix2;\r
338 }\r
339if (opsize==fp_f)\r
340 (void)vis_trunc(&dot,dot); /* truncate to SNGL(sumnrm) */\r
341WriteOp(daddr, dot, opsize); /* write result */\r
342}\r
343\r
344static void vis_movswp(OPS op, OPSIZE opsize, t_bool doswp)\r
345{\r
346OP v1,v2;\r
347int16 delta = opsize==fp_f ? 2 : 4;\r
348uint32 v1addr = op[0].word;\r
349int16 ix1 = INT16(op[1].word) * delta;\r
350uint32 v2addr = op[2].word;\r
351int16 ix2 = INT16(op[3].word) * delta;\r
352int16 i,n = INT16(op[4].word);\r
353\r
354if (n <= 0) return;\r
355for (i=0; i<n; i++) {\r
356 v1 = ReadOp(v1addr, opsize);\r
357 v2 = ReadOp(v2addr, opsize);\r
358 WriteOp(v2addr, v1, opsize); /* v2 := v1 */\r
359 if (doswp) WriteOp(v1addr, v2, opsize); /* v1 := v2 */\r
360 v1addr += ix1; /* forward to next array elements */\r
361 v2addr += ix2;\r
362 }\r
363}\r
364\r
365t_stat cpu_vis (uint32 IR, uint32 intrq)\r
366{\r
367t_stat reason = SCPE_OK;\r
368OPS op;\r
369OP ret;\r
370uint32 entry, rtn, rtn1 = 0, subcode = 0;\r
371OP_PAT pattern;\r
372OPSIZE opsize;\r
373t_bool debug = DEBUG_PRI (cpu_dev, DEB_VIS);\r
374\r
375if ((cpu_unit.flags & UNIT_VIS) == 0) /* VIS option installed? */\r
376 return stop_inst;\r
377\r
378opsize = (IR & 004000) ? fp_t : fp_f; /* double or single precision */\r
379entry = IR & 017; /* mask to entry point */\r
380pattern = op_vis[entry];\r
381\r
382if (entry==0) { /* retrieve sub opcode */\r
383 ret = ReadOp (PC, in_s); /* get it */\r
384 subcode = ret.word;\r
385 if (subcode & 0100000) /* special property of ucode */\r
386 subcode = AR; /* for reentry */ \r
387 PC = (PC + 1) & VAMASK; /* bump to real argument list */\r
388 pattern = (subcode & 0400) ? OP_AAKAKK : OP_AKAKAKK; /* scalar or vector operation */\r
389}\r
390\r
391if (pattern != OP_N)\r
392 if (op_ftnret[entry]) { /* most VIS instrs ignore RTN addr */\r
393 ret = ReadOp(PC, in_s);\r
394 rtn = rtn1 = ret.word; /* but save it just in case */\r
395 PC = (PC + 1) & VAMASK; /* move to next argument */\r
396 }\r
397 if (reason = cpu_ops (pattern, op, intrq)) /* get instruction operands */\r
398 return reason;\r
399\r
400if (debug) { /* debugging? */\r
401 fprintf (sim_deb, ">>CPU VIS: IR = %06o/%06o (", /* print preamble and IR */\r
402 IR, subcode);\r
403 fprint_sym (sim_deb, err_PC, (t_value *) &IR, /* print instruction mnemonic */\r
404 NULL, SWMASK('M'));\r
405 fprintf (sim_deb, "), P = %06o", err_PC); /* print location */\r
406 fprint_ops (pattern, op); /* print operands */\r
407 fputc ('\n', sim_deb); /* terminate line */\r
408 }\r
409\r
410switch (entry) { /* decode IR<3:0> */\r
411 case 000: /* .VECT (OP_special) */\r
412 if (subcode & 0400)\r
413 vis_svop(subcode,op,opsize); /* scalar/vector op */\r
414 else\r
415 vis_vvop(subcode,op,opsize); /* vector/vector op */\r
416 break;\r
417 case 001: /* VPIV (OP_(A)AAKAKAKK) */\r
418 vis_vpiv(op,opsize);\r
419 break;\r
420 case 002: /* VABS (OP_(A)AKAKK) */\r
421 vis_vabs(op,opsize);\r
422 break;\r
423 case 003: /* VSUM (OP_(A)AAKK) */\r
424 vis_vsmnm(op,opsize,FALSE);\r
425 break;\r
426 case 004: /* VNRM (OP_(A)AAKK) */\r
427 vis_vsmnm(op,opsize,TRUE);\r
428 break;\r
429 case 005: /* VDOT (OP_(A)AAKAKK) */\r
430 vis_vdot(op,opsize);\r
431 break;\r
432 case 006: /* VMAX (OP_(A)AAKK) */\r
433 vis_minmax(op,opsize,TRUE,FALSE);\r
434 break;\r
435 case 007: /* VMAB (OP_(A)AAKK) */\r
436 vis_minmax(op,opsize,TRUE,TRUE);\r
437 break;\r
438 case 010: /* VMIN (OP_(A)AAKK) */\r
439 vis_minmax(op,opsize,FALSE,FALSE);\r
440 break;\r
441 case 011: /* VMIB (OP_(A)AAKK) */\r
442 vis_minmax(op,opsize,FALSE,TRUE);\r
443 break;\r
444 case 012: /* VMOV (OP_(A)AKAKK) */\r
445 vis_movswp(op,opsize,FALSE);\r
446 break;\r
447 case 013: /* VSWP (OP_(A)AKAKK) */\r
448 vis_movswp(op,opsize,TRUE);\r
449 break;\r
450 case 014: /* .ERES (OP_(A)AA) */\r
451 reason = cpu_ema_eres(&rtn,op[2].word,PC,debug); /* handle the ERES instruction */\r
452 PC = rtn;\r
453 if (debug)\r
454 fprintf (sim_deb, \r
455 ">>CPU VIS: return .ERES: AR = %06o, BR = %06o, rtn=%s\n",\r
456 AR, BR, PC==op[0].word ? "error" : "good");\r
457 break;\r
458\r
459 case 015: /* .ESEG (OP_(A)A) */\r
460 reason = cpu_ema_eseg(&rtn,IR,op[0].word,debug); /* handle the ESEG instruction */ \r
461 PC = rtn;\r
462 if (debug)\r
463 fprintf (sim_deb,\r
464 ">>CPU VIS: return .ESEG: AR = %06o , BR = %06o, rtn=%s\n",\r
465 AR, BR, rtn==rtn1 ? "error" : "good");\r
466 break;\r
467\r
468 case 016: /* .VSET (OP_(A)AAACCC) */\r
469 reason = cpu_ema_vset(&rtn,op,debug);\r
470 PC = rtn;\r
471 if (debug)\r
472 fprintf (sim_deb, ">>CPU VIS: return .VSET: AR = %06o BR = %06o, rtn=%s\n",\r
473 AR, BR, \r
474 rtn==rtn1 ? "error" : (rtn==(rtn1+1) ? "hard" : "easy") );\r
475 break;\r
476\r
477 case 017: /* [test] (OP_N) */\r
478 XR = 3; /* firmware revision */\r
479 SR = 0102077; /* test passed code */\r
480 PC = (PC + 1) & VAMASK; /* P+2 return for firmware w/VIS */\r
481 break;\r
482 default: /* others undefined */\r
483 reason = stop_inst;\r
484 }\r
485\r
486return reason;\r
487}\r
488\r
489\r
490/* SIGNAL/1000 Instructions\r
491\r
492 The SIGNAL/1000 instructions provide fast Fourier transforms and complex\r
493 arithmetic. They utilize the F-Series floating-point processor and the\r
494 Vector Instruction Set.\r
495\r
496 Option implementation by CPU was as follows:\r
497\r
498 2114 2115 2116 2100 1000-M 1000-E 1000-F\r
499 ------ ------ ------ ------ ------ ------ ------\r
500 N/A N/A N/A N/A N/A N/A 92835A\r
501\r
502 The routines are mapped to instruction codes as follows:\r
503\r
504 Instr. 1000-F Description\r
505 ------ ------ ----------------------------------------------\r
506 BITRV 105600 Bit reversal\r
507 BTRFY 105601 Butterfly algorithm\r
508 UNSCR 105602 Unscramble for phasor MPY\r
509 PRSCR 105603 Unscramble for phasor MPY\r
510 BITR1 105604 Swap two elements in array (alternate format)\r
511 BTRF1 105605 Butterfly algorithm (alternate format)\r
512 .CADD 105606 Complex number addition\r
513 .CSUB 105607 Complex number subtraction\r
514 .CMPY 105610 Complex number multiplication\r
515 .CDIV 105611 Complex number division\r
516 CONJG 105612 Complex conjugate\r
517 ..CCM 105613 Complex complement\r
518 AIMAG 105614 Return imaginary part\r
519 CMPLX 105615 Form complex number\r
520 [nop] 105616 [no operation]\r
521 [test] 105617 [self test]\r
522\r
523 Notes:\r
524\r
525 1. SIGNAL/1000 ROM data are available from Bitsavers.\r
526\r
527 Additional references (documents unavailable):\r
528 - HP Signal/1000 User Reference and Installation Manual (92835-90002).\r
529 - SIGNAL/1000 Microcode Source (92835-18075, revision 2).\r
530*/\r
531\r
532#define RE(x) (x+0)\r
533#define IM(x) (x+2)\r
534\r
535static const OP_PAT op_signal[16] = {\r
536 OP_AAKK, OP_AAFFKK, OP_AAFFKK,OP_AAFFKK, /* BITRV BTRFY UNSCR PRSCR */\r
537 OP_AAAKK, OP_AAAFFKK,OP_AAA, OP_AAA, /* BITR1 BTRF1 .CADD .CSUB */\r
538 OP_AAA, OP_AAA, OP_AAA, OP_A, /* .CMPY .CDIV CONJG ..CCM */\r
539 OP_AA, OP_AAFF, OP_N, OP_N /* AIMAG CMPLX --- [test]*/\r
540 };\r
541\r
542/* complex addition helper */\r
543static void sig_caddsub(uint32 addsub,OPS op)\r
544{\r
545OP a,b,c,d,p1,p2;\r
546\r
547a = ReadOp(RE(op[1].word), fp_f); /* read 1st op */\r
548b = ReadOp(IM(op[1].word), fp_f);\r
549c = ReadOp(RE(op[2].word), fp_f); /* read 2nd op */\r
550d = ReadOp(IM(op[2].word), fp_f);\r
551(void)fp_exec(addsub,&p1, a, c); /* add real */\r
552(void)fp_exec(addsub,&p2, b, d); /* add imag */\r
553WriteOp(RE(op[0].word), p1, fp_f); /* write result */\r
554WriteOp(IM(op[0].word), p2, fp_f); /* write result */\r
555}\r
556\r
557/* butterfly operation helper */\r
558static void sig_btrfy(uint32 re,uint32 im,OP wr,OP wi,uint32 k, uint32 n2)\r
559{\r
560/*\r
561 * v(k)-------->o-->o----> v(k)\r
562 * \ /\r
563 * x\r
564 * / \ \r
565 * v(k+N/2)---->o-->o----> v(k+N/2)\r
566 * Wn -1\r
567 * \r
568 */\r
569\r
570OP p1,p2,p3,p4;\r
571OP v1r = ReadOp(re+k, fp_f); /* read v1 */\r
572OP v1i = ReadOp(im+k, fp_f);\r
573OP v2r = ReadOp(re+k+n2, fp_f); /* read v2 */\r
574OP v2i = ReadOp(im+k+n2, fp_f);\r
575\r
576/* (p1,p2) := cmul(w,v2) */\r
577(void)fp_exec(040, &p1, wr, v2r); /* S7,8 p1 := wr*v2r */\r
578(void)fp_exec(040, ACCUM, wi, v2i); /* ACCUM := wi*v2i */\r
579(void)fp_exec(024, &p1, p1, NOP); /* S7,S8 p1 := wr*v2r-wi*v2i ==real(w*v2) */\r
580(void)fp_exec(040, &p2, wi, v2r); /* S9,10 p2 := wi*v2r */\r
581(void)fp_exec(040, ACCUM, wr, v2i); /* ACCUM := wr*v2i */\r
582(void)fp_exec(004, &p2, p2, NOP); /* S9,10 p2 := wi*v2r+wr*v2i ==imag(w*v2) */\r
583/* v2 := v1 - (p1,p2) */\r
584(void)fp_exec(020, &p3, v1r, p1); /* v2r := v1r-real(w*v2) */\r
585(void)fp_exec(020, &p4, v1i, p2); /* v2i := v1i-imag(w*v2) */\r
586WriteOp(re+k+n2, p3, fp_f); /* write v2r */\r
587WriteOp(im+k+n2, p4, fp_f); /* write v2i */\r
588/* v1 := v1 + (p1,p2) */\r
589(void)fp_exec(0, &p3, v1r, p1); /* v1r := v1r+real(w*v2) */\r
590(void)fp_exec(0, &p4, v1i, p2); /* v1i := v1i+imag(w*v2) */\r
591WriteOp(re+k, p3, fp_f); /* write v1r */\r
592WriteOp(im+k, p4, fp_f); /* write v1i */\r
593O = 0;\r
594}\r
595\r
596/* helper for bit reversal\r
597 * idx is 0-based already */\r
598static void sig_bitrev(uint32 re,uint32 im, uint32 idx, uint32 log2n, int sz)\r
599{\r
600uint32 i, org=idx, rev = 0;\r
601OP v1r,v1i,v2r,v2i;\r
602\r
603for (i=0; i<log2n; i++) { /* swap bits of idx */\r
604 rev = (rev<<1) | (org & 1); /* into rev */\r
605 org >>= 1;\r
606}\r
607\r
608if (rev < idx) return; /* avoid swapping same pair twice in loop */\r
609\r
610idx *= sz; /* adjust for element size */\r
611rev *= sz; /* (REAL*4 vs COMPLEX*8) */\r
612\r
613v1r = ReadOp(re+idx, fp_f); /* read 1st element */ \r
614v1i = ReadOp(im+idx, fp_f);\r
615v2r = ReadOp(re+rev, fp_f); /* read 2nd element */\r
616v2i = ReadOp(im+rev, fp_f);\r
617WriteOp(re+idx, v2r, fp_f); /* swap elements */\r
618WriteOp(im+idx, v2i, fp_f);\r
619WriteOp(re+rev, v1r, fp_f);\r
620WriteOp(im+rev, v1i, fp_f);\r
621}\r
622\r
623/* helper for PRSCR/UNSCR */\r
624static OP sig_scadd(uint32 oper,t_bool addh, OP a, OP b)\r
625{\r
626OP r;\r
627static const OP plus_half = { { 0040000, 0000000 } }; /* DEC +0.5 */\r
628\r
629(void)fp_exec(oper,&r,a,b); /* calculate r := a +/- b */\r
630if (addh) (void)fp_exec(044,&r,plus_half,NOP); /* if addh set, multiply by 0.5 */\r
631return r;\r
632}\r
633\r
634/* complex multiply helper */\r
635static void sig_cmul(OP *r, OP *i, OP a, OP b, OP c, OP d)\r
636{\r
637OP p;\r
638(void)fp_exec(040, &p , a, c); /* p := ac */\r
639(void)fp_exec(040, ACCUM, b, d); /* ACCUM := bd */\r
640(void)fp_exec(024, r, p , NOP); /* real := ac-bd */\r
641(void)fp_exec(040, &p, a, d); /* p := ad */\r
642(void)fp_exec(040, ACCUM, b, c); /* ACCUM := bc */\r
643(void)fp_exec(004, i, p, NOP); /* imag := ad+bc */\r
644}\r
645\r
646t_stat cpu_signal (uint32 IR, uint32 intrq)\r
647{\r
648t_stat reason = SCPE_OK;\r
649OPS op;\r
650OP a,b,c,d,p1,p2,p3,p4,m1,m2,wr,wi;\r
651uint32 entry, v, idx1, idx2;\r
652int32 exc, exd;\r
653\r
654t_bool debug = DEBUG_PRI (cpu_dev, DEB_SIG);\r
655if ((cpu_unit.flags & UNIT_SIGNAL) == 0) /* SIGNAL option installed? */\r
656 return stop_inst;\r
657\r
658entry = IR & 017; /* mask to entry point */\r
659\r
660if (op_signal[entry] != OP_N)\r
661 if (reason = cpu_ops (op_signal[entry], op, intrq)) /* get instruction operands */\r
662 return reason;\r
663\r
664if (debug) { /* debugging? */\r
665 fprintf (sim_deb, ">>CPU SIG: IR = %06o (", IR); /* print preamble and IR */\r
666 fprint_sym (sim_deb, err_PC, (t_value *) &IR, /* print instruction mnemonic */\r
667 NULL, SWMASK('M'));\r
668 fprintf (sim_deb, "), P = %06o", err_PC); /* print location */\r
669 fprint_ops (op_signal[entry], op); /* print operands */\r
670 fputc ('\n', sim_deb); /* terminate line */\r
671 }\r
672\r
673switch (entry) { /* decode IR<3:0> */\r
674 case 000: /* BITRV (OP_AAKK) */\r
675 /* BITRV\r
676 * bit reversal for FFT\r
677 * JSB BITRV\r
678 * DEF ret(,I) return address\r
679 * DEF vect,I base address of array\r
680 * DEF idx,I index bitmap to be reversed (one-based)\r
681 * DEF nbits,I number of bits of index\r
682 *\r
683 * Given a complex*8 vector of nbits (power of 2), this calculates:\r
684 * swap( vect[idx], vect[rev(idx)]) where rev(i) is the bitreversed value of i */\r
685 sig_bitrev(op[1].word, op[1].word+2, op[2].word-1, op[3].word, 4);\r
686 PC = op[0].word & VAMASK;\r
687 break;\r
688 \r
689 case 001: /* BTRFY (OP_AAFFKK) */\r
690 /* BTRFY - butterfly operation\r
691 * JSB BTRFY\r
692 * DEF ret(,I) return address\r
693 * DEF vect(,I) complex*8 vector\r
694 * DEF wr,I real part of W\r
695 * DEF wi,I imag part of W\r
696 * DEF node,I index of 1st op (1 based)\r
697 * DEF lmax,I offset to 2nd op (0 based) */\r
698 sig_btrfy(op[1].word, op[1].word+2,\r
699 op[2], op[3], \r
700 2*(op[4].word-1), 2*op[5].word);\r
701 PC = op[0].word & VAMASK;\r
702 break;\r
703\r
704 case 002: /* UNSCR (OP_AAFFKK) */\r
705 /* UNSCR unscramble for phasor MPY\r
706 * JSB UNSCR\r
707 * DEF ret(,I)\r
708 * DEF vector,I\r
709 * DEF WR\r
710 * DEF WI\r
711 * DEF idx1,I\r
712 * DEF idx2,I */\r
713 v = op[1].word;\r
714 idx1 = 2 * (op[4].word - 1);\r
715 idx2 = 2 * (op[5].word - 1);\r
716 wr = op[2]; /* read WR */\r
717 wi = op[3]; /* read WI */\r
718 p1 = ReadOp(RE(v + idx1), fp_f); /* S1 VR[idx1] */\r
719 p2 = ReadOp(RE(v + idx2), fp_f); /* S2 VR[idx2] */\r
720 p3 = ReadOp(IM(v + idx1), fp_f); /* S9 VI[idx1] */\r
721 p4 = ReadOp(IM(v + idx2), fp_f); /* S10 VI[idx2] */\r
722 c = sig_scadd(000, TRUE, p3, p4); /* S5,6 0.5*(p3+p4) */\r
723 d = sig_scadd(020, TRUE, p2, p1); /* S7,8 0.5*(p2-p1) */\r
724 sig_cmul(&m1, &m2, wr, wi, c, d); /* (WR,WI) * (c,d) */\r
725 c = sig_scadd(000, TRUE, p1, p2); /* 0.5*(p1+p2) */\r
726 d = sig_scadd(020, TRUE, p3, p4); /* 0.5*(p3-p4) */\r
727 (void)fp_exec(000, &p1, c, m1); /* VR[idx1] := 0.5*(p1+p2) + real(W*(c,d)) */ \r
728 WriteOp(RE(v + idx1), p1, fp_f); \r
729 (void)fp_exec(000, &p2, d, m2); /* VI[idx1] := 0.5*(p3-p4) + imag(W*(c,d)) */\r
730 WriteOp(IM(v + idx1), p2, fp_f); \r
731 (void)fp_exec(020, &p1, c, m1); /* VR[idx2] := 0.5*(p1+p2) - imag(W*(c,d)) */\r
732 WriteOp(RE(v + idx2), p1, fp_f); \r
733 (void)fp_exec(020, &p2, d, m2); /* VI[idx2] := 0.5*(p3-p4) - imag(W*(c,d)) */\r
734 WriteOp(IM(v + idx2), p2, fp_f); \r
735 PC = op[0].word & VAMASK;\r
736 break; \r
737 \r
738 case 003: /* PRSCR (OP_AAFFKK) */\r
739 /* PRSCR unscramble for phasor MPY\r
740 * JSB PRSCR\r
741 * DEF ret(,I)\r
742 * DEF vector,I\r
743 * DEF WR\r
744 * DEF WI\r
745 * DEF idx1,I\r
746 * DEF idx2,I */\r
747 v = op[1].word;\r
748 idx1 = 2 * (op[4].word - 1);\r
749 idx2 = 2 * (op[5].word - 1);\r
750 wr = op[2]; /* read WR */\r
751 wi = op[3]; /* read WI */\r
752 p1 = ReadOp(RE(v + idx1), fp_f); /* VR[idx1] */\r
753 p2 = ReadOp(RE(v + idx2), fp_f); /* VR[idx2] */\r
754 p3 = ReadOp(IM(v + idx1), fp_f); /* VI[idx1] */\r
755 p4 = ReadOp(IM(v + idx2), fp_f); /* VI[idx2] */\r
756 c = sig_scadd(020, FALSE, p1, p2); /* p1-p2 */\r
757 d = sig_scadd(000, FALSE, p3, p4); /* p3+p4 */ \r
758 sig_cmul(&m1,&m2, wr, wi, c, d); /* (WR,WI) * (c,d) */\r
759 c = sig_scadd(000, FALSE, p1, p2); /* p1+p2 */\r
760 d = sig_scadd(020, FALSE, p3,p4); /* p3-p4 */\r
761 (void)fp_exec(020, &p1, c, m2); /* VR[idx1] := (p1-p2) - imag(W*(c,d)) */\r
762 WriteOp(RE(v + idx1), p1, fp_f); \r
763 (void)fp_exec(000, &p2, d, m1); /* VI[idx1] := (p3-p4) + real(W*(c,d)) */ \r
764 WriteOp(IM(v + idx1), p2, fp_f); \r
765 (void)fp_exec(000, &p1, c, m2); /* VR[idx2] := (p1+p2) + imag(W*(c,d)) */\r
766 WriteOp(RE(v + idx2), p1, fp_f); \r
767 (void)fp_exec(020, &p2, m1, d); /* VI[idx2] := imag(W*(c,d)) - (p3-p4) */\r
768 WriteOp(IM(v + idx2), p2, fp_f); \r
769 PC = op[0].word & VAMASK;\r
770 break;\r
771\r
772 case 004: /* BITR1 (OP_AAAKK) */\r
773 /* BITR1\r
774 * bit reversal for FFT, alternative version\r
775 * JSB BITR1\r
776 * DEF ret(,I) return address if already swapped\r
777 * DEF revect,I base address of real vect\r
778 * DEF imvect,I base address of imag vect\r
779 * DEF idx,I index bitmap to be reversed (one-based)\r
780 * DEF nbits,I number of bits of index\r
781 *\r
782 * Given a complex*8 vector of nbits (power of 2), this calculates:\r
783 * swap( vect[idx], vect[rev(idx)]) where rev(i) is the bitreversed value of i\r
784 *\r
785 * difference to BITRV is that BITRV uses complex*8, and BITR1 uses separate real*4\r
786 * vectors for Real and Imag parts */\r
787 sig_bitrev(op[1].word, op[2].word, op[3].word-1, op[4].word, 2);\r
788 PC = op[0].word & VAMASK;\r
789 break;\r
790\r
791 \r
792 case 005: /* BTRF1 (OP_AAAFFKK) */\r
793 /* BTRF1 - butterfly operation with real*4 vectors\r
794 * JSB BTRF1\r
795 * DEF ret(,I) return address\r
796 * DEF rvect,I real part of vector\r
797 * DEF ivect,I imag part of vector\r
798 * DEF wr,I real part of W\r
799 * DEF wi,I imag part of W\r
800 * DEF node,I index (1 based)\r
801 * DEF lmax,I index (0 based) */\r
802 sig_btrfy(op[1].word, op[2].word,\r
803 op[3], op[4],\r
804 op[5].word-1, op[6].word);\r
805 PC = op[0].word & VAMASK;\r
806 break;\r
807 \r
808 case 006: /* .CADD (OP_AAA) */\r
809 /* .CADD Complex addition\r
810 * JSB .CADD\r
811 * DEF result,I\r
812 * DEF oprd1,I\r
813 * DEF oprd2,I\r
814 * complex addition is: (a+bi) + (c+di) => (a+c) + (b+d)i */\r
815 sig_caddsub(000,op);\r
816 break;\r
817 \r
818 case 007: /* .CSUB (OP_AAA) */\r
819 /* .CSUB Complex subtraction\r
820 * JSB .CSUB\r
821 * DEF result,I\r
822 * DEF oprd1,I\r
823 * DEF oprd2,I\r
824 * complex subtraction is: (a+bi) - (c+di) => (a - c) + (b - d)i */\r
825 sig_caddsub(020,op);\r
826 break;\r
827\r
828 case 010: /* .CMUL (OP_AAA) */\r
829 /* .CMPY Complex multiplication\r
830 * call:\r
831 * JSB .CMPY\r
832 * DEF result,I\r
833 * DEF oprd1,I\r
834 * DEF oprd2,I\r
835 * complex multiply is: (a+bi)*(c+di) => (ac-bd) + (ad+bc)i */\r
836 a = ReadOp(RE(op[1].word), fp_f); /* read 1st op */\r
837 b = ReadOp(IM(op[1].word), fp_f);\r
838 c = ReadOp(RE(op[2].word), fp_f); /* read 2nd op */\r
839 d = ReadOp(IM(op[2].word), fp_f);\r
840 sig_cmul(&p1, &p2, a, b, c, d);\r
841 WriteOp(RE(op[0].word), p1, fp_f); /* write real result */\r
842 WriteOp(IM(op[0].word), p2, fp_f); /* write imag result */\r
843 break;\r
844 \r
845 case 011: /* .CDIV (OP_AAA) */\r
846 /* .CDIV Complex division\r
847 * call:\r
848 * JSB .CDIV\r
849 * DEF result,I\r
850 * DEF oprd1,I\r
851 * DEF oprd2,I\r
852 * complex division is: (a+bi)/(c+di) => ((ac+bd) + (bc-ad)i)/(c^2+d^2) */\r
853 a = ReadOp(RE(op[1].word), fp_f); /* read 1st op */\r
854 b = ReadOp(IM(op[1].word), fp_f);\r
855 c = ReadOp(RE(op[2].word), fp_f); /* read 2nd op */\r
856 d = ReadOp(IM(op[2].word), fp_f);\r
857 (void)fp_unpack (NULL, &exc, c, fp_f); /* get exponents */\r
858 (void)fp_unpack (NULL, &exd, d, fp_f);\r
859 if (exc < exd) { /* ensure c/d < 1 */\r
860 p1 = a; a = c; c = p1; /* swap dividend and divisor */\r
861 p1 = b; b = d; d = p1;\r
862 }\r
863 (void)fp_exec(060, &p1, d, c); /* p1,accu := d/c */\r
864 (void)fp_exec(044, ACCUM, d, NOP); /* ACCUM := dd/c */\r
865 (void)fp_exec(004, &p2, c, NOP); /* p2 := c + dd/c */\r
866 (void)fp_exec(040, ACCUM, b, p1); /* ACCUM := bd/c */\r
867 (void)fp_exec(004, ACCUM, a, NOP); /* ACCUM := a + bd/c */\r
868 (void)fp_exec(070, &p3, NOP, p2); /* p3 := (a+bd/c)/(c+dd/c) == (ac+bd)/(cc+dd) */\r
869 WriteOp(RE(op[0].word), p3, fp_f); /* Write real result */\r
870 (void)fp_exec(040, ACCUM, a, p1); /* ACCUM := ad/c */\r
871 (void)fp_exec(030, ACCUM, NOP, b); /* ACCUM := ad/c - b */\r
872 if (exd < exc) { /* was not swapped? */\r
873 (void)fp_exec(024, ACCUM, zero, NOP); /* ACCUM := -ACCUM */\r
874 }\r
875 (void)fp_exec(070, &p3, NOP, p2); /* p3 := (b-ad/c)/(c+dd/c) == (bc-ad)/cc+dd) */\r
876 WriteOp(IM(op[0].word), p3, fp_f); /* Write imag result */\r
877 break;\r
878 \r
879 case 012: /* CONJG (OP_AAA) */\r
880 /* CONJG build A-Bi from A+Bi\r
881 * call:\r
882 * JSB CONJG\r
883 * DEF RTN\r
884 * DEF res,I result\r
885 * DEF arg,I input argument */\r
886 a = ReadOp(RE(op[2].word), fp_f); /* read real */\r
887 b = ReadOp(IM(op[2].word), fp_f); /* read imag */\r
888 (void)fp_pcom(&b, fp_f); /* negate imag */\r
889 WriteOp(RE(op[1].word), a, fp_f); /* write real */\r
890 WriteOp(IM(op[1].word), b, fp_f); /* write imag */\r
891 break;\r
892 \r
893 case 013: /* ..CCM (OP_A) */\r
894 /* ..CCM complement complex\r
895 * call\r
896 * JSB ..CCM\r
897 * DEF arg\r
898 * build (-RE,-IM)\r
899 */\r
900 v = op[0].word;\r
901 a = ReadOp(RE(v), fp_f); /* read real */\r
902 b = ReadOp(IM(v), fp_f); /* read imag */\r
903 (void)fp_pcom(&a, fp_f); /* negate real */\r
904 (void)fp_pcom(&b, fp_f); /* negate imag */\r
905 WriteOp(RE(v), a, fp_f); /* write real */\r
906 WriteOp(IM(v), b, fp_f); /* write imag */\r
907 break;\r
908 \r
909 case 014: /* AIMAG (OP_AA) */\r
910 /* AIMAG return the imaginary part in AB\r
911 * JSB AIMAG\r
912 * DEF *+2\r
913 * DEF cplx(,I)\r
914 * returns: AB imaginary part of complex number */\r
915 a = ReadOp(IM(op[1].word), fp_f); /* read imag */\r
916 AR = a.fpk[0]; /* move MSB to A */\r
917 BR = a.fpk[1]; /* move LSB to B */\r
918 break;\r
919\r
920 case 015: /* CMPLX (OP_AFF) */\r
921 /* CMPLX form a complex number\r
922 * JSB CMPLX\r
923 * DEF *+4\r
924 * DEF result,I complex number\r
925 * DEF repart,I real value\r
926 * DEF impart,I imaginary value */\r
927 WriteOp(RE(op[1].word), op[2], fp_f); /* write real part */ \r
928 WriteOp(IM(op[1].word), op[3], fp_f); /* write imag part */\r
929 break;\r
930\r
931 case 017: /* [slftst] (OP_N) */\r
932 XR = 2; /* firmware revision */\r
933 SR = 0102077; /* test passed code */\r
934 PC = (PC + 1) & VAMASK; /* P+2 return for firmware w/SIGNAL1000 */\r
935 break;\r
936\r
937 case 016: /* invalid */\r
938 default: /* others undefined */\r
939 reason = stop_inst;\r
940 }\r
941\r
942return reason;\r
943}\r
944\r
945#endif /* end of int64 support */\r