打印
[PIC®/AVR®/dsPIC®产品]

如何启用PIC18的扩展指令集?

[复制链接]
2851|32
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
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.

使用特权

评论回复
5
panxiaoyi| | 2021-4-21 16:46 | 只看该作者
多谢,多谢指点说明

使用特权

评论回复
6
panxiaoyi| | 2021-4-21 16:55 | 只看该作者
我用64M时钟的PIC18F24Q10和51单片机16M时钟的HC89F0541(多数指令在2-4个震荡时钟),这个51也没有硬件乘除法,测试了如下代码,发现PIC好慢啊,两个芯片都是定时100ms,结果51可以跑接近9000次,而PIC才跑了1677次
    for(i=0; i<65535; i++)             //全部语句可以运行8988次
    {
      x=test(37);                      //注释这条可以运行9580次
      out=x;
            
      if(x>47) x=57; else x=67;        //注释这条可以运行9998次
      out=x;
            
      x<<=1;                           //注释这条可以运行9248次
      out=x;
            
      x>>=1;                           //注释这条可以运行9248次
      out=x;
            
      x|=1;                            //注释这条可以运行9142次
      out=x;
            
      x&=1;                            //注释这条可以运行9142次
      out=x;
            
      x=~x;                            //注释这条可以运行9142次
      out=x;
            
      x=x^1;                           //注释这条可以运行9142次
      out=x;
            
      x+=1;                            //注释这条可以运行9090次
      out=x;
            
      x-=1;                            //注释这条可以运行9090次
      out=x;
            
      x*=3;                            //注释这条可以运行9523次
      out=x;
            
      x/=3;                            //注释这条可以运行9523次
      out=x;
            
      x%=3;                            //注释这条可以运行9638次
      out=x;
    }
                while(1);


使用特权

评论回复
评论
wooda 2021-4-22 07:29 回复TA
工程文件打包给下,我也来试试。。。 
7
panxiaoyi| | 2021-4-21 16:59 | 只看该作者
第3行是简单的函数调用,out=x;是对寄存器赋值,全部都是 unsigned char 变量,怎么PIC就这么慢?

使用特权

评论回复
8
奔波儿熊| | 2021-4-21 17:50 | 只看该作者
panxiaoyi 发表于 2021-4-21 16:59
第3行是简单的函数调用,out=x;是对寄存器赋值,全部都是 unsigned char 变量,怎么PIC就这么慢? ...

比比看两边的汇编指令条数

使用特权

评论回复
9
wooda| | 2021-4-22 07:26 | 只看该作者
这个有点意思,要不你把工程打包发过来看看?
这个测试是有意义的。要么是搞清楚芯片性能,要么是搞清楚代码如何能发挥芯片性能,要么是搞清楚不同指令集的差异,总之能对如何获得更佳的实现效果有帮助。

使用特权

评论回复
10
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引脚这里。
TestSample.rar (635.64 KB)

使用特权

评论回复
11
panxiaoyi| | 2021-4-22 12:11 | 只看该作者
这个是51的代码,PIC的稍后
//
#define          ALLOCATE_EXTERN
#include "HC89F0541.h"
#include "BIT.h"
#include "FONT0805.h"
#include "DELAY_LONG.h"
#include "MCUIIC.h"
#include "SH1106.h"

#define out P1

unsigned int i, n;
unsigned char x, a;

unsigned char test(unsigned char dat)
{
  unsigned char y;
  y=dat;
  return y;
}


void TIMER3_ISR(void) interrupt 10
{
        n++;
        P2_7 =1;                            //LED亮
        WDTC |= 0x10;                       //看门狗清零
        OLED_gotoxy(71,3);                  //显示时间
  OLED_show(n);
        P2_7 =0;
  if(a)                               //显示:程序在1600K个CPU时钟里运行for()语句的次数
  {
    a=0;
    OLED_gotoxy(35,3);
    OLED_show(i);
  }
}

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

  OLED_clear();
  OLED_gotoxy(14,1);
  OLED_string("HC8051 ==> SH1106");
        OLED_gotoxy(11,5);
        OLED_string("21IC.COM PANXIAOYI");
       
  EA = 1;                                                                               //打开总中断
       
        T3CON=0;
        T3CON B5H;  T3CON B4H;               //计数时钟=Fosc/256分频
        TH3 = 0xE7; TL3 = 0x96;                                  //消耗时钟=(65536-0xE796)*256分频=1600K,即中断时间是100ms
  ET3 = 1;                                                                       //打开T3中断
        T3CON B2H;                           //启动定时器
       
        a=1;
  i=1;
        n=0;
       
  while(1)
  {
    for(i=0; i<65535; i++)             //全部语句可以运行8988次
    {
      x=test(37);                      //注释这条可以运行9580次
      out=x;
            
      if(x>47) x=57; else x=67;        //注释这条可以运行9998次
      out=x;
            
      x<<=1;                           //注释这条可以运行9248次
      out=x;
            
      x>>=1;                           //注释这条可以运行9248次
      out=x;
            
      x|=1;                            //注释这条可以运行9142次
      out=x;
            
      x&=1;                            //注释这条可以运行9142次
      out=x;
            
      x=~x;                            //注释这条可以运行9142次
      out=x;
            
      x=x^1;                           //注释这条可以运行9142次
      out=x;
            
      x+=1;                            //注释这条可以运行9090次
      out=x;
            
      x-=1;                            //注释这条可以运行9090次
      out=x;
            
      x*=3;                            //注释这条可以运行9523次
      out=x;
            
      x/=3;                            //注释这条可以运行9523次
      out=x;
            
      x%=3;                            //注释这条可以运行9638次
      out=x;
    }
                while(1);
  }
}


HC89F0541运行速度测试.rar

272.06 KB

使用特权

评论回复
12
panxiaoyi| | 2021-4-22 12:20 | 只看该作者
这个是 PIC18F24Q10 的代码,全部语句运行只有1677次
//
#include "Configuration.h"
#include <xc.h>

#include "BIT.h"
#include "DELAY_LONG.h"
#include "FONT0805.h"
#include "MCUIIC.h"
#include "SH1106.h"

#define out LATA

unsigned int i, n;
unsigned char x, a;


unsigned char test(unsigned char dat)
{
    unsigned char y;
    y=dat;
    return y;
}



void __interrupt() isr(void)
{
    TMR0IF=0;                           //清零中断位
        n++;
        OLED_gotoxy(71,3);                  //显示时间
    OLED_show(n);
    if(a)                               //显示:程序在1600K个CPU时钟里运行for()语句的次数
   {
        a=0;
        OLED_gotoxy(35,3);
        OLED_show(i);
    }

}

void main(void)
{
    IIC_init();
    OLED_init();
    OLED_clear();
    OLED_gotoxy(11,1);
    OLED_string("PIC18F26K83>SH1106");
    OLED_gotoxy(11,5);
    OLED_string("21IC.COM PANXIAOYI");

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

    T0CON1=64+13;                      //时钟源=Fosc/4,8192预分频
    TMR0H=195;                         //8位计时的周期值
    TMR0IE=1;                          //中断使能,速度=16M/(8192*195)=10次/秒
    T0CON0|=0x80;                      //TMR0 使能位
       
    a=1;
    i=1;
        n=0;
       
    while(1)                                 //下面这些是 51 单片机的数据
    {
        for(i=0; i<65535; i++)               //全部语句可以运行8988次
        {
            x=test(37);                      //注释这条可以运行9580次
            out=x;
            
            if(x>47) x=57; else x=67;        //注释这条可以运行9998次
            out=x;
            
            x<<=1;                           //注释这条可以运行9248次
            out=x;
            
            x>>=1;                           //注释这条可以运行9248次
            out=x;
            
            x|=1;                            //注释这条可以运行9142次
            out=x;
            
            x&=1;                            //注释这条可以运行9142次
            out=x;
            
            x=~x;                            //注释这条可以运行9142次
            out=x;
            
            x=x^1;                           //注释这条可以运行9142次
            out=x;
            
            x+=1;                            //注释这条可以运行9090次
            out=x;
            
            x-=1;                            //注释这条可以运行9090次
            out=x;
            
            x*=3;                            //注释这条可以运行9523次
            out=x;
            
            x/=3;                            //注释这条可以运行9523次
            out=x;
            
            x%=3;                            //注释这条可以运行9638次
            out=x;
       }
           while(1);
    }
}



微信图片_20210422122012.jpg (186.73 KB )

微信图片_20210422122012.jpg

PIC18F24Q10.rar

169.87 KB

使用特权

评论回复
13
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 官网下载,这个我也没有设置任何优化,也没有搞过这个东西

使用特权

评论回复
14
wooda| | 2021-4-22 21:06 | 只看该作者
你的代码我编译后,运行 ,timer0中断没发生,运行到107行while1时候a还是1
当然我没有硬件,是用软件模拟器的,不过这种纯内部寄存器的模拟,不太可能有错误。
看了你的代码
感觉2个部分可能有问题
1,尽量不要用a,i,这样的变量名,改成aaa都比a要好。
2,初始化没有初始化时钟,这个可能有问题
3,中断初始化最后再开GIEH=1;   否则再设定的时候很容易触发触发不必要的中断进入
4,为啥要GIEL=1;  

使用特权

评论回复
15
panxiaoyi| | 2021-4-23 00:27 | 只看该作者
试试这个看看?

PIC18F26K83性能测试.rar

389.49 KB

使用特权

评论回复
16
panxiaoyi| | 2021-4-23 00:31 | 只看该作者
我上面的代码都是在实验板上测试过的,它们都是在中断里面闪烁LED和中断显示时间的,如上面的图。下面的代码也是基本一样的,运行次数1655

PIC18F26K83性能测试.rar

389.49 KB

使用特权

评论回复
17
panxiaoyi| | 2021-4-23 00:36 | 只看该作者
2,初始化没有初始化时钟,这个可能有问题
请问在配置字里面设置了64M,是不是这样还不够?我真的不懂喔

使用特权

评论回复
18
panxiaoyi| | 2021-4-23 00:56 | 只看该作者
请问是不是要加上 OSCFRQ=8; 这个语句?改变这个值的确会改变LED的闪烁速度,但是 for() 运行次数还是不变,也可以这样理解:速度=16M/(8192*195)=10次,也就是CPU运行16M次,中断就产生了10次,然后第一次中断就发现for()运行了1677次

使用特权

评论回复
19
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的话,更加简单一些,比较容易理解和入门。

各位围观的兄弟们如果有条件,也可以在开发板上跑一下。毕竟软件模拟结果可靠性不如硬件跑起来更加有说服力。

使用特权

评论回复
20
panxiaoyi| | 2021-4-23 12:05 | 只看该作者
是啊,随便一个PIC芯片都可以测试,只需要测试for()语句就可以了,我毕竟是个PIC的入门者,也是个电子爱好者而已,技术有限,E文就更不用提了,就是一个字,差。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

102

主题

227

帖子

0

粉丝