Разработка и ромхакинг > Программирование
[NES] Изучаем Ассемблер 6502
<< < (2/2)
Ti_:

--- Цитата: Arigato от 03 Июнь 2023, 17:09:38 ---В общем, как такое решение? Можно ли что-то улучшить или оптимизировать?

--- Конец цитаты ---
Не совсем понял, но отдельный код для вывода каждой строки нигде не делают, обычно везде одна функция печати строки, и для нее параметры передаются. Это может быть даже просто её номер, а всё остальное в массиве данных быть. Вычисления как раз можно через макрос сделать.  LDA PPU_STATUS тоже нет никакого смысла каждый раз перед установкой адреса делать, это нужно только в 1 случае - если ты где-то записал только 1 раз в $2006 или $2005. Сам по себе регистр на 'нечетный' никак не слетит.

Вот под твой случай:

--- Код: ---; 2 переменные обязательно в zeropage!
tmp_ptr_l equ $20
tmp_ptr_h equ $21

; макрос для печати строки (не знаю подойдёт ли под твой asm)
MACRO print_str str_x,str_y,str_ptr,nt
LDX #>((str_y*32)+$2000 + nt*$400)
LDY #<(str_y*32 + str_x)
LDA #<str_ptr
STA tmp_ptr_l
LDA #>str_ptr
JSR print_str_
ENDM

; функция печати
print_str_:
STA tmp_ptr_h
STX PPU_ADDRESS
STY PPU_ADDRESS
LDY #0
LDA (tmp_ptr_l),Y
@print_l
INY
STA PPU_DATA
LDA (tmp_ptr_l),Y
BNE @print_l
RTS

stroka1: .BYTE 'TEST STROKA 1        ',0
stroka2: .BYTE '   STROKA 2 TEST     ',0


; пример использования в коде:
print_str 4,5,stroka1,0    ; печать строки str0 по x=4,y=5, экран0
print_str 10,15,stroka2,0  ; печать строки str1 по x=10,y=15, экран0

--- Конец кода ---
Arigato:

--- Цитата: Ti_ от 03 Июнь 2023, 21:59:12 ---LDA PPU_STATUS тоже нет никакого смысла каждый раз перед установкой адреса делать, это нужно только в 1 случае - если ты где-то записал только 1 раз в $2006 или $2005.
--- Конец цитаты ---
Ну по идеи чисто в теории такая ситуация может возникнуть, если между парой записей произойдет вызов nmi. Хотя это весьма странно, так как к этому моменту работу с PPU уже надо бы завершить. Но читал рекомендацию делать LDA PPU_STATUS, видимо, как раз на такой случай (вариант что просто в коде где-то забыли второй раз записать маловероятен, да и в принципе ошибочен). В общем убрал.

По поводу печати, то у меня две отдельные подпрограммы: одна устанавливает "курсор" в нужную клетку экрана, а другая выводит текст, перемещая курсор в конец строки (ну это автоматически происходит при обращении к PPUDATA). Это позволяет вызывать подпрограмму печати одну за другой, тогда текст будет выводиться дальше, за предыдущим. По логике это как в обычном BASIC командой PRINT происходит.

Например:


--- Код: --- _GOTOXY #1, #11 ; это координаты курсора
_PRINT str_hello4 ; это вывод строки на экран
_PRINT16 game_hst ; тут вывод 16-битного числа
_PRINT_CHAR #'.' ; и символ "." в конце предложения
--- Конец кода ---

На экране это выглядит так:



При этом в _GOTOXY можно передавать не только числа (константы), но и регистры или переменные. Скажем: _GOTOXY #10, Y - установить курсор в строку с номером Y (регистр) в позицию 10.

Выбор экранов пока не сделал, в данный момент мне это не нужно. Может позже добавлю.
Ti_:

--- Цитата: Arigato от 03 Июнь 2023, 23:04:00 ---Ну по идеи чисто в теории такая ситуация может возникнуть, если между парой записей произойдет вызов nmi. Хотя это весьма странно, так как к этому моменту работу с PPU уже надо бы завершить.

--- Конец цитаты ---
Само по себе NMI не сбрасывает адрес тоже. Просто там может быть, код который тоже делает запись в vram, или даже просто строчка BIT PPU_STATUS.
Только чтение PPU_STATUS в основном цикле в этом случае не поможет, код всё равно 'посыпется'. Потому что тогда nmi может проскочить и 'между строк' установки адреса, или просто в цикле записи в PPU_DATA.
Поэтому, если у тебя много данных для записи (более 1 фрейма по времени) то NMI отключают вместе с дисплеем (или можно в самом nmi вначале добавить 'флаг'),  а если у тебя записи в пределах vblank или даже экрана, то случайно/повторно в текущем кадре nmi сработать не может.

Добавлено позже:

--- Цитата: Arigato от 03 Июнь 2023, 23:04:00 ---При этом в _GOTOXY можно передавать не только числа (константы), но и регистры или переменные. Скажем: _GOTOXY #10, Y - установить курсор в строку с номером Y (регистр) в позицию 10.
--- Конец цитаты ---
Понятно, ну минимально можно сделать функцию вместо макроса .macro _PRINT ,  чтобы не забивать ром однотипным кодом (передавать адрес строки).  Если скорость не важна, можно даже сделать и отдельную функцию для установки адреса сделать вместо макроса, а в макросе оставить только вычисление A и Y.

--- Код: ---proc_set_ppu_addr:
 STA PPU_ADDRESS
 STY PPU_ADDRESS
 RTS
--- Конец кода ---

Если наоборот нужна скорость , можно и в столбик строчки писать (такое тоже встречается):

--- Код: ---; 'PRESS START'
   LDX #'P'
   STX PPU_DATA
   INX  ; R'
   STX PPU_DATA
   LDA #'E'
   STA PPU_DATA
   LDY #'S'
   STY PPU_DATA
   STY PPU_DATA
   LDA #'  '
   STA PPU_DATA
   STY PPU_DATA ; 'S'
   INY ; 'T'
   STY PPU_DATA ; 'T'
   LDA #'A'
   STA PPU_DATA  ; 'A'
   STX PPU_DATA  ; 'R'
   STY PPU_DATA ; 'T'
--- Конец кода ---

Касаемо вычислений, можно так попробовать:

--- Код: ---offset:
LDA #>SCR_BASE ; SCR_BASE = $2000
ORA sreg + 1
        STA PPU_ADDRESS
        TXA
        ORA sreg
        STA PPU_ADDRESS
        RTS
--- Конец кода ---
Arigato:

--- Цитата: Ti_ от 04 Июнь 2023, 08:00:20 ---Поэтому, если у тебя много данных для записи (более 1 фрейма по времени) то NMI отключают вместе с дисплеем (или можно в самом nmi вначале добавить 'флаг'),
--- Конец цитаты ---
Или можно разбить вывод на несколько кадров, если скорость неважна. Я так делаю, разбиваю информацию на части и вывожу порциями в разных кадрах.

Навигация
Главная страница сообщений
Предыдущая страница

Перейти к полной версии