CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Eye opening realization about arrays

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
newguy



Joined: 24 Jun 2004
Posts: 1903

View user's profile Send private message

Eye opening realization about arrays
PostPosted: Sat Jul 15, 2017 1:22 pm     Reply with quote

So yesterday I got done a project ("done" = it works) but I was not happy at all about the memory usage. This is with v5.073 by the way. I did note that the memory utilization was going up alarmingly fast, but I had to simply get it done first and then deal with the memory issue later.

Anyway, I extensively use arrays to group things that make sense, like user buttons, similar sensors, etc. Programming in this manner means that when a customer wants another button or another supported sensor, it's relatively easy to add and support.

Given what Ttelmah in particular has been saying of late about CCS and its handling of arrays, I did note in the disassembly that how they were being handled seemed wasteful at best. I decided to throw together a very simple test program to compare directly accessing array elements and also using pointers to accomplish the same goal. I've posted the program and the disassembly below. All I can say is that come Monday I have some changes to make.... Rolling Eyes

Program:
Code:
#include <18F24K40.h>
#device ADC=10
#use delay(clock=40000000,crystal=10000000)

struct _test {
   int1 flag;
   unsigned int8 data1;
   unsigned int8 data2;
   unsigned int16 big_data;
};

struct _test test_array[4];

unsigned int8 i;

void main(void) {
   
   for (i = 0; i < 4; i++) {
      test_array[i].flag = FALSE;
      test_array[i].data1 = 0;
      test_array[i].data2 = 0;
      test_array[i].big_data = 0;
   }
   
   struct _test *test_pointer1, *test_pointer2;
   
   test_pointer1 = &test_array[0];
   
   test_pointer1->flag = FALSE;
   test_pointer1->data1 = 0;
   test_pointer1->data2 = 0;
   test_pointer1->big_data = 0;
   
   for (i = 0; i < 4; i++) {
      test_pointer1 = &test_array + i;
      test_pointer1->flag = FALSE;
      test_pointer1->data1 = 0;
      test_pointer1->data2 = 0;
      test_pointer1->big_data = 0;
   }
   
   if ((test_array[0].flag) && (test_array[1].flag == FALSE)) {
      test_array[2].flag = FALSE;
   }
   
   test_pointer1 = &test_array;
   test_pointer2 = test_pointer1 + 1;
   
   if ((test_pointer1->flag) && (test_pointer2->flag == FALSE)) {
      test_pointer2++;
      test_pointer2->flag = FALSE;
   }
   
   while (TRUE) {

   }
}


Disassembly:
Code:
.................... #device PIC18F24K40
.................... 
.................... #list
.................... 
.................... #device ADC=10
.................... #use delay(clock=40000000,crystal=10000000)
.................... 
.................... 
.................... 
.................... struct _test {
....................    int1 flag;
....................    unsigned int8 data1;
....................    unsigned int8 data2;
....................    unsigned int16 big_data;
.................... };
.................... 
.................... struct _test test_array[4];
.................... 
.................... unsigned int8 i;
.................... 
.................... void main(void) {
0004:  BSF    NVMCON1.NVMREG1
0006:  BCF    NVMCON1.NVMREG0
0008:  CLRF   TBLPTRU
000A:  BCF    INTCON.IPEN
000C:  MOVLB  E
000E:  CLRF   xDD
0010:  CLRF   xDA
0012:  CLRF   xDC
0014:  CLRF   xDE
0016:  MOVLW  20
0018:  MOVWF  xD8
001A:  MOVLB  F
001C:  CLRF   x11
001E:  CLRF   x19
0020:  CLRF   x21
0022:  CLRF   x3A
0024:  CLRF   x3B
0026:  CLRF   x3C
0028:  CLRF   x39
002A:  CLRF   x36
002C:  CLRF   x37
002E:  CLRF   x38
0030:  CLRF   x35
....................     
....................    for (i = 0; i < 4; i++) {
0032:  CLRF   i
0034:  MOVF   i,W
0036:  SUBLW  03
0038:  BTFSS  STATUS.C
003A:  GOTO   00CC
....................       test_array[i].flag = FALSE;
003E:  MOVF   i,W
0040:  MULLW  05
0042:  MOVF   PRODL,W
0044:  CLRF   @@1E
0046:  MOVWF  @@1D
0048:  MOVLW  test_array
004A:  ADDWF  @@1D,W
004C:  MOVWF  FSR0L
004E:  MOVLW  test_array+-4
0050:  ADDWFC @@1E,W
0052:  MOVWF  FSR0H
0054:  BCF    INDF0.0
....................       test_array[i].data1 = 0;
0056:  MOVF   i,W
0058:  MULLW  05
005A:  MOVF   PRODL,W
005C:  CLRF   @@1E
005E:  MOVWF  @@1D
0060:  MOVLW  01
0062:  ADDWF  @@1D,W
0064:  MOVWF  @01
0066:  MOVLW  00
0068:  ADDWFC @@1E,W
006A:  MOVWF  @03
006C:  MOVF   @01,W
006E:  ADDLW  test_array
0070:  MOVWF  FSR0L
0072:  MOVLW  test_array+-4
0074:  ADDWFC @03,W
0076:  MOVWF  FSR0H
0078:  CLRF   INDF0
....................       test_array[i].data2 = 0;
007A:  MOVF   i,W
007C:  MULLW  05
007E:  MOVF   PRODL,W
0080:  CLRF   @@1E
0082:  MOVWF  @@1D
0084:  MOVLW  02
0086:  ADDWF  @@1D,W
0088:  MOVWF  @01
008A:  MOVLW  00
008C:  ADDWFC @@1E,W
008E:  MOVWF  @03
0090:  MOVF   @01,W
0092:  ADDLW  test_array
0094:  MOVWF  FSR0L
0096:  MOVLW  test_array+-4
0098:  ADDWFC @03,W
009A:  MOVWF  FSR0H
009C:  CLRF   INDF0
....................       test_array[i].big_data = 0;
009E:  MOVF   i,W
00A0:  MULLW  05
00A2:  MOVF   PRODL,W
00A4:  CLRF   @@1E
00A6:  MOVWF  @@1D
00A8:  MOVLW  03
00AA:  ADDWF  @@1D,W
00AC:  MOVWF  @01
00AE:  MOVLW  00
00B0:  ADDWFC @@1E,W
00B2:  MOVWF  @03
00B4:  MOVF   @01,W
00B6:  ADDLW  test_array
00B8:  MOVWF  FSR0L
00BA:  MOVLW  test_array+-4
00BC:  ADDWFC @03,W
00BE:  MOVWF  FSR0H
00C0:  CLRF   PREINC0
00C2:  MOVF   POSTDEC0,F
00C4:  CLRF   INDF0
00C6:  INCF   i,F
00C8:  GOTO   0034
....................    }
....................     
....................    struct _test *test_pointer1, *test_pointer2;
....................     
....................    test_pointer1 = &test_array[0];
00CC:  CLRF   test_pointer1+1
00CE:  MOVLW  test_array
00D0:  MOVWF  test_pointer1
....................     
....................    test_pointer1->flag = FALSE;
00D2:  MOVFF  test_pointer1,FSR0L
00D6:  MOVFF  test_pointer1+1,FSR0H
00DA:  BCF    INDF0.0
....................    test_pointer1->data1 = 0;
00DC:  MOVLW  01
00DE:  ADDWF  test_pointer1,W
00E0:  MOVWF  FSR0L
00E2:  MOVLW  00
00E4:  ADDWFC test_pointer1+1,W
00E6:  MOVWF  FSR0H
00E8:  CLRF   INDF0
....................    test_pointer1->data2 = 0;
00EA:  MOVLW  02
00EC:  ADDWF  test_pointer1,W
00EE:  MOVWF  FSR0L
00F0:  MOVLW  00
00F2:  ADDWFC test_pointer1+1,W
00F4:  MOVWF  FSR0H
00F6:  CLRF   INDF0
....................    test_pointer1->big_data = 0;
00F8:  MOVLW  03
00FA:  ADDWF  test_pointer1,W
00FC:  MOVWF  FSR0L
00FE:  MOVLW  00
0100:  ADDWFC test_pointer1+1,W
0102:  MOVWF  FSR0H
0104:  CLRF   PREINC0
0106:  MOVF   POSTDEC0,F
0108:  CLRF   INDF0
....................     
....................    for (i = 0; i < 4; i++) {
010A:  CLRF   i
010C:  MOVF   i,W
010E:  SUBLW  03
0110:  BTFSS  STATUS.C
0112:  GOTO   0164
....................       test_pointer1 = &test_array + i;
0116:  MOVF   i,W
0118:  MULLW  05
011A:  MOVF   PRODL,W
011C:  ADDLW  test_array
011E:  MOVWF  test_pointer1
0120:  CLRF   test_pointer1+1
0122:  BTFSC  STATUS.C
0124:  INCF   1A,F
....................       test_pointer1->flag = FALSE;
0126:  MOVFF  test_pointer1,FSR0L
012A:  MOVFF  test_pointer1+1,FSR0H
012E:  BCF    INDF0.0
....................       test_pointer1->data1 = 0;
0130:  MOVLW  01
0132:  ADDWF  test_pointer1,W
0134:  MOVWF  FSR0L
0136:  MOVLW  00
0138:  ADDWFC test_pointer1+1,W
013A:  MOVWF  FSR0H
013C:  CLRF   INDF0
....................       test_pointer1->data2 = 0;
013E:  MOVLW  02
0140:  ADDWF  test_pointer1,W
0142:  MOVWF  FSR0L
0144:  MOVLW  00
0146:  ADDWFC test_pointer1+1,W
0148:  MOVWF  FSR0H
014A:  CLRF   INDF0
....................       test_pointer1->big_data = 0;
014C:  MOVLW  03
014E:  ADDWF  test_pointer1,W
0150:  MOVWF  FSR0L
0152:  MOVLW  00
0154:  ADDWFC test_pointer1+1,W
0156:  MOVWF  FSR0H
0158:  CLRF   PREINC0
015A:  MOVF   POSTDEC0,F
015C:  CLRF   INDF0
015E:  INCF   i,F
0160:  GOTO   010C
....................    }
....................     
....................    if ((test_array[0].flag) && (test_array[1].flag == FALSE)) {
0164:  BTFSS  04.0
0166:  GOTO   0172
016A:  BTFSC  09.0
016C:  GOTO   0172
....................       test_array[2].flag = FALSE;
0170:  BCF    test_array+10.0
....................    }
....................     
....................    test_pointer1 = &test_array;
0172:  CLRF   test_pointer1+1
0174:  MOVLW  test_array
0176:  MOVWF  test_pointer1
....................    test_pointer2 = test_pointer1 + 1;
0178:  MOVLW  05
017A:  ADDWF  test_pointer1,W
017C:  MOVWF  test_pointer2
017E:  MOVLW  00
0180:  ADDWFC test_pointer1+1,W
0182:  MOVWF  test_pointer2+1
....................     
....................    if ((test_pointer1->flag) && (test_pointer2->flag == FALSE)) {
0184:  MOVFF  test_pointer1,FSR0L
0188:  MOVFF  test_pointer1+1,FSR0H
018C:  BTFSS  INDF0.0
018E:  GOTO   01B6
0192:  MOVFF  test_pointer2,FSR0L
0196:  MOVFF  test_pointer2+1,FSR0H
019A:  MOVF   INDF0,W
019C:  ANDLW  01
019E:  BTFSS  STATUS.Z
01A0:  GOTO   01B6
....................       test_pointer2++;
01A4:  MOVLW  05
01A6:  ADDWF  test_pointer2,F
01A8:  BTFSC  STATUS.C
01AA:  INCF   test_pointer2+1,F
....................       test_pointer2->flag = FALSE;
01AC:  MOVFF  test_pointer2,FSR0L
01B0:  MOVFF  test_pointer2+1,FSR0H
01B4:  BCF    INDF0.0
....................    }
....................     
....................    while (TRUE) {
01B6:  GOTO   01B6
.................... 
....................    }
.................... }
*
01BA:  SLEEP
Ttelmah



Joined: 11 Mar 2010
Posts: 19236

View user's profile Send private message

PostPosted: Sat Jul 15, 2017 1:46 pm     Reply with quote

That is inherent in the chip and handling an array like this.

Think about it yourself. You want element 3 on row 4 of an array, but with the row number selected by a variable (so you can't pre-calculate the address). So you have to take the size of the row, multiply this by 3, add the address in the row of the third element, then add this to the start of the array. Then use indirect addressing to access the byte at this point.... :(

This is a huge amount of work on any chip, but made worse on the PIC (most processors have instructions to allow direct addressing - the PIC doesn't).

Now you can reduce this by using a pointer and moving this once to the start of the required element, but a large percentage of the overhead involved in indirect addressing still applies... Sad
allenhuffman



Joined: 17 Jun 2019
Posts: 537
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Thu Jan 30, 2020 10:22 am     Reply with quote

This is an eye opener. Thanks for posting the link.
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group