1 引 言
P89C51RD2是PH ILIPS 公司的8位单片机产品。在保证80C51指令系统和硬件结构的大体框架的同时, 扩充了许多功能, 包括看门狗、ISP功能和F lash操作。值得一提的是, PH ILIPS的技术并非完全公开, 这就给单片机的使用带来了一定的困难。
比如说, 它的Boot ROM 区本来是4K 字节, 但在手册中只提及了1K 字节, 其他部分程序隐藏调用, 这就给程序设计带来了很大的麻烦。同时, 除了手册中提及的高位地址特殊寄存器区, P89C51RD2 还设计了一些特殊功能寄存器, 对这些寄存器的意外访问也有可能造成芯片的异常。因此, 有必要对这些功能区进行分析, 以找出其所有单片机资源。
2 Boo tROM 固件代码的读出
对于1K ( 地址FC00H ~ FFFFH ) Boot ROM 的flash代码读取方法, 参考文献已经有提及, 这里只是在此基础上进行进一步分析。下面来看PGM _MTP入口地址的部分代码。
PUSH 0E4H ; 保存E4H值
ORL 0E 4H, # 80H ; 置位E4H 最高位
PUSH PSW
ACALL 0F9ADH ; 调用看门狗服务程序
C JNE R1, # 00H, 0FF4FH
ACALL 0F9D9H ; 读生产批号子程序
通过这部分程序可以看出, Boo tROM 区调用了0F9ADH 地址中的子程序, 而从手册上, 只写出有FC00H ~ FFFFH 地址。所以, 这是一个需要特殊访问的flash区。同时, 程序还控制了E4H, 这个特殊功能寄存器也是手册里面没有提及的。鉴于P89C51RD2有专门的控制位来控制1K flash, 假设还有一个控制位, 位于E4H 的最高位, 也是通过置位方式, 能够得到flash切换的效果, 只要程序中首先置位了E 4H, 就可以通过movc 指令得到隐藏区的程序。实践证明这个假设是对的, 从F000H ~FFFFH 都读出了数据, 其中F000H ~ F7FFH 地址中全为0。而F800H ~ FBFFH中存在1K 可执行程序,并且这些程序就是PGM _MTP调用的隐藏子程序。
通过反汇编这一区间程序, 可以找到全部flash底层操作的程序。所以实际的P89C51RD2的f lash 空间分布应该如图1所示。
手册里面1K 字节的Boo t ROM 区, 实际上是由一个4K 的flash块构成的, 其中2K 字节的flash最终被填写进00H, 另外2K 用于实现Boot ROM 的实际操作。所以, 用户也可以将这2K 的地址空间, 作为用户的使用空间, 存放一些需要保留的重要数据。
3 部分子程序分析
P89C51RD2多余的1K 程序空间写满了程序。
这些程序都是由FFF0的子程序调用的。通过反汇编这一段子程序, 能够知道单片机的底层操作细节。
由于篇幅所限, 这里面仅列出flash写操作的部分程序, 有兴趣的读者可以依照上面的方法反汇编所有程序进行分析。以下是编程数据字节子程序的反汇编结果。
; 编程数据字节一级子程序
F9C9: 75 E4 91MOV 0E4H, # 91H ; E4H 未公开
F9CC: 31 D1 ACALL 0F9D1H ;
F9CE: 65 E5 XRL A, 0E5H ; 返回E5H 参数
F9D0: 22 RET
; 编程数据字节二级子程序
F9D1: F5 E5MOV 0E5H, A
F9D3: 31 25 ACALL 0F925H ; 多入口子程序,连续写和读E6H, flash操作
F9D5: 75 E4 80MOV 0E4H, # 80H
F9D8: 22 RET
; 编程数据字节三级子程序
F925: C0 F0 PUSH B
F927: C0 E0 PUSH ACC
F929: 31 83 ACALL 0F983H ; flash1
F92B: 75 F0 05MOV B, # 05H
F92E: 31 A3 ACALL 0F9A3H ; 看门狗子程序
F930: E5 E6MOV A, 0E6H
F932: 54 08 ANL A, # 08H
F934: 60 03 JZ 0F939H
F936: D5 F0 F5 DJNZ B, 0F92EH
F939: 31 93 ACALL 0F993H ; flash2
F93B: 31 9B ACALL 0F99BH ; flash3
F93D: D0 E0 POP ACC
F93F: D0 F0 POP B
F941: 22 RET
; flash底层操作1
F983: 75 E6 C0MOV 0E6H, # 0C0H
F986: 00 NOP
F987: 75 E6 D0MOV 0E6H, # 0D0H
F98A: 00 NOP
F98B: 00 NOP; 这里面较多的NOP 起延迟作用
F992: 22 RET
; flash底层操作2
F993: 75 E6 C0MOV 0E6H, # 0C0H
F996: 00 NOP
F997: 75 E6 E 0MOV 0E6H, # 0E0H
F99A: 22 RET
; flash底层操作3
F99B: 75 E6 C0MOV 0E6H, # 0C0H
F99E: 00 NOP
F99F: 75 E6 00MOV 0E 6H, # 00H
F9A2: 22 RET
上面的flash 区写字节子程序, 动用了E4H、E5H 和E6H 三个隐藏的特殊功能寄存器, 其中E4寄存器带入状态, E5寄存器返回结果, E 6寄存器用于发布实际的写操作命令。这就要求在程序设计中, 一定注意不能随便对上述地址做操作, 否则可能会意外改写程序区。同时, 从程序中也可以看到, 每一个具体的子程序操作, 到底使用了多大的堆栈空间。在程序设计中, 遇到调用写f lash 子程序时, 有了对堆栈使用情况的了解, 可以防止堆栈的溢出, 对堆栈的设计考虑起辅助作用。
4 结论与展望
通过对P89C51RD2的分析可以看出, 在单片机功能增加方面, 采用的设计方法就是扩展高位地址特殊功能寄存器, 而这种方法几乎应用在所有80C51架构和指令集的扩展型单片机中。由于能够读出P89C51RD2的所有程序, 实际应用中可以将Boot ROM 区转移到其他地址, 或者为用户扩展2K的隐藏空间。从分析中还可以发现, flash 区的隐藏, 是通过特殊寄存器的控制位切换来实现的。因此, 这一读出Boot ROM 区的方法, 也可以应用于分析其他型号单片机的flash区。