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