/* This program modifies an Atari 400/800 OS ROM image by adding the necessary
   checksums to it.
   The checksums stored in a 400/800 OS ROM are only used by the SALT
   cartridges, during the OS ROM verifcation tests. */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

enum {
	ROM_SIZE = 0x2800, /* Size of the ROM image in bytes. */
	ROM_START = 0xd800 /* Address of the ROM's first byte in the Atari
	                      computer's address space. */
};

/* A checksum is computed by sequentially summing up all bytes of the ROM area
   (skipping the location of the checksum itself), ignoring any carry bits. */
void write_checksum(unsigned char rom[ROM_SIZE],
		    unsigned int start, unsigned int end,
		    unsigned int lsb, unsigned int msb)
{
	unsigned int i;
	unsigned int sum = 0;

	start -= ROM_START;
	end -= ROM_START;
	lsb -= ROM_START;
	msb -= ROM_START;

	for (i = start; i <= end; ++i) {
		if (i != lsb && i != msb)
			sum += rom[i];
	}

	rom[lsb] = sum & 0xff;
	rom[msb] = (sum >> 8) & 0xff;
}

int main(int argc, char *argv[])
{
	FILE *f;
	unsigned char rom[ROM_SIZE];
	if (argc < 4) {
		fprintf(stderr, " Usage: %s <antsc|apal|bntsc|bpal> <input filename> <output filename>\n", argv[0]);
		return EXIT_FAILURE;
	}

	/* Read ROM image. */
	f = fopen(argv[2], "rb");
	if (f == NULL) {
		fprintf(stderr, "Can't open %s\n", argv[2]);
		return EXIT_FAILURE;
	}
	if (fread(rom, sizeof(char), ROM_SIZE, f) != ROM_SIZE) {
		fprintf(stderr, "Can't read %s or file length not equal to %04x bytes\n", argv[2], ROM_SIZE);
		return EXIT_FAILURE;
	}
	if (fclose(f) != 0) {
		fprintf(stderr, "Can't close %s\n", argv[2]);
		return EXIT_FAILURE;
	}

	/* The 400/800 OS ROM contains three 16-bit checksum, one for the
	   2KB Floating Point Package, and one for each half of the OS ROM.

	   Checksum of the FPP ROM is located at 0xdffe-0xdfff. */
	write_checksum(rom, 0xd800, 0xdfff, 0xdffe, 0xdfff);

	/* If the ROM is NTSC Rev. B, we skip writing the OS checksums.

	   Atari definitely blundered in building the Rev. B ROM image - not
	   only they left over random bytes in the unused areas (see the end of
	   ca65/800b.s), they also forgot to write the proper checksums into
	   the image! As a result, the checksum locations are filled with
	   whatever there was after assembing.

	   Judging from the XL Addendum, they were going to fix the issue in
	   the PAL Rev. B ROM - the checksum value for this revision, as given
	   in the document, matches the computed value. */
	if (strcmp(argv[1], "bntsc") != 0) {
		/* Checksum of the first 4K ROM half is located at 0xe40f and 0xe41f. */
		write_checksum(rom, 0xe000, 0xefff, 0xe40f, 0xe41f);

		/* Checksum of the second 4K ROM half is located at 0xfff8-0xfff9. */
		write_checksum(rom, 0xf000, 0xffff, 0xfff8, 0xfff9);
	}

	/* Save modified ROM image. */
	f = fopen(argv[3], "wb");
	if (f == NULL) {
		fprintf(stderr, "Can't open %s\n", argv[3]);
		return EXIT_FAILURE;
	}
	if (fwrite(rom, sizeof(char), ROM_SIZE, f) != ROM_SIZE) {
		fprintf(stderr, "Can't write %s\n", argv[3]);
		return EXIT_FAILURE;
	}
	if (fclose(f) != 0) {
		fprintf(stderr, "Can't close %s\n", argv[3]);
		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}
