June 13th, 2020

core5277, логирование

Сразу несколько изменений.

  Ранее логирование было вынесено в виде драйвера, при этом часть кода находилась в ядре.
Скорость UART логирования в порт(BAUDRATE) была 115200, что сулило большие проблемы так как при передаче октета прерывания запрещались.
Удобство было не очень, например часто приходилось писать конструкции вида:

LDI YH,high(_CORE5277_TEXT_STARTED)|0x80 ;ROM
LDI YL,low(_CORE5277_TEXT_STARTED)
MCALL CORE5277_LOG



Теперь так:
1) В основном файле проекта необходимо объявить LOGGING_PORT:
.SET    LOGGING_PORT                            = (PORTC<<4)|PC0
  После чего, в инициализации ядра произойдет подгрузка файла с функционалом для логирования и инициализация логирования.
  Если LOGGING_PORT не объявлять, то файл подгружен не будет, но все метки для логирования будут также доступны, и мы сэкономим сотни байт ПЗУ.

2) Скорость UART для логирования теперь 460800. При передачи байта прерывания также запрещаются, но теперь на передачу байта требуется ~22 микросекунды. Таймер к примеру тикает каждые 50 микросекунд. Т.е. в теории времени вполне достаточно для логирования и прерываний.

3) Добавлены процедуры логирования символа, байта, слова, строки, строки из ПЗУ.
Теперь предыдущий пример выглядит так:
LOG_ROM _LOGSTR_CORE_STARTED

4) В процессе монитор - процедура позволяющая логировать состояние задач и ядра. К приеру, при перезагрузки контроллера, если включено логирование, мы получим вот такой дамп:

---COREDUMP:
TID:01 STA:00 RAM:0000.00 STK:0000.00 VRS:00000000000000000000000000000000
TID:02 STA:84 RAM:03E1.13 STK:0B13.00 VRS:00000000000000000000000000000000
TID:03 STA:84 RAM:03F4.39 STK:0C21.00 VRS:00000000000000000000000000000000
TID:04 STA:84 RAM:0000.00 STK:0CE5.00 VRS:05040000000000000000000000000000
TID:05 STA:84 RAM:0000.00 STK:0DB9.00 VRS:04000000000000000000000000000000
TID:06 STA:84 RAM:0000.00 STK:0E5E.00 VRS:D0041201139E4A042D80000000000000
TID:07 STA:84 RAM:042D.13 STK:0F31.00 VRS:16252412062006000000000000000000
TID:08 STA:00 RAM:0000.00 STK:0000.00 VRS:00000000000000000000000000000000
TID:09 STA:03 RAM:0000.00 STK:08A4.1B VRS:53503A303846430D0A00200000000000
TID:0A STA:03 RAM:0000.00 STK:0889.17 VRS:00000000000000000000000000000000
TID:0B STA:00 RAM:0000.00 STK:0000.00 VRS:00000000000000000000000000000000
TID:0C STA:03 RAM:0000.00 STK:08BF.1B VRS:00000000000000000000000000000000
TID:0D STA:00 RAM:0000.00 STK:0000.00 VRS:00000000000000000000000000000000
TID:0E STA:00 RAM:0000.00 STK:0000.00 VRS:00000000000000000000000000000000
TID:0F STA:03 RAM:0440.0C STK:0872.1E VRS:00000000000000000000000000000000
TID:10 STA:00 RAM:0000.00 STK:0000.00 VRS:00000000000000000000000000000000
TID:11 STA:00 RAM:0000.00 STK:0000.00 VRS:00000000000000000000000000000000
TID:12 STA:00 RAM:0000.00 STK:0000.00 VRS:00000000000000000000000000000000
TID:13 STA:00 RAM:0000.00 STK:0000.00 VRS:00000000000000000000000000000000
TID:14 STA:00 RAM:0000.00 STK:0000.00 VRS:00000000000000000000000000000000
TID:15 STA:00 RAM:0000.00 STK:0000.00 VRS:00000000000000000000000000000000
TID:16 STA:00 RAM:0000.00 STK:0000.00 VRS:00000000000000000000000000000000
TID:17 STA:00 RAM:0000.00 STK:0000.00 VRS:00000000000000000000000000000000
---DONE


В нем видно:
- номер задачи и ее состояние,
- адрес выделенной динамической памяти и ее размер,
- адрес стека и его размер ,
- дамп 16 байт переменных.

Пока так, потом будет больше полезной информации.

Вот кстати, как пример, часть кода монитора:
...
    LOG_ROM _LOGSTR_COREDUMP
    LDI LOOP_CNTR,0x01
_LOG_COREDUMP__TASK_LOOP:
    LOG_ROM LOGSTR_NEW_LINE

    MOV TEMP,LOOP_CNTR
    LOG_ROM _LOGSTR_TID
    MCALL LOG_BYTE
    LOG_ROM LOGSTR_SPACE

    MOV TEMP,LOOP_CNTR
    MCALL _CORE5277_TASK_HEADER_GET

    LDD TEMP,Z+_CORE5277_TASK_STATE
    LOG_ROM _LOGSTR_STATE
    MCALL LOG_BYTE
    LOG_ROM LOGSTR_SPACE

    LDD TEMP_H,Z+_CORE5277_TASK_RAM_OFFSET+0x00
    LDD TEMP_L,Z+_CORE5277_TASK_RAM_OFFSET+0x01
    LDD TEMP,Z+_CORE5277_TASK_RAM_SIZE
    LOG_ROM _LOGSTR_RAM
    MCALL LOG_WORD
    LOG_ROM LOGSTR_DOT
    MCALL LOG_BYTE
    LOG_ROM LOGSTR_SPACE
    ...



update:
  У драйвера нет собственного стека, он работает в стеке вызванной задачи. В мониторе STK драйвера указывает на точку входа в драйвер после инициализации. Различить драйвер от задачи можно по старшему биту в STA.

core5277, регистры

  Семейство AVR имеет 32 регистра, первые 16 регистров обозначены как 'source' и не могут быть использованы в некоторых командах.
  Из-за многопоточности ядру приходится, при переключении задач, сохранять в стек регистры. У каждой задачи свой собственный стек. Более того, в ядре есть узкие места, где нельзя использовать стек, но регистрами пользоваться необходимо.
  Держать в стеке все регистры для каждой задачи слишком жирно, да и зачем? Я считаю, что для задачи вполне достаточно остальных 16 регистров, тем более они используются гораздо чаще первых.

Поэтому одно из требований к драйверу или задаче - использовать только старшие 16 регистров.

  Также при инициализации ядра задаются имена регистрам:
.DEF    TEMP_L   = r16                ;Младший регистр общего назначения
.DEF    TEMP_H   = r17                ;Старший регистр общего назначения
.DEF    TEMP   = r18                ;Регистр общего назначения
.DEF   TEMP_EL   = r19                ;Младший расширенный регистр общего назначения
.DEF    TEMP_EH   = r20                ;Старший расширенный регистр общего назначения
.DEF    LOOP_CNTR   = r21                ;Регистр счета циклов
.DEF    FLAGS   = r22                ;Регистр флагов
.DEF    TRY_CNTR   = r23                ;Счетчик ошибок
.DEF    ACCUM   = r24                ;Аккумулятор
.DEF    DRIVER_ID   = r25                ;ИД драйвера, используется для удобства вызова драйвера


Остальные регистры уже имеют названия, кстати для них есть макросы работы со стеком:
  PUSH_X,PUSH_Y,PUSH_Z и аналогично POP_Z,POP_Y,POP_X