Example #1
0
        private void DoStoreForCurrentInstruction(ushort word)
        {
            ushort effectiveAddress = _currentInstruction.IsIndirect ? _currentIndirectAddress : GetEffectiveAddress(_currentInstruction.Data);

            // If there's a write breakpoint on this address we will halt here.
            if (BreakpointManager.TestBreakpoint(BreakpointType.Write, effectiveAddress))
            {
                _state             = ProcessorState.BreakpointHalt;
                _breakpointAddress = effectiveAddress;
            }

            _mem.Store(effectiveAddress, word);
        }
Example #2
0
        private ushort DoFetchForCurrentInstruction()
        {
            ushort effectiveAddress = _currentInstruction.IsIndirect ? _currentIndirectAddress : GetEffectiveAddress(_currentInstruction.Data);

            // If there's a read breakpoint on this address we will halt here.
            if (BreakpointManager.TestBreakpoint(BreakpointType.Read, effectiveAddress))
            {
                _state             = ProcessorState.BreakpointHalt;
                _breakpointAddress = effectiveAddress;
            }

            return(_mem.Fetch(effectiveAddress));
        }
Example #3
0
        private void ExecuteIncrement()
        {
            int halfWord = _immediateHalf == ImmediateHalf.First ? (_immediateWord & 0xff00) >> 8 : (_immediateWord & 0xff);

            // translate the half word to vector movements or escapes
            if ((halfWord & 0x80) == 0)
            {
                // Control Byte:

                if ((halfWord & 0x40) != 0)
                {
                    // Escape code
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "Increment mode escape on halfword {0}", _immediateHalf);
                    }
                    _mode = DisplayProcessorMode.Processor;
                    _pc++;  // move to next word

                    if ((halfWord & 0x20) != 0)
                    {
                        if (Trace.TraceOn)
                        {
                            Trace.Log(LogType.DisplayProcessor, "Increment mode return from subroutine.");
                        }
                        ReturnFromDisplaySubroutine();
                    }
                }
                else
                {
                    // Stay in increment mode.
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "Increment instruction, non-drawing.");
                    }
                    MoveToNextHalfWord();
                }

                if ((halfWord & 0x10) != 0)
                {
                    X += MSBIncrement;
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "Increment X MSB, X is now {0}", X);
                    }
                }

                if ((halfWord & 0x08) != 0)
                {
                    X = X & (MSBMask);
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "Reset X LSB, X is now {0}", X);
                    }
                }

                if ((halfWord & 0x02) != 0)
                {
                    Y += MSBIncrement;
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "Increment Y MSB, Y is now {0}", Y);
                    }
                }

                if ((halfWord & 0x01) != 0)
                {
                    Y = Y & (MSBMask);
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "Reset Y LSB, Y is now {0}", Y);
                    }
                }

                _system.Display.MoveAbsolute(X, Y, DrawingMode.Off);
            }
            else
            {
                // Drawing Byte:

                int xSign = ((halfWord & 0x20) == 0) ? 1 : -1;
                int xMag  = (int)(((halfWord & 0x18) >> 3) * _scale);

                int ySign = (int)(((halfWord & 0x04) == 0) ? 1 : -1);
                int yMag  = (int)((halfWord & 0x03) * _scale);

                if (Trace.TraceOn)
                {
                    Trace.Log(LogType.DisplayProcessor, "Inc mode ({0}:{1}), x={2} y={3} dx={4} dy={5} beamon {6}", Helpers.ToOctal((ushort)_pc), Helpers.ToOctal((ushort)halfWord), X, Y, xSign * xMag, ySign * yMag, (halfWord & 0x40) != 0);
                }

                X = X + xSign * xMag;
                Y = Y + ySign * yMag;
                _system.Display.MoveAbsolute(X, Y, (halfWord & 0x40) == 0 ? DrawingMode.Off : DrawingMode.Normal);

                MoveToNextHalfWord();
            }

            // If the next instruction has a breakpoint set we'll halt at this point, before executing it.
            if (_immediateHalf == ImmediateHalf.First && BreakpointManager.TestBreakpoint(BreakpointType.Display, _pc))
            {
                _state = ProcessorState.BreakpointHalt;
            }
        }
Example #4
0
        private void ExecuteProcessor()
        {
            PDS4DisplayInstruction instruction = GetCachedInstruction(_pc, DisplayProcessorMode.Processor);

            instruction.UsageMode = DisplayProcessorMode.Processor;

            switch (instruction.Opcode)
            {
            case DisplayOpcode.DEIM:
                _mode          = DisplayProcessorMode.Increment;
                _immediateWord = instruction.Data;
                _immediateHalf = ImmediateHalf.Second;
                if (Trace.TraceOn)
                {
                    Trace.Log(LogType.DisplayProcessor, "Enter increment mode");
                }
                break;

            case DisplayOpcode.DJMP:
                if (!_dadr)
                {
                    // DADR off, use only 12 bits
                    _pc = (ushort)((instruction.Data & 0xfff) | _block);
                }
                else
                {
                    _pc = (ushort)(instruction.Data | _block);
                }
                break;

            case DisplayOpcode.DJMS:
                Push();

                if (!_dadr)
                {
                    // DADR off, use only 12 bits
                    _pc = (ushort)((instruction.Data & 0xfff) | _block);
                }
                else
                {
                    _pc = (ushort)(instruction.Data | _block);
                }
                break;

            case DisplayOpcode.DOPR:
                // Each of bits 4-11 can be combined in any fashion
                // to do a number of operations simultaneously; we walk the bits
                // and perform the operations as set.
                if ((instruction.Data & 0x800) == 0)
                {
                    // DHLT -- halt the display processor.  other micro-ops in this
                    // instruction are still run.
                    HaltProcessor();
                }

                // Used to modify DSTS or DSTB operation
                bool bit5 = (instruction.Data & 0x400) != 0;

                if ((instruction.Data & 0x200) != 0)
                {
                    // DIXM -- increment X DAC MSB
                    X += MSBIncrement;
                    _system.Display.MoveAbsolute(X, Y, DrawingMode.Off);
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "DIXM, X is now {0}", X);
                    }
                }

                if ((instruction.Data & 0x100) != 0)
                {
                    // DIYM -- increment Y DAC MSB
                    Y += MSBIncrement;
                    _system.Display.MoveAbsolute(X, Y, DrawingMode.Off);
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "DIYM, Y is now {0}", Y);
                    }
                }

                if ((instruction.Data & 0x80) != 0)
                {
                    // DDXM - decrement X DAC MSB
                    X -= MSBIncrement;
                    _system.Display.MoveAbsolute(X, Y, DrawingMode.Off);
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "DDXM, X is now {0}", X);
                    }
                }

                if ((instruction.Data & 0x40) != 0)
                {
                    // DDYM - decrement y DAC MSB
                    Y -= MSBIncrement;
                    _system.Display.MoveAbsolute(X, Y, DrawingMode.Off);
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "DDYM, Y is now {0}", Y);
                    }
                }

                if ((instruction.Data & 0x20) != 0)
                {
                    // DRJM - return from display subroutine
                    ReturnFromDisplaySubroutine();
                    _pc--;      // hack (we add +1 at the end...)
                }

                if ((instruction.Data & 0x10) != 0)
                {
                    // DDSP -- intensify point on screen for 1.8us (one instruction)
                    // at the current position.
                    _system.Display.DrawPoint(X, Y);

                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "DDSP at {0},{1}", X, Y);
                    }
                }

                // F/C ops:
                int f = (instruction.Data & 0xc) >> 2;
                int c = instruction.Data & 0x3;

                switch (f)
                {
                case 0x0:
                    // if bit 15 is set, the MIT mods flip the DADR bit.
                    if (Configuration.MITMode && (c == 1))
                    {
                        _dadr = !_dadr;
                    }
                    break;

                case 0x1:
                    // Set scale based on C and Bit 5.
                    _scale = c + (bit5 ? 4 : 0);

                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "Scale set to {0}", _scale);
                    }
                    break;

                case 0x2:
                    _block = (ushort)((c + (bit5 ? 4 : 0) << 12));
                    break;

                case 0x3:
                    // TODO: light pen sensitize
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "Light pen, stub!");
                    }
                    break;
                }

                _pc++;
                break;

            case DisplayOpcode.DLXA:
                X = instruction.Data;

                DrawingMode mode;
                if (_fxyOn && _fxyBeamOn)
                {
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "SGR-1 X set to {0}", X);
                    }
                    mode = DrawingMode.SGR1;
                }
                else
                {
                    mode = DrawingMode.Off;
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "X set to {0}", X);
                    }
                }

                _system.Display.MoveAbsolute(X, Y, mode);

                if (_fxyDRJMOn)
                {
                    ReturnFromDisplaySubroutine();
                }
                else
                {
                    _pc++;
                }
                break;

            case DisplayOpcode.DLYA:
                Y = instruction.Data;

                if (_fxyOn && _fxyBeamOn)
                {
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "SGR-1 Y set to {0}", Y);
                    }
                    mode = DrawingMode.SGR1;
                }
                else
                {
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "Y set to {0}", Y);
                    }
                    mode = DrawingMode.Off;
                }

                _system.Display.MoveAbsolute(X, Y, mode);

                if (_fxyDRJMOn)
                {
                    ReturnFromDisplaySubroutine();
                }
                else
                {
                    _pc++;
                }
                break;

            case DisplayOpcode.DLVH:
                DrawLongVector(instruction.Data);
                break;

            case DisplayOpcode.DFXY:
                _fxyOn     = (instruction.Data & 0x1) != 0;
                _fxyDRJMOn = (instruction.Data & 0x2) != 0;
                _fxyBeamOn = (instruction.Data & 0x4) != 0;

                if (Trace.TraceOn)
                {
                    Trace.Log(LogType.DisplayProcessor, "SGR-1 instruction: Enter {0} BeamOn {1} DRJM {2}",
                              _fxyOn,
                              _fxyBeamOn,
                              _fxyDRJMOn);
                }

                _pc++;
                break;

            case DisplayOpcode.DVIC:
                _system.Display.SetIntensity(instruction.Data);
                _pc++;
                break;

            case DisplayOpcode.DCAM:
                // Enter Compact Addressing Mode, this is supposedly illegal if
                // we're already in that mode, so we'll throw here to help with debugging
                if (_camEnabled)
                {
                    throw new InvalidOperationException("DCAM while in Compact Addressing Mode.");
                }

                _camEnabled = true;

                // subroutine table address is the next word.  Low 8-bits should be zero, we'll
                // sanity check it.
                _caBase = _mem.Fetch(++_pc);

                if ((_caBase & 0xff) != 0)
                {
                    throw new InvalidOperationException(
                              String.Format("CAM subroutine base address {0} not on a 256-word boundary!",
                                            Helpers.ToOctal(_caBase)));
                }

                // start things off by fetching the first subroutine word.  This is not strictly
                // accurate with respect to timing.  (Ok, it's not accurate at all.)
                // TODO: refactor Immediate halfword routines here (share w/short vectors?)
                _camWord = _mem.Fetch(++_pc);
                _camHalf = ImmediateHalf.First;
                if (Trace.TraceOn)
                {
                    Trace.Log(LogType.DisplayProcessor, "Enter Compact Addressing mode, base address {0}",
                              Helpers.ToOctal(_caBase));
                }

                _mode = DisplayProcessorMode.CompactAddressing;
                break;

            case DisplayOpcode.DBLI:
                _system.Display.SetBlink((instruction.Data) != 0);
                _pc++;
                break;

            default:
                throw new NotImplementedException(String.Format("Unimplemented Display Processor Opcode {0}, ({1}), operands {1}",
                                                                instruction.Opcode,
                                                                Helpers.ToOctal((ushort)instruction.Opcode),
                                                                Helpers.ToOctal(instruction.Data)));
            }

            // If the next instruction has a breakpoint set we'll halt at this point, before executing it.
            if (BreakpointManager.TestBreakpoint(BreakpointType.Display, _pc))
            {
                _state = ProcessorState.BreakpointHalt;
            }
        }
        private void ExecuteIncrement()
        {
            int halfWord = _immediateHalf == ImmediateHalf.First ? (_immediateWord & 0xff00) >> 8 : (_immediateWord & 0xff);

            int newX = (int)X;
            int newY = (int)Y;

            // translate the half word to vector movements or escapes
            if ((halfWord & 0x80) == 0)
            {
                if ((halfWord & 0x40) != 0)
                {
                    // Escape code
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "Increment mode escape on halfword {0}", _immediateHalf);
                    }
                    _mode = DisplayProcessorMode.Processor;
                    _pc++;  // move to next word

                    // Moved this into this check (not sure it makes sense to do a DJMS when not escaped from Increment mode)
                    if ((halfWord & 0x20) != 0)
                    {
                        if (Trace.TraceOn)
                        {
                            Trace.Log(LogType.DisplayProcessor, "Increment mode return from subroutine.");
                        }
                        ReturnFromDisplaySubroutine();
                    }
                }
                else
                {
                    // Stay in increment mode.
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "Increment instruction, non-drawing.");
                    }
                    MoveToNextHalfWord();
                }

                if ((halfWord & 0x10) != 0)
                {
                    newX += 0x20;
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "Increment X MSB, X is now {0}", X);
                    }
                }

                if ((halfWord & 0x08) != 0)
                {
                    newX = newX & (0xffe0);
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "Reset X LSB, X is now {0}", X);
                    }
                }

                if ((halfWord & 0x02) != 0)
                {
                    newY += 0x20;
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "Increment Y MSB, Y is now {0}", Y);
                    }
                }

                if ((halfWord & 0x01) != 0)
                {
                    newY = newY & (0xffe0);
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "Reset Y LSB, Y is now {0}", Y);
                    }
                }

                _system.Display.MoveAbsolute(newX, newY, DrawingMode.Off);
            }
            else
            {
                int xSign = ((halfWord & 0x20) == 0) ? 1 : -1;
                int xMag  = (int)(((halfWord & 0x18) >> 3) * _scale);

                int ySign = (int)(((halfWord & 0x04) == 0) ? 1 : -1);
                int yMag  = (int)((halfWord & 0x03) * _scale);

                if (Trace.TraceOn)
                {
                    Trace.Log(LogType.DisplayProcessor,
                              "Inc mode ({0}:{1}), x={2} y={3} dx={4} dy={5} beamon {6}",
                              Helpers.ToOctal((ushort)_pc),
                              Helpers.ToOctal((ushort)halfWord),
                              newX,
                              newY,
                              xSign * xMag,
                              ySign * yMag,
                              (halfWord & 0x40) != 0);
                }

                newX = (int)(newX + xSign * xMag * 2);
                newY = (int)(newY + ySign * yMag * 2);

                _system.Display.MoveAbsolute(newX, newY, (halfWord & 0x40) == 0 ? DrawingMode.Off : DrawingMode.Dotted);

                MoveToNextHalfWord();
            }

            // Assign back to X, Y registers; clipping into range.
            X = newX;
            Y = newY;

            // If the next instruction has a breakpoint set we'll halt at this point, before executing it.
            if (_immediateHalf == ImmediateHalf.First && BreakpointManager.TestBreakpoint(BreakpointType.Display, _pc))
            {
                _state = ProcessorState.BreakpointHalt;
            }
        }
        private void ExecuteProcessor()
        {
            PDS1DisplayInstruction instruction = GetCachedInstruction(_pc, DisplayProcessorMode.Processor);

            instruction.UsageMode = DisplayProcessorMode.Processor;

            switch (instruction.Opcode)
            {
            case DisplayOpcode.DEIM:
                _mode          = DisplayProcessorMode.Increment;
                _immediateWord = instruction.Data;
                _immediateHalf = ImmediateHalf.Second;
                if (Trace.TraceOn)
                {
                    Trace.Log(LogType.DisplayProcessor, "Enter increment mode");
                }
                break;

            case DisplayOpcode.DJMP:
                if (!_dadr)
                {
                    // DADR off, use only 12 bits
                    _pc = (ushort)((instruction.Data & 0xfff) | _block);
                }
                else
                {
                    _pc = (ushort)(instruction.Data | _block);
                }
                break;

            case DisplayOpcode.DJMS:
                Push();

                if (!_dadr)
                {
                    // DADR off, use only 12 bits
                    _pc = (ushort)((instruction.Data & 0xfff) | _block);
                }
                else
                {
                    _pc = (ushort)(instruction.Data | _block);
                }
                break;

            case DisplayOpcode.DOPR:
                // Each of bits 4-11 can be combined in any fashion
                // to do a number of operations simultaneously; we walk the bits
                // and perform the operations as set.
                if ((instruction.Data & 0x800) == 0)
                {
                    // DHLT -- halt the display processor.  other micro-ops in this
                    // instruction are still run.
                    HaltProcessor();
                }

                if ((instruction.Data & 0x400) != 0)
                {
                    // HV Sync; this is currently a no-op, not much to do in emulation.
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "HV Sync");
                    }

                    _system.Display.MoveAbsolute(X, Y, DrawingMode.Off);
                }

                if ((instruction.Data & 0x200) != 0)
                {
                    // DIXM -- increment X DAC MSB
                    X += 0x20;
                    _system.Display.MoveAbsolute(X, Y, DrawingMode.Off);
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "DIXM, X is now {0}", X);
                    }
                }

                if ((instruction.Data & 0x100) != 0)
                {
                    // DIYM -- increment Y DAC MSB
                    Y += 0x20;
                    _system.Display.MoveAbsolute(X, Y, DrawingMode.Off);
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "DIYM, Y is now {0}", Y);
                    }
                }

                if ((instruction.Data & 0x80) != 0)
                {
                    // DDXM - decrement X DAC MSB
                    X -= 0x20;
                    _system.Display.MoveAbsolute(X, Y, DrawingMode.Off);
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "DDXM, X is now {0}", X);
                    }
                }

                if ((instruction.Data & 0x40) != 0)
                {
                    // DDYM - decrement y DAC MSB
                    Y -= 0x20;
                    _system.Display.MoveAbsolute(X, Y, DrawingMode.Off);
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "DDYM, Y is now {0}", Y);
                    }
                }

                if ((instruction.Data & 0x20) != 0)
                {
                    // DRJM - return from display subroutine
                    ReturnFromDisplaySubroutine();
                    _pc--;      // hack (we add +1 at the end...)
                }

                if ((instruction.Data & 0x10) != 0)
                {
                    // DDSP -- intensify point on screen for 1.8us (one instruction)
                    // at the current position.
                    _system.Display.DrawPoint(X, Y);

                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "DDSP at {0},{1}", X, Y);
                    }
                }

                // F/C ops:
                int f = (instruction.Data & 0xc) >> 2;
                int c = instruction.Data & 0x3;

                switch (f)
                {
                case 0x0:
                    // if bit 15 is set, the MIT mods flip the DADR bit.
                    if (Configuration.MITMode && (c == 1))
                    {
                        _dadr = !_dadr;
                    }
                    break;

                case 0x1:
                    // Set scale based on C
                    switch (c)
                    {
                    case 0:
                        _scale = 1.0f;
                        break;

                    default:
                        _scale = c;
                        break;
                    }
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "Scale set to {0}", _scale);
                    }
                    break;

                case 0x2:
                    if (!Configuration.MITMode)
                    {
                        _block = (ushort)(c << 12);
                    }
                    break;

                case 0x3:
                    // TODO: light pen sensitize
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "Light pen, stub!");
                    }
                    break;
                }

                _pc++;
                break;

            case DisplayOpcode.DLXA:
                X = instruction.Data << 1;

                DrawingMode mode;
                if (_sgrModeOn && _sgrBeamOn)
                {
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "SGR-1 X set to {0}", X);
                    }
                    mode = DrawingMode.SGR1;
                }
                else
                {
                    mode = DrawingMode.Off;
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "X set to {0}", X);
                    }
                }

                _system.Display.MoveAbsolute(X, Y, mode);

                if (_sgrDJRMOn)
                {
                    ReturnFromDisplaySubroutine();
                }
                else
                {
                    _pc++;
                }
                break;

            case DisplayOpcode.DLYA:
                Y = instruction.Data << 1;

                if (_sgrModeOn && _sgrBeamOn)
                {
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "SGR-1 Y set to {0}", Y);
                    }
                    mode = DrawingMode.SGR1;
                }
                else
                {
                    if (Trace.TraceOn)
                    {
                        Trace.Log(LogType.DisplayProcessor, "Y set to {0}", Y);
                    }
                    mode = DrawingMode.Off;
                }

                _system.Display.MoveAbsolute(X, Y, mode);

                if (_sgrDJRMOn)
                {
                    ReturnFromDisplaySubroutine();
                }
                else
                {
                    _pc++;
                }
                break;

            case DisplayOpcode.DLVH:
                DrawLongVector(instruction.Data);
                break;

            case DisplayOpcode.SGR1:
                _sgrModeOn = (instruction.Data & 0x1) != 0;
                _sgrDJRMOn = (instruction.Data & 0x2) != 0;
                _sgrBeamOn = (instruction.Data & 0x4) != 0;

                if (Trace.TraceOn)
                {
                    Trace.Log(LogType.DisplayProcessor, "SGR-1 instruction: Enter {0} BeamOn {1} DRJM {2}", _sgrModeOn, _sgrBeamOn, _sgrDJRMOn);
                }
                _pc++;
                break;

            default:
                throw new NotImplementedException(String.Format("Unimplemented Display Processor Opcode {0}, operands {1}", Helpers.ToOctal((ushort)instruction.Opcode), Helpers.ToOctal(instruction.Data)));
            }

            // If the next instruction has a breakpoint set we'll halt at this point, before executing it.
            if (BreakpointManager.TestBreakpoint(BreakpointType.Display, _pc))
            {
                _state = ProcessorState.BreakpointHalt;
            }
        }
Example #7
0
        private void Execute()
        {
            ushort q;
            uint   res;

            switch (_currentInstruction.Opcode)
            {
            case Opcode.ADD:
                q   = DoFetchForCurrentInstruction();
                res = (uint)(_ac + q);

                _ac = (ushort)res;

                // link bit is complemented if carry-out occurs
                if ((res & 0x10000) != 0)
                {
                    _link = (ushort)((_link ^ 1) & 0x1);
                }
                _pc++;
                break;

            case Opcode.AND:
                _ac = (ushort)(_ac & DoFetchForCurrentInstruction());
                _pc++;
                break;

            case Opcode.DAC:
                DoStoreForCurrentInstruction(_ac);
                _pc++;
                break;

            case Opcode.IOR:
                _ac = (ushort)(_ac | DoFetchForCurrentInstruction());
                _pc++;
                break;

            case Opcode.IOT:
                DoIOT();
                _pc++;
                break;

            case Opcode.ISZ:
                q = DoFetchForCurrentInstruction();
                q++;
                DoStoreForCurrentInstruction(q);

                if (q == 0)
                {
                    _pc++;      // skip next instruction
                }

                _pc++;
                break;

            case Opcode.JMP:
                if (_currentInstruction.IsIndirect)
                {
                    _pc = _currentIndirectAddress;
                }
                else
                {
                    _pc = GetEffectiveAddress(_currentInstruction.Data);
                }
                break;

            case Opcode.JMS:
                // Store next PC at location specified by instruction (Q),
                // continue execution at Q+1
                DoStoreForCurrentInstruction((ushort)(_pc + 1));

                if (_currentInstruction.IsIndirect)
                {
                    _pc = (ushort)(_currentIndirectAddress + 1);
                }
                else
                {
                    _pc = (ushort)(GetEffectiveAddress(_currentInstruction.Data) + 1);
                }
                break;

            case Opcode.LAC:
                _ac = DoFetchForCurrentInstruction();
                _pc++;
                break;

            case Opcode.LAW:
                _ac = _currentInstruction.Data;
                _pc++;
                break;

            case Opcode.LWC:
                _ac = (ushort)(-_currentInstruction.Data);
                _pc++;
                break;

            case Opcode.OPR:
                // Execute the Operate Class 1 instruction based on the data bits.

                // T1: Clear AC and / or Link
                if ((_currentInstruction.Data & 0x0001) != 0)
                {
                    _ac = 0x0000;
                }

                if ((_currentInstruction.Data & 0x0008) != 0)
                {
                    _link = 0;
                }

                // T2: 1's Complement AC and / or Link
                if ((_currentInstruction.Data & 0x0002) != 0)
                {
                    _ac = (ushort)(~_ac);
                }

                if ((_currentInstruction.Data & 0x0010) != 0)
                {
                    _link = (ushort)((~_link) & 0x1);
                }

                // T3: Increment AC and / or OR data switches with AC
                if ((_currentInstruction.Data & 0x0004) != 0)
                {
                    _ac++;

                    // If an overflow occurs, the link is complemented.
                    _link = (_ac == 0) ? (ushort)((~_link) & 0x1) : _link;
                }

                if ((_currentInstruction.Data & 0x0020) != 0)
                {
                    _ac |= _ds;
                }

                if ((_currentInstruction.Data & 0x8000) == 0)
                {
                    // Halt the CPU.
                    _state = ProcessorState.Halted;
                }

                _pc++;
                break;

            case Opcode.RAL:
                // TODO: this is pretty inefficient.
                for (int i = 0; i < _currentInstruction.Data; i++)
                {
                    ushort oldLink = _link;
                    _link = (ushort)((_ac & 0x8000) >> 15);
                    _ac   = (ushort)((_ac << 1) | oldLink);
                }

                if (_currentInstruction.DisplayOn)
                {
                    _system.DisplayProcessor.State = ProcessorState.Running;
                }

                _pc++;
                break;

            case Opcode.RAR:
                for (int i = 0; i < _currentInstruction.Data; i++)
                {
                    ushort oldLink = _link;
                    _link = (ushort)((_ac & 0x0001));
                    _ac   = (ushort)((_ac >> 1) | (oldLink << 15));
                }

                if (_currentInstruction.DisplayOn)
                {
                    _system.DisplayProcessor.State = ProcessorState.Running;
                }

                _pc++;
                break;

            case Opcode.SAL:
                // The shift operators are arithmetic (& preserve sign).  Shifting left only shifts bits 2-15 left,
                // bit 0 stays the same and bit 1 is lost (the link register is not involved in any way).
                ushort bitZero = (ushort)(_ac & 0x8000);
                for (int i = 0; i < _currentInstruction.Data; i++)
                {
                    _ac = (ushort)(_ac << 1);
                }
                _ac = (ushort)(bitZero | (_ac & 0x7fff));

                if (_currentInstruction.DisplayOn)
                {
                    _system.DisplayProcessor.State = ProcessorState.Running;
                }

                _pc++;
                break;

            case Opcode.SAM:
                q = DoFetchForCurrentInstruction();
                if (_ac == q)
                {
                    _pc++;
                }
                _pc++;
                break;

            case Opcode.SAR:
                // The shift operators are arithmetic (& preserve sign).  Shifting right shifts bits 1-14 left,
                // bit 0 is copied to bit 1, and bit 15 is lost (the link register is not involved in any way).
                bitZero = (ushort)(_ac & 0x8000);
                for (int i = 0; i < _currentInstruction.Data; i++)
                {
                    _ac = (ushort)(_ac >> 1);
                    _ac = (ushort)(bitZero | _ac);
                }

                if (_currentInstruction.DisplayOn)
                {
                    _system.DisplayProcessor.State = ProcessorState.Running;
                }

                _pc++;
                break;

            case Opcode.SKP:
                bool skip = false;

                // AC == 0
                if ((_currentInstruction.Data & 0x0001) != 0)
                {
                    skip = (_ac == 0);
                }

                // AC > = 0
                if ((_currentInstruction.Data & 0x0002) != 0)
                {
                    skip = ((_ac & 0x8000) == 0);
                }

                // Link == 0
                if ((_currentInstruction.Data & 0x0004) != 0)
                {
                    skip = (_link == 0);
                }

                // Display on
                if ((_currentInstruction.Data & 0x0008) != 0)
                {
                    skip = (_system.DisplayProcessor.State == ProcessorState.Running);
                }

                // Keyboard data present
                if ((_currentInstruction.Data & 0x0010) != 0)
                {
                    skip = _system.Keyboard.KeyReady;
                }

                // TTY input present
                if ((_currentInstruction.Data & 0x0020) != 0)
                {
                    skip = _system.TTY.DataReady;
                }

                // TTY send complete
                if ((_currentInstruction.Data & 0x0040) != 0)
                {
                    skip = _system.TTY.DataSendReady;
                }

                // 40Hz display sync
                if ((_currentInstruction.Data & 0x0080) != 0)
                {
                    skip = _system.DisplayProcessor.FrameLatch;
                }

                // Paper Tape Reader data present
                if ((_currentInstruction.Data & 0x0100) != 0)
                {
                    skip = _system.PaperTapeReader.DataReady();
                }

                if (_currentInstruction.SkipNegate)
                {
                    skip = !skip;
                }

                if (skip)
                {
                    _pc++;
                }

                _pc++;
                break;

            case Opcode.SUB:
                q   = DoFetchForCurrentInstruction();
                res = (uint)(_ac - q);

                _ac = (ushort)res;

                // link bit is complemented if carry-in occurs
                if ((res & 0x10000) != 0)
                {
                    _link = (ushort)((_link ^ 1) & 0x1);
                }
                _pc++;
                break;

            case Opcode.XAM:
                q = DoFetchForCurrentInstruction();
                ushort ac = _ac;
                _ac = q;
                DoStoreForCurrentInstruction(ac);
                _pc++;
                break;

            case Opcode.XOR:
                _ac = (ushort)(_ac ^ DoFetchForCurrentInstruction());
                _pc++;
                break;

            default:
                throw new NotImplementedException(String.Format("Unimplemented Opcode {0}", _currentInstruction.Opcode));
            }

            // If the next instruction has a breakpoint set we'll halt at this point, before executing it.
            if (BreakpointManager.TestBreakpoint(BreakpointType.Execution, _pc))
            {
                _state             = ProcessorState.BreakpointHalt;
                _breakpointAddress = _pc;
            }
        }