[PIC®/AVR®/dsPIC®产品] 如何启用PIC18的扩展指令集?

[复制链接]
 楼主| roalychen 发表于 2015-11-19 16:33 | 显示全部楼层 |阅读模式
用的是X IDE + XC8
配置字XINST = OFF的时候功能是正常的
但是,修改成XINST = ON,所有功能都不正常了

是还要哪里设置吗?
panxiaoyi 发表于 2021-4-21 15:37 | 显示全部楼层
虽然是老帖,但是,我的PIC18F也遇到了同样的问题

XINST 扩展指令集使能位

1
禁止扩展指令集和变址寻址模式(传统模式)
0
使能扩展指令集和变址寻址模式
panxiaoyi 发表于 2021-4-21 15:41 | 显示全部楼层
我对比了一下,PIC18与传统的1T模式的51单片机对比,发现64M时钟的PIC18还不如16M时钟的51快,而且51的运行速度快好几倍,于是,我就想打开这个扩展指令集试试,结果,打开后,很多原来的C语句编译失败,请问是为什么?
lcczg 发表于 2021-4-21 16:00 | 显示全部楼层
XC8编译器不支持扩展指令集
https://microchipdeveloper.com/faq:14

Does the XC8 compiler support the extended instruction set?

No, the MPLAB® XC8 compiler does not support the extended instruction set. It generates smaller code using the non-extended instruction set, rather than using the extended instructions.
panxiaoyi 发表于 2021-4-21 16:46 | 显示全部楼层
多谢,多谢指点说明
panxiaoyi 发表于 2021-4-21 16:55 | 显示全部楼层
我用64M时钟的PIC18F24Q10和51单片机16M时钟的HC89F0541(多数指令在2-4个震荡时钟),这个51也没有硬件乘除法,测试了如下代码,发现PIC好慢啊,两个芯片都是定时100ms,结果51可以跑接近9000次,而PIC才跑了1677次
  1.     for(i=0; i<65535; i++)             //全部语句可以运行8988次
  2.     {
  3.       x=test(37);                      //注释这条可以运行9580次
  4.       out=x;
  5.             
  6.       if(x>47) x=57; else x=67;        //注释这条可以运行9998次
  7.       out=x;
  8.             
  9.       x<<=1;                           //注释这条可以运行9248次
  10.       out=x;
  11.             
  12.       x>>=1;                           //注释这条可以运行9248次
  13.       out=x;
  14.             
  15.       x|=1;                            //注释这条可以运行9142次
  16.       out=x;
  17.             
  18.       x&=1;                            //注释这条可以运行9142次
  19.       out=x;
  20.             
  21.       x=~x;                            //注释这条可以运行9142次
  22.       out=x;
  23.             
  24.       x=x^1;                           //注释这条可以运行9142次
  25.       out=x;
  26.             
  27.       x+=1;                            //注释这条可以运行9090次
  28.       out=x;
  29.             
  30.       x-=1;                            //注释这条可以运行9090次
  31.       out=x;
  32.             
  33.       x*=3;                            //注释这条可以运行9523次
  34.       out=x;
  35.             
  36.       x/=3;                            //注释这条可以运行9523次
  37.       out=x;
  38.             
  39.       x%=3;                            //注释这条可以运行9638次
  40.       out=x;
  41.     }
  42.                 while(1);
复制代码


评论

工程文件打包给下,我也来试试。。。  发表于 2021-4-22 07:29
panxiaoyi 发表于 2021-4-21 16:59 | 显示全部楼层
第3行是简单的函数调用,out=x;是对寄存器赋值,全部都是 unsigned char 变量,怎么PIC就这么慢?
奔波儿熊 发表于 2021-4-21 17:50 | 显示全部楼层
panxiaoyi 发表于 2021-4-21 16:59
第3行是简单的函数调用,out=x;是对寄存器赋值,全部都是 unsigned char 变量,怎么PIC就这么慢? ...

比比看两边的汇编指令条数
wooda 发表于 2021-4-22 07:26 | 显示全部楼层
这个有点意思,要不你把工程打包发过来看看?
这个测试是有意义的。要么是搞清楚芯片性能,要么是搞清楚代码如何能发挥芯片性能,要么是搞清楚不同指令集的差异,总之能对如何获得更佳的实现效果有帮助。
wooda 发表于 2021-4-22 08:00 | 显示全部楼层
跑了一下模拟,,6楼这个for函数,在64M时钟的PIC18F24Q10上,完成时间如下
Stopwatch cleared. Stopwatch cycle count = undefined
Target halted. Stopwatch cycle count = 22151448 (346.116375 ms)
Target halted. Stopwatch cycle count = 22151363 (346.115047 ms)
Target halted. Stopwatch cycle count = 22151364 (346.115063 ms)
Target halted. Stopwatch cycle count = 19005719 (296.964359 ms)
Target halted. Stopwatch cycle count = 19005675 (296.963672 ms)
Target halted. Stopwatch cycle count = 19005675 (296.963672 ms)
Target halted. Stopwatch cycle count = 19005675 (296.963672 ms)

说明,前3次是没有优化过的,后几次是优化过的。
按照6楼这个测试数据,100ms就中断的话,没有优化过的应该是65535/3.46=18940次左右
试过编译版本不同的情况下,结果差不多附件在此,断点设在翻转A0引脚这里。


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
panxiaoyi 发表于 2021-4-22 12:11 | 显示全部楼层
这个是51的代码,PIC的稍后
  1. //
  2. #define          ALLOCATE_EXTERN
  3. #include "HC89F0541.h"
  4. #include "BIT.h"
  5. #include "FONT0805.h"
  6. #include "DELAY_LONG.h"
  7. #include "MCUIIC.h"
  8. #include "SH1106.h"

  9. #define out P1

  10. unsigned int i, n;
  11. unsigned char x, a;

  12. unsigned char test(unsigned char dat)
  13. {
  14.   unsigned char y;
  15.   y=dat;
  16.   return y;
  17. }


  18. void TIMER3_ISR(void) interrupt 10
  19. {
  20.         n++;
  21.         P2_7 =1;                            //LED亮
  22.         WDTC |= 0x10;                       //看门狗清零
  23.         OLED_gotoxy(71,3);                  //显示时间
  24.   OLED_show(n);
  25.         P2_7 =0;
  26.   if(a)                               //显示:程序在1600K个CPU时钟里运行for()语句的次数
  27.   {
  28.     a=0;
  29.     OLED_gotoxy(35,3);
  30.     OLED_show(i);
  31.   }
  32. }

  33. void main(void)
  34. {
  35.   CLKSWR = 0x51;                                                           //选择内部高频RC为系统时钟,内部高频RC2分频,Fosc=16MHz
  36.   CLKDIV = 0x01;                                                           //CPU时钟Fcpu=Fosc/分频值,比如CLKDIV=0x01,则CPU=16MHz
  37.        
  38.         P2M7 = 0xC2;                         //P27设置为推挽输出驱动LED
  39.        
  40.         IIC_init();
  41.         OLED_init();

  42.   OLED_clear();
  43.   OLED_gotoxy(14,1);
  44.   OLED_string("HC8051 ==> SH1106");
  45.         OLED_gotoxy(11,5);
  46.         OLED_string("21IC.COM PANXIAOYI");
  47.        
  48.   EA = 1;                                                                               //打开总中断
  49.        
  50.         T3CON=0;
  51.         T3CON B5H;  T3CON B4H;               //计数时钟=Fosc/256分频
  52.         TH3 = 0xE7; TL3 = 0x96;                                  //消耗时钟=(65536-0xE796)*256分频=1600K,即中断时间是100ms
  53.   ET3 = 1;                                                                       //打开T3中断
  54.         T3CON B2H;                           //启动定时器
  55.        
  56.         a=1;
  57.   i=1;
  58.         n=0;
  59.        
  60.   while(1)
  61.   {
  62.     for(i=0; i<65535; i++)             //全部语句可以运行8988次
  63.     {
  64.       x=test(37);                      //注释这条可以运行9580次
  65.       out=x;
  66.             
  67.       if(x>47) x=57; else x=67;        //注释这条可以运行9998次
  68.       out=x;
  69.             
  70.       x<<=1;                           //注释这条可以运行9248次
  71.       out=x;
  72.             
  73.       x>>=1;                           //注释这条可以运行9248次
  74.       out=x;
  75.             
  76.       x|=1;                            //注释这条可以运行9142次
  77.       out=x;
  78.             
  79.       x&=1;                            //注释这条可以运行9142次
  80.       out=x;
  81.             
  82.       x=~x;                            //注释这条可以运行9142次
  83.       out=x;
  84.             
  85.       x=x^1;                           //注释这条可以运行9142次
  86.       out=x;
  87.             
  88.       x+=1;                            //注释这条可以运行9090次
  89.       out=x;
  90.             
  91.       x-=1;                            //注释这条可以运行9090次
  92.       out=x;
  93.             
  94.       x*=3;                            //注释这条可以运行9523次
  95.       out=x;
  96.             
  97.       x/=3;                            //注释这条可以运行9523次
  98.       out=x;
  99.             
  100.       x%=3;                            //注释这条可以运行9638次
  101.       out=x;
  102.     }
  103.                 while(1);
  104.   }
  105. }
复制代码


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
panxiaoyi 发表于 2021-4-22 12:20 | 显示全部楼层
这个是 PIC18F24Q10 的代码,全部语句运行只有1677次
  1. //
  2. #include "Configuration.h"
  3. #include <xc.h>

  4. #include "BIT.h"
  5. #include "DELAY_LONG.h"
  6. #include "FONT0805.h"
  7. #include "MCUIIC.h"
  8. #include "SH1106.h"

  9. #define out LATA

  10. unsigned int i, n;
  11. unsigned char x, a;


  12. unsigned char test(unsigned char dat)
  13. {
  14.     unsigned char y;
  15.     y=dat;
  16.     return y;
  17. }



  18. void __interrupt() isr(void)
  19. {
  20.     TMR0IF=0;                           //清零中断位
  21.         n++;
  22.         OLED_gotoxy(71,3);                  //显示时间
  23.     OLED_show(n);
  24.     if(a)                               //显示:程序在1600K个CPU时钟里运行for()语句的次数
  25.    {
  26.         a=0;
  27.         OLED_gotoxy(35,3);
  28.         OLED_show(i);
  29.     }

  30. }

  31. void main(void)
  32. {
  33.     IIC_init();
  34.     OLED_init();
  35.     OLED_clear();
  36.     OLED_gotoxy(11,1);
  37.     OLED_string("PIC18F26K83>SH1106");
  38.     OLED_gotoxy(11,5);
  39.     OLED_string("21IC.COM PANXIAOYI");

  40.     GIEH=1;                            //全局中断允许位
  41.     GIEL=1;                            //外设中断允许位
  42.     IPEN=0;                            //禁止中断优先级

  43.     T0CON1=64+13;                      //时钟源=Fosc/4,8192预分频
  44.     TMR0H=195;                         //8位计时的周期值
  45.     TMR0IE=1;                          //中断使能,速度=16M/(8192*195)=10次/秒
  46.     T0CON0|=0x80;                      //TMR0 使能位
  47.        
  48.     a=1;
  49.     i=1;
  50.         n=0;
  51.        
  52.     while(1)                                 //下面这些是 51 单片机的数据
  53.     {
  54.         for(i=0; i<65535; i++)               //全部语句可以运行8988次
  55.         {
  56.             x=test(37);                      //注释这条可以运行9580次
  57.             out=x;
  58.             
  59.             if(x>47) x=57; else x=67;        //注释这条可以运行9998次
  60.             out=x;
  61.             
  62.             x<<=1;                           //注释这条可以运行9248次
  63.             out=x;
  64.             
  65.             x>>=1;                           //注释这条可以运行9248次
  66.             out=x;
  67.             
  68.             x|=1;                            //注释这条可以运行9142次
  69.             out=x;
  70.             
  71.             x&=1;                            //注释这条可以运行9142次
  72.             out=x;
  73.             
  74.             x=~x;                            //注释这条可以运行9142次
  75.             out=x;
  76.             
  77.             x=x^1;                           //注释这条可以运行9142次
  78.             out=x;
  79.             
  80.             x+=1;                            //注释这条可以运行9090次
  81.             out=x;
  82.             
  83.             x-=1;                            //注释这条可以运行9090次
  84.             out=x;
  85.             
  86.             x*=3;                            //注释这条可以运行9523次
  87.             out=x;
  88.             
  89.             x/=3;                            //注释这条可以运行9523次
  90.             out=x;
  91.             
  92.             x%=3;                            //注释这条可以运行9638次
  93.             out=x;
  94.        }
  95.            while(1);
  96.     }
  97. }
复制代码



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
panxiaoyi 发表于 2021-4-22 12:26 | 显示全部楼层
MPLAB xc8-v2.32-full-install-windows-x32-x64-installer 和 MPLAB X-v4.20-windows-installer
我没有设置任何优化,也不会设置,配置字只修改了64M,内部复位,看门狗,其它的默认
KEIL C51 V960A 2020 官网下载,这个我也没有设置任何优化,也没有搞过这个东西
wooda 发表于 2021-4-22 21:06 | 显示全部楼层
你的代码我编译后,运行 ,timer0中断没发生,运行到107行while1时候a还是1
当然我没有硬件,是用软件模拟器的,不过这种纯内部寄存器的模拟,不太可能有错误。
看了你的代码
感觉2个部分可能有问题
1,尽量不要用a,i,这样的变量名,改成aaa都比a要好。
2,初始化没有初始化时钟,这个可能有问题
3,中断初始化最后再开GIEH=1;   否则再设定的时候很容易触发触发不必要的中断进入
4,为啥要GIEL=1;  
panxiaoyi 发表于 2021-4-23 00:27 | 显示全部楼层
试试这个看看?

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
panxiaoyi 发表于 2021-4-23 00:31 | 显示全部楼层
我上面的代码都是在实验板上测试过的,它们都是在中断里面闪烁LED和中断显示时间的,如上面的图。下面的代码也是基本一样的,运行次数1655

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
panxiaoyi 发表于 2021-4-23 00:36 | 显示全部楼层
2,初始化没有初始化时钟,这个可能有问题
请问在配置字里面设置了64M,是不是这样还不够?我真的不懂喔
panxiaoyi 发表于 2021-4-23 00:56 | 显示全部楼层
请问是不是要加上 OSCFRQ=8; 这个语句?改变这个值的确会改变LED的闪烁速度,但是 for() 运行次数还是不变,也可以这样理解:速度=16M/(8192*195)=10次,也就是CPU运行16M次,中断就产生了10次,然后第一次中断就发现for()运行了1677次
wooda 发表于 2021-4-23 09:13 | 显示全部楼层
panxiaoyi 发表于 2021-4-23 00:56
请问是不是要加上 OSCFRQ=8; 这个语句?改变这个值的确会改变LED的闪烁速度,但是 for() 运行次数还是不变 ...

理论上来说,因为timer0是Fosc分频的,所以主时钟是1M还是64M,timer0中断前,cpu执行了多少个指令是固定的,那么这个计数值a是多少也是基本固定的。
我建议初始化时候也初始化一遍时钟,是因为pic的芯片,timer0计数可以来自多个时钟源,主时钟也是有多个选择。其实看规格书可以看到默认值是哪个。。。只不过没功夫去查pdf文档而已。。。

你做的这个测试,包括这个代码很有意义,可以评估不同指令集的实际效能。pic的指令集作为和51同样渊源久远的,做一下这个评估更有意义。其实51和pic,在芯片和指令集上面,各有千秋,作为pic指令集,同样任务需要的指令数量更多是有可能的,很多51一句汇编可以解决的事情,pic可能需要2-3句汇编指令才能搞定。pic的优势在于芯片更稳定,指令集更加合理,逻辑相对严密,有利于内核时钟速度提高。51的话,更加简单一些,比较容易理解和入门。

各位围观的兄弟们如果有条件,也可以在开发板上跑一下。毕竟软件模拟结果可靠性不如硬件跑起来更加有说服力。
panxiaoyi 发表于 2021-4-23 12:05 来自手机 | 显示全部楼层
是啊,随便一个PIC芯片都可以测试,只需要测试for()语句就可以了,我毕竟是个PIC的入门者,也是个电子爱好者而已,技术有限,E文就更不用提了,就是一个字,差。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

102

主题

227

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部