|
|
View previous topic :: View next topic |
Author |
Message |
newguy
Joined: 24 Jun 2004 Posts: 1911
|
Eye opening realization about arrays |
Posted: Sat Jul 15, 2017 1:22 pm |
|
|
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....
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: 19588
|
|
Posted: Sat Jul 15, 2017 1:46 pm |
|
|
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... |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 589 Location: Des Moines, Iowa, USA
|
|
Posted: Thu Jan 30, 2020 10:22 am |
|
|
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 ?
Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002. |
|
|
|
|
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
|