EmbeddedRelated.com
Forums
Memfault Beyond the Launch

MSP430X have segmented memory

Started by Matthias Weingart February 14, 2009
Hi,

I remember we had a discussion here that the MSP430X is not segmented - but
in fact it is - with all drawbacks - I remember from the x86-architecture.
Depending on the philosophy of the compiler vendor you can not use the whole
flash range for code or const (well ISR's have to reside in the lower range,
but this is not a problem). Crossworks currently limits the CONST range to
the lower adress range. Well you can put large tables in the upper (>0x0ffff)
adress range and read them with read_extended() - but the MSP430X IS
segmented (at least from the view of the compiler user).

I do not know why Rowley have choosen this way (I think to keep the stack
usage low, and maybe the code density will be a little better?) - how are
other compilers doing it?

Matthias

Beginning Microcontrollers with the MSP430

Matthias,

> I remember we had a discussion here that the MSP430X is not segmented -
but
> in fact it is - with all drawbacks - I remember from the x86-architecture.
> Depending on the philosophy of the compiler vendor you can not use the
> whole flash range for code or const (well ISR's have to reside in the
lower
> range, but this is not a problem). Crossworks currently limits the CONST
range to
> the lower adress range. Well you can put large tables in the upper
> (>0x0ffff) adress range and read them with read_extended() - but the
MSP430X IS
> segmented (at least from the view of the compiler user).

This depends upon your viewpoint. I decided that most users will want to
still have fast programs which address up to 64K of data, but those programs
grow and most importantly you should be able to use up to 1MB of code space.
Hence I chose a 20-bit code and 16-bit data model.

If all pointers are 20 bits then when you pass them on the stack, you use 32
bits, two words. When you store them in a structure, 32 bits. When you
call a function, it needs to push 20-bit registers taking twice the space on
the stack. When pointers are in registers and you're using them in mainline
code there is no penalty. Oh, and when an ISR fires, yes, you have to push
double the amount of data (20-bit registers vs 16-bit registers) which is
just plain ugly.

In short, I felt there were too many compromises to make 20-bit pointers the
default for MSP430X. This is our decision and I think it is honestly the
best decision that we can make.

The CrossWorks linker will flow code around holes in the address space, so
the interrupt vectors 0xffc0-0xffff are not "used". You don't need to
segment code into "lower" and "upper" address ranges.

Oh, and function pointers are thunked 16-bit pointers so passing a function
pointer through a void * still works without loss of address bits.

If you need "wide" data pointers, then I guess we could consider a "far"
20-bit pointer qualifier, but my head spins with the ramifications of using
and providing it. (Well done IAR for taking this on the chin and doing
20-bit data, it's not something I want to do any time soon.)

> I do not know why Rowley have choosen this way (I think to keep the stack
> usage low, and maybe the code density will be a little better?) - how are
> other compilers doing it?

I believe IAR have a large data model and, perhaps, you can mix 20-bit
pointers in 16-bit code but I honestly can't say--I'm sure Anders can spill
the beans. I don't know what CCE does or how it deals with these issues.

--
Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
CrossWorks for ARM, MSP430, AVR, MAXQ, and now Cortex-M3 processors

Hi Paul,

"Paul Curtis" :

> This depends upon your viewpoint. I decided that most users will want
> to still have fast programs which address up to 64K of data, but those
> programs grow and most importantly you should be able to use up to 1MB
> of code space. Hence I chose a 20-bit code and 16-bit data model.

I think this is a good compromise for most users. One drawback is the
blocking of interrupts when accessing (a large number) of CONST-data in the
upper flash. Other drawback is a little bit larger complexity of the code.
However, having 1MB Flash and 16k RAM later, the pushing of 32bit registers
is maybe neglible. (You should consider the large data model, and rewrite
your libs ;-).

> Oh, and function pointers are thunked 16-bit pointers so passing a
> function pointer through a void * still works without loss of address
> bits.

I am using it and it is working; however, how can I get rid of the ugly
warning "cast or assignment from 'void (*)(int, int)' to 'void *' is compiler
dependent" but keep other warnings?. Or "literal contains non-portable
characters" just for a "@" character. (is'nt "@" at 0x40, like "A" at0x41?)
Before I was able to write warning free code, but now impossible.

> If you need "wide" data pointers, then I guess we could consider a "far"
> 20-bit pointer qualifier, but my head spins with the ramifications of
> using and providing it. (Well done IAR for taking this on the chin and
> doing 20-bit data, it's not something I want to do any time soon.)

As long as a 20bit register is used, interrupts have to be disabled, and
afterwards the register used must be restored (in your model)... complex...

>> I do not know why Rowley have choosen this way (I think to keep the
>> stack usage low, and maybe the code density will be a little better?) -
>> how are other compilers doing it?
>
> I believe IAR have a large data model and, perhaps, you can mix 20-bit
> pointers in 16-bit code but I honestly can't say--I'm sure Anders can
> spill the beans. I don't know what CCE does or how it deals with these
> issues.

Do you have a example, how to put a large CONST in the upper memory and how
to access it? I think I have to edit my memory map and placement files?

M.

If any one needs un-segmented memory, then the 430 is as bad as the
ol' 51. You should look to the Motorola, now FreeScale, for a true
non-segmented architecture. Today, 32 bit data/memory pointer/register
are common with them.

BB.
Without Wax
--- On Sat, 2/14/09, Matthias Weingart wrote:

> From: Matthias Weingart
> Subject: [msp430] RE: MSP430X have segmented memory
> To: m...
> Date: Saturday, February 14, 2009, 6:40 AM
> Hi Paul,
>
> "Paul Curtis" :
>
> > This depends upon your viewpoint. I decided that most
> users will want
> > to still have fast programs which address up to 64K of
> data, but those
> > programs grow and most importantly you should be able
> to use up to 1MB
> > of code space. Hence I chose a 20-bit code and 16-bit
> data model.
>
> I think this is a good compromise for most users. One
> drawback is the
> blocking of interrupts when accessing (a large number) of
> CONST-data in the
> upper flash. Other drawback is a little bit larger
> complexity of the code.
> However, having 1MB Flash and 16k RAM later, the pushing of
> 32bit registers
> is maybe neglible. (You should consider the large data
> model, and rewrite
> your libs ;-).
>
> > Oh, and function pointers are thunked 16-bit pointers
> so passing a
> > function pointer through a void * still works without
> loss of address
> > bits.
>
> I am using it and it is working; however, how can I get rid
> of the ugly
> warning "cast or assignment from 'void (*)(int,
> int)' to 'void *' is compiler
> dependent" but keep other warnings?. Or "literal
> contains non-portable
> characters" just for a "@" character.
> (is'nt "@" at 0x40, like "A"
> at0x41?)
> Before I was able to write warning free code, but now
> impossible.
>
> > If you need "wide" data pointers, then I
> guess we could consider a "far"
> > 20-bit pointer qualifier, but my head spins with the
> ramifications of
> > using and providing it. (Well done IAR for taking
> this on the chin and
> > doing 20-bit data, it's not something I want to do
> any time soon.)
>
> As long as a 20bit register is used, interrupts have to be
> disabled, and
> afterwards the register used must be restored (in your
> model)... complex...
>
> >> I do not know why Rowley have choosen this way (I
> think to keep the
> >> stack usage low, and maybe the code density will
> be a little better?) -
> >> how are other compilers doing it?
> >
> > I believe IAR have a large data model and, perhaps,
> you can mix 20-bit
> > pointers in 16-bit code but I honestly can't
> say--I'm sure Anders can
> > spill the beans. I don't know what CCE does or
> how it deals with these
> > issues.
>
> Do you have a example, how to put a large CONST in the
> upper memory and how
> to access it? I think I have to edit my memory map and
> placement files?
>
> M.
>
>
Matthias Weingart wrote:
> Hi,
>
> I remember we had a discussion here that the MSP430X is not segmented - but
> in fact it is - with all drawbacks - I remember from the x86-architecture.
> Depending on the philosophy of the compiler vendor you can not use the
> whole
> flash range for code or const (well ISR's have to reside in the lower
> range,
> but this is not a problem). Crossworks currently limits the CONST range to
> the lower adress range. Well you can put large tables in the upper
> (>0x0ffff)
> adress range and read them with read_extended() - but the MSP430X IS
> segmented (at least from the view of the compiler user).
>
> I do not know why Rowley have choosen this way (I think to keep the stack
> usage low, and maybe the code density will be a little better?) - how are
> other compilers doing it?

Hi Matthias!

The way I see it, the MSP430X architecture has two memory kinds, one is
the lower 64KB and the other is the full address range.

We have named the two memory areas "__data16" and "__data20". The memory
type applies both to variable placement as well as pointers (a __data16
pointer is two bytes, a __data20 pointer would require four, when stored
in memory). In fact, we provide separate heaps for the two memory areas
(in case you ever would have RAM outside the lower 64KB).

Our compiler supports three different data models:

* "small". Only __data16 memory can be accessed. In fact, this mode only
utilizes 16 bits of the 20 bit processor registers, in order to reduce
stack usage. (Note: intrinsics can be used to access the entire memory
range.)

* "medium". __data16 memory is default, but __data20 can be used for,
say, large constant arrays.

* "large". __data20 is default. Typically, this is not used unless you
want a quick and crude method to get a large application up and running
on a MSP430X.

-- Anders Lindgren, IAR Systems
--
Disclaimer: Opinions expressed in this posting are strictly my own and
not necessarily those of my employer.

Hi Anders,

> Hi Matthias!
>
> The way I see it, the MSP430X architecture has two memory kinds, one is
> the lower 64KB and the other is the full address range.
>
> We have named the two memory areas "__data16" and "__data20". The memory
> type applies both to variable placement as well as pointers (a __data16
> pointer is two bytes, a __data20 pointer would require four, when stored
> in memory). In fact, we provide separate heaps for the two memory areas
> (in case you ever would have RAM outside the lower 64KB).
>
> Our compiler supports three different data models:
>
> * "small". Only __data16 memory can be accessed. In fact, this mode only
> utilizes 16 bits of the 20 bit processor registers, in order to reduce
> stack usage. (Note: intrinsics can be used to access the entire memory
> range.)
>
> * "medium". __data16 memory is default, but __data20 can be used for,
> say, large constant arrays.

In 'medium' mode, do you use push PUSM.A on entry/exit from a function and
on an ISR by default?

> * "large". __data20 is default. Typically, this is not used unless you
> want a quick and crude method to get a large application up and running
> on a MSP430X.

...in this mode I assume that PUSHM.A is used by default...

--
Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
CrossWorks for ARM, MSP430, AVR, MAXQ, and now Cortex-M3 processors

Paul Curtis wrote:
> > * "small". Only __data16 memory can be accessed. In fact, this mode only
> > utilizes 16 bits of the 20 bit processor registers, in order to reduce
> > stack usage. (Note: intrinsics can be used to access the entire memory
> > range.)
> >
> > * "medium". __data16 memory is default, but __data20 can be used for,
> > say, large constant arrays.
>
> In 'medium' mode, do you use push PUSM.A on entry/exit from a function and
> on an ISR by default?
>
> > * "large". __data20 is default. Typically, this is not used unless you
> > want a quick and crude method to get a large application up and running
> > on a MSP430X.
>
> ...in this mode I assume that PUSHM.A is used by default...

Hi Paul!

We use PUSHM.A in both "medium" and "large" mode, as we must preserve
the full 20 bit registers.

If stack usage is a premium, there is always the "small" model. It
doesn't use the upper four bits of the processor registers, ever, so it
only needs to save and restore 16 bits.

-- Anders Lindgren, IAR Systems
--
Disclaimer: Opinions expressed in this posting are strictly my own and
not necessarily those of my employer.

Anders,

I have a similar question (that was asked by Paul). If I write
assembly routines to be called by c-routines and I need to use Rn
(where n is between 4 and 11), do I need to use PUSH.A Rn instead of
PUSH.W Rn?

Does this depend on the data model of the c-routine? The documents
seem to imply that I can use PUSH.W Rn. Is that for "small" only?

Thanks,

--OCY

--- In m..., "Paul Curtis" wrote:
>
> Hi Anders,
>
> > Hi Matthias!
> >
> > The way I see it, the MSP430X architecture has two memory kinds,
one is
> > the lower 64KB and the other is the full address range.
> >
> > We have named the two memory areas "__data16" and "__data20". The
memory
> > type applies both to variable placement as well as pointers (a
__data16
> > pointer is two bytes, a __data20 pointer would require four, when
stored
> > in memory). In fact, we provide separate heaps for the two memory
areas
> > (in case you ever would have RAM outside the lower 64KB).
> >
> > Our compiler supports three different data models:
> >
> > * "small". Only __data16 memory can be accessed. In fact, this
mode only
> > utilizes 16 bits of the 20 bit processor registers, in order to reduce
> > stack usage. (Note: intrinsics can be used to access the entire memory
> > range.)
> >
> > * "medium". __data16 memory is default, but __data20 can be used for,
> > say, large constant arrays.
>
> In 'medium' mode, do you use push PUSM.A on entry/exit from a
function and
> on an ISR by default?
>
> > * "large". __data20 is default. Typically, this is not used unless you
> > want a quick and crude method to get a large application up and
running
> > on a MSP430X.
>
> ...in this mode I assume that PUSHM.A is used by default...
>
> --
> Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
> CrossWorks for ARM, MSP430, AVR, MAXQ, and now Cortex-M3 processors
>

Hi Anders,

> Hi Paul!
>
> We use PUSHM.A in both "medium" and "large" mode, as we must preserve
> the full 20 bit registers.
>
> If stack usage is a premium, there is always the "small" model. It
> doesn't use the upper four bits of the processor registers, ever, so it
> only needs to save and restore 16 bits.

...as a follow on, in "small" model is a function pointer 16 bits? Given
you should be able to pass a function pointer through a void * (we can argue
this point, but, say it's true for now), does that restrict code size to 64K
in the "small" data model?

--
Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
CrossWorks for ARM, MSP430, AVR, MAXQ, and now Cortex-M3 processors


Memfault Beyond the Launch