2015-03-08 19:09:43 oCoreCode 阅读数 2147
  • 单片机有很多种-1.3.第1季第3部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第3个课程,主要讲了单片机的发展史,各种主流单片机的各自特点,STC51单片机的各系列的特点以及项目中如何选型主控单片机。

    2487 人正在学习 去看看 朱有鹏

“郭孟琦 + 原创作品转载请注明CSDN博客 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ”


在大学计算机组成原理一课中学习各种汇编语言跟C语言的关系,同时在单片机接口技术中也学习了C51的汇编语言,在一些MCU调试中也看到了反汇编的内容。但是从来没亲自实践一下C语言是怎么变成汇编的过程以及他们之间的对应关系。作为作业今天就在这里写下我的发现吧。


按照要求这是一段很简单的c语言程序


进行编译生成汇编文件

生成的main.s文件 已经把多余的命令删除了(gvim好像确实没vim好用。。。)


一开始是这样的 空栈

ebp!esp!
 
 
 
 

程序从main标签处运行,开始push,mov后(我用ebp!和esp!来表示实际的ebp esp所指向的位置吧,表示起来好麻烦 ebp(main)是指向0那个位置的ebp 就是表格最上边那个位置)

 
ebp!esp!ebp(main)
 
 
 
到了subl esp减4 向下移动一个字节 并且把立即数233存到了esp指向的位置(间接寻址?)

 
ebp!ebp(main)
esp! 233
 
 
当执行call f时 eip会被push

 
ebp!ebp(main)
 233
esp!eip(main)
 
接下来看f标签

在push 和movl后 ebp(f)是指向第二行那个ebp

 
ebp(main)
 233
eip(main)
esp!ebp!ebp(f)
 
同样esp在减4后向下移动1个地址

 
ebp(main)
 233
eip(main)
ebp!ebp(f)
esp!
 
接下来因为栈空间向下生长,变址寻址向上加8也就是向上2个位置(就是233)存入eax

接下来要把eax的内容存入esp指向的位置就成了

 
ebp(main)
 233
eip(main)
ebp!ebp(f)
esp!233
 
又一次的Call

 
ebp(main)
 233
eip(main)
ebp!ebp(f)
233
esp!eip(f)
进入g标签,前两句类似(其实就是存储原来ebp的位置将ebp指向新的位置),变址寻址向上加8也就是向上2个位置(就是233)存入eax

 
ebp(main)
 233
eip(main)
ebp(f)
233
eip(f)
ebp!esp!ebp(g)
 
然后666加上eax里的内容也就是c语言中的 “x +666”啦 到这里函数的嵌套总算是完事了开始一层层恢复,首先是popl ebp,ebp指向f 中的ebp位置了 同时 esp也会加4向上移动

 
ebp(main)
 233
eip(main)
ebp!ebp(f)
233
esp!eip(f)
ebp(g)
 
然后ret相当于 pop eip程序回到 刚才 eip(f)的那个位置啦

 
ebp(main)
 233
eip(main)
ebp!ebp(f)
esp!233
eip(f)
ebp(g)
 
leave实际上是

mov %ebp %esp   

pop %ebp

也就是将上一级的栈恢复回来(有个问题为什么在g里没有leave? 我认为popl %ebp就ok了 因为当时后序操作并未改变esp,esp和ebp指向同一位置 就没必要mov %ebp %esp 了可能就被优化掉了。)

要注意mov后pop操作又再一次改变了esp指向的位置

 
ebp!ebp(main)
 233
esp!eip(main)
ebp(f)
233
eip(f)
ebp(g)
 

我们继续走ret

 
ebp!ebp(main)
esp!233
eip(main)
ebp(f)
233
eip(f)
ebp(g)
 
别忘了结果一直在存着eax,现在再加1 就是c语言里 的f(233)+1

最后leave恢复之前的 ebp和esp

ebp!esp!
ebp(main)
233
eip(main)
ebp(f)
233
eip(f)
ebp(g)
 
 跟刚开始是不是一样了!


那么到现在为止,计算机是如何工作的?

我认为计算机的工作方式就是执行一系列指令,在其中当我们只用高级语言中的“函数调用”等需要跳转时计算机总会先保存现在的状态然后再处理完成后再依次恢复之前的状态,同时需要“带回去”的数据另存在其他地方比如:eax。此外我终于明白为什么C语言只能有一个返回值了。。。。

2018-12-04 16:39:46 cxd15194119481 阅读数 854
  • 单片机有很多种-1.3.第1季第3部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第3个课程,主要讲了单片机的发展史,各种主流单片机的各自特点,STC51单片机的各系列的特点以及项目中如何选型主控单片机。

    2487 人正在学习 去看看 朱有鹏

汇编语言中的“#”代表的是寻址方式为立即寻址
比如指令: MOV A,#21H
MOV意思是单片机片内RAM之间传送,该指令的意思是:将值21H送给寄存器A中暂存;
如果把**“#”去掉**,MOV A,21H该指令寻址方式变了,为直接寻址,21H就不是值了,而变成了一个地址,意思为:将21H这个地址里面中的内容送给寄存器A中暂存。
其中单片机中的寻址方式为7种方式,分别为:立即寻址,直接寻址,位寻址,寄存器寻址,寄存器间接寻址,变址寻址,相对寻址。

加了#就是发送立即数的意思。

2019-09-15 22:27:38 gy759656363 阅读数 102
  • 单片机有很多种-1.3.第1季第3部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第3个课程,主要讲了单片机的发展史,各种主流单片机的各自特点,STC51单片机的各系列的特点以及项目中如何选型主控单片机。

    2487 人正在学习 去看看 朱有鹏

写在前面

  就我所知,STM8的开发平台有两种:意法官方的STVD和IAR for STM8. STVD没尝试过。反正IAR用的感觉还凑合,各种该有的功能都有,但界面不怎么友好。估计是低版本的缘故,由于我长时间盯着屏幕眼睛酸痛,所以没办法只能把编辑界面底色改成黑色,可TM怎么行号编程白色的了?根本看不清。看不清就不看了呗,反正也没啥用。但是就是感觉超不爽。而且字体显示不知道怎么搞的,在缩放的时候就变得特别奇怪,跟手写的一样。

相关资料

  如之前所述,官方的永远是最好的,没有谁比创造者更了解他的产品了。
在这里插入图片描述

环境设置

  俗话说,站在巨人的肩膀上能看得更远。学习汇编也是一样,先看代码。但是由于汇编对于不同的芯片差异很大,网络上也很难找到资源。怎么办呢?最好的办法是去看看编译环境是怎么把c语言转换成汇编的。但是默认情况下,编译结果是不会自动跑到workspace的。所以需要作如下设置:
1. workspace右键选’options…'或单击Project菜单选择’options…'打开工程选项
2. 选择 ‘C/C++ Compiler’,在 ‘List’ 选项卡中选择 ‘Output assembler file’,并选择其子选项 'Include source’
  ‘Output assembler file’ 是为了让编译器输出汇编的编译结果,‘Include source’ 可以把对应的C语言标在每段汇编前,这样有助于理解每段汇编的含义。如果想看到全部汇编信息,请将 ‘Include all call frame information’ 勾选。
3. 还是在 ‘Options…’ => ‘C/C++ Compiler’ 中,选择 ‘Optimization’ 选项卡,优化等级选择 ‘Low’ 或 'None’
  选择优化等级的原因是,在高等级的优化中,C语言和汇编的对应关系不是特别明显,有的时候会把十几行代码一起优化掉,虽然结果相同,但是你很难去用自己写的时候的思路去理解生成的代码,而且有的时候会把你的代码逻辑彻底变掉。之前就遇到过这种情况,初始化的时候本来想用查表法去对参数赋初值,结果发现改Flash里面的数据根本不会影响运行结果。把汇编打开之后,发现居然把从Flash取值的指令直接优化成立即数寻址。唉,不得不感慨编译器不懂我啊。当然还有其他更好的办法解决,之后会讲到。
  完成以上设置之后,去编译你的工程,你会发现在每个c文件下多了个Output文件夹,点开后,里面有一个 ‘.s’ 文件,这个里面就是编译得到的汇编结果。 在这里插入图片描述
在这里插入图片描述

汇编语言结构

  做完上述设置之后,编译完打开 ‘.s’ 文件,你会看到如下格式的代码:

        RTMODEL "__SystemLibrary", "DLib"
        RTMODEL "__code_model", "small"
        RTMODEL "__core", "stm8"
        RTMODEL "__data_model", "medium"
        RTMODEL "__rt_version", "4"

        EXTERN ?b0
        EXTERN ?b1
        EXTERN ?w0
        EXTERN ?w1

        PUBLIC array
        PUBLIC main
        PUBLIC val
        
          CFI Names cfiNames0
          CFI StackFrame CFA SP DATA
          CFI Resource A:8, XL:8, XH:8, YL:8, YH:8, SP:16, CC:8, PC:24, PCL:8
          CFI Resource PCH:8, PCE:8, ?b0:8, ?b1:8, ?b2:8, ?b3:8, ?b4:8, ?b5:8
          CFI Resource ?b6:8, ?b7:8, ?b8:8, ?b9:8, ?b10:8, ?b11:8, ?b12:8, ?b13:8
          CFI Resource ?b14:8, ?b15:8
          CFI ResourceParts PC PCE, PCH, PCL
          CFI EndNames cfiNames0
        
          CFI Common cfiCommon0 Using cfiNames0
          CFI CodeAlign 1
          CFI DataAlign 1
          CFI ReturnAddress PC CODE
          CFI CFA SP+2
          CFI A Undefined
          CFI XL Undefined
          CFI XH Undefined
          CFI YL Undefined
          CFI YH Undefined
          CFI CC Undefined
          CFI PC Concat
          CFI PCL Frame(CFA, 0)
          CFI PCH Frame(CFA, -1)
          CFI PCE SameValue
          CFI ?b0 Undefined
          CFI ?b1 Undefined
          CFI ?b2 Undefined
          CFI ?b3 Undefined
          CFI ?b4 Undefined
          CFI ?b5 Undefined
          CFI ?b6 Undefined
          CFI ?b7 Undefined
          CFI ?b8 SameValue
          CFI ?b9 SameValue
          CFI ?b10 SameValue
          CFI ?b11 SameValue
          CFI ?b12 SameValue
          CFI ?b13 SameValue
          CFI ?b14 SameValue
          CFI ?b15 SameValue
          CFI EndCommon cfiCommon0
        
// E:\soc\example_empty\main.c
//    1 #include "Untitled1.h"
//    2 typedef enum {FALSE = 0, TRUE = !FALSE} bool;

        SECTION `.near.bss`:DATA:REORDER:NOROOT(0)
//    3 int val;
val:
        DS8 2

        SECTION `.near.data`:DATA:REORDER:NOROOT(0)
//    4 int array[10] = {1,33,2,6,8,9,4,45,8,0};
array:
        DC16 1, 33, 2, 6, 8, 9, 4, 45, 8, 0

        SECTION `.near_func.text`:CODE:REORDER:NOROOT(0)
          CFI Block cfiBlock0 Using cfiCommon0
          CFI Function main
        CODE
//    5 int main( void )
//    6 {
//    7   int i = 0;
main:
        CLR       S:?b1
        CLR       S:?b0
//    8   int buf;
//    9   bool flag = TRUE;
        LD        A, #0x1
        JRA       L:??main_0
//   10   while(1)
//   11   {
//   12     if(array[i] > array[i+1])
//   13     {
//   14       buf = array[i];
//   15       array[i] = array[i+1];
//   16       array[i+1] = buf;
//   17       flag = FALSE;
//   18     }
//   19     if(i == 9)
//   20     {
//   21       if(flag)
//   22       {
//   23         break;
//   24       }
//   25       i = 0;
??main_1:
        CLR       S:?b1
        CLR       S:?b0
??main_0:
        LDW       X, S:?w0
        SLLW      X
        ADDW      X, #array + 2
        LDW       X, (X)
        LDW       S:?w1, X
        LDW       X, S:?w0
        SLLW      X
        ADDW      X, #array
        LDW       Y, X
        LDW       X, S:?w1
        CPW       X, (Y)
        JRSGE     L:??main_2
        LDW       X, S:?w0
        SLLW      X
        LDW       X, (L:array,X)
        LDW       S:?w1, X
        LDW       X, S:?w0
        SLLW      X
        ADDW      X, #array + 2
        LDW       X, (X)
        LDW       Y, X
        LDW       X, S:?w0
        SLLW      X
        LDW       (L:array,X), Y
        LDW       X, S:?w0
        SLLW      X
        LDW       Y, S:?w1
        ADDW      X, #array + 2
        LDW       (X), Y
        SUBW      X, #array + 2
        CLR       A
??main_2:
        LDW       X, S:?w0
        CPW       X, #0x9
        JRNE      L:??main_0
        TNZ       A
        JREQ      L:??main_1
//   26     }
//   27 
//   28   }
//   29   return 0;
        CLRW      X
        RET
//   30 }
          CFI EndBlock cfiBlock0

        SECTION VREGS:DATA:REORDER:NOROOT(0)

        END
// 
//  2 bytes in section .near.bss
// 20 bytes in section .near.data
// 84 bytes in section .near_func.text
// 

  具体含义简单介绍一下:

1. 运行模型结构(Runtime model attributes)

  这类东西基本找不到官方的翻译,那就按字面上的意思咯。它主要是对程序整体的一些基础设置,一般要保持代码中所有汇编文件保持一致。在自己写汇编时可加可不加。如果要加的话一定要从同工程下别处原样复制过来,一个符号都不要改

        RTMODEL "__SystemLibrary", "DLib"		//基础库,包括C和C++所必需的头文件
        RTMODEL "__code_model", "small"			//代码量,代表寻址空间
        										//"small"  ->最大16KB寻址空间
        										//"medium" ->最大16MB寻址空间,但函数代码地址不允许超过64KB边界
        										//"large"  ->最大16MB寻址空间,函数代码地址允许超过64KB边界
        RTMODEL "__core", "stm8"				//芯片型号,只能是"stm8"
        RTMODEL "__data_model", "medium"		//详见帮助文档
        RTMODEL "__rt_version", "4"				//同个程序RTMODEL改变时,版本号相应改变

2. 标号声明(Symbol control)

  对一些本文件中涉及到的变量名或函数名(地址标号)进行声明,并表示该变量的作用域。

        EXTERN ?b0
        EXTERN ?b1
        EXTERN ?w0
        EXTERN ?w1

        PUBLIC array
        PUBLIC main
        PUBLIC val
指令 描述
EXTERN, IMPORT 声明该标号为外部标号
OVERLAY 可以识别该标号但是忽略它(不大理解)
PUBLIC 声明一个标号,可以被其他文件调用
PUBWEAK 标号可以被其他文件调用,可以被重定义
PEQUIRE 声明一个参考标号,如果一段代码对于某段程序的加载必不可少,但除此以外没什么用

  这部分很重要。如果你想要定义全局变量或引用外部变量,必须在此处声明。
  (a) 引用外部变量或函数,请在此处将相应标号声明为:EXTERN;
  (b) 定义全局变量或函数,请在此处将相应标号声明为:PUBLIC;

3. 标号定义(Call frame information directives)

  框架信息,内容较多.

          CFI Names cfiNames0
          //命名块定义(Define a names block)
          CFI StackFrame CFA SP DATA
          //将堆栈指针指向数据。
          //格式:CFI STACKFRAME cfa resource type
          //CFA     ->(Canonical Frame Address)堆栈指针基地址
          //resource->堆栈指针资源的名称
          //type    ->三类,CODE, CONST和DATA. 具体地址由ILINK编译器决定
          CFI Resource A:8, XL:8, XH:8, YL:8, YH:8, SP:16, CC:8, PC:24, PCL:8
          CFI Resource PCH:8, PCE:8, ?b0:8, ?b1:8, ?b2:8, ?b3:8, ?b4:8, ?b5:8
          CFI Resource ?b6:8, ?b7:8, ?b8:8, ?b9:8, ?b10:8, ?b11:8, ?b12:8, ?b13:8
          CFI Resource ?b14:8, ?b15:8
          //定义系统资源,其中?b0-?b15为虚拟通用寄存器
          CFI ResourceParts PC PCE, PCH, PCL
          //PC由三字节构成:(MSB->)PCE->PCH->PAL(->LSB)
          CFI EndNames cfiNames0
		  //结束命名块定义

          CFI Common cfiCommon0 Using cfiNames0
          //使用之前定义的cfiNames0资源定义共有资源cfiCommon0
          CFI CodeAlign 1
          //代码域数据对齐为8位,即字节对齐
          CFI DataAlign 1
          //数据域数据对齐为8位,即字节对齐
          CFI ReturnAddress PC CODE
          //返回值赋给PC,指向代码域
          CFI CFA SP+2
          //Canonical Frame Address,才疏学浅,找不到合适的汉语,反正就是一个地址,
          //这个地址是个相对于堆栈地址向上偏移2字节的地址,

          CFI A Undefined
          CFI XL Undefined
          CFI XH Undefined
          CFI YL Undefined
          CFI YH Undefined
          CFI CC Undefined
          //Undefined 将变量声明为临时变量,不需要重载
          CFI PC Concat
          //声明PC为拼接变量,上文定义Resource时,PC被定义为24位字长,则其包含之后的字长和为24的变量,
          //即PCL,PCH,PCE
          CFI PCL Frame(CFA, 0)
          CFI PCH Frame(CFA, -1)
          //由CFA指向的地址偏移x值后的地址内的值赋给操作数
          //如果SP指向0x0700,则CFA指向SP+2,即0x0702;由于STM8堆栈方式为向下生长,并指向空数据,
          //所以在该命名块(Name block)中,PCL初始化值为地址0x0702中的值,PCH为地址0x0703的值
          //可见,正好与函数调用返回(RET指令)后的效果一致
          //该语法在带有形参和返回值的汇编函数中很有用
          CFI PCE SameValue
          //不需要初始化,能够保证它的值是正确的(小段程序PCE用不到)
          CFI ?b0 Undefined
          CFI ?b1 Undefined
          //同上
		  ...
          CFI ?b15 SameValue
          //同上
          CFI EndCommon cfiCommon0
          //结束共有命名块的定义

4. 内存块分配及控制(Section control directives)

// E:\soc\example_empty\main.c
//    1 #include "Untitled1.h"
//    2 typedef enum {FALSE = 0, TRUE = !FALSE} bool;

        SECTION `.near.bss`:DATA:REORDER:NOROOT(0)
        //下方的数据块地址采用如上配置

内存块配置标记(Section configuration):

标记 描述 存储位置
,near.bss 初始值为0的静态或__near全局变量 RAM起始处
.near.data 含有初始值的静态或全局__near变量(初始值在.o中) RAM起始处
.near.data_init 为.near.data赋初值的__near常量 可在16MB寻址空间的任意位置,但所有量必须集中在64KB范围内
near.noinit 不含有初始值的__near静态或全局变量 RAM起始处
.near.rodata __near常量,可用于查表(数码管/LCD/CRC等等) 64KB ROM起始处

  REORDER表示用SECTION后的名称申请一个内存块,于此相对有NOREORDER,只是申请一个内存片段。
  ROOT防止编译器将其优化,NOROOT表示不用的时候此块区域可供给其他变量使用
  后面的参数表示字节对齐,对齐字节数为2n(n为括号内的值)一般不需要对齐,破八位机。
  上述涉及.icf文件的一些内容,之后可能会讲到…

//    3 int val;
val:
        DS8 2

  这里涉及一些数据类型的定义(Data Defination),和上面内存块(Section)定义相关联:

标号 别名 描述
DC8 DB 8位常量,可以是字符串(ROM)
DC16 DW 16位常量(ROM)
DC24 /
DC64 /
DF32 / 32位浮点数常量(ROM)
DF64 / 64位浮点数常量(ROM)
DQ15 / 16位小数常量(ROM)
DQ31 / 32位小数常量(ROM)
DS16 / 16位整形变量(RAM)
DS24 / 16位整形变量(RAM)
DS32 /
DS64 /

        SECTION `.near.data`:DATA:REORDER:NOROOT(0)
//    4 int array[10] = {1,33,2,6,8,9,4,45,8,0};
array:
        DC16 1, 33, 2, 6, 8, 9, 4, 45, 8, 0

  同上


        SECTION `.near_func.text`:CODE:REORDER:NOROOT(0)
          CFI Block cfiBlock0 Using cfiCommon0
          CFI Function main

  分配代码空间

特性关键字 标号 内存范围 指针大小 默认代码量(RTMODEL中定义) 描述
__near_func 0x0-0xFF FF 2字节 Small 前64KB空间,在Midium和Large中不允许使用
__far_func 0x0-0xFF FF FF 3字节 Medium 代码运行范围不可超过64KB,不允许在Small下定义
__huge_func 0x0-0xFF FF FF 3字节 Large 可以越过64KB空间,不允许在Small code下定义

5. 函数主体(Main body of function)

        CODE								//代码区声明
//    5 int main( void )
//    6 {
//    7   int i = 0;
main:										//函数入口声明,可以看做一个标号
        CLR       S:?b1
        CLR       S:?b0
//    8   int buf;
//    9   bool flag = TRUE;
        LD        A, #0x1
        JRA       L:??main_0
//   10   while(1)
//   11   {
//   12     if(array[i] > array[i+1])
//   13     {
//   14       buf = array[i];
//   15       array[i] = array[i+1];
//   16       array[i+1] = buf;
//   17       flag = FALSE;
//   18     }
//   19     if(i == 9)
//   20     {
//   21       if(flag)
//   22       {
//   23         break;
//   24       }
//   25       i = 0;
??main_1:
        CLR       S:?b1
        CLR       S:?b0
??main_0:
        LDW       X, S:?w0
        SLLW      X
        ADDW      X, #array + 2
        LDW       X, (X)
        LDW       S:?w1, X
        LDW       X, S:?w0
        SLLW      X
        ADDW      X, #array
        LDW       Y, X
        LDW       X, S:?w1
        CPW       X, (Y)
        JRSGE     L:??main_2
        LDW       X, S:?w0
        SLLW      X
        LDW       X, (L:array,X)
        LDW       S:?w1, X
        LDW       X, S:?w0
        SLLW      X
        ADDW      X, #array + 2
        LDW       X, (X)
        LDW       Y, X
        LDW       X, S:?w0
        SLLW      X
        LDW       (L:array,X), Y
        LDW       X, S:?w0
        SLLW      X
        LDW       Y, S:?w1
        ADDW      X, #array + 2
        LDW       (X), Y
        SUBW      X, #array + 2
        CLR       A
??main_2:
        LDW       X, S:?w0
        CPW       X, #0x9
        JRNE      L:??main_0
        TNZ       A
        JREQ      L:??main_1
//   26     }
//   27 
//   28   }
//   29   return 0;
        CLRW      X
        RET
//   30 }
          CFI EndBlock cfiBlock0

        SECTION VREGS:DATA:REORDER:NOROOT(0)

        END

链接器配置文件(linker configuration file)

  下图为.icf中涉及到的几个概念之间的关系。存储区域(Region)把整个存储地址空间划分为若干个部分:Tinydata, NearFuncCode… 这些部分中存储着各种各样的数据,这些数据可以为Section或Block.其中两者的区别,我觉得,Section是表明一些用户自定义的变量存放区域,而Section是系统资源的数据块,比如说向量、堆栈区域。

Section
Section
block
Region
Memory
.far.rodata
FarFuncCode
.far_func.text
.huge.rodata
HugeFuncCode
.huge_func.text
.eeprom.noinit
Eeprom
.eeprom.data
.eeprom.rodata
.vregs
TinyData
.tiny.bss
.tiny.data
.tiny.noinit
.tiny.rodata
.far.data_init
NearFuncCode
.far_func.textrw_init
INTVEC
CSTACK
NearData
HEAP
Address
BootROM

  如果我们想自定义一些数据,并将数据存放到指定地址,那么我们就需要修改.icf文件。对于新建的一个工程来说,它的.icf文件地址默认在IAR安装文件中,那么我们如果想要修改,不要去在默认文件修改,因为这玩意就这一份,改错了就不好恢复原样了。所以我们可以先设置一下cfi文件路径,然后把默认icf文件复制到设置的路径下。设置方法如下:
 (1) 在workspace中右击选Options…
 (2) 依次选择Linker->Config,在其中勾选Override Default,然后选择路径。我设置的是:
$PROJ_DIR$\config\lnkstm8l152c6.icf. 其中$PROJ_DIR$的含义是工程目录下的路径。
 (3) 将默认目录下的.icf文件复制到选择的文件夹下,把文件的权限修改一下,使其可以编辑,然后编译工程,出现在Output->project.out下的.icf就是了在这里插入图片描述
  下面介绍几种设置的语法:
(1) 设置Region
  define region TinyData = [from 0x00 to 0xFF];
  定义TinyData为0x00-0xFF地址范围内的Region名称。
(2) 设置Section
  place at start of TinyData { rw section .vregs };
  在区域TinyData的起始位置放置名为.vreg的Section。
2019-09-15

2012-04-12 18:40:06 liujianli123 阅读数 6809
  • 单片机有很多种-1.3.第1季第3部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第3个课程,主要讲了单片机的发展史,各种主流单片机的各自特点,STC51单片机的各系列的特点以及项目中如何选型主控单片机。

    2487 人正在学习 去看看 朱有鹏

1.汇编语言中

对于51单片来说:

   1.1 逻辑左移指令

         RLA:将A中的值逻辑左移,将A中最高位D7位移动到最低位D0位,D0位送到D1位,例如A为00111001B,执行RL A指令之后,A变成0111 0010

         RLCA:将A中的值加上进位(CY)进行逻辑左移,将CY的值送到D0位,然后再把D7的值送给CY,例如A为00111001B,CY=1为,执行RLC A指令之后,A变成0111 0011,CY=0

   1.2逻辑右移指令

         RRA:将A中的值逻辑右移,例子省略

         RRCA:将A中的值加上进位(CY)进行逻辑右移,例子省略

2.C51中:

 对于51单片机:

         2.1 m<<n:左移指令,共移位n次,每执行一次,操作数最高位D7移入CY,CY中本来的数丢失,最低位D0补0,其他位依次向左移动1位。

       例如m为0011 1001B,n为1,CY=1,执行m<<n之后,A变成0111 0010,CY=0

         2.2 m>>n:   右移指令,跟左移相似。

     

2016-01-25 12:03:03 baidu_33836580 阅读数 904
  • 单片机有很多种-1.3.第1季第3部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第3个课程,主要讲了单片机的发展史,各种主流单片机的各自特点,STC51单片机的各系列的特点以及项目中如何选型主控单片机。

    2487 人正在学习 去看看 朱有鹏

;

;有个题目,要求把 C 语言的程序,改成汇编的,链接如下:

;

;http://zhidao.baidu.com/question/561427047

;

;看他原来的程序,是驱动 8*8 LED 点阵显示字符的。

;

;根据程序,做而论道画出了点阵驱动电路,运行C程序后显示如下所示:

;

51 汇编编程:8×8 点阵驱动 - 非著名博主 - 电子信息角落

;

;LED 所显示的全部字符都在下面给出了,有些字符的图形,还是很有创造力的,呵呵

;

;图片链接:http://xiangce.baidu.com/picture/detail/3b752a17543a58b5727ea8a790d10f05767d8833

;

;做而论道写出了功能相同的汇编程序,全部代码如下:


;8 * 8 LED 点阵


    ORG   0000H

    JMP   START

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

RED:

    DB  0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x18;//i

    DB  0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0xFC,0xFC;//l

    DB  0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x3C;//o

    DB  0x00,0x00,0x44,0x44,0x44,0x44,0x28,0x10;//v

    DB  0x00,0x3E,0x02,0x02,0x3E,0x02,0x02,0x3E;//e

    DB  0x81,0xA5,0xDB,0xC3,0xA5,0x99,0x81,0xFF;//u

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

START:

    MOV   DPTR, #RED

    MOV   R2, #254

LP0:MOV   R3, #0

LP1:MOV   R5, #100

LP2:MOV   R4, #0

LP3:MOV   A, R3

    ADD   A, R4

    CALL  DISP

    INC   R4

    CJNE  R4, #8, LP3

    DJNZ  R5, LP2

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

    MOV   A, R3

    ADD   A, #8

    MOV   R3, A

    CJNE  R3, #48, LP1

    SJMP  LP0

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

DISP:

    MOVC  A, @A + DPTR

    MOV   P2, A

    MOV   P0, R2

    MOV   A, R2

    RL    A

    MOV   R2, A

    DJNZ  R7, $

    DJNZ  R7, $

    MOV   P2, #0

    RET

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

END


;做而论道把汇编程序提交后,却出现下面的提示:

;

;>_<!! 您的回答可能违反了知道内容规范,暂时仅您自己可见。可发起申诉找回。

;

;这种事情,出现过多次,申诉后,也没有什么结果的。

;

;呵呵,百度知道的某些网管,判断能力、水平,真难以用语言描述。

;

;

;本题目给出的 C 程序如下:


#include <reg52.h>

#define uchar  unsigned char

#define uint   unsigned int

uchar code  RED[] = {

    0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x18,//i

    0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0xFC,0xFC,//l

    0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,//o

    0x00,0x00,0x44,0x44,0x44,0x44,0x28,0x10,//v

    0x00,0x3E,0x02,0x02,0x3E,0x02,0x02,0x3E,//e

    0x81,0xA5,0xDB,0xC3,0xA5,0x99,0x81,0xFF //u

    };


void delay(uint t)

{

    for(; t > 0; t--);

}


void main()

{

    uchar r, j, q = 0, t = 0;

    while(1)  {

      for(r = 0; r < 40; r++) {

        for(j = q; j < q + 8; j++) {

          P0 = (~(0x01 << t));

          P2 = RED[j]; delay(200); P2 = 0;

          t++;  t %= 8;

        }

      }

      q += 8;  q %= 48;

    }

}


大家可以试试,两种程序的功能,是否相同。


有位网友,利用反汇编 C 语言的方法,得出了汇编语言程序,程序长得多且不说,而且还编译不成功。

没有更多推荐了,返回首页