在STC论坛上看到有人用C++语言实现8051汇编编译器(源码),好奇下,试着用FB写了一下。
基本原理就是通过分析汇编文件然后转换为机器码。以下是51汇编与机器码对应的表格(数据来自网络,如果发现有误请联系QQ1493446087修正。)。
助记符 | 说明 | 字节 | 周期 | 机器码 | 二进制机器码 | 参数1 | 参数2 | 说明 |
NOP | 空操作 | 1 | 1 | 00 | 0000 0000 | / | / | |
ACALL addr 11 | 绝对子程序调用 | 2 | 2 | ***0 0001 | a10a9a80 0001 | a7a6a5a4 a3a2a1a0 | / | |
LJMP addr 16 | 长转移 | 3 | 2 | 02 | 0000 0010 | a15a14a13a12 a11a10a9a8 | a7a6a5a4 a3a2a1a0 | |
RR A | A右移一位 | 1 | 1 | 03 | 0000 0011 | / | / | |
INC A | A加1 | 1 | 1 | 04 | 0000 0100 | / | / | |
INC data | 直接字节加1 | 2 | 1 | 05 | 0000 0101 | 直接地址 | / | |
INC @Ri | 间接RAM加1 | 1 | 1 | 06 - 07 | 0000 011i | / | / | i = 0,1 |
INC Rn | 寄存器加1 | 1 | 1 | 08 - 0F | 0000 1rrr | / | / | r = 0 - 7 |
JBC bit,rel | 若直接位==1则转移且清除 | 3 | 2 | 10 | 0001 0000 | 位地址 | 相对地址 rel | rel = 标签地址 - 当前地址的下一个地址 |
AJMP addr 11 | 绝对转移 | 2 | 2 | ***1 0001 | a10a9a81 0001 | a7a6a5a4 a3a2a1a0 | / | |
LCALL addr 16 | 子程序调用 | 3 | 2 | 12 | 0001 0010 | a15a14a13a12 a11a10a9a8 | a7a6a5a4 a3a2a1a0 | |
RRC A | A带进位右移一位 | 1 | 1 | 13 | 0001 0011 | / | / | |
DEC A | A减1 | 1 | 1 | 14 | 0001 0100 | / | / | |
DEC data | 直接字节减1 | 2 | 1 | 15 | 0001 0101 | 直接地址 | / | |
DEC @Ri | 间接RAM减1 | 1 | 1 | 16 - 17 | 0001 011i | / | / | i = 0,1 |
DEC Rn | 寄存器减1 | 1 | 1 | 18 - 1F | 0001 1rrr | / | / | r = 0 - 7 |
JB bit,rel | 若直接位==1则转移 | 3 | 2 | 20 | 0010 0000 | 位地址 | 相对地址 rel | |
RET | 子程序调用返回 | 1 | 2 | 22 | 0010 0010 | / | / | |
RL A | A循环左移一位 | 1 | 1 | 23 | 0010 0011 | / | / | |
ADD A,#data | 立即数加到A | 2 | 1 | 24 | 0010 0100 | 立即数 | / | |
ADD A,data | 直接字节加到A | 2 | 1 | 25 | 0010 0101 | 直接地址 | / | |
ADD A,@Ri | 间接RAM加到A | 1 | 1 | 26 - 27 | 0010 011i | / | / | i = 0,1 |
ADD A,Rn | 寄存器加到A | 1 | 1 | 28 - 2F | 0010 1rrr | / | / | r = 0 - 7 |
JNB bit,rel | 若直接位==0则转移 | 3 | 2 | 30 | 0011 0000 | 位地址 | 相对地址 rel | |
RETI | 中断程序调用返回 | 1 | 2 | 32 | 0011 0010 | / | / | |
RLC A | A带进位左移一位 | 1 | 1 | 33 | 0011 0011 | / | / | |
ADDC A,#data | 立即数带进位加到A | 2 | 1 | 34 | 0011 0100 | 立即数 | / | |
ADDC A,data | 直接字节带进位加到A | 2 | 1 | 35 | 0011 0101 | 直接地址 | / | |
ADDC A,@Ri | 间接RAM带进位加到A | 1 | 1 | 36 - 37 | 0011 011i | / | / | i = 0,1 |
ADDC A,Rn | 寄存器带进位加到A | 1 | 1 | 38 - 3F | 0011 1rrr | / | / | r = 0 - 7 |
JC rel | 若C==1则转移 | 2 | 2 | 40 | 0100 0000 | 相对地址 rel | / | |
ORL data,A | A或到直接字节 | 2 | 1 | 42 | 0100 0010 | 直接地址 | ||
ORL data,#data | 立即数或到直接字节 | 3 | 2 | 43 | 0100 0011 | 直接地址 | 立即数 | |
ORL A,#data | 立即数或到A | 2 | 1 | 44 | 0100 0100 | 立即数 | / | |
ORL A,data | 直接字节或到A | 2 | 1 | 45 | 0100 0101 | 直接地址 | / | |
ORL A,@Ri | 间接RAM或到A | 1 | 1 | 46 - 47 | 0100 011i | / | / | i = 0,1 |
ORL A,Rn | 寄存器或到A | 1 | 1 | 48 - 4F | 0100 1rrr | / | / | r = 0 - 7 |
JNC rel | 若C≠1则转移 | 2 | 2 | 50 | 0101 0000 | 相对地址 rel | / | |
ANL data,A | A与到直接字节 | 2 | 1 | 52 | 0101 0010 | 直接地址 | / | |
ANL data,#data | 立即数与到直接字节 | 3 | 2 | 53 | 0101 0011 | 直接地址 | 立即数 | |
ANL A,#data | 立即数与到A | 2 | 1 | 54 | 0101 0100 | 立即数 | / | |
ANL A,data | 直接字节与到A | 2 | 1 | 55 | 0101 0101 | 直接地址 | / | |
ANL A,@Ri | 间接RAM与到A | 1 | 1 | 56 - 57 | 0101 011i | / | / | i = 0,1 |
ANL A,Rn | 寄存器与到A | 1 | 1 | 58 - 5F | 0101 1rrr | / | / | r = 0 - 7 |
JZ rel | 若A==0则转移 | 2 | 2 | 60 | 0110 0000 | 相对地址 rel | / | |
XRL data,A | A异或到直接字节 | 2 | 1 | 62 | 0110 0010 | 直接地址 | / | |
XRL data,#data | 立即数异或到直接字节 | 3 | 2 | 63 | 0110 0011 | 直接地址 | 立即数 | |
XRL A,#data | 立即数异或到A | 2 | 1 | 64 | 0110 0100 | 立即数 | / | |
XRL A,data | 直接字节异或到A | 2 | 1 | 65 | 0110 0101 | 直接地址 | / | |
XRL A,@Ri | 间接RAM异或到A | 1 | 1 | 66 - 67 | 0110 011i | / | / | i = 0,1 |
XRL A,Rn | 寄存器异或到A | 1 | 1 | 68 - 6F | 0110 1rrr | / | / | r = 0 - 7 |
JNZ rel | 若A≠0则转移 | 2 | 2 | 70 | 0111 0000 | 相对地址 rel | / | |
ORL C,bit | 直接位或到进位位 | 2 | 2 | 72 | 0111 0010 | 位地址 | / | |
JMP @A+DPTR | 相对于DPTR间接转移 | 1 | 2 | 73 | 0111 0011 | / | / | |
MOV A,#data | 立即数送A | 2 | 1 | 74 | 0111 0100 | 立即数 | / | |
MOV data,#data | 立即数送直接字节 | 3 | 2 | 75 | 0111 0101 | 直接地址 | 立即数 | |
MOV @Ri,#data | 立即数送间接Rn | 2 | 2 | 76 - 77 | 0111 011i | 立即数 | / | i = 0,1 |
MOV Rn,#data | 立即数送寄存器 | 2 | 1 | 78 - 7F | 0111 1rrr | 立即数 | / | r = 0 - 7 |
SJMP rel / JMP rel | 短转移 | 2 | 2 | 80 | 1000 0000 | 相对地址 rel | / | |
ANL C,bit | 直接位与到进位位 | 2 | 2 | 82 | 1000 0010 | 位地址 | / | |
MOVC A,@A+PC | A+PC寻址程序存贮字节送A | 1 | 2 | 83 | 1000 0011 | / | / | |
DIV AB | A除B | 1 | 4 | 84 | 1000 0100 | / | / | |
MOV data,data | 直接字节送直接字节 | 3 | 2 | 85 | 1000 0101 | 直接地址 | / | |
MOV data,@Ri | 间接Rn送直接字节 | 2 | 2 | 86 - 87 | 1000 011i | 直接地址 | / | i = 0,1 |
MOV data,Rn | 寄存器送直接字节 | 2 | 1 | 88 - 8F | 1000 1rrr | 直接地址 | / | r = 0 - 7 |
MOV DPTR,#data16 | 16位常数送数据指针 | 3 | 1 | 90 | 1001 0000 | 高立即数 | 底立即数 | |
MOV bit,C | 进位位送直接位 | 2 | 2 | 92 | 1001 0010 | 位地址 | / | |
MOVC A,@A+DPTR | A+DPTR寻址程序存贮字节送A | 1 | 2 | 93 | 1001 0011 | / | / | |
SUBB A,#data | 从A中减去立即数和进位 | 2 | 1 | 94 | 1001 0100 | 立即数 | / | |
SUBB A,data | 从A中减去直接字节和进位 | 2 | 1 | 95 | 1001 0101 | 直接地址 | / | |
SUBB A,@Ri | 从A中减去间接RAM和进位 | 1 | 1 | 96 - 97 | 1001 011i | / | / | i = 0,1 |
SUBB A,Rn | 从A中减去寄存器和进位 | 1 | 1 | 98 - 9F | 1001 1rrr | / | / | r = 0 - 7 |
ORL C,/bit | 直接位的反码或到进位位 | 2 | 2 | A0 | 1010 0000 | 位地址 | / | |
MOV C,bit | 直接位送进位位 | 2 | 1 | A2 | 1010 0010 | 位地址 | / | |
INC DPTR | 数据指针加1 | 1 | 2 | A3 | 1010 0011 | / | / | |
MUL AB | A乘B | 1 | 4 | A4 | 1010 0100 | / | / | |
MOV @Ri,data | 直接字节送间接Rn | 1 | 1 | A6 - A7 | 1010 011i | / | / | i = 0,1 |
MOV Rn,data | 直接数送寄存器 | 2 | 2 | A8 - AF | 1010 1rrr | 直接地址 | / | r = 0 - 7 |
ANL C,/bit | 直接位的反码与到进位位 | 2 | 2 | B0 | 1011 0000 | 位地址 | / | |
CPL bit | 直接位取反 | 2 | 1 | B2 | 1011 0010 | 位地址 | / | |
CPL C | 进位位取反 | 1 | 1 | B3 | 1011 0011 | / | / | |
CJNE A,#data,rel | 立即数与A比较,不等转移 | 3 | 2 | B4 | 1011 0100 | 立即数 | 相对地址 rel | |
CJNE A,data,rel | 直接数与A比较,不等转移 | 3 | 2 | B5 | 1011 0101 | 直接地址 | 相对地址 rel | |
CJNE @Ri,#data,rel | 立即数与间接RAM比较,不等转移 | 3 | 2 | B6 - B7 | 1011 011i | 立即数 | 相对地址 rel | i = 0,1 |
CJNE Rn,#data,rel | 立即数与寄存器比较不等转移 | 3 | 2 | B8 - BF | 1011 1rrr | 立即数 | 相对地址 rel | r = 0 - 7 |
PUSH data | 直接字节入栈,SP加1 | 2 | 2 | C0 | 1100 0000 | 直接地址 | / | |
CLR bit | 直接位清0 | 2 | 1 | C2 | 1100 0010 | 位地址 | / | |
CLR C | 进位位清0 | 1 | 1 | C3 | 1100 0011 | / | / | |
SWAP A | A半字节交换 | 1 | 1 | C4 | 1100 0100 | / | / | |
XCH A,data | 直接字节与A交换 | 2 | 1 | C5 | 1100 0101 | 直接地址 | / | |
XCH A,@Ri | 间接Rn与A交换 | 1 | 1 | C6 - C7 | 1100 011i | / | / | i = 0,1 |
XCH A,Rn | 寄存器与A交换 | 1 | 1 | C8 - CF | 1100 1rrr | / | / | r = 0 - 7 |
POP data | 直接字节出栈,SP减1 | 2 | 2 | D0 | 1101 0000 | 直接地址 | / | |
SETB bit | 直接位置位 1 | 2 | 1 | D2 | 1101 0010 | 位地址 | / | |
SETB C | 进位位置位 1 | 1 | 1 | D3 | 1101 0011 | / | / | |
DA A | A十进制调整 | 1 | 1 | D4 | 1101 0100 | / | / | |
DJNE data,rel | 直接字节减1不为0转移 | 3 | 2 | D5 | 1101 0101 | 直接地址 | 相对地址 rel | |
XCHD A,@Ri | 间接Rn与A低半字节交换 | 1 | 1 | D6 - D7 | 1101 011i | / | / | i = 0,1 |
DJNE Rn,rel | 寄存器减1不为0转移 | 2 | 2 | D8 - DF | 1101 1rrr | 相对地址 rel | / | r = 0 - 7 |
MOVX A,@DPTR | 外部数据送A(16位地址) | 1 | 2 | E0 | 1110 0000 | / | / | |
MOVX A,@Ri | 外部数据送A(8位地址) | 1 | 2 | E2 - E3 | 1110 0010 | / | / | |
CLR A | A清0 | 1 | 1 | E4 | 1110 0011 | / | / | |
MOV A,data | 直接字节送A | 2 | 1 | E5 | 1110 0100 | 直接地址 | / | |
MOV A,@Ri | 间接RAM送A | 1 | 1 | E6 - E7 | 1110 011i | / | / | i = 0,1 |
MOV A,Rn | 寄存器送A | 1 | 1 | E8 - EF | 1110 1rrr | / | / | r = 0 - 7 |
MOVX @DPTR,A | A送外部数据(16位地址) | 1 | 2 | F0 | 1111 0000 | / | / | |
MOVX @Ri,A | A送外部数据(8位地址) | 1 | 2 | F2 - F3 | 1111 001i | / | / | |
CPL A | A求反码 | 1 | 1 | F4 | 1111 0100 | / | / | |
MOV data,A | A送直接字节 | 2 | 1 | F5 | 1111 0101 | 直接地址 | / | |
MOV @Ri,A | A送间接Rn | 1 | 2 | F6 - F7 | 1111 0101 | / | / | i = 0,1 |
MOV Rn,A | A送寄存器 | 1 | 1 | F8 - FF | 1111 1rrr | / | / | r = 0 - 7 |
所以就可以开始分析汇编文件,然后根据以上表格转换对应的机器码。
1、使用main函数来接收控制台的命令参数
FB里使用Main函数需要自己定义入口点,并使用__FB_ARGC__和__FB_ARGV__来获取参数。ParseAsmFile来解析ASM文件到机器码。CompileToHex将机器码转换为Hex文件。(具体实现看源码)
Private Function main(ByVal argc As Integer,ByVal argv As ZString Ptr Ptr) As Integer
Print argc,*argv[1],*argv[2]
'argc 是参数个数
'argv 是命令行的参数指针
'*argv[0] 表示第1个参数,是exe本身的名字
'*argv[1] 表示第2个参数,这里固定为ASM文件名
'*argv[2] 表示第3个参数,这里固定为Hex文件名
If argc > 1 Then '有参数
'1、解析命令(未完成)
'根据命令添加8051默认寄存器
'2、解析汇编文件
ParseAsmFile(*argv[1])
'3、输出Hex文件
CompileToHex(*argv[2])
End If
Return 0
End Function
End main(__FB_ARGC__, __FB_ARGV__)
2、另外建立一个调用编译器的窗体工程
窗体如下:
测试打印信息:
源码工程