Как я могу создать контрольную сумму для этого заголовка картриджа? - PullRequest
2 голосов
/ 27 марта 2020

Я пытаюсь сгенерировать заголовок картриджа контрольную сумму для корзины Game Boy. Контрольная сумма заголовка картриджа определяется как этот C -подобный псевдокод:

unsigned char checksum = 0;
for(unsigned char *p = 0x0134; p < 0x014D; p++)
    x += ~*p;

или альтернативно:

unsigned char checksum = 0;
for(unsigned char *p = 0x0134; p < 0x014D; p++)
    x = x - *p - 1;

Эти данные начинаются с адреса 0x0104. Адрес 0x0134 соответствует началу title. Адрес 0x014D соответствует началу header_checksum.

Обратите внимание, что в демонстрационных целях я использую шестнадцатеричные escape-последовательности в строках .ascii. Это не на самом деле работает, потому что \x не распознается GNU as.

nintendo_logo:
    # Nintendo logo. Must be present and unmodified.
    .ascii "\xce\xed\x66\x66\xcc\x0d\x00\x0b\x03\x73\x00\x83\x00\x0c\x00\x0d"
    .ascii "\x00\x08\x11\x1f\x88\x89\x00\x0e\xdc\xcc\x6e\xe6\xdd\xdd\xd9\x99"
    .ascii "\xbb\xbb\x67\x63\x6e\x0e\xec\xcc\xdd\xdc\x99\x9f\xbb\xb9\x33\x3e"
title:
    # Title. At most 11 characters and zero-padded if smaller.
    # GameBoys use 16 characters.
    TITLE_SIZE = 11
    .ascii "ABCDEF"
    .fill TITLE_SIZE-(.-title)
manufacturer:
    .ascii "ABCD"
cgb_f:
    # Color Game Boy flag. 0x80 means that the game supports
    # Color Game Boy functions, but still works on the original Game Boy.
    .byte 0x80
new_licensee:
    # Company or publisher ASCII code. 00 is none.
    .ascii "00"
sgb_f:
    # Super Game Boy flag. 3 means it has support for the SGB, 0 means no.
    # I might implement color for the SGB
    .byte 0x03
cart_type:
    # Memory bank controller used and any additional hardware.
    # 0x00 is rom-only.
    .byte 0x00
rom_size:
    # ROM size in terms of 32KB << B
    .byte 0x00
ram_size:
    # The amount of externam RAM in the catridge
    .byte 0x00
is_japan:
    # If the byte is 0x00 it's for Japan, if 0x01 anywhere else
    .byte 0x01
old_licensee:
    # hex value of company/publisher
    # Super Game Boy needs 0x33 to work
    .byte 0x33
version:
    # version of the game
    .byte 0x00
header_checksum:
    # TODO: How to calculate this?
    sum = add(title, version)
    .byte sum

Как я могу вычислить эту контрольную сумму? Если возможно, есть ли способ сделать это, используя директивы ассемблера?

1 Ответ

1 голос
/ 28 марта 2020

Директивы GAS не могут прочитать байты, которые уже были переданы в выходной файл.

Если вам нужно время сборки вычисление чего-либо, я думаю, вы могли бы сделать это с a GAS .macro, который использовал свой аргумент в выражении времени сборки, обновляющем переменную ассемблера, и в качестве операнда для .byte.

Но вам нужно сделать это в выражениях, которые работают как числа, что, вероятно, исключило бы удобные .ascii строковые литералы.

В этом случае, вероятно, больше проблем, чем стоит преобразовать в используя макрос типа
byte_cksum_accum 0xce,0xed,0x66,0x66,0xcc,0x0d,0x00, ....

Такой макрос может использовать .set cksum, cksum + ~\1 или что-то подобное, а также .byte \1. Зацикливание на нескольких макро-аргументах GAS выполняется путем записи рекурсивного .macro. Поэтому я думаю, что это возможно. GAS также имеет синтаксис .altmacro, который позволяет i = i + 1. Я сам не очень часто использовал макросы GAS.

Лучшая альтернатива: используйте C программу + правила сборки + .incbin

  • Пусть ваш источник использует .incbin "checksum_file.bin директива
  • ... которую программа C пишет после прочтения вашего .o
  • В Makefile, правило сборки для этого .o собирается / генерируется внешняя / повторная сборка контрольной суммы, включающая правильную контрольную сумму. (коснитесь или обрежьте или удалите checksum_file.bin перед сборкой в ​​первый раз, что наиболее удобно, чтобы убедиться, что он все еще собирается, и при необходимости не содержит устаревший байт контрольной суммы.)

Еще лучшая альтернатива?

  • Ваша программа C выводит плоский двоичный файл с данными и контрольной суммой. Итак, заголовок байты все еще присутствуют в одном месте вашего источника, в инициализаторе uint8_t header[] = {...} в вашей программе C.
  • Используйте .incbin в .S, чтобы включить его.
  • Используйте правило сборки, чтобы убедиться, что cksummed-header.bin является входной зависимостью для построения .S

Или напишите C программу, которая изменяет двоичный файл

  • Считывает заголовок, обновляет заполнитель .byte 0 в двоичном файле.
  • Сохраняет данные заголовка вместе с остальной частью исходного кода asm
  • C программы не нужно перекомпилировать для разных тележек.
...