diff --git a/examples/mdview2/mdview2.c b/examples/mdview2/mdview2.c index 47d4ebe..e8c037b 100644 --- a/examples/mdview2/mdview2.c +++ b/examples/mdview2/mdview2.c @@ -350,60 +350,61 @@ static inline void map_page(uint8_t page) /* Читает один байт логического файла по смещению p. * При переходе между страницами автоматически переключает W3. * Проверка границ выполняется вызывающей стороной. - */ - -static char fb(uint32_t p) + * + * Эквивалент C-кода (оставлен для справки): + * uint8_t *pb = (uint8_t *)&p; + * uint8_t page = (pb[1] >> 6) | (pb[2] << 2); + * uint16_t off = ((pb[1] & 0x3F) << 8) | pb[0]; + * map_page(page); // if (page!=cur_page){cur_page=page; OUT W3,file_phys[page];} + * return FILE_BUF[off]; // *(0xC000 + off) + * + * Ручной asm — это горячая примитивная операция (вызывается сотни тысяч раз + * при индексации 50КБ-файла); C-версия тратила вызов функции + 32-битную + * арифметику на КАЖДЫЙ байт. Раскладка __sdcccall(1): аргумент uint32_t в + * HLDE (E=pb[0], D=pb[1], L=pb[2], H=pb[3] — проверено sdcc -S), возврат + * char в A. Координация маппинга с bank_read/bank_write держится на том, + * что _io_page_w3 — это ПОРТ (__sfr 0xE2): здесь пишем его через OUT, + * bank_read читает через IN — общий аппаратный регистр, без теневой RAM. + * NB: __naked обязателен (внутри собственный ret); IX/IY не трогаем + * (callee-saved), BC/DE/HL/AF — caller-saved, можно клобберить. */ +static char fb(uint32_t p) __naked { - uint8_t *pb = (uint8_t *)&p; - uint8_t page = (uint8_t)((pb[1] >> 6) | (pb[2] << 2)); - uint16_t off = (uint16_t)(((uint16_t)(pb[1] & 0x3F) << 8) | pb[0]); - map_page(page); - return FILE_BUF[off]; -/* - // p = HLDE - (void)p; - - __asm -; uint16_t off = (uint16_t)(((uint16_t)(pb[1] | 0xC0) << 8) | pb[0]); + (void)p; /* p = HLDE; доступ только из asm */ + __asm + ; off -> BC = 0xC000 + ((pb[1]&0x3F)<<8 | pb[0]) ; D=pb[1], E=pb[0] ld a, d - or a, #0xC0 + or a, #0xC0 ; (D|0xC0) == (D&0x3F)|0xC0 — старший байт окна W3 ld b, a - ld c, e - -; uint8_t page = (uint8_t)((pb[1] >> 6) | (pb[2] << 2)); - ld a, l ;; pb[2] << 2 - add a, a - add a, a - ld e, a ;; e = pb[2] << 2 - - ld a, d ;; pb[1] >> 6 - rlca - rlca - and a, #0x03 + ld c, e ; C = pb[0] - or a, e ;; a = (pb[2] << 2) | (pb[1] >> 6) - ld e, a -; map_page(page); -; if (page != cur_page) { + ; page = (pb[1]>>6) | (pb[2]<<2) ; L=pb[2] + ld a, l + add a, a + add a, a ; A = pb[2]<<2 + ld e, a ; E свободен (pb[0] уже сохранён в C) + + ld a, d + rlca + rlca + and a, #0x03 ; A = pb[1]>>6 + or a, e ; A = page + ld e, a ; E = page + + ; map_page(page) ld a, (_cur_page) cp e - jr Z, __fbl0 -; cur_page = page; + jr Z, fb_same ld a, e ld (_cur_page), a -; sprinter_page_w3(file_phys[page]); ld hl, #_file_phys ld d, #0x00 - add hl, de + add hl, de ; hl = &file_phys[page] ld a, (hl) - out (__io_page_w3), a -; } -__fbl0: -; return FILE_BUF[off]; - ld a, (bc) + out (#0xE2), a ; OUT PORT_PAGE_W3 (== _io_page_w3 sfr) + fb_same: + ld a, (bc) ; A = *(0xC000 + off) ret __endasm; -*/ } /* ESTEX WINREST (5Ah, RST 0x10) — копирует готовый буфер (char,attr) @@ -1663,7 +1664,10 @@ static void render_line_to_cache(uint16_t line_idx) ch = ' '; } - if (parse_inline) { + /* handle_inline_marker реагирует только на ` * _ ~ — для остальных + * символов (подавляющее большинство) она возвращает 0 без side-эффектов. + * Пропускаем вызов функции (6 аргументов) на горячем пути обычного текста. */ + if (parse_inline && (ch == '`' || ch == '*' || ch == '_' || ch == '~')) { char lit_ch = 0; uint8_t mk = handle_inline_marker(ch, &p, seg_end, prev_ch, &emph, &lit_ch); if (mk == 1) { @@ -1689,7 +1693,11 @@ static void render_line_to_cache(uint16_t line_idx) cc = tgt; prev_ch = ' '; } else { - cc_put(cellbuf, &col, ch, cur_attr); + /* инлайн cc_put: col < MAX_CACHE_LINE_LEN гарантирован условием while */ + uint16_t ci = (uint16_t)col * 2u; + cellbuf[ci] = (uint8_t)ch; + cellbuf[ci + 1] = cur_attr; + col++; cc++; prev_ch = ch; } @@ -1744,7 +1752,7 @@ static void draw_line_from_cache(uint16_t line_idx, uint8_t row) * перерисовки видимой области после загрузки файла (Фаза 3-4). */ static void draw_viewport_from_cache(void) { - for (uint8_t i = 0; i < VIEW_H - 1; i++) { + for (uint8_t i = 0; i < VIEW_H; i++) { draw_line_from_cache((uint16_t)(top_line + i), (uint8_t)(VIEW_TOP_ROW + i)); } }