Beispiel #1
0
 private void AddRtsInfo(JsrInfo info)
 {
     info.ReturnAddr        = _cpu.RPC;
     info.CyclesAfterRts    = _cpu.Cycles;
     info.RtsOpcodeAddr     = _cpu.OpcodeRPC;
     info.CallDepthAfterRts = CallDepth;
 }
Beispiel #2
0
        public void cpu_OnJSR(Cpu cpu)
        {
            Debug.Assert(cpu.OpCode == 0x20);   // JSR

            // 6502 JSR semantics
            StackByte jsrReturnAddrH = _stackBytes[StackPtr + 2];
            StackByte jsrReturnAddrL = _stackBytes[StackPtr + 1];

            JsrInfo info = new JsrInfo {
                JsrOpcodeAddr    = cpu.OpcodeRPC,
                JsrTargetAddr    = cpu.RPC,
                StackPtrAfterJsr = StackPtr,
                CyclesAfterJsr   = cpu.Cycles,
                JsrReturnAddrH   = jsrReturnAddrH,
                JsrReturnAddrL   = jsrReturnAddrL,
                CallDepthAtJsr   = CallDepth,
            };

            // check integrity of JsrInfo (ReturnAddrOnStack is calculated property)
            Debug.Assert((jsrReturnAddrL.Value | jsrReturnAddrH.Value << 8) == info.ReturnAddrOnStack);

            _jsrInfoStack.Push(info);

            jsrReturnAddrH.NotifyNewJsrInfo(info, AddressPart.High, cpu.Cycles);
            jsrReturnAddrL.NotifyNewJsrInfo(info, AddressPart.Low, cpu.Cycles);

            OnJSR?.Invoke(info);
        }
Beispiel #3
0
        public JsrInfo NotifyJsrInfoRetired(long cycles)
        {
            Debug.Assert(IsPartOfReturnAddr);
            JsrInfo jsrInfoToRetire = JsrInfo;

            _retiredJsrInfos.Push(jsrInfoToRetire);
            LastRetiredCycles = cycles;
            ClearJsrPartInfo();
            TraceLine("retired", StackPtr.ToHex(), _retiredJsrInfos.Count);
            return(jsrInfoToRetire);
        }
Beispiel #4
0
 public void NotifyNewJsrInfo(JsrInfo info, AddressPart addressPart, long cycles)
 {
     Debug.Assert(info != null);
     Debug.Assert(JsrInfo == null);
     Debug.Assert(addressPart != AddressPart.NA);
     Debug.Assert(addressPart == AddressPart.High ? info.JsrReturnAddrH == this : info.JsrReturnAddrL == this);
     Debug.Assert(cycles == info.CyclesAfterJsr);
     JsrInfo            = info;
     ReturnAddrPart     = addressPart;
     LastAssignedCycles = cycles;
 }
Beispiel #5
0
 public void cpu_OnPL(Cpu cpu)
 {
     OnPL?.Invoke(null);
     if (CurrentStackByte.IsPartOfReturnAddr)
     {
         JsrInfo info = CurrentStackByte.JsrInfo;
         TraceLine($"PL, retire{info.JsrOpcodeAddr.ToHex()}, {StackPtr.ToHex()}");
         info.JsrReturnAddrL.NotifyJsrInfoRetired(cpu.Cycles);
         info.JsrReturnAddrH.NotifyJsrInfoRetired(cpu.Cycles);
         info.CyclesAtRetire = cpu.Cycles;
         info.Retired        = true;
     }
     else
     {
         // ignore PL from stack which doesn't affect any return address on the stack
     }
 }
Beispiel #6
0
        public void cpu_OnRTS(Cpu cpu)
        {
            Debug.Assert(cpu.OpCode == 0x60);   // RTS
            // RTS adds 1 to RPC, so return address needs to be one byte less than target RPC
            // this how RTS is defined, so we can safely assert (6502 semantics, not StackWrapper semantics)
            StackByte highRtsPart = _stackBytes[StackPtr];
            StackByte lowRtsPart  = _stackBytes[StackPtr - 1];

            Debug.Assert(lowRtsPart.Value + (highRtsPart.Value << 8) + 1 == cpu.RPC);

            if (StackPtr == TopStackPtrH)
            {
                // StackPtr is at the level where the matching JSR happened
                JsrInfo info = PopJsrInfo(i => {
                    // TraceLine( $"<- RTS /{CallDepth} {cpu.RPC.ToHex()}" + (i.Retired ? $" (retired {i.JsrOpcodeAddr.ToHex()})" : "" ) );
                });
                AddRtsInfo(info);
                OnRTS?.Invoke(info);
            }
            else
            {
                Debug.Assert(false, "UNTESTED");
                if (StackPtr < TopStackPtrH)
                {
                    // probably a RTS jump table
                    // nothing to do for us here
                    // we could probably assert that StackPtr is 2 below exectedStackPtr, but maybe caller wants to pass sth on the stack?
                }
                else
                {
                    // probably an "exception", i.e. returning not to the caller but to the caller's caller
                    Debug.Assert(StackPtr > TopStackPtrH);

                    while (_jsrInfoStack.Count > 0 && StackPtr > TopStackPtrH)
                    {
                        JsrInfo info = PopJsrInfo(i => {
                            // TraceLine( $"<- ignored RTS /{CallDepth} {cpu.RPC.ToHex()}" + (i.Retired ? $" (retired {i.JsrOpcodeAddr.ToHex()})" : "") );
                        });
                        info.Ignored = true;
                        AddRtsInfo(info);
                        OnRTS?.Invoke(info);
                    }
                }
            }
        }
Beispiel #7
0
        private JsrInfo PopJsrInfo(Action <JsrInfo> action)
        {
            JsrInfo info = _jsrInfoStack.Pop();

            if (info.Retired)
            {
                JsrInfo retiredInfoL = info.JsrReturnAddrL._retiredJsrInfos.Pop();
                JsrInfo retiredInfoH = info.JsrReturnAddrH._retiredJsrInfos.Pop();
                Debug.Assert(retiredInfoL == retiredInfoH && retiredInfoL == info);
            }
            else
            {
                info.JsrReturnAddrH.ClearJsrPartInfo();
                info.JsrReturnAddrL.ClearJsrPartInfo();
            }
            action?.Invoke(info);
            return(info);
        }
Beispiel #8
0
 public void wrapper_OnTXS(JsrInfo info)
 {
     return;
 }
Beispiel #9
0
 public void wrapper_OnRts(JsrInfo info)
 {
     return;
 }
Beispiel #10
0
 public void wrapper_OnJsr(JsrInfo info)
 {
     _jsrInfoList.Add(info);
 }