This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

singlecore bootloader ---> multicore bootloader

Hi,

I have an out-file for C6670, which has to be run on all 4 cores (Ethernet Bootloader)

Ethernet Bootloader for singlecore application is already working, the question is about the mutlicore case with one out-file for all cores.

With hex6x I get the *.btbl with local section adresses ( 0x0080 0000) for internal SRAM.


I guess the new multicore *.btbl has to contain 4 times the section data of the *.btbl above and the local addresses have to be changed to global (0x1080 0000, 0x1180 0000, ...) adresses.

Am I right?

Are there exisiting some tools to do this (address, single-/multicore-bootloader) conversion?

Best regards

Simon

  • Hi Simon,

    you can solve it this way:

          hex6x core0.rmd
          hex6x core1.rmd
          hex6x core2.rmd
          hex6x core3.rmd

          bfmerge (previously known as mergebtbl) core0.btbl core1.btbl core2.btbl core3.btbl simple.btbl

    You can find it in:
    C:\ti\mcsdk_2_01_02_06\tools\boot_loader\ibl\src\util\btoccs

    Kind regards,
    one and zero

  • Thank you, one and zero,

    but how about the adresses of L1/L2 - after the merge with bfmerge I see the local (0080 0000) addresses in the according sections. for all four cores. Don't they have to be changed to the global (1080 0000, 1180 0000, ...) ones?

    Kind regards

    simon

  • Hello Simon,

    You are asking a very good question.

    There are multiple ways to do it:

    1) keep separate *.out files for each core by modifying the *.cmd file so each core mapes to it own address with global address being used in the *.cmd file. The problem here is if application is same for all cores, you probably don't want to maintain four copies of that;

    Or: 2) keep a single *.out but use some utilities to do the conversion. I remember I wrote such utilities in the past. Might be good to add it into MCSDK. For now, I attached it for your quick reference. Please give it a try. You  can try 2 cores first. Remember to run this utilitiy before the merge btbl utilities. Also there is room for further improvement for this utility: if there is shared memory/DDR being used, it just needs to be loaded once so could add some conditions there after you getting the starting address information to determine and maybe just load it for the core 0, not for other cores. Of course loading multiple times won't hurts but just takes time. But try without this enhancement first. Hopefully you follow what I mean.

    /* This short program was written by David Zhou to convert a boot table from using the local memory address
       to global memory address so identical application *.out can be maintained just one copy in stead of multiple copies.
       
       Ver: 0.2
       Last modified on: April 16, 2010
    
       Usage example:
    	Local2Global input.btbl core0.btbl 0
    	Local2Global input.btbl core1.btbl 1
    	Local2Global input.btbl core2.btbl 2
    	Local2Global input.btbl core3.btbl 3
    	Local2Global input.btbl core4.btbl 4
    	Local2Global input.btbl core5.btbl 5
    
    	The above is to convert the boot table from local address to global address for core 0 to 5.
    
    	Limitation: the input.btbl is boot table format in big endian mode already.
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int toNum (unsigned char c)
    {
      if ((c >= '0') && (c <= '9'))
        return (c - '0');
    
      else if ((c >= 'A') && (c <= 'F'))
        return (c - 'A'+10);
    
     else  return (c - 'a' + 10);
    }
    
    int main (int argc, char *argv[])
    {
      FILE *strin;
      FILE *strout;
      int core_num;
      char cores[] = { '0','1','2','3','4','5'};
      unsigned long int block_size,block_counter=0;
      unsigned int count_words=0,temp;
      int i, slen;
      char iline[132];
    
      /* Verify the number of args */
      if (argc != 4)  {
        printf ("usage: %s inputfile outputfile core_num\n", argv[0]);
    	printf ("core_num: from 0 to 5\n", argv[0]);
        return (-1);
      }
    
      /* Open all the files */
      strin = fopen (argv[1], "r");
      if (strin == NULL)  {
        printf ("could not open input file %s\n", argv[1]);
        return (-1);
      }
    
      strout = fopen (argv[2], "w");
      if (strout == NULL)  {
        printf ("could not open input file %s\n", argv[2]);
        return (-1);
      }
    
      core_num = atoi(argv[3]);
    
      if(core_num <0 || core_num >5){
    		printf ("core_num: between 0 to 5\n", argv[3]);
    		return (-1);
      }
    
      printf("Now converting the boot table to global address for core %d\n",core_num);
    
    	/* skip the first two lines */
    	fgets (iline, 132, strin);
    	fprintf(strout, iline);
    	fgets (iline, 132, strin);
    	fprintf(strout, iline);
    
    	/* Handle the 3rd line */
    	fgets (iline, 132, strin);
    	slen = strlen(iline);
    	if(slen <34) {
    		printf("Error in the 3rd line in the input file\n");
    		fcloseall();
    		return(-1);
    	}
    
    	iline[0] = '1';
    	iline[1] = cores[core_num];
    
    	iline[24] = '1';
    	iline[25] = cores[core_num];
    
    	block_size = 0;
    	for(i=0; i<4; i++) {
    		block_size <<= 8;
    	    block_size += ((toNum(iline[12+i*3])<<4) + toNum(iline[13+i*3]));
    	}
    	
    	block_counter++;
    	block_size = block_size >> 2;
    	printf("Found block %d, block size is %x words\n",block_counter,block_size);
    	count_words = block_size - ((((slen-1)/3)/4)-3);
    	fprintf(strout, iline);
    
    	/* Handle the rest lines */
    	while(1) {
    		if(fgets(iline, 132, strin)==NULL) break;
    		slen = strlen(iline);
    		temp = ((slen-1)/3)/4;
    		if(count_words>=temp)  
    			count_words -= temp;
    		else {
    			block_size = 0;
    			temp = 12 * count_words;
    			for(i=0; i<4; i++) {
    				block_size <<= 8;
    			    block_size += ((toNum(iline[temp+i*3])<<4) + toNum(iline[temp+i*3+1]));
    			}
    
    			block_counter++;
    			block_size = block_size >> 2;
    			if(block_size < 1) block_size = 1;
    			printf("Found block %d, block size is %d words\n",block_counter,block_size);
    			count_words = block_size - ((((slen-1)/3)/4)-2) - count_words;
    			temp += 12;
    			iline[temp++] = '1';
    			iline[temp] = cores[core_num];
    		}
    		fprintf(strout, iline);
    	}
      
    	fclose(strin);
    	fclose(strout);
    	return(0);
    }
    
    

    best regards,

    David Zhou

  • Hello David,

    thank you very much for your tool. It seems to be working. I only made some changes to handle shared memory.

    My Problem is now, that the Byte count of one section in my *.btbl file seems to be wrong - or it is right and there are to much bytes written out by hex6x for this section, the byte count of this section is the same as in the *.map-file.

    This leads to the point, that your tool considers a wrong number as the byte count of the next section. The resulting btbl-file is totaly wrong, of course.        

    I don't know if hex6x has a bug or if we did something wrong in CCS.

    Did you see something similar in the past?

    Best regards

    Simon 

  • Simon,

    You would need to provide more details: what is the byte count for that section? Is this from hex6x? Usually it should be padded so size will be a mutiple of 4 bytes. I think you can trace it step by step to narrow it down.

    regards,

    David

  • Hi David,

    The byte count of that section is: 0x3DBB6 --> 252854 which is no multiple of 4 bytes !
    So now I catch this in the tool you provided. Now it works!

    Here the edited tool. I added the fix above and shared memory handling:

    /* This short program was written by David Zhou to convert a boot table from using the local memory address
       to global memory address so identical application *.out can be maintained just one copy in stead of multiple copies.
       
       Ver: 0.2
       Last modified on: April 16, 2010
    
       Usage example:
    	Local2Global input.btbl core0.btbl 0
    	Local2Global input.btbl core1.btbl 1
    	Local2Global input.btbl core2.btbl 2
    	Local2Global input.btbl core3.btbl 3
    	Local2Global input.btbl core4.btbl 4
    	Local2Global input.btbl core5.btbl 5
    
    	The above is to convert the boot table from local address to global address for core 0 to 5.
    
    	Limitation: the input.btbl is boot table format in big endian mode already.
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int toNum (unsigned char c)
    {
      if ((c >= '0') && (c <= '9'))
        return (c - '0');
    
      else if ((c >= 'A') && (c <= 'F'))
        return (c - 'A'+10);
    
     else  return (c - 'a' + 10);
    }
    
    int main (int argc, char *argv[])
    {
      FILE *strin;
      FILE *strout;
      int core_num;
      char cores[] = { '0','1','2','3','4','5'};
      unsigned long int block_size,block_counter=0;
      unsigned int count_words=0,temp;
      int i, slen;
      char iline[132];
    
    	printf("\n");
    
      /* Verify the number of args */
      if (argc != 4)  {
        printf ("usage: %s inputfile outputfile core_num\n", argv[0]);
    	printf ("core_num: from 0 to 5\n", argv[0]);
        return (-1);
      }
    
      /* Open all the files */
      strin = fopen (argv[1], "r");
      if (strin == NULL)  {
        printf ("could not open input file %s\n", argv[1]);
        return (-1);
      }
    
      strout = fopen (argv[2], "w");
      if (strout == NULL)  {
        printf ("could not open input file %s\n", argv[2]);
        return (-1);
      }
    
      core_num = atoi(argv[3]);
    
      if(core_num <0 || core_num >5){
    		printf ("core_num: between 0 to 5\n", argv[3]);
    		return (-1);
      }
    
      printf("*** Now converting the boot table to global address for core %d ***\n\n",core_num);
    
    	/* skip the first two lines */
    	fgets (iline, 132, strin);
    	fprintf(strout, iline);
    	fgets (iline, 132, strin);
    	fprintf(strout, iline);
    
    	/* Handle the 3rd line */
    	fgets (iline, 132, strin);
    	slen = strlen(iline);
    	if(slen <34) {
    		printf("Error in the 3rd line in the input file\n");
    		fcloseall();
    		return(-1);
    	}
    
    
    	if(iline[0]=='0' && iline[1]=='0') //only L2/L1
    	{
    		iline[0] = '1';
    		iline[1] = cores[core_num];
    	}
    
    	if(iline[24]=='0' && iline[25]=='0')//only L2/L1
    	{
    		iline[temp++] = '1';
    		iline[temp] = cores[core_num];
    	}
    
    	block_size = 0;
    
    	for(i=0; i<4; i++) {
    		block_size <<= 8;
    		block_size += ((toNum(iline[12+i*3])<<4) + toNum(iline[13+i*3]));
    	}
    
    	block_counter++;
    	block_size = block_size >> 2;
    	printf("Found block %d, block size is 0x%x words\n",block_counter,block_size);
    	count_words = block_size - ((((slen-1)/3)/4)-3);
    
    	printf("\--> block %d, block size is 0x%x words (%x Bytes)\n",block_counter,block_size, block_size*4);
    	fprintf(stdout, iline);
    	printf("\n");
    
    	fprintf(strout, iline);
    
    	/* Handle the rest lines */
    	while(1) {
    		if(fgets(iline, 132, strin)==NULL) break;
    		slen = strlen(iline);
    		temp = ((slen-1)/3)/4;
    		if(count_words>=temp)  
    			count_words -= temp;
    		else {
    			block_size = 0;
    			temp = 12 * count_words; // conversion back to bytes (3Bytes ascii per code byte, 4 Bytes per word)
    			for(i=0; i<4; i++) {
    				block_size <<= 8;
    			    block_size += ((toNum(iline[temp+i*3])<<4) + toNum(iline[temp+i*3+1]));
    			}
    
    			if (block_size%4 != 0) // no multiple of 4
    			{
    				printf(" -- %d bytes padded here: --\n", (4 - block_size%4) );
    				block_size += 4 - block_size%4;
    			}
    
    			block_counter++;
    			block_size = block_size >> 2;
    			if(block_size < 1) block_size = 1;
    
    			count_words = block_size - ((((slen-1)/3)/4)-2) - count_words;
    			temp += 12;
    			if(iline[temp]=='0' && iline[temp+1]=='0')//only L2/L1
    			{
    				iline[temp++] = '1';
    				iline[temp] = cores[core_num];
    			}
    
    
    			{
    				printf("Found block %d, block size is 0x%x words (0x%x Bytes)\n",block_counter,block_size, block_size*4);
    				printf("First Line:\n");
    				fprintf(stdout, iline);
    				printf("\n");
    			}
    
    		}
    		fprintf(strout, iline);
    	}
      
    	fclose(strin);
    	fclose(strout);
    	return(0);
    }
    
    


    Coming to the next question:

    Unfortunately the resulting bootloader does not work. The DSP does not start.

    Is it possible that we have to manage the right entry points for Core 1-3 ?

    The bootloader only has the entrypoint for core 0, right? But our code does not start at address 0x00800000, so I think we have to set the correct entrypoint, the same as core0, because every core has exact the same software running.

    Is that right?

    Many thanks for your help!

    regards,

    Simon

  • Hello Simon,

    1) About padding: I think our example *.rmd file has:

    memwidth = 32, romwidth = 32

    So when you use hex6x, it will be automacally padded with zero already. Meaning you will always get it in every 4 bytes.It is better to control this way rather then via post processing utilities:

    2) I assume you mean core 0 is working but not core 1 to 3? Yes, core 1 to 3 need to given with correct entry point address. Below I give you some example code to try (surprized didn't find it in bootloader user's guide, will push to get it in next version of that).

    #define DEVICE_REG32_W(x,y)   *(volatile uint32_t *)(x)=(y)
    #define DEVICE_REG32_R(x)       (*(volatile uint32_t *)(x))

    /* Magic address RBL is polling */
    #ifdef _EVMC6678L_
    #define MAGIC_ADDR     0x87fffc
    #endif

    #ifdef _EVMC6670L_
    #define MAGIC_ADDR     0x8ffffc
    #endif

    #define BOOT_MAGIC_ADDR(x)  (MAGIC_ADDR + (1<<28) + (x<<24))
    #define IPCGR(x)                       (0x02620240 + x*4)
    #define KICK0                            (0x2620038)
    #define KICK1                            (0x262003C)

    for (core = 1; core < pform_info.cpu.core_count; core++)
     {
                DEVICE_REG32_W(BOOT_MAGIC_ADDR(core), entry_addr);
                DEVICE_REG32_W(KICK0, 0x83e70b13);
                DEVICE_REG32_W(KICK1, 0x95a4f1e0  );
                DEVICE_REG32_W(IPCGR(core), 1);
                platform_delay(200); /* note this is optional, controlled by you */
     }    

    Please note in your case you would use 6670 as code covers both, also number of cores will be different.

    Good luck with your debugging.

    best regards,

    David Zhou

     

    memwidth

  • Just to add: above code will need to be added for core 0, typically right at the beginning in main().

    -David

  • Thank you David, everthing is running well now.


    dzhou said:

    1) About padding: I think our example *.rmd file has:

    memwidth = 32, romwidth = 32

    So when you use hex6x, it will be automacally padded with zero already. Meaning you will always get it in every 4 bytes.It is better to control this way rather then via post processing utilities:

    Yes we use memwidth = 32, romwidth = 32

    I can see the padded zeros, but the Byte count has still the old value (non multible of 4 bytes), before padding, so the tool cannot find the right end of the section.

    This I fixed in the tool.

    Best regards

    Simon