Microchip
直播中

向珍

7年用户 294经验值
私信 关注
[问答]

XC8从不使用POSTINC

大多数PIC18(如果不是全部)有一个惊人的寄存器称为PoStic(除此之外),但XC8似乎永远不会使用它。通过这个,MCU可以在一个指令中移动数据并自动增加一个16位指针。XC8使用大量的指令来做同样的操作:将地址复制到FSR对,移动数据并增加变量。乘以循环总数和……你得到一个非常低效的代码。有没有办法“强制”XC8使用这个寄存器?在汇编中必须编写所有代码?

以上来自于百度翻译


      以下为原文

    Most of the PIC18 (if not all) have an amazing register called POSTINC (among others), but XC8 seems to never use it.
With this the MCU can move data and automatically increment a 16-bit pointer in a single instruction. Very useful for data transmit loops.
XC8 uses a lot of instructions to do the same: copy the address to the FSR pair, move the data and increment the variable.
Multiplying this for the total number of loops and...you get a very inefficient code.

Is there a way to "force" XC8 to use this register (without having to write all the code in assembly)?

回帖(11)

李涛

2018-10-15 16:07:37
这是它处理间接寻址的方法,包括PoST或Pro,而不是在指令集中。没有什么了不起的,只有1个寄存器是低效的,这就是为什么我不再使用8位芯片。不知道强制编译器这样做,也许一个付费编译器会这么做。就像你的SAI一样。使用汇编程序。

以上来自于百度翻译


      以下为原文

    It's the way it handles indirect addressing including post/pre, just not in the instruction set.
Nothing really amazing, it's inefficient only having 1 register, that's why I don't use 8bit chips anymore.
 
Don't know about forcing the compiler to do that, maybe a paid compiler would do it.
 
Like you said, use the assembler.
举报

李铭鑫

2018-10-15 16:13:02
您好,XC8编译器使用的是哪种许可证?自由模式或Pro模式。在自由模式下有很多优化,如果你还没有做过的话,有可能尝试2个月的最大优化。你不必在程序集中编写所有代码,只需要那些真正重要的部分。你可以完全编写一个函数。程序集,你可以在C中写一个函数条目和完成,并用一大块汇编代码填充它,或者你可以在C代码中加入汇编指令。注意,在C代码中加入汇编指令,如果没有C编译器知道发生了什么,可能会导致错误。例如改变FSR寄存器。R内容,而不是恢复原始值,可能会导致以下代码中的错误。这里是一个在C函数中封装的汇编代码的例子,它已经用于连接的交流测量和PIC16和PIC18上的RMS平均计算。

以上来自于百度翻译


      以下为原文

    Hi,
Which kind of license for XC8 compiler are you using? Free  or Pro mode.
There are a lot of optimizations not done in Free mode,
 
There is a possibility to try out maximum optimizations for 2 months, if you haven't done so already.
You don't have to write all the code in assembly, only those parts where it really matter.
You may write a function entirely in assembly,
You may write a function entry and completion in C and fill it with a big block of assembly code,
or you may put in assembly instructions in C code.
 
Be careful, putting in assembly instructions in C code, without C compiler knowing what is going on, 
may cause errors.
E.g.  changing  FSR register contents, and not restoring the original value, may cause error in following code.
 
Here is an example of assembly code wrapped in a C function, it have been used in connection AC measurements and RMS average calculations on PIC16 and PIC18.:
/*
 *  PIC16, PIC18
 *    Calculate average from a running accumulator  Avg = Avg >> 10;
 *    Modified from code contributed on Microchip forum by "co_worker"
 *  containing suggestions from "1and0" and "andig"
 *  Microchip Forum http://www.microchip.com/forums/FindPost/848067
 */
#include
#include

#define IN_ASM
#ifndef     Avgshift
    #define Avgshift    10
#endif
/*
 * Unsigned integer shift
 *
 *   Result = Arg >> 10;
 *
 * Parameters:
 *   a = 24-bit unsigned integer accumulating samples.
 *
 * Return Value:
 *   The function returns a 16-bit unsigned integer Result.
 *
 * Program Memory:
 *   20 instructions including call and return
 *
 * Execution Time:
 *   14 cycles excluding the call (prolog) and return (epilog).
 *
 * Remarks:
 *
 *
 * History:
 *      2016-05-04                            - by Arne Bergseth "Mysil"
 */
uint16_t uShift_24_10(uint24_t Arg)
{
    uint16_t Result = 0;    /* Zero to make compiler happy, */
                             /* zeroing may be omitted if compiler warning is acceptable. */
#if defined(IN_C)
    result  = a >> avgshift;
#endif

#if defined(IN_ASM) /* ? instructions, ? cycles, ? avg ? to be tested. */
/*
 * Ma.
 *
 * rh:rl = (au:ah:al >> 10)
 *
 */
#asm
#ifdef _PIC18
    #define rh (uShift_24_10@Result+1)
    #define rl (uShift_24_10@Result)
    #define au (uShift_24_10@Arg+2)
    #define ah (uShift_24_10@Arg+1)
    #define al (uShift_24_10@Arg)

#elif  _PIC14 || _PIC14E
    #define rh (uShift_24_10@Result+1)&0x7F
    #define rl (uShift_24_10@Result)&0x7F
    #define au (uShift_24_10@Arg+2)&0x7F
    #define ah (uShift_24_10@Arg+1)&0x7F
    #define al (uShift_24_10@Arg)&0x7F
#endif
    BANKSEL(uShift_24_10@Arg)
                    /*    rh:rl = au:ah >> 1    Do 8 bit shift by picking bytes
                     *                            then 1 bit shift by instruction */
    bcf        STATUS,0    /* clear the carry bit. */
#if (Avgshift == 8)        /* Do 8 bit shift by picking bytes . */
    movf    au,W
    movwf    rh
    movf    ah,W
    movwf    rl
#elif (Avgshift > 8)    /* then 1 bit shift by instruction. */
    rrcf     au,W        /* Move from Au into W */
    movwf    rh            /* store in Rh */
    rrcf    ah,W
    movwf    rl
#endif
#if (Avgshift == 10)    /* ru:rh:rl = ru:rh:rl >> 1 */
    clrc                /* one more rotation for 10 bit shift */
    rrcf    rh,F
    rrcf    rl,F        /* Shift into rl from the carry bit */
//    rrcf    rl,W        ;/* may use W for this. */
#else
    movf    rl,W        /* start with low byte */
#endif  

#endasm
#endif
    return Result;

 
Regards,
   Mysil
举报

李涛

2018-10-15 16:21:26
得到一个16位芯片。添加x,[y++],[-Z]

以上来自于百度翻译


      以下为原文

    Get a 16bit chip.
 
add x,[y++],[--z]
举报

邹先莹

2018-10-15 16:36:46
我不认为XC8将编译一个16位的ChIPWink:我最后写了C和汇编的混合。效率提高了很多,但是代码可读性却呈指数下降,在编译器中重用FSR对的内容(在PRO模式下),在所有程序中找不到一个点。但是我知道手册警告这一点。下面是我做的一个例子。原始C代码:混合1:MIX2:用模拟器运行代码给出了以下结果(我必须注释“For(FLAG)”,因为SPI模块的这一部分在模拟器中没有实现):IFTXLEN=1(1循环):C:20 Cy;Mix1:18 Cy;Mix2:16 CyftxLeN=10(10个循环):C:146 Cy;Mix1:81 Cy;MIX2:70 Cy*Cy指令Cyrimix2是我能够做到的最优化的版本。最小化最后一次传输到结束的等待和下一次传输之间的指令数目。

以上来自于百度翻译


      以下为原文

   
I don't think XC8 will compile for a 16-bit chip wink:
 
Well I ended up writing a mix of C and assembly. The efficiency increases a lot, but code readability decreases exponentially.

I could not find a single point in all program where the compiler reuses the contents of the FSR pair (in PRO mode). But I know the manual warns about this.
 
Here is an example of what I did.
Original C code:
for (i = 0; i < txLen; i++)
{
 PIR1bits.SSP1IF = 0;
 SSP1BUF = txBuffer;
 while (PIR1bits.SSP1IF == 0);
}
 
Mix 1:
 i = txLen + 1;
#asm
 MOVLW low(_txBuffer)
 MOVWF FSR2, C
 MOVLW high(_txBuffer)
 MOVWF FSR2H, C;
#endasm
 while (--i)
 {
  PIR1bits.SSP1IF = 0;
#asm
  MOVFF POSTINC2, SSP1BUF;
#endasm
  while (PIR1bits.SSP1IF == 0);
 }
 
Mix2:
 if (txLen)
 {
  i = txLen;
#asm
  MOVLW low(_txBuffer)
  MOVWF FSR2, C
  MOVLW high(_txBuffer)
  MOVWF FSR2H, C;
#endasm
  PHY_CS = 0;
#asm
  goto asm_send;
#endasm
  do
  {
   while (SSP1STATbits.BF == 0);
   SSP1BUF; // Clear BF bit
#asm
asm_send:
   MOVFF POSTINC2, SSP1BUF;
#endasm
  } while (--i);
  while (SSP1STATbits.BF == 0);
 }
 
Running the code with the simulator gives the following results (I had to comment out the "while(flag);", because this part of the SPI module is not implement in the simulator):
If txLen = 1 (1 loop):
  C: 20 cy; Mix1: 18 cy; Mix2: 16 cy
If txLen = 10 (10 loops):
  C: 146 cy; Mix1: 81 cy; Mix2: 70 cy
*cy - instruction cycle
 
Mix 2 is the most optimized version that I was able to do. The number of instructions between the wait for the last transfer to finish and the next transfer are minimized.
举报

更多回帖

×
20
完善资料,
赚取积分