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