Добавить общее ядро DEIF, эмуляцию приборов и переносимые панели Python/Qt. Расширить загрузчики F2812 и F28335, обновление Flash и профиль STM Invertor. Добавить альтернативный МНК Eigen, модели неисправностей и диагностику сигналов. Обновить справочники устройств, проекты CCS и регрессионные проверки.
84 lines
15 KiB
C
84 lines
15 KiB
C
#include "../ports/tms320f2812/boot2812.h" /* Проверяет реальные callbacks NOR и общий ProtoCAN codec в wide-octet режиме. */
|
||
#include <assert.h> /* Любое нарушение границ, публикации или CRC завершает тест ошибкой. */
|
||
#include <stdint.h> /* Модель физической x16 памяти использует ровно 16 бит на слово даже на ПК. */
|
||
#include <stdio.h> /* Сообщает результат поведенческих сценариев без физического JTAG. */
|
||
#include <string.h> /* Подготавливает память и отдельные структуры C-ядра перед серией. */
|
||
static uint16_t memory[0x80000]; /* AM29LV800BT содержит 512K слов x16, то есть 1 МиБ. */
|
||
static unsigned int state, selected, bad_id, erases, programmed, busy_calls, loaded_words, stuck; /* Состояния относятся только к модели командной шины AMD. */
|
||
static long budget = -1; /* Отрицательное значение разрешает записи, ноль моделирует исчезновение питания перед очередным word program. */
|
||
static unsigned long clock_ms; /* Детерминированные часы позволяют проверить ограниченный выход из polling. */
|
||
unsigned long Boot2812_Now(void) { return clock_ms++; } /* Продвигает миллисекунды без зависимости теста от wall clock ПК. */
|
||
void Boot2812_Busy(void) { ++busy_calls; } /* Подтверждает, что длительное ожидание вызывает разрешённый сервис BUSY. */
|
||
void NorModel_LoadWord(uint32_t target, unsigned int value) /* Получает только реальные записи валидатора в разрешённую RAM приложения. */
|
||
{ /* Тестовый образ ниже содержит пять слов H0. */
|
||
assert(target >= 0x3F8000UL && target < 0x3F8005UL); assert(value == 0U); ++loaded_words; /* Неверный адрес либо повреждённый payload не может скрыться в аппаратной заглушке. */
|
||
} /* Запись в адресное пространство процесса ПК отсутствует. */
|
||
unsigned int NorModel_Read(unsigned long word) /* Имитирует обычное чтение либо режим autoselect чипа. */
|
||
{ /* Все обращения обязаны оставаться внутри установленной физической NOR. */
|
||
assert(word >= BOOT2812_NOR_BASE && word < BOOT2812_NOR_BASE + 0x80000UL); /* Выход на соседнюю XINTF-память является ошибкой драйвера. */
|
||
if (selected) return word == BOOT2812_NOR_BASE ? (bad_id ? 2U : 1U) : 0x22DAU; /* Модель отличает правильный AMD от неподходящего производителя. */
|
||
if (stuck && word >= BOOT2812_IMAGE_WORD) return 0U; /* DQ7=0/DQ5=0 удерживают erase busy до программного тайм-аута. */
|
||
return memory[word - BOOT2812_NOR_BASE]; /* Возвращает настоящие 16-битные данные модели. */
|
||
} /* Чтение не выполняет скрытых записей и не исправляет повреждённые данные. */
|
||
void NorModel_Write(unsigned long word, unsigned int value) /* Проверяет настоящий unlock state machine драйвера, а не принимает готовые запросы erase. */
|
||
{ /* Командные адреса трактуются как x16 смещения согласно datasheet AMD. */
|
||
assert(word >= BOOT2812_NOR_BASE && word < BOOT2812_NOR_BASE + 0x80000UL); /* Любой командный цикл ограничен физическим чипом. */
|
||
if (state == 3U) { /* После A0 следующий цикл обязательно содержит программируемое слово данных. */
|
||
if (budget != 0) { memory[word - BOOT2812_NOR_BASE] &= (uint16_t)value; ++programmed; if (budget > 0) --budget; } /* NOR программирует только переходы 1→0; обрыв питания оставляет прежнее слово. */
|
||
state = 0U; return; /* Программирование одного слова завершает командную последовательность. */
|
||
} /* Значение F0 в payload не должно ошибочно интерпретироваться как отдельная команда Reset. */
|
||
if (value == 0xF0U) { state = selected = 0U; return; } /* Reset возвращает обычное чтение независимо от предыдущей незавершённой команды. */
|
||
if (state == 0U) { assert(word == BOOT2812_NOR_BASE + 0x555UL && value == 0xAAU); state = 1U; } /* Первый unlock-цикл проверяется вместе с адресом. */
|
||
else if (state == 1U) { assert(word == BOOT2812_NOR_BASE + 0x2AAUL && value == 0x55U); state = 2U; } /* Второй цикл исключает ошибочную x8 адресацию. */
|
||
else if (state == 2U) { /* Третий цикл выбирает только одну из поддерживаемых безопасных команд. */
|
||
assert(word == BOOT2812_NOR_BASE + 0x555UL); /* Командный регистр находится по x16 смещению 555h. */
|
||
if (value == 0x90U) { selected = 1U; state = 0U; } /* Autoselect не изменяет содержимое памяти. */
|
||
else if (value == 0xA0U) state = 3U; /* Следующий цикл будет word program. */
|
||
else { assert(value == 0x80U); state = 4U; } /* Стирание требует второй unlock-пары, а не одного произвольного слова. */
|
||
} /* Завершает декодирование третьего такта AMD. */
|
||
else if (state == 4U) { assert(word == BOOT2812_NOR_BASE + 0x555UL && value == 0xAAU); state = 5U; } /* Проверяет четвёртый цикл Sector Erase. */
|
||
else if (state == 5U) { assert(word == BOOT2812_NOR_BASE + 0x2AAUL && value == 0x55U); state = 6U; } /* Проверяет пятый цикл Sector Erase. */
|
||
else { /* Шестой цикл выбирает только разрешённый отдельный сектор. */
|
||
unsigned long count = word == BOOT2812_META_WORD ? 0x2000UL : 0x8000UL, i; /* Модель различает обычные и последние top-boot сектора. */
|
||
assert(value == 0x30U); assert(word == BOOT2812_META_WORD || word == BOOT2812_IMAGE_WORD || word == BOOT2812_IMAGE_WORD + 0x8000UL || word == BOOT2812_IMAGE_WORD + 0x10000UL); /* Запрещает Chip Erase и любые соседние секторы legacy/FPGA. */
|
||
for (i = 0; i < count; ++i) memory[word - BOOT2812_NOR_BASE + i] = 0xFFFFU; /* Реально стирает все слова выбранного сектора модели. */
|
||
++erases; state = 0U; /* Сохраняет число аппаратных sector erase для проверки отказов до разрушительных циклов. */
|
||
} /* Завершает разрешённую операцию command bus. */
|
||
} /* Модель не предоставляет драйверу обходного пути прямой записи массива. */
|
||
static pcan_boot_byte_t image[40]; /* Небольшой полный SCI8: заголовок 22, секция 6+10, терминатор 2 октета. */
|
||
static pcan_boot_manifest_t manifest; /* Metadata используют те же размеры и совместимость, что настоящий клиент. */
|
||
static void make_image(void) /* Создаёт независимо определённый SCI8 с entry=3F8000 и пятью нулевыми словами H0. */
|
||
{ /* Нулевой payload облегчает точную проверку каждого перенесённого слова. */
|
||
memset(image, 0, sizeof(image)); image[0] = 0xAAU; image[1] = 8U; image[18] = 0x3FU; image[21] = 0x80U; image[22] = 5U; image[24] = 0x3FU; image[27] = 0x80U; /* Адрес TI передаётся старшим словом вперёд, внутри слова — little endian. */
|
||
memset(&manifest, 0, sizeof(manifest)); manifest.image_size = 40UL; manifest.image_crc32 = pcan_boot_crc32_update(0UL, image, 40U); /* Начальная CRC вычисляется общим codec по независимому массиву файла. */
|
||
manifest.product_type = BOOT2812_PRODUCT; manifest.hardware_revision_min = manifest.hardware_revision_max = 1U; /* Проверяет исключительно совместимый профиль F2812. */
|
||
} /* Последующие сценарии меняют данные с новой CRC, чтобы отделить ошибки структуры от ошибок передачи. */
|
||
static void save_image(void) /* Заполняет слоты через настоящие production callbacks, а не memcpy в образ. */
|
||
{ /* Каждая порция соответствует одному восьмиоктетному CAN DATA. */
|
||
unsigned int i; assert(Boot2812_Erase(0, 0U)); /* Перед каждой полной передачей удаляет marker и три полных сектора образа. */
|
||
for (i = 0; i < 40U; i += 8U) assert(Boot2812_Write(0, 0U, i, image + i, 8U)); /* Проверяет упаковку октетов и readback каждого x16 слова. */
|
||
} /* Только после завершения записи разрешены VERIFY и COMMIT. */
|
||
int main(void) /* Проверяет драйвер, SCI8, publication и независимость соседних данных платы. */
|
||
{ /* Все операции используют модель, физический CAN/JTAG не открывается. */
|
||
unsigned long i; uint32_t entry; unsigned int before, cut; /* Счётчики контролируют защищённые диапазоны и обрывы manifest. */
|
||
for (i = 0; i < 0x80000UL; ++i) memory[i] = 0x5AA5U; make_image(); /* Заполняет весь чип контрольным значением, включая старые данные и FPGA. */
|
||
bad_id = 1U; before = erases; assert(!Boot2812_Erase(0, 0U) && erases == before); bad_id = 0U; /* Неподходящий производитель блокируется до первого sector erase. */
|
||
assert(!Boot2812_NorErase(0x100000UL) && !Boot2812_NorErase(BOOT2812_IMAGE_WORD + 1UL)); /* Не разрешает старую область либо адрес внутри разрешённого сектора вместо его точного начала. */
|
||
assert(!Boot2812_NorProgram(0x130000UL, 0U)); /* FPGA-образ запрещён даже при ошибочном прямом вызове нижнего драйвера. */
|
||
save_image(); assert(Boot2812_Verify(0, 0U, &manifest) == PCAN_BOOT_STATUS_OK); /* Реальный NOR readback и формат SCI8 должны совпасть с входом. */
|
||
assert(!Boot2812_Load(&entry)); assert(Boot2812_Commit(0, 0U, &manifest)); loaded_words = 0U; assert(Boot2812_Load(&entry) && entry == 0x3F8000UL && loaded_words == 5U); /* До COMMIT загрузка запрещена, после него переносятся ровно проверенные слова H0. */
|
||
before = programmed; assert(!Boot2812_NorProgram(BOOT2812_IMAGE_WORD, 0xFFFFU) && programmed == before); /* Перевод 0→1 отклоняется без лишней попытки аппаратного program. */
|
||
for (cut = 0; cut <= 12U; ++cut) { /* Проверяет публикацию при обрыве на каждом месте manifest из двенадцати слов. */
|
||
bool committed; save_image(); budget = (long)cut; committed = Boot2812_Commit(0, 0U, &manifest); budget = -1; /* Останавливает только циклы NOR word program, не подменяя механизм публикации. */
|
||
loaded_words = 0U; assert(Boot2812_Load(&entry) == committed); /* Незавершённая публикация остаётся recovery; полностью опубликованный образ запускается. */
|
||
} /* Предыдущие legacy-данные всё время остаются за пределами разрешённого erase. */
|
||
save_image(); memory[BOOT2812_IMAGE_WORD - BOOT2812_NOR_BASE + 15UL] ^= 1U; assert(Boot2812_Verify(0, 0U, &manifest) == PCAN_BOOT_STATUS_CRC_ERROR); /* Порча физической NOR обнаруживается независимо от принятой потоковой CRC. */
|
||
make_image(); image[18] = 0U; image[21] = 0x90U; image[24] = 0U; image[27] = 0x90U; manifest.image_crc32 = pcan_boot_crc32_update(0UL, image, 40U); save_image(); /* Формирует целостную, но опасную секцию в L1 работающего загрузчика. */
|
||
assert(Boot2812_Verify(0, 0U, &manifest) == PCAN_BOOT_STATUS_INVALID_STATE && !Boot2812_Commit(0, 0U, &manifest)); /* Корректная CRC не разрешает перезапись очереди и состояния сессии. */
|
||
make_image(); stuck = 1U; before = busy_calls; assert(!Boot2812_NorErase(BOOT2812_IMAGE_WORD) && busy_calls > before); stuck = 0U; /* Постоянный DQ7 busy даёт ограниченный отказ и вызывает живой сервис BUSY. */
|
||
for (i = 0; i < 0x60000UL; ++i) assert(memory[i] == 0x5AA5U); /* Сохраняет весь нижний участок старого firmware, параметров и FPGA, а не одну контрольную точку. */
|
||
for (i = 0x78000UL; i < 0x7E000UL; ++i) assert(memory[i] == 0x5AA5U); /* Промежуточные top-boot сектора 15/16/17 также не стираются. */
|
||
puts("F2812 NOR: AMD commands, ID, bounds, CRC, SCI8, torn commit, timeout and legacy/FPGA preservation: OK"); /* Перечисляет программно проверенные свойства аппаратного порта. */
|
||
return 0; /* Успех означает завершение всех граничных и отказных сценариев. */
|
||
} /* Политика аппаратного boot/CPLD дополнительно проверяется на реальной плате. */
|