Разработка и ромхакинг > Программирование

Ребенок изучает 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ов и переход, в зависимости от включенных, в один из нескольких разных сервисных режимов (коих у мини-игры, понятно-дело, быть не может). Сообразуясь с той же логикой, под нож пущены и предварительная чистка ОЗУ.

Навигация

[0] Главная страница сообщений

[*] Предыдущая страница

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