Цитата(Pavel V. @ Feb 11 2012, 18:11)

Код
SEL0 &= ConfigurationMask<pin>::Clear();
SEL0 |= ConfigurationMask<pin>::SelSet(configuration);
MODE0 &= ConfigurationMask<pin>::Clear();
MODE0 |= ConfigurationMask<pin>::ModeSet(configuration);
LPC17 ?
Тоже наткнулся на такую заразу со сдвигами («больше ширины» либо «сдвиг на отрицательное значение» в зависимости от константы и ветки
if (shift < 32)).
Код
if (shift < 32) {
LPC_SC->PCLKSEL0 = (LPC_SC->PCLKSEL0 & ~(0x03 << shift))
| (CLKPWR_PCLKSEL_CCLK_DIV_1 << shift);
} else {
LPC_SC->PCLKSEL1 = (LPC_SC->PCLKSEL1 & ~(0x03 << (shift-32)))
| (CLKPWR_PCLKSEL_CCLK_DIV_1 << (shift-32));
}
Сначала по-быстрячку сделал
shift локальной переменной функции. Оптимизатор всё делает нормально, а предупреждение пропадает. Потом нарисовал такое (в рабочий код ещё не интегрировал, в тесте с ключиком -S всё красиво):
CODE
#include <stdint.h>
template<unsigned width, unsigned position, unsigned reg_bits = 32>
struct field_traits
{
enum {
reg_index = position / reg_bits,
shift = position % reg_bits,
unshifted_mask = (1UL << width) - 1,
mask = unshifted_mask << shift
};
static unsigned value(unsigned val) { return (val & unshifted_mask) << shift; }
static unsigned place(unsigned reg) { return reg & ~mask; }
static unsigned insert(unsigned reg, unsigned val) { return place(reg) | value(val); }
};
struct params {
volatile uint32_t reg0, reg1;
};
params p;
template<unsigned pin>
struct tst
{
typedef field_traits<2, 2*pin> traits;
static void Setup(unsigned v)
{
#if 1
traits::reg_index == 0 ? p.reg0 = traits::insert(p.reg0,v)
: p.reg1 = traits::insert(p.reg1,v);
#else
// Имея уверенность (или при соответствующем описании целевой структуры)
// можно и так:
volatile uint32_t *preg = &p.reg0 + traits::reg_index;
*preg = traits::insert(*preg,v);
#endif
}
};
typedef tst<1> tst1;
typedef tst<15> tst15;
typedef tst<16> tst16;
typedef tst<18> tst18;
typedef tst<31> tst31;
void foo1() { tst1::Setup(0); }
void foo15() { tst15::Setup(1); }
void foo16() { tst16::Setup(2); }
void foo18() { tst18::Setup(2); tst18::Setup(1);}
void foo31() { tst31::Setup(3); }