1 Basic principles
Following the last blog s3c2440 learning path-010 sdram, sdram has been initialized, and now the value of SDRAM can be officially brought into play. (SDRAM can be read and written at will, and the subsequent codes will be placed on it to run)
1.1 Division of program segments
After a program is compiled, there will be a code segment, a data segment, a read-only data segment, a bss segment, and a comment segment.
Here we mainly talk about why the bss segment can reduce the size of the bin file. The bbs mainly records the location of global (static-modified local) variables that are not initialized or initialized to 0, but does not record their specific data, because the value of this part is set to 0 by default.
Here are 2 small programs
test1.c
#include char a[1000]; int main(int argc, char *argv) { return 0; } test2.c #include char a[1000] = {1}; int main(int argc, char *argv) { return 0; } test1.c defines an array of 1 char[1000], does not initialize it, and saves it in the bss segment. The size of the compiled bin file is 8756B. test2.c also defines an array of chart1000], but initializes it and saves it in the data segment. The size of the compiled bin file is 9592B. Because the data of test1.c is stored in the bss segment, and bss only records its location, it does not require a large storage space. However, test2.c needs to store the entire array value in the data segment, so it needs to be at least 1000Byte larger than the bin of test1.c. It should be noted that only the size of the bin file is reduced, and the memory size consumed when the code is actually running is the same. 1.2 Why do we need to relocate code? When using nand to boot, due to the characteristics of 2440, only the first 4K of code can be run (the first 4K will be automatically copied to the internal sram), so it is impossible to run a 100K+ uboot.bin, so the code needs to be relocated to the external SDRAM. When using nor to start, the nor on the jz2440 development board is 2MB, which is enough to store general programs. However, nor can be read at will but not written at will, which means that global variables cannot be modified. Because modifying global variables requires rewriting the values into nor, and nor cannot be written at will, writing values will fail. Therefore, the code also needs to be relocated to the external SDRAM. (Local variables can be modified because local variables are placed in the stack, which is generally set in the sram inside the 2440) 1.3 How to implement relocation It is very simple to implement relocation. First, copy all the codes to SDRAM. Second, jump the code to SDRAM to run, which means modifying the value of PC. To copy code to SDRAM, you need to figure out where to start copying, how big to copy, and whether there is any order or rule. 1) The code is placed in NOR/NAND, so it should be copied from NOR/NAND. When burning the code, it starts from the address 0 of NOR/NAND, so it should be copied from the address 0 of NOR/NAND. 2) The program is divided into code segment, data segment, read-only data segment, bss segment and comment segment, so all this data must be copied into SDRAM, but what is the specific size? I will briefly talk about the lsd link script later, and this script can tell you the size of the program. 3) The order can be set by the lds linker script, but the general order is code segment -> read-only data segment -> data segment -> bss segment. 1.4 lds linker script Because I haven't done an in-depth study of the lsd linker script, I only know how to use it simply. For detailed usage, please refer to the official documentation at http://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_mono/ld.es.html. Here I only comment on the lds linker script I use. test.lds SECTIONS { // . represents the current position, set the current position to 0x30000000, 0x30000000 is the starting address of SDRAM . = 0x30000000 ; // 4-byte alignment . = ALIGN(4); //Define a variable __copy_code_start = the current position, which is 0x30000000 __copy_code_start = . ; //Code snippet .text : { //Store the code segment of start.o first, because start.o is the first file to be run start.o //* indicates all, code snippets for all files *(.text) } . = ALIGN(4); //Read-only data segment for all files .rodata : { *(.rodata) } . = ALIGN(4); //Data segment of all files .data : { *(.data) } . = ALIGN(4); //Define variable __bss_start = current position, the current position is equal to 0x30000000 + code segment of all files + read-only data segment of all files + data segment of all files __bss_start = . ; //The bss segment and comment segment of the file .bss : { *(.bss) *(.COMMON) } //Define variable __end = current position, the current position is equal to __bss_start + bss segment and comment segment of all files __end = . ; } From the test.lds script, we can know that the storage order of the program is: text->text->rodata->data->bss of start.o. A total of three variables are defined, __copy_code_start, __bss_start, and __end. When compiling, you can use the link script by using -T. Because the first sentence of the link script ". = 0x30000000;" sets the current position to 0x30000000, so the starting position of the dis file is 0x30000000 when disassembling. When you burn the generated bin file into nor/nand, it will still be copied from the 0 position of nor/nand. After reset, PC=0, and the program still runs from address 0. Therefore, 0x30000000 in the dis file will not have any effect on the code. The __copy_code_start, __bss_start, and __end are what you need for programming later. Makefile test.dis 2 Source code explanation 2.1 Main Process start.s /* Initialize external sdram */ bl bank6_sdram_init /* Copy code from NOR to SDRAM */ /* copy .data .rodata. .text to SDRAM */ bl copy2sdram /* Clear bss segment */ /* clear bss segment */ bl clear_bss /* Initialize the serial port */ bl uart0_init /* Print position value */ bl print_position /* Jump to main to execute */ ldr pc, =main /* abs jump to main */ There will be some other initializations before start.s, but I will skip them all and only look at the most important parts. The initialization of SDRAM was discussed in the previous blog, so I will not introduce it here. 2.2 Copying text, data, and rodata segments init.c void copy2sdram(void) { extern int __copy_code_start, __bss_start; volatile unsigned int *src = (unsigned int *)0; volatile unsigned int *dst = (unsigned int *)&__copy_code_start; volatile unsigned int *end = (unsigned int *)&__bss_start; while(dst < end) { *dst++ = *src++; } } __copy_code_start, __bss_start are variables in the link script, which refer to external variables, so extern is required. The current program only supports the relocation of nor, while 2440 can directly access nor, so src=0 means the address 0 of nor. &__copy_code_start means taking the value of the variable __copy_code_start, which is also 0x30000000. The expression here is different from C language. C language takes the address of the variable, while __copy_code_start is a variable in the link script, so it is used differently. You can remember this as a rule. Similarly, end = &__bss_start also takes the value of __bss_start, 0x30001000. The main function of this code is to copy the data at address nor 0 to address 0x30000000, with a length of end - dst = &__bss_start - &__copy_code_start = 0x30001000 - 0x30000000 = 0x1000. Only text, data, and rodata are copied here, and the bss segment is not copied. Next, the bss segment will be processed. (0x30000000 is the starting address of SDRAM. Copying to this address means copying to SDRAM. If you don’t understand, please read the previous blog) 2.3 Clear the bss segment init.c void clear_bss(void) { extern int __bss_start, __end; volatile unsigned int *src = (unsigned int *)&__bss_start; volatile unsigned int *end = (unsigned int *)&__end; while(src <= end) { *src++ = 0; } } Similarly, extern is required to reference __bss_start and __end link script variables. Here, &__bss_start and &__end are also used to obtain their values. src = &__bss_start = 0x30001000, end = &__end = 30001008. The main function of this code is to clear the data from 0x30001000 to 0x30001008. When copying the code, do not copy the bss segment, so this data is all 0, so you only need to record the starting and ending positions of bss, and then clear it. This also corresponds to what was said before, the bss segment can reduce the size of the bin file. 2.4 Print __copy_code_start, __bss_start, __end init.c void print_positon(void) { extern int __copy_code_start, __bss_start, __end; volatile unsigned int *code_start = (unsigned int *)&__copy_code_start; volatile unsigned int *bss_start= (unsigned int *)&__bss_start; volatile unsigned int *end= (unsigned int *)&__end; printf("code_start:%xn", code_start); printf("bss_start:%xn", bss_start); printf("end:%xn", end); } The function of print_positon is to print the values of __copy_code_start, __bss_start, and __end, so you need to call bl uart0_init first to initialize the serial port. 2.5 Program Jump start.s finally executes ldr pc, =main to assign pc to the value of main. From the dis file, we can see that the statement corresponding to ldr pc, =main is ldr pc, [pc, #16]. pc + 16 = 0x30000088, the value at the position of 0x30000088 is 0x30000af8, which happens to be the value of main. Therefore, ldr pc, =main is equal to pc=0x30000af8, and the program starts running on SDRAM. It should be noted here that before executing ldr pc, =main, the program is running on nor, so the address of the program cannot exceed 2M. Although the starting address of the program is 0x30000000, the actual value of PC needs to be subtracted by 0x30000000. Although the displayed address is 0x30000000+, the program is burned from the address 0 of nor. After reset, the program starts to fetch instructions from the address 0 of nor, which is also the corresponding 0x30000000. Therefore, PC increases from 0, not from 0x30000000, until the value of PC is truly equal to the value displayed in the dis file after executing ldr pc, =main.
Previous article:【s3c2440】Lesson 3: Code Relocation
Next article:Code relocation of s3c2440
Recommended ReadingLatest update time:2024-11-23 18:29
- Naxin Micro and Xinxian jointly launched the NS800RT series of real-time control MCUs
- How to learn embedded systems based on ARM platform
- Summary of jffs2_scan_eraseblock issues
- Application of SPCOMM Control in Serial Communication of Delphi7.0
- Using TComm component to realize serial communication in Delphi environment
- Bar chart code for embedded development practices
- Embedded Development Learning (10)
- Embedded Development Learning (8)
- Embedded Development Learning (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Intel promotes AI with multi-dimensional efforts in technology, application, and ecology
- ChinaJoy Qualcomm Snapdragon Theme Pavilion takes you to experience the new changes in digital entertainment in the 5G era
- Infineon's latest generation IGBT technology platform enables precise control of speed and position
- Two test methods for LED lighting life
- Don't Let Lightning Induced Surges Scare You
- Application of brushless motor controller ML4425/4426
- Easy identification of LED power supply quality
- World's first integrated photovoltaic solar system completed in Israel
- Sliding window mean filter for avr microcontroller AD conversion
- What does call mean in the detailed explanation of ABB robot programming instructions?
- STMicroelectronics discloses its 2027-2028 financial model and path to achieve its 2030 goals
- 2024 China Automotive Charging and Battery Swapping Ecosystem Conference held in Taiyuan
- State-owned enterprises team up to invest in solid-state battery giant
- The evolution of electronic and electrical architecture is accelerating
- The first! National Automotive Chip Quality Inspection Center established
- BYD releases self-developed automotive chip using 4nm process, with a running score of up to 1.15 million
- GEODNET launches GEO-PULSE, a car GPS navigation device
- Should Chinese car companies develop their own high-computing chips?
- Infineon and Siemens combine embedded automotive software platform with microcontrollers to provide the necessary functions for next-generation SDVs
- Continental launches invisible biometric sensor display to monitor passengers' vital signs
- EEWORLD University ---- Linux Embedded Development
- [Today at 10:00 live broadcast] Deep digging into NXP LPC55S69: a new generation of secure and low-power MCU based on ARM Cortex-M33 core
- Pearl River Delta: The third pole of China's semiconductor industry?
- Automotive electronic systems require low quiescent current
- Four doctoral students designed an intelligent monitoring system for earthmoving trucks
- Learn about C2000 32-bit microcontrollers
- Migrate ssh service to EK200-zlib-openssl-openssh
- Microchip Expands Lineup of 22-Bit Delta-Sigma ADCs
- Application in Distributed Control Systems
- Working principle of wind turbine