+432.17
Рейтинг
1200.49
Сила
Попробовал так сделать — ассемблер ругается что символ неопределён. Логично, ведь ini-файл есть параметр в линкер, но не в ассемблер. А если сообщаешь через .global что есть символ который потом пытаешься положить в .byte, то ругается что range error. Опять таки логично, ведь символы это адреса как правило и обойти можно сделав <NAME, т.е. взять младший байт и видимо в простой ситуации как PRG_BANKS уже сработало бы, но я попытался воткнуть это в вычисление по битовым маскам
byte MIRRORING | (HAS_SRAM << 1) | ((MAPPER & $0F) << 4) | NAME
и тут линкер выдал ошибку «Attribute expected» которая даже не гуглится особо да и я не понимаю как линкер может такое вообще отрабатывать нормально. Если только весь байт сразу там и определить разве что, но есть ли там битовые операции?
  • avatar aa-dav
  • 0
Нда, сам не заметил как скатился к полному разжёвыванию каждого нового встреченного ключевого слова и объяснения как байты лежат в памяти, так что заявление из первой статьи о том, что я не буду учить как программировать в ассемблере и архитектуре 6502 вообще пошло ломанными трещинами и начало рассыпаться в пух и прах.
Уже даже не пойму какая аудитория выйдет идеальной для этого всего, уже даже закрадывается что как тот PHP-шник который стал делать выступления на конференциях как он стал писать на NES за месяц. :D
  • avatar aa-dav
  • 0
P.S.
А ведь если задуматься, то такой подход (как у SjAsm) ничем не мешает и созданию кросс-платформенных форматов — генерацию каких то заголовков и служебных вещей тоже легко положить на какие то макросы из SAVEBIN OUTPUT_FILE которые обязательно надо выполнить в оговоренном порядке. В общем то дело техники. И у меня возникает подозрение, что FASM так и работает, поэтому конкретные форматы конкретных PE и COFF там дело библиотечного уровня.
  • avatar aa-dav
  • 0
В SjAsmPlus код в банках размещается как раз ORG'ами в одни и те же адреса и сохраняется в бинарники по мере трансляции, т.е. в те моменты, когда в нужных адресах виртуальной памяти сгенерирован нужный код, а дальше по ходу трансляции он может быть перезаписан.
О, кстати, вчитался и да — это то что мне было непонятно, вчера уже сонный был, так что цитата выше немного не по делу и касается только первой части. Получается что путало само наличие директивы PAGE X, и это воспринималось как раз как то наподобие сегментации, но непонятно как работающее в рамках многостраничных моделей. А это просто как бы переключение виртуальной памяти по схеме реальных 128Кб для возможных упрощений в каких то моментах, но сбрасывать на диск всё-равно надо постранично в момент активации нужных страниц.
Теперь и с SjAsmPlus всё понятно, спасибо.
  • avatar aa-dav
  • 0
Процитирую себя же из начала статьи:
В целом такой же «сегментированный» модульный и высокоуровневый подход не редкость и в ассемблерах и активно использовался и в программировании на Intel 8086, так что наверняка для многих из вас открытием он не будет. Но тем кто привык под «модулями» понимать просто включаемые в основной файл директивой INCLUDE тексты цельной программы компилируемые в один проход — тем надо немного переучится.
Не оно разве?
  • avatar aa-dav
  • 0
CA65/CC65 — пакет не для конкретно NES, а для любых систем на 6502
Нигде я не говорил что CC65 это только для NES, более того в начале этой части статьи написано про любой MOS 6502, но как то абстрактно и действительно стоит обозначить что cc65 имеет широкий охват. Это стоит сделать еще в предыдущей части. Действительно.

Также бывают ситуации, когда часть памяти кода переключаемая (разная память в одних и тех же адресах, т.е. банки)
Ни видел упоминаний сегментов в нескольких серьёзных исходниках, например Mighty Final Fight (под SjAsmPlus), но я тут реально слабо понимаю в том как именно в таком коде метки привязываются к переключению страниц.
У меня сложилось ощущение что просто через пару еще других ключевых слов и, вероятно, привязанных к виртуальным образам самого спектрума. Вообще не уверен.
Но разбираясь с секциями MEMORY и SEGMENTS ini-файла линкера cc65 очень быстро и легко понял как оно должно ложится на мапперы и любую структуру памяти любой машины. Это действительно сложно на первый взгляд, но понять нетрудно как и все выгоды — на самом деле даже очень просто.
Т.е. как переключать банки памяти на CA65 я понял даже быстрее чем на SjAsmPlus несмотря на то что со вторым столкнулся намного раньше.
Забавно, ведь во втором это сделано явно проще и для конкретной платформы, но глядя в документацию я не смог понять как.
А в CC65 просто поглядел пару минут в файл .ini с описаниями кусков памяти и сегментов и понял всё очень быстро.
Дальше только уточнения насчёт align и т.п. из официальной документации. И сразу понял кристально как сюда встраивать переключения банков.
Действительно вроде и сложнее, но по факту много проще.
  • avatar aa-dav
  • 0
У меня есть такая проблема — я вырос в детстве на ZX Spectrum 48 (конкретно отечественном клоне Кворум-64), но именно в детстве не стал в это деле опытным и начитанным ассемблерщиком и сейчас возвращаясь к этому и восторгаясь тем или иным вещам просто вынужден описывать как можно более подробно, вплоть для самого себя, с чем сталкиваюсь, причём опять и снова, но уже наученный про всё.
Вероятно действительно выходит ну очень подробно и с остановкой на каждом шаге. Надеюсь так и есть.
  • avatar aa-dav
  • 1
А ведь я искал по сайту на слова «многопоточность» и «многозадачность», но т.к. эта статья не содержит таких слов, то успешно не нашёл. :)
  • avatar aa-dav
  • 0
Shiru, ты везде!
Когда я искал аналогичные материалы, то наткнулся на статью на хабре про Си в рамках cc65 тут habr.com/ru/post/348022/
А это перевод англоязычных статей от Nesdoug: nesdoug.com/ где если в архив заглянуть, то в первоварианте от 2018 года написано: nesdoug.files.wordpress.com/2018/07/introduction-e28093-nesdoug.pdf
«As far asI know, there are no other tutorials for cc65 (not counting the example games over at Shiru’s site.)»
Воу, круто.
Тут еще на выходных пообщался с Кристофером который делает IDE Nesicide — он сейчас оказывается учавствует в джеме (сделать игру на NES за 48 часов) где вот: globalgamejam.org/2020/games/super-city-mayor-3
Credits:
Music by Shiru from the Famitone library.
xD И снова Shiru!
Ну прям респект как говорится.
  • avatar aa-dav
  • 0
Хехехе, первая тестовая программа с обильными комментариями на русском готова и крутится в эмуляторе:


Так что скоро наверное будет вторая часть. Правда таки разрываюсь на тему того не сделать ли сперва одну часть краткого введения в ассемблер и архитектуру MOS 6502 чтобы статья в целом лучше заходила тем кто в этом ни бум-бум изначально, а так, из Си пришёл. Хм…
  • avatar aa-dav
  • 0
Аллилуйя! Автор Nesicide наконец то устал с чем то там разбираться на своей стороне и добавил поддержку utf-8 и убрал дурацкое насильное автодополнение единственного оставшегося выбора в списке автодополнений (последнее вообще съедало мозг). Если кто-то из любопытства качал сборку для виндовс из-за этого поста, то обязательно перекачайте архив и зайдите в настройки среды — там настройки редактора и поставьте Encoding в utf-8.
  • avatar aa-dav
  • 0
P.S. Первая ссылка поломалась, вот она: retrocoder.d3.ru/perekhvat-preryvanii-na-zx-spectrum-1915801
  • avatar aa-dav
  • 0
Еще у меня есть вопрос к старожилам ресурса — недавно развлекаясь с нереализованными в детстве идеями на ZX Spectrum я написал еще две статьи на менее профильном ресурсе:
Перехват прерываний на ZX Spectrum
и как бы её продолжение:
Многопоточность на ZX Spectrum
Я знаю что про перехват прерываний не писал только ленивый и возможно это уже просто моветон. Про многопоточность вроде меньше материалов — поэтому вопрос: стоит ли тащить что либо из этого сюда?
  • avatar aa-dav
  • 0
А, точно, тут же и «возвращать» ничего не надо из одних линий в другие, зеркалирование от игнорированиясамо сработает как надо.
  • avatar aa-dav
  • 1
Секция графики часто может отсутствовать
Действительно. Спасибо, перепишу это предложение.

есть трюк, позволяющий замаппить 2K видеопамяти как память тайлов
Эмм… интересно конечно же как? Маппер VRAM который возвращает на верхние линии адреса частично состояние нижних?
  • avatar aa-dav
  • 0
:) Я, кстати, немного сравнивал Z8000 с i8086 по разным возможностям и в целом — забавно.
Как уже написано у Z8000 16 РОН и 8Мб сегментируемой памяти. При этом сегменты сделаны еще круче, чем в i8086 — вместо того чтобы держать отдельные сегментные регистры при сегментированной памяти адресация памяти через регистры автоматически подразумевает, что в чётных регистрах содержится номер сегмента (в верхнем байте), а в нечётных — смещение в сегменте. Т.е. косвенная адресация через регистры возможна с восемью 32-битными регистровыми парами 16-битных регистров R0-R15 которые уже называются RR0-RR14 (и могут быть только чётными номерами). Объединение в регистровые пары — характерная черта i8080/Z80 которая в Z8000 присутствует вплоть до 64-битных регистров RQ0,RQ4,RQ8,RQ12 видимо для операций длинного деления — разбираться не стал.
Дальше-больше. Если в i8086 подытожить все формы адресации, то их можно выразить самой комплексной формой:

[bx|bp+di|si+offset]

Т.е. или bx или bp сложенный с или di или si плюс смещение, при этом любая часть могла быть выкинута из выражения.
А вот в Z8000 самая сложная адресация возможная в любой команде — это [Rx+offset], где Rx это любой из шестнадцати его регистров кроме R0. А самая сложная адресация [Rx+Ry] где так же Rx и Ry это любые регистры кроме R0 возможна только в операциях передачи данных. С одной стороны вроде и менее сложные адресации, но с другой стороны этого более чем достаточно для эффективной адресации стековых переменных, а с другой стороны нет ограничений никаких какие именно регистры могут выступать в роли индексных, так что всё это немного похоже на современные RISC по возможностям.
Еще на англовики можно прочитать, что Z8000 неоднократно использовался в машинах на базе Unix. Чем же он был для них так привлекателен по сравнению с i8086? А вот чем:
Дело в том, что у Z8000 был дополнительный чип в _возможной_ обвязке — Z8010 именуемый еще Memory Managment Unit или MMU.
Так как сам Z8000 (точнее первая модель — Z8001) уже имел сегментированную память на 23 бита (8Мб) состоящую из 128 сегментов по 64Кб, то наличие MMU вроде бы смущает — казалось бы зачем?
Так вот как раз это самое — обеспечивать аппаратную защиту памяти read-only, code-only, data-only и system сегментов.
MMU ставился между процессором и памятью и обычные сегменты Z8010 становились «логическим адресным пространством», а аппаратный маппинг MMU уже превращал их в физические. Как я понял возможен даже трюк с шарингом одного сегмента в физической памяти между несколькими логическими сегментами разных процессов чтобы, допустим, на коде тех же DLL-ек экономить.
Забавно, что в один MMU вмещались дескрипторы только 64 сегментов, поэтому с одним MMU Z8000 мог обрабатывать в защите только 4Мб из 8 возможных.
Но достаточно было поставить еще один MMU в пару к другому — и возможно было обрабатывать аппаратной защитой все 128 возможных сегментов.
Но хуже того — можно было впаять и 4 MMU и сделать 16Мб физической памяти — и тогда с помощью MMU можно было разбрасывать задачи по 24-битному физическому адресному пространству хотя логические адреса конкретной задачи оставались 23-битными.
В общем Z8000 был реально не промах и наверное даже жаль, что его звезда закатилась. :)
  • avatar aa-dav
  • 1
Очень странно, ибо это реальный пакет где просто распаковываешь IDE, запускаешь, делаешь New->Project->From template и имеешь рабочий код который прямо в IDE же можно отлаживать проходясь отладчиком по реальным строкам кода, а не каким то там символам из отладочного файла. И всё это в ассемблере ca65 и всё это прям без проблем (ну кроме некоторых).
Может годы назад проект был глючным и не катил, да и сейчас вот глюки есть, но альтернатив я на горизонтах просто не заметил.
  • avatar aa-dav
  • 1
… через Nesicide...
Весело девки пляшут. Довольно быстро обнаружил, что редактор Nesicide не воспринимает русские буквы ни под каким соусом — заменяет их на знаки вопроса хоть при вводе с клавиатуры хоть при загрузке из файла. А как мне комментарии писать для туториалов на русском то?
Залез на гитхаб в проект и посмотрел там на код. Оказалось, что для редактора используется компонента QsciScintilla у которой в документации по методу setUtf8 чёрным по белому написано:
Sets the current text encoding. If cp is true then UTF8 is used, otherwise Latin1 is used.
И конечно же оказалось, что нигде в коде инициализации setUtf8( true ) не вызывается.
Вот так да, все годы существования Nesicide автор похоже и не подозревал, что редактор в нём ничего кроме латиницы с некоторой диакритикой не воспринимает принципиально! И никто не пожаловался! =8()

В общем я сказал и автор пообещал исправить в следующих релизах. :)
  • avatar aa-dav
  • 0
P.S.
Вот опять таки посмотрел статьи migera по ссылке из начала статьи — хорошая информация, но опять не про то как сесть и начать программировать конкретный код с конкретными эффектами конкретными инструментами, а больше справочная информация. Мне же хочется написать именно такую статью, что садишься за неё, а через несколько часов встаёшь уже с работающим кодом в работающей среде никуда больше не заглядывая особо.
  • avatar aa-dav
  • 0
А есть на примете какие-нибудь русскоязычные руководства в том духе о котором я пишу — чтобы от установки Nesicide и по каждому аспекту отдельно и нудно проходилось? Просто чтобы не писать одно и то же, а как то изменить точку зрения по сравнению с существующими аналогами.