I'm trying to generate a cartridge header checksum for a Game Boy cart. The cartridge header checksum is defined as this C-like pseudocode:
unsigned char checksum = 0;
for(unsigned char *p = 0x0134; p < 0x014D; p++)
x += ~*p;
or alternatively:
unsigned char checksum = 0;
for(unsigned char *p = 0x0134; p < 0x014D; p++)
x = x - *p - 1;
This data starts at the address 0x0104. The address 0x0134 corresponds to the beginning of title. The address 0x014D corresponds to the beginning of header_checksum.
Note that for demonstration purposes I'm using hexadecimal escape sequences in .ascii strings. This won't actually work because \x isn't recognized by 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
How can I calculate this checksum? If possible, is there a way to do it using assembler directives?