Help for Lab. 1 Subroutines calling Subroutines. Topics tackled today Handling some “C++”...

30
Help for Lab. 1 Subroutines calling Subroutines

Transcript of Help for Lab. 1 Subroutines calling Subroutines. Topics tackled today Handling some “C++”...

Help for Lab. 1Subroutines calling Subroutines

Topics tackled today

Handling some “C++” keywords when programming assembly codeProgramming “subroutines called by subroutines”Programming “extern” variablesProgramming “volatile” variables

Understanding what I did when Programming “subroutines called by subroutines”Programming “extern” variablesProgramming “volatile” variables

Subroutine calling subroutineAll void functionsFile “bloodEnglishmanASM.asm”

.extern _Fee__Fv;

.extern _Fi__Fv;

.extern _Fo__Fv;

.section program;

.global _Fum__Fv;_Fum__Fv: LINK 16; Stores RETS

CALL _Fee __Fv; Overwrites RETS CALL _Fi __Fv; Overwrites RETS CALL _Fo__Fv; Overwrites RETS

P0 = [FP +4]; P0 = stored RTS UNLINK; Recover RTS_Fum__Fv.END: JUMP (P0); Use P0 as RTS

WHY – Pipeline speed issues I think

File “bloodEnglishmanCPP.cpp”

void Fee(void);void Fi(void);void Fo(void);void Fum(void);

void Fum(void) { Fee( ); Fi( ); Fo( );}

What nursery rhyme?

Fe, Fi, Fo, Fum, I smell the blood of an Englishman?

Subroutine calling subroutineAll integer functionsFile “bloodEnglishmanASM.asm”

.extern _Fee__Fi;

.extern _Fi__Fi;

.extern _Fo__Fi;

.section program;

.global _Fum__Fi;_Fum__Fi: // value passed in R0 LINK 16; Stores RETS

R0 += 6; // pass parameter in R0 // R0 is dead – value is no longer needed CALL _Fee __Fi; Overwrites RETS

R0 = 7; // pass parameter in R0 CALL _Fi __Fi;

R0 = 8; // pass parameter in R0 CALL _Fo__Fi;

P0 = [FP +4]; Recover RETS UNLINK;_Fum__Fi.END: JUMP (P0);

File “bloodEnglishmanCPP.cpp”

void Fee(int);void Fi(int);void Fo(int);void Fum(int);

void Fum(int value) { Fee(6 + value); Fi(7); Fo(8);}

Subroutine calling subroutineAll integer functions -- WRONG APPROACH

.extern _Fee__Fi;

.extern _Fi__Fi;

.extern _Fo__Fi;

.section program;

.global _Fum__Fi;_Fum__Fi: // value passed in R0 LINK 16; Stores RETS R0 = 6; // pass parameter in R0 CALL _Fee __Fi;

R0 = 7; // pass parameter in R0 CALL _Fi __Fi;

// Problem – can’t do this R0 destroyed R0 += 8; // pass parameter in R0

CALL _Fo__Fi;

P0 = [FP +4]; Recovers RETS UNLINK;_Fum__Fi.END: JUMP (P0);

File “bloodEnglishmanCPP.cpp”

void Fee(int);void Fi(int);void Fo(int);void Fum(int);

void Fum(int value) { Fee(6); Fi(7); Fo(8 + value);}

Subroutine calling integer subroutineSave R0 to stack frame – Review of ENCM368 MIPS ideas

.section program;

.global _Fum__Fi;_Fum__Fi: // value passed in R0 LINK (16 + 4); [FP + 20] = R0; SAVE INCOMING R0 R0 = 6; // pass parameter in R0 CALL _Fee __Fi; DESTROYS R0, R1,

R2

R0 = 7; // pass parameter in R0 CALL _Fi __Fi; DESTROYS R0, R1, R2

R0 = [FP + 20]; // Recover R0 R0 += 8; // pass parameter in R0 CALL _Fo__Fi;

P0 = [FP +4]; UNLINK; // This unlink discards 20_Fum__Fi.END: JUMP (P0);

File “bloodEnglishmanCPP.cpp”

void Fee(int);void Fi(int);void Fo(int);void Fum(int);

void Fum(int value) { Fee(6); Fi(7); Fo(8 + value);}

Subroutine calling integer subroutine (passing parameters)The way I remember the easiest and have the least trouble with

.section program;

.global _Fum__Fi;_Fum__Fi: // value passed in R0 [--SP] = R7; // R7 always saved by other

routines – SAVE before LINKR7 = R0; // Save R0 to R7

LINK 16 R0 = 6; // pass parameter in R0 CALL _Fee __Fi;

R0 = 7; // pass parameter in R0 CALL _Fi __Fi;

R0 = R7 // Recover R0 R0 += 8; // pass parameter in R0 CALL _Fo__Fi;

P0 = [FP +4]; UNLINK; R7 = [SP++]; // Recover R7 AFTER unlink_Fum__Fi.END: JUMP (P0);

File “bloodEnglishmanCPP.cpp”

void Fee(int);void Fi(int);void Fo(int);void Fum(int);

void Fum(int value) { Fee(6); Fi(7); Fo(8 + value);}

long int and extern long intarrays long int * and extern long int *

.extern _thumb; in C++

.extern _thumbPt; in C++

Means the following in assembly code

.section L1_data;

.global _plumb;

.var _plumb[5] = {1, 2, 3, 4, 5};

.global _pointers;

.var _pointers[5];

.section program;

File “PutInHisThumb.cpp”

extern long int thumb[10];extern long int *thumbPt[10];long int plumb[5] = {1, 2, 3, 4, 5};long int *pointers[6];

long int Jack(long int *goodboy)

long int Jack(long int *goodboy{ long int sum;

goodboy[3] = thumb[2] + plumb[1]}

extern long int

.extern _thumb;

.section L1_data;

.global _plumb;_ .var _plumb[5] = {1, 2, 3, 4, 5};

.section program;

.global _Jack__FPl; // Pointer long_Jack__FPl: // pointer passed in R0 LINK 16; P0 = R0; // Use passed value as a pointer

P1.L = _thumb; P1.H = _thumb; R0 = [P1 + (2 * 4)]; // LOAD

P1.L = _plumb; P1.H = _plumb; R1= [P1 + (1 * 4)]; // LOAD R0 = R0 + R1; [P0 + (3 * 4)] = R0; // STORE

P0 = [FP +4]; UNLINK;_ Jack__FPl .END:: JUMP (P0);

File “PutInHisThumb.cpp”

extern long int thumb[10];long int plumb[5] = {1, 2, 3, 4, 5}long int Jack(long int *goodboy)

long int Jack(long int *goodboy{ long int sum;

goodboy[3] = thumb[2] + plumb[1]}

extern volatile long int

.extern _thumb;

.section L1_data;

.global _plumb[5] = {1, 2, 3, 4, 5};

.section program;

.global _Jack__FPl; // Pointer long_Jack__FPl: // pointer passed in R0 LINK 16; P0 = R0; // Use passed value as a pointer // R0 is now dead – can reuse

P1.L = _thumb; P1.H = _thumb; R0 = [P1 + (2 * 4)]; // LOAD

P1.L = _plumb; P1.H = _plumb; R1= [P1 + (1 * 4)]; // LOAD R0 = R0 + R1; [P0 + (3 * 4)] = R0; // STORE

P0 = [FP +4]; UNLINK;_Jack__FPl.END: JUMP (P0);

File “PutInHisThumb.cpp”

extern volatile long int thumb[10];long int plumb[5] = {1, 2, 3, 4, 5}long int Jack(long int *goodboy)

long int Jack(long int *goodboy{ long int sum;

goodboy[3] = thumb[2] + plumb[1]}

extern long int – optimized code generated by C++ -- NOT CORRECT

.extern _star;

.extern _BlinkLight__Fv;

.section program;

.global _Wonderwhat__Fv; _Wonderwhat__Fv:

LINK 16; P1.L = _star; P1.H = _star; R0 = [P1 + (2 * 4)]; // LOAD

CC = R0 == 2; IF !CC JUMP DONE;

LOOP: CALL _BlinkLight__Fv;JUMP LOOP;

DONE:P0 = [FP +4];

UNLINK;_Wonderwhat__Fv .END: JUMP (P0);

File “TwinkleTwinkle.cpp”

extern long int star[10];void WonderWhat(void);void BlinkLight(void);

void WonderWhat(void) { while (star[2] == 2) { BlinkLight( ); }}

Either star[2] == 2, or it does not

If star[2] == 2 then get an infinite loopotherwise BlinkLight( ) never called

extern volatile long int optimized code – STILL WRONG

.extern _star; // No volatile in ASM

.extern _BlinkLight__Fv;

.section program;

.global _Wonderwhat__Fv; _Wonderwhat__Fv:

LINK 16;

P1.L = _star; // Re-use as pointer P1.H = _star;

LOOP: R0 = [P1 + (2 * 4)]; // KEEP LOADING // THIS CODES THE VOLATILITY CC = R0 == 2; // LOOP NEEDED IF !CC JUMP DONE;

CALL _BlinkLight__Fv; DESTROYS P1JUMP LOOP;

DONE:P0 = [FP +4];

UNLINK;_Wonderwhat__Fv .END: JUMP (P0);

File “TwinkleTwinkle.cpp”

extern volatile long int star[10];void WonderWhat(void);void BlinkLight(void);

void WonderWhat(void) { while (star[2] == 2) { BlinkLight( ); }}

star[2] == 2 MAY START OFF BEING 2

But since star is “volatile” then some external action may change it.

Loop needed in optimized code if “volatile” memory value

GOOD IDEA – WILL NOT WORK AS P1 isdestroyed during CALL BlinkLight

extern volatile long int optimized code -- CORRECT

.extern _star;

.extern _BlinkLight__Fv;

.section program;

.global _Wonderwhat__Fv; _Wonderwhat__Fv: [--SP] = P5; // Save the non-volatile

LINK 16;

P5.L = _star; P5.H = _star;LOOP: R0 = [P5 + (2 * 4)]; // KEEP LOADING // THIS CODES THE VOLATILITY CC = R0 == 2; // LOOP NEEDED IF !CC JUMP DONE;

CALL _BlinkLight__Fv; KEEPS P5JUMP LOOP; UNCHANGED

DONE:P0 = [FP +4];

UNLINK; P5 = [SP++];_Wonderwhat__Fv .END: JUMP (P0);

File “TwinkleTwinkle.cpp”

extern volatile long int star[10];void WonderWhat(void);void BlinkLight(void);

void WonderWhat(void) { while (star[2] == 2) { BlinkLight( ); }}

star[2] == 2 MAY START OFF BEING 2

But since star is “volatile” then some external action may change it.

Loop needed in optimized code if “volatile” memory value

Understanding what I did

Will look at things in more detail later in class

But here are some ideas of why we did what we did

LINK – what does it do?A correction – Processor Programming Reference 4:17

LINK 16

Does all the following in one instruction

[--SP] = RETS;[--SP] = FP;FP = SP;SP SP – 16;

LINK (200 + 16)

Does all the following in one instruction

[--SP] = RETS;[--SP] = FP;FP = SP;SP SP – 200; (Space for

an array)SP SP – 16;

UNLINK – what does it do?

LINK 16

UNLINK

Unlink does all the following in one instruction

SP = FP;

FP = [SP++];

RETS = [SP++];

LINK (200 + 16)

UNLINK

Unlink does all the following in one instruction

SP = FP;

FP = [SP++];

RETS = [SP++];

Subroutine calling subroutineAll void functions

File “bloodEnglishmanASM.asm”

.extern _Fee__Fv; defined elsewhere

.extern _Fi__Fv;

.extern _Fo__Fv;

.section program;

.global _Fum__Fv;_Fum__Fv:

Since the other functions are coded “outside” or “external” to this file then we indicate that with the keyword .extern

File “bloodEnglishmanCPP.cpp”

void Fee(void);void Fi(void);void Fo(void);void Fum(void);

void Fum(void) {

}

Subroutine calling subroutineAll void functionsFile “bloodEnglishmanASM.asm”

.extern _Fee__Fv;

.extern _Fi__Fv;

.extern _Fo__Fv;

.section program;

.global _Fum__Fv; // Not “private”_Fum__Fv:

Since we want other functions (coded “outside” or “external” to this file) to be able to use Fum( ) coded in this file we must “globalize” (tell everybody) this functions name with the keyword .global

File “bloodEnglishmanCPP.cpp”

void Fee(void);void Fi(void);void Fo(void);void Fum(void);

void Fum(void) {

}

Subroutine calling subroutineAll void functionsFile “bloodEnglishmanASM.asm”

.extern _Fee__Fv;

.extern _Fi__Fv;

.extern _Fo__Fv;

.section program;

.global _Fum__Fv;_Fum__Fv: LINK 16; // Save RETS to stack

CALL _Fee __Fv; // Changes RETS CALL _Fi __Fv; // Changes RETS CALL _Fo__Fv; // Changes RETS

P0 = [FP +4]; // Saved RETS into P0 UNLINK; // Saved RETS into RETS

// and destroy (remove) stack frame_Fum__Fv.END: JUMP (P0); // Now equivalent to RTS

Why this approach? Possibly more efficient because of the pipeline

The LINK 16; operation saves this subroutine’s return address (stored in the “RETurn from Subroutine register” RETS) onto the stack.

This allows the processor to use register RETS when it calls other subroutines – same was as the MIPS – different register name

UNLINK restores (recovers, reads) RETS from the stack so we can exit this subroutine.

Subroutine calling subroutineAll integer functions

Name mangle changes(Do not need to remember

details in quizzes and exams – critical to get correct in labs)

void Foo(void) _Foo__Fvint Foo(void) _Foo__Fvint Foo(int) _Foo__Fiint Foo(long int) _Foo__Flint Foo(int *) _Foo__FPiInt Foo(long int *) _Foo_FPl

Can’t overload on the basis of return value – C++ rule

This is the “assembly code reason why

void Foo(void) _Foo__Fvint Foo(void) _Foo__Fv

Subroutine calling subroutineAll integer functions

.extern _Fee__Fi;

.extern _Fi__Fi;

.extern _Fo__Fi;

.section program;

.global _Fum__Fi;_Fum__Fi: // value passed in R0 LINK 16; // R0 incoming parameter is unsaved

R0 = 6; // pass parameter in R0 CALL _Fee __Fi; Destroys R0, R1, P0, P1

R0 = 7; // pass parameter in R0 CALL _Fi __Fi; Destroys R0, R1, P0, P1

R0 += 8; // pass parameter in R0 – WRONG VALUE AS TRUE VALUE HAS BEEN DESTROYED

CALL _Fo__Fi;

P0 = [FP +4]; UNLINK;_Fum__Fi.END: JUMP (P0);

void Fum(int value) { Fee(6); Fi(7); Fo(8 + value);}

ALWAYS pass the parameter to the subroutine in R0 – very similar to MIPS

Must save the passed value (in R0), otherwise it will be destroyed when we call the other subroutines while we use R0 to pass the parameter

Subroutine calling subroutineAll integer functions

.section program;

.global _Fum__Fi;_Fum__Fi: // value passed in R0 [--SP] = R7; // Save volatile register R7 = R0; // Save passed value

LINK 16;

R0 = 6; // pass parameter in R0 CALL _Fee __Fi;

R0 = 7; // pass parameter in R0 CALL _Fi __Fi;

R0 = R7; // Recover passed value R0 += 8; // pass parameter in R0 CALL _Fo__Fi;

P0 = [FP +4]; UNLINK;

R7 = [SP++]; // Recover saved volatile register

_Fum__Fi.END: JUMP (P0);

void Fum(int value) { Fee(6); Fi(7); Fo(8 + value);}

I always save a non-volatile register (R7) onto the stack

-- and then save R0 into R7. Easier to remember and optimize

ALWAYS pass the parameter to the subroutine in R0 – very similar to MIPS

This file is in a project by itself. It compiles but does not link or run! Why not?

A project containing only the file “PutInHisThumb.cpp” will not link and run because

Very common errorAll projects must have a

main( ) in them If you receive a message –

can’t link to _main – when you are doing the laboratory – then this is the problem.

File “PutInHisThumb.cpp”

extern long int thumb[10];long int plumb[5] = {1, 2, 3, 4, 5}long int Jack(long int *goodboy)

long int Jack(long int *goodboy{ long int sum;

goodboy[3] = thumb[2] + plumb[1]

}

These two files compile but does not link and run-- Why not?File “main.cpp”

extern long int thumb[10];extern long int plumb[5] ;long int goodboy[10];

long int Jack(long int *goodboy)

int main(void) {for (int count = 0;

count < 10; count++) goodboy[count] = 0; Jack(goodboy); printf(“%d\n”, goodboy[3]);}

File “PutInHisThumb.cpp”

extern long int thumb[10];long int plumb[5] = {1, 2, 3, 4, 5}long int Jack(long int *goodboy)

long int Jack(long int *goodboy{ long int sum;

goodboy[3] = thumb[2] + plumb[1]}

This does not link and runWhy not?

DECLARED IN ANOTHER FILEDECLARED IN THIS FILE

File “main.cpp”

extern long int thumb[10];extern long int plumb[5] ;long int goodboy[10];

File “PutInHisThumb.cpp”

extern long int thumb[10];long int plumb[5] = {1, 2, 3, 4, 5}

DECLARED IN ANOTHER FILEDECLARED IN ANOTHER FILEDECLARED IN THIS FILE

IN NO FILE HAS MEMORY SPACE BEEN SET ASIDE FOR THE “THUMB” ARRAY

This does link and run -- because all arrays have been given “space”File “main.cpp”

long int thumb[10] = {2, 4, 6, 8, 10};extern long int plumb[5] ;long int goodboy[10];

long int Jack(long int *goodboy)

int main(void) {for (int count = 0;

count < 10; count++) goodboy[count] = 0; Jack(goodboy); printf(“%d\n”, goodboy[3]);}

File “PutInHisThumb.cpp”

extern long int thumb[10];long int plumb[5] = {1, 2, 3, 4, 5}long int Jack(long int *goodboy)

long int Jack(long int *goodboy{ long int sum;

goodboy[3] = thumb[2] + plumb[1]}

How can something in memory change like this

.extern _star;

.extern _BlinkLight__Fv;

.section program;

.global _Wonderwhat__Fv; _Wonderwhat__Fv:

LINK 16; P0 = R0; // Use passed value as a pointer

P1.L = _thumb; P1.H = _thumb;

LOOP: R0 = [P1 + (2 * 4)]; // KEEP LOADING

CC = R0 == 2; // LOOP NEEDED IF !CC JUMP DONE;

CALL _BlinkLight__Fv;JUMP LOOP;

DONE:P0 = [FP +4];

UNLINK;_Wonderwhat__Fv .END: JUMP (P0);

File “TwinkleTwinkle.cpp”

extern volatile long int star[10];void WonderWhat(void);void BlinkLight(void);

void WonderWhat(void) { while (star[2] == 2) { BlinkLight( ); }}

star[2] == 2 MAY START OFF BEING 2

But since star is “volatile” then some external action may change it.

Loop with repeated read needed in optimized code if “volatile” memory value

Example from Lab. 1 Audio talkthroughDifference between subroutines and interrupts

There is a main routine There is an “interrupt audio” routine. Every

1 / 40000 s the interrupt routine “interrupts” (temporarily halts) main( ),then runs itself, and then returns control to main

Interrupts run under “external control” when “something happens” switch changes or voltage changes -- unexpected

Subroutines run under “internal control” ONLY WHEN CALLED – NEVER UNEXPECTED

Example from Lab. 1 Task 4

File “main.cpp”

volatile boolean mute_on = FALSE;

long int ReadSwitches(void);

int main( ) InitializeSwitches( ); InitializeAudio( );

StartInterrupts( ); while (1) { int value = ReadSwitches( );// If switch pressed // – turn off sound; if (value == 0x100) mute_on = TRUE;

else mute_on = FALSE; }}

File “interruptservice.cpp”

extern volatile boolean mute_on;void Process_DataASM(void);

EX_INTERRUPT_HANDLER(Sport0_RX_ISR){

…….. /// Lots of good stuff

Process_DataASM( ); // Make the sound occur

…….. // Lots of more good stuff;}

void Process_DataASM(void) { if (mute_on = = FALSE)

MakeTheSound( );}

WORRY ABOUT WHAT EX_INTERRUPT_HANDLER( ) MEANS IN LAB. 2