Разработка и ромхакинг > Ромхакинг
[SMD] Какие валидные инструкции не встречаются в коде игр?
Беларус учит русский:
Надо определить, являются ли некие два байта инструкцией m68k или нет без присоединения дизассэмблера к коду.
По комментам ниже была сделана таблица битов валидности всех 65 536 вариантов двух байт. В нём дополнительно отмечены невалидными условные инструкции, указывающие на нечётные адреса и на себя (кроме прямого прыжка BRA на себя, он встречается в играх).
Можно так же поступить с бессмысленными инструкциями типа OR 0, но нейросеть пишет, что их могут использовать для изменения состояния флагов.
Есть ли ещё какие-то инструкции, которые можно уверенно признать невалидными?
Задача вторая, не очень важная: эта таблица битов занимает 8192 байт. Немного, влезает в кэши первого уровня. Но может можно сжать таблицу в битовые маски типа такого, чтобы занимало ещё меньше места в кэше и в коде:
0000 0000 0.11 11..
0000 0000 11.. ....
0000 0000 0000 1...
0000 ...1 ..11 11** (кроме 00)
0100 1110 0111 1...
0100 1110 0111 0100
1010 .... .... ....
0111 ...1 .... ....
1111 .... .... ....
В коде, генерирующем оригинальную таблицу, есть что-то такое с битами. Есть идеи алгоритма составления таких масок по изменённой таблице?
SeregaZ:
а почему свой не вариант?
DrMefistO:
Если я правильно помню, достаточно запустить Musashi 68k генератор и он выплюнет все возможные варианты всех инструкций, которые потом фильтруются по валидности каким-то образом.
https://github.com/kstenerud/Musashi/blob/master/m68kmake.c
https://github.com/kstenerud/Musashi/blob/master/m68kdasm.c
Беларус учит русский:
SeregaZ, ты же сам пробовал - понравилось? m68k и x86-64 - самые сложные наборы инструкций, легко допустить ошибки при создании дизассэмблера и займёт много времени. Подключать существующие - может много весить, производительность может быть не очень, и баги. Встречал тэсты, где дизассэмблеры не всегда правильно определяют некорректные инструкции, даже мой любимый Capstone (авторам которых я и сам отправлял ошибки).
Хотя, как помню, у тебя было даже проще - ты разбирал уже разобранный код.
DrMefistO, я рассматривал такой вариант, но, как описал выше, не доверяю им в плане некорректных инструкций - обычно они все направлены на корректные. И даже если он будет без ошибок, то боюсь не справиться с фильтрами и допустить ошибку, если он выдаст огромную портянку всех вариантов.
Exodus направлен на отладку и разработку, поэтому ему доверяю больше. Тут он оказался даже точнее BlastEm, хотя это 2017-ый и второй мог догнать уже.
+я хочу привести вот эту таблицу в человеческий вид, а то глазам больно :)
paul_met:
--- Цитата: perfect_genius от 08 Сентябрь 2025, 12:03:40 ---+я хочу привести вот эту таблицу в человеческий вид, а то глазам больно
--- Конец цитаты ---
В заголовке таблицы не помешало бы пронумеровать биты и добавить вертикальные полоски, чтобы сразу было видно какой бит какое значение принимает.
SeregaZ:
perfect_genius, да, кайфанул пока ковырялся - но я делал изначально не правильно. надо было строго по таблице, а я же какие мне надо - те добавлял. и после уже городил огород, когда поверх этой своей ахинеи надо было еще какие-то команды добавить. и, кстате, икалось кое кому при этом дичайше, когда я сидел с непонимающим взглядом пытался понять - почему святая Ида рожает код так, когда должно вот так... так-же r57shell тоже досталось, так как в его эмуляторе тоже дебажит местами коряво.
на корявые команды можно Doom Troopers потестировать. что-то я помню там швах творится... но игра один фиг как-то работает :)
в общем таблица эта не сложная. там просто надо вникнуть. пятсот ифоф конечно в разбор надо будет добавлять, чтобы учесть все нюансы... и главное чтоб на выходе было ASM68K.exe совместимо из коробки.
если аппатия меня все-таки отпустит - может попробую второй заход сделать. чтоб эмулятор докрутить. пока думаю чтоб шелловские места, где в эмуляторе дебажит - отлавливать и делать вывод, что там код, а не данные, а значит их можно отдизасмить. чтобы мой дизассемблер как у взрослых стал, а не так что только с $200 адреса и до первого тупика. эта магия влезания в память эмулятора меня прям настолько преисполнила. ящик пандоры открыл для себя. мы правда её для другого использовали, но думаю для отлова адресов тоже сойдет. просто надо вникнуть.
Беларус учит русский:
paul_met, ты взорвал мне мозг :lol:
--- Цитата ---В заголовке таблицы не помешало бы пронумеровать биты
--- Конец цитаты ---
Потому что ты отправляешь в функцию номер бита, а не отсеиваешь по битовой маске? Или зачем?
--- Цитата ---добавить вертикальные полоски
--- Конец цитаты ---
Но ведь они там есть, через 4 бита, или ты про что? :unsure:
--- Цитата ---чтобы сразу было видно какой бит какое значение принимает
--- Конец цитаты ---
Снова - они же уже обозначены нулями и единицами :debile:
Короче, если не лень, накалякай в Пэйнте простой набросок что ты предлагаешь.
Обновил, переделал вот так:
т.к. нули и единицы мельтешат, разницу было углядеть сложно. +добавил ещё линию, делящую на 4 бита к концу инструкции, чтобы лучше различать полубайты.
GManiac:
Была ещё такая версия таблицы
https://www.emu-land.net/forum/index.php/topic,42330.msg567560.html#msg567560
Старый дисс от Никодима, там допустимые опкоды сделаны в виде таблиц с двумя масками: с AND и с OR.
https://shedevr.org.ru/cgi-bin/utilz.cgi?n=14
Моя логика определения опкода (и не-опкода) базировалась на нём и таблицей из моего аттача. Исходник моего дизасма и анализатора не-опкодов могу скинуть, сейчас не под рукой.
SeregaZ:
гыгыгы... дураки думают одинаково :))) я тоже делал програмку, куда втуливаешь опкод, а потом подкрашиваешь где какие байты. блин... только что тот старый комп выключил. надо было скрины поделать как раз :)))
Добавлено позже:
по иллегалам можно сделать так:
создаем "ром" файл,
а туда втуливаем в цикле 00 00, 00 01, 00 02, 00 03... скармливаем Иде и смотрим на что ругается. Тай мне такой файл скидывал, и там было расписано где иллегалы затусились. правда это не совсем точный метод, ибо некоторые подразумевают не 2 байта, а больше. следовательно такой подход не совсем точно сработает. разве что сделать 00 00 00 00 00 00 00 00, 00 01 00 00 00 00 00 00, 00 02 00 00 00 00 00 00, 00 03 00 00 00 00 00 00,...
pav13:
в эмуляторе genesis plus gx есть
https://github.com/ekeeke/Genesis-Plus-GX/blob/master/core/m68k/m68ki_instruction_jump_table.h
скорее всего это сохранённый результат работы "build opcode table" из musashi, чтобы не создавать эту таблицу каждый новый запуск.
это массив размером 65536 элементов из обработчиков всех опкодов. если на месте опкода обработчик m68k_op_illegal, m68k_op_1111 или m68k_op_1010 - то это не инструкция.
Добавлено позже:
m68k_op_illegal - 11529 опкодов
m68k_op_1010 - 4096 опкодов
m68k_op_1111 - 4096 опкодов
итого ~30.1 % всех возможных опкодов изначально нелегальные
https://pastebin.com/cnzH46gt
в виде bool массива для удобства использования. если обработчик был m68k_op_illegal, m68k_op_1111 или m68k_op_1010, то false, а для всех остальных true.
paul_met:
--- Цитата: perfect_genius от 08 Сентябрь 2025, 15:37:32 ---Короче, если не лень, накалякай в Пэйнте простой набросок что ты предлагаешь.
--- Конец цитаты ---
Вот, пример для первой таблицы.
Rumata:
Несуществующих инструкций не бывает, ибо они не существуют.
Бывают не документированные.
Теперь живите с этим :biggrin:
Sharpnull:
Нужно использовать дизассемблер и не страдать фигнёй. Всё равно придётся проверять допустимость, что у branch инструкции размера byte не смещение 00 и что переходы в пределах рома (UPD: ещё код в RAM учитывать).
pav13:
--- Цитата: Sharpnull от 08 Сентябрь 2025, 21:42:21 ---Нужно использовать дизассемблер и не страдать фигнёй. Всё равно придётся проверять допустимость, что у branch инструкции размера byte не смещение 00 и что переходы в пределах рома (UPD: ещё код в RAM учитывать).
--- Конец цитаты ---
для простых задач простые решения.
прикрутил таблицу валидности опкодов, дало неплохое отсеивание.
--- Код: ---// Читаем нормализованный ROM
uint8_t high_byte = 0;
uint8_t low_byte = 0;
int32_t target_addr = 0;
uint32_t trim = rom_has_header ? 0 : 0x200;
for (uint32_t byte_addr = trim; byte_addr + 1 < rom_size; byte_addr += 2) {
high_byte = rom_data[byte_addr];
// Ищем только BEQ(0x67) и BNE(0x66)
if (high_byte != 0x66 && high_byte != 0x67)
continue;
low_byte = rom_data[byte_addr + 1];
// Проверка целевого адреса на чётность и попадание в ROM
if (low_byte != 0 && (low_byte & 1) == 0) {
// Короткое смещение
target_addr = byte_addr + 2 + (int8_t)low_byte;
}
else {
// Длинное смещение
if (low_byte != 0)
continue;
if (byte_addr + 3 >= rom_size)
continue;
uint16_t disp16 = (rom_data[byte_addr + 2] << 8) | rom_data[byte_addr + 3];
if ((disp16 & 1) != 0)
continue;
target_addr = byte_addr + 2 + (int16_t)disp16;
}
if (target_addr < (int32_t)trim || (target_addr + 1) >= (int32_t)rom_size)
continue;
// Проверка данных по целевому адресу на легальность для M68K
if (!m68k_opcode_valid[(rom_data[target_addr] << 8) | rom_data[target_addr + 1]])
continue;
// Правдоподобная BEQ/BNE инструкция
/* последующая обработка ......*/
}
--- Конец кода ---
Sharpnull:
--- Цитата: pav13 от 08 Сентябрь 2025, 22:21:27 ---для простых задач простые решения.
--- Конец цитаты ---
Вы правы, для опкодов подходит таблица (я написал, не подумав). Таблицу можно сжать, я каждое значение представил битом в массиве байтов, потом каждые 16 байт заменил на индекс из таблицы уникальных 16 байт. На Python получилось так, в начале постройка массива из 0x2000 байт:
--- Код: ---table = (
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'\xff\xff\xff\xff\xff\xff\xff\x1f\xff\xff\xff\xff\xff\xff\xff\x1f',
b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff',
b'\xff\xff\xff\xff\xff\xff\xff\x03\xff\xff\xff\xff\xff\xff\xff\x03',
b'\xff\x00\xff\xff\xff\xff\xff\x1f\xff\x00\xff\xff\xff\xff\xff\x1f',
b'\xff\x00\xff\xff\xff\xff\xff\x1f\xff\xff\xff\xff\xff\xff\xff\x1f',
b'\xff\xff\xff\xff\xff\xff\xff\x03\xff\xff\xff\xff\xff\xff\xff\x1f',
b'\xff\x00\xff\xff\xff\xff\xff\x03\xff\xff\xff\xff\xff\xff\xff\x03',
b'\xff\x00\xff\xff\xff\xff\xff\x1f\x00\x00\x00\x00\x00\x00\x00\x00',
b'\xff\xff\xff\xff\xff\xff\xff\x1f\x00\x00\x00\x00\x00\x00\x00\x00',
b'\xff\x00\xff\xff\xff\xff\xff\x03\xff\x00\xff\xff\xff\xff\xff\x03',
b'\xff\xff\xff\xff\xff\xff\xff\x1f\xff\xff\xff\xff\xff\xff\xff\x03',
b'\xff\x00\xff\xff\xff\xff\xff\x1f\x00\x00\xff\x00\x00\xff\xff\x0f',
b'\xff\xff\xff\xff\xff\xff\xff\x03\x00\x00\xff\xff\xff\xff\xff\x03',
b'\x00\x00\xff\xff\xff\xff\xff\x03\xff\x00\xff\xff\xff\xff\xff\x1f',
b'\x00\xff\xff\xff\xff\xff\xff\x03\xff\x00\xff\xff\xff\xff\xff\x1f',
b'\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\x03',
b'\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00',
b'\xff\x00\xff\xff\xff\xff\xff\x03\x00\x00\x00\x00\x00\x00\x00\x00',
b'\xff\x00\xff\xff\xff\xff\xff\x13\xff\x00\xff\xff\xff\xff\xff\x13',
b'\xff\x00\xff\xff\xff\xff\xff\x03\xff\x00\xff\xff\xff\xff\xff\x1f',
b'\xff\x00\xff\xff\xff\xff\xff\x0f\xff\x00\xff\xff\xff\xff\xff\x03',
b'\xff\x00\xff\xff\xff\xff\xff\x03\xff\x00\xff\x00\x00\xff\xff\x0f',
b'\xff\x00\xff\x00\xff\xff\xff\x03\xff\x00\xff\x00\xff\xff\xff\x03',
b'\x00\x00\xff\xff\x00\xff\xff\x0f\x00\x00\xff\xff\x00\xff\xff\x0f',
b'\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xef\x00',
b'\x00\x00\xff\x00\x00\xff\xff\x0f\x00\x00\xff\x00\x00\xff\xff\x0f'
)
table2 = (
19,18,11, 3,19,18,11, 3,10,18,11, 3,10,18,11, 3,
21,10,11, 3,19,18,11, 3,10,18,11, 3, 0, 0,11, 3,
8, 4, 4, 4, 8, 4, 4, 4, 8, 4, 4, 8, 8, 4, 4, 8,
8, 4, 4, 8, 8, 4, 4, 8, 8, 4, 4, 8, 8, 4, 4, 8,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, 9,
1, 1, 1, 9, 1, 1, 1, 9, 1, 1, 1, 9, 1, 1, 1, 9,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, 9,
1, 1, 1, 9, 1, 1, 1, 9, 1, 1, 1, 9, 1, 1, 1, 9,
10,10, 0,12,10,18, 0,12,10,20, 0,12,10,20, 0,12,
22,23, 0,12,10,10, 0,12, 0,24, 0,12,25,26, 0,12,
7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3,
7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0,
2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0,
4, 4,13,14, 4, 4,13,14, 4, 4,13,14, 4, 4,13,14,
4, 4,13,14, 4, 4,13,14, 4, 4,13,14, 4, 4,13,14,
5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6,
5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6,
5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6,
4, 4, 3,15, 4, 4, 3,15, 4, 4, 3,15, 4, 4, 3,15,
4, 4, 3,15, 4, 4, 3,15, 4, 4, 3,15, 4, 4, 3,15,
5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6,
5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6,
2,16, 2,16, 2,16, 2,16, 2,16, 2,16, 2,16, 2,16,
2,17, 2,17, 2,17, 2,17, 2,17, 2,17, 2,17, 2,17,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
)
m68k_opcode_valid = bytearray()
for i in range(512):
m68k_opcode_valid += table[table2[i]]
def is_valid_opcode(opcode):
return 0 != m68k_opcode_valid[opcode >> 3] & (1 << (opcode & 7))
--- Конец кода ---
pav13:
--- Цитата: Sharpnull от 08 Сентябрь 2025, 22:49:29 ---Таблицу можно сжать
--- Конец цитаты ---
:thumbup: 8 Кб это не 65 Кб
UPD: переписал на си.
--- Код: ---const uint8_t table[][16] = {
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f},
{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},
{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03},
{0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x1f,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x1f},
{0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x1f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f},
{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f},
{0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03},
{0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x03,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x03},
{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03},
{0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0x0f},
{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x03},
{0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x03,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x1f},
{0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x1f},
{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x03},
{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x13,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x13},
{0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x03,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x1f},
{0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x03},
{0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x03,0xff,0x00,0xff,0x00,0x00,0xff,0xff,0x0f},
{0xff,0x00,0xff,0x00,0xff,0xff,0xff,0x03,0xff,0x00,0xff,0x00,0xff,0xff,0xff,0x03},
{0x00,0x00,0xff,0xff,0x00,0xff,0xff,0x0f,0x00,0x00,0xff,0xff,0x00,0xff,0xff,0x0f},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0x00},
{0x00,0x00,0xff,0x00,0x00,0xff,0xff,0x0f,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0x0f}
};
const uint8_t table2[512] = {
19,18,11, 3,19,18,11, 3,10,18,11, 3,10,18,11, 3,
21,10,11, 3,19,18,11, 3,10,18,11, 3, 0, 0,11, 3,
8, 4, 4, 4, 8, 4, 4, 4, 8, 4, 4, 8, 8, 4, 4, 8,
8, 4, 4, 8, 8, 4, 4, 8, 8, 4, 4, 8, 8, 4, 4, 8,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, 9,
1, 1, 1, 9, 1, 1, 1, 9, 1, 1, 1, 9, 1, 1, 1, 9,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, 9,
1, 1, 1, 9, 1, 1, 1, 9, 1, 1, 1, 9, 1, 1, 1, 9,
10,10, 0,12,10,18, 0,12,10,20, 0,12,10,20, 0,12,
22,23, 0,12,10,10, 0,12, 0,24, 0,12,25,26, 0,12,
7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3,
7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0,
2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0,
4, 4,13,14, 4, 4,13,14, 4, 4,13,14, 4, 4,13,14,
4, 4,13,14, 4, 4,13,14, 4, 4,13,14, 4, 4,13,14,
5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6,
5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6,
5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6,
4, 4, 3,15, 4, 4, 3,15, 4, 4, 3,15, 4, 4, 3,15,
4, 4, 3,15, 4, 4, 3,15, 4, 4, 3,15, 4, 4, 3,15,
5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6,
5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6, 5, 1, 3, 6,
2,16, 2,16, 2,16, 2,16, 2,16, 2,16, 2,16, 2,16,
2,17, 2,17, 2,17, 2,17, 2,17, 2,17, 2,17, 2,17,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
uint8_t m68k_opcode_valid_table[0x2000];
void init_m68k_opcode_valid(void) {
for (int i = 0; i < 512; i++) {
int offset = i * 16;
for (int j = 0; j < 16; j++)
m68k_opcode_valid_table[offset + j] = table[table2[i]][j];
}
}
bool m68k_opcode_valid(uint16_t opcode) {
return ((m68k_opcode_valid_table[opcode >> 3]) & (1 << (opcode & 7))) != 0;
}
--- Конец кода ---
всё работает. спс
Yoti:
--- Цитата: pav13 от 08 Сентябрь 2025, 23:22:02 ---переписал на си
--- Конец цитаты ---
"Папа может в Си -- пока это так, всё в порядке на Руси!" (С)
pav13:
закинул musashi m68000 opcode table в excel.
уточню, что эта таблица именно для m68000
можно ввести опкод в ячейке С1, а в E1 будет результат.
онлайн
https://docs.google.com/spreadsheets/d/15_shH2m7CCpVwqm5QfqcWF_k1o0iEjfTGDsFVrJkLrQ/edit?usp=drive_link
оффлайн
musashi m68000 opcode table.zip (97.79 КБ - загружено 99 раз.)
upd:
просто оставлю это здесь
DrMefistO:
При генерации через мусаши можно дефайном задавать под какие генерить же.
Беларус учит русский:
--- Цитата: GManiac от 08 Сентябрь 2025, 18:01:47 ---Была ещё такая версия таблицы
--- Конец цитаты ---
В её счётчике скачиваний я давно есть :)
Но она кажется ещё сложнее. Например, что значит xxxl, Bxxx и крестики в самой таблице?
--- Цитата: GManiac от 08 Сентябрь 2025, 18:01:47 ---допустимые опкоды сделаны в виде таблиц с двумя масками: с AND и с OR
--- Конец цитаты ---
Т.е. как я делаю, но я наоборот для недопустимых?
pav13, крутота, то что надо! :jumpy:
Получается, надо будет поправить таблицу: сделать невалидными инструкции, отсутствующие в Сеге, а также все нечётные смещения - видимо, 16 инструкций * 128 нечётные смещения каждой = 2048 лишнего.
Все невалидные отмечены как m68k_op_illegal, но у Сеги есть официальная инструкция Illegal (0x4AFC). Интересно, как она там названа?.. Тоже m68k_op_illegal! Ну логично ;)
--- Цитата: paul_met от 08 Сентябрь 2025, 21:25:05 ---Вот, пример для первой таблицы.
--- Конец цитаты ---
Понятно теперь, тебе не понравились вот эти области:
Да, ужасно. У себя такое не допущу.
Есть идеи, почему в таблице названия некоторых инструкций выделены зелёным? Особенно с SR.
Sharpnull такой злой, будто мы ему спать мешаем :lol:
Сжать таблицу в биты - идея интересная. Посмотрим в будущем, получится ли в битовых масках ещё компактнее.
Тут и RLE можно применить :shifty:
Навигация
Перейти к полной версии