Я уже понял, что надо :) . Это уникальная вещь в своем роде. У программиста должен быть выбор. Я бы уже давно протестировал, просто лень ставить VS 2019, но как-нибудь протестирую.
Вид для печати
У него ХР.
Подскажите, как быстро переходить по строке вверх/вниз на расширенном экране скорпиона?
У него все строчки по порядку идут, каждая 80 байт.
Знаю, что на тех компах, где между соседними строчками ровно 2048 байт, пользуются командами типа
set 3,d
res 3,d
А тут как? Вот самый простой и медленный вариант, для ширины спрайта 6 байт:
;de - адрес на экране
;hl - адрес спрайта
ldi ;скопировали байт
ldi
... ;перенесли одну строчку спрайта
push hl ; теперь на строку ниже
ld hl,80-6 ;ширина строки минус ширина спрайта
add hl,de ;перешли на след. строку
ex de,hl
pop hl ;восстановили hl
Есть способы побыстрее?
Давно спрашивали, но ответа не было... пускай будет))
Условимся, что машина без циклов wait. Считаем такты в исходном примере: 11+10+11+4+10 = 46, длина 7 байт.
Без использования стека как хранилища/приемника данных вариантов немного. Первый, без каких-либо опций со стеком:
ld hl ,from
ld de ,to
ld bc ,80-ширина спрайта ; b=0, c=смещение
ld a,с ; аккум хранит смещение, задается один раз перед выводом спрайта
ldi ldi ldi сколько надо
------ сама процедура перевода строки:
ld c,a ; восстанавливаем регистр
ex de, hl
add hl, bc
ex de, hl
------ все, дальше опять пошло ldi ldi ldi
Итого: 4+4+11+4 = 23 такта, 4 байта. Используем аккум, зато в 2 раза ускоряем процедуру.
Если код вывода свернут в цикл, счетчик можно организовать в половинке IX либо в альт. регистре
Второй способ нестандартный, используем регистр SP как константу:
ld (savesp+1), sp ; сохраняем стек
ld sp, смещение ; (80-ширина) грузим смещение в SP и больше его не трогаем
; задаем hl и de. аккумулятор не задействуется
ldi ldi ldi сколько надо
------ сама процедура перевода строки:
ex de, hl
add hl, sp
ex de, hl
------ все, дальше опять пошло ldi ldi ldi
savesp ld sp, 0 ; восстанавливаем sp, конец вывода
Итого 19 тактов, 3 байта. Разница с первым вариантом минимальна, но все зависит от конкретных условий применения.
Сразу видно ограничение: можно юзать только при запрещенных прерываниях, поскольку sp будет указывать в ПЗУ.
Однако можно красиво обойти его при одном условии: строки спрайта хранятся наоборот, от нижних к верхним, и выводятся так же.
В таком случае смещение задается отрицательное, т.к. нужно вернуться "назад" по экранным адресам, зато регистр sp будет указывать
на самый верх ОЗУ (#FFXX), который можно спокойно затереть (скажем, верхние 256 байт памяти резервируем и не трогаем).
Сама процедура аналогична предыдущей, можно юзать при разрешенных прерываниях.
Именно, думаете)) вся соль в начальном задании пары BC как нуля (B) и ширины спрайта в C.
Если кол-во команд LDI равно ширине спрайта - LDI будет менять только С, а после каждой строки BC будет равно нулю (до перевода строки).
После вывода спрайта HL=адрес след. спрайта, если лежат последовательно, - может пригодиться.
Счетчик, как указывал, можно организовать в половинках IX/IY либо в AF', а можно развернуть код (если память не жмет).