Esempio n. 1
0
        /// <summary>
        /// Writes one byte of the microcode word currently pointed to by
        /// TPC[6].
        /// </summary>
        /// <param name="b"></param>
        /// <param name="value"></param>
        private void WriteIOPMicrocodeWord(int b, byte value)
        {
            //
            // In true Xerox fashion, the 48 bits of the microcode word provided by the IOP
            // are not in order from MSB to LSB or anything simple like that.  Though most of them are.
            // From SysDefs.asm:
            //
            // "; Write (all CSi are complemented values):
            //  CSa equ CSBase + 0; CS Byte a: rA[0:3],,rB[0:3]
            //  CSb equ CSBase + 1; CS Byte b: aS[0:2],,aF[0:2],,aD[0:1]
            //  CSc equ CSBase + 2; CS Byte c: EP,,CIN,,EnSU,,mem,,fS[0:3]
            //  CSd equ CSBase + 3; CS Byte d: fY[0:3], INIA[0:3]
            //  CSe equ CSBase + 4; CS Byte e: fX[0:3], INIA[4:7]
            //  CSf equ CSBase + 5; CS Byte f: fZ[0:3], INIA[8:11]"
            //
            // "value" is expected to already be complemented on call to WriteIOPMicrocodeWord.
            //


            // TPC register 6 is always used for IOP microcode writes.
            ulong word = _microcode[_tpc[6]];

            switch (b)
            {
            case 0:
                word = (word & 0x00ffffffffff) | ((ulong)value << 40);
                break;

            case 1:
                word = (word & 0xff00ffffffff) | ((ulong)value << 32);
                break;

            case 2:
                word = (word & 0xffff00ffffff) | ((ulong)value << 24);
                break;

            case 3:
            {
                // FY[0:3], INIA[0:3]
                ulong fy   = ((ulong)value & 0xf0) >> 4;
                ulong inia = ((ulong)value & 0xf);
                word = (word & 0xfffffff0f0ff) | (fy << 16) | (inia << 8);
            }
            break;

            case 4:
            {
                // FX[0:3], INIA[4:7]
                ulong fx   = ((ulong)value & 0xf0) >> 4;
                ulong inia = ((ulong)value & 0xf);
                word = (word & 0xffffff0fff0f) | (fx << 20) | (inia << 4);
            }
            break;

            case 5:
            {
                // FZ[0:3], INIA[8:11]
                ulong fz   = ((ulong)value & 0xf0) >> 4;
                ulong inia = ((ulong)value & 0xf);
                word = (word & 0xffffffff0ff0) | (fz << 12) | inia;
            }
            break;

            default:
                throw new InvalidOperationException("Invalid byte number for microcode word.");
            }

            _microcode[_tpc[6]]      = word;
            _microcodeCache[_tpc[6]] = new Microinstruction(word);
        }
Esempio n. 2
0
        /// <summary>
        /// Executes the ALU operation specified by the given microinstruction.
        /// </summary>
        /// <param name="i">The microinstruction</param>
        /// <param name="d">The ALU D input</param>
        /// <param name="carryIn">The ALU Carry in</param>
        /// <param name="loadMAR">Whether this operation is taking place during an MAR<- operation,
        /// in which case the top half of the ALU needs to be treated specially.</param>
        public ushort Execute(Microinstruction i, ushort d, bool carryIn, bool loadMAR)
        {
            //
            // Save R[a] for the A-bypass case.
            // (If the ALU op ends up modifying R[a] in A-Bypass mode (because a == b)
            // it will happen much later than A-bypass and we want
            // Y to get the original value of R[a], not the later value.)
            //

            // Select source data
            int r, s;

            switch (i.aS)
            {
            case AluSourcePair.AQ:
                r = _r[i.rA];
                s = _q;
                break;

            case AluSourcePair.AB:
                r = _r[i.rA];
                s = _r[i.rB];
                break;

            case AluSourcePair.ZQ:
                r = 0;
                s = _q;
                break;

            case AluSourcePair.ZB:
                r = 0;
                s = _r[i.rB];
                break;

            case AluSourcePair.ZA:
                r = 0;
                s = _r[i.rA];
                break;

            case AluSourcePair.DA:
                r = d;
                s = _r[i.rA];
                break;

            case AluSourcePair.DQ:
                r = d;
                s = _q;
                break;

            case AluSourcePair.D0:
                r = d;
                s = 0;
                break;

            default:
                throw new InvalidOperationException(
                          String.Format("Unhandled source pair {0}", i.aS));
            }

            //
            // Do ALU op
            //
            int f;
            int cIn = (carryIn ? 1 : 0);

            switch (i.aF)
            {
            case AluFunction.RplusS:
            {
                f        = r + s + cIn;
                CarryOut = (f > 0xffff);
                NibCarry = (r & 0xf) + (s & 0xf) + cIn > 0xf;
                PgCarry  = (r & 0xff) + (s & 0xff) + cIn > 0xff;
                int cn = (r & 0xfff) + (s & 0xfff) + cIn > 0xfff ? 1 : 0;
                Overflow = _overflowTable[r >> 12, s >> 12, cn];
            }
            break;

            case AluFunction.SminusR:
            {
                f        = s + (~r & 0xffff) + cIn;
                CarryOut = (f > 0xffff);
                NibCarry = ((~r & 0xf) + (s & 0xf) + cIn > 0xf);
                PgCarry  = ((~r & 0xff) + (s & 0xff) + cIn > 0xff);
                int cn = (~r & 0xfff) + (s & 0xfff) + cIn > 0xfff ? 1 : 0;
                Overflow = _overflowTable[(~r & 0xffff) >> 12, s >> 12, cn];
            }
            break;

            case AluFunction.RminusS:
            {
                f        = r + (~s & 0xffff) + cIn;
                CarryOut = (f > 0xffff);
                NibCarry = ((r & 0xf) + (~s & 0xf) + cIn > 0xf);
                PgCarry  = ((r & 0xff) + (~s & 0xff) + cIn > 0xff);
                int cn = (r & 0xfff) + (~s & 0xfff) + cIn > 0xfff ? 1 : 0;
                Overflow = _overflowTable[r >> 12, (~s & 0xffff) >> 12, cn];
            }
            break;

            case AluFunction.RorS:
                f = r | s;
                // A few microinstructions do an MAR<- with RorS and expect PgCarry to be set appropriately.
                NibCarry = _carryTableOr[r & 0xf, s & 0xf, cIn];
                PgCarry  = _carryTableOr[(r >> 4) & 0xf, (s >> 4) & 0xf, NibCarry ? 1 : 0];
                CarryOut = false;
                Overflow = false;
                break;

            case AluFunction.RandS:
                f        = r & s;
                NibCarry = false;
                PgCarry  = false;
                CarryOut = false;
                Overflow = false;
                break;

            case AluFunction.notRandS:
                f        = (~r) & s;
                NibCarry = false;
                PgCarry  = false;
                CarryOut = false;
                Overflow = false;
                break;

            case AluFunction.RxorS:
                f        = r ^ s;
                NibCarry = false;
                PgCarry  = false;
                CarryOut = false;
                Overflow = false;
                break;

            case AluFunction.notRxorS:
                f        = (~r) ^ s;
                NibCarry = false;
                PgCarry  = false;
                CarryOut = false;
                Overflow = false;
                break;

            default:
                throw new InvalidOperationException(
                          String.Format("Unhandled function {0}", i.aF));
            }

            // Clip F to 16 bits
            f = f & 0xffff;

            if (loadMAR)
            {
                //
                // If the ALU is being run during a MAR<- operation, the top 8 bits of the ALU are
                // computed using an operator specified by aF | 3, with the source set to 0,B.
                // The CarryOut and Overflow flags are clear (since they are not affected by the
                // OR/notXOR operation), and the carry from the least-significant byte of the ALU does not
                // carry over to the most-significant byte.
                //
                // See page 25 of the microcode ref for details.
                //
                // We implement this here by overwriting the upper byte of F with the upper bits of rB
                // (or its complement).  Interlisp microcode expects Overflow and Carry to be set appropriately.
                //
                switch ((AluFunction)((int)i.aF | 0x3))
                {
                case AluFunction.RorS:
                {
                    f = (f & 0xff) | (_r[i.rB] & 0xff00);
                    bool midCarry = _carryTableOr[(r >> 8) & 0xf, (s >> 8) & 0xf, PgCarry ? 1 : 0];
                    Overflow = CarryOut = _carryTableOr[(r >> 12) & 0xf, (s >> 12) & 0xf, midCarry ? 1 : 0];
                }
                break;

                case AluFunction.notRxorS:
                {
                    f = (f & 0xff) | ((~_r[i.rB]) & 0xff00);
                    bool midCarry = _carryTableNotXor[(r >> 8) & 0xf, (s >> 8) & 0xf, PgCarry ? 1 : 0];
                    CarryOut = _carryTableNotXor[(r >> 12) & 0xf, (s >> 12) & 0xf, midCarry ? 1 : 0];
                    Overflow = _overflowNotXor[(r >> 12) & 0xf, (s >> 12) & 0xf, midCarry ? 1 : 0];
                }
                break;
                }
            }

            Zero = (f == 0);
            Neg  = ((f & 0x8000) != 0);

            //
            // Write outputs, do shifts and cycles as appropriate before writing back.
            // (Shifts and cycles do not affect the Y output, only the register being written back to.)
            //
            switch (i.AluDestination)
            {
            case 0:
                _q = (ushort)f;
                Y  = (ushort)f;
                break;

            case 1:
                Y = (ushort)f;
                break;

            case 2:
                Y        = _r[i.rA];
                _r[i.rB] = (ushort)f;
                break;

            case 3:
                _r[i.rB] = (ushort)f;
                Y        = (ushort)f;
                break;

            case 4:
                Y = (ushort)f;

                if (i.Cycle)
                {
                    // double-word right shift
                    // MSB of Q gets inverted LSB of F.
                    _q = (ushort)((_q >> 1) | ((~f & 0x1) << 15));

                    // MSB of F gets Carry in.
                    f = (ushort)((f >> 1) | (carryIn ? 0x8000 : 0x0));
                }
                else
                {
                    // double-word arithmetic right shift.
                    // MSB of Q gets inverted LSB of F.
                    _q = (ushort)((_q >> 1) | ((~f & 0x1) << 15));

                    // MSB of F gets Carry out.
                    f = (ushort)((f >> 1) | (CarryOut ? 0x8000 : 0x0));
                }
                _r[i.rB] = (ushort)f;
                break;

            case 5:
                Y = (ushort)f;
                if (i.Cycle)
                {
                    // F: single-word right rotate:
                    f = (ushort)((f >> 1) | ((f & 0x1) << 15));
                }
                else
                {
                    // F: single-word right shift w/carryIn to MSB:
                    f = (ushort)((f >> 1) | (carryIn ? 0x8000 : 0x0));
                }
                _r[i.rB] = (ushort)f;
                break;

            case 6:
                Y = (ushort)f;

                // double-word left shift (apparently identical for cycle and shift)
                // LSB of F gets MSB of Q, not inverted.
                f = (ushort)((f << 1) | ((_q & 0x8000) >> 15));

                // LSB of Q gets Cin, inverted
                _q = (ushort)((_q << 1) | (1 - cIn));

                _r[i.rB] = (ushort)f;
                break;

            case 7:
                Y = (ushort)f;
                if (i.Cycle)
                {
                    // F: single-word left rotate:
                    f = (ushort)((f << 1) | ((f & 0x8000) >> 15));
                }
                else
                {
                    // F: single-word left shift w/carryIn to LSB:
                    f = (ushort)((f << 1) | cIn);
                }
                _r[i.rB] = (ushort)f;
                break;

            default:
                throw new InvalidOperationException(
                          String.Format("Unhandled destination {0}", i.aF));
            }

            return(Y);
        }