Principles of Computers 18th Lecture Pavel Ježek, Ph.D. pavel.jezek@d3s.mff.cuni.cz
6502 Registers (Accumulator Architecture) 7 0 X 7 0 Y 7 0 S 0000 0001 7 0 P 7 0 PC 15 0 6502: 8-bit CPU with 16-bit logical and physical address spaces (1:1 mapping between logical and physical addresses, i.e. logical address = physical address)
Load and Store & Setting Flags LDA #$xx LDA $xxxx LDA $xxxx,X LDA $xxxx,Y LDX imm/addr LDY imm/addr STA $xxxx STA $xxxx,X STA $xxxx,Y STX addr STY addr A := xx A := ($xxxx)^ A := ($xxxx + X)^ A := ($xxxx + Y)^ X := imm/addr Y := imm/addr ($xxxx)^ := A ($xxxx + X)^ := A ($xxxx + Y)^ := A addr := X addr := Y TAX TXA TAY TYA TSX TXS X := A A := X Y := A A := Y X := S S := X 7654 3210 P N... ..Z. P.Negative := target.7 if target = 0 then P.Zero := 1 else P.Zero := 0; PHP PLP PHA PLA push P (flags) pop P (flags) push A pop A CLC SEC P.Carry := 0 P.Carry := 1
Bitwise Operations ORA imm/addr AND imm/addr EOR imm/addr ? NOT ASL A LSR A ROL A ROR A A := A BitwiseOr imm/addr A := A BitwiseAnd imm/addr A := A BitwiseXor imm/addr EOR #$FF A := A shl 1 A := A shr 1 A := A rol 1 A := A ror 1 P.Negative := A.7 if A = 0 then P.Zero := 1 else P.Zero := 0;
Integer Operations (Adding 8-bit Numbers) 7654 3210 ADC imm/addr result := A + imm/addr + P.Carry P.Carry := result.8 A := result.7 … result.0 P N... ..ZC P.Negative := A.7 if A = 0 then P.Zero := 1 else P.Zero := 0; LSB of A stored at $A000 A7 A6 A5 A4 A3 A2 A1 A0 carry + + LSB of B stored at $B000 B7 B6 B5 B4 B3 B2 B1 B0 = LSB of C stored at $C000 = C8 carry C7 C6 C5 C4 C3 C2 C1 C0 LDA $A000 CLC ADC $B000 STA $C000
Integer Operations – Subtraction? Subtract with Borrow ADC imm/addr SBC imm/addr result := A + imm/addr + P.Carry P.Carry := result.8 A := result.7 … result.0 result := A – imm/addr – not(P.Carry) P.Carry := not(result.7) P.Negative := A.7 if A = 0 then P.Zero := 1 else P.Zero := 0; P.Negative := A.7 if A = 0 then P.Zero := 1 else P.Zero := 0; P.Negative := X/Y.7 if X/Y = 0 then P.Zero := 1 else P.Zero := 0; INX INY DEX DEY X := X + 1 Y := Y + 1 X := X – 1 Y := Y - 1
No Division (div), No Mutiplication (*) Instructions on 6502
How To Write/Compile Complex Expressions? x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x;
Rewriting Complex Expressions – Step 1: Function Calls As Separate Commands, Each Having Variables and Constants As Arguments Only (i.e. No Expressions As Arguments) x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; temp11 := b + c; temp12 := F1(temp11); temp21 := F3(2, 3); temp22 := d + e + temp21; temp23 := F4(4); temp24 := f + temp23; temp25 := F2(temp22, temp24); temp31 := F5(5); x := 1 + a + temp12 * temp25 + temp31 + x; Introducing temporary variables to hold intermediate results of inner subexpressions
Step 2: Rewrite To Have a := b op c Or d := F(…) Only x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; temp11 := b + c; temp12 := F1(temp11); temp21 := F3(2, 3); temp22 := d + e; temp22 := temp22 + temp21; temp23 := F4(4); temp24 := f + temp23; temp25 := F2(temp22, temp24); temp31 := F5(5); tempX := 1 + a; temp4 := temp12 * temp25; tempX := tempX + temp4; tempX := tempX + temp31; x := tempX + x; temp11 := b + c; temp12 := F1(temp11); temp21 := F3(2, 3); temp22 := d + e + temp21; temp23 := F4(4); temp24 := f + temp23; temp25 := F2(temp22, temp24); temp31 := F5(5); x := 1 + a + temp12 * temp25 + temp31 + x;
Step 3 (If Target CPU Does Not Support a := b op c): a := a + b x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; temp11 := b; temp11 := temp11 + c; temp12 := F1(temp11); temp21 := F3(2, 3); temp22 := d; temp22 := temp22 + e; temp22 := temp22 + temp21; temp23 := F4(4); temp24 := f; temp24 := temp24 + temp23; temp25 := F2(temp22, temp24); temp31 := F5(5); tempX := 1 { x := 1 + a + temp12 * temp25 + temp31 + x; } tempX := tempX + a; temp4 := temp12; temp4 := temp4 * temp25; tempX := tempX + temp4; tempX := tempX + temp31; tempX := tempX + x; x := tempX; OR x := x + tempX; temp11 := b + c; temp12 := F1(temp11); temp21 := F3(2, 3); temp22 := d + e; temp22 := temp22 + temp21; temp23 := F4(4); temp24 := f + temp23; temp25 := F2(temp22, temp24); temp31 := F5(5); tempX := 1 + a; temp4 := temp12 * temp25; tempX := tempX + temp4; tempX := tempX + temp31; x := tempX + x;
Step 4: Rewriting Function Calls – Expecting Calling Convention With Arguments Passed On Stack x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; temp11 := b; temp11 := temp11 + c; push temp11 call F1 temp12 := returnValue; push 3 push 2 call F3 temp21 := returnValue; temp22 := d; temp22 := temp22 + e; temp22 := temp22 + temp21; push 4 call F4 temp23 := returnValue; temp24 := f; temp24 := temp24 + temp23; push temp24 push temp22 call F2 temp25 := returnValue; push 5 call F5 temp31 := returnValue; tempX := 1 tempX := tempX + a; temp4 := temp12; temp4 := temp4 * temp25; tempX := tempX + temp4; tempX := tempX + temp31; tempX := tempX + x; x := tempX;
Step 5: Rewrite Operations Unsupported by Target CPU into Calls to Runtime x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; temp11 := b; temp11 := temp11 + c; push temp11 call F1 temp12 := returnValue; push 3 push 2 call F3 temp21 := returnValue; temp22 := d; temp22 := temp22 + e; temp22 := temp22 + temp21; push 4 call F4 temp23 := returnValue; temp24 := f; temp24 := temp24 + temp23; push temp24 push temp22 call F2 temp25 := returnValue; push 5 call F5 temp31 := returnValue; tempX := 1 tempX := tempX + a; push temp12 temp4 := temp12; push temp25 temp4 := temp4 * temp25; call runtimeMultiply temp4 := returnValue tempX := tempX + temp4; tempX := tempX + temp31; tempX := tempX + x; x := tempX;
Target CPU: 6502 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; temp11 := b; temp11 := temp11 + c; push temp11 call F1 temp12 := returnValue; push 3 push 2 call F3 temp21 := returnValue; temp22 := d; temp22 := temp22 + e; temp22 := temp22 + temp21; push 4 call F4 temp23 := returnValue; temp24 := f; temp24 := temp24 + temp23; push temp24 push temp22 call F2 temp25 := returnValue; push 5 call F5 temp31 := returnValue; tempX := 1 tempX := tempX + a; temp4 := temp12; temp4 := temp4 * temp25; call Pascal runtime temp4 := returnValue tempX := tempX + temp4; tempX := tempX + temp31; tempX := tempX + x; x := tempX;
Target CPU: 6502 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; temp11 := b; temp11 := temp11 + c; push temp11 call F1 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 temp21 := returnValue; temp22 := d; temp22 := temp22 + e; temp22 := temp22 + temp21; push 4 call F4 temp23 := returnValue; temp24 := f; temp24 := temp24 + temp23; push temp24 push temp22 call F2 temp25 := returnValue; push 5 call F5 temp31 := returnValue; tempX := 1 tempX := tempX + a; temp4 := temp12; temp4 := temp4 * temp25; call Pascal runtime temp4 := returnValue tempX := tempX + temp4; tempX := tempX + temp31; tempX := tempX + x; x := tempX;
Passing all return values in A register Target CPU: 6502 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; Passing all return values in A register temp11 := b; temp11 := temp11 + c; push temp11 call F1 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 temp21 := returnValue; temp22 := d; temp22 := temp22 + e; temp22 := temp22 + temp21; push 4 call F4 temp23 := returnValue; temp24 := f; temp24 := temp24 + temp23; push temp24 push temp22 call F2 temp25 := returnValue; push 5 call F5 temp31 := returnValue; tempX := 1 tempX := tempX + a; temp4 := temp12; temp4 := temp4 * temp25; call Pascal runtime temp4 := returnValue tempX := tempX + temp4; tempX := tempX + temp31; tempX := tempX + x; x := tempX;
Passing all return values in A register Target CPU: 6502 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; Passing all return values in A register temp11 := b; temp11 := temp11 + c; push temp11 call F1 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 STA &temp21 temp21 := returnValue; temp22 := d; temp22 := temp22 + e; temp22 := temp22 + temp21; push 4 call F4 temp23 := returnValue; temp24 := f; temp24 := temp24 + temp23; push temp24 push temp22 call F2 temp25 := returnValue; push 5 call F5 temp31 := returnValue; tempX := 1 tempX := tempX + a; temp4 := temp12; temp4 := temp4 * temp25; call Pascal runtime temp4 := returnValue tempX := tempX + temp4; tempX := tempX + temp31; tempX := tempX + x; x := tempX;
Passing all return values in A register Target CPU: 6502 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; Passing all return values in A register temp11 := b; temp11 := temp11 + c; push temp11 call F1 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 STA &temp21 temp21 := returnValue; temp22 := d; temp22 := temp22 + e; temp22 := temp22 + temp21; LDA #4 push 4 JSR &F3 call F4 STA &temp23 temp23 := returnValue; temp24 := f; temp24 := temp24 + temp23; push temp24 push temp22 call F2 temp25 := returnValue; LDA #5 push 5 PHA JSR &F5 call F5 STA &temp31 temp31 := returnValue; tempX := 1 tempX := tempX + a; temp4 := temp12; temp4 := temp4 * temp25; call Pascal runtime temp4 := returnValue tempX := tempX + temp4; tempX := tempX + temp31; tempX := tempX + x; x := tempX;
x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; Target CPU: 6502 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; Passing all return values in A register temp11 := b; temp11 := temp11 + c; push temp11 call F1 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 STA &temp21 temp21 := returnValue; temp22 := d; temp22 := temp22 + e; temp22 := temp22 + temp21; LDA #4 push 4 JSR &F3 call F4 STA &temp23 temp23 := returnValue; temp24 := f; temp24 := temp24 + temp23; push temp24 push temp22 call F2 temp25 := returnValue; LDA #5 push 5 PHA JSR &F5 call F5 STA &temp31 temp31 := returnValue; tempX := 1 tempX := tempX + a; temp4 := temp12; temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue tempX := tempX + temp4; tempX := tempX + temp31; tempX := tempX + x; x := tempX; Arguments of the runtimeMultiply function call
x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; Target CPU: 6502 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; Passing all return values in A register temp11 := b; temp11 := temp11 + c; push temp11 call F1 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 STA &temp21 temp21 := returnValue; temp22 := d; temp22 := temp22 + e; temp22 := temp22 + temp21; LDA #4 push 4 JSR &F3 call F4 STA &temp23 temp23 := returnValue; temp24 := f; temp24 := temp24 + temp23; push temp24 push temp22 call F2 temp25 := returnValue; LDA #5 push 5 PHA JSR &F5 call F5 STA &temp31 temp31 := returnValue; tempX := 1 tempX := tempX + a; LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue tempX := tempX + temp4; tempX := tempX + temp31; tempX := tempX + x; x := tempX; Arguments of the runtimeMultiply function call
Passing all return values in A register Target CPU: 6502 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; Passing all return values in A register temp11 := b; temp11 := temp11 + c; push temp11 call F1 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 STA &temp23 temp23 := returnValue; temp24 := f; temp24 := temp24 + temp23; push temp24 push temp22 call F2 temp25 := returnValue; LDA #5 push 5 PHA JSR &F5 call F5 STA &temp31 temp31 := returnValue; tempX := 1 tempX := tempX + a; LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue tempX := tempX + temp4; tempX := tempX + temp31; tempX := tempX + x; x := tempX; If temp* is part of arithmetic operation, it needs to be loaded into A
Passing all return values in A register Target CPU: 6502 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; Passing all return values in A register LDA &b temp11 := b; ADC &c temp11 := temp11 + c; PHA push temp11 JSR &F1 call F1 STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 STA &temp23 temp23 := returnValue; temp24 := f; temp24 := temp24 + temp23; push temp24 push temp22 call F2 temp25 := returnValue; LDA #5 push 5 PHA JSR &F5 call F5 STA &temp31 temp31 := returnValue; tempX := 1 tempX := tempX + a; LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue tempX := tempX + temp4; tempX := tempX + temp31; tempX := tempX + x; x := tempX; If temp* is part of arithmetic operation, it needs to be loaded into A
Passing all return values in A register Target CPU: 6502 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; Passing all return values in A register LDA &b temp11 := b; ADC &c temp11 := temp11 + c; PHA push temp11 JSR &F1 call F1 STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 STA &temp25 temp25 := returnValue; LDA #5 push 5 PHA JSR &F5 call F5 STA &temp31 temp31 := returnValue; tempX := 1 tempX := tempX + a; LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue tempX := tempX + temp4; tempX := tempX + temp31; tempX := tempX + x; x := tempX;
Passing all return values in A register Target CPU: 6502 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; Passing all return values in A register LDA &b temp11 := b; ADC &c temp11 := temp11 + c; PHA push temp11 JSR &F1 call F1 STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 STA &temp25 temp25 := returnValue; LDA #5 push 5 PHA JSR &F5 call F5 STA &temp31 temp31 := returnValue; tempX := 1 tempX := tempX + a; LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue tempX := tempX + temp4; tempX := tempX + temp31; tempX := tempX + x; x := tempX; x := 1 + a + temp12 * temp25 + temp31 + x;
Passing all return values in A register Target CPU: 6502 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; Passing all return values in A register LDA &b temp11 := b; ADC &c temp11 := temp11 + c; PHA push temp11 JSR &F1 call F1 STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 STA &temp25 temp25 := returnValue; LDA #5 push 5 PHA JSR &F5 call F5 STA &temp31 temp31 := returnValue; LDA #1 tempX := 1 ADC &a tempX := tempX + a; LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue ADC &temp4 tempX := tempX + temp4; ADC &temp31 tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX; x := 1 + a + temp12 * temp25 + temp31 + x;
x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; Target CPU: 6502 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; Passing all return values in A register LDA &b temp11 := b; ADC &c temp11 := temp11 + c; PHA push temp11 JSR &F1 call F1 STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 STA &temp25 temp25 := returnValue; LDA #5 push 5 PHA JSR &F5 call F5 STA &temp31 temp31 := returnValue; LDA #1 tempX := 1 ADC &a tempX := tempX + a; LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue ADC &temp4 tempX := tempX + temp4; ADC &temp31 tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX; x := 1 + a + temp12 * temp25 + temp31 + x; A ≠ tempX but was overwritten by current value of temp12, then temp25, then temp4
Passing all return values in A register Target CPU: 6502 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; Passing all return values in A register LDA &b temp11 := b; ADC &c temp11 := temp11 + c; PHA push temp11 JSR &F1 call F1 STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 STA &temp25 temp25 := returnValue; LDA #5 push 5 PHA JSR &F5 call F5 STA &temp31 temp31 := returnValue; LDA #1 tempX := 1 ADC &a tempX := tempX + a; TAY save tempX into Y reg. LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue TYA restore tempX from Y ADC &temp4 tempX := tempX + temp4; ADC &temp31 tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX; x := 1 + a + temp12 * temp25 + temp31 + x;
LDA &b temp11 := b; CLC ADC &c temp11 := temp11 + c; PHA push temp11 JSR &F1 call F1 STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 STA &temp25 temp25 := returnValue; Fix 8-bit Additions x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; LDA #5 push 5 PHA JSR &F5 call F5 STA &temp31 temp31 := returnValue; LDA #1 tempX := 1 CLC ADC &a tempX := tempX + a; TAY save tempX into Y reg. LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue TYA restore tempX from Y ADC &temp4 tempX := tempX + temp4; ADC &temp31 tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX;
Allocate space for 7 temporary variables on stack LDA &b temp11 := b; CLC ADC &c temp11 := temp11 + c; PHA push temp11 JSR &F1 call F1 STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 STA &temp25 temp25 := returnValue; Allocate space for 7 temporary variables on stack x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; LDA #5 push 5 PHA JSR &F5 call F5 STA &temp31 temp31 := returnValue; LDA #1 tempX := 1 CLC ADC &a tempX := tempX + a; TAY save tempX into Y reg. LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue TYA restore tempX from Y ADC &temp4 tempX := tempX + temp4; ADC &temp31 tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX; 6 1 2 7 3 4 5
Allocate space for 7 temporary variables on stack S := S - 7 LDA &b temp11 := b; CLC ADC &c temp11 := temp11 + c; PHA push temp11 JSR &F1 call F1 STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 STA &temp25 temp25 := returnValue; Allocate space for 7 temporary variables on stack x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; LDA #5 push 5 PHA JSR &F5 call F5 STA &temp31 temp31 := returnValue; LDA #1 tempX := 1 CLC ADC &a tempX := tempX + a; TAY save tempX into Y reg. LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue TYA restore tempX from Y ADC &temp4 tempX := tempX + temp4; ADC &temp31 tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX; S := S + 7 6 1 2 7 3 4 5
Allocate space for 7 temporary variables on stack TSX allocate 7 one byte temps TXA SEC SBC #7 TAX TXS LDA &b temp11 := b; CLC ADC &c temp11 := temp11 + c; PHA push temp11 JSR &F1 call F1 STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 STA &temp25 temp25 := returnValue; Allocate space for 7 temporary variables on stack x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; LDA #5 push 5 PHA JSR &F5 call F5 STA &temp31 temp31 := returnValue; LDA #1 tempX := 1 CLC ADC &a tempX := tempX + a; TAY save tempX into Y reg. LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue TYA restore tempX from Y ADC &temp4 tempX := tempX + temp4; ADC &temp31 tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX; TSX free 7 one byte temps TXA ADC #7 TAX TXS
Removing arguments from stack Passing all return values in A register TSX allocate 7 one byte temps TXA SEC SBC #7 TAX TXS LDA &b temp11 := b; CLC ADC &c temp11 := temp11 + c; PHA push temp11 JSR &F1 call F1 TSX remove arguments from stack INX STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 TSX remove arguments from stack STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 TSX remove arguments from stack STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 STA &temp25 temp25 := returnValue; x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; LDA #5 push 5 PHA JSR &F5 call F5 TSX remove arguments from stack INX TXS STA &temp31 temp31 := returnValue; LDA #1 tempX := 1 CLC ADC &a tempX := tempX + a; TAY save tempX into Y reg. LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue TSX remove arguments from stack TYA restore tempX from Y ADC &temp4 tempX := tempX + temp4; ADC &temp31 tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX; TSX free 7 one byte temps TXA ADC #7 TAX
x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; TSX allocate 7 one byte temps TXA SEC SBC #7 TAX TXS LDA &b temp11 := b; CLC ADC &c temp11 := temp11 + c; PHA push temp11 JSR &F1 call F1 TSX INX remove arguments from stack STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 TSX remove arguments from stack INX STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 TSX remove arguments from stack STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 TSX remove arguments from stack STA &temp25 temp25 := returnValue; Passing return value on stack for F1, and in accumulator for F2, F3, F4, F5 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; LDA #5 push 5 PHA JSR &F5 call F5 TSX remove arguments from stack INX TXS STA &temp31 temp31 := returnValue; LDA #1 tempX := 1 CLC ADC &a tempX := tempX + a; TAY save tempX into Y reg. LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue TSX remove arguments from stack TYA restore tempX from Y ADC &temp4 tempX := tempX + temp4; ADC &temp31 tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX; TSX free 7 one byte temps TXA ADC #7 TAX
x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; TSX allocate 7 one byte temps TXA SEC SBC #7 TAX TXS LDA &b temp11 := b; CLC ADC &c temp11 := temp11 + c; PHA push temp11 PHA reserve space for return value by pushing dummy value JSR &F1 call F1 TSX ?? save return value into A INX remove return value from stack INX remove arguments from stack STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 TSX remove arguments from stack INX STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 TSX remove arguments from stack STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 TSX remove arguments from stack STA &temp25 temp25 := returnValue; Passing return value on stack for F1, and in accumulator for F2, F3, F4, F5 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; LDA #5 push 5 PHA JSR &F5 call F5 TSX remove arguments from stack INX TXS STA &temp31 temp31 := returnValue; LDA #1 tempX := 1 CLC ADC &a tempX := tempX + a; TAY save tempX into Y reg. LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue TSX remove arguments from stack TYA restore tempX from Y ADC &temp4 tempX := tempX + temp4; ADC &temp31 tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX; TSX free 7 one byte temps TXA ADC #7 TAX
6502 stack pointer register: TSX allocate 7 one byte temps TXA SEC SBC #7 TAX TXS LDA &b temp11 := b; CLC ADC &c temp11 := temp11 + c; PHA push temp11 PHA reserve space for return value by pushing dummy value JSR &F1 call F1 TSX ?? save return value into A INX remove return value from stack INX remove arguments from stack STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 TSX remove arguments from stack INX STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 TSX remove arguments from stack STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 TSX remove arguments from stack STA &temp25 temp25 := returnValue; Passing return value on stack for F1, and in accumulator for F2, F3, F4, F5 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; LDA #5 push 5 PHA JSR &F5 call F5 TSX remove arguments from stack INX TXS STA &temp31 temp31 := returnValue; LDA #1 tempX := 1 CLC ADC &a tempX := tempX + a; TAY save tempX into Y reg. LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue TSX remove arguments from stack TYA restore tempX from Y ADC &temp4 tempX := tempX + temp4; ADC &temp31 tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX; TSX free 7 one byte temps TXA ADC #7 TAX ... ?? $01EC $01EB $01EA $01E9 ↔ temp $01E8 ↔ temp $01E7 ↔ temp $01E6 ↔ temp $01E5 ↔ temp $01E4 ↔ temp $01E3 ↔ temp a1 $01E2 ↔ 1st argument r $01E1 ↔ return value S($E0) → $01E0 $01DF 6502 stack pointer register: 0000 0001 7 0 S
6502 stack pointer register: TSX allocate 7 one byte temps TXA SEC SBC #7 TAX TXS LDA &b temp11 := b; CLC ADC &c temp11 := temp11 + c; PHA push temp11 PHA reserve space for return value by pushing dummy value JSR &F1 call F1 TSX ?? save return value into A INX remove return value from stack INX remove arguments from stack STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 TSX remove arguments from stack INX STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 TSX remove arguments from stack STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 TSX remove arguments from stack STA &temp25 temp25 := returnValue; Passing return value on stack for F1, and in accumulator for F2, F3, F4, F5 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; LDA #5 push 5 PHA JSR &F5 call F5 TSX remove arguments from stack INX TXS STA &temp31 temp31 := returnValue; LDA #1 tempX := 1 CLC ADC &a tempX := tempX + a; TAY save tempX into Y reg. LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue TSX remove arguments from stack TYA restore tempX from Y ADC &temp4 tempX := tempX + temp4; ADC &temp31 tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX; TSX free 7 one byte temps TXA ADC #7 TAX ... ?? $01EC $01EB $01EA $01E9 ↔ temp $01E8 ↔ temp $01E7 ↔ temp $01E6 ↔ temp $01E5 ↔ temp $01E4 ↔ temp $01E3 ↔ temp $100+S+2 a1 $01E2 ↔ 1st argument $100+S+1 r $01E1 ↔ return value S($E0) → $01E0 $01DF 6502 stack pointer register: 0000 0001 7 0 S
6502 stack pointer register: TSX allocate 7 one byte temps TXA SEC SBC #7 TAX TXS LDA &b temp11 := b; CLC ADC &c temp11 := temp11 + c; PHA push temp11 PHA reserve space for return value by pushing dummy value JSR &F1 call F1 TSX ?? save return value into A INX remove return value from stack INX remove arguments from stack STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 TSX remove arguments from stack INX STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 TSX remove arguments from stack STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 TSX remove arguments from stack STA &temp25 temp25 := returnValue; Passing return value on stack for F1, and in accumulator for F2, F3, F4, F5 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; LDA #5 push 5 PHA JSR &F5 call F5 TSX remove arguments from stack INX TXS STA &temp31 temp31 := returnValue; LDA #1 tempX := 1 CLC ADC &a tempX := tempX + a; TAY save tempX into Y reg. LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue TSX remove arguments from stack TYA restore tempX from Y ADC &temp4 tempX := tempX + temp4; ADC &temp31 tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX; TSX free 7 one byte temps TXA ADC #7 TAX ... ?? $01EC $01EB $01EA $01E9 ↔ temp $01E8 ↔ temp $01E7 ↔ temp $01E6 ↔ temp $01E5 ↔ temp $01E4 ↔ temp $01E3 ↔ temp $102+S a1 $01E2 ↔ 1st argument $101+S r $01E1 ↔ return value S($E0) → $01E0 $01DF 6502 stack pointer register: 0000 0001 7 0 S
Not a valid 6502 instruction TSX allocate 7 one byte temps TXA SEC SBC #7 TAX TXS LDA &b temp11 := b; CLC ADC &c temp11 := temp11 + c; PHA push temp11 PHA reserve space for return value by pushing dummy value JSR &F1 call F1 TSX LDA $101 + S save return value into A INX remove return value from stack INX remove arguments from stack STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 TSX remove arguments from stack INX STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 TSX remove arguments from stack STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 TSX remove arguments from stack STA &temp25 temp25 := returnValue; Passing return value on stack for F1, and in accumulator for F2, F3, F4, F5 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; LDA #5 push 5 PHA JSR &F5 call F5 TSX remove arguments from stack INX TXS STA &temp31 temp31 := returnValue; LDA #1 tempX := 1 CLC ADC &a tempX := tempX + a; TAY save tempX into Y reg. LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue TSX remove arguments from stack TYA restore tempX from Y ADC &temp4 tempX := tempX + temp4; ADC &temp31 tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX; TSX free 7 one byte temps TXA ADC #7 TAX Not a valid 6502 instruction ... ?? $01EC $01EB $01EA $01E9 ↔ temp $01E8 ↔ temp $01E7 ↔ temp $01E6 ↔ temp $01E5 ↔ temp $01E4 ↔ temp $01E3 ↔ temp $102+S a1 $01E2 ↔ 1st argument $101+S r $01E1 ↔ return value S($E0) → $01E0 $01DF 6502 stack pointer register: 0000 0001 7 0 S
Not a valid 6502 instruction TSX allocate 7 one byte temps TXA SEC SBC #7 TAX TXS LDA &b temp11 := b; CLC ADC &c temp11 := temp11 + c; PHA push temp11 PHA reserve space for return value by pushing dummy value JSR &F1 call F1 TSX LDA $101 + S save return value into A INX remove return value from stack INX remove arguments from stack STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 TSX remove arguments from stack INX STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 TSX remove arguments from stack STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 TSX remove arguments from stack STA &temp25 temp25 := returnValue; Passing return value on stack for F1, and in accumulator for F2, F3, F4, F5 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; LDA #5 push 5 PHA JSR &F5 call F5 TSX remove arguments from stack INX TXS STA &temp31 temp31 := returnValue; LDA #1 tempX := 1 CLC ADC &a tempX := tempX + a; TAY save tempX into Y reg. LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue TSX remove arguments from stack TYA restore tempX from Y ADC &temp4 tempX := tempX + temp4; ADC &temp31 tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX; TSX free 7 one byte temps TXA ADC #7 TAX 6502 indexed load into A: LDA $xxxx,X LDA $xxxx,Y A := ($xxxx + X)^ A := ($xxxx + Y)^ Not a valid 6502 instruction ... ?? $01EC $01EB $01EA $01E9 ↔ temp $01E8 ↔ temp $01E7 ↔ temp $01E6 ↔ temp $01E5 ↔ temp $01E4 ↔ temp $01E3 ↔ temp $102+S a1 $01E2 ↔ 1st argument $101+S r $01E1 ↔ return value S($E0) → $01E0 $01DF 6502 stack pointer register: 0000 0001 7 0 S
We already have current content of S register stored in X register! TSX allocate 7 one byte temps TXA SEC SBC #7 TAX TXS LDA &b temp11 := b; CLC ADC &c temp11 := temp11 + c; PHA push temp11 PHA reserve space for return value by pushing dummy value JSR &F1 call F1 TSX LDA $101 + S save return value into A INX remove return value from stack INX remove arguments from stack STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 TSX remove arguments from stack INX STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 TSX remove arguments from stack STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 TSX remove arguments from stack STA &temp25 temp25 := returnValue; Passing return value on stack for F1, and in accumulator for F2, F3, F4, F5 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; We already have current content of S register stored in X register! LDA #5 push 5 PHA JSR &F5 call F5 TSX remove arguments from stack INX TXS STA &temp31 temp31 := returnValue; LDA #1 tempX := 1 CLC ADC &a tempX := tempX + a; TAY save tempX into Y reg. LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue TSX remove arguments from stack TYA restore tempX from Y ADC &temp4 tempX := tempX + temp4; ADC &temp31 tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX; TSX free 7 one byte temps TXA ADC #7 TAX 6502 indexed load into A: LDA $xxxx,X LDA $xxxx,Y A := ($xxxx + X)^ A := ($xxxx + Y)^ Not a valid 6502 instruction ... ?? $01EC $01EB $01EA $01E9 ↔ temp $01E8 ↔ temp $01E7 ↔ temp $01E6 ↔ temp $01E5 ↔ temp $01E4 ↔ temp $01E3 ↔ temp $102+S a1 $01E2 ↔ 1st argument $101+S r $01E1 ↔ return value S($E0) → $01E0 $01DF 6502 stack pointer register: 0000 0001 7 0 S
We already have current content of S register stored in X register! TSX allocate 7 one byte temps TXA SEC SBC #7 TAX TXS LDA &b temp11 := b; CLC ADC &c temp11 := temp11 + c; PHA push temp11 PHA reserve space for return value by pushing dummy value JSR &F1 call F1 TSX LDA $101,X save return value into A INX remove return value from stack INX remove arguments from stack STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 TSX remove arguments from stack INX STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 TSX remove arguments from stack STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 TSX remove arguments from stack STA &temp25 temp25 := returnValue; Passing return value on stack for F1, and in accumulator for F2, F3, F4, F5 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; We already have current content of S register stored in X register! LDA #5 push 5 PHA JSR &F5 call F5 TSX remove arguments from stack INX TXS STA &temp31 temp31 := returnValue; LDA #1 tempX := 1 CLC ADC &a tempX := tempX + a; TAY save tempX into Y reg. LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue TSX remove arguments from stack TYA restore tempX from Y ADC &temp4 tempX := tempX + temp4; ADC &temp31 tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX; TSX free 7 one byte temps TXA ADC #7 TAX LDA $101 + S 6502 indexed load into A: LDA $xxxx,X LDA $xxxx,Y A := ($xxxx + X)^ A := ($xxxx + Y)^ Not a valid 6502 instruction ... ?? $01EC $01EB $01EA $01E9 ↔ temp $01E8 ↔ temp $01E7 ↔ temp $01E6 ↔ temp $01E5 ↔ temp $01E4 ↔ temp $01E3 ↔ temp $102+S a1 $01E2 ↔ 1st argument $101+S r $01E1 ↔ return value S($E0) → $01E0 $01DF 6502 stack pointer register: 0000 0001 7 0 S
Assign memory locations to temporary variables TSX allocate 7 one byte temps TXA SEC SBC #7 TAX TXS LDA &b temp11 := b; CLC ADC &c temp11 := temp11 + c; PHA push temp11 PHA reserve space for return value by pushing dummy value JSR &F1 call F1 TSX LDA $101,X save return value into A INX remove return value from stack INX remove arguments from stack STA &temp12 temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 TSX remove arguments from stack INX STA &temp21 temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC &temp21 temp22 := temp22 + temp21; STA &temp22 LDA #4 push 4 JSR &F3 call F4 TSX remove arguments from stack STA &temp23 temp23 := returnValue; LDA &f temp24 := f; ADC &temp23 temp24 := temp24 + temp23; PHA push temp24 LDA &temp22 push temp22 JSR &f2 call F2 TSX remove arguments from stack STA &temp25 temp25 := returnValue; Assign memory locations to temporary variables Passing return value on stack for F1, and in accumulator for F2, F3, F4, F5 x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; LDA #5 push 5 PHA JSR &F5 call F5 TSX remove arguments from stack INX TXS STA &temp31 temp31 := returnValue; LDA #1 tempX := 1 CLC ADC &a tempX := tempX + a; TAY save tempX into Y reg. LDA &temp12 temp4 := temp12; LDA &temp25 temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA &temp4 temp4 := returnValue TSX remove arguments from stack TYA restore tempX from Y ADC &temp4 tempX := tempX + temp4; ADC &temp31 tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX; TSX free 7 one byte temps TXA ADC #7 TAX ... ?? $01EC $01EB $01EA +7 $01E9 ↔ temp12 +6 $01E8 ↔ temp21 +5 $01E7 ↔ temp22 +4 $01E6 ↔ temp23 +3 $01E5 ↔ temp25 +2 $01E4 ↔ temp31 +1 $01E3 ↔ temp4 S($E0) → a1 $01E2 r $01E1 $01E0 $01DF
Assign memory locations to temporary variables TSX allocate 7 one byte temps TXA SEC SBC #7 TAX TXS LDA &b temp11 := b; CLC ADC &c temp11 := temp11 + c; PHA push temp11 PHA reserve space for return value by pushing dummy value JSR &F1 call F1 TSX LDA $101,X save return value into A INX remove return value from stack INX remove arguments from stack STA $107,X temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 TSX remove arguments from stack INX STA $106,X temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC $106,X temp22 := temp22 + temp21; STA $105,X LDA #4 push 4 JSR &F3 call F4 TSX remove arguments from stack STA $104,X temp23 := returnValue; LDA &f temp24 := f; ADC $104,X temp24 := temp24 + temp23; PHA push temp24 LDA $105,X push temp22 JSR &f2 call F2 TSX remove arguments from stack STA $103,X temp25 := returnValue; Assign memory locations to temporary variables x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; LDA #5 push 5 PHA JSR &F5 call F5 TSX remove arguments from stack INX TXS STA $102,X temp31 := returnValue; LDA #1 tempX := 1 CLC ADC &a tempX := tempX + a; TAY save tempX into Y reg. LDA $107,X temp4 := temp12; LDA $103,X temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA $101,X temp4 := returnValue TSX remove arguments from stack TYA restore tempX from Y ADC $101,X tempX := tempX + temp4; ADC $102,X tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX; TSX free 7 one byte temps TXA ADC #7 TAX ... ?? $01EC $01EB $01EA +7 $01E9 ↔ temp12 +6 $01E8 ↔ temp21 +5 $01E7 ↔ temp22 +4 $01E6 ↔ temp23 +3 $01E5 ↔ temp25 +2 $01E4 ↔ temp31 +1 $01E3 ↔ temp4 S($E0) → a1 $01E2 r $01E1 $01E0 $01DF
Final variant = 89 instructions in 6502 CPU machine code TSX allocate 7 one byte temps TXA SEC SBC #7 TAX TXS LDA &b temp11 := b; CLC ADC &c temp11 := temp11 + c; PHA push temp11 PHA reserve space for return value by pushing dummy value JSR &F1 call F1 TSX LDA $101,X save return value into A INX remove return value from stack INX remove arguments from stack STA $107,X temp12 := returnValue; LDA #3 push 3 PHA LDA #2 push 2 JSR &F3 call F3 TSX remove arguments from stack INX STA $106,X temp21 := returnValue; LDA &d temp22 := d; ADC &e temp22 := temp22 + e; ADC $106,X temp22 := temp22 + temp21; STA $105,X LDA #4 push 4 JSR &F3 call F4 TSX remove arguments from stack STA $104,X temp23 := returnValue; LDA &f temp24 := f; ADC $104,X temp24 := temp24 + temp23; PHA push temp24 LDA $105,X push temp22 JSR &f2 call F2 TSX remove arguments from stack STA $103,X temp25 := returnValue; Single command in Pascal: x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; LDA #5 push 5 PHA JSR &F5 call F5 TSX remove arguments from stack INX TXS STA $102,X temp31 := returnValue; LDA #1 tempX := 1 CLC ADC &a tempX := tempX + a; TAY save tempX into Y reg. LDA $107,X temp4 := temp12; LDA $103,X temp4 := temp4 * temp25; JSR &runtimeMultiply call Pascal runtime STA $101,X temp4 := returnValue TSX remove arguments from stack TYA restore tempX from Y ADC $101,X tempX := tempX + temp4; ADC $102,X tempX := tempX + temp31; ADC &x tempX := tempX + x; STA &x x := tempX; TSX free 7 one byte temps TXA ADC #7 TAX Final variant = 89 instructions in 6502 CPU machine code
X86-* Registers: More Registers → More Freedom For Programmer/Compiler EAX AX AH AL 31 16 15 8 7 0 EAX EBX 31 16 15 8 7 0 ECX 31 16 15 8 7 0 EDX 31 16 15 8 7 0 ESI 31 0 EDI 31 0 EBP 31 0 x86 (IA-32)
x86: OP target, source MOV target, source → target := source OP target, source → target := target OP source
x86: OP target, source MOV target, source → target := source LD? #$xx LD? $xxxx LD? $xxxx,? ST? $xxxx ST? $xxxx,X T?? PHA PLA MOV r, imm MOV r, [addr] MOV r2, [r1 + addr] MOV [addr], r MOV [r1 + addr], r2 MOV r2, r1 PUSH r POP r MOV target, source → target := source OP target, source → target := target OP source
x86: OP target, source MOV target, source → target := source LD? #$xx LD? $xxxx LD? $xxxx,? ST? $xxxx ST? $xxxx,X T?? PHA PLA MOV r, imm MOV r, [addr] MOV r2, [r1 + addr] MOV [addr], r MOV [r1 + addr], r2 MOV r2, r1 PUSH r POP r Most complex x86 addressing mode: [r1 + (r2 * scale) + imm] scale = immediate value: 1, 2, 4, 8 MOV target, source → target := source OP target, source → target := target OP source
x86: Accessing Array of Records (pArr^[1].b?) LD? #$xx LD? $xxxx LD? $xxxx,? ST? $xxxx ST? $xxxx,X T?? PHA PLA MOV r, imm MOV r, [addr] MOV r2, [r1 + addr] MOV [addr], r MOV [r1 + addr], r2 MOV r2, r1 PUSH r POP r Most complex x86 addressing mode: [r1 + (r2 * scale) + imm] scale = immediate value: 1, 2, 4, 8 type TRecord = record a : longword; { offset 0 } b : longword; { offset 4 } c : byte; { offset 8 } end; var pArr : ^array[0..15] of TRecord; MOV target, source → target := source OP target, source → target := target OP source
x86: Accessing Array of Records (pArr^[1].b?) LD? #$xx LD? $xxxx LD? $xxxx,? ST? $xxxx ST? $xxxx,X T?? PHA PLA MOV r, imm MOV r, [addr] MOV r2, [r1 + addr] MOV [addr], r MOV [r1 + addr], r2 MOV r2, r1 PUSH r POP r ... 17 $00B91017 [2].b 16 $00B91016 15 $00B91015 14 $00B91014 13 $00B91013 [2].a 12 $00B91012 [1].c 11 $00B91011 10 $00B91010 0F $00B9100F 0E $00B9100E [1].b 0D $00B9100D 0C $00B9100C 0B $00B9100B 0A $00B9100A [1].a 09 $00B91009 [0].c 08 $00B91008 07 $00B91007 06 $00B91006 05 $00B91005 [0].b 04 $00B91004 03 $00B91003 02 $00B91002 01 $00B91001 [0].a 00 $00B91000 ← pArr Most complex x86 addressing mode: [r1 + (r2 * scale) + imm] scale = immediate value: 1, 2, 4, 8 type TRecord = record a : longword; { offset 0 } b : longword; { offset 4 } c : byte; { offset 8 } end; var pArr : ^array[0..15] of TRecord; If Pascal compiler does not align records in array. MOV target, source → target := source OP target, source → target := target OP source
x86: Accessing Array of Records (pArr^[1].b?) LD? #$xx LD? $xxxx LD? $xxxx,? ST? $xxxx ST? $xxxx,X T?? PHA PLA MOV r, imm MOV r, [addr] MOV r2, [r1 + addr] MOV [addr], r MOV [r1 + addr], r2 MOV r2, r1 PUSH r POP r ... 17 $00B91017 [2].b 16 $00B91016 15 $00B91015 14 $00B91014 13 $00B91013 [2].a 12 $00B91012 [1].c 11 $00B91011 10 $00B91010 0F $00B9100F 0E $00B9100E [1].b 0D $00B9100D .b = ? 0C $00B9100C 0B $00B9100B 0A $00B9100A [1].a 09 $00B91009 [1] = ? [0].c 08 $00B91008 07 $00B91007 06 $00B91006 05 $00B91005 [0].b 04 $00B91004 03 $00B91003 02 $00B91002 01 $00B91001 [0].a 00 $00B91000 ← EAX=pArr Most complex x86 addressing mode: [r1 + (r2 * scale) + imm] scale = immediate value: 1, 2, 4, 8 type TRecord = record a : longword; { offset 0 } b : longword; { offset 4 } c : byte; { offset 8 } end; var pArr : ^array[0..15] of TRecord; MOV target, source → target := source OP target, source → target := target OP source
x86: Accessing Array of Records (pArr^[1].b?) LD? #$xx LD? $xxxx LD? $xxxx,? ST? $xxxx ST? $xxxx,X T?? PHA PLA MOV r, imm MOV r, [addr] MOV r2, [r1 + addr] MOV [addr], r MOV [r1 + addr], r2 MOV r2, r1 PUSH r POP r ... 17 $00B91017 [2].b 16 $00B91016 15 $00B91015 14 $00B91014 13 $00B91013 [2].a 12 $00B91012 [1].c 11 $00B91011 10 $00B91010 0F $00B9100F 0E $00B9100E [1].b 0D $00B9100D +4 0C $00B9100C 0B $00B9100B 0A $00B9100A [1].a 09 $00B91009 +ECX=1*9 [0].c 08 $00B91008 07 $00B91007 06 $00B91006 05 $00B91005 [0].b 04 $00B91004 03 $00B91003 02 $00B91002 01 $00B91001 [0].a 00 $00B91000 ← EAX=pArr Most complex x86 addressing mode: [r1 + (r2 * scale) + imm] scale = immediate value: 1, 2, 4, 8 type TRecord = record a : longword; { offset 0 } b : longword; { offset 4 } c : byte; { offset 8 } end; var pArr : ^array[0..15] of TRecord; MOV target, source → target := source OP target, source → target := target OP source
x86: Accessing Array of Records (pArr^[1].b?) LD? #$xx LD? $xxxx LD? $xxxx,? ST? $xxxx ST? $xxxx,X T?? PHA PLA MOV r, imm MOV r, [addr] MOV r2, [r1 + addr] MOV [addr], r MOV [r1 + addr], r2 MOV r2, r1 PUSH r POP r ... 17 $00B91017 [2].b 16 $00B91016 15 $00B91015 14 $00B91014 13 $00B91013 [2].a 12 $00B91012 [1].c 11 $00B91011 10 $00B91010 0F $00B9100F 0E $00B9100E [1].b 0D $00B9100D +4 0C $00B9100C 0B $00B9100B 0A $00B9100A [1].a 09 $00B91009 +ECX=1*9 [0].c 08 $00B91008 07 $00B91007 06 $00B91006 05 $00B91005 [0].b 04 $00B91004 03 $00B91003 02 $00B91002 01 $00B91001 [0].a 00 $00B91000 ← EAX=pArr Most complex x86 addressing mode: [r1 + (r2 * scale) + imm] scale = immediate value: 1, 2, 4, 8 type TRecord = record a : longword; { offset 0 } b : longword; { offset 4 } c : byte; { offset 8 } end; var pArr : ^array[0..15] of TRecord; MOV ECX, 1 { 1 = index into array } IMUL ECX, 9 { 9 = size of record } MOV target, source → target := source OP target, source → target := target OP source
x86: Accessing Array of Records (pArr^[1].b?) LD? #$xx LD? $xxxx LD? $xxxx,? ST? $xxxx ST? $xxxx,X T?? PHA PLA MOV r, imm MOV r, [addr] MOV r2, [r1 + addr] MOV [addr], r MOV [r1 + addr], r2 MOV r2, r1 PUSH r POP r ... 17 $00B91017 [2].b 16 $00B91016 15 $00B91015 14 $00B91014 13 $00B91013 [2].a 12 $00B91012 [1].c 11 $00B91011 10 $00B91010 0F $00B9100F 0E $00B9100E [1].b 0D $00B9100D +4 0C $00B9100C 0B $00B9100B 0A $00B9100A [1].a 09 $00B91009 +ECX=1*9 [0].c 08 $00B91008 07 $00B91007 06 $00B91006 05 $00B91005 [0].b 04 $00B91004 03 $00B91003 02 $00B91002 01 $00B91001 [0].a 00 $00B91000 ← EAX=pArr Most complex x86 addressing mode: [r1 + (r2 * scale) + imm] scale = immediate value: 1, 2, 4, 8 type TRecord = record a : longword; { offset 0 } b : longword; { offset 4 } c : byte; { offset 8 } end; var pArr : ^array[0..15] of TRecord; MOV ECX, 1 { 1 = index into array } IMUL ECX, 9 { 9 = size of record } MOV EBX, [EAX + ECX + 4] { 4 = offset of b } MOV target, source → target := source OP target, source → target := target OP source
x86: Accessing Array of Records (pArr^[1].b?) LD? #$xx LD? $xxxx LD? $xxxx,? ST? $xxxx ST? $xxxx,X T?? PHA PLA MOV r, imm MOV r, [addr] MOV r2, [r1 + addr] MOV [addr], r MOV [r1 + addr], r2 MOV r2, r1 PUSH r POP r ... 17 $00B91017 16 $00B91016 15 $00B91015 [2].b 14 $00B91014 13 $00B91013 12 $00B91012 11 $00B91011 [2].a 10 $00B91010 0F $00B9100F 0E $00B9100E 0D $00B9100D +4 [1].b 0C $00B9100C 0B $00B9100B 0A $00B9100A 09 $00B91009 [1].a 08 $00B91008 +8=1*8 07 $00B91007 06 $00B91006 05 $00B91005 [0].b 04 $00B91004 03 $00B91003 02 $00B91002 01 $00B91001 [0].a 00 $00B91000 ← EAX=pArr Most complex x86 addressing mode: [r1 + (r2 * scale) + imm] scale = immediate value: 1, 2, 4, 8 type TRecord = record a : longword; { offset 0 } b : longword; { offset 4 } end; var pArr : ^array[0..15] of TRecord; MOV ECX, 1 { 1 = index into array } MOV EBX, [EAX + ECX * 8 + 4] { 8 = size of record } { 4 = offset of b } MOV target, source → target := source OP target, source → target := target OP source
x86: OP target, source MOV target, source → target := source LD? #$xx LD? $xxxx LD? $xxxx,? ST? $xxxx ST? $xxxx,X T?? PHA PLA MOV r, imm MOV r, [addr] MOV r2, [r1 + addr] MOV [addr], r MOV [r1 + addr], r2 MOV r2, r1 PUSH r POP r Most complex x86 addressing mode: [r1 + (r2 * scale) + imm] scale = immediate value: 1, 2, 4, 8 MOV target, source → target := source OP target, source → target := target OP source
x86: OP target, source MOV target, source → target := source LD? #$xx LD? $xxxx LD? $xxxx,? ST? $xxxx ST? $xxxx,X T?? PHA PLA MOV r, imm MOV r, [addr] MOV r2, [r1 + addr] MOV [addr], r MOV [r1 + addr], r2 MOV r2, r1 PUSH r POP r ADD r, reg/imm/addr ADC r, reg/imm/addr SUB r, reg/imm/addr SBB r, reg/imm/addr IMUL r, reg/imm/addr IDIV r, reg/imm/addr OR r, reg/imm/addr AND r, reg/imm/addr XOR r, reg/imm/addr NOT r SHR reg/addr, imm/CL SAR reg/addr, imm/CL SHL reg/addr, imm/CL r := r + reg/imm/addr EFlags.Carry := result.32 r := r + reg/imm/addr + EFlags.Carry Most complex x86 addressing mode: [r1 + (r2 * scale) + imm] scale = immediate value: 1, 2, 4, 8 MOV target, source → target := source OP target, source → target := target OP source
x86: Flags LD? #$xx LD? $xxxx LD? $xxxx,? ST? $xxxx ST? $xxxx,X T?? PHA PLA MOV r, imm MOV r, [addr] MOV r2, [r1 + addr] MOV [addr], r MOV [r1 + addr], r2 MOV r2, r1 PUSH r POP r ADD r, reg/imm/addr ADC r, reg/imm/addr SUB r, reg/imm/addr SBB r, reg/imm/addr IMUL r, reg/imm/addr IDIV r, reg/imm/addr OR r, reg/imm/addr AND r, reg/imm/addr XOR r, reg/imm/addr NOT r SHR reg/addr, imm/CL SAR reg/addr, imm/CL SHL reg/addr, imm/CL r := r + reg/imm/addr EFlags.Carry := result.32 r := r + reg/imm/addr + EFlags.Carry Most complex x86 addressing mode: [r1 + (r2 * scale) + imm] scale = immediate value: 1, 2, 4, 8 EFlags.Sign := target.31 if target = 0 then EFlags.Zero := 1 else EFlags.Zero := 0; CLC STC EFlags.Carry := 0 EFlags.Carry := 1
Same Example Targeting x86 Architecture x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; temp11 := b; temp11 := temp11 + c; push temp11 call F1 temp12 := returnValue; push 3 push 2 call F3 temp21 := returnValue; temp22 := d; temp22 := temp22 + e; temp22 := temp22 + temp21; push 4 call F4 temp23 := returnValue; temp24 := f; temp24 := temp24 + temp23; push temp24 push temp22 call F2 temp25 := returnValue; push 5 call F5 temp31 := returnValue; tempX := 1 tempX := tempX + a; temp4 := temp12; temp4 := temp4 * temp25; tempX := tempX + temp4; tempX := tempX + temp31; tempX := tempX + x; x := tempX;
x86 – With “Dynamic Temporary Variable Allocation” x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; MOV EAX, [&b] temp11 := b; ADD EAX, [&c] temp11 := temp11 + c; PUSH EAX push temp11 CALL &F1 call F1 ADD ESP, 4 PUSH EAX temp12 := returnValue; PUSH 3 push 3 PUSH 2 push 2 CALL &F3 call F3 ADD ESP, 8 NOP temp21 := returnValue; MOV EBX, [&d] temp22 := d; ADD EBX, [&e] temp22 := temp22 + e; ADD EBX, EAX temp22 := temp22 + temp21; PUSH 4 push 4 CALL &F4 call F4 NOP temp23 := returnValue; MOV ECX, [&f] temp24 := f; ADD ECX, EAX temp24 := temp24 + temp23; PUSH ECX push temp24 PUSH EBX push temp22 CALL F2 call F2 PUSH EAX temp25 := returnValue; PUSH 5 push 5 CALL &F5 call F5 ADD ESP, 4 NOP temp31 := returnValue; MOV EBX, 1 tempX := 1 ADD EBX, [&a] tempX := tempX + a; POP ECX assign ECX <- temp25 POP EDX temp4 := temp12; IMUL EDX, ECX temp4 := temp4 * temp25; ADD EBX, EDX tempX := tempX + temp4; ADD EBX, EAX tempX := tempX + temp31; ADD EBX, [&x] tempX := tempX + x; MOV [&x], EBX x := tempX;
x86 – “temporary variable preallocation” x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; SUB ESP, 8 MOV EAX, [&b] temp11 := b; ADD EAX, [&c] temp11 := temp11 + c; PUSH EAX push temp11 CALL &F1 call F1 ADD ESP, 4 MOV [ESP + 4], EAX temp12 := returnValue; PUSH 3 push 3 PUSH 2 push 2 CALL &F3 call F3 ADD ESP, 8 NOP temp21 := returnValue; MOV EBX, [&d] temp22 := d; ADD EBX, [&e] temp22 := temp22 + e; ADD EBX, EAX temp22 := temp22 + temp21; PUSH 4 push 4 CALL &F4 call F4 NOP temp23 := returnValue; MOV ECX, [&f] temp24 := f; ADD ECX, EAX temp24 := temp24 + temp23; PUSH ECX push temp24 PUSH EBX push temp22 CALL F2 call F2 MOV [ESP], EAX temp25 := returnValue; PUSH 5 push 5 CALL &F5 call F5 ADD ESP, 4 NOP temp31 := returnValue; MOV EBX, 1 tempX := 1 ADD EBX, [&a] tempX := tempX + a; MOV EDX, [ESP + 4] temp4 := temp12; IMUL EDX, [ESP] temp4 := temp4 * temp25; ADD EBX, EDX tempX := tempX + temp4; ADD EBX, EAX tempX := tempX + temp31; ADD EBX, [&x] tempX := tempX + x; MOV [&x], EBX x := tempX; ADD ESP, 8
Final variant = 89 instructions in 6502 CPU machine code x := 1 + a + F1(b + c) * F2(d + e + F3(2, 3), f + F4(4)) + F5(5) + x; SUB ESP, 8 MOV EAX, [&b] temp11 := b; ADD EAX, [&c] temp11 := temp11 + c; PUSH EAX push temp11 CALL &F1 call F1 ADD ESP, 4 MOV [ESP + 4], EAX temp12 := returnValue; PUSH 3 push 3 PUSH 2 push 2 CALL &F3 call F3 ADD ESP, 8 NOP temp21 := returnValue; MOV EBX, [&d] temp22 := d; ADD EBX, [&e] temp22 := temp22 + e; ADD EBX, EAX temp22 := temp22 + temp21; PUSH 4 push 4 CALL &F4 call F4 NOP temp23 := returnValue; MOV ECX, [&f] temp24 := f; ADD ECX, EAX temp24 := temp24 + temp23; PUSH ECX push temp24 PUSH EBX push temp22 CALL F2 call F2 MOV [ESP], EAX temp25 := returnValue; PUSH 5 push 5 CALL &F5 call F5 ADD ESP, 4 NOP temp31 := returnValue; MOV EBX, 1 tempX := 1 ADD EBX, [&a] tempX := tempX + a; MOV EDX, [ESP + 4] temp4 := temp12; IMUL EDX, [ESP] temp4 := temp4 * temp25; ADD EBX, EDX tempX := tempX + temp4; ADD EBX, EAX tempX := tempX + temp31; ADD EBX, [&x] tempX := tempX + x; MOV [&x], EBX x := tempX; ADD ESP, 8 Final variant = 36 instructions (excluding NOPs) in x86 CPU machine code Final variant = 89 instructions in 6502 CPU machine code
Saving Contents of Registers as Part of a Calling Convention (Save in Prolog/Restore in Epilog): x86 Save EBP at Least, 6502 Save X at Least
Typical x86 Prolog and Epilog PUSH EBP MOV EBP, ESP SUB ESP, 10 ; 10 = total size of all local and temp variables Function/procedure body: EBP + x: function/procedure arguments EBP + 4: return address EBP : old EBP (value saved for the caller) EBP – x: local variables/temporary variables Epilog: MOV ESP, EBP POP EBP RET Pascal procedure P1; var a : longword; b : longword; c : word; begin end;
Typical x86 Prolog and Epilog PUSH EBP MOV EBP, ESP SUB ESP, 10 ; 10 = total size of all local and temp variables Function/procedure body: EBP + x: function/procedure arguments EBP + 4: return address EBP : old EBP (value saved for the caller) EBP – x: local variables/temporary variables Epilog: MOV ESP, EBP POP EBP RET Pascal procedure P1; var a : longword; b : longword; c : word; begin end; Some compilers using a shorter variant on x86: LEAVE