5b0e3d0c68ba9cc93a66f12e4223c92c3d99d22b
1 /* hp2100_cpu7.c: HP 1000 VIS and SIGNAL/1000 microcode
3 Copyright (c) 2006, J. David Bryan
4 Copyright (c) 2008, Holger Veit
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:
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
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.
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.
27 CPU7 Vector Instruction Set and SIGNAL firmware
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
35 - HP 1000 M/E/F-Series Computers Technical Reference Handbook
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)
41 Additional references are listed with the associated firmware
42 implementations, as are the HP option model numbers pertaining to the
46 #include "hp2100_defs.h"
47 #include "hp2100_cpu.h"
48 #include "hp2100_cpu1.h"
50 #if defined (HAVE_INT64) /* int64 support available */
52 #include "hp2100_fp1.h"
55 t_stat
cpu_vis (uint32 IR
, uint32 intrq
); /* Vector Instruction Set */
56 t_stat
cpu_signal (uint32 IR
, uint32 intrq
); /* SIGNAL/1000 Instructions */
58 static const OP zero
= { { 0, 0, 0, 0, 0 } }; /* DEC 0.0D0 */
61 /* Vector Instruction Set
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
68 Option implementation by CPU was as follows:
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
74 The routines are mapped to instruction codes as follows:
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]
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.
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.
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.
120 Additional references:
121 - 12824A Vector Instruction Set User's Manual (12824-90001, Jun-1979).
122 - VIS Microcode Source (12824-18059, revision 3).
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
);
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] */
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
,
145 /* handle the scalar/vector base ops */
146 static void vis_svop(uint32 subcode
, OPS op
, OPSIZE opsize
)
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);
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
);
168 /* handle the vector/vector base ops */
169 static void vis_vvop(uint32 subcode
, OPS op
,OPSIZE opsize
)
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);
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
);
194 #define GET_MSIGN(op) ((op)->fpk[0] & 0100000)
196 static void vis_abs(OP
* in
, uint32 opsize
)
198 uint32 sign
= GET_MSIGN(in
); /* get sign */
199 if (sign
) (void)fp_pcom(in
, opsize
); /* if negative, make positive */
202 static void vis_minmax(OPS op
,OPSIZE opsize
,t_bool domax
,t_bool doabs
)
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
);
211 int32 subop
= 020 | (opsize
==fp_f
? 0 : 2);
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 */
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 */
226 vmxmn
= v1
; /* save the new max/min value */
228 v1addr
+= ix1
; /* point to next element */
230 res
.word
= mxmn
+1; /* adjust to one-based FTN array */
231 WriteOp(mxmnaddr
, res
, in_s
); /* save result */
234 static void vis_vpiv(OPS op
, OPSIZE opsize
)
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;
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 */
263 static void vis_vabs(OPS op
, OPSIZE opsize
)
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
);
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 */
284 static void vis_trunc(OP
* out
, OP in
)
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);
292 static void vis_vsmnm(OPS op
,OPSIZE opsize
,t_bool doabs
)
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
);
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 */
312 (void)vis_trunc(&sumnrm
,sumnrm
); /* truncate to SNGL(sumnrm) */
313 WriteOp(saddr
, sumnrm
, opsize
); /* write result */
316 static void vis_vdot(OPS op
,OPSIZE opsize
)
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
);
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 */
340 (void)vis_trunc(&dot
,dot
); /* truncate to SNGL(sumnrm) */
341 WriteOp(daddr
, dot
, opsize
); /* write result */
344 static void vis_movswp(OPS op
, OPSIZE opsize
, t_bool doswp
)
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
);
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 */
365 t_stat
cpu_vis (uint32 IR
, uint32 intrq
)
367 t_stat reason
= SCPE_OK
;
370 uint32 entry
, rtn
, rtn1
= 0, subcode
= 0;
373 t_bool debug
= DEBUG_PRI (cpu_dev
, DEB_VIS
);
375 if ((cpu_unit
.flags
& UNIT_VIS
) == 0) /* VIS option installed? */
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
];
382 if (entry
==0) { /* retrieve sub opcode */
383 ret
= ReadOp (PC
, in_s
); /* get it */
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 */
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 */
397 if (reason
= cpu_ops (pattern
, op
, intrq
)) /* get instruction operands */
400 if (debug
) { /* debugging? */
401 fprintf (sim_deb
, ">>CPU VIS: IR = %06o/%06o (", /* print preamble and IR */
403 fprint_sym (sim_deb
, err_PC
, (t_value
*) &IR
, /* print instruction mnemonic */
405 fprintf (sim_deb
, "), P = %06o", err_PC
); /* print location */
406 fprint_ops (pattern
, op
); /* print operands */
407 fputc ('\n', sim_deb
); /* terminate line */
410 switch (entry
) { /* decode IR<3:0> */
411 case 000: /* .VECT (OP_special) */
413 vis_svop(subcode
,op
,opsize
); /* scalar/vector op */
415 vis_vvop(subcode
,op
,opsize
); /* vector/vector op */
417 case 001: /* VPIV (OP_(A)AAKAKAKK) */
420 case 002: /* VABS (OP_(A)AKAKK) */
423 case 003: /* VSUM (OP_(A)AAKK) */
424 vis_vsmnm(op
,opsize
,FALSE
);
426 case 004: /* VNRM (OP_(A)AAKK) */
427 vis_vsmnm(op
,opsize
,TRUE
);
429 case 005: /* VDOT (OP_(A)AAKAKK) */
432 case 006: /* VMAX (OP_(A)AAKK) */
433 vis_minmax(op
,opsize
,TRUE
,FALSE
);
435 case 007: /* VMAB (OP_(A)AAKK) */
436 vis_minmax(op
,opsize
,TRUE
,TRUE
);
438 case 010: /* VMIN (OP_(A)AAKK) */
439 vis_minmax(op
,opsize
,FALSE
,FALSE
);
441 case 011: /* VMIB (OP_(A)AAKK) */
442 vis_minmax(op
,opsize
,FALSE
,TRUE
);
444 case 012: /* VMOV (OP_(A)AKAKK) */
445 vis_movswp(op
,opsize
,FALSE
);
447 case 013: /* VSWP (OP_(A)AKAKK) */
448 vis_movswp(op
,opsize
,TRUE
);
450 case 014: /* .ERES (OP_(A)AA) */
451 reason
= cpu_ema_eres(&rtn
,op
[2].word
,PC
,debug
); /* handle the ERES instruction */
455 ">>CPU VIS: return .ERES: AR = %06o, BR = %06o, rtn=%s\n",
456 AR
, BR
, PC
==op
[0].word
? "error" : "good");
459 case 015: /* .ESEG (OP_(A)A) */
460 reason
= cpu_ema_eseg(&rtn
,IR
,op
[0].word
,debug
); /* handle the ESEG instruction */
464 ">>CPU VIS: return .ESEG: AR = %06o , BR = %06o, rtn=%s\n",
465 AR
, BR
, rtn
==rtn1
? "error" : "good");
468 case 016: /* .VSET (OP_(A)AAACCC) */
469 reason
= cpu_ema_vset(&rtn
,op
,debug
);
472 fprintf (sim_deb
, ">>CPU VIS: return .VSET: AR = %06o BR = %06o, rtn=%s\n",
474 rtn
==rtn1
? "error" : (rtn
==(rtn1
+1) ? "hard" : "easy") );
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 */
482 default: /* others undefined */
490 /* SIGNAL/1000 Instructions
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.
496 Option implementation by CPU was as follows:
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
502 The routines are mapped to instruction codes as follows:
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]
525 1. SIGNAL/1000 ROM data are available from Bitsavers.
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).
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]*/
542 /* complex addition helper */
543 static void sig_caddsub(uint32 addsub
,OPS op
)
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 */
557 /* butterfly operation helper */
558 static void sig_btrfy(uint32 re
,uint32 im
,OP wr
,OP wi
,uint32 k
, uint32 n2
)
561 * v(k)-------->o-->o----> v(k)
565 * v(k+N/2)---->o-->o----> v(k+N/2)
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
);
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 */
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
)
600 uint32 i
, org
=idx
, rev
= 0;
603 for (i
=0; i
<log2n
; i
++) { /* swap bits of idx */
604 rev
= (rev
<<1) | (org
& 1); /* into rev */
608 if (rev
< idx
) return; /* avoid swapping same pair twice in loop */
610 idx
*= sz
; /* adjust for element size */
611 rev
*= sz
; /* (REAL*4 vs COMPLEX*8) */
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
);
623 /* helper for PRSCR/UNSCR */
624 static OP
sig_scadd(uint32 oper
,t_bool addh
, OP a
, OP b
)
627 static const OP plus_half
= { { 0040000, 0000000 } }; /* DEC +0.5 */
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 */
634 /* complex multiply helper */
635 static void sig_cmul(OP
*r
, OP
*i
, OP a
, OP b
, OP c
, OP d
)
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 */
646 t_stat
cpu_signal (uint32 IR
, uint32 intrq
)
648 t_stat reason
= SCPE_OK
;
650 OP a
,b
,c
,d
,p1
,p2
,p3
,p4
,m1
,m2
,wr
,wi
;
651 uint32 entry
, v
, idx1
, idx2
;
654 t_bool debug
= DEBUG_PRI (cpu_dev
, DEB_SIG
);
655 if ((cpu_unit
.flags
& UNIT_SIGNAL
) == 0) /* SIGNAL option installed? */
658 entry
= IR
& 017; /* mask to entry point */
660 if (op_signal
[entry
] != OP_N
)
661 if (reason
= cpu_ops (op_signal
[entry
], op
, intrq
)) /* get instruction operands */
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 */
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 */
673 switch (entry
) { /* decode IR<3:0> */
674 case 000: /* BITRV (OP_AAKK) */
676 * bit reversal for FFT
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
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
;
689 case 001: /* BTRFY (OP_AAFFKK) */
690 /* BTRFY - butterfly operation
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,
700 2*(op
[4].word
-1), 2*op
[5].word
);
701 PC
= op
[0].word
& VAMASK
;
704 case 002: /* UNSCR (OP_AAFFKK) */
705 /* UNSCR unscramble for phasor MPY
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
;
738 case 003: /* PRSCR (OP_AAFFKK) */
739 /* PRSCR unscramble for phasor MPY
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
;
772 case 004: /* BITR1 (OP_AAAKK) */
774 * bit reversal for FFT, alternative version
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
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
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
;
792 case 005: /* BTRF1 (OP_AAAFFKK) */
793 /* BTRF1 - butterfly operation with real*4 vectors
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
,
804 op
[5].word
-1, op
[6].word
);
805 PC
= op
[0].word
& VAMASK
;
808 case 006: /* .CADD (OP_AAA) */
809 /* .CADD Complex addition
814 * complex addition is: (a+bi) + (c+di) => (a+c) + (b+d)i */
818 case 007: /* .CSUB (OP_AAA) */
819 /* .CSUB Complex subtraction
824 * complex subtraction is: (a+bi) - (c+di) => (a - c) + (b - d)i */
828 case 010: /* .CMUL (OP_AAA) */
829 /* .CMPY Complex multiplication
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 */
845 case 011: /* .CDIV (OP_AAA) */
846 /* .CDIV Complex division
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
;
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 */
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 */
879 case 012: /* CONJG (OP_AAA) */
880 /* CONJG build A-Bi from A+Bi
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 */
893 case 013: /* ..CCM (OP_A) */
894 /* ..CCM complement complex
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 */
909 case 014: /* AIMAG (OP_AA) */
910 /* AIMAG return the imaginary part in AB
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 */
920 case 015: /* CMPLX (OP_AFF) */
921 /* CMPLX form a complex number
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 */
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 */
937 case 016: /* invalid */
938 default: /* others undefined */
945 #endif /* end of int64 support */