Pull to refresh

Comments 15

Как интересно, счетчик сделали 64-битным, а атомарное 64-битное чтение не завезли?

Неужто инструкция LD неатомарная?

В микроконтроллерах обычно предусмотрен аппаратный механизм, обеспечивающий “атомарность” при чтении таких регистров. Одна часть читается напрямую, а вторая через промежуточный регистр-защелку. При чтении младшей части, старшая защелкивается в промежуточном регистре (а может наоборот). Надо просто соблюдать последовательность чтения младший-старший.
В этом контроллере что-то нестандартно сделано. Надо документацию посмотреть. Или может это ранняя ревизия, инженерный образец.

Это абсолютно стандрартный подход для Performance Counters, в RISC-V найти аппаратную защелку для даннго типа инструкций практически нереально. Подобное поведение описано спецификацией.

в RISC-V найти аппаратную защелку для даннго типа инструкций практически нереально

Этот аппаратный механизм не связан с набором команд и конкретной архитектурой. Он применяется в ситуации, когда разрядность регистра больше чем разрядность шины данных, если младшая и старшая часть должны читаться/записываться одновременно. Это еще с древних времен используется.

On 8-bit AVR microcontrollers, accessing 16-bit I/O registers requires a strict byte-access order and a hardware temporary high-byte register to ensure atomicity. You must write the Low byte first (storing it in the temp register), then write the High byte (which triggers a simultaneous update). For reading, you must read the Low byte first (capturing the high byte into the temp register), then read the High byte.

Предположим, что есть защелка. Читаем младшую часть(старшая в защелку), получаем прерывание, уходим на обработчик в котором тоже читается этот счетчик и портит защелку. Возвращаемся и читаем уже непонятно что. Разве не так?

Это само собой. В статье другая проблема описана, от которой запрещение прерываний не помогает.
Прерывания в любом случае отключаются, чтобы не было проблемы связанной с устареванием считанных данных. Это в статье обозначено.

Нет, на QingKe V4 (RV32IMAC) не завезли. STK_CNTL и STK_CNTH читаются двумя отдельными LW

Мда, гениальное решение конечно; от создателей 24битного систика на Cortex-M

Только запрет прерываний для этой комманды не поможет. Нужно использовать специальную обертку:

```

static uint64_t __riscv_get_cycle64(void)

{

#if __riscv_xlen == 64

    uint64_t val;

    asm volatile(

        "rdcycle    %0"

        : "=r"(val));

    return val;

#else

    uint32_t hi1, hi2, low;

    do

    {

        asm volatile(

            "rdcycleh   %0\n"

            "rdcycle    %1\n"

            "rdcycleh   %2"

            : "=r"(hi1), "=r"(low), "=r"(hi2));

    } while (hi1 != hi2);

    return ((uint64_t)hi1 << 32) | low;

#endif

}
```

SysTick - вендорный системный таймер QingKe V4. И, согласно документации на ядро, оно не умеет rdcycle/rdcycleh

Понятно. Я думал стандартным расширением ISA делали. Но смысл такой же.

Я бы завернул в цикл просто вместо одиночного if. И даже без запрета прерываний оно бы в итоге смогло считать корректное значение.

Впрочем, и без цикла запрет прерываний не так уж нужен. Не исполняются обработчики прерываний десятки секунд. А если исполняются, то у нас уже всё сломалось.

Не исполняются обработчики прерываний десятки секунд. А если исполняются, то у нас уже всё сломалось.

Согласен. Можно отказаться и от цикла, и от прерывания

Это реальная задача из собеса в яндекс. Как прочитать 64-битный каунтер 32-битными операциями.

Как увидел uint64_t сразу стало понятно, подобная ошибка достаточно типичная. К примеру на MS430 такое сплошь и рядом, там даже операция чтения uint16_t атомарная, но в силу асинхронного источника тактирования - может разъехаться старший и младший байт. Прерывания я бы не маскировал, просто бесконечный цикл пока два чтения расходятся.

Sign up to leave a comment.

Articles