Chinaunix首页 | 论坛 | 博客
  • 博客访问: 459147
  • 博文数量: 107
  • 博客积分: 6073
  • 博客等级: 准将
  • 技术积分: 790
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-14 15:34
文章分类

全部博文(107)

文章存档

2010年(1)

2009年(106)

分类: C/C++

2009-09-16 13:46:46

作者:wangxinus,
来源:
http://wangxinus.cublog.cn
说明:转载请注明来源,交流请Email给作者

这是一段单片机的汇编程序, 它并不是像平时写代码那样,在IDE中写成的。这段代码(一万行以上)由另外一个程序生成, 但是我们需要把编译成二进制的指令码,这样单片机才能执行。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;汇编程序片段
    MOVI20        #h'4a,         R0
    MOV.W        @(R0, R13),        R6
    MOVI20        #h'800,         R7
    OR        R7,        R6
    MOV.W        R6,        @(R0, R13)
?L3:
    MOVI20        #h'14,         R0
    MOV.W        @(R0, R14),        R6
    MOVI20        #h'1,         R7
    TST            R7,        R6
    BF    ?L3_0
    MOVI20        #h'44,         R0
    MOV.W        @(R0, R14),        R6
    MOVI20        #h'8000,         R7
    TST            R7,        R6
    BF    ?L3_0
    MOVI20        #h'44,         R0
    MOV.W        @(R0, R14),        R6
    MOVI20        #h'4000,         R7
    TST            R7,        R6
    BT    ?L4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

在芯片的DataSheet中可以查到每个指令的二进制代码。
例如:
ADD Rm, Rn 0011nnnnmmmm1100 Rn+Rm→Rn
在解析汇编源文件时, 把每条语句做相应的字符串处理, 即可填充出指令码。

存在几个难点:
一是,跳转指令。跳转指令以label来书写,但是分析的时候必须确定出当前指令于跳转目标指令间的偏移大小。
二是,32位指令。大部分的指令都是16位的(该单片机), 但有部分指令是32位的,相当于会编译出2条16位的指令,这会影响到label的定位。
三是,优化指令。汇编还能优化?的确!因为这里的汇编不是人为编写的,是自动生成的。跳转指令有距离限制,当生成的跳转指令已经不能到达目标位置是,需要把它改成长跳转,这需要多加几条指令,而这又会影响到label的定位。


步骤:
1。读入源代码, 删除注释。
2。分离出每一语句存入list中,所有语句顺序存储list>。
3。把所有的label的位置都找出来,放入map中。检查跳转指令,不符合要求的添加指令,然后再生成map,如此递归直至达到要求。
4。根据datasheet中的指令,翻译出二进制指令码, 顺序写入一个二进制文件。

记录1:
语句:MOVI20        #h'4a,         R0
不能使用stringstream,它会在','出分割字符串,@(R0, R14)会变成2个字符串。只能自己手写一个字符串的处理函数,分离出每条语句的有效字符串部分。 用到的函数有:
#include
int isgraph( int ch );
功能:如果参数是除空格外的可打印字符(可见的字符),函数返回非零值,否则返回零值。
list statement; //用来存储一条语句
statement.push_back("MOVI20");
statement.push_back("#h'4a");
statement.push_back("R0");

记录2:
由于指令码的填充涉及到很多位操作, 单单定义一个uint16_t类型数据并方便,所以可以采用STL提供的bitset;
#include
typedef bitset<16> opcode;

记录3:
ADD Rm, Rn 0011nnnnmmmm1100 Rn+Rm→Rn
获取m,n的值。
int m,n,ret;
ret = sscanf(string, "R%d,R%d", &m, &n); //string="R1,R2"
if(ret == 2)
    //获取值成功
else
    //获取值失败

使用"%X"可以取得16进制数据。 FF -> 255;

记录4:
一个指令比如ADD,往往有几个用法。
ADD Rm, Rn   0011nnnnmmmm1100  //两个寄存器
ADD #imm, Rn 0111nnnniiiiiiii  //使用立即数
可以根据记录3,做如下处理。

int m, n, i, ret;
if((ret=sscanf(string, "R%d,R%d", &m, &n)) == 2)
{
    //使用的寄存器
}
else if((ret=sscanf(string, "#%d,R%d", &i, &n)) == 2)
{
    //使用的立即数
}
else
{
    //错误的语句,或者没有实现的方式
}
阅读(3526) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~