探讨一下ChipON---IDE编译代码低效的原因
KungFu8有很多特点,主要有1.具有典型的RISC架构,程序存储器和数据存储器分开
2.具有8个8位寄存器组成的寄存器组堆
3.SFR无需分组,简化程序设计
4.高性能的单时钟周期结构,大部分指令为单机器周期执行
5.KF8系列与当前的8位单片机相比,KF8通过结构的改进,提高了代码密度并简化程序设计;
。。。。
通过下载,安装 ChipON---IDE集成开发环境,编写极简单的程序测试,发现 2K的程序存储器装不下,得改 4K的程序容量。
为何如此低效?通过观看LST文件,发现 几乎每一、二条指令中,插入一条多余的 页面切换指令BANKSEL,消耗了大量的 ROM程序, 使得这么简单的DEMO, 2k装不下,要占用4k的 约60%容量。
继续看汇编代码,发现ChipON单片机存在一个极大的设计缺陷,竟然没有带CY的加减法指令!
要知道,自从Intel 4004单片机问世的 50几年来,最简单简化的单片机结构,可以没有减法指令,但不会没有带CY的加法指令!
带CY的和不带CY的加法指令,都是成双成对出现的! 想了一下,也没什么好方法,以后的ChipON单片机,会程序容量越做越大,同时也希望内核能完善指令集,增加带CY的加减法指令! 研究得这么深入透彻啊啊!!!! 本帖最后由 laoxu 于 2016-6-12 11:29 编辑
最后,对 ChipON---IDE集成开发环境 的改进,提点建议,仅供参考。
1. 非BYTE变量, 在RAM中的存放地址要连续,并且放在同一页面中,这样,在读取变量时,只需一次BANK切换。其次,变量在RAM中存放地址的连续,也有利于今后软件升级,支持位结构体和联合体。
2. 优先充分利用 R0~R7这8个寄存器,像子程序调用的入口变量, 返回变量,以及读入输出的中间过渡变量及运算中的中间过渡变量,都应该优先放在这R0~R7这8个寄存器中,这样,程序效率最高。
3. 其次充分利用 RAM70H~7FH这16个字节,像子程序调用的入口变量, 返回变量,以及读入输出的中间过渡变量及运算中的中间过渡变量,都应该优先放在这70H~7FH中,这样,无需作BANK切换。都能直接使用。
4. 通过分析现在的编译结果,对long类长变量,先读入 R0~R7及 RAM(70H~7FH这16个字节)中,再运算或作其他的处理,肯定比现在直接处理的方法,程序代码要精简许多,程序代码也相应缩短很多。
laoxu 发表于 2016-6-12 11:15
最后,对 ChipON---IDE集成开发环境 的改进,提点建议,仅供参考。
1. 非BYTE变量, 在RAM中的存放地址要连 ...
身为ChipON的版主,还是很感谢你给出那么多的建议。楼主绝对是花了精力来了解我们的产品的{:handshake:}。 楼主准备从中颖换ChipON了? dirtwillfly 发表于 2016-6-12 11:47
楼主准备从中颖换ChipON了?
这个可以有。{:smile:}
编译器为了做兼容,没有使用0x70-0x7f,这样需要通过寄存器进行中断现场保护。所以寄存器只使用了一部分。
变量必须在内存中连续存放,因为涉及指针操作时,地址必须联系
banksel有特定优化,楼主下载的ide版本是否太老
楼主只是站在纯编译器单版本的角度来分析,楼主提出的建议我们会慎重考虑
本帖最后由 laoxu 于 2016-6-12 14:36 编辑
随便写了一个 long 的加法程序,是否比原编译程序短小许多?
1.用ChipON---IDE编译的汇编代码:
; .line 20; "../main.c" Lc = La + Lb;
000f30 6d03 SET 0x3, 5 BANKSEL r0x1000
000f31 508d MOV R0, 0x8d MOV R0, r0x1000
000f32 6d03 SET 0x3, 5 BANKSEL r0x1001
000f33 208e ADD R0, 0x8e ADD R0, r0x1001
000f34 6d03 SET 0x3, 5 BANKSEL r0x1006
000f35 5193 MOV 0x93, R0 MOV r0x1006, R0
000f36 6d03 SET 0x3, 5 BANKSEL r0x1003
000f37 5090 MOV R0, 0x90 MOV R0, r0x1003
000f38 6d03 SET 0x3, 5 BANKSEL r0x1007
000f39 5194 MOV 0x94, R0 MOV r0x1007, R0
000f3a 6d03 SET 0x3, 5 BANKSEL r0x1002
000f3b 0e8f MOVZ R0, 0x8f MOVZ R0, r0x1002
000f3c 7003 JNB 0x3, 0 JNB PSW, 0
000f3d ff10 INC R0 INC R0
000f3e 7203 JNB 0x3, 2 JNB PSW, 2
000f3f cf42 JMP #0xf42 JMP _00006_DS_
000f40 6d03 SET 0x3, 5 BANKSEL r0x1007
000f41 2194 ADD 0x94, R0 ADD r0x1007, R0
_00006_DS_
000f42 6d03 SET 0x3, 5 BANKSEL r0x1005
000f43 5091 MOV R0, 0x91 MOV R0, r0x1005
000f44 6d03 SET 0x3, 5 BANKSEL r0x1009
000f45 5195 MOV 0x95, R0 MOV r0x1009, R0
000f46 6d03 SET 0x3, 5 BANKSEL r0x100A
000f47 0e97 MOVZ R0, 0x97 MOVZ R0, r0x100A
000f48 7003 JNB 0x3, 0 JNB PSW, 0
000f49 ff10 INC R0 INC R0
000f4a 7203 JNB 0x3, 2 JNB PSW, 2
000f4b cf4e JMP #0xf4e JMP _00007_DS_
000f4c 6d03 SET 0x3, 5 BANKSEL r0x1009
000f4d 2195 ADD 0x95, R0 ADD r0x1009, R0
_00007_DS_
000f4e 6d03 SET 0x3, 5 BANKSEL r0x1004
000f4f 5092 MOV R0, 0x92 MOV R0, r0x1004
000f50 6d03 SET 0x3, 5 BANKSEL r0x1008
000f51 5196 MOV 0x96, R0 MOV r0x1008, R0
000f52 6d03 SET 0x3, 5 BANKSEL r0x100B
000f53 0e98 MOVZ R0, 0x98 MOVZ R0, r0x100B
000f54 7003 JNB 0x3, 0 JNB PSW, 0
000f55 ff10 INC R0 INC R0
000f56 7203 JNB 0x3, 2 JNB PSW, 2
000f57 cf5a JMP #0xf5a JMP _00008_DS_
000f58 6d03 SET 0x3, 5 BANKSEL r0x1008
000f59 2196 ADD 0x96, R0 ADD r0x1008, R0
; op : SEND
2.通过R0~R7传送变量,写的汇编代码:
; Lc = La + Lb;
BANKSEL 切换页面La
MOV R4, La ; 表示La最低位,表示La最高位
MOV R5, La
MOV R6, La
MOV R7, La
BANKSEL 切换页面Lb
MOV R0, Lb ; 表示Lb最低位,表示Lb最高位
MOV R1, Lb
MOV R2, Lb
MOV R3, Lb
BANKSEL 切换页面PSW
ADD R4, R0 ; 个位数相加
MOV R0, PSW
AND R0, #1
ADD R5, R1 ; 十位数相加
MOV R1, PSW
ADD R5, R0 ; 加个位数进位
ORL R1, PSW
AND R1, #1
ADD R6, R2 ; 百位数相加
MOV R2, PSW
ADD R6, R1 ; 加十位数进位
ORL R2, PSW
AND R2, #1
ADD R7, R3 ; 千位数相加
ADD R7, R2 ; 加百位数进位
BANKSEL 切换页面Lc
MOV Lc, R4 ; 表示Lc最低位,表示Lc最高位
MOV Lc, R5
MOV Lc, R6
MOV Lc, R7
gbbfbaa 发表于 2016-6-12 12:01
编译器为了做兼容,没有使用0x70-0x7f,这样需要通过寄存器进行中断现场保护。所以寄存器只使用了一部分。 ...
你的变量不连续的!!!
比如12楼的程序中,乱的很!!!
La 占用: 0x8d , 0x90 , 0x91 , 0x92 ,
Lb 占用: 0x8e , 0x8f , 0x97 , 0x98 ,
Lc 占用: 0x93 , 0x94 , 0x95 , 0x96 ,
版本是你们官网下的,最新版。 12楼的示例DEMO, 没有使用0x70-0x7f,仅使用寄存器,也比原来编译的精练。 另外请教一下, MOVZ R0, 0x8e 是什么指令?
指令集中没有注明,不过从使用上看,等同于 MOV R0, 0x8e, 除了两者的机器码不同?其他还有啥区别? gbbfbaa 发表于 2016-6-12 12:01
编译器为了做兼容,没有使用0x70-0x7f,这样需要通过寄存器进行中断现场保护。所以寄存器只使用了一部分。 ...
别想着高大尚了,目前的内核寻址范围只能做到 8K, 再想上去只能升级内核了。
中断也简单,最多 2个优先级,入口单一同PIC,不像51的多地址入口。
数据寻址一页只有 128字节,比51的 256字节少一半,只能做些简单应用了。
再给个建议,数据变量命名时加页面指定,如同 51的 data, xdata等指定。不指定默认第0页,方便编译器编译,且代码短小精练。
太智能化的容易出错(像PIC编译器,变量多了易放错地方),比如一个串囗,发送接收缓冲区,各100字节,能指定分页的,就比较简洁
rd_buff BANK 1 ;
wr_buff BANK 2 ;
多余的空间用户可另行命名变量。
如自动分配,搞不好就出错,以前我用的PIC编译器, 就有时会犯这错误,并且出了错,排查也困难。 如升级内核,像 PSW 这等重要的寄存器,最好做到 每一页能有镜像,能不分页的直接使用。 请问一下,下列指令中,
000f46 6d03 SET 0x3, 5 BANKSEL r0x100A // 强置 第1页
000f47 0e97 MOVZ R0, 0x97 MOVZ R0, r0x100A
000f48 7003 JNB 0x3, 0 JNB PSW, 0 // 判断 第0页PSW寄存器
中间的指令 MOVZ R0, r0x100A ,是否除了 MOV R0, r0x100A 功能外,还将BANK 强置到 第0页 ?
假如没有这个功能,则编译的程序就是错误的。 000f30 6d03 SET 0x3, 5 BANKSEL r0x1000
000f31 508d MOV R0, 0x8d MOV R0, r0x1000
000f32 6d03 SET 0x3, 5 BANKSEL r0x1001
这也太NB了。我们公司做智能电视,内存很小,自己人称为 弱智能 ,外人直接说脑残。 这个编译器的效率也太过于智能了。即使优化等级为0也不应该生成这这样的代码吧?
long+long正常应该是个库,直接链接进来的。
没有用过此MCU,从bank切换来看,应该是类似PIC的。过去的经验,PIC编译器只有ccs info公司的最好,其它的吹的再厉害,一测试都差30%多。而ccs info的优化真不是一点两点。