private void AddRtsInfo(JsrInfo info) { info.ReturnAddr = _cpu.RPC; info.CyclesAfterRts = _cpu.Cycles; info.RtsOpcodeAddr = _cpu.OpcodeRPC; info.CallDepthAfterRts = CallDepth; }
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); }
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); }
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; }
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 } }
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); } } } }
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); }
public void wrapper_OnTXS(JsrInfo info) { return; }
public void wrapper_OnRts(JsrInfo info) { return; }
public void wrapper_OnJsr(JsrInfo info) { _jsrInfoList.Add(info); }