Я уже понял, что надо :) . Это уникальная вещь в своем роде. У программиста должен быть выбор. Я бы уже давно протестировал, просто лень ставить 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', а можно развернуть код (если память не жмет).
Точно, всё правильно.
Тогда ещё вопрос в зал: проект на sjasm разбит на несколько файлов, но часть процедур используется одна и та же.
Приходится писать везде строчку типа:
Метка equ Адрес
А как сделать чтобы автоматом метки работали, как будто весь проект в одном файле?
Слить в один файл с указанием где какой банк памяти по ходу текста?
Ммм по ассемблерам на PC не подскажу, код писал пока только на реале))
Предположу, по аналогии, что там должны быть инструкции включения других файлов в проект.
Насчет банков, скорее всего, верно, на реале тоже можно распихивать код (и исходники) по страницам.
Да, я просто думал есть волшебная команда BANK. Но похоже она не так работает.
Изначально проект в нескольких файлах, как бы перекрёстные ссылки автоматом сделать. Из файла в файл.
Или надо собрать всё с помощью INCLUDE в один файл и не думать.
upd. То есть компилируем единый файл и выгружаем частями, если надо.
Переформулирую: Как правильно сделать так, чтобы за один клик компилировалась большая прога и выгружался код в разные файлы для каждого банка памяти. Там же все они с одного адреса, типа #c000. И могли быть ссылки из любой части кода в любой. И можно было без проблем что-то менять в тексте, после чего адреса меток скомпилируются новые, естественно.
А потом загрузчик проги загружал всё по нужным банкам.
То есть можно типа:
org #c000
....
save "part1"
org #c000
...
save "part2"
ну во первых sjasm поддерживает sna128
а делается это как то так
Код:device zxspectrum128
include "_defines.a80"
slot 3
page 1
org #c000
incbin "./bin/gm.ram1.bin"
page 3
org #c000
incbin "./bin/gm.ram3.bin"
include "_levels.a80"
page 4
org lev1_data
incbin "./bin/stage1.bin"
page 6
org #c000
play_mus
include "_pt3_player.a80"
mus_table
dw mus_boss ;1 ;menu
dw intro_music ;2 ;intro
dw mus_stagestart ;3
dw mus_level1 ;4
dw mus_level2 ;5
dw mus_level3 ;6
dw mus_level4 ;7
dw mus_level5 ;8
dw mus_boss ;9
dw mus_garuda ;10
dw mus_stageclear ;11
dw mus_gameover ;12
dw mus_boss ;13
dw out_mus0 ;14
dw out_mus1 ;15
dw mus_boss ;16 ;empty mus
; dw mus_boss ;17
; dw mus_boss ;18
; dw mus_boss ;19
mus_boss incbin "\music\boss\BOSS.pt3"
mus_stagestart incbin "\music\stagestart.pt3"
mus_stageclear incbin "\music\stageclear.pt3"
mus_gameover incbin "\music\gameover.pt3"
ays_effects incbin "\sfx\sw.afb"
display "music free:",#10000-$
savebin "./bin/gm.music.bin",#c000,$-#c000
music_buf equ $
org music_buf
mus_level1
mus_level2
mus_level3
mus_level4
; incbin "\music\Level1.pt3"
; incbin "\music\level2.pt3"
; incbin "\music\L3final.pt3"
; incbin "\music\Level4.pt3"
mus_level5
incbin "\music\Level5.pt3"
mus_garuda
incbin "\music\GARUDA_FINAL_BATTLE.pt3"
display "l5music ",$
savesna "qsave.sna",beginning
В целом понятно, всем спасибо.
Напомните, пожалуйста, адрес подпрограммы ПЗУ - подобие бейсикового PAUSE.
Вспомнил - 7997
Объясните мне пожалуйста про байт. Принимать значений он может 256. Но как они считаются? Когда имеются все 8 бит - 00000000, или складываются так:
Количество значений 1 бита
0ххххххх
+
Количество значений 2х бит
00хххххх
+
.... И так далее?
- - - Добавлено - - -
Объясните мне пожалуйста про байт. Принимать значений он может 256. Но как они считаются? Когда имеются все 8 бит - 00000000, или складываются так:
Количество значений 1 бита
0ххххххх
+
Количество значений 2х бит
00хххххх
+
.... И так далее?
Эммм.
00000000 - 0
00000001
00000010
00000011
00000100
...
11111111 - 255
Всего 256.
В чем вопрос?
В 10-ой 3 знаками можно записать 1000 чисел, от 0 до 999. Тут так же. Только разряд хранит не 10, 2 возможных значения.
- - - Добавлено - - -
Емкость = Основание системы (2) в степени числа разрядов (8). 2^8=256.
10^3=1000.
А почему это число 256 пишут ещё как +128 и - 128?
Знаковое. Старший бит как знак, 7 бит -- число.
в байте то нет
ну когда нуужон счетчик на 256
можно использовать 0 :)
ld b,low 256 ;0
djnz $
- - - Добавлено - - -
с третей стороны это в ваших сях байт равен 0...255
на асме жо он можот быть равен тому чего надо програмизду
0...1
-10...+92
0...358,59°
Как мы хотим представить себе значения байта это вопрос отдельной темы...
Значение байта при этом никак не изменится как было от #00 до #FF так и останется
байт это 8 бит
как програмист решит их трактовать
так оно и будет :)
оно можот быть вообще двоично десятичным
а сяпаскали так не умеют
Многие наверняка нижеописанное знают, однако, мало ли. Чуток оффтопного капитанства в продолжение темы байта.
Принимать он может 256 значений, часто применяются лукап-таблицы по 256 байт (или 256+256 для 16-битных слов), но я не про это.
У восьмиразрядного счетчика, коим является байт - ну или регистр, что чаще - есть одно замечательное свойство.
Неважно, какое значение мы прибавляем к байту (регистру) - через 256 повторов мы получим изначальное содержимое счетчика.
Для четных приращений оно "вернется" раньше, кратно степени двойки, т.е. на 256 повторов получим 2/4/8 и так далее возвратов к исходному числу.
Для любой нечетной прибавки, хоть +1, хоть +171, через 256 шагов счетчик примет исходный вид. Разумеется, оперируя байтом, а не словом.
Соответственно, если с неким шагом перебирать таблицу в 256 байт через приращение младшего регистра в паре, за 256 проходов она гарантированно будет обработана.
я о тёплом, вы о мягком....
байт может кодировать ровно 256 значений от %00000000 до %11111111. нет там ни 256, ни 511, 510 и т.п.
как значение байта интерпретирует программер, это уже совсем иной вопрос.
Каждый прав, исходя из собственного определения байта. Суть одна и та же.
Изначально человека знакомят с битом, а потом с байтом как восьмью битами.
Учащийся должен сам попытаться посчитать, сколько различных состояний может принимать один бит, два бита, три бита и наконец восемь бит.
С другого захода человеку рассказывают, что есть десятичная система, где основание десять, а есть всякие другие. Особенно двоичная.
А наивный вопрос "что первично?", он как то сам по себе возникает в голове стайных животных с иерархией. Кто главнее?
Вот тот же z80 он по разному интерпретирует байт.
Как 8 уникальных бит в логических операциях.
Как ряд из 8 бит в операциях сдвига.
как целое 0..255 или -128..127 в операциях сложения отнимания, в зависимости от дальнейшего использования флагов.
Как смещение -128..+127 в коротких переходах и обращениях по индексным регистрам.
Чуть костылнее двоичнодесятичное представление и как два набора по четыре бита.
Видеосистема zx интерпретирует байт как ряд из 8 бит-пикселей и как совокупность бита мигания, бита яркости, 8 цветам подложки и 8 цветам чернил.
В других портах тоже соответствующие интерпретации.
Хотя первичны электрические состояния в восьми пронумерованных проводниках.
А программист может интерпретировать гораздо шире. Считать, например, байт числом от 1900 до 2155.
Определение же байта тоже у всех может быть разное. Смотря с какой стороны ты к сути байта подошёл.
И вот тут (снова пооффтоплю) виден разный подход у разных людей. Вернёмся в прошлый век, к первым компам, да даже к первым линейкам PC, где год даты задавался всего одним байтом для экономии памяти. Вводился он непосредственным значением, скажем, 90-й. Может, там даже использовали символьное представление, тогда уходит два байта. В результате получили знаменитую "проблему 2000" при обнулении этого самого числа. Но что мешало задать дату смещением, выбрав за точку отсчёта некий год, например, год создания первого компьютера или (для удобства отсчёта) 1900-й, например? Всего один байт смещения решил бы проблему даты на двести с лишним лет вперёд - по сути, навсегда.
Ну вот Unix date считается с 1972 года, и в 2036 юниксовы года закончатся. Это не решение проблемы, а заметание мусора под ковёр. Лучше всё-таки хранить дату, как есть.