Process for systematic conversion of a design in


































- Slides: 34

Process for systematic conversion of a design in “C-pseudo code” to SHARC 21061 assembly code M. Smith, Electrical and Computer Engineering, University of Calgary, Canada smithmr @ ucalgary. ca

To be tackled today n Example conversion of “C” program into ADSP 21061 using a standard procedure n n n Take into account register architecture Take into account LOAD/STORE architecture Take into account standard assembly code problems Handle Program Flow Constructs Then do conversion of code on line by line basis Learning why to avoid calling “C” from assembly 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 2

SHARC process -- Respect the registers that the “C” compiler uses Volatile Registers (not used by “C” compiler -- destroyed by “C”) R 0, R 1, R 2 (also F 0, F 1, F 2) R 4, I 4, M 4 (also F 4) (S. O. T. T. ) R 8 (also F 8) (S. O. T. T. ) R 12, I 12, M 12 (also F 12) (S. O. T. T. ) S. O. T. T. means Some Of The Time -- special issues Non-volatile Registers (used by “C” compiler) EVERYTHING ELSE SHARC PROCESS -- Save and recover NON-VOLATILE registers 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 3

3 parts of SHARC process to obtain “C” compatible assembly language code <- Always the “same” n PROLOGUE CODY BODY EPILOGUE n Always the “same” means that you learn to write the n n n <- Always the “same” code once and then use with only minor modification each time you write code in the future Just the same as with 68 K “C”/assembly compatibly taught in ENMCM 415. 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 4

STANDARD SHARC PROCESS We want to have a PROCESS to convert the basic parts of a design in “C” pseudo-code to SHARC 21 k assembly code n n n Minimize ERRORS -- jumping backwards and forwards between editor, assembler and linker while developing a prototype ERRORs become the big time waster when jumping to and from the simulator while testing this prototype. Minimize DEFECTS -- Defects are the carry over of the mistakes from one apparently working prototype into another protype -- HUGE TIME WASTER 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 5

Remember the 5 -OR-60 rule n n n Spend enough time in design and code review. An EXTREME PROGRAMMING APPROACH with 5 minutes for design and code review will save you 60 minutes during testing. What’s enough time? -- SEI INDUSTRY VALIDATION 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 6

SHARC code -- FM-STEREO Example n AM - amplitude modulation -- typically MONO n n n Carrier with varying amplitude Mix to bring to base frequency then rectify FM - frequency modulation n n Carrier with varying frequency/phase Use FM demodulator to convert frequency changes into amplitude changes Get DC components (0 -- 10 k. Hz) plus an AM modulated carrier (10 - 30 khz) Channel 1 -- Left sound + Right Sound from DC Channel 2 -- Left Sound - Right Sound from carrier 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 7

void Decode. FMSTEREO(int, int *) void Decode. FMSTEREO(int channel_two_strength, int *channel_one, int *channel_two) { int temp_one = *channel_one; int temp_two = *channel_two; static int comment = 0; if (!comment) { Jump to “C” -- printf( ) -- why code the slow and obvious printf("Smith Decode. FMStereo() -- FM_STEREO demodulation example"); comment = 1; } // If Channel Strength is too weak then just use channel_one on both channels if (channel_two_strength < 25) *channel_two = *channel_one; // L + R else { *channel_one = (temp_one + temp_two) >> 1; // L+ R +(L - R) *channel_two = (temp_one - temp_two) >> 1; // L+ R - (L - R) } } 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 8

SHARC PROCESS -- STEP 1 A Convert C-design to account for RISC architecture void Decode. FMSTEREO(int channel_two_strength, int *channel_one, int *channel_two) { ON SHARC -- First three subroutine parameters are PLACED in DATA registers even if the parameters are copies of values of pointer registers (index registers) void Decode. FMSTEREO(register int channel_two_strength, register int *channel_one, register int *channel_two) { 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 9

SHARC PROCESS -- STEP 1 B Convert C-design to account for RISC architecture int temp_one = *channel_one; int temp_two = *channel_two; static int comment = 0; if (!comment) { ……………. } BECOMES register int temp_one = *channel_one; register int temp_two = *channel_two; static int comment = 0; if (comment == 0) { ………. . . } 12/22/2021 <- must be stored in memory and not register <- Got to be specific when writing assembly ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 10

SHARC PROCESS -- STEP 1 C Convert C-design to account for RISC architecture static int comment = 0; if (comment != 0) { printf( ); comment = 1; } <- Must be stored in memory and not register <- Tests can’t be done on memory values in a RISC processor architecture BECOMES static int comment = 0; <- Must be stored in memory -- not register int temp_comment; temp_comment = comment; if (temp_comment == 0) { <- Grab the value from memory <- Test using a register printf( ); comment = 1; <- Still okay in THIS RISC architecture } ENDIF: <- Must add this to handle assembly code GOTO structure 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 11

SHARC PROCESS -- STEP 1 D Convert C-design to account for RISC architecture if (channel_two_strength < 25) *channel_two = *channel_one; else { *channel_one = (temp_one + temp_two) >> 1; *channel_two = (temp_one - temp_two) >> 1; } BECOMES register int temp_constant; temp_constant = 25; ********!!!!!********* if (channel_two_strength < temp-constant) *channel_two = *channel_one; else { *channel_one = (temp_one + temp_two); *channel_one = *channel_one >> 1; *channel_two = (temp_one - temp_two); *channel_two = *channel_two >> 1; } 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 12

void Decode. FMSTEREO(register int channel_two_strength, register int *channel_one, register int *channel_two) { register int temp_one = *channel_one; register int temp_two = *channel_two; register temp_value; static int comment = 0; temp_value = comment; if (temp_value == 0) { WARNING -- SPECIAL CASE printf("Smith Decode. FMStereo() -- FM_STEREO demodulation examp comment = 1; } else /* DO NOTHING */; WARNING -- MUST ADD THIS temp_value = 25; if (channel_two_strength < temp_value) *channel_two = *channel_one; else { *channel_one = (temp_one + temp_two); *channel_one = *channel_one >> 1; *channel_two = (temp_one - temp_two); *channel_two = *channel_two >> 1; } 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 13

SHARC PROCESS -- STEP 2 Develop the subroutine PROLOGUE void Decode. FMSTEREO(register int channel_two_strength, register int *channel_one, register int *channel_two) { register int temp_one = *channel_one; register int temp_two = *channel_two; register temp_value; Incoming register int channel_two_strength -- INPAR 1 -- in R 4 -- leave it there Incoming register int *channel_one -- INPAR 2 -- in R 8 -- CAN’T leave it there Must move into volatile DM pointer -- I 4 Incoming register int *channel_two -- INPAR 3 -- in R 12 -- CAN’T leave it there Must move into volatile DM pointer -- BUT I 4 already in use register int temp_one = *channel_one; register int temp_two = *channel_two; register temp_value; 12/22/2021 Allowed in R 1? Allowed in R 2? Allowed in R 3? ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 14

Make use of a standard format for register names -- “cdefines. i” #define #define scratch. R 0 scratch. R 1 scratch. R 2 scratch. F 1 scratch. F 2 R 0 R 1 R 2 F 1 F 2 #define scratch. DMpt scratch. DMmod scratch. PMpt scratch. PMmod I 4 M 4 I 12 M 12 #define INPAR 1_R 4 INPAR 2_R 8 INPAR 3_R 12 scratch. R 4 R 8 R 12 R 4 12/22/2021 (WARNING -- also retvalue. R 0) (WARNING -- identical to R 1 for storage) (WARNING -- identical to R 2 for storage) (WARNING -- Program Memory DAG) (WARNING -- DATA register NOT POINTER) even when used to pass copy of pointer etc. ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 15

SHARC PROCESS -- STEP 2 A Develop the subroutine PROLOGUE // Show the parameters being passed as part of documentation #define channel_two_strength. R 4 scratch. R 4 // Same as INPAR 1 void Decode. FMSTEREO(register int channel_two_strength, register int *channel_one, register int *channel_two) { #define temp_one. R 1 scratch. R 1 // register int temp_one = GARBAGE register int temp_one = *channel_one; #define temp_two. R 2 scratch. R 2 // register int temp_two = GARBAGE register int temp_two = *channel_two; #define temp_value. R 0 scratch. R 0 // register temp_value = GARBAGE Incoming register int *channel_one -- INPAR 2 -- in R 8 -- CAN’T leave it there Must move into volatile DM pointer -- I 4 Incoming register int *channel_two -- INPAR 3 -- in R 12 -- CAN’T leave it there Must move into volatile DM pointer -- BUT I 4 already in use CHOICES -- Place I 3 onto stack or Reuse I 4 -- worry about speed later 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 16

SHARC PROCESS -- STEP 2 B Develop the subroutine PROLOGUE // Show the parameters being passed as part of documentation #define channel_two_strength. R 4 scratch. R 4 // Same as INPAR 1 void Decode. FMSTEREO(register int channel_two_strength, register int *channel_one, register int *channel_two) { #define temp_one. R 1 scratch. R 1 // register int temp_one = GARBAGE scratch. DMpt = INPAR 2; // register int temp_one = *channel_one; temp_one. R 1 = dm(scratch. DMpt); #define temp_two. R 2 scratch. R 2 YOU ADD THE CODE // // register int temp_two = GARBAGE register int temp_two = *channel_two; #define temp_value. R 0 scratch. R 0 // register temp_value = GARBAGE Placing I 3 onto stack Reuse I 4 12/22/2021 // Two extra lines -- if you get it right (Save/Recover) // Four EXTRA lines of which only two shown here // Actually do-able in 3 (a little dicey) ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 17

SHARC PROCESS -- STEP 2 C Correct the subroutine PROLOGUE. segment/pm seg_pmco; // void Decode. FMSTEREO(register int channel_two_strength, register int *channel_one, register int *channel_two) {. global _Decode. FMSTEREO, Decode. FM_STEREO _Decode. FMSTEREO: // Show the parameters being passed as part of documentation #define channel_two_strength. R 4 scratch. R 4 // Same as INPAR 1 #define temp_one scratch. R 1 // scratch. DMpt = INPAR 2; // temp_one. R 1 = dm(scratch. DMpt); register int temp_one = GARBAGE register int temp_one = *channel_one; #define temp_two. R 2 scratch. R 2 YOU ADD THE CODE // // register int temp_two = GARBAGE register int temp_two = *channel_two; #define temp_value. R 0 scratch. R 0 // register temp_value = GARBAGE 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 18

SHARC PROCESS -- STEP 2 D Correct the subroutine PROLOGUE CORRECTLY void Decode. FMSTEREO(int channel_two_strength, int *channel_one, int *channel_two) { int temp_one = *channel_one; NOT A REGISTER int temp_two = *channel_two; NOR A STACK VALUE static int comment = 0; if (!comment) { printf("Smith Decode. FMStereo() -- FM_STEREO demodulation example"); comment = 1; } // If Channel Strength is too weak then just use channel_one on both channels if (channel_two_strength < 25) *channel_two = *channel_one; else { *channel_one = (temp_one + temp_two) >> 1; *channel_two = (temp_one - temp_two) >> 1; } } 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 19

SHARC PROCESS -- STEP 2 D Correct the subroutine PROLOGUE CORRECTLY. segment/dm seg_dmda var int comment = 0; . endseg; // NASTY HIDDEN ERROR . segment/pm seg_pmco; // void Decode. FMSTEREO(register int channel_two_strength, register int *channel_one, register int *channel_two) {. global _Decode. FMSTEREO, Decode. FM_STEREO What’s missing? _Decode. FMSTEREO: // Show the parameters being passed as part of documentation #define channel_two_strength scratch. R 4 // Same as INPAR 1 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 20

SHARC PROCESS -- STEP 3 Modify the standard EPILOGUE // Place the return value in retvalue. R 0 -- N/A // Recover non-volatile registers from stack -- N/A scratch. PMpt = dm(minus 1 DM, FP); nop; // might be carefully filled jump(plus 1 PM, scratch. PMpt) (DB); nop; // might be carefully filled RFRAME; . endseg; Just a CUT-AND-PASTE job 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 21

SHARC PROCESS -- STEP 4 A Convert C-design body -- standard IF-ELSE scratch. R 0 = 25; // temp_constant = 25; // if (channel_two_strength < temp-constant) COMP(channel_two_strength, scratch. R 0); // dead <- scratch. R 0 if LE jump(PC, DO_ELSE) (DB); nop; // Are these delayed branches fillable nop; scratch. DMpt = INPAR 2; // *channel_two = *channel_one; scratch. R 0 = dm(scratch. DMpt); scratch. DMpt = INPAR 3; // Note the indenting as part of the documentation dm(scratch. DMpt) = scratch. R 0; jump (PC, ENDIF) (DB); nop; DO_ELSE: // else { // *channel_one = (temp_one + temp_two); ENCM 515 -- Process for “pseudo-C” design to 21 k assembly 12/22/2021 22 Copyright smithmr@ucalgary. ca // *channel_one = *channel_one >> 1;

SHARC PROCESS -- STEP 4 A -- in this particular subroutine Convert C-design body -- standard IF-ELSE scratch. R 0 = 25; // temp_constant = 25; // if (channel_two_strength < temp-constant) COMP(channel_two_strength, scratch. R 0); // dead <- scratch. R 0 if LE jump(PC, DO_ELSE) (DB); nop; // Are these delayed branches fillable nop; dm(scratch. DMpt) = temp_one. R 1 // *channel_two = *channel_one (temp_one); // INPAR 3 just HAPPENS to be in scratch. DMpt already jump (PC, ENDIF) (DB); nop; DO_ELSE: 12/22/2021 // because of the code you added earlier // else { // *channel_one = (temp_one + temp_two); // *channel_one = *channel_one >> 1; // *channel_two = (temp_one - temp_two); // *channel_two = *channel_two >> 1; ENCM 515 -- Process for “pseudo-C” design to 21 k assembly // } Copyright smithmr@ucalgary. ca 23

ENORMOUS DEFECT INTRODUCED n You can’t do any of this -- ALL WRONG n You have forgotten n what you are coding in the whole while micromanaging the details Key issues -- volatile/non-volatile register use. 21 k “C” subroutines -- like 68 k “C” subroutines -- destroy volatile registers (R 0) 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 24

void Decode. FMSTEREO(int, int *) void Decode. FMSTEREO(int channel_two_strength, int *channel_one, int *channel_two) { int temp_one = *channel_one; Using R 1, R 0, R 4, int temp_two = *channel_two; I 4 etc Probably destroys R 1, R 0, R 4, I 4 etc static int comment = 0; if (!comment) { printf("Smith Decode. FMStereo() -- FM_STEREO demodulation example"); comment = 1; } // If Channel Strength is too weak then just use channel_one on both channels if (channel_two_strength < 25) *channel_two = *channel_one; else { *channel_one = (temp_one + temp_two) >> 1; *channel_two = (temp_one - temp_two) >> 1; } } 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 25

Program smart -- and cut the DEFECTS void Decode. FMSTEREO(int channel_two_strength, int *channel_one, int *channel_two) { int temp_one = *channel_one; int temp_two = *channel_two; static int comment = 0; // printf( ) CODE WAS HERE // If Channel Strength is too week then just use channel_one on both channels if (channel_two_strength < 25) *channel_two = *channel_one; else { *channel_one = (temp_one + temp_two) >> 1; *channel_two = (temp_one - temp_two) >> 1; } “C” CAN DESTROY VOLATILES TO HEART’S CONTENT if (!comment) { printf("Smith Decode. FMStereo() -- FM_STEREO demodulation example"); comment = 1; } } 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 26

SHARC PROCESS -- STEP 4 A -- in this particular subroutine Convert C-design body -- standard IF-ELSE scratch. R 0 = 25; COMP(channel_two_strength, scratch. R 0); if LE jump(PC, DO_ELSE) (DB); nop; dm(scratch. DMpt) = temp_one. R 1 jump (PC, ENDIF) (DB); nop; DO_ELSE: // temp_constant = 25; // if (channel_two_strength < temp-constant) // dead <- scratch. R 0 // Are these delayed branches fillable // *channel_two = *channel_one (temp_one); // else { scratch. R 0 = temp_one. R 1 + temp_two. R 2; // *channel_one = (temp_one + temp_two); scratch. R 0 = ASHIFT scratch. R 0 BY -1; // *channel_one = *channel_one >> 1; scratch. DMpt = INPAR 2; dm(scratch. DMpt) = scratch. R 0; // dead <- scratch. R 0 YOU ENDIF: // *channel_two = (temp_one - temp_two); COMPLETE // *channel_two = *channel_two >> 1; ENCM 515 -- Process // } for “pseudo-C” design to 21 k assembly 12/22/2021 Copyright smithmr@ucalgary. ca 27

void Decode. FMSTEREO(int, int *) static int comment = 0; Got placed in seg_dmda in PROLOGUE and given label “comment” Label means “address-location” not value if (comment == 0) { printf("Smith Decode. FMStereo() -- FM_STEREO demodulation example"); comment = 1; } scratch. R 0 = dm(comment); // NOT scratch. R 0 = comment // This operation would set 68 k N and Z flags // which could then be used to control conditional branch // Not true on the 21 k scratch. R 0 = PASS scratch. R 0; if NE jump (PC, NOCOMMENT) (DB); NOP; 12/22/2021 // Test for Zero and Negative // NOT pass(scratch. R 0) // which is MFE ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 28

void Decode. FMSTEREO(int, int *) static int comment = 0; if (comment == 0) { printf("Smith Decode. FMStereo() -- FM_STEREO demodulation example"); comment = 1; } #define comment. R 0 scratch. R 0 comment. R 0 = dm(comment); comment. R 0 = PASS comment. R 0; if NE jump (PC, NOCOMMENT) (DB); NOP; // Better code maintainability // Test for Zero and Negative // dead <- R 0 Code to call printf ( ) here NOCOMMENT: 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 29

Why we don’t “Call C” from assembly Coding the “printf( )” call printf(“Print out the value of %d”, comment); . segment/dm seg_dmda var int comment = 0; Ascii code for “Print out the value of %d” FORMAT 1_LABEL: . var FORMAT 1_STRING[ ] =83, 109, 105, 116, 104, 32, 68, 101, etc, 0; // Don’t forget me! -- “C” EOS. endseg; . segment/pm seg_pmco; OUTPAR 2 = FORMAT 1_LABEL; OUTPAR 1 = dm(comment); CALL _printf (DB): nop; 12/22/2021 // Pointer to string // Value NOT pointer ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 30

Why we don’t “Call C” from assembly Coding the “printf( )” call GOT ONE LINE RIGHT // Get starting address of printf format scratch. R 0 = FORMAT 1_LABEL; USING CJUMP not CALL // Note that is not the stack controlled by SP dm(CTOPstack, minus 1 DM) = scratch. R 0; CJUMP causes R 2 <- FP (I 6) R 2 is destroyed “internally”. extern _printf; cjump _printf (DB); Save FP (as R 2) dm(CTOPstack, minus 1 DM) = r 2; dm(CTOPstack, minus 1 DM) = pc; Save Return Address (one off) modify(CTOPstack, plus 1 DM); 12/22/2021 3 Values placed on stack Only 1 taken off here ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 31

SHARC PROCESS -- STEP 5 OPTIMIZE THE CODE n n Remember -- not normally worth the effort Going to require n n n Knowing the parallel instructions Knowing which ones are valid in combination Taking into account the limitations associated with the finite number of bits in the op-code to describe the parallel operations wanted Understanding Hardware loops Understanding memory and ALU pipelining Optimization is “NEXT WEEK COUNTRY” 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 32

Other examples of code conversion n n Many examples in previous year’s web pages Take a look at the “assembly output” generated by the “C”-compiler for Lab. 0 n n Use the -S option and look for the. s file Get to know the “required stuff” so you can quickly break through the “barrier” and get to the stuff you really want to do -- DSP customization n KEY -- Develop a PSP code review process 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 33

Tackled today n n Prologue, Body and Epilogue of “C” program translated to assembly code (NO DIFFERENCE by hand or by compiler) Example conversion of “C” program into ADSP 21061 using a standard procedure n n n Take into account register architecture Take into account LOAD/STORE architecture Take into account standard assembly code problems Handle Program Flow Constructs Then do conversion of code on line by line basis Learning why to avoid calling “C” from assembly 12/22/2021 ENCM 515 -- Process for “pseudo-C” design to 21 k assembly Copyright smithmr@ucalgary. ca 34