| Разработка и ромхакинг > Программирование |
| Ребенок изучает asm [SMD] |
| << < (11/11) |
| SegaMark:
Нужна помощь знатоков ассемблера, может кто нибудь сталкивался с таким или эта какая-то распространенная проблема. Вообщем вот такой код: --- Код: ---movem.l d0-d2/a0-a1, -(a7) movea.l #$200000, a1 add.l d0, d0 subq.l #$1, d1 move.b $1(a1, d0.l), d2 ;d0=423e move.b d2, (a0)+ --- Конец кода --- проблема в том что размер РОМа у меня 2mb и получается что после этой строки move.b $1(a1, d0.l), d2 данные берутся за приделами РОМ. Как решить эту проблему чтобы он брал данные откуда нужно? |
| Томахомэ:
--- Цитата: SegaMark от 06 Март 2026, 09:03:28 ---movem.l d0-d2/a0-a1, -(a7) movea.l #$200000, a1 add.l d0, d0 subq.l #$1, d1 move.b $1(a1, d0.l), d2 ;d0=423e move.b d2, (a0)+ --- Конец цитаты --- Вроде в пределах первых 4 МБ адресуемого адресного пространства, если данная область заполнена не полностью, SMD заполненную зеркалит по нескольку раз. Добавлено позже: В этом я убедился, просматривая дебаггер MAME на позициях параллельно $0 и $100000 во время выполнения Dune II. Добавлено позже: Ровно такая же ситуация с $200000 и $300000. Добавлено позже: Процитированный тобой код - это, возможно, форма антипиратской защиты. |
| SeregaZ:
я не специалист :) но знаю одного типка... с именем Grok :lol: :lol: :lol: шаг первый - просим добавить комментарии, чтобы самому понимать что там происходит: --- Код: --- movem.l d0-d2/a0-a1, -(a7) ; Сохраняем регистры d0,d1,d2,a0,a1 в стек ; (push multiple registers) — стандартный пролог movea.l #$200000, a1 ; a1 = $200000 ; Очень часто это начало области VRAM в DMA-режиме ; либо начало таблицы тайлов / спрайтов в RAM add.l d0, d0 ; d0 *= 2 ; Самый частый случай: преобразование номера тайла ; в смещение в байтах (каждый тайл = 32 байта → ×32 = ←8+←5) subq.l #$1, d1 ; d1 -= 1 ; Теперь d1 содержит количество повторений - 1 ; (удобно для цикла типа dbra) move.b $1(a1, d0.l), d2 ; d2 = byte[ a1 + d0 + 1 ] ; Берём второй байт из 16-битного слова по адресу ; (a1 + d0) — скорее всего это старший байт тайла ; или атрибуты тайла (palette, flip, priority) move.b d2, (a0)+ ; *a0++ = d2 ; Записываем этот байт по текущему адресу a0 ; и сразу увеличиваем указатель на следующий байт ; После этого кода обычно идёт что-то вроде: ; move.b (a1,d0.l), (a0)+ ; младший байт тайла ; addq.l #2, d0 ; или add.l #32,d0 — следующий тайл ; dbra d1, метка_цикла --- Конец кода --- описываем проблему, что вот вылазит за пределы бла бла бла... --- Цитата ---Проблема, которую ты описываешь, очень типичная при работе с ROM > 1 МБ на Sega Genesis / Mega Drive. Коротко: у тебя нет ошибки в коде, а есть особенность зеркалирования (mirroring) адресов в железе Genesis при размере ROM 2 МБ. Почему происходит чтение "за пределами ROM"? Когда ROM ровно 2 МБ, железо зеркалит его дважды в пространстве $000000–$3FFFFF: $000000 – $1FFFFF → первая копия (нижние 2 МБ) $200000 – $3FFFFF → вторая копия тех же самых 2 МБ То есть адреса $200000 – $3FFFFF физически читают то же самое содержимое, что и $000000 – $1FFFFF. Поэтому строка: --- Код: ---movea.l #$200000, a1 ; a1 = $200000 ... move.b $1(a1, d0.l), d2 ; читаем байт с адреса $200001 + d0 --- Конец кода --- совершенно корректна на реальном железе при 2 МБ ROM — она просто читает из второй половины зеркала. Когда это действительно ломается? Чаще всего проблема проявляется в одном из двух случаев: Эмулятор не реализует зеркалирование 2 МБ ROM (очень многие старые / простые эмуляторы этого не делают) У тебя ROM не 2 МБ, а меньше (например 1.5 МБ, 1 МБ, 768 КБ и т.д.), но код всё равно обращается к $200000+ Пример универсального варианта (работает при любом размере ROM): --- Код: --- movem.l d0-d2/a0-a1, -(a7) ; Вариант 1 — всегда безопасно (если данные ≤ 1 МБ) ; movea.l #0, a1 ; или #$10000, #$8000 и т.п. — где реально лежат данные ; Вариант 2 — если точно знаешь, что 2 МБ и хочешь зеркало movea.l #$200000, a1 add.l d0, d0 ; ×2 (если индекс тайлов в словах → смещение в байтах) subq.l #1, d1 ; для dbra .loop move.b 1(a1, d0.l), d2 ; старший байт move.b d2, (a0)+ ; move.b 0(a1, d0.l), (a0)+ ; младший байт (если дальше в цикле) addq.l #2, d0 ; или add.l #32,d0 — смотря что за данные dbra d1, .loop movem.l (a7)+, d0-d2/a0-a1 rts --- Конец кода --- --- Конец цитаты --- код не знаю для какого ассемблера, да и под вопросом рабочий ли он мне его подсунул, ибо начинаешь влезать в эту тему с ИИ - он из раза в раз пишет ахинею и надо вникать. но вот видео редактор (успешно) и свой аудио драйвер (не очень) я делал именно с помощью ИИ, только что нельзя ему сразу весь код пихать - у него крыша едет. надо разбивать задачу на мелкие кирпичики, а после их самому компоновать в кучу. |
| SegaMark:
--- Цитата: Томахомэ от 06 Март 2026, 10:40:02 ---если данная область заполнена не полностью, SMD заполненную зеркалит по нескольку раз. --- Конец цитаты --- Спасибо за подсказку, да это действительно оказалось зеркалирование, но почему то данные берутся неправильные. --- Цитата: Томахомэ от 06 Март 2026, 10:40:02 ---Процитированный тобой код - это, возможно, форма антипиратской защиты. --- Конец цитаты --- если это так, знаешь какой нибудь способ как ее можно победить --- Цитата: SeregaZ от 06 Март 2026, 17:28:19 ---шаг первый - просим добавить комментарии, чтобы самому понимать что там происходит: --- Конец цитаты --- Он не правильно понял это не чтение тайлов, а чтение некоторых данных для игры. Насколько я понял в РОМ находиться некоторая таблица параметров и эта часть функции последовательно считывает их, но мне не удалось найти это место в РОМ потому что данные берутся не совсем последовательно а через байт. --- Цитата: SeregaZ от 06 Март 2026, 17:28:19 ---код не знаю для какого ассемблера --- Конец цитаты --- Для нашего родного Motorola M68K :lol: --- Цитата: SeregaZ от 06 Март 2026, 17:28:19 ---да и под вопросом рабочий ли он мне его подсунул --- Конец цитаты --- выглядит рабочим Я заметил еще одну особенность есть модификация данного РОМ где изменен только заголовок, и все работает как надо, данные берутся откуда положено, но только на эмуляторе Bizhawk и Exodus(на остальных не проверял), а мне нужно записать его на картридж и на реальном железе он почему то не работает, видимо ему плевать на заголовок. Как можно исправить эту проблему? Слева ориг ром. Справа модифицированный |
| SeregaZ:
а контрольную сумму поправил перед записью? может из-за неё не работает на железе? |
| Ti_:
--- Цитата: SegaMark от 06 Март 2026, 21:02:43 ---Слева ориг ром. Справа модифицированный --- Конец цитаты --- это картридж с sram. |
| SegaMark:
--- Цитата: Ti_ от 07 Март 2026, 07:59:59 ---это картридж с sram. --- Конец цитаты --- похоже что да https://data.spludlow.co.uk/mame/software/megadriv/nhl98. То есть получается если игре нужен sram, то она его размещает сразу после ROM? А как тогда заголовок решил эту проблему, там типа сказано что нужно использовать sram и прописаны все его параметры? И каким самым простым способом можно это починить чтобы заработало на карике? Добавлено позже: --- Цитата: SeregaZ от 06 Март 2026, 21:23:05 ---а контрольную сумму поправил перед записью? --- Конец цитаты --- Нет. Не подскажешь как проще всего это сделать, никогда не сталкивался с проблемами в контрольной сумме. |
| SeregaZ:
вроде что-то там есть какая-то программа... не помню уже точные детали. набросал примерно по мотивам... правда у меня в коде зачем-то еще в заголовке размер всего файла указывался. но вроде как не сильно то он и нужен. поэтому тут только сама сумма правится, размер нет. но если надо это легко поправить будет. но лучше поискать что-то более проверенное и точно рабочее :) я мог накосячить :blush: |
| SegaMark:
В итоге удалось решить, но так как мне нужно было срочно, я придумал самый прямой способ. Возможно кому то это поможет. Я взял экспортировал sram в эмуляторе и объединил его с ромом после этого все заработало. |
| Томахомэ:
Вот тут у нас - первичный лонч Double Point: --- Код: ---000106: 46FC 2700 move #$2700, SR 00010A: 4FF9 0008 4000 lea $84000.l, A7 000110: 41F9 0008 0000 lea $80000.l, A0 000116: 303C 0FFF move.w #$fff, D0 00011A: 20FC 0000 0000 move.l #$0, (A0)+ 000120: 51C8 FFF8 dbra D0, $11a 000124: 41F9 0003 F800 lea $3f800.l, A0 00012A: 43F9 0008 0000 lea $80000.l, A1 000130: 3E3C 01FF move.w #$1ff, D7 000134: 22D8 move.l (A0)+, (A1)+ 000136: 51CF FFFC dbra D7, $134 00013A: 4EB9 0001 489A jsr $1489a.l 000140: 60FE bra $140 <...> 01489A: 303C 48E7 movem.l D2-D3/A2-A5, -(A7) 01489E: 207C 0000 B97C move.l #$b97c, A0 0148A4: 2408 move.l A0, D2 0148A6: 263C 0008 24EC move.l #$824ec, D3 0148AC: 4EB9 0000 B1C2 jsr $b1c2.l 0148B2: 4241 clr.w D1 0148B4: 207C 0008 24C6 movea.l #$824c6, A0 0148BA: 227C 0000 062A movea.l #$62a, A1 0148C0: 247C 0008 24B2 movea.l #$824b2, A2 0148C6: 267C 0000 063E movea.l #$63e, A3 0148CC: 287C 0008 24DA movea.l #$824da, A4 0148D2: 203C 0000 0652 move.l #$652, D0 0148D8: 20D9 move.l (A1)+, (A0)+ 0148DA: 24DB move.l (A3)+, (A2)+ 0148DC: 2A40 movea.l D0, A5 0148DE: 38D5 move.w (A5), (A4)+ 0148E0: 5241 addq.w #1, D1 0148E2: 5480 addq.l #2, D0 0148E4: 0C41 0005 cmpi.w #$5, D1 0148E8: 65EE bcs $148d8 0148EA: 4EB9 0000 BA14 jsr $ba14.l 0148F0: 4240 clr.w D0 0148F2: 33C0 0008 24EA move.w D0, $824ea.l 0148F8: 33C0 0008 2498 move.w D0, $82498.l 0148FE: 33C0 0008 24F6 move.w D0, $824f6.l 014904: 4EB9 0000 DFD8 jsr $dfd8.l 01490A: 2443 movea.l D3, A2 01490C: 082A 0007 0001 btst #$7, ($1,A2) 014912: 6706 beq $1491a 014914: 4878 0003 pea $3.w 014918: 6022 bra $1493c 01491A: 2043 movea.l D3, A0 01491C: 0828 0004 0001 btst #$4, ($1,A0) 014922: 6706 beq $1492a 014924: 4878 0004 pea $4.w 014928: 6012 bra $1493c 01492A: 2043 movea.l D3, A0 01492C: 0828 0005 0001 btst #$5, ($1,A0) 014932: 6706 beq $1493a 014934: 4878 0005 pea $5.w 014938: 6002 bra $1493c 01493A: 42A7 clr.l -(A7) 01493C: 4EB9 0000 B97C jsr $b97c.l 014942: 588F addq.l #4, A7 014944: 4EB9 0000 0174 jsr $174.l 01494A: 60FE bra $1494a --- Конец кода --- А тут - обработчик кадрового прерывания: --- Код: ---000142: 48E7 FFFE movem.l D0-D7/A0-A6, -(A7) 000146: 3039 0008 1E96 move.w $81e96.l, D0 00014C: 0C40 0000 cmpi.w #$0, D0 000150: 6700 0010 beq $162 000154: 4EB8 0180 jsr $180.w 000158: 4E71 nop 00015A: 33FC 0000 0008 1E96 move.w #$0, $81e96.l 000162: 4EB8 01C2 jsr $1c2.w 000166: 4E71 nop 000168: 4EB9 0001 4EB6 jsr $14eb6.l 00016E: 4CDF 7FFF movem.l (A7)+, D0-D7/A0-A6 000172: 4E73 rte --- Конец кода --- Дизассемблят Double Point я решил взять за основу limited access-source'ного движка бонусной активности для разных хоумбрюшных игр на Neo-Geo. Такой перенос повторяющихся действий с обработчика прерываний на основной код достаточно грамотен? --- Код: --- ;movem.l D2-D3/A2-A5, -(A7) ;move.l #LocalModeSelect, D2 jsr cls_local moveq #4, D1 movea.l #TemporaryLocalPlayerNames, A0 movea.l #LocalPlayerNames, A1 movea.l #TemporaryLocalHiScore, A2 movea.l #LocalHiScore, A3 movea.l #TemporaryLocalAvatars, A4 movea.l #LocalAvatars, A5 LocalHiScoreInit: move.l (A1)+, (A0)+ move.l (A3)+, (A2)+ move.w (A5)+, (A4)+ dbra D1, LocalHiScoreInit ;jsr LocalSoundInit clr.w $824ea.l clr.w $82498.l clr.w $824f6.l clr.l -(A7) jsr LocalModeSelect addq.l #4, A7 VBlankReturnCheck: cmp BIOS_FRAME_COUNTER, LocalFrameCounter beq VBlankReturnCheck movem.l D0-D7/A0-A6, -(A7) move.w LocalPalChange, D0 cmpi.w #0, D0 beq LocalNewFrame jsr LocalLoadPal move.w #0, LocalPalChange LocalNewFrame: jsr LocalPlaySound jsr BonusGameLoop movem.l (A7)+, D0-D7/A0-A6 bra VBlankReturnCheck --- Конец кода --- Предваряя возникающие вопросы, спешу предупредить, что в последней цитате из кода сохранившие свою числовую форму переменные считайте, называются так условно (про то, что work RAM у Neo-Geo и железа Double Point назначен на разные области адресуемого пространства, я таки прекрасно в курсах), LocalFrameCounter должна прирасти в BonusGameLoop или одной из её дочерних подпрограмм (примерно как системный счётчик кадров в оригинальной Double Point), а код с jsr $dfd8.l по clr.l -(A7) пропал потому, что у Double Point он отвечал за считывание аппаратных (в то время как у Neo-Geo за сугубо игровые настройки отвечают программные, да и вообще сложность и пр. у бонусной игры должны плясать от аналогичных параметров материнской игры) DIPов и переход, в зависимости от включенных, в один из нескольких разных сервисных режимов (коих у мини-игры, понятно-дело, быть не может). Сообразуясь с той же логикой, под нож пущены и предварительная чистка ОЗУ. |
| SegaMark:
Кто-нибудь знает как написать код который выводит 4 тайла на слой B, где у каждого тайла своя палитра? например есть 4 тайла, нужно чтобы тайл 1=палитра 1, тайл 2=палитра 2, тайл 3=палитра 3, тайл 4=палитра 4 и вывести их слева направо в Слой B начиная с нулевой координаты. |
| SeregaZ:
так ты асм файлы видео мейкера открой. там и увидишь. я же все строчки прокомментировал. смотри где берется тайловая карта из таблицы, куда пишется. что в этой тайловой карте - так и поймешь. |
| Навигация |
| Главная страница сообщений |
| Предыдущая страница |