51 MCU UCOS II task switching assembly code analysis (1)

Publisher:baiyuguojiLatest update time:2020-04-29 Source: eefocus Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

The task switching functions in ucos are all written in assembly language and belong to the "need to be ported" files.


The assembly file name is generally called: OS_CPU_A.ASM


If you want to understand the principle of task switching, the first difficulty you encounter is the large number of uncommon assembly pseudo-instructions in the assembly file OS_CPU_A.ASM. Understanding these instructions is the first step to understand the principles of the program.


This article will only analyze these assembly instructions.


This file provides 4 API functions for the ucos operating system, namely:


PUBLIC OSStartHighRdy; Function: Switch to the task with the highest horizontal and vertical priority among the ready tasks

PUBLIC OSCtxSw ; Function: general context switch, ContextSwitch, context switch is also called task switch

PUBLIC OSIntCtxSw ; Function: Context switch in interrupt

PUBLIC OSTickISR ; Function: system tick


PULIC is an assembly pseudocode indicating that the declared function can be called by other files

First, let's learn a knowledge point. How to write a function in assembly code so that this function can be called by other files? It is not as simple as adding the PUBLIC keyword. In addition, we must also abide by certain specifications. You can refer to this article, link: click to open the link


If the link is down, just search for the keyword: "Mutual calls between assembly functions and C functions"


In addition to being used by external files to reference their own functions, this file OS_CPU_A.ASM also needs to reference functions and variables of other files, for example: 


EXTRN IDATA (OSRunning); declare the variable OSRunning that references the IDATA area

MOV R0,#LOW (OSRunning) ; Use external variables in assembly

EXTRN CODE (_?OSTaskSwHook) ;Declare reference to external function (code), OSTaskSwHook()

LCALL _?OSTaskSwHook ;Call C language function OSTaskSwHook() in assembly


Explanation: The function OSTaskSwHook is written in C language and is named OSTaskSwHook. However, if you want to reference it in assembly, you must add a prefix in front of it. From the article in the previous link, we know that if we reference a reentrant function in assembly, we must add a _? prefix in front of the function name so that it can be recognized by the assembly file. Why do we need to add a prefix? Because when the C51 C language function is converted to assembly, the keil compiler will automatically change the C language function name. Of course, the changes made by keil are regular. For example, when we declare a reentrant C function, keil will automatically add the prefix "_?" to the original function name after converting it to assembly.


What prefix will keil automatically add? What are the specifications for the added prefix? For these questions, you can refer to the keil help file. Click the menu bar -> help -> uVision help in sequence. Search for "Segment Naming Conventions" in the opened help file to view relevant information.


The standard format for writing a function in assembly for calling from C is as follows:


?PR?OSStartHighRdy?OS_CPU_A SEGMENT CODE; First declare a relocatable code segment (the usage and explanation of this statement can be referred to another article in this blog)

RSEG ?PR?OSStartHighRdy?OS_CPU_A; for relocation, the following codes will be linked to the segment specified by the RSEG instruction

OSStartHighRdy: ; Address number, used as function name

·········; The function body of the assembly function, until it encounters segment allocation instructions such as CSEG/DSEG/RSEG

Explanation of the above code: ?PR?OSStartHighRdy?OS_CPU_A SEGMENT CODE This sentence not only declares a segment name of a relocatable segment, but also the prefix of this segment name is ?PR?, which means that this segment is a function segment (Executable program code)


Let's look at an example of assembling a C language function:


In the main.c file, we define a function like this:



char add_two(char a1, char a2) REENTRANT

{

return a1+a2;

}

This function is as follows after Keil compilation:


85: char add_two(char a1, char a2) REENTRANT 

86: {        

C:0x269B 90FFFF MOV DPTR,#0xFFFF

C:0x269E 120436 LCALL C?ADDXBP(C:0436)

C:0x26A1 ED MOV A,R5

C:0x26A2 F0 MOVX @DPTR,A

C:0x26A3 90FFFF MOV DPTR,#0xFFFF

C:0x26A6 120436 LCALL C?ADDXBP(C:0436)

C:0x26A9 EF MOV A,R7

C:0x26AA F0 MOVX @DPTR,A

    87: return a1+a2; 

C:0x26AB 850883 MOV DPH(0x83),?C_XBP(0x08)

C:0x26AE 850982 MOV DPL(0x82),OutTxBuf(0x09)

C:0x26B1 A3 INC DPTR

C:0x26B2 E0 MOVX A,@DPTR

C:0x26B3 FF MOV R7,A

C:0x26B4 850883 MOV DPH(0x83),?C_XBP(0x08)

C:0x26B7 850982 MOV DPL(0x82),OutTxBuf(0x09)

C:0x26BA E0 MOVX A,@DPTR

C:0x26BB 2F ADD A,R7

C:0x26BC FF MOV R7,A

88: } 

C:0x26BD 900002 MOV DPTR,#0x0002

C:0x26C0 020436 LJMP C?ADDXBP(C:0436)


From the assembly code, we can see that the function is placed at address 0x269B. Continue to observe the .m51 file (map file) generated by keil, search for add_two, and find the following related content:

(1) CODE 269BH 0028H UNIT ?PR?_?ADD_TWO?MAIN


(2) C:269BH PUBLIC _?add_two

(3) ------- PROC _?ADD_TWO

  x:0000H SYMBOL a1

  x:0001H SYMBOL a2

  C:269BH LINE# 85

  C:26ABH LINE# 87

  C:26BDH LINE# 88

------- ENDPROC _?ADD_TWO


From the above information, it is found that keil does three things in the process of compiling the add_two() function:


(1) A segment is declared for the add_two() function, starting at 269BH and with a size of 0028H. This segment contains only the code segment of the add_two function, and does not contain other functions or any data segments. The segment name is: ?PR?_?ADD_TWO?MAIN (the segment name consists of three parts: one is the fixed prefix ?PR?, the second is the uppercase ADD_TWO of the function name, and when Keil generates assembly for the function, it automatically adds the prefix _? to the function name of the reentrant function, and the third is the module name. The default module name is the file name where the function is located).


(2) Keil declares the "assembler function generated for add_two()" as PUBLIC so that other files can call the function. However, when declaring the function name, it adds the _? prefix: _?add_two. If an assembly file intends to call the add_two() function, it must be like this:


EXTRN CODE (_?add_two) ;Declare reference to external function (code): add_two()

LCALL _?add_two ; Call the C language function add_two() in assembly

According to Keil's naming convention,


Functions prefixed with _? are reentrant functions.


Additional information: The naming conventions for other types of functions are as follows:


Function without parameters: ?PR?function name?file name

Function with parameters: ?PR?_function name?file name

Reentrant function: ?PR?_?function name?file name


(3) This is the symbol table of the add_two() function, which indicates the storage location of the parameters and local variables in the add_two() function. So here is a question, why are a1 and a2 placed at addresses 00h and 01H? Aren't these two addresses registers R0 and R1? This involves the compilation rules of Keil. When the type and number of parameters are different, the method of passing parameters is different. There are special articles introducing where to put the parameters. Generally speaking, when there are fewer parameters and local variables, all of them are passed and stored in register Rn; when there are more parameters and local variables of non-reentrant functions, when Rn is not enough, the rest are stored in fixed memory addresses. When Rn is not enough for the parameters and local variables of reentrant functions, the rest are placed in the simulation stack.

Reference address:51 MCU UCOS II task switching assembly code analysis (1)

Previous article:51 MCU IO port expansion
Next article:Snake game based on 51 single chip microcomputer

Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号