diff --git a/examples/mdview2/mdview2.c b/examples/mdview2/mdview2.c index e43a10a..58d45a3 100644 --- a/examples/mdview2/mdview2.c +++ b/examples/mdview2/mdview2.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -269,6 +270,7 @@ static void doc_switch(uint8_t target); /* forward (нужна в progress_tic void put_str_attr(uint8_t x, uint8_t y, const char *s, uint8_t attr) { uint8_t len = (x < SCREEN_W) ? (uint8_t)(SCREEN_W - x) : 0; + len = min(len, strlen(s)); if (len == 0) return; bios_set_place(y, x); bios_writeattr_until(s, len, attr, 0); @@ -490,7 +492,7 @@ static int alloc_set_storage(void) { uint8_t want; - want = (uint8_t)(file_pages >> 1 + 1u); + want = (uint8_t)((file_pages >> 1) + 1u); if (want > MAX_INDEX_PAGES) want = MAX_INDEX_PAGES; index_blk = mem_alloc_pages(want); if (index_blk == 0) return -5; @@ -499,7 +501,7 @@ static int alloc_set_storage(void) index_phys[i] = mem_get_page(index_blk, i); max_lines = (uint16_t)index_pages * INDEX_RECS_PER_PAGE; - want = (uint8_t)(file_pages >> 1 + 1u); + want = (uint8_t)((file_pages >> 1) + 1u); if (want > MAX_CACHE_DIR_PAGES) want = MAX_CACHE_DIR_PAGES; cache_dir_blk = mem_alloc_pages(want); if (cache_dir_blk == 0) return -6; @@ -616,32 +618,67 @@ static void load_key(uint16_t k) uint16_t maxtop = (dr > VIEW_H) ? (uint16_t)(dr - VIEW_H) : 0; uint16_t nt = top_line; - if (ascii == 0x1B || scan == KEY_F10) { g_abort = 1; return; } /* Esc/F10 → выход */ - if (ascii) return; /* прочие ascii игнорируем */ + if (ascii == 0x1B || scan == KEY_F10) { + g_abort = 1; + return; + } /* Esc/F10 → выход */ + if (ascii) + return; /* прочие ascii игнорируем */ switch (scan) { - case KEY_UP: nt = (top_line >= 1) ? (uint16_t)(top_line - 1) : 0; break; - case KEY_DOWN: nt = top_line + 1; break; - case KEY_PGUP: nt = (top_line >= VIEW_H) ? (uint16_t)(top_line - VIEW_H) : 0; break; - case KEY_PGDN: nt = top_line + VIEW_H; break; - case KEY_HOME: top_line = 0; viewport_x = 0; draw_viewport_from_cache(); render_md_status_numbers(); return; - case KEY_END: top_line = maxtop; viewport_x = 0; draw_viewport_from_cache(); render_md_status_numbers(); return; - case KEY_LEFT: md_scroll_horizon(-(int8_t)HPAN_STEP); render_md_status_numbers(); return; - case KEY_RIGHT: md_scroll_horizon(+(int8_t)HPAN_STEP); render_md_status_numbers(); return; - case KEY_F1: show_help(); return; - case KEY_F8: /* во время сборки крутим ТОЛЬКО 8-бит и только если набор 8-битный - * (ремап на отрисовке; индексация не зависит от кодировки) */ - if (g_f8_enabled && g_active_doc == DOC_8BIT) { - uint8_t nx = (g_encoding == ENC_CP866) ? ENC_CP1251 : - (g_encoding == ENC_CP1251) ? ENC_KOI8R : ENC_CP866; - set_encoding(nx); g_doc[DOC_8BIT].enc = nx; - draw_viewport_from_cache(); - render_full_status(); - } - return; - default: return; + case KEY_UP: + nt = (top_line >= 1) ? (uint16_t)(top_line - 1) : 0; + break; + case KEY_DOWN: + nt = top_line + 1; + break; + case KEY_PGUP: + nt = (top_line >= VIEW_H) ? (uint16_t)(top_line - VIEW_H) : 0; + break; + case KEY_PGDN: + nt = top_line + VIEW_H; + break; + case KEY_HOME: + top_line = 0; + viewport_x = 0; + draw_viewport_from_cache(); + render_md_status_numbers(); + return; + case KEY_END: + top_line = maxtop; + viewport_x = 0; + draw_viewport_from_cache(); + render_md_status_numbers(); + return; + case KEY_LEFT: + md_scroll_horizon(-(int8_t)HPAN_STEP); + render_md_status_numbers(); + return; + case KEY_RIGHT: + md_scroll_horizon(+(int8_t)HPAN_STEP); + render_md_status_numbers(); + return; + case KEY_F1: + show_help(); + return; + case KEY_F8: + /* во время сборки крутим ТОЛЬКО 8-бит и только если набор 8-битный + * (ремап на отрисовке; индексация не зависит от кодировки) */ + if (g_f8_enabled && g_active_doc == DOC_8BIT) { + uint8_t nx = (g_encoding == ENC_CP866) ? ENC_CP1251 : + (g_encoding == ENC_CP1251) ? ENC_KOI8R : ENC_CP866; + set_encoding(nx); + g_doc[DOC_8BIT].enc = nx; + draw_viewport_from_cache(); + render_full_status(); + } + return; + default: + return; } - if (nt > maxtop) nt = maxtop; + + if (nt > maxtop) + nt = maxtop; if (nt != top_line) { top_line = nt; draw_viewport_from_cache(); @@ -676,10 +713,11 @@ void progress_tick(void) g_first_drawn = 1; touched = 1; } - if (n_lines >= (uint16_t)(g_last_prog + 20)) { + if (n_lines >= (uint16_t)(g_last_prog + 10)) { g_last_prog = n_lines; spinner_tick(); - if (g_first_drawn) render_md_status_numbers(); + if (g_first_drawn) + render_md_status_numbers(); touched = 1; } if (g_first_drawn && kbhit()) { @@ -688,7 +726,8 @@ void progress_tick(void) } /* Отрисовка/WINREST/BIOS могли сбить маппинг W3, на который опирается fb() * при индексации → форсируем ре-маппинг страницы файла на следующем fb(). */ - if (touched) cur_page = 0xFF; + if (touched) + cur_page = 0xFF; } /* ================================================================== @@ -710,10 +749,12 @@ static int build_doc(uint8_t slot, uint8_t enc, uint8_t visible) { if (slot == DOC_UTF8) { if (!utf_avail) { /* первый вход: выделить страницы */ - if (!utf_alloc()) return -7; /* выделяет страницы + сбрасывает конвертер */ + if (!utf_alloc()) + return -7; /* выделяет страницы + сбрасывает конвертер */ utf_avail = 1; } - file_blk = utf_blk; file_pages = utf_pages; + file_blk = utf_blk; + file_pages = utf_pages; memcpy(file_phys, utf_phys, MAX_PAGES); if (g_utf_building) { file_size = 0; @@ -723,18 +764,25 @@ static int build_doc(uint8_t slot, uint8_t enc, uint8_t visible) file_size = utf_size; } } else { - file_blk = orig_file_blk; file_pages = orig_file_pages; file_size = orig_file_size; + file_blk = orig_file_blk; + file_pages = orig_file_pages; + file_size = orig_file_size; memcpy(file_phys, orig_file_phys, MAX_PAGES); } cur_page = 0xFF; int rc = alloc_set_storage(); - if (rc < 0) return rc; + if (rc < 0) + return rc; set_encoding(enc); - top_line = 0; viewport_x = 0; + top_line = 0; + viewport_x = 0; g_active_doc = slot; - if (visible) { g_disp_doc = slot; g_first_drawn = 0; } + if (visible) { + g_disp_doc = slot; + g_first_drawn = 0; + } g_loading = 1; g_last_prog = 0; @@ -743,7 +791,10 @@ static int build_doc(uint8_t slot, uint8_t enc, uint8_t visible) /* Зафиксировать конвертацию (на случай обрыва индекса по max_lines до конца * исходника) — иначе g_utf_building остался бы 1 и сломал бы следующую сборку. */ - if (g_utf_building) { utf_size = file_size; g_utf_building = 0; } + if (g_utf_building) { + utf_size = file_size; + g_utf_building = 0; + } g_doc[slot].built = 1; doc_save_live(slot); @@ -762,31 +813,37 @@ static void switch_encoding(uint8_t next) { uint8_t target = (next == ENC_UTF8) ? DOC_UTF8 : DOC_8BIT; - if (target == g_active_doc) { /* тот же набор — только ремап */ - set_encoding(next); g_doc[target].enc = next; - } else if (g_doc[target].built) { /* набор готов — мгновенный свап */ - doc_switch(target); g_disp_doc = target; - set_encoding(next); g_doc[target].enc = next; - } else { /* строим набор лениво */ - doc_save_live(g_active_doc); /* сохранить текущий (позиция и т.п.) */ + if (target == g_active_doc) { /* тот же набор — только ремап */ + set_encoding(next); + g_doc[target].enc = next; + } else if (g_doc[target].built) { /* набор готов — мгновенный свап */ + doc_switch(target); + g_disp_doc = target; + set_encoding(next); + g_doc[target].enc = next; + } else { /* строим набор лениво */ + doc_save_live(g_active_doc); /* сохранить текущий (позиция и т.п.) */ #if WITH_RAW - g_ready = 0; render_menu(); /* идёт индексация — прячем F2 */ + g_ready = 0; + render_menu(); /* идёт индексация — прячем F2 */ #endif spinner_show(1); - int rc = build_doc(target, next, 1); /* visible: прогрессивный показ первого экрана - * (progress_tick рисует по текущему виду — MD/RAW) */ + int rc = build_doc(target, next, 1); /* visible: прогрессивный показ первого экрана + * (progress_tick рисует по текущему виду — MD/RAW) */ spinner_show(0); #if WITH_RAW - g_ready = 1; render_menu(); + g_ready = 1; + render_menu(); #endif - if (rc < 0) { /* нет EMM — откат на текущий набор */ - if (target == DOC_UTF8) g_utf_failed = 1; + if (rc < 0) { /* нет EMM — откат на текущий набор */ + if (target == DOC_UTF8) + g_utf_failed = 1; doc_load_live(g_active_doc); return; } - g_disp_doc = target; /* build_doc уже выставил active/enc */ + g_disp_doc = target; /* build_doc уже выставил active/enc */ } - clamp_top(); /* привести top_line к новому набору (для MD) */ + clamp_top(); /* привести top_line к новому набору (для MD) */ } /* ================================================================== diff --git a/examples/mdview2/mdview2.h b/examples/mdview2/mdview2.h index ab2ef80..bb65a45 100644 --- a/examples/mdview2/mdview2.h +++ b/examples/mdview2/mdview2.h @@ -72,10 +72,11 @@ /* ---- Кодировки --------------------------------------------------- */ /* 8-битные (CP866/CP1251/KOI8R) различаются только ремапом глифов [128-255] * на отрисовке; UTF-8 — отдельный декодированный набор. */ -#define ENC_CP866 0 -#define ENC_CP1251 1 -#define ENC_KOI8R 2 -#define ENC_UTF8 3 +#define ENC_CP866 0 +#define ENC_CP1251 1 +#define ENC_KOI8R 2 +#define ENC_UTF8 3 +#define ENC_UNSUPPORTED -1 /* UTF16 / UTF32 */ #define CONV_MARGIN 4096u /* на сколько байт держать UTF-конвертацию впереди индексатора */ /* ---- Флаги сегмента индекса (IF_*) — общие для индексатора/кэша/вью ---- */ diff --git a/examples/mdview2/mdview2_enc.c b/examples/mdview2/mdview2_enc.c index 643288d..2bec570 100644 --- a/examples/mdview2/mdview2_enc.c +++ b/examples/mdview2/mdview2_enc.c @@ -70,12 +70,22 @@ void set_encoding(uint8_t enc) /* Самые ходовые строчные русские буквы (о е а и н т с р в л) — их байты * различают 8-битные кодировки по частоте. */ -static const uint8_t common866 [10] = {0xAE,0xA5,0xA0,0xA8,0xAD,0xE2,0xE1,0xE0,0xA2,0xAB}; -static const uint8_t common1251[10] = {0xEE,0xE5,0xE0,0xE8,0xED,0xF2,0xF1,0xF0,0xE2,0xEB}; -static const uint8_t commonkoi [10] = {0xCF,0xC5,0xC1,0xC9,0xCE,0xD4,0xD3,0xD2,0xD7,0xCC}; +// static const uint8_t common866 [10] = {0xAE,0xA5,0xA0,0xA8,0xAD,0xE2,0xE1,0xE0,0xA2,0xAB}; +// static const uint8_t common1251[10] = {0xEE,0xE5,0xE0,0xE8,0xED,0xF2,0xF1,0xF0,0xE2,0xEB}; +// static const uint8_t commonkoi [10] = {0xCF,0xC5,0xC1,0xC9,0xCE,0xD4,0xD3,0xD2,0xD7,0xCC}; +// static uint8_t in_set10(const uint8_t *s, uint8_t b) +// { +// for (uint8_t i = 0; i < 10; i++) if (s[i] == b) return 1; +// return 0; +// } + +/* Проверяем только пять самых популярных символов (о е а и н) */ +static const uint8_t common866 [5] = {0xAE,0xA5,0xA0,0xA8,0xAD}; +static const uint8_t common1251[5] = {0xEE,0xE5,0xE0,0xE8,0xED}; +static const uint8_t commonkoi [5] = {0xCF,0xC5,0xC1,0xC9,0xCE}; static uint8_t in_set10(const uint8_t *s, uint8_t b) { - for (uint8_t i = 0; i < 10; i++) if (s[i] == b) return 1; + for (uint8_t i = 0; i < 5; i++) if (s[i] == b) return 1; return 0; } @@ -88,7 +98,7 @@ uint8_t detect_encoding(void) return ENC_UTF8; uint32_t n = file_size; - if (n > 4096u) n = 4096u; /* сэмпл: первые 4 КБ — детекции хватает */ + if (n > 1024u) n = 1024u; /* сэмпл: первый 1 КБ — детекции хватает */ uint8_t utf_ok = 1, has_mb = 0, has_high = 0, cont = 0; uint16_t s866 = 0, s1251 = 0, skoi = 0; @@ -102,10 +112,11 @@ uint8_t detect_encoding(void) if (cont) { if ((b & 0xC0) == 0x80) cont--; else { utf_ok = 0; cont = 0; } - } else if (b >= 0xC2 && b <= 0xDF) { cont = 1; has_mb = 1; } - else if (b >= 0xE0 && b <= 0xEF) { cont = 2; has_mb = 1; } - else if (b >= 0xF0 && b <= 0xF4) { cont = 3; has_mb = 1; } - else utf_ok = 0; /* битый лид/одиночный континюэйшн */ + } + else if (b >= 0xC2 && b <= 0xDF) { cont = 1; has_mb = 1; } + else if (b >= 0xE0 && b <= 0xEF) { cont = 2; has_mb = 1; } + else if (b >= 0xF0 && b <= 0xF4) { cont = 3; has_mb = 1; } + else utf_ok = 0; /* битый лид/одиночный континюэйшн */ } /* Незавершённая multibyte-последовательность на КОНЦЕ — нарушение только * если это настоящий EOF; на границе сэмпла (n HELP_W - 2u) len = HELP_W - 2u; + + if (len > HELP_W - 2u) + len = HELP_W - 2u; bios_set_place(y, x); - if (len > 0) bios_writeattr(s, len, attr); + if (len > 0) + bios_writeattr(s, len, attr); /* place уже продвинут bios_writeattr на len колонок (verified). */ if (len < HELP_W - 2u) { bios_fillcharattr(' ', ATTR_HELP_BG, (uint8_t)(HELP_W - 2u - len)); @@ -70,24 +73,25 @@ void show_help(void) /* Содержимое (20 внутренних строк) */ uint8_t r = 0; help_line(r++, "", ATTR_HELP_BG); - help_line(r++, " MDView v0.2 -- Markdown Viewer for Sprinter", ATTR_HELP_HDR); - help_line(r++, " (c) 2026 Petrov A.G.", ATTR_HELP_BG); + help_line(r++, " MDView v1.0 (a3) -- Markdown Viewer for Sprinter", ATTR_HELP_HDR); + help_line(r++, " (c) 2026 \x8F\xA5\xE2\xE0\xAE\xA2 \x80\x2E\x83\x2E", + ATTR_HELP_BG); help_line(r++, "", ATTR_HELP_BG); help_line(r++, " Navigation:", ATTR_HELP_HDR); help_line(r++, " \x18 \x19 Scroll one line up / down", ATTR_HELP_BG); help_line(r++, " PgUp PgDn Scroll one page up / down", ATTR_HELP_BG); help_line(r++, " Home End Jump to beginning / end of document", ATTR_HELP_BG); - help_line(r++, " \x1B \x1A Horizontal pan (code blocks/tables)", ATTR_HELP_BG); + help_line(r++, " \x1B \x1A Horizontal pan (code blocks/tables/unwrap)", ATTR_HELP_BG); help_line(r++, " Esc F10 Exit", ATTR_HELP_BG); help_line(r++, "", ATTR_HELP_BG); help_line(r++, " Markdown elements:", ATTR_HELP_HDR); - help_line(r++, " # ## ### Headings H1-H6", ATTR_HELP_BG); - help_line(r++, " **bold** *italic* `code` ~~strike~~", ATTR_HELP_BG); - help_line(r++, " > quote ``` ... ``` Fenced code block", ATTR_HELP_BG); - help_line(r++, " - * + item 1. 2. Ordered list", ATTR_HELP_BG); - help_line(r++, " |----|----| Tables", ATTR_HELP_BG); + help_line(r++, " # ## ### Headings H1-H6, **bold**, *italic*,", ATTR_HELP_BG); + help_line(r++, " `code`, ``` code ```, ~~strike~~, > quote", ATTR_HELP_BG); + help_line(r++, " - * + 1. 2. Ordered list, |----|----| Tables", ATTR_HELP_BG); help_line(r++, "", ATTR_HELP_BG); - help_line(r++, " Encoding:", ATTR_HELP_HDR); + help_line(r++, " Encoding and View modes:", ATTR_HELP_HDR); + help_line(r++, " F2 RAW Mode", ATTR_HELP_BG); + help_line(r++, " F3 Wrap/Unwrap Mode for RAW View", ATTR_HELP_BG); help_line(r++, " F8 Cycle CP866 / CP1251 / KOI8-R / UTF-8", ATTR_HELP_BG); help_line(r++, " Auto-detected on open; F8 to override", ATTR_HELP_BG); help_line(r++, "", ATTR_HELP_BG); diff --git a/examples/mdview2/mdview2_md.c b/examples/mdview2/mdview2_md.c index 9c10ce7..3e17751 100644 --- a/examples/mdview2/mdview2_md.c +++ b/examples/mdview2/mdview2_md.c @@ -187,14 +187,19 @@ uint8_t md_key(uint8_t scan) md_scroll_down(VIEW_H); break; case KEY_HOME: - top_line = 0; - viewport_x = 0; - draw_viewport_from_cache(); + if(top_line != 0 || viewport_x != 0 ) { + top_line = 0; + viewport_x = 0; + draw_viewport_from_cache(); + } break; case KEY_END: - top_line = (n_lines > VIEW_H) ? (uint16_t)(n_lines - VIEW_H) : 0; - viewport_x = 0; - draw_viewport_from_cache(); + uint16_t new_top_line = (n_lines > VIEW_H) ? (uint16_t)(n_lines - VIEW_H) : 0; + if(top_line != new_top_line || viewport_x != 0 ) { + top_line = new_top_line; + viewport_x = 0; + draw_viewport_from_cache(); + } break; default: diff --git a/examples/mdview2/mdview2_status.c b/examples/mdview2/mdview2_status.c index f911339..0424c19 100644 --- a/examples/mdview2/mdview2_status.c +++ b/examples/mdview2/mdview2_status.c @@ -21,6 +21,7 @@ #include #include /* dec8/dec16, cputs */ #include /* textattr/gotoxy/wrchar/COLOR */ +#include #include /* bios_fillcharattr/bios_write_until */ #include "mdview2.h" @@ -32,7 +33,8 @@ static uint8_t spinner_active = 0; /* Продвигает спиннер на один кадр (если включён). */ void spinner_tick(void) { - if (!spinner_active) return; + if (!spinner_active) + return; wrchar(SPINNER_COL, 0, spinner_chars[spinner_phase & 3], ATTR_BAR_SPINNER); spinner_phase++; } @@ -73,8 +75,8 @@ void prerender_status(void) void status_encoding(void) { textattr(ATTR_BAR); - gotoxy(37, 0); - bios_write_until(enc_name(g_encoding), 7, 0); + gotoxy(DIV1_X - 10, 0); + bios_write_until(enc_name(g_encoding), 8, 0); } /* Числовая часть (MD): "L a-b / total" между разделителями + "pct%" справа. @@ -82,22 +84,29 @@ void status_encoding(void) * хром не трогает. */ 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) last = total; - textattr(ATTR_BAR); - gotoxy(DIV1_X + 1, 0); - bios_fillcharattr(' ', ATTR_BAR, DIV2_X - DIV1_X - 1); /* очистить [DIV1_X+1 .. DIV2_X-1] */ - gotoxy(DIV1_X + 2, 0); - cputs("L "); - dec16(top_line + 1); - cputs("-"); - dec16(last); - cputs(" / "); - dec16(total); - if (g_loading) cputs("..."); /* ещё грузится */ + if(local_total != total || local_last != last || local_loading != g_loading) { + local_total = total; local_last = last; local_loading = g_loading; + textattr(ATTR_BAR); + gotoxy(DIV1_X + 2, 0); + bios_fillcharattr(' ', ATTR_BAR, DIV2_X - DIV1_X - 2); /* очистить [DIV1_X+1 .. DIV2_X-1] */ + gotoxy(DIV1_X + 2, 0); + cputs("L "); + dec16(top_line + 1); + cputs("-"); + dec16(last); + cputs(" / "); + dec16(total); + if (g_loading) cputs("..."); /* ещё грузится */ + } } @@ -109,11 +118,15 @@ void render_full_status(void) } void render_percent_progress(uint8_t pct) { - gotoxy(DIV2_X + 1, 0); - bios_fillcharattr(' ', ATTR_BAR, SCREEN_W - DIV2_X - 1); /* очистить [DIV2_X+1 .. конец] */ - gotoxy(DIV2_X + 2, 0); - dec8(pct); - cputs("%"); + static uint8_t local_pct = UCHAR_MAX; + if (local_pct != pct) { + local_pct = pct; + gotoxy(DIV2_X + 2, 0); + bios_fillcharattr(' ', ATTR_BAR, SCREEN_W - DIV2_X - 2); /* очистить [DIV2_X+1 .. конец] */ + gotoxy(DIV2_X + 2, 0); + dec8(pct); + cputs("%"); + } } #if WITH_RAW @@ -141,7 +154,8 @@ void render_menu(void) * только у задействованных и доступных сейчас. */ fill_row(MENU_ROW, ATTR_MENU_T); - char num[3]; num[2] = 0; + char num[3]; + num[2] = 0; for (uint8_t i = 0; i < 9; i++) { /* F1..F9: ' 1'..' 9' */ num[0] = ' '; num[1] = (char)('1' + i); put_str_attr((uint8_t)(i * 8), MENU_ROW, num, ATTR_MENU_K); diff --git a/lib/Makefile b/lib/Makefile index 74361ab..e1570fc 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -60,6 +60,7 @@ LIBC_C := \ libc/stdio/getchar.c \ libc/stdio/putchar.c \ libc/stdio/puts.c \ + libc/stdlib/minmax.c \ libc/file/file.c \ libc/stdio/hex_print.c \ libc/stdio/dec_print.c \ diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h new file mode 100644 index 0000000..ce8a295 --- /dev/null +++ b/libc/include/stdlib.h @@ -0,0 +1,12 @@ +#ifndef STDLIB_H +#define STDLIB_H + +#include /* size_t */ +#include + + +int16_t min(int16_t a, int16_t b); +int16_t max(int16_t a, int16_t b); + + +#endif diff --git a/libc/stdlib/minmax.c b/libc/stdlib/minmax.c new file mode 100644 index 0000000..d2d2b80 --- /dev/null +++ b/libc/stdlib/minmax.c @@ -0,0 +1,42 @@ +#include + +int16_t min(int16_t a, int16_t b) __naked +{ + (void)a; (void)b; + __asm + ld a, h + cp d + jr c, min_less + jr nz, min_greater + ld a, l + cp e + jr c, min_less + min_greater: + ret /* DE уже содержит b */ + min_less: + ex de, hl + ret + __endasm; +} + +int16_t max(int16_t a, int16_t b) __naked +{ + (void)a; (void)b; + __asm + ld a, h + cp d + jr c, max_less + jr nz, max_greater + ld a, l + cp e + jr c, max_less + ret /* a >= b, return a in HL */ + max_less: + /* a < b, return b in DE */ + ret /* DE already contains b */ + max_greater: + /* a > b, return a in HL */ + ex de, hl + ret + __endasm; +}