static void vis_vdot(OPS op,OPSIZE opsize) { OP v1,v2,dot = zero; int16 delta = opsize==fp_f ? 2 : 4; uint32 daddr = op[0].word; uint32 v1addr = op[1].word; int16 ix1 = INT16(op[2].word) * delta; uint32 v2addr = op[3].word; int16 ix2 = INT16(op[4].word) * delta; int16 i,n = INT16(op[5].word); if (n <= 0) return; /* calculates dot = dot + v1[i]*v2[j] for incrementing i,j */ for (i=0; i<n; i++) { v1 = ReadOp(v1addr, opsize); if (opsize==fp_f) (void)fp_cvt(&v1,fp_f,fp_t); /* cvt to DBLE(v1) */ v2 = ReadOp(v2addr, opsize); if (opsize==fp_f) (void)fp_cvt(&v2,fp_f,fp_t); /* cvt to DBLE(v2) */ (void)fp_exec(042,ACCUM, v1, v2); /* ACCU := v1 * v2 */ (void)fp_exec(006,&dot,dot,NOP); /* dot := dot + v1*v2 */ v1addr += ix1; /* forward to next array elements */ v2addr += ix2; } if (opsize==fp_f) (void)vis_trunc(&dot,dot); /* truncate to SNGL(sumnrm) */ WriteOp(daddr, dot, opsize); /* write result */ }
static void vis_vpiv(OPS op, OPSIZE opsize) { OP s,v1,v2,v3; int16 delta = opsize==fp_f ? 2 : 4; uint32 saddr = op[0].word; uint32 v1addr = op[1].word; int16 ix1 = INT16(op[2].word) * delta; uint32 v2addr = op[3].word; int16 ix2 = INT16(op[4].word) * delta; uint32 v3addr = op[5].word; int16 ix3 = INT16(op[6].word) * delta; int16 i, n = INT16(op[7].word); int16 oplen = opsize==fp_f ? 0 : 2; if (n <= 0) return; s = ReadOp(saddr,opsize); /* calculates v3[k] = s * v1[i] + v2[j] for incrementing i,j,k */ for (i=0; i<n; i++) { v1 = ReadOp(v1addr, opsize); (void)fp_exec(040+oplen, ACCUM, s ,v1); /* ACCU := s*v1 */ v2 = ReadOp(v2addr, opsize); (void)fp_exec(004+oplen,&v3,v2,NOP); /* v3 := v2 + s*v1 */ WriteOp(v3addr, v3, opsize); /* write result */ v1addr += ix1; /* forward to next array elements */ v2addr += ix2; v3addr += ix3; } }
static void vis_minmax(OPS op,OPSIZE opsize,t_bool domax,t_bool doabs) { OP v1,vmxmn,res; int16 delta = opsize==fp_f ? 2 : 4; uint32 mxmnaddr = op[0].word; uint32 v1addr = op[1].word; int16 ix1 = INT16(op[2].word) * delta; int16 n = INT16(op[3].word); int16 i,mxmn,sign; uint16 subop = 020 | (opsize==fp_f ? 0 : 2); if (n <= 0) return; mxmn = 0; /* index of maxmin element */ vmxmn = ReadOp(v1addr,opsize); /* initialize with first element */ if (doabs) vis_abs(&vmxmn,opsize); /* ABS(v[1]) if requested */ for (i = 0; i<n; i++) { v1 = ReadOp(v1addr,opsize); /* get v[i] */ if (doabs) vis_abs(&v1,opsize); /* build ABS(v[i]) if requested */ (void)fp_exec(subop,&res,vmxmn,v1); /* subtract vmxmn - v1[i] */ sign = GET_MSIGN(&res); /* !=0 if vmxmn < v1[i] */ if ((domax && sign) || /* new max value found */ (!domax && !sign)) { /* new min value found */ mxmn = i; vmxmn = v1; /* save the new max/min value */ } v1addr += ix1; /* point to next element */ } res.word = mxmn+1; /* adjust to one-based FTN array */ WriteOp(mxmnaddr, res, in_s); /* save result */ }
/* complex addition helper */ static void sig_caddsub(uint16 addsub,OPS op) { OP a,b,c,d,p1,p2; a = ReadOp(RE(op[1].word), fp_f); /* read 1st op */ b = ReadOp(IM(op[1].word), fp_f); c = ReadOp(RE(op[2].word), fp_f); /* read 2nd op */ d = ReadOp(IM(op[2].word), fp_f); (void)fp_exec(addsub,&p1, a, c); /* add real */ (void)fp_exec(addsub,&p2, b, d); /* add imag */ WriteOp(RE(op[0].word), p1, fp_f); /* write result */ WriteOp(IM(op[0].word), p2, fp_f); /* write result */ }
OpCode ByteCodeReader::ReadOp(LayoutSize& layoutSize) { OpCode op = ReadOp(m_currentLocation, layoutSize); #if ENABLE_NATIVE_CODEGEN Assert(!OpCodeAttr::BackEndOnly(op)); #endif return op; }
static void vis_movswp(OPS op, OPSIZE opsize, t_bool doswp) { OP v1,v2; int16 delta = opsize==fp_f ? 2 : 4; uint32 v1addr = op[0].word; int16 ix1 = INT16(op[1].word) * delta; uint32 v2addr = op[2].word; int16 ix2 = INT16(op[3].word) * delta; int16 i,n = INT16(op[4].word); if (n <= 0) return; for (i=0; i<n; i++) { v1 = ReadOp(v1addr, opsize); v2 = ReadOp(v2addr, opsize); WriteOp(v2addr, v1, opsize); /* v2 := v1 */ if (doswp) WriteOp(v1addr, v2, opsize); /* v1 := v2 */ v1addr += ix1; /* forward to next array elements */ v2addr += ix2; } }
/* handle the scalar/vector base ops */ static void vis_svop(uint32 subcode, OPS op, OPSIZE opsize) { OP v1,v2; int16 delta = opsize==fp_f ? 2 : 4; OP s = ReadOp(op[0].word,opsize); uint32 v1addr = op[1].word; int16 ix1 = INT16(op[2].word) * delta; uint32 v2addr = op[3].word; int16 ix2 = INT16(op[4].word) * delta; int16 i, n = INT16(op[5].word); uint16 fpuop = (uint16) (subcode & 060) | (opsize==fp_f ? 0 : 2); if (n <= 0) return; for (i=0; i<n; i++) { v1 = ReadOp(v1addr, opsize); (void)fp_exec(fpuop, &v2, s ,v1); WriteOp(v2addr, v2, opsize); v1addr += ix1; v2addr += ix2; } }
/* butterfly operation helper */ static void sig_btrfy(uint32 re,uint32 im,OP wr,OP wi,uint32 k, uint32 n2) { /* * v(k)-------->o-->o----> v(k) * \ / * x * / \ * v(k+N/2)---->o-->o----> v(k+N/2) * Wn -1 * */ OP p1,p2,p3,p4; OP v1r = ReadOp(re+k, fp_f); /* read v1 */ OP v1i = ReadOp(im+k, fp_f); OP v2r = ReadOp(re+k+n2, fp_f); /* read v2 */ OP v2i = ReadOp(im+k+n2, fp_f); /* (p1,p2) := cmul(w,v2) */ (void)fp_exec(040, &p1, wr, v2r); /* S7,8 p1 := wr*v2r */ (void)fp_exec(040, ACCUM, wi, v2i); /* ACCUM := wi*v2i */ (void)fp_exec(024, &p1, p1, NOP); /* S7,S8 p1 := wr*v2r-wi*v2i ==real(w*v2) */ (void)fp_exec(040, &p2, wi, v2r); /* S9,10 p2 := wi*v2r */ (void)fp_exec(040, ACCUM, wr, v2i); /* ACCUM := wr*v2i */ (void)fp_exec(004, &p2, p2, NOP); /* S9,10 p2 := wi*v2r+wr*v2i ==imag(w*v2) */ /* v2 := v1 - (p1,p2) */ (void)fp_exec(020, &p3, v1r, p1); /* v2r := v1r-real(w*v2) */ (void)fp_exec(020, &p4, v1i, p2); /* v2i := v1i-imag(w*v2) */ WriteOp(re+k+n2, p3, fp_f); /* write v2r */ WriteOp(im+k+n2, p4, fp_f); /* write v2i */ /* v1 := v1 + (p1,p2) */ (void)fp_exec(0, &p3, v1r, p1); /* v1r := v1r+real(w*v2) */ (void)fp_exec(0, &p4, v1i, p2); /* v1i := v1i+imag(w*v2) */ WriteOp(re+k, p3, fp_f); /* write v1r */ WriteOp(im+k, p4, fp_f); /* write v1i */ O = 0; }
/* helper for bit reversal * idx is 0-based already */ static void sig_bitrev(uint32 re,uint32 im, uint32 idx, uint32 log2n, int sz) { uint32 i, org=idx, rev = 0; OP v1r,v1i,v2r,v2i; for (i=0; i<log2n; i++) { /* swap bits of idx */ rev = (rev<<1) | (org & 1); /* into rev */ org >>= 1; } if (rev < idx) return; /* avoid swapping same pair twice in loop */ idx *= sz; /* adjust for element size */ rev *= sz; /* (REAL*4 vs COMPLEX*8) */ v1r = ReadOp(re+idx, fp_f); /* read 1st element */ v1i = ReadOp(im+idx, fp_f); v2r = ReadOp(re+rev, fp_f); /* read 2nd element */ v2i = ReadOp(im+rev, fp_f); WriteOp(re+idx, v2r, fp_f); /* swap elements */ WriteOp(im+idx, v2i, fp_f); WriteOp(re+rev, v1r, fp_f); WriteOp(im+rev, v1i, fp_f); }
static void vis_vabs(OPS op, OPSIZE opsize) { OP v1; int16 delta = opsize==fp_f ? 2 : 4; uint32 v1addr = op[0].word; int16 ix1 = INT16(op[1].word) * delta; uint32 v2addr = op[2].word; int32 ix2 = INT16(op[3].word) * delta; int16 i,n = INT16(op[4].word); if (n <= 0) return; /* calculates v2[j] = ABS(v1[i]) for incrementing i,j */ for (i=0; i<n; i++) { v1 = ReadOp(v1addr, opsize); vis_abs(&v1,opsize); /* make absolute value */ WriteOp(v2addr, v1, opsize); /* write result */ v1addr += ix1; /* forward to next array elements */ v2addr += ix2; } }
static void vis_vsmnm(OPS op,OPSIZE opsize,t_bool doabs) { uint16 fpuop; OP v1,sumnrm = zero; int16 delta = opsize==fp_f ? 2 : 4; uint32 saddr = op[0].word; uint32 v1addr = op[1].word; int16 ix1 = INT16(op[2].word) * delta; int16 i,n = INT16(op[3].word); if (n <= 0) return; /* calculates sumnrm = sumnrm + DBLE(v1[i]) resp DBLE(ABS(v1[i])) for incrementing i */ for (i=0; i<n; i++) { v1 = ReadOp(v1addr, opsize); if (opsize==fp_f) (void)fp_cvt(&v1,fp_f,fp_t); /* cvt to DBLE(v1) */ fpuop = (doabs && GET_MSIGN(&v1)) ? 022 : 002; /* use subtract for NRM && V1<0 */ (void)fp_exec(fpuop,&sumnrm, sumnrm, v1); /* accumulate */ v1addr += ix1; /* forward to next array elements */ } if (opsize==fp_f) (void)vis_trunc(&sumnrm,sumnrm); /* truncate to SNGL(sumnrm) */ WriteOp(saddr, sumnrm, opsize); /* write result */ }
OpCode ByteCodeReader::PeekOp(const byte * ip, LayoutSize& layoutSize) { return ReadOp(ip, layoutSize); }
OpCode ByteCodeReader::PeekOp(LayoutSize& layoutSize) const { const byte * ip = m_currentLocation; return ReadOp(ip, layoutSize); }
OpCodeAsmJs ByteCodeReader::ReadAsmJsOp(LayoutSize& layoutSize) { OpCode op = ReadOp(m_currentLocation, layoutSize); return (OpCodeAsmJs)op; }
void* AsmJsEncoder::Encode( FunctionBody* functionBody ) { Assert( functionBody ); mFunctionBody = functionBody; #if DBG_DUMP AsmJsJitTemplate::Globals::CurrentEncodingFunction = mFunctionBody; #endif AsmJsFunctionInfo* asmInfo = functionBody->GetAsmJsFunctionInfo(); FunctionEntryPointInfo* entryPointInfo = ((FunctionEntryPointInfo*)(functionBody->GetDefaultEntryPointInfo())); // number of var on the stack + ebp + eip mIntOffset = asmInfo->GetIntByteOffset() + GetOffset<Var>(); mDoubleOffset = asmInfo->GetDoubleByteOffset() + GetOffset<Var>(); mFloatOffset = asmInfo->GetFloatByteOffset() + GetOffset<Var>(); mSimdOffset = asmInfo->GetSimdByteOffset() + GetOffset<Var>(); NoRecoverMemoryArenaAllocator localAlloc(_u("BE-AsmJsEncoder"), GetPageAllocator(), Js::Throw::OutOfMemory); mLocalAlloc = &localAlloc; mRelocLabelMap = Anew( mLocalAlloc, RelocLabelMap, mLocalAlloc ); mTemplateData = AsmJsJitTemplate::InitTemplateData(); mEncodeBufferSize = GetEncodeBufferSize(functionBody); mEncodeBuffer = AnewArray((&localAlloc), BYTE, mEncodeBufferSize); mPc = mEncodeBuffer; mReader.Create( functionBody ); ip = mReader.GetIP(); #ifdef ENABLE_DEBUG_CONFIG_OPTIONS if( PHASE_TRACE( Js::AsmjsEncoderPhase, mFunctionBody ) ) { Output::Print( _u("\n\n") ); functionBody->DumpFullFunctionName(); Output::Print( _u("\n StackSize = %d , Offsets: Var = %d, Int = %d, Double = %d\n"), mFunctionBody->GetAsmJsFunctionInfo()->GetTotalSizeinBytes(), GetOffset<Var>(), GetOffset<int>(), GetOffset<double>() ); } #endif AsmJsJitTemplate::FunctionEntry::ApplyTemplate( this, mPc ); while( ReadOp() ){} AsmJsJitTemplate::FunctionExit::ApplyTemplate( this, mPc ); AsmJsJitTemplate::FreeTemplateData( mTemplateData ); #if DBG_DUMP AsmJsJitTemplate::Globals::CurrentEncodingFunction = nullptr; #endif ApplyRelocs(); ptrdiff_t codeSize = mPc - mEncodeBuffer; if( codeSize > 0 ) { Assert( ::Math::FitsInDWord( codeSize ) ); BYTE *buffer; EmitBufferAllocation *allocation = GetCodeGenAllocator()->emitBufferManager.AllocateBuffer( codeSize, &buffer, 0, 0 ); functionBody->GetAsmJsFunctionInfo()->mTJBeginAddress = buffer; if (buffer == nullptr) { Js::Throw::OutOfMemory(); } if (!GetCodeGenAllocator()->emitBufferManager.CommitBuffer(allocation, buffer, codeSize, mEncodeBuffer)) { Js::Throw::OutOfMemory(); } functionBody->GetScriptContext()->GetThreadContext()->SetValidCallTargetForCFG(buffer); // TODO: improve this once EntryPoint cleanup work is complete! #if 0 const char16 *const functionName = functionBody->GetDisplayName(); const char16 *const suffix = _u("TJ"); char16 functionNameArray[256]; const size_t functionNameCharLength = functionBody->GetDisplayNameLength(); wcscpy_s(functionNameArray, 256, functionName); wcscpy_s(&functionNameArray[functionNameCharLength], 256 - functionNameCharLength, suffix); #endif JS_ETW(EventWriteMethodLoad(functionBody->GetScriptContext(), (void *)buffer, codeSize, EtwTrace::GetFunctionId(functionBody), 0 /* methodFlags - for future use*/, MethodType_Jit, EtwTrace::GetSourceId(functionBody), functionBody->GetLineNumber(), functionBody->GetColumnNumber(), functionBody->GetDisplayName())); entryPointInfo->SetTJCodeGenDone(); // set the codegen to done state for TJ entryPointInfo->SetCodeSize(codeSize); return buffer; } return nullptr; }
t_stat cpu_signal (uint32 IR, uint32 intrq) { t_stat reason = SCPE_OK; OPS op; OP a,b,c,d,p1,p2,p3,p4,m1,m2,wr,wi; uint32 entry, v, idx1, idx2; int32 exc, exd; entry = IR & 017; /* mask to entry point */ if (op_signal [entry] != OP_N) { reason = cpu_ops (op_signal [entry], op, intrq); /* get instruction operands */ if (reason != SCPE_OK) /* evaluation failed? */ return reason; /* return reason for failure */ } switch (entry) { /* decode IR<3:0> */ case 000: /* BITRV (OP_AAKK) */ /* BITRV * bit reversal for FFT * JSB BITRV * DEF ret(,I) return address * DEF vect,I base address of array * DEF idx,I index bitmap to be reversed (one-based) * DEF nbits,I number of bits of index * * Given a complex*8 vector of nbits (power of 2), this calculates: * swap( vect[idx], vect[rev(idx)]) where rev(i) is the bitreversed value of i */ sig_bitrev(op[1].word, op[1].word+2, op[2].word-1, op[3].word, 4); PR = op[0].word & VAMASK; break; case 001: /* BTRFY (OP_AAFFKK) */ /* BTRFY - butterfly operation * JSB BTRFY * DEF ret(,I) return address * DEF vect(,I) complex*8 vector * DEF wr,I real part of W * DEF wi,I imag part of W * DEF node,I index of 1st op (1 based) * DEF lmax,I offset to 2nd op (0 based) */ sig_btrfy(op[1].word, op[1].word+2, op[2], op[3], 2*(op[4].word-1), 2*op[5].word); PR = op[0].word & VAMASK; break; case 002: /* UNSCR (OP_AAFFKK) */ /* UNSCR unscramble for phasor MPY * JSB UNSCR * DEF ret(,I) * DEF vector,I * DEF WR * DEF WI * DEF idx1,I * DEF idx2,I */ v = op[1].word; idx1 = 2 * (op[4].word - 1); idx2 = 2 * (op[5].word - 1); wr = op[2]; /* read WR */ wi = op[3]; /* read WI */ p1 = ReadOp(RE(v + idx1), fp_f); /* S1 VR[idx1] */ p2 = ReadOp(RE(v + idx2), fp_f); /* S2 VR[idx2] */ p3 = ReadOp(IM(v + idx1), fp_f); /* S9 VI[idx1] */ p4 = ReadOp(IM(v + idx2), fp_f); /* S10 VI[idx2] */ c = sig_scadd(000, TRUE, p3, p4); /* S5,6 0.5*(p3+p4) */ d = sig_scadd(020, TRUE, p2, p1); /* S7,8 0.5*(p2-p1) */ sig_cmul(&m1, &m2, wr, wi, c, d); /* (WR,WI) * (c,d) */ c = sig_scadd(000, TRUE, p1, p2); /* 0.5*(p1+p2) */ d = sig_scadd(020, TRUE, p3, p4); /* 0.5*(p3-p4) */ (void)fp_exec(000, &p1, c, m1); /* VR[idx1] := 0.5*(p1+p2) + real(W*(c,d)) */ WriteOp(RE(v + idx1), p1, fp_f); (void)fp_exec(000, &p2, d, m2); /* VI[idx1] := 0.5*(p3-p4) + imag(W*(c,d)) */ WriteOp(IM(v + idx1), p2, fp_f); (void)fp_exec(020, &p1, c, m1); /* VR[idx2] := 0.5*(p1+p2) - imag(W*(c,d)) */ WriteOp(RE(v + idx2), p1, fp_f); (void)fp_exec(020, &p2, d, m2); /* VI[idx2] := 0.5*(p3-p4) - imag(W*(c,d)) */ WriteOp(IM(v + idx2), p2, fp_f); PR = op[0].word & VAMASK; break; case 003: /* PRSCR (OP_AAFFKK) */ /* PRSCR unscramble for phasor MPY * JSB PRSCR * DEF ret(,I) * DEF vector,I * DEF WR * DEF WI * DEF idx1,I * DEF idx2,I */ v = op[1].word; idx1 = 2 * (op[4].word - 1); idx2 = 2 * (op[5].word - 1); wr = op[2]; /* read WR */ wi = op[3]; /* read WI */ p1 = ReadOp(RE(v + idx1), fp_f); /* VR[idx1] */ p2 = ReadOp(RE(v + idx2), fp_f); /* VR[idx2] */ p3 = ReadOp(IM(v + idx1), fp_f); /* VI[idx1] */ p4 = ReadOp(IM(v + idx2), fp_f); /* VI[idx2] */ c = sig_scadd(020, FALSE, p1, p2); /* p1-p2 */ d = sig_scadd(000, FALSE, p3, p4); /* p3+p4 */ sig_cmul(&m1,&m2, wr, wi, c, d); /* (WR,WI) * (c,d) */ c = sig_scadd(000, FALSE, p1, p2); /* p1+p2 */ d = sig_scadd(020, FALSE, p3,p4); /* p3-p4 */ (void)fp_exec(020, &p1, c, m2); /* VR[idx1] := (p1-p2) - imag(W*(c,d)) */ WriteOp(RE(v + idx1), p1, fp_f); (void)fp_exec(000, &p2, d, m1); /* VI[idx1] := (p3-p4) + real(W*(c,d)) */ WriteOp(IM(v + idx1), p2, fp_f); (void)fp_exec(000, &p1, c, m2); /* VR[idx2] := (p1+p2) + imag(W*(c,d)) */ WriteOp(RE(v + idx2), p1, fp_f); (void)fp_exec(020, &p2, m1, d); /* VI[idx2] := imag(W*(c,d)) - (p3-p4) */ WriteOp(IM(v + idx2), p2, fp_f); PR = op[0].word & VAMASK; break; case 004: /* BITR1 (OP_AAAKK) */ /* BITR1 * bit reversal for FFT, alternative version * JSB BITR1 * DEF ret(,I) return address if already swapped * DEF revect,I base address of real vect * DEF imvect,I base address of imag vect * DEF idx,I index bitmap to be reversed (one-based) * DEF nbits,I number of bits of index * * Given a complex*8 vector of nbits (power of 2), this calculates: * swap( vect[idx], vect[rev(idx)]) where rev(i) is the bitreversed value of i * * difference to BITRV is that BITRV uses complex*8, and BITR1 uses separate real*4 * vectors for Real and Imag parts */ sig_bitrev(op[1].word, op[2].word, op[3].word-1, op[4].word, 2); PR = op[0].word & VAMASK; break; case 005: /* BTRF1 (OP_AAAFFKK) */ /* BTRF1 - butterfly operation with real*4 vectors * JSB BTRF1 * DEF ret(,I) return address * DEF rvect,I real part of vector * DEF ivect,I imag part of vector * DEF wr,I real part of W * DEF wi,I imag part of W * DEF node,I index (1 based) * DEF lmax,I index (0 based) */ sig_btrfy(op[1].word, op[2].word, op[3], op[4], op[5].word-1, op[6].word); PR = op[0].word & VAMASK; break; case 006: /* .CADD (OP_AAA) */ /* .CADD Complex addition * JSB .CADD * DEF result,I * DEF oprd1,I * DEF oprd2,I * complex addition is: (a+bi) + (c+di) => (a+c) + (b+d)i */ sig_caddsub(000,op); break; case 007: /* .CSUB (OP_AAA) */ /* .CSUB Complex subtraction * JSB .CSUB * DEF result,I * DEF oprd1,I * DEF oprd2,I * complex subtraction is: (a+bi) - (c+di) => (a - c) + (b - d)i */ sig_caddsub(020,op); break; case 010: /* .CMUL (OP_AAA) */ /* .CMPY Complex multiplication * call: * JSB .CMPY * DEF result,I * DEF oprd1,I * DEF oprd2,I * complex multiply is: (a+bi)*(c+di) => (ac-bd) + (ad+bc)i */ a = ReadOp(RE(op[1].word), fp_f); /* read 1st op */ b = ReadOp(IM(op[1].word), fp_f); c = ReadOp(RE(op[2].word), fp_f); /* read 2nd op */ d = ReadOp(IM(op[2].word), fp_f); sig_cmul(&p1, &p2, a, b, c, d); WriteOp(RE(op[0].word), p1, fp_f); /* write real result */ WriteOp(IM(op[0].word), p2, fp_f); /* write imag result */ break; case 011: /* .CDIV (OP_AAA) */ /* .CDIV Complex division * call: * JSB .CDIV * DEF result,I * DEF oprd1,I * DEF oprd2,I * complex division is: (a+bi)/(c+di) => ((ac+bd) + (bc-ad)i)/(c^2+d^2) */ a = ReadOp(RE(op[1].word), fp_f); /* read 1st op */ b = ReadOp(IM(op[1].word), fp_f); c = ReadOp(RE(op[2].word), fp_f); /* read 2nd op */ d = ReadOp(IM(op[2].word), fp_f); (void)fp_unpack (NULL, &exc, c, fp_f); /* get exponents */ (void)fp_unpack (NULL, &exd, d, fp_f); if (exc < exd) { /* ensure c/d < 1 */ p1 = a; a = c; c = p1; /* swap dividend and divisor */ p1 = b; b = d; d = p1; } (void)fp_exec(060, &p1, d, c); /* p1,accu := d/c */ (void)fp_exec(044, ACCUM, d, NOP); /* ACCUM := dd/c */ (void)fp_exec(004, &p2, c, NOP); /* p2 := c + dd/c */ (void)fp_exec(040, ACCUM, b, p1); /* ACCUM := bd/c */ (void)fp_exec(004, ACCUM, a, NOP); /* ACCUM := a + bd/c */ (void)fp_exec(070, &p3, NOP, p2); /* p3 := (a+bd/c)/(c+dd/c) == (ac+bd)/(cc+dd) */ WriteOp(RE(op[0].word), p3, fp_f); /* Write real result */ (void)fp_exec(040, ACCUM, a, p1); /* ACCUM := ad/c */ (void)fp_exec(030, ACCUM, NOP, b); /* ACCUM := ad/c - b */ if (exd < exc) { /* was not swapped? */ (void)fp_exec(024, ACCUM, zero, NOP); /* ACCUM := -ACCUM */ } (void)fp_exec(070, &p3, NOP, p2); /* p3 := (b-ad/c)/(c+dd/c) == (bc-ad)/cc+dd) */ WriteOp(IM(op[0].word), p3, fp_f); /* Write imag result */ break; case 012: /* CONJG (OP_AAA) */ /* CONJG build A-Bi from A+Bi * call: * JSB CONJG * DEF RTN * DEF res,I result * DEF arg,I input argument */ a = ReadOp(RE(op[2].word), fp_f); /* read real */ b = ReadOp(IM(op[2].word), fp_f); /* read imag */ (void)fp_pcom(&b, fp_f); /* negate imag */ WriteOp(RE(op[1].word), a, fp_f); /* write real */ WriteOp(IM(op[1].word), b, fp_f); /* write imag */ break; case 013: /* ..CCM (OP_A) */ /* ..CCM complement complex * call * JSB ..CCM * DEF arg * build (-RE,-IM) */ v = op[0].word; a = ReadOp(RE(v), fp_f); /* read real */ b = ReadOp(IM(v), fp_f); /* read imag */ (void)fp_pcom(&a, fp_f); /* negate real */ (void)fp_pcom(&b, fp_f); /* negate imag */ WriteOp(RE(v), a, fp_f); /* write real */ WriteOp(IM(v), b, fp_f); /* write imag */ break; case 014: /* AIMAG (OP_AA) */ /* AIMAG return the imaginary part in AB * JSB AIMAG * DEF *+2 * DEF cplx(,I) * returns: AB imaginary part of complex number */ a = ReadOp(IM(op[1].word), fp_f); /* read imag */ AR = a.fpk[0]; /* move MSB to A */ BR = a.fpk[1]; /* move LSB to B */ break; case 015: /* CMPLX (OP_AFF) */ /* CMPLX form a complex number * JSB CMPLX * DEF *+4 * DEF result,I complex number * DEF repart,I real value * DEF impart,I imaginary value */ WriteOp(RE(op[1].word), op[2], fp_f); /* write real part */ WriteOp(IM(op[1].word), op[3], fp_f); /* write imag part */ break; case 017: /* [slftst] (OP_N) */ XR = 2; /* firmware revision */ SR = 0102077; /* test passed code */ PR = (PR + 1) & VAMASK; /* P+2 return for firmware w/SIGNAL1000 */ break; case 016: /* invalid */ default: /* others unimplemented */ reason = STOP (cpu_ss_unimpl); } return reason; }