public void NegativeStackOffset_IsUsedCalculateAddresses_InTheExistingStackFrame() { var offset = new NewStackFrame(0, 3); var negative = new StackFrame(3); Assert.That(offset.NewStackPointer + negative.ReturnValue, Is.EqualTo(offset.ReturnValue)); Assert.That(offset.NewStackPointer + negative.Register0, Is.EqualTo(offset.Register0)); Assert.That(offset.NewStackPointer + negative.Register1, Is.EqualTo(offset.Register1)); Assert.That(offset.NewStackPointer + negative.Register2, Is.EqualTo(offset.Register2)); Assert.That(offset.NewStackPointer + negative.Register3, Is.EqualTo(offset.Register3)); Assert.That(offset.NewStackPointer + negative.Register4, Is.EqualTo(offset.Register4)); Assert.That(offset.NewStackPointer + negative.Register5, Is.EqualTo(offset.Register5)); Assert.That(offset.NewStackPointer + negative.Register6, Is.EqualTo(offset.Register6)); }
public void NewStackFrame_IsUsedToCalculateAddresses_InANewStackFrame_ForACaller() { // new stackframe beginning at address 20, with 3 arguments var offset = new NewStackFrame(20, 3); Assert.That(offset.ReturnValue, Is.EqualTo(20)); Assert.That(offset.Argn(0), Is.EqualTo(21)); Assert.That(offset.Argn(1), Is.EqualTo(22)); Assert.That(offset.Argn(2), Is.EqualTo(23)); Assert.That(() => offset.Argn(3), Throws.Exception.InstanceOf <ArgumentOutOfRangeException>()); Assert.That(offset.ReturnAddress, Is.EqualTo(24)); Assert.That(offset.Register0, Is.EqualTo(25)); Assert.That(offset.Register1, Is.EqualTo(26)); Assert.That(offset.Register2, Is.EqualTo(27)); Assert.That(offset.Register3, Is.EqualTo(28)); Assert.That(offset.Register4, Is.EqualTo(29)); Assert.That(offset.Register5, Is.EqualTo(30)); Assert.That(offset.Register6, Is.EqualTo(31)); Assert.That(offset.NewStackPointer, Is.EqualTo(32)); }
public static string Call(ref int lineNumber, NewStackFrame newStackFrame, StackFrame calleeStackFrame, string name) { return($@"* Call '{name}' {lineNumber++}: ST 0, {newStackFrame.Register0}(6) ; store registers in stack frame {lineNumber++}: ST 1, {newStackFrame.Register1}(6) {lineNumber++}: ST 2, {newStackFrame.Register2}(6) {lineNumber++}: ST 3, {newStackFrame.Register3}(6) {lineNumber++}: ST 4, {newStackFrame.Register4}(6) {lineNumber++}: ST 5, {newStackFrame.Register5}(6) {lineNumber++}: ST 6, {newStackFrame.Register6}(6) {lineNumber++}: LDA 5, 3(7) ; calculate address of **return point** {lineNumber++}: ST 5, {newStackFrame.ReturnAddress}(6) ; store return address in stack frame {lineNumber++}: LDA 6, {newStackFrame.NewStackPointer}(6) ; set value of stack pointer (r6) to one past top of new stack frame {lineNumber++}: LDA 7, [func:{name}](0) ; jump to function {lineNumber++}: LD 0, {calleeStackFrame.Register0}(6) ; **return point**, restore registers from stack frame {lineNumber++}: LD 1, {calleeStackFrame.Register1}(6) {lineNumber++}: LD 2, {calleeStackFrame.Register2}(6) {lineNumber++}: LD 3, {calleeStackFrame.Register3}(6) {lineNumber++}: LD 4, {calleeStackFrame.Register4}(6) {lineNumber++}: LD 5, {calleeStackFrame.Register5}(6) {lineNumber++}: LD 6, {calleeStackFrame.Register6}(6) ; r6 stack pointer gets loaded last * End Call '{name}' "); }
public static string Param(ref int lineNumber, StackFrame stackFrame, NewStackFrame newStackFrame, string variable, int argNum) { return($@"{lineNumber++}: LD 2, {stackFrame.Address(variable)}(6) ; param{argNum} := {variable} {lineNumber++}: ST 2, {newStackFrame.Argn(argNum)}(6) "); }