Jump to page: 1 2 3
Thread overview
Creating a microcontroller startup file
Apr 07, 2015
Jens Bauer
Apr 07, 2015
Jens Bauer
Apr 08, 2015
Rikki Cattermole
Apr 08, 2015
Johannes Pfau
Apr 08, 2015
Jens Bauer
Apr 08, 2015
Mike
Apr 08, 2015
Mike
Apr 08, 2015
Jens Bauer
Apr 10, 2015
Mike
Apr 11, 2015
Jens Bauer
Apr 08, 2015
Jens Bauer
Apr 08, 2015
Mike
Apr 08, 2015
Jens Bauer
Apr 08, 2015
Jens Bauer
Apr 08, 2015
Mike
Apr 11, 2015
Jens Bauer
Apr 08, 2015
Jens Bauer
Apr 08, 2015
Mike
Apr 08, 2015
Mike
Apr 09, 2015
Jens Bauer
Apr 09, 2015
Jens Bauer
Apr 09, 2015
Mike
Apr 09, 2015
Artur Skawina
Apr 11, 2015
Jens Bauer
April 07, 2015
I'm currently working on a startup file for Cortex-M.
Thanks to Johannes, I'm now able to implement almost everything I need.

While the most important part of the code code works, there are still a few things, that I would like added/changed.

Here's a cut-down version of a start.d:
---8<-----8<-----8<-----
/* file: startup.d */

import gcc.attribute;
import core.stdc.config;

//alias extern(C) const void function() VectorFunc;	// currently, this won't work for me
alias extern(C) const void *VectorFunc;			// so I'm using a void* instead.

extern(C) extern __gshared c_ulong[0] _stack;
const SIGNATURE_VALUE = 0x5a5a5a5a;
@attribute("weak") @attribute("alias", "defaultResetHandler") extern(C) void Reset_Handler();
@attribute("weak") @attribute("alias", "defaultExceptionHandler") extern(C) void NMI_Handler();

@attribute("section",".isr_vector.ro") VectorFunc[] g_pfnVectors = [
	cast(VectorFunc)_stack,					// Initial Stack Pointer
	&Reset_Handler,						// Reset Vector
	&NMI_Handler,							// Non Maskable Interrupt Vector
	cast(VectorFunc)SIGNATURE_VALUE,
	];


extern(C) void main();
@attribute("weak") extern(C) void LowLevelInit();
@attribute("weak") extern(C) void SystemInit();
extern(C) void defaultResetHandler()
{
//	if(&LowLevelInit) LowLevelInit;
//	if(&SystemInit) SystemInit;

	/* (snipped code to copy the DATA section to RAM and clear the BSS section) */

//	main();

	while(true){}
}

extern(C) void defaultExceptionHandler()
{
	while(true){}
}
--->8----->8----->8-----

The most important thing here is that I have not been successful in making the two subroutines LowLevelInit() and SystemInit() optional.
That is: If they are not linked to startup.o, then they should simply be NULL pointers.
I can do this in C, by supplying the 'weak' attribute, but so far, my attempts to do this in D have not been successful.

If I enable the two lines calling those subroutines, I get link errors...

startup.d:(.text+0x2): undefined reference to `LowLevelInit'
startup.d:(.text+0x6): undefined reference to `SystemInit'

Question number 1: How can a C subroutine be made optional, so it's called only if it linked ?

You may have noticed that the VectorFunc is not a real function, but a void*.
The code will work fine this way, but I'd prefer it to be more correct (if possible).

Question number 2: Is it possible to change the VectorFunc to be a real function pointer, rather than a void* ?

I've placed an empty main function in a file called main.d, which is linked to startup.o.
If I enable calling main(); then suddenly the executable file grows from TEXT=20 bytes, DATA=16 bytes, BSS=280 bytes to TEXT=10184 bytes, DATA=2132 bytes and BSS=12824 bytes.
The disassembly shows that suddenly malloc & friends are added to the executable, even though they're not used at all. I've tried renaming the function I call to something different; but that did not change anything. The things that seem to trigger that the binary file grows, is that if I call the function. I've also tried just having a pointer to the function, and nothing extra is included.

Question number 3: How can I call an external function and keep the binary file size down ?

I've found out that the 'alias' keyword comes in quite handy, in order to reduce the size of the source code. In my test source, you'll find that the attribute keyword is used twice in front of each function declaration. This looks quite bulky, and I'm sure it can be much improved upon. ;)
Question number 4: How can I reduce the function declaration of the Reset_Handler and NMI_Handler shown above ?
April 07, 2015
On Tuesday, 7 April 2015 at 20:33:26 UTC, Jens Bauer wrote:
> Question number 1: How can a C subroutine be made optional, so it's called only if it linked ?

Question 1 might be answered by the following thread:
http://forum.dlang.org/thread/mg1bad$30uk$1@digitalmars.com
-So no need to answer question 1. ;)
April 08, 2015
On 8/04/2015 8:38 a.m., Jens Bauer wrote:
> On Tuesday, 7 April 2015 at 20:33:26 UTC, Jens Bauer wrote:
>> Question number 1: How can a C subroutine be made optional, so it's
>> called only if it linked ?
>
> Question 1 might be answered by the following thread:
> http://forum.dlang.org/thread/mg1bad$30uk$1@digitalmars.com
> -So no need to answer question 1. ;)

I was going to say wrap it into a function pointer global declaration and set it in a module constructor.
April 08, 2015
Am Tue, 07 Apr 2015 20:38:52 +0000
schrieb "Jens Bauer" <doctor@who.no>:

> On Tuesday, 7 April 2015 at 20:33:26 UTC, Jens Bauer wrote:
> > Question number 1: How can a C subroutine be made optional, so it's called only if it linked ?
> 
> Question 1 might be answered by the following thread: http://forum.dlang.org/thread/mg1bad$30uk$1@digitalmars.com -So no need to answer question 1. ;)

I actually saw these errors when I first tested your examples, but I thought that was a mistake in the example code. I didn't even know that extern weak symbols get default values in C ;-)
April 08, 2015
On Wednesday, 8 April 2015 at 08:02:35 UTC, Johannes Pfau wrote:
> I actually saw these errors when I first tested your examples, but I thought that was a mistake in the example code. I didn't even know that extern weak symbols get default values in C ;-)

Don't feel bad about that. I think I found out by looking at
someone else's source-code. ;)
It's not really information that is easy to find on the net.
April 08, 2015
On Tuesday, 7 April 2015 at 20:33:26 UTC, Jens Bauer wrote:

>
> Question number 2: Is it possible to change the VectorFunc to be a real function pointer, rather than a void* ?
>

I did something along these lines (modified to match your example) and it worked fine for me:

alias VectorFunc = void function();

@attribute("weak") @attribute("alias", "defaultHandler")
extern void Reset_Handler();

@attribute("weak") @attribute("alias", "defaultHandler")
extern void NMI_Handler()

@attribute("weak") @attribute("alias", "defaultHandler")
extern void HardFault_Handler();

@attribute("section",".isr_vector.ro")
immutable ISR[3] g_pfnVectors =
[
      &Reset_Handler
    , &NMI_Handler
    , &HardFault_Handler
];

I did this before "weak", "alias", and "section" attributes were added, however.  To see my original code, look at the slide in the presentation here: https://youtu.be/o5m0m_ZG9e8?t=2332.  My original code had everything decorated with extern(C) as well so I could refer to the symbol directly in my linker scripts.  That may not be needed for you, so I left it out.

> Question number 3: How can I call an external function and keep the binary file size down ?

Are you compiling with -ffunction-sections -fdata-sections and linking with --gc-sections? You may need to in order to get rid of some things.

What do you using for your D runtime?  Perhaps some code in your runtime is implicitly linking to some code you're not directly calling.

I also add the following to my linker scripts to get rid of stuff I don't find necessary:

/DISCARD/ :
{
   *(.ARM.extab*)
   *(.ARM.exidx*)
}

/DISCARD/ :
{
   *(.ARM.attributes*)
   *(.comment)
}

You can see the latest incarnation of my linker script here: https://github.com/JinShil/stm32f42_discovery_demo/blob/master/linker/linker.ld


> Question number 4: How can I reduce the function declaration of the Reset_Handler and NMI_Handler shown above ?

Try something along these lines.

enum weak = gcc.attribute.attribute("weak");
enum isrDefault = gcc.attribute.attribute("alias", "defaultHandler");

extern @weak @isrDefault void NMI_Handler();
extern @weak @isrDefault void HardFault_Handler();

I use this idiom briefly in my code here: https://github.com/JinShil/stm32f42_discovery_demo/blob/master/source/start.d

The enum thing kinda bugs me about D, but you'll see it used everywhere, especially phobos.  It's called a manifest constant, and you can find a short blurb about it at the bottom of this page:  http://dlang.org/enum.html

Mike
April 08, 2015
On Wednesday, 8 April 2015 at 11:17:12 UTC, Mike wrote:
> On Tuesday, 7 April 2015 at 20:33:26 UTC, Jens Bauer wrote:
>
>>
>> Question number 2: Is it possible to change the VectorFunc to be a real function pointer, rather than a void* ?
>>
>
> I did something along these lines (modified to match your example) and it worked fine for me:
>
> alias VectorFunc = void function();
>
[...]
>
> @attribute("section",".isr_vector.ro")
> immutable ISR[3] g_pfnVectors =
> [
>       &Reset_Handler
>     , &NMI_Handler
>     , &HardFault_Handler
> ];
>

Sorry, but that code should be:

@attribute("section",".isr_vector.ro")
immutable VectorFunc[3] g_pfnVectors =
[
      &Reset_Handler
    , &NMI_Handler
    , &HardFault_Handler
];


April 08, 2015
Something tells me that now is when I have to start doing some hard work. ;)
-Sorry, I need to split this up into short replies/questions.

On Wednesday, 8 April 2015 at 11:17:12 UTC, Mike wrote:
> On Tuesday, 7 April 2015 at 20:33:26 UTC, Jens Bauer wrote:
>> Question number 2: Is it possible to change the VectorFunc to be a real function pointer, rather than a void* ?

> immutable ISR[3] g_pfnVectors =
> [
>       cast(ISR)&_stack
>     , &Reset_Handler
>     , &NMI_Handler
>     , &HardFault_Handler
> ];

In your example, you do not have the initial stack pointer.
The above code gives me the following:
src/test.d:24:13: error: reinterpreting cast from uint* to void()* is not supported in CTFE
    cast(ISR)&_stack
             ^

-That's the only reason I needed to change it to from function() to void*.
Can you successfully cast(ISR)&_stack ?
April 08, 2015
On Wednesday, 8 April 2015 at 11:17:12 UTC, Mike wrote:
> I did something along these lines (modified to match your example) and it worked fine for me:
>
> alias VectorFunc = void function();
>
> @attribute("weak") @attribute("alias", "defaultHandler")
> extern void Reset_Handler();

Strange; I can't get it to build without extern(C).
Also, if I remove extern(C) from for instance HardFault_Handler, then a HardFault_Handler written in C is not found by the linker.
April 08, 2015
On Wednesday, 8 April 2015 at 11:17:12 UTC, Mike wrote:
> On Tuesday, 7 April 2015 at 20:33:26 UTC, Jens Bauer wrote:
>
>> Question number 3: How can I call an external function and keep the binary file size down ?
>
> Are you compiling with -ffunction-sections -fdata-sections and linking with --gc-sections? You may need to in order to get rid of some things.

I had -fdata-sections for the compiler and --gc-sections for the linker, but I was missing -ffunction-sections. Thank you for letting me know about this.
Unfortunately, it did not reduce the size of the output file.

> What do you using for your D runtime?

minlibd by Timo Sintonen.

>  Perhaps some code in your runtime is implicitly linking
> to some code you're not directly calling.

Maybe that's what's causing it, but I find it strange that calling an empty function outside the source file will cause that huge difference.
-But of course, there's a logic explanation somewhere. ;)

Note: I can rename the 'main()' function to 'My1Own2Weird3Function4Name567()' and the same thing happens, so it's not because main() is special.

> I also add the following to my linker scripts to get rid of stuff I don't find necessary:
> [snip]

It might be caused by the linker script; I'll try and see if I can modify it to get rid of those things.

> You can see the latest incarnation of my linker script here: https://github.com/JinShil/stm32f42_discovery_demo/blob/master/linker/linker.ld

Mine is quite huge, so I'll try out yours as a starting point. ;)
« First   ‹ Prev
1 2 3