In this video, we will be discussing code memory and the code segment. A compiled program primarily allocates information in two types of memory, code and data. Just like the data segment, the code segment can be broken down into many different sub-segments and characteristics. A third type of memory, register memory, is utilized by a program to run assembly instructions and to interact with the microcontroller. A program's executions is a series of instructions that is retrieved from our code memory. The CPU registers are utilized in nearly every assembly instruction that gets executed. In order for this interaction, the assembly instructions need to know precise details about what's registers and what memory locations each instruction is programmed to use. This information is encoded directly into the instructions. The code segment represents the part of compiled memory that contains all of our executable program. This segment primarily contains all of our compiled code but also a little bit of program data memory. The code segment is put into memories like flash, that are run time read-only. This is done to protect your code from being overwritten but also for security reasons. Code memory can be runtime writable but it requires extra interaction and permissions to write data depending on the implementation? Code memory has other limitations like latency, durability, but it has a strong benefit of being non-volatile memory. Because of this, memories like flash are used to store our program code without fear of data loss when power is removed. Let's dive into the sub-segments of the code segment. These include things like the interrupt vector table, your written software program, constant read-only data, initialization code, Bootloaders and flash configuration. Much like the data segment, the linker file specifies what physical memory the code segments map to. The sub segments get mapped continuously into this region starting at the address 0. Here we have an example of how this code segment and the sub-segments map into physical memory. The sizes of each of these segments are implementation dependent, either due to the architecture, the compiler, or your program. Starting at address 0, we have the vector table. The vector table represents a function address table that maps to specific interrupt sub-routines. We will discuss interrupting more details on the follow up course. But interrupt routines are just like specialized routines that take priority over your main program. They get called in synchronously and they must be defined in a very particular way. When you enable an interrupt and write the function routine for that interrupt handler, you must map the interrupt function's address from code memory into the proper spot on the table. That way when the CPU needs to respond to an interrupt request by calling the associated interrupt function, it can look up in this table and find encode memory where that function lives. In general, the location to put in the vector table at address 0 is pretty standard. But this can be configurable on our map architectures. The size of the sub-segment will be set based on the architecture as different architecture support different numbers of interrupts. The next section we will discuss is the text segment. The text represents the segment where all of your actual code you wrote is compiled into. This includes your main function and all of your software routines that you write. Your text section size will depend on how large your program is. In addition, there are many functions to get added to the text from the C standard library. This includes things like call your main function and things that you're turn from your main function too. The read-only data or RO data section is sometimes owned as the .const and we discussed this previously. This is where our constant variables are defined. You should not be able to alter your constant data. Trying to overwrite data that is put in your flash memory may cause a processor exception or the operation may just do nothing depending on the architecture. This is because the code memory requires extra interactions with the flash controller in order to write data into it. The .pinit and .cinit sub segments are used at initialization. All of your initialization data values are stored in non-volatile data memory until the program starts. This should make sense because your data memory in SRAM will lose its data once power is removed. Initial values should work every time your program starts up. This is because initialization data is stored in your code memory, and then loaded into data memory at start up. In general, a compiler may be able to optimize out storage of single variable constants, if it knows there's only a single use. However, for large pieces of initialization data, like arrays or strings, they get stored in areas like the read-only data. In addition, there are associated routines to help perform the actual process of data initialization. This is a double hit on overhead because initialization of data requires both the code memory allocated for initial values but also the initialization process. Depending on the architecture and compiler, these sections may have different names or different implementations. However, you are likely to see sub segments similarly named .pinit, .cinit, .ctors, .init_array and .init. Some embedded applications may also use languages like C++, in addition to C. Some sections may be specific for construction and destruction of C++ objects in this case. The last sub-segment you may see is something related to Bboot or bootloaders and flash config. As the stuff before, embedded systems need a method of installing code. Using external program loaders that connect directly to a processor are expensive and require extra hardware. The dev kits we are using in this class utilize an on-board processor to program our marker controllers through a cheaper much more standard interface like USB. So we can avoid using these external programmers. These extra on-board processors are referred to as external bootloader or flasher. Alternatively, you can reserve a small segment of your code memory to act as your installer. The bootloader would be a small program that at reboot looks for a signal on one of its communication interfaces signalling a program install. If it sees this, it overwrites the current flash memory with the new program. If it does not see anything, it will just call the currently loaded program and begin program execution. This will reduce the amount of space you have for your program but also reduce the amount of hardware required to install. This process is actually very complex and it will have its own video later on. One last note about this code segments and the C standard functions. You do not automatically need to include this. Compilers will automatically use some C standard functions when your code is compiled. You can avoid the addition of all this extra sub segments by writing your own beta metal C with no standard library compiler flux. Or by writing your own assembly directly. However, this is not suggested as some of the standards library functionality makes writing your programs much easier. Like defining what happens at start up and program completion. In addition, it will map unsupported operations for your architecture into equivalent software processes. Code memory contains our program and also our data in some cases. The code memory is usually a lot larger than our data memory, because code memory is not meant to be rewritten during run time. When we install program code, we want that information to persist in between power cycles. More advanced architectures with embedded OS support allow for code memory to be written and installed while the processor is running. But most microcontrollers do not support it this way. Installing a new program requires a very particular process to interface with the flash memory. However, the way we broke down a program's code memory into the code segment is very similar to how we divided our data memory into smaller subsegments of data.