Help needed:- what's the quickest way to store 256 bytes of data?
2006-02-13 by thekenhunt
Yahoo Groups archive
Index last updated: 2026-04-28 22:41 UTC
Thread
2006-02-13 by thekenhunt
I have an application which needs to store 256 bytes of data. My
current (C) solution is way too slow. Could anyone point me to the
fastest way to go about reading a fixe number of bytes into an
array/memory location using assembler? ie how can I replace the loop
below most efficiently.
char mydata[256];
void myloop()
{
for(d=256;d;d--) mydata[d]=PIND;
}
many thanks
Ken2006-02-13 by kernels_nz
Hi Ken,
Im a C user myself, so I can only think of 3 possible answers. . .
1. Try using a higher clock speed.
2. if you had :
mydata[0] = PIND;
mydata[1] = PIND;
mydata[2] = PIND;
.
.
.
mydata[255] = PIND;
all written out the hard way like that, it would be slightly faster,
because the "for" loop condition would not be checked every time, it
would of course occupy much more code space, and be considered
terrible programming.
I dont believe that assembler can do it much faster than option 2 tho.
3. Look around and see if there are any flash memory ICs that have 8
bit parallel data in, and a line that only need to be clocked to save
that data to the next address in memory, then read it out at your
leasure. (Dont personally know of any IC like this, maybe someone else
has used something like this ?)
Cheers
Hein B
Auckland, New Zealand.
--- In AVR-Chat@yahoogroups.com, "thekenhunt" <kenhunt@...> wrote:>
> I have an application which needs to store 256 bytes of data. My
> current (C) solution is way too slow. Could anyone point me to the
> fastest way to go about reading a fixe number of bytes into an
> array/memory location using assembler? ie how can I replace the loop
> below most efficiently.
>
> char mydata[256];
> void myloop()
> {
> for(d=256;d;d--) mydata[d]=PIND;
> }
>
> many thanks
>
> Ken
>2006-02-13 by John Samperi
At 04:26 AM 14/02/2006, you wrote:
>fastest way to go about reading a fixe number of bytes into an
>array/memory location using assembler?
>
>char mydata[256];
>void myloop()
> {
> for(d=256;d;d--) mydata[d]=PIND;
> }
ldi xl,low(mydata)
ldi xh,high(mydata) ;use x as pointer
clr counter ;use any 8 bit register
cpy_loop:
in data_reg,pind ;use any 8 bit register for data
st x+,data_reg ;save data with post increment
dec counter
brne cpy_loop ;exit when 8 bit counter reaches 0 again
Regards
John Samperi
********************************************************
Ampertronics Pty. Ltd.
11 Brokenwood Place Baulkham Hills, NSW 2153 AUSTRALIA
Tel. (02) 9674-6495 Fax (02) 9674-8745
Email: john@ampertronics.com.au
Website http://www.ampertronics.com.au
*Electronic Design * Custom Products * Contract Assembly
********************************************************2006-02-13 by thekenhunt
John Many thanks for the reply - Just tested it out and it works a treat. cheers Ken --- In AVR-Chat@yahoogroups.com, John Samperi <samperi@...> wrote:
>
> At 04:26 AM 14/02/2006, you wrote:
> >fastest way to go about reading a fixe number of bytes into an
> >array/memory location using assembler?
> >
> >char mydata[256];
> >void myloop()
> > {
> > for(d=256;d;d--) mydata[d]=PIND;
> > }
>
> ldi xl,low(mydata)
> ldi xh,high(mydata) ;use x as pointer
> clr counter ;use any 8 bit register
>
> cpy_loop:
> in data_reg,pind ;use any 8 bit register for data
> st x+,data_reg ;save data with post increment
> dec counter
> brne cpy_loop ;exit when 8 bit counter reaches 0 again
>
> Regards
>
> John Samperi
>
> ********************************************************
> Ampertronics Pty. Ltd.
> 11 Brokenwood Place Baulkham Hills, NSW 2153 AUSTRALIA
> Tel. (02) 9674-6495 Fax (02) 9674-8745
> Email: john@...
> Website http://www.ampertronics.com.au
> *Electronic Design * Custom Products * Contract Assembly
> ********************************************************
>2006-02-13 by thekenhunt
Ned Many thanks for the feedback. I think 3 cycles/byte is about as good as it gets.. 8o) cheers Ken --- In AVR-Chat@yahoogroups.com, Ned Konz <bikenomad@...> wrote:
>
>
> On Feb 13, 2006, at 9:26 AM, thekenhunt wrote:
>
> > I have an application which needs to store 256 bytes of data. My
> > current (C) solution is way too slow. Could anyone point me to the
> > fastest way to go about reading a fixe number of bytes into an
> > array/memory location using assembler? ie how can I replace the loop
> > below most efficiently.
> >
> > char mydata[256];
> > void myloop()
> > {
> > for(d=256;d;d--) mydata[d]=PIND;
> > }
> >
>
> Well, the first byte you're storing is past the end of mydata[],
> and you're storing from the end to the beginning.
>
> Assuming that you wanted to store entirely inside mydata[],
> this is the output from gcc 4.0.2 with -O2:
>
> 7:test3.c **** void myloop(void)
> 8:test3.c **** {
> 74 .LM0:
> 75 /* prologue: frame size=0 */
> 76 /* prologue end (size=0) */
> 77 0000 E0E0 ldi r30,lo8(mydata+255)
> 78 0002 F0E0 ldi r31,hi8(mydata+255)
> 79 .L2:
> 80 .LBB2:
> 9:test3.c **** for(unsigned char d=255;d;d--)
> 10:test3.c **** mydata[d]=PIND;
> 82 .LM1:
> 83 0004 80B3 in r24,48-0x20
> 84 0006 8083 st Z,r24
> 85 0008 3197 sbiw r30,1
> 87 .LM2:
> 88 000a 80E0 ldi r24,hi8(mydata)
> 89 000c E030 cpi r30,lo8(mydata)
> 90 000e F807 cpc r31,r24
> 91 0010 C9F7 brne .L2
>
> That would be 1+2+2+1+1+2 = 9 cycles / byte
>
> And using a pre-decremented pointer helps a little bit:
>
>
> 7:test3.c **** void myloop(void)
> 8:test3.c **** {
> 74 .LM0:
> 75 /* prologue: frame size=0 */
> 76 /* prologue end (size=0) */
> 77 0000 E0E0 ldi r30,lo8(mydata+256)
> 78 0002 F0E0 ldi r31,hi8(mydata+256)
> 79 .L2:
> 9:test3.c **** char* p=mydata+256;
> 10:test3.c ****
> 11:test3.c **** do
> 12:test3.c **** {
> 13:test3.c **** *--p=PIND;
> 81 .LM1:
> 82 0004 80B3 in r24,48-0x20
> 83 0006 8293 st -Z,r24
> 14:test3.c **** }
> 15:test3.c **** while (p >= mydata);
> 85 .LM2:
> 86 0008 80E0 ldi r24,hi8(mydata)
> 87 000a E030 cpi r30,lo8(mydata)
> 88 000c F807 cpc r31,r24
> 89 000e D0F7 brsh .L2
>
> For 1+2+1+1+1+2 = 8 cycles/byte
>
> Of course, you could always unroll the loop:
>
> 7:test3.c **** void myloop(void)
> 8:test3.c **** {
> 74 .LM0:
> 75 /* prologue: frame size=0 */
> 76 /* prologue end (size=0) */
> 9:test3.c **** mydata[255] = PIND;
> 78 .LM1:
> 79 0000 80B3 in r24,48-0x20
> 80 0002 8093 0000 sts mydata+255,r24
> 10:test3.c **** mydata[254] = PIND;
> 82 .LM2:
> 83 0006 80B3 in r24,48-0x20
> 84 0008 8093 0000 sts mydata+254,r24
> 11:test3.c **** mydata[253] = PIND;
> 86 .LM3:
> 87 000c 80B3 in r24,48-0x20
> 88 000e 8093 0000 sts mydata+253,r24
>
> I can't imagine it getting much faster than that.
>
> That would be 3 cycles / byte
> * 256 = 768 cycles for 256 bytes.
>
> It's also 768 words (1536 bytes) of code, but you wanted fast...
>
> --
> Ned Konz
> ned@...
>2006-02-13 by Ned Konz
On Feb 13, 2006, at 9:26 AM, thekenhunt wrote:
> I have an application which needs to store 256 bytes of data. My
> current (C) solution is way too slow. Could anyone point me to the
> fastest way to go about reading a fixe number of bytes into an
> array/memory location using assembler? ie how can I replace the loop
> below most efficiently.
>
> char mydata[256];
> void myloop()
> {
> for(d=256;d;d--) mydata[d]=PIND;
> }
>
Well, the first byte you're storing is past the end of mydata[],
and you're storing from the end to the beginning.
Assuming that you wanted to store entirely inside mydata[],
this is the output from gcc 4.0.2 with -O2:
7:test3.c **** void myloop(void)
8:test3.c **** {
74 .LM0:
75 /* prologue: frame size=0 */
76 /* prologue end (size=0) */
77 0000 E0E0 ldi r30,lo8(mydata+255)
78 0002 F0E0 ldi r31,hi8(mydata+255)
79 .L2:
80 .LBB2:
9:test3.c **** for(unsigned char d=255;d;d--)
10:test3.c **** mydata[d]=PIND;
82 .LM1:
83 0004 80B3 in r24,48-0x20
84 0006 8083 st Z,r24
85 0008 3197 sbiw r30,1
87 .LM2:
88 000a 80E0 ldi r24,hi8(mydata)
89 000c E030 cpi r30,lo8(mydata)
90 000e F807 cpc r31,r24
91 0010 C9F7 brne .L2
That would be 1+2+2+1+1+2 = 9 cycles / byte
And using a pre-decremented pointer helps a little bit:
7:test3.c **** void myloop(void)
8:test3.c **** {
74 .LM0:
75 /* prologue: frame size=0 */
76 /* prologue end (size=0) */
77 0000 E0E0 ldi r30,lo8(mydata+256)
78 0002 F0E0 ldi r31,hi8(mydata+256)
79 .L2:
9:test3.c **** char* p=mydata+256;
10:test3.c ****
11:test3.c **** do
12:test3.c **** {
13:test3.c **** *--p=PIND;
81 .LM1:
82 0004 80B3 in r24,48-0x20
83 0006 8293 st -Z,r24
14:test3.c **** }
15:test3.c **** while (p >= mydata);
85 .LM2:
86 0008 80E0 ldi r24,hi8(mydata)
87 000a E030 cpi r30,lo8(mydata)
88 000c F807 cpc r31,r24
89 000e D0F7 brsh .L2
For 1+2+1+1+1+2 = 8 cycles/byte
Of course, you could always unroll the loop:
7:test3.c **** void myloop(void)
8:test3.c **** {
74 .LM0:
75 /* prologue: frame size=0 */
76 /* prologue end (size=0) */
9:test3.c **** mydata[255] = PIND;
78 .LM1:
79 0000 80B3 in r24,48-0x20
80 0002 8093 0000 sts mydata+255,r24
10:test3.c **** mydata[254] = PIND;
82 .LM2:
83 0006 80B3 in r24,48-0x20
84 0008 8093 0000 sts mydata+254,r24
11:test3.c **** mydata[253] = PIND;
86 .LM3:
87 000c 80B3 in r24,48-0x20
88 000e 8093 0000 sts mydata+253,r24
I can't imagine it getting much faster than that.
That would be 3 cycles / byte
* 256 = 768 cycles for 256 bytes.
It's also 768 words (1536 bytes) of code, but you wanted fast...
--
Ned Konz
ned@bike-nomad.com2006-02-14 by Ned Konz
On Feb 13, 2006, at 11:31 AM, kernels_nz wrote:
> 2. if you had :
>
> mydata[0] = PIND;
> mydata[1] = PIND;
> mydata[2] = PIND;
> .
> .
> .
> mydata[255] = PIND;
>
> all written out the hard way like that, it would be slightly faster,
> because the "for" loop condition would not be checked every time, it
> would of course occupy much more code space, and be considered
> terrible programming.
Yes, but there's still a middle way, which is partial unrolling:
#define ATONCE 8
uint8_t mydata[256];
void myloop(void)
{
uint8_t *p = mydata;
for (uint8_t counter = sizeof(mydata) / ATONCE; counter--; p +=
ATONCE)
{
p[0] = PIND;
p[1] = PIND;
p[2] = PIND;
p[3] = PIND;
p[4] = PIND;
p[5] = PIND;
p[6] = PIND;
p[7] = PIND;
}
}
which results in (with avr-gcc 4.0 and -O2):
9:test3.c **** void myloop(void)
10:test3.c **** {
74 .LM0:
75 /* prologue: frame size=0 */
76 /* prologue end (size=0) */
77 0000 E0E0 ldi r30,lo8(mydata)
78 0002 F0E0 ldi r31,hi8(mydata)
79 .L2:
80 .LBB2:
11:test3.c **** uint8_t *p = mydata;
12:test3.c **** for (uint8_t counter = sizeof(mydata) /
ATONCE; counter--; p += ATONCE)
13:test3.c **** {
14:test3.c **** p[0] = PIND;
82 .LM1:
83 0004 80B3 in r24,48-0x20
84 0006 8083 st Z,r24
15:test3.c **** p[1] = PIND;
86 .LM2:
87 0008 80B3 in r24,48-0x20
88 000a 8183 std Z+1,r24
16:test3.c **** p[2] = PIND;
90 .LM3:
91 000c 80B3 in r24,48-0x20
92 000e 8283 std Z+2,r24
... etc ...
21:test3.c **** p[7] = PIND;
110 .LM8:
111 0020 80B3 in r24,48-0x20
112 0022 8783 std Z+7,r24
114 .LM9:
115 0024 3896 adiw r30,8 ; 2
116 0026 80E0 ldi r24,hi8(mydata+256) ; 1
117 0028 E030 cpi r30,lo8(mydata+256) ; 1
118 002a F807 cpc r31,r24 ; 1
119 002c 59F7 brne .L2 ; 2
As a result, you amortize the cost of lines 115-119 (7 cycles) over 8
bytes of transfer.
For a cost/byte transferred of 3+7/8 cycles.
--
Ned Konz
ned@bike-nomad.com2006-02-14 by Peter Harrison
And there is Duff's device (Google is your friend here) for the more
general case where the count is neither 8 bits nor a multiple of 8:
count = 256;
uint8_t *to = mydata;
register int n = (count + 7) / 8; /* count > 0 assumed */
switch (count % 8)
{
case 0: do { *to++ = PIND;
case 7: *to++ = PIND;
case 6: *to++ = PIND;
case 5: *to++ = PIND;
case 4: *to++ = PIND;
case 3: *to++ = PIND;
case 2: *to++ = PIND;
case 1: *to++ = PIND;
} while (--n > 0);
}
Which compiles, with GCC3.4.5 and -Os, to give:
count = 256;
uint8_t *to = mydata;
136: e2 e6 ldi r30, 0x62 ; 98
138: f0 e0 ldi r31, 0x00 ; 0
register int n = (count + 7) / 8; /* count > 0 assumed */
13a: 20 e2 ldi r18, 0x20 ; 32
13c: 30 e0 ldi r19, 0x00 ; 0
switch (count % 8)
{
case 0: do { *to++ = PIND;
13e: 80 b3 in r24, 0x10 ; 16
140: 81 93 st Z+, r24
case 7: *to++ = PIND;
142: 80 b3 in r24, 0x10 ; 16
144: 81 93 st Z+, r24
case 6: *to++ = PIND;
146: 80 b3 in r24, 0x10 ; 16
148: 81 93 st Z+, r24
case 5: *to++ = PIND;
14a: 80 b3 in r24, 0x10 ; 16
14c: 81 93 st Z+, r24
case 4: *to++ = PIND;
14e: 80 b3 in r24, 0x10 ; 16
150: 81 93 st Z+, r24
case 3: *to++ = PIND;
152: 80 b3 in r24, 0x10 ; 16
154: 81 93 st Z+, r24
case 2: *to++ = PIND;
156: 80 b3 in r24, 0x10 ; 16
158: 81 93 st Z+, r24
case 1: *to++ = PIND;
15a: 80 b3 in r24, 0x10 ; 16
15c: 81 93 st Z+, r24
} while (--n > 0);
15e: 21 50 subi r18, 0x01 ; 1
160: 30 40 sbci r19, 0x00 ; 0
162: 12 16 cp r1, r18
164: 13 06 cpc r1, r19
166: 5c f3 brlt .-42 ; 0x13e <myloop+0x6c>
168: 08 95 ret
I have to dash to work so I have not checked the cycle count and such
but it looks pretty good to me.
Pete Harrison