Dare I ... another volatile discussion ?

Jens Bauer via Digitalmars-d digitalmars-d at puremagic.com
Thu May 7 09:04:55 PDT 2015


I'm sorry for opening such a topic; I've heard it's not liked a 
lot, but I think it might be necessary.

I'm not asking for a 'volatile' keyword, but rather to find out 
what the right thing to use is.
After reading a few different threads related to 
microcontrollers, I started wondering how to program the 
following in D:

1: System level drivers, which writes directly to hardware 
registers (any architecture, PC/i386 [Linux, Windows, others], 
Atari ST, IBM BladeCenter, etc.)
2: Interrupts that needs to share variables.

1) is what we basically need on microcontrollers. If it's 
possible to write a driver in D, which has no problems with 
accessing hardware, then it should be possible to do it for any 
microcontroller as well.

2) shared variables could be used for interrupts, but what 
happens if the TLS is disabled; will shared variables work ? 
-Interrupts are not threads.

Regarding (1), because marking a variable 'shared' is not enough 
(it allows instructions to be moved around), Johannes already 
made a volatileLoad and volatileStore, which will be usable for 
microcontrollers, though for convenience, it requires writing 
additional code.
-But this solution ... I do not know if it would work, when 
writing a driver for Debian running on a i586 platform or 
PowerMac G3 for instance.

If variable 'alice' and variable 'bob' are both shared, and 
reading from 'bob', then writing to 'alice'; would instructions 
be moved around, so reading from 'bob' could actually occur after 
writing to 'alice' ?

Imagine that in the microcontroller world, there's a *bunch* of 
hardware registers.
The best thing a microcontroller knows, is to read/write hardware 
registers; often only a few bits at a time - but definitely also 
8-, 16- and 32-bit values.

Thus you will most likely not be able to find a single piece of 
source-code for a microcontroller, where it does not access 
hardware. This means: Hardware is used often, and reading/writing 
hardware registers should not take up a lot of space in the 
source code.


For those, who are unfamiliar with such code, here's a silly 
example in C on how it might look.
The following code changes the clock-frequency of the 
microcontroller, so it runs at 100 MHz:

---8<-----8<-----8<-----
uint32_t setupCoreClock()
{
	/* By default, we run at 100MHz, however,
	 * our PLL clock frequency is 300 MHz.
	 * We'd like to run 400MHz! */

	LPC_SC->SCS = SCS_MainOscillatorEnable;	/* enable Main 
Oscillator */
	if(LPC_SC->SCS & SCS_MainOscillatorEnable)
	{
		while(0 == (LPC_SC->SCS & SCS_MainOscillatorStatus)){}
	}

	LPC_SC->CCLKCFG = CCLK_Divider - 1;

	LPC_SC->PCLKSEL0 = 0;
	LPC_SC->PCLKSEL1 = 0;

	LPC_SC->CLKSRCSEL = PLL0_ClockSource;

	LPC_SC->PLL0CFG = PLL0_Configuration;
	LPC_SC->PLL0FEED = 0xaa;
	LPC_SC->PLL0FEED = 0x55;

	LPC_SC->PLL0CON = PLL_Enable;
	LPC_SC->PLL0FEED = 0xaa;
	LPC_SC->PLL0FEED = 0x55;
	while(!(LPC_SC->PLL0STAT & PLL0_Lock)){}	/* Wait for PLOCK0 */

	LPC_SC->PLL0CON = PLL_Enable | PLL_Connect;
	LPC_SC->PLL0FEED = 0xaa;
	LPC_SC->PLL0FEED = 0x55;
	while((LPC_SC->PLL0STAT & (PLL0_EnabledFlag | 
PLL0_ConnectedFlag)) != (PLL0_EnabledFlag | 
PLL0_ConnectedFlag)){}	/* Wait until connected */

	return(F_CCLK);
}
--->8----->8----->8-----

Everything you see above, which starts with 'LPC_' are hardware 
register accesses.
Not counting the curly braces, nearly every line of the code 
access hardware registers.

Things like LPC_SC are pointers to structures, which contains a 
load of volatile keywords; some prohibit reading, some prohibit 
writing, some allow both, some allow neither.

Most code for ARM Cortex-M looks like the above, because the 
silicon vendors just modifies the stock (template) source code, 
which they receive from ARM. Thus there's some convenience, but 
not a lot. Bitfields are not provided by ARM, so it propagates 
down to the vendor, which do not supply bitfields either. 
However, byte/halfword/word access (8/16/32-bit) are sometimes 
provided through anonymous unions, which is very helpful.

So back to what originally triggered this post; this is what the 
question is actually about:
If writing a driver for <platform X>, how is reading/writing 
hardware registers usually done in D ?


More information about the Digitalmars-d mailing list