I. Basic concepts and syntax of CMD files The professional name of CMD is linker configuration file, which stores the configuration information of the linker. We call it command file for short. As its name shows, the function of this file is to specify how to link the program. So we know that when writing TI DSP programs, the program can be divided into many segments, such as text, bss, etc., and the functions of each segment are different. When actually running in the chip, the location is also different. For example, text code should generally be placed in flash, while bss variables should be placed in ram. And so on. However, for different chips, the start and end addresses of each memory are different, and the user wants to place a certain segment, especially a custom segment, in what memory and what location, which is also unknown to the linker. In order to tell the linker the allocation of the internal storage space of the chip to be used and the specific storage location of each program segment, it is necessary to write a configuration file, namely CMD file. Therefore, the most important parts of the CMD file are the two sections, namely the two sections of configuration specified by the two pseudo-instructions MEMORY and SECTIONS. Simply put, MEMORY is used to build a model of the target memory, and the SECTIONS instruction arranges the positions of each section according to this model. MEMORY pseudo-instruction MEMORY is used to build a model of the target memory, and the SECTIONS instruction can arrange the positions of each section according to this model. The MEMORY instruction can define various types of memory and capacity of the target system. The syntax of MEMORY is as follows: MEMORY { PAGE 0 : name1[(attr)] : origin = constant,length = constant name1n[(attr)] : origin = constant,length = constant PAGE 1 : name2[(attr)] : origin = constant,length = constant name2n[(attr)] : origin = constant,length = constant PAGE n : namen[(attr)] : origin = constant,length = constant namenn[(attr)] : origin = constant,length = constant } PAGE The keyword marks an independent storage space, page number n The maximum value is 255. In practical applications, it is generally divided into two pages, PAGE0 program memory and PAGE1 data memory. name is the name of the storage interval, no more than 8 characters, the same name can appear on different PAGEs (it is best not to avoid confusion), and the same name is not allowed in a PAGE. attr is the attribute identifier, R means readable; W means writable; X means the interval can be loaded with executable code; I means the memory can be initialized. No attribute code is written, indicating that the storage interval has the above four attributes. Basically, we choose this writing method. The following is an example: MEMORY { PAGE 0 : BEGIN : origin = 0x000000, length = 0x000002 RAMM0 : origin = 0x000050, length = 0x0003B0 PAGE 1 : RAMM1 : origin = 0x000480, length = 0x000380 RAML2 : origin = 0x008C00, length = 0x000400 } SECTIONS pseudo-instruction SECTIONS The syntax of the instruction is as follows: SECTIONS { .text: {all .text input segment names} load = load address run = run address .cinit: {all .data input segment names} load = load address run = run address .bss: {all .bss input segment names} load = load address run = run address .other: {all .other input segment names} load = load address run = run address } For example: .text : > RAML0L1, PAGE = 0 SECTIONS must be written in uppercase letters. The following curly brackets contain the descriptive statement of the output segment. The description of each output segment starts with the segment name. After the segment name is the parameter description of how to organize the input segment and allocate memory to the segment: Starting with .text For example, the attribute statement of the segment, "{all .text input segment names}" is used to explain which sub-target files' segments make up the .text segment of the connector output segment. For example, SECTIONS { .text:{ file1.obj(.text) file2(.text) file3(.text,cinit)} omitted } indicates that the output segment .text is to link file1.obj's .text and file2's .text as well as file3's .text and .cinit. In CCS's SECTIONS, usually only a "{ }" with no content in the middle is written to indicate the corresponding segments of all target files. Next, it is explained that "load = load address run = run address". The linker allocates two addresses in the target memory for each output segment: one is the load address, and the other is the run address. Normally, the two addresses are the same, and it can be considered that the output segment has only one address. In this case, the statement "run = run address" can be omitted; but sometimes the two addresses need to be separated, such as loading the program into FLASH and then putting it into RAM for high-speed operation. This requires the separate configuration of the run address and the load address, as shown in the following example: .const :{omitted} load = PROG run = 0x0800 The constant is loaded into the program storage area and configured to be called in RAM. Several ways of writing "load = load address" need to be explained. First, the "load" keyword can be omitted, "=" can be written as ">", and the "load address" can be: address value, storage interval name, PAGE keyword, etc., so when you see ".text:{ } > 0x0080”. Don’t be surprised by statements like “>” in “run = running address”. The “=” in “run = running address” can be replaced by “>”, and there are no other simplified writing methods. Please don’t use them indiscriminately. Custom segments (C language) #pragma DATA_SECTION(global variable name,"user-defined segment name in data space"); #pragma CODE_SECTION(function name,"user-defined segment name in program space"); CODE_SECTION is used to define code segments DATA_SECTION is used to define data segments For example: a data segment my_sect and a code segment ramfuncs are defined in the c file, as follows: #pragma DATA_SECTION(bufferB, "my_sect") char bufferB[512]; #pragma CODE_SECTION(dragon_update,"ramfuncs"); Uint16 dragon_update(UPDATE_SOURCE_TYPE *update_flag) { . . . } Then specify the location of these two sections in the cmd file. If you want to specify the segment in the assembly, use the method, start with .sect "XXX" before the code to indicate that the next section of code is in the xxx code segment. Example: PieVectTableFile : > PIE_VECT, PAGE = 1 // nonBIOS. cmd#pragma DATA_SECTION(PieVectTable,"PieVectTableFile"); // globalVariableDefs.cstruct PIE_VECT_TABLE PieVectTable; // globalVariableDefs.cNote: #pragma cannot be declared in a function body; #pragma must be declared before the symbol is defined and used