STM8S assembly code analysis

Publisher:快乐飞翔Latest update time:2020-09-22 Source: eefocusKeywords:STM8S Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

Write the picture description here

 
Among them, .asm file is the source file of assembly code, and .inc file is the include file, which is similar to .c file and .h file in C language. Next, let's analyze these three files. (It is best to understand the startup process of STM8 microcontroller when analyzing assembly code. You can read my other blog post http://blog.csdn.net/u010093140/article/details/49982879)
First, look at the mapping.inc file:


;------------------------------------------------------

; SEGMENT MAPPING FILE AUTOMATICALLY GENERATED BY STVD

; SHOULD NOT BE MANUALLY MODIFIED.

; CHANGES WILL BE LOST WHEN FILE IS REGENERATED.

;------------------------------------------------------

#define RAM0 1

#define ram0_segment_start 0

#define ram0_segment_end FF

#define RAM1 1

#define ram1_segment_start 100

#define ram1_segment_end 5FF

#define stack_segment_start 600

#define stack_segment_end 7FF


This code should not be difficult to understand, it just defines some constants. It should be noted that the semicolon ";" is the symbol used to write comments in assembly code. So the semicolon is followed by a comment. 

Next, let's take a look at the mapping.asm file



stm8/

    ;------------------------------------------------------

    ; SEGMENT MAPPING FILE AUTOMATICALLY GENERATED BY STVD

    ; SHOULD NOT BE MANUALLY MODIFIED.

    ; CHANGES WILL BE LOST WHEN FILE IS REGENERATED.

    ;------------------------------------------------------

    #include "mapping.inc"


    BYTES           ; The following addresses are 8 bits long

    segment byte at ram0_segment_start-ram0_segment_end 'ram0'


    WORDS           ; The following addresses are 16 bits long

    segment byte at ram1_segment_start-ram1_segment_end 'ram1'


    WORDS           ; The following addresses are 16 bits long

    segment byte at stack_segment_start-stack_segment_end 'stack'


    WORDS           ; The following addresses are 16 bits long

    segment byte at 4000-43FF 'eeprom'


    WORDS           ; The following addresses are 16 bits long

    segment byte at 8080-FFFF 'rom'


    WORDS           ; The following addresses are 16 bits long

    segment byte at 8000-807F 'vectit'


        END


The first line of the code above starts with stm8/. Many people don't know why it is like this. In fact, it is because the Assembler Linker we use not only supports STM8 assembly code but also supports the assembly code of another chip ST7 of ST company. If you use ST7 chip, it should start with st7/. The conclusion is that using stm8/ to indicate that the target chip of the code is stm8 chip.

The comments after the semicolon are not counted in the code. The remaining code defines the memory segments on the chip. For example, segment byte at ram0_segment_start-ram0_segment_end 'ram0' means that the memory segment from ram0_segment_start to ram0_segment_end is named "ram0", segment byte at ram1_segment_start-ram1_segment_end 'ram1' means that the memory segment from ram1_segment_start to ram1_segment_end is named "ram1", and the same is true for the others. Then, you will also notice that there is a sentence "Bytes" or "Words" before each such code. What does this mean? According to the meaning in the code comments, Bytes means that the address of the memory in the memory segment is 8 bits, and Words means that the address of the memory in the memory segment is 16 bits. By checking the Assembler Linker PDF, I found that Bytes and Words are used to specify the default length of the label following it. What does it mean? You can see the following example:


   Bytes

label1 

; The following statement is compiled successfully because A is 8 bits and label1 is also 8 bits.

   LD A,#label1  

   Words

 label2

 ;The following statement will not compile because A is 8 bits and label2 is 16 bits, so it is assigned to A.

   LD A,#label2  

   Words

 label3.b

 ; The following statement can be compiled because I explicitly specified label3 as byte length (.b), which is 8 bits.


Let's look back at the mapping.asm file. All the instructions in the mapping file are pseudo-instructions and do not generate actual executable code. So what is the role of bytes and words? From the above description of the role of bytes and words, I personally think that they do not work in mapping.asm, and only serve as an explanation, which is equivalent to comments. Of course, if there are any errors, you are welcome to point them out^_^. So the role of mapping is to divide the chip's storage space into areas and name them. The code we write later can be stored in the storage area represented by this name. For example, ram0 area, ram1 area, rom area, etc. 

Next, let’s look at main.asm. This code is a bit long, so let’s paste it first.



;As mentioned before, stm8 indicates that the following code is for stm8 chip, not st7 chip.

stm8/

;The following code means including the mapping.inc file, so that the constants defined in mapping.inc can be used directly.

    #include "mapping.inc"

;The following code indicates that all subsequent codes are placed in the ROM storage area. As indicated in mapping.asm, the address range of ROM is 8080-FFFF.

    segment 'rom'

;main.l is a label, written on the leftmost line, and the label does not generate actual instructions. The role of the label is to name an address, and then other instructions can use this name to use this address. For example, the address of the following main.l is equal to the address of the following ldw X,#stack_end. And .l means that the address is 3 bytes 24 bits.

main.l

    ; initialize SP

    ; The following sentence means to load the value of stack_end into the X register. # means immediate value. The w in ldw means word, indicating that it is a 16-bit load instruction. There is also an 8-bit load instruction, ld.

    ldw X,#stack_end

    ;The following sentence means to assign the value of register X to the SP register. SP is the stack pointer. The function of the above and below sentences is to make SP point to the top of the stack. (The stack structure of STM8 is from top to bottom. The value at the top of the stack is stack_end, the number with the largest address value in the stack).

    ldw SP,X

    ; Pseudo-instruction, if RAM0 is defined, then compile the following code. Obviously, this judgment is true, because RAM0 and RAM1 have been defined in mapping.inc.

    #ifdef RAM0 

    ; clear RAM0

; Pseudo instruction, define the value of label ram0_start.b as the value of ram0_segment_start, $ means hexadecimal number, and the same is true for ram0_end.b. This direct assignment method is different from the previous main.l label. The following one assigns an absolute address, while main.l assigns a relative address.

ram0_start.b EQU $ram0_segment_start

ram0_end.b EQU $ram0_segment_end

    ; Load the value of ram0_start to X

    ldw X,#ram0_start

; define label clear_ram0.l

clear_ram0.l

        ;clr means clear, () means indirect addressing, and clr(X) means taking the value of X as the address and clearing the value at that address.

    clr (X)

    ;X plus 1, incw has a w because X is 16 bits.

    incw X

    ;cpw means compare, comparing the values ​​of X and ram0_end, and the meaning of w is the same as mentioned above.

    cpw X,#ram0_end 

    ; Do you understand the meaning of jrule (jump relative unsigned less than)? It means that if it is less than, jump to the address marked with clear_ram0.

    jrule clear_ram0

    ; Corresponds to the previous #ifdef RAM0.

    #endif

    ;The operation of RAM1 in this section is the same as the operation of RAM0 above. The function of this whole section of code is to clear the storage area.

    #ifdef RAM1

    ; clear RAM1

ram1_start.w EQU $ram1_segment_start

ram1_end.w EQU $ram1_segment_end   

    ldw X,#ram1_start

clear_ram1.l

    clr (X)

    incw X

    cpw X,#ram1_end 

    jrule clear_ram1

    #endif

    ;The following operation of initializing the stack area is the same as the previous operation on RAM0.

    ; clear stack

stack_start.w EQU $stack_segment_start

stack_end.w EQU $stack_segment_end

    ldw X,#stack_start

clear_stack.l

    clr (X)

    incw X

    cpw X,#stack_end    

    jrule clear_stack

;The infinite_loop.l label is defined below.

infinite_loop.l

    ;jra means relative jump, jump to the label above. So this is an infinite loop. The code here is to continuously execute the statement jra infinite_loop, which is equivalent to while(1) in C language;

    jra infinite_loop

    ;interrupt is a pseudo-instruction, which describes NoHandleInterrupt as a label for interruption.

    interrupt NonHandledInterrupt

;Define the NonHandledInterrupt.l label

NonHandledInterrupt.l

    ;iret means interrupt return, and ret means function return.

    would go

; The code below the segment 'vectic' instruction is placed in the vectit storage area, which is the area where 8000-807F is located.

    segment 'vectit'

    ;dc.l means to apply for a 4-byte space, and the number added after it is the value assigned to this space. What? The previous usage of l is 3 bytes, but here the l in dc.l becomes 4 bytes? Yes, it is like this, a bit messy, and this is also a bit confusing. I don’t understand why it is not changed to another statement. The usage of {} is to calculate the statements in it during compilation, not in the code. For example, {1+1} will become 2 after compilation.

    ;All the dc.l below actually define an interrupt vector table, corresponding to different interrupts. For example, the first one is the reset interrupt. After the chip is reset, the main label will be found here, and then the program will jump to main. Of course, if you are not satisfied with main, you can also change it to something else, such as example. But after this change, the main.l label at the front should also be changed to example.l. It is equivalent to "no" main function in this program. Isn't it amazing? Uh. There are comments about trap, irq0, irq2, etc. below, which actually correspond to different interrupts. For example, the I2C interrupt corresponds to irq19, so when you have written the I2C interrupt service program, you need to fill in its label in the irq19 sentence. You can refer to the sentence dc.l{$82000000+main}. If you define the label of the I2C interrupt service program as I2C_Interrupt.l, then the sentence in irq19 should be changed to dc.l{$82000000+I2C_Interrupt}. The last question is that after the interrupt, the microcontroller will jump to the interrupt label to execute, which is no problem. What does the 82 in $82000000 mean? (I can't find the information I saw before... but I still remember the meaning) 82 is an opcode in the STM8 instruction set (assembly instructions are composed of opcodes and operands). I think the meaning of using it here for interrupts is that the surface address label is the address label of the interrupt service program. The chip can recognize the opcode 82 and treat it differently.

[1] [2]
Keywords:STM8S Reference address:STM8S assembly code analysis

Previous article:Development Tools: IAR Download, Installation and Activation
Next article:Floating point number conversion to string function

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号