2 Commits

Author SHA1 Message Date
snark13 3a33b30c07 mdview2: статик-кэш статуса в file-scope + сентинел вместо force-флага
render_full_status форсирует перерисовку чисел через local_loading=UCHAR_MAX
(сентинел), а не отдельным force_redraw в условии. Отдельный 4-й терм + запись
флага опрокидывали render_md_status_numbers в IX-стек-фрейм (все локали в
память, +68 Б). Вынос local_* в file-scope разгрузил регистровый аллокатор
SDCC — функция осталась на регистрах. Итог даже меньше базы (28215 Б).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 23:00:22 +03:00
snark13 fabbc8129c mdview2: percent на 16-битной арифметике (убрать __divulong)
calc_md_pct/calc_raw_pct тянули 32-битное деление __divulong (+__muluint2ulong)
ради показа процента в статусе. Оба дают операнды ≤16 бит (≤18432 / ≤1024),
переполняет только *100. Новый pct16() масштабирует оба вниз и считает долю
циклом-вычитанием — 66 Б, НОЛЬ подтянутых арифм-хелперов. Точность ±1%
(на границах точно), для индикатора прокрутки незаметно.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 23:00:14 +03:00
5 changed files with 29 additions and 11 deletions
+17
View File
@@ -284,6 +284,23 @@ void fill_row(uint8_t y, uint8_t attr)
bios_clearwin(y, 0, 1, SCREEN_W, attr);
}
/* Процент 0..100 = num*100/den на чистой 16-битной арифметике — чтобы НЕ
* тянуть 32-битное деление __divulong (~760 Б) ради показа процента в статусе.
* Оба вызова (MD/RAW) дают операнды, влезающие в 16 бит (≤18432 и ≤1024),
* переполняет только *100 — поэтому масштабируем оба вниз, пока num*100 не
* влезёт в uint16, затем считаем долю циклом-вычитанием (без div-хелпера).
* Инвариант вызовов: num ≤ den; результат всё равно ограничен 100. */
uint8_t pct16(uint16_t num, uint16_t den)
{
if (den == 0) return 0;
while (num > 655) { num >>= 1; den >>= 1; } /* num*100 ≤ 65500 < 65536 */
if (den == 0) return 100; /* страховка от num>den */
uint16_t n = (uint16_t)(num * 100u);
uint8_t p = 0;
while (n >= den && p < 100) { n = (uint16_t)(n - den); p++; }
return p;
}
/* Отображает указанную EMM-страницу файла в окно W3.
* Если эта страница уже активна, переключение не выполняется. */
+1
View File
@@ -137,6 +137,7 @@ extern uint8_t g_scratch_phys; /* scratch EMM-страница для wi
char fb(uint32_t p); /* байт активного буфера (W3-маппинг) */
void win_rest(uint8_t row, uint8_t col, uint8_t h, uint8_t w, uint8_t page, uint16_t off);
void fill_row(uint8_t y, uint8_t attr);
uint8_t pct16(uint16_t num, uint16_t den); /* num*100/den (0..100), 16-бит, без __divulong */
uint32_t seg_off(uint16_t idx); /* offset исходника для логической строки idx */
/* ================================================================== *
+1 -1
View File
@@ -172,7 +172,7 @@ static uint8_t calc_md_pct(void)
{
uint16_t total = drawable_lines();
if (total <= VIEW_H) return 100;
return (uint8_t)((uint32_t)top_line * 100UL / (uint32_t)(total - VIEW_H));
return pct16(top_line, (uint16_t)(total - VIEW_H));
}
/* ---- навигация MD после загрузки (peer к raw_key) ---------------- */
+4 -5
View File
@@ -161,15 +161,14 @@ static uint32_t raw_prev(uint32_t off)
/* ---- статус-бар: % по байтам (отрисовка — render_raw_status_numbers
* в mdview2_status.c, читает позицию через этот raw_pct) ---- */
/* Процент по байтам без 32-битного деления: масштабируем offset'ы (>>8),
* дальше 32-битная арифметика. raw_top приватен модулю, поэтому % считаем
* здесь и отдаём готовым числом в статус-модуль. */
/* Процент по байтам без 32-битного деления: масштабируем offset'ы (>>8
* ≤1024), дальше 16-битный pct16 (без __divulong). raw_top приватен модулю,
* поэтому % считаем здесь и отдаём готовым числом в статус-модуль. */
uint8_t calc_raw_pct(void)
{
uint16_t a = (uint16_t)(raw_top >> 8);
uint16_t b = (uint16_t)(file_size >> 8);
if (b == 0) return 0; /* файл < 1 КБ */
return (uint8_t)(a * 100UL / b);
return pct16(a, b); /* den==0 (файл < 1 КБ) → pct16 вернёт 0 */
}
/* ---- посев позиции / пересев при смене активного буфера ----------- */
+6 -5
View File
@@ -79,15 +79,16 @@ void status_encoding(void)
bios_write_until(enc_name(g_encoding), 8, 0);
}
static uint16_t local_total = UINT_MAX;
static uint16_t local_last = UINT_MAX;
static uint8_t local_loading = UCHAR_MAX;
static uint8_t local_pct = UCHAR_MAX;
/* Числовая часть (MD): "L a-b / total" между разделителями + "pct%" справа.
* Перезаписывает ТОЛЬКО области между/после разделителей, сами │ и фикс.
* хром не трогает. */
void render_md_status_numbers(void)
{
static uint16_t local_total = UINT_MAX;
static uint16_t local_last = UINT_MAX;
static uint8_t local_loading = UCHAR_MAX;
uint16_t total = drawable_lines();
uint16_t last = top_line + VIEW_H;
if (last > total)
@@ -113,12 +114,12 @@ void render_md_status_numbers(void)
/* Полное обновление переменной части (MD): кодировка + числа. */
void render_full_status(void)
{
local_loading = UCHAR_MAX;
status_encoding();
render_md_status_numbers();
}
void render_percent_progress(uint8_t pct) {
static uint8_t local_pct = UCHAR_MAX;
if (local_pct != pct) {
local_pct = pct;
gotoxy(DIV2_X + 2, 0);