On Mon, Jul 11, 2011 at 1:50 PM, Mahr, Stefan stefan.m...@sphairon.com wrote:
Yes, if BE target shifts out an 32 bit value from address 0, it will
begin with bit0:7, that is byte address 0x03 at targets memory.
And host will do the same. When it shifts out 32-bit value , it will
put contents
BTW,
Stefan and all others,
thank you very much for this long discussion and for the effort on
explaining things. I think it was very useful.
BR,
Drasko
On Tue, Aug 9, 2011 at 11:20 PM, Drasko DRASKOVIC
drasko.drasko...@gmail.com wrote:
On Mon, Jul 11, 2011 at 1:50 PM, Mahr, Stefan
buf_get_u32:
return (((uint32_t)buffer[3]) 24) |
(((uint32_t)buffer[2]) 16) |
(((uint32_t)buffer[1]) 8) |
(((uint32_t)buffer[0]) 0);
I do not get this function at all... What I see is that it is
On Mon, Jul 11, 2011 at 12:17 PM, Drasko DRASKOVIC
drasko.drasko...@gmail.com wrote:
On Mon, Jul 11, 2011 at 7:31 AM, Øyvind Harboe oyvind.har...@zylin.com
wrote:
Now a sequence of 8 bit words happens to be identical to
little endian representation
In what way ? 8 bits is 8 bits - one byte,
On Mon, Jul 11, 2011 at 12:31 PM, Øyvind Harboe oyvind.har...@zylin.com wrote:
On Mon, Jul 11, 2011 at 12:17 PM, Drasko DRASKOVIC
drasko.drasko...@gmail.com wrote:
On Mon, Jul 11, 2011 at 7:31 AM, Øyvind Harboe oyvind.har...@zylin.com
wrote:
Now a sequence of 8 bit words happens to be
On Mon, Jul 11, 2011 at 11:53 AM, Øyvind Harboe oyvind.har...@zylin.com wrote:
I think there is a fundamental misunderstanding about JTAG
and OpenOCD.
Let me try to clarify:
JTAG clocks in and out bits, not bytes, so the concept of
big/small-endian does not enter the picture at the JTAG
Sorry, little mistake:
wrong:
LE host: result = (uint32_t)buffer[0]; // result = 0x78563412 (memory
0x12 0x34 0x56 0x78)
BE host: result = (uint32_t)buffer[0]; // result = 0x12345678 (memory
0x12 0x34 0x56 0x78)
corrected:
LE host: result = *(uint32_t*)buffer[0];// result =
On Mon, Jul 11, 2011 at 12:45 PM, Drasko DRASKOVIC
drasko.drasko...@gmail.com wrote:
On Mon, Jul 11, 2011 at 11:53 AM, Øyvind Harboe oyvind.har...@zylin.com
wrote:
I think there is a fundamental misunderstanding about JTAG
and OpenOCD.
Let me try to clarify:
JTAG clocks in and out bits,
On Mon, Jul 11, 2011 at 12:52 PM, Øyvind Harboe oyvind.har...@zylin.com wrote:
On Mon, Jul 11, 2011 at 12:45 PM, Drasko DRASKOVIC
drasko.drasko...@gmail.com wrote:
On Mon, Jul 11, 2011 at 11:53 AM, Øyvind Harboe oyvind.har...@zylin.com
wrote:
I think there is a fundamental misunderstanding
On Mon, Jul 11, 2011 at 1:10 PM, Drasko DRASKOVIC
drasko.drasko...@gmail.com wrote:
On Mon, Jul 11, 2011 at 12:52 PM, Øyvind Harboe oyvind.har...@zylin.com
wrote:
On Mon, Jul 11, 2011 at 12:45 PM, Drasko DRASKOVIC
drasko.drasko...@gmail.com wrote:
On Mon, Jul 11, 2011 at 11:53 AM, Øyvind
Øyvind Harboe wrote:
Really OpenOCD could have stored the bits as a series of
words larger than bytes in the host representation to be more
efficient.
This would probably be a source of much more confusion :-)
___
Openocd-development mailing list
On Mon, Jul 11, 2011 at 1:30 PM, Øyvind Harboe oyvind.har...@zylin.com wrote:
On Mon, Jul 11, 2011 at 1:10 PM, Drasko DRASKOVIC
drasko.drasko...@gmail.com wrote:
On Mon, Jul 11, 2011 at 12:52 PM, Øyvind Harboe oyvind.har...@zylin.com
wrote:
On Mon, Jul 11, 2011 at 12:45 PM, Drasko DRASKOVIC
When you start shifting out LSB (bit) from the BE host, will you start
shifting out contents of address 0x3, or the address 0x0 ? In my
opinion, it will be content of the addr 0x3 that will be shifted out
first (as it holds bits 0:7 for on the BE host).
Yes, if BE target shifts out an 32 bit
On Mon, Jul 11, 2011 at 1:41 PM, Mahr, Stefan stefan.m...@sphairon.com wrote:
When you start shifting out LSB (bit) from the BE host, will you start
shifting out contents of address 0x3, or the address 0x0 ? In my
opinion, it will be content of the addr 0x3 that will be shifted out
first (as
On Mon, Jul 11, 2011 at 1:43 PM, Drasko DRASKOVIC
drasko.drasko...@gmail.com wrote:
Yes, if BE target shifts out an 32 bit value from address 0, it will
begin with bit0:7, that is byte address 0x03 at targets memory.
And host will do the same. When it shifts out 32-bit value , it will
put
Yes, if BE target shifts out an 32 bit value from address 0, it will
begin with bit0:7, that is byte address 0x03 at targets memory.
And host will do the same. When it shifts out 32-bit value , it will
put contents of it's address 0x3 to output buffer[0] and send this
first.
I am talking
On Sat, Jul 9, 2011 at 10:44 AM, Mahr, Stefan stefan.m...@sphairon.com wrote:
How do they convert then, when they do not know from which endianes to
convert from ?
Conversion is done from byte array of jtag chain.
How ?
buf_get_u32 does conversion from uint8* array
example:
buf_get_u32:
return (((uint32_t)buffer[3]) 24) |
(((uint32_t)buffer[2]) 16) |
(((uint32_t)buffer[1]) 8) |
(((uint32_t)buffer[0]) 0);
I do not get this function at all... What I see is that it is
How do they convert then, when they do not know from which endianes to
convert from ?
Conversion is done from byte array of jtag chain.
How ?
buf_get_u32 does conversion from uint8* array
example:
mips_ejtag_get_impcode (mips_ejtag.c)
field.in_value is filled by jtag_add_dr_scan with
On Fri, Jul 8, 2011 at 11:43 AM, Drasko DRASKOVIC
drasko.drasko...@gmail.com wrote:
On Thu, Jul 7, 2011 at 11:58 AM, Øyvind Harboe oyvind.har...@zylin.com
wrote:
Note that this problem has cropped up many places over the OpenOCD
code. I'd like to get rid of it once and for all
I
On Fri, Jul 8, 2011 at 11:47 AM, Øyvind Harboe oyvind.har...@zylin.com wrote:
On Fri, Jul 8, 2011 at 11:43 AM, Drasko DRASKOVIC
drasko.drasko...@gmail.com wrote:
On Thu, Jul 7, 2011 at 11:58 AM, Øyvind Harboe oyvind.har...@zylin.com
wrote:
Note that this problem has cropped up many places
On Thu, Jul 7, 2011 at 11:52 AM, Øyvind Harboe oyvind.har...@zylin.com wrote:
011/7/7 Mahr, Stefan stefan.m...@sphairon.com:
Øyvind Harboe wrote:
It is not obvious at all from the context that there is an alignment
guarantee.
If alignment is not guaranteed, casting from uint32 to void would
There is no particular need to cast this into uint8_t* and this can be
kept as a void*. Would that suppress the warnings ?
It does look like this code is using uint8_t * in lieu of void *...
I think it would suppress the warnings, yes.
--
Øyvind Harboe - Can Zylin Consulting help on your
On Fri, Jul 8, 2011 at 12:31 PM, Drasko DRASKOVIC
drasko.drasko...@gmail.com wrote:
On Fri, Jul 8, 2011 at 12:14 PM, Øyvind Harboe oyvind.har...@zylin.com
wrote:
There is no particular need to cast this into uint8_t* and this can be
kept as a void*. Would that suppress the warnings ?
It
On Fri, Jul 8, 2011 at 12:14 PM, Øyvind Harboe oyvind.har...@zylin.com wrote:
There is no particular need to cast this into uint8_t* and this can be
kept as a void*. Would that suppress the warnings ?
It does look like this code is using uint8_t * in lieu of void *...
Why ? It is just an
On Fri, Jul 8, 2011 at 12:10 PM, Øyvind Harboe oyvind.har...@zylin.com wrote:
OK, I am starting to get this... Thanks Øyvind.
But looking from to the code, I see no explicit casting uint8_t* to
uint32_t in mips_pracc code. Where did you exactly run into compiler
warning ?
git revert
On Fri, Jul 8, 2011 at 12:35 PM, Øyvind Harboe oyvind.har...@zylin.com wrote:
On Fri, Jul 8, 2011 at 12:31 PM, Drasko DRASKOVIC
drasko.drasko...@gmail.com wrote:
On Fri, Jul 8, 2011 at 12:14 PM, Øyvind Harboe oyvind.har...@zylin.com
wrote:
There is no particular need to cast this into
I still can not reproduce a problem - it buidls just fine. No warnings
whatsoever.
libtool: compile: nios2-linux-gnu-gcc -std=gnu99 -DHAVE_CONFIG_H -I.
-I/home/oyvind/workspace/zy1000/build/../openocd/src/target -I../..
-I/home/oyvind/workspace/zy1000/build/../openocd/src -I../../src
What puzzles me is that there is no warning on x86, even if I the
-Wcast-align option
is there
-Wcast-align
Warn whenever a pointer is cast such that the required alignment
of the target is increased. For example, warn if a char * is cast to
an int * on machines where integers can
On Fri, Jul 8, 2011 at 12:42 PM, Øyvind Harboe oyvind.har...@zylin.com wrote:
I still can not reproduce a problem - it buidls just fine. No warnings
whatsoever.
libtool: compile: nios2-linux-gnu-gcc -std=gnu99 -DHAVE_CONFIG_H -I.
-I/home/oyvind/workspace/zy1000/build/../openocd/src/target
On Fri, Jul 8, 2011 at 12:52 PM, Øyvind Harboe oyvind.har...@zylin.com wrote:
What puzzles me is that there is no warning on x86, even if I the
-Wcast-align option
is there
This kind of explains why I never saw it...
BR,
Drasko
___
On Wed, Jul 6, 2011 at 2:42 PM, Mahr, Stefan stefan.m...@sphairon.com wrote:
mips32_pracc_read_mem and mips32_pracc_write_mem return values
(buffer[i]) are already in host endianness, so le_to_h_u32 fails on big
endian hosts. I already mentioned this in previous discussions.
Hi Stefan,
are
that casts void* buf to uint32_t*.
Actually buffer is uint8_t *. The definition of target-type-read_memory is
bad in that it uses uint8_t * instead of void *. Which is kinda the
root of this mess.
--
Øyvind Harboe - Can Zylin Consulting help on your project?
US toll free 1-866-980-3434 /
On Fri, Jul 8, 2011 at 1:13 PM, Øyvind Harboe oyvind.har...@zylin.com wrote:
that casts void* buf to uint32_t*.
Actually buffer is uint8_t *. The definition of target-type-read_memory is
bad in that it uses uint8_t * instead of void *. Which is kinda the
root of this mess.
Well, this
I am just wandering, would :
t32 = *(uint32_t*)((void *)buffer[i]);
quite the compiler ;)
BR,
Drasko
On Fri, Jul 8, 2011 at 1:14 PM, Drasko DRASKOVIC
drasko.drasko...@gmail.com wrote:
On Fri, Jul 8, 2011 at 1:13 PM, Øyvind Harboe oyvind.har...@zylin.com wrote:
that casts void* buf to
On Fri, Jul 8, 2011 at 12:52 PM, Øyvind Harboe oyvind.har...@zylin.comwrote:
What puzzles me is that there is no warning on x86, even if I the
-Wcast-align option
is there
-Wcast-align
Warn whenever a pointer is cast such that the required alignment
of the target is increased.
On Fri, Jul 8, 2011 at 1:17 PM, Drasko DRASKOVIC drasko.drasko...@gmail.com
wrote:
I am just wandering, would :
t32 = *(uint32_t*)((void *)buffer[i]);
quite the compiler ;)
Yes probably, but it would still crash on an architecture that doesn't
support unaligned accesses.
/Andreas
On Fri, Jul 8, 2011 at 1:20 PM, Andreas Fritiofson
andreas.fritiof...@gmail.com wrote:
On Fri, Jul 8, 2011 at 1:17 PM, Drasko DRASKOVIC
drasko.drasko...@gmail.com wrote:
I am just wandering, would :
t32 = *(uint32_t*)((void *)buffer[i]);
quite the compiler ;)
Yes probably, but it would
On Fri, Jul 8, 2011 at 1:19 PM, Andreas Fritiofson
andreas.fritiof...@gmail.com wrote:
I looked briefly at the memory read functions in mips32_dmaacc.c and
mips32_pracc.c and it looks like the type usage is a bit confused. The
difference between the *_read_mem{32,16,8} functions should only be
are you sure about this ?
It seems to me that buffer[i] is directly filled by target, and I see
no reason that it is in the host endianess...
Hi Drasko,
Yes I'm sure. I tested it on my big endian host platform.
I do not understand the code completely, but I think it's caused by the mips
On Fri, Jul 8, 2011 at 1:38 PM, Mahr, Stefan stefan.m...@sphairon.comwrote:
are you sure about this ?
It seems to me that buffer[i] is directly filled by target, and I see
no reason that it is in the host endianess...
Hi Drasko,
Yes I'm sure. I tested it on my big endian host
Problem is not in the mips32_pracc.c, thought, but when you come back
to mips_m4k_read_memory(), in which buf is uint8_t*.
That's why the solution could be to add swapping to _mem16, _mem32 etc. and
alway return uint8*.
___
Openocd-development
Where are those functions defined and how do they know what the target
endianness is?
They doesn't know the target endianness, but host endianness.
It sounds a little strange to do the swapping at this low level.
You need swapping when reading and comparing debug registers or send code to
On Fri, Jul 8, 2011 at 2:05 PM, Mahr, Stefan stefan.m...@sphairon.comwrote:
Where are those functions defined and how do they know what the target
endianness is?
They doesn't know the target endianness, but host endianness.
It sounds a little strange to do the swapping at this low level.
On Fri, Jul 8, 2011 at 2:05 PM, Mahr, Stefan stefan.m...@sphairon.comwrote:
Where are those functions defined and how do they know what the target
endianness is?
They doesn't know the target endianness, but host endianness.
You can't convert between target and host endianness if you don't
On Fri, Jul 8, 2011 at 1:26 PM, Drasko DRASKOVIC drasko.drasko...@gmail.com
wrote:
On Fri, Jul 8, 2011 at 1:19 PM, Andreas Fritiofson
andreas.fritiof...@gmail.com wrote:
I looked briefly at the memory read functions in mips32_dmaacc.c and
mips32_pracc.c and it looks like the type usage is
On Fri, Jul 8, 2011 at 1:38 PM, Mahr, Stefan stefan.m...@sphairon.com wrote:
are you sure about this ?
It seems to me that buffer[i] is directly filled by target, and I see
no reason that it is in the host endianess...
Hi Drasko,
Yes I'm sure. I tested it on my big endian host platform.
On Fri, Jul 8, 2011 at 1:54 PM, Mahr, Stefan stefan.m...@sphairon.com wrote:
Problem is not in the mips32_pracc.c, thought, but when you come back
to mips_m4k_read_memory(), in which buf is uint8_t*.
That's why the solution could be to add swapping to _mem16, _mem32 etc. and
alway return
On Fri, Jul 8, 2011 at 2:05 PM, Mahr, Stefan stefan.m...@sphairon.com wrote:
Where are those functions defined and how do they know what the target
endianness is?
They doesn't know the target endianness, but host endianness.
It sounds a little strange to do the swapping at this low level.
On Fri, Jul 8, 2011 at 3:08 PM, Andreas Fritiofson
andreas.fritiof...@gmail.com wrote:
On Fri, Jul 8, 2011 at 1:26 PM, Drasko DRASKOVIC
drasko.drasko...@gmail.com wrote:
On Fri, Jul 8, 2011 at 1:19 PM, Andreas Fritiofson
andreas.fritiof...@gmail.com wrote:
I looked briefly at the memory
- buf_set_u32 and buf_get_u32 make sure that data is in host endianness
Why ? Don't we want the data to be in target endianess ?
You need swapping when reading and comparing debug registers or send code to
MIPS CPU.
Can you give the example of some of these comparisons in the source
code ?
On Fri, Jul 8, 2011 at 4:10 PM, Mahr, Stefan stefan.m...@sphairon.com wrote:
- buf_set_u32 and buf_get_u32 make sure that data is in host endianness
Why ? Don't we want the data to be in target endianess ?
You need swapping when reading and comparing debug registers or send code
to MIPS CPU.
Is this swap to host endianess done by buf_get_u32() in
mips_ejtag_drscan_32() after the queue has been executed ?
Yes, buf_get_u32() and buf_set_u32() make sure uint32 is in host endianness.
___
Openocd-development mailing list
On Fri, Jul 8, 2011 at 2:05 PM, Mahr, Stefan stefan.m...@sphairon.com wrote:
Where are those functions defined and how do they know what the target
endianness is?
They doesn't know the target endianness, but host endianness.
How do they convert then, when they do not know from which endianes
On Fri, Jul 8, 2011 at 4:23 PM, Mahr, Stefan stefan.m...@sphairon.com wrote:
Is this swap to host endianess done by buf_get_u32() in
mips_ejtag_drscan_32() after the queue has been executed ?
Yes, buf_get_u32() and buf_set_u32() make sure uint32 is in host endianness.
OK, we are slowely
How do they convert then, when they do not know from which endianes to
convert from ?
Conversion is done from byte array of jtag chain. The endianness of MIPS EJTAG
tap seems to have always the same endianness, no matter of MIPS CPU memory
endianness.
On Fri, Jul 8, 2011 at 4:30 PM, Mahr, Stefan stefan.m...@sphairon.com wrote:
How do they convert then, when they do not know from which endianes to
convert from ?
Conversion is done from byte array of jtag chain.
How ?
The endianness of MIPS EJTAG tap seems to have always the same
How do they convert then, when they do not know from which endianes to
convert from ?
Conversion is done from byte array of jtag chain.
How ?
buf_get_u32 does conversion from uint8* array
example:
mips_ejtag_get_impcode (mips_ejtag.c)
field.in_value is filled by jtag_add_dr_scan with 4
On Fri, Jul 8, 2011 at 6:30 PM, Mahr, Stefan stefan.m...@sphairon.com wrote:
How do they convert then, when they do not know from which endianes to
convert from ?
Conversion is done from byte array of jtag chain.
How ?
buf_get_u32 does conversion from uint8* array
example:
Øyvind Harboe wrote:
It is not obvious at all from the context that there is an alignment
guarantee.
If alignment is not guaranteed, casting from uint32 to void would cause
problems too, wouldn't it?
011/7/7 Mahr, Stefan stefan.m...@sphairon.com:
Øyvind Harboe wrote:
It is not obvious at all from the context that there is an alignment
guarantee.
If alignment is not guaranteed, casting from uint32 to void would cause
problems too, wouldn't it?
Why?
Note that this problem has cropped up many places over the OpenOCD
code. I'd like to get rid of it once and for all
I absolutely intend to fix it for MIPS, but I'd like a good long term solution.
With jtag queue callbacks, a user data pointer to the callback is cast to
a void pointer, then
If alignment is not guaranteed, casting from uint32 to void would cause
problems too, wouldn't it?
Why?
Sorry for confusion. I meant the casting within mips32_pracc_read_mem. This
is also a cast from void* to uint32_t*. If there will be an alignment error, it
will occur here too.
If alignment is not guaranteed, casting from uint32 to void would cause
problems too, wouldn't it?
Why?
Sorry for confusion. I meant the casting within mips32_pracc_read_mem. This
is also a cast from void* to uint32_t*. If there will be an alignment error,
it will
occur here too.
On Thu, Jul 7, 2011 at 10:41 PM, Mahr, Stefan stefan.m...@sphairon.com wrote:
If alignment is not guaranteed, casting from uint32 to void would cause
problems too, wouldn't it?
Why?
Sorry for confusion. I meant the casting within mips32_pracc_read_mem.
This
is also a cast from void* to
Probably the best way would be to remove endianness swapping from
mips_m4k_read_memory
and put it to mips32_pracc/dma_read_mem32/16. Same for write.
pro: mips32_pracc_read_mem32, ... will return a byte array in target
endianness, so no cast necessary.
con: Add swapping to at least 10
There is no problem to get it work, but I'm not sure if this is
really the best way. I try to prepare a patch within the next
days, so you and others can comment.
I have particular reason to be especially grateful for your efforts here... ;-)
Thanks!
--
Øyvind Harboe - Can Zylin Consulting
On Wed, Jul 6, 2011 at 6:35 PM, Mahr, Stefan stefan.m...@sphairon.com wrote:
Did you see this by testing or by inspection?
Both :)
Do we even have the right macros here?
It would be something like unaligned uint32_t access macros, which will have
to
exist in host endian versions.
On Thu, Jul 7, 2011 at 12:59 AM, Andreas Fritiofson
andreas.fritiof...@gmail.com wrote:
No, casting a pointer-to-any-type to a pointer-to-void and back will never
cause alignment issues. The question is who makes the guarantee that the
function is only ever called with uint32-aligned generic
On Thu, Jul 7, 2011 at 11:04 PM, Michael Schwingen
rincew...@discworld.dascon.de wrote:
Am 07/07/2011 10:41 PM, schrieb Mahr, Stefan:
Probably the best way would be to remove endianness swapping from
mips_m4k_read_memory
and put it to mips32_pracc/dma_read_mem32/16. Same for write.
pro:
On Thu, Jul 7, 2011 at 10:41 PM, Mahr, Stefan stefan.m...@sphairon.com wrote:
If alignment is not guaranteed, casting from uint32 to void would cause
problems too, wouldn't it?
Why?
Sorry for confusion. I meant the casting within mips32_pracc_read_mem.
This
is also a cast from void* to
Hi Øyvind,
Did you see problems with host endianness or why did you commit this patch:
http://openocd.git.sourceforge.net/git/gitweb.cgi?p=openocd/openocd;a=commit;h=2482244b0788c007dd789c21a4416379c229ea5c
This patch brokes endianness on big endian host.
mips32_pracc_read_mem and
mips32_pracc_read_mem and mips32_pracc_write_mem return
values (buffer[i]) are already in host endianness, so le_to_h_u32 fails on
big endian hosts. I already
mentioned this in previous discussions.
Ouch. Did you see this by testing or by inspection?
The problem is that I mis-interpreted a
Did you see this by testing or by inspection?
Both :)
Do we even have the right macros here?
It would be something like unaligned uint32_t access macros, which will have
to
exist in host endian versions.
mips32_pracc_read_mem casts uint32 to void, so we need to cast it back to
On Wed, Jul 6, 2011 at 6:35 PM, Mahr, Stefan stefan.m...@sphairon.com wrote:
Did you see this by testing or by inspection?
Both :)
Do we even have the right macros here?
It would be something like unaligned uint32_t access macros, which will
have to
exist in host endian
mips32_pracc_read_mem casts uint32 to void, so we need to cast it
back to uint32. I found no suitable macro in actual sources.
Hmm then I think we ought to define one to get this put to
bed once and for all...
static inline uint32_t uint32_read_unaligned(const void *data)
{
uint32_t t;
mips32_pracc_read_mem casts uint32 to void, so we need to cast it
back to uint32. I found no suitable macro in actual sources.
Hmm then I think we ought to define one to get this put to
bed once and for all...
static inline uint32_t uint32_read_unaligned(const void *data)
{
uint32_t
On Wed, Jul 6, 2011 at 11:28 PM, Mahr, Stefan stefan.m...@sphairon.com wrote:
mips32_pracc_read_mem casts uint32 to void, so we need to cast it
back to uint32. I found no suitable macro in actual sources.
Hmm then I think we ought to define one to get this put to
bed once and for all...
Trust the compiler
NO !
:-)
$ gcc -O3 -S test.c
$ cat test.s
.file test.c
.text
.p2align 4,,15
.globl uint32_read_unaligned
.type uint32_read_unaligned, @function
uint32_read_unaligned:
On Wed, Jul 6, 2011 at 11:35 PM, Øyvind Harboe oyvind.har...@zylin.comwrote:
On Wed, Jul 6, 2011 at 11:28 PM, Mahr, Stefan stefan.m...@sphairon.com
wrote:
mips32_pracc_read_mem casts uint32 to void, so we need to cast it
back to uint32. I found no suitable macro in actual sources.
80 matches
Mail list logo