помогите понять макрос - PullRequest
       2

помогите понять макрос

5 голосов
/ 26 октября 2010

У меня проблема с пониманием некоторого фрагмента кода в драйвере MTD

#define ROUNDUP(x, y)       ((((x)+((y)-1))/(y))*(y))
...
static struct mtd_partition my_parts[] =
{
   {
      .name = "boot",
      .size = 0,
      .offset = 0,
      .mask_flags = MTD_WRITEABLE
   },
   {
      .name = "linux",
      .size = 0,
      .offset = 0
   },
   {
       .name = "rootfs",
       .size = 0,
       .offset = 0,
       .mask_flags = MTD_WRITEABLE
   },
   {
       .name = "nvram",
       .size = 0,
       .offset = 0
   },
   {
       .name = 0,
       .size = 0,
       .offset = 0
   }
}
...

i = (sizeof(bcm947xx_parts)/sizeof(struct mtd_partition)) - 2;

bcm947xx_parts[i].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
bcm947xx_parts[i].offset = size - bcm947xx_parts[i].size;

Итак, вот мои квесты: 1) почему необходимо округлять размер раздела? 2) не могли бы вы помочь понять, как работает округление? 3) флэш-драйвер в загрузчике на той же платформе не выполняет округление для этого конкретного раздела, поэтому макет флэш-памяти имеет разные смещения на стороне ядра и в загрузчике. В чем причина?

Заранее благодарим за любые ценные комментарии!

1 Ответ

6 голосов
/ 26 октября 2010

(1) Флэш-память кратна размеру стираемой памяти. (По-видимому. По крайней мере, это то, что говорит мне цитируемый код.) Это означает, что есть разрыв между концом NVRAM и тем, что будет дальше. Этот разрыв меньше размера одного размера стирания. Во флэш-памяти удобно не помещать два объекта с разными расписаниями перезаписи в один блок стирания - для изменения любого объекта требуется, чтобы контроллер флэш-памяти скопировал блок во временное хранилище, применил частичное обновление к хранилищу, удалил блок ( slow-ish) и запишите обновленный блок в главное хранилище. (Он может повторно использовать другой ранее стертый блок и вернуть его на место исходного блока. Но это считается высокотехнологичной оптимизацией.)

(2) Как разобрать макросы:

((((x)+((y)-1))/(y))*(y))

Шаг 1, удалите символы вокруг аргументов, которые гарантируют, что сложные выражения, переданные в качестве аргументов, не переплетаются неожиданным образом из-за приоритета оператора.

(((x+(y-1))/y)*y)

Шаг 2, удалите параноидальные скобки для операций, которые явно имеют указанный приоритет.

(x+y-1)/y*y

Шаг 3, используйте ваши правила синтаксического анализа C, а не правила алгебры. Если x и y являются целочисленными типами (в вашем коде недостаточно информации, чтобы быть уверенным в этом), то деление является целочисленным делением, поэтому переведите с C на математический.

 floor((x+y-1)/y)*y

Шаг 4, читай. Если x кратно y, то, поскольку y-1 слишком мало, чтобы быть кратным y, операция просто возвращает x. Если x на 1 больше, чем кратное y, то + y-1 сдвигает числитель по следующему кратному y, и в результате получается наименьшее кратное y, которое оказывается больше x. На самом деле, если x на 1 больше, а y-1 больше, чем кратное y, «+ y-1» увеличивает числитель до следующего кратного y, и результат округления наименьшего кратного y больше чем х.

Таким образом, мы находим, что ROUNDUP (x, y) округляет x до наименьшего кратного y, которое оказывается больше или равно x. Кроме того, этот макрос оценивает свой второй аргумент более одного раза: не помещайте выражения с побочными эффектами во второй слот, если только вы не хотите, чтобы эти побочные эффекты возникали три раза за вызов. (Рассмотрим int i = 3; ROUNDUP (6, i ++) и задаемся вопросом, какие подвыражения вычисляются до, а какие после каждого из трех приращений i.)

(3) Понятия не имею. Никто не сказал автору загрузчика, что NVRAMs могут быть только кратны стиранию?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...