Как справиться с "невозможными" инструкциями Chip-8
Поэтому я работал над эмулятором Chip-8 в качестве финального проекта для моего класса CompSci, и столкнулся с проблемой, которая выходит за рамки моего кода. Большое количество демонстраций, которые я скачал (и я уверен, что это подлинные программы для Chip-8, а не SuperChip или что-то подобное), содержат машинные инструкции, которые не соответствуют формату любого кода операции Chip-8.
http://mattmik.com/files/chip8/mastering/chip8.html
Внизу страницы находится список всех кодов операций, каждый длиной 2 байта, и то, что представляет каждый кусочек данных в них. Тем не менее, довольно много программ имеют инструкции, которые не соответствуют ни одному формату для какой-либо инструкции. Например, вот шестнадцатеричный дамп одного из них - я укажу на несколько отдельных случаев в нем
0000000 6a 00 6b 04 6c 01 6d 00 6e 02 23 26 23 20 60 30
0000010 61 01 f0 15 f0 07 f1 18 30 00 12 14 22 42 23 20
0000020 7d 01 23 20 60 08 e0 a1 23 0a 4a 00 12 3e a3 62
0000030 d8 91 79 01 d8 91 4f 01 12 f4 49 18 12 e4 22 b2
0000040 12 1e 4c 01 22 6c 4c 02 22 7a 4c 03 22 88 4c 04
0000050 22 96 4c 05 22 a4 a3 59 d6 72 44 00 00 ee a3 57
0000060 d4 52 42 00 00 ee a3 5b d2 32 00 ee 66 28 67 09
0000070 64 00 65 00 62 00 63 00 00 ee 66 28 67 0e 64 28
0000080 65 14 62 00 63 00 00 ee 66 28 67 07 64 28 65 0c
0000090 62 16 63 11 00 ee 66 28 67 07 64 28 65 0e 62 16
00000a0 63 14 00 ee 66 28 67 05 64 28 65 10 62 16 63 0b
00000b0 00 ee a3 59 d6 72 76 fe d6 72 44 00 00 ee a3 57
00000c0 d4 52 74 02 44 44 74 c0 d4 52 42 00 00 ee a3 5b
00000d0 d2 32 72 02 4c 04 72 02 4c 05 72 02 42 44 72 c0
00000e0 d2 32 00 ee 7c 01 6d 00 6e 02 00 e0 4c 06 6c 01
00000f0 6a 00 12 0a 60 06 f0 18 7b ff 4b 00 13 08 6d 00
0000100 6e 02 00 e0 6a 00 12 0a 13 08 4a 01 00 ee 60 02
0000110 f0 18 6a 01 88 d0 78 01 89 e0 79 01 d8 91 00 ee
0000120 a3 54 dd e2 00 ee 64 19 63 00 a3 56 d3 41 73 08
0000130 33 40 13 2c 63 1e 64 1b fc 29 d3 45 4b 04 a3 5f
0000140 4b 03 a3 60 4b 02 a3 61 4b 01 a3 62 63 01 74 02
0000150 d3 41 00 ee 80 f8 ff 80 e0 10 70 88 ee 11 77 aa
0000160 a8 a0 80 00
0000164
В 0x154 есть
80 f8
но никакая инструкция, начинающаяся с 8, не может заканчиваться цифрой 8 - единственные юридические инструкции, заканчивающиеся на 8, должны заканчиваться на 1,2,3,4,5,6,7, или e. Еще один, в 0x158,
e0 10
ни одна инструкция не соответствует этому формату. второй байт любой инструкции, начинающейся с e, должен быть 9E или A1.
Это лишь небольшое количество ошибок - в коде есть еще несколько этих "невозможных" инструкций
Я делаю что-то резко неправильно? Как мне поступить с этими инструкциями? Просто пропустить их? Является ли страница, которую я использую в качестве ресурса Chip-8, неполной? Любой совет о том, как справиться с этим, с благодарностью. Спасибо!
2 ответа
Имейте в виду, что я совершенно незнаком с чип-8 конкретно; просто низкоуровневые вычисления в целом.
Это очень вероятно, данные; графика и звук, которые составляют игру. Вам не нужно "иметь дело с этим"; если программа написана правильно, указатель инструкций никогда не будет указывать на эту область.
Если он в конечном итоге указывает туда, это ошибка, как деление на ноль; "разберись с этим", как хочешь, предположительно, показав пользователю сообщение "ты пытался выполнить недопустимую инструкцию, которую ты пустил".
Вот что имеют в виду программисты, когда говорят "неопределенное поведение"; буквально нет определения того, что должно происходить, когда указатель инструкции указывает на то, что не является инструкцией. Вы можете делать все, что хотите, потому что правильно созданная программа никогда не должна делать это (в реальной жизни они все равно делают, все время на самом деле, но на самом деле не должны).
Вы предполагаете, что каждая пара байтов в двоичном файле является инструкцией? это было бы плохим предположением. Когда вы следуете правилам чипов для точки входа и следуете возможным путям кода, появляются ли эти невозможные инструкции? наборы команд фиксированной или переменной длины, различные архитектуры (arm, mips, x86 и т. д.), вы найдете данные в двоичном коде, которые не являются инструкциями, просто так это работает. Разбирая полноразмерную программу arm (32-битные инструкции фиксированной длины), вы найдете неопределенные инструкции, потому что они не являются инструкциями, а являются данными, адреса должны достигать больших расстояний, строки ascii и т. д. При фиксированной длине вы можете перейти от нуля до конца и дизассемблирование (при условии, что это фиксированная длина и там нет большого пальца кода), но вы просто должны разрешить / игнорировать недопустимые битовые комбинации. то же самое здесь, если это то, что вы бьете. Это не всегда идеально, но чтобы попытаться устранить некоторые из них, вы должны следовать возможным путям выполнения (что вам в значительной степени приходится делать для наборов команд переменной длины).
Теперь, если вы эмулируете, чтобы добраться до них и эмулируете правильно, тогда вы следуете путям выполнения. И мы, вероятно, не можем вам помочь. Есть ли у вас правильный порядок байтов, правильно ли вы интерпретируете пары байтов? может быть, вам повезло, а затем ударил неопределенный?
РЕДАКТИРОВАТЬ:
это все, что я получил от вашего двоичного файла, так как он не описывает, что находится в 0x300
0000: 6A00
mov r10,0x00
0002: 6B04
mov r11,0x04
0004: 6C01
mov r12,0x01
0006: 6D00
mov r13,0x00
0008: 6E02
mov r14,0x02
000A: 2326
call 326
0326: 0000
UNDEFINED
хуже того, я вижу, что эмуляторы и другие документы говорят, что компьютер начинается с 0x200, для которого ваш двоичный файл не имеет никаких данных.
Итак, я только что выбил симулятор chip8, и до сих пор ваша программа не достигла неопределенности. Он ждет нажатия клавиш и других вещей, которые я еще не расшифровал вручную.
вместо этого попробую дизассемблер.
EDIT2:
поэтому я ударил дизассемблер, и он не попал в эти адреса, он заканчивается
034E : 0x7402 add v4,0x02
0350 : 0xD341 drw v3,v4,1
0352 : 0x00EE ret
Вы можете сделать это самостоятельно, следовать всем путям кода, и, надеюсь, вы получите те же результаты.
Инструкция 0xBnnn, я думаю, единственная, которая может сбить вас с толку, поскольку она зависит от данных во время выполнения, поэтому вы должны эмулировать ее (со всеми возможными комбинациями, которые могут действительно произойти), чтобы увидеть, куда она вас приведет. В принципе, если вы столкнетесь с одним из них, вам в какой-то степени придется вручную изучить возможные места посадки и идти оттуда.
Я не нашел этого в этом коде.
Моя разборка, посмотри, как она сравнивается с твоей:
0200 : 0x6A00 ld v10,0x00
0202 : 0x6B04 ld v11,0x04
0204 : 0x6C01 ld v12,0x01
0206 : 0x6D00 ld v13,0x00
0208 : 0x6E02 ld v14,0x02
020A : 0x2326 call 326
020C : 0x2320 call 320
020E : 0x6030 ld v0,0x30
0210 : 0x6101 ld v1,0x01
0212 : 0xF015 ld dt,v0
0214 : 0xF007 ld v0,dt
0216 : 0xF118 ld st,v1
0218 : 0x3000 se v0,0x00
021A : 0x1214 jp 214
021C : 0x2242 call 242
021E : 0x2320 call 320
0220 : 0x7D01 add v13,0x01
0222 : 0x2320 call 320
0224 : 0x6008 ld v0,0x08
0226 : 0xE0A1 sknp v0
0228 : 0x230A call 30A
022A : 0x4A00 sne v10,0x00
022C : 0x123E jp 23E
022E : 0xA362 ld i,362
0230 : 0xD891 drw v8,v9,1
0232 : 0x7901 add v9,0x01
0234 : 0xD891 drw v8,v9,1
0236 : 0x4F01 sne v15,0x01
0238 : 0x12F4 jp 2F4
023A : 0x4918 sne v9,0x18
023C : 0x12E4 jp 2E4
023E : 0x22B2 call 2B2
0240 : 0x121E jp 21E
0242 : 0x4C01 sne v12,0x01
0244 : 0x226C call 26C
0246 : 0x4C02 sne v12,0x02
0248 : 0x227A call 27A
024A : 0x4C03 sne v12,0x03
024C : 0x2288 call 288
024E : 0x4C04 sne v12,0x04
0250 : 0x2296 call 296
0252 : 0x4C05 sne v12,0x05
0254 : 0x22A4 call 2A4
0256 : 0xA359 ld i,359
0258 : 0xD672 drw v6,v7,2
025A : 0x4400 sne v4,0x00
025C : 0x00EE ret
025E : 0xA357 ld i,357
0260 : 0xD452 drw v4,v5,2
0262 : 0x4200 sne v2,0x00
0264 : 0x00EE ret
0266 : 0xA35B ld i,35B
0268 : 0xD232 drw v2,v3,2
026A : 0x00EE ret
026C : 0x6628 ld v6,0x28
026E : 0x6709 ld v7,0x09
0270 : 0x6400 ld v4,0x00
0272 : 0x6500 ld v5,0x00
0274 : 0x6200 ld v2,0x00
0276 : 0x6300 ld v3,0x00
0278 : 0x00EE ret
027A : 0x6628 ld v6,0x28
027C : 0x670E ld v7,0x0E
027E : 0x6428 ld v4,0x28
0280 : 0x6514 ld v5,0x14
0282 : 0x6200 ld v2,0x00
0284 : 0x6300 ld v3,0x00
0286 : 0x00EE ret
0288 : 0x6628 ld v6,0x28
028A : 0x6707 ld v7,0x07
028C : 0x6428 ld v4,0x28
028E : 0x650C ld v5,0x0C
0290 : 0x6216 ld v2,0x16
0292 : 0x6311 ld v3,0x11
0294 : 0x00EE ret
0296 : 0x6628 ld v6,0x28
0298 : 0x6707 ld v7,0x07
029A : 0x6428 ld v4,0x28
029C : 0x650E ld v5,0x0E
029E : 0x6216 ld v2,0x16
02A0 : 0x6314 ld v3,0x14
02A2 : 0x00EE ret
02A4 : 0x6628 ld v6,0x28
02A6 : 0x6705 ld v7,0x05
02A8 : 0x6428 ld v4,0x28
02AA : 0x6510 ld v5,0x10
02AC : 0x6216 ld v2,0x16
02AE : 0x630B ld v3,0x0B
02B0 : 0x00EE ret
02B2 : 0xA359 ld i,359
02B4 : 0xD672 drw v6,v7,2
02B6 : 0x76FE add v6,0xFE
02B8 : 0xD672 drw v6,v7,2
02BA : 0x4400 sne v4,0x00
02BC : 0x00EE ret
02BE : 0xA357 ld i,357
02C0 : 0xD452 drw v4,v5,2
02C2 : 0x7402 add v4,0x02
02C4 : 0x4444 sne v4,0x44
02C6 : 0x74C0 add v4,0xC0
02C8 : 0xD452 drw v4,v5,2
02CA : 0x4200 sne v2,0x00
02CC : 0x00EE ret
02CE : 0xA35B ld i,35B
02D0 : 0xD232 drw v2,v3,2
02D2 : 0x7202 add v2,0x02
02D4 : 0x4C04 sne v12,0x04
02D6 : 0x7202 add v2,0x02
02D8 : 0x4C05 sne v12,0x05
02DA : 0x7202 add v2,0x02
02DC : 0x4244 sne v2,0x44
02DE : 0x72C0 add v2,0xC0
02E0 : 0xD232 drw v2,v3,2
02E2 : 0x00EE ret
02E4 : 0x7C01 add v12,0x01
02E6 : 0x6D00 ld v13,0x00
02E8 : 0x6E02 ld v14,0x02
02EA : 0x00E0 cls
02EC : 0x4C06 sne v12,0x06
02EE : 0x6C01 ld v12,0x01
02F0 : 0x6A00 ld v10,0x00
02F2 : 0x120A jp 20A
02F4 : 0x6006 ld v0,0x06
02F6 : 0xF018 ld st,v0
02F8 : 0x7BFF add v11,0xFF
02FA : 0x4B00 sne v11,0x00
02FC : 0x1308 jp 308
02FE : 0x6D00 ld v13,0x00
0300 : 0x6E02 ld v14,0x02
0302 : 0x00E0 cls
0304 : 0x6A00 ld v10,0x00
0306 : 0x120A jp 20A
0308 : 0x1308 jp 308
030A : 0x4A01 sne v10,0x01
030C : 0x00EE ret
030E : 0x6002 ld v0,0x02
0310 : 0xF018 ld st,v0
0312 : 0x6A01 ld v10,0x01
0314 : 0x88D0 ld v8,v13
0316 : 0x7801 add v8,0x01
0318 : 0x89E0 ld v9,v14
031A : 0x7901 add v9,0x01
031C : 0xD891 drw v8,v9,1
031E : 0x00EE ret
0320 : 0xA354 ld i,354
0322 : 0xDDE2 drw v13,v14,2
0324 : 0x00EE ret
0326 : 0x6419 ld v4,0x19
0328 : 0x6300 ld v3,0x00
032A : 0xA356 ld i,356
032C : 0xD341 drw v3,v4,1
032E : 0x7308 add v3,0x08
0330 : 0x3340 se v3,0x40
0332 : 0x132C jp 32C
0334 : 0x631E ld v3,0x1E
0336 : 0x641B ld v4,0x1B
0338 : 0xFC29 ld f,v12
033A : 0xD345 drw v3,v4,5
033C : 0x4B04 sne v11,0x04
033E : 0xA35F ld i,35F
0340 : 0x4B03 sne v11,0x03
0342 : 0xA360 ld i,360
0344 : 0x4B02 sne v11,0x02
0346 : 0xA361 ld i,361
0348 : 0x4B01 sne v11,0x01
034A : 0xA362 ld i,362
034C : 0x6301 ld v3,0x01
034E : 0x7402 add v4,0x02
0350 : 0xD341 drw v3,v4,1
0352 : 0x00EE ret
Существует ряд инструкций, которые загружают i с адресом в этом пространстве в 0x354 и после него, поэтому я предполагаю, что вы обнаружите, что данные используются программой, а не инструкции. и самый большой из них 0x362. из данных, описываемых вашей hexdump, самый большой адрес - 0x363, но это нулевое и / или преднамеренное заполнение, или ему придется взглянуть на код в отношении использования i.
022E : 0xA362 ld i,362
0256 : 0xA359 ld i,359
025E : 0xA357 ld i,357
0266 : 0xA35B ld i,35B
02B2 : 0xA359 ld i,359
02BE : 0xA357 ld i,357
02CE : 0xA35B ld i,35B
0320 : 0xA354 ld i,354
032A : 0xA356 ld i,356
033E : 0xA35F ld i,35F
0342 : 0xA360 ld i,360
0346 : 0xA361 ld i,361
034A : 0xA362 ld i,362