aboutsummaryrefslogtreecommitdiff
path: root/mkcart.c
diff options
context:
space:
mode:
Diffstat (limited to 'mkcart.c')
-rw-r--r--mkcart.c678
1 files changed, 678 insertions, 0 deletions
diff --git a/mkcart.c b/mkcart.c
new file mode 100644
index 0000000..28ba5d5
--- /dev/null
+++ b/mkcart.c
@@ -0,0 +1,678 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ mkcart.c, by B. Watson, part of DASM Atari 8-bit support.
+
+ DASM and atari800 are both GPLv2 so I've lifted code straight
+ from the emulator.
+
+ This is not great C code. It's what happens when I try to write
+ C after spending a week hacking assembly code.
+ */
+
+/* nobody needs more input files than this, right? I should
+ define it to 640K :) */
+#define MAX_INPUT_FILES 1024
+
+/* this is the smallest supported cart size */
+#define CARTBUFLEN 2048
+
+typedef struct {
+ char *name;
+ int size;
+} cart_t;
+
+/* from atari800-3.1.0/src/cartridge.h */
+enum {
+ CARTRIDGE_UNKNOWN = -1,
+ CARTRIDGE_NONE = 0,
+ CARTRIDGE_STD_8 = 1,
+ CARTRIDGE_STD_16 = 2,
+ CARTRIDGE_OSS_034M_16 = 3,
+ CARTRIDGE_5200_32 = 4,
+ CARTRIDGE_DB_32 = 5,
+ CARTRIDGE_5200_EE_16 = 6,
+ CARTRIDGE_5200_40 = 7,
+ CARTRIDGE_WILL_64 = 8,
+ CARTRIDGE_EXP_64 = 9,
+ CARTRIDGE_DIAMOND_64 = 10,
+ CARTRIDGE_SDX_64 = 11,
+ CARTRIDGE_XEGS_32 = 12,
+ CARTRIDGE_XEGS_07_64 = 13,
+ CARTRIDGE_XEGS_128 = 14,
+ CARTRIDGE_OSS_M091_16 = 15,
+ CARTRIDGE_5200_NS_16 = 16,
+ CARTRIDGE_ATRAX_128 = 17,
+ CARTRIDGE_BBSB_40 = 18,
+ CARTRIDGE_5200_8 = 19,
+ CARTRIDGE_5200_4 = 20,
+ CARTRIDGE_RIGHT_8 = 21,
+ CARTRIDGE_WILL_32 = 22,
+ CARTRIDGE_XEGS_256 = 23,
+ CARTRIDGE_XEGS_512 = 24,
+ CARTRIDGE_XEGS_1024 = 25,
+ CARTRIDGE_MEGA_16 = 26,
+ CARTRIDGE_MEGA_32 = 27,
+ CARTRIDGE_MEGA_64 = 28,
+ CARTRIDGE_MEGA_128 = 29,
+ CARTRIDGE_MEGA_256 = 30,
+ CARTRIDGE_MEGA_512 = 31,
+ CARTRIDGE_MEGA_1024 = 32,
+ CARTRIDGE_SWXEGS_32 = 33,
+ CARTRIDGE_SWXEGS_64 = 34,
+ CARTRIDGE_SWXEGS_128 = 35,
+ CARTRIDGE_SWXEGS_256 = 36,
+ CARTRIDGE_SWXEGS_512 = 37,
+ CARTRIDGE_SWXEGS_1024 = 38,
+ CARTRIDGE_PHOENIX_8 = 39,
+ CARTRIDGE_BLIZZARD_16 = 40,
+ CARTRIDGE_ATMAX_128 = 41,
+ CARTRIDGE_ATMAX_1024 = 42,
+ CARTRIDGE_SDX_128 = 43,
+ CARTRIDGE_OSS_8 = 44,
+ CARTRIDGE_OSS_043M_16 = 45,
+ CARTRIDGE_BLIZZARD_4 = 46,
+ CARTRIDGE_AST_32 = 47,
+ CARTRIDGE_ATRAX_SDX_64 = 48,
+ CARTRIDGE_ATRAX_SDX_128 = 49,
+ CARTRIDGE_TURBOSOFT_64 = 50,
+ CARTRIDGE_TURBOSOFT_128 = 51,
+ CARTRIDGE_ULTRACART_32 = 52,
+ CARTRIDGE_LOW_BANK_8 = 53,
+ CARTRIDGE_SIC_128 = 54,
+ CARTRIDGE_SIC_256 = 55,
+ CARTRIDGE_SIC_512 = 56,
+ CARTRIDGE_STD_2 = 57,
+ CARTRIDGE_STD_4 = 58,
+ CARTRIDGE_RIGHT_4 = 59,
+ CARTRIDGE_BLIZZARD_32 = 60,
+ CARTRIDGE_MEGAMAX_2048 = 61,
+ CARTRIDGE_THECART_128M = 62,
+ CARTRIDGE_MEGA_4096 = 63,
+ CARTRIDGE_MEGA_2048 = 64,
+ CARTRIDGE_THECART_32M = 65,
+ CARTRIDGE_THECART_64M = 66,
+ CARTRIDGE_XEGS_8F_64 = 67,
+ CARTRIDGE_LAST_SUPPORTED = 67
+};
+
+#define CARTRIDGE_MAX_SIZE (128 * 1024 * 1024)
+
+#define CARTRIDGE_STD_8_DESC "Standard 8 KB cartridge"
+#define CARTRIDGE_STD_16_DESC "Standard 16 KB cartridge"
+#define CARTRIDGE_OSS_034M_16_DESC "OSS two chip 16 KB cartridge (034M)"
+#define CARTRIDGE_5200_32_DESC "Standard 32 KB 5200 cartridge"
+#define CARTRIDGE_DB_32_DESC "DB 32 KB cartridge"
+#define CARTRIDGE_5200_EE_16_DESC "Two chip 16 KB 5200 cartridge"
+#define CARTRIDGE_5200_40_DESC "Bounty Bob 40 KB 5200 cartridge"
+#define CARTRIDGE_WILL_64_DESC "64 KB Williams cartridge"
+#define CARTRIDGE_EXP_64_DESC "Express 64 KB cartridge"
+#define CARTRIDGE_DIAMOND_64_DESC "Diamond 64 KB cartridge"
+#define CARTRIDGE_SDX_64_DESC "SpartaDOS X 64 KB cartridge"
+#define CARTRIDGE_XEGS_32_DESC "XEGS 32 KB cartridge"
+#define CARTRIDGE_XEGS_07_64_DESC "XEGS 64 KB cartridge (banks 0-7)"
+#define CARTRIDGE_XEGS_128_DESC "XEGS 128 KB cartridge"
+#define CARTRIDGE_OSS_M091_16_DESC "OSS one chip 16 KB cartridge"
+#define CARTRIDGE_5200_NS_16_DESC "One chip 16 KB 5200 cartridge"
+#define CARTRIDGE_ATRAX_128_DESC "Atrax 128 KB cartridge"
+#define CARTRIDGE_BBSB_40_DESC "Bounty Bob 40 KB cartridge"
+#define CARTRIDGE_5200_8_DESC "Standard 8 KB 5200 cartridge"
+#define CARTRIDGE_5200_4_DESC "Standard 4 KB 5200 cartridge"
+#define CARTRIDGE_RIGHT_8_DESC "Right slot 8 KB cartridge"
+#define CARTRIDGE_WILL_32_DESC "32 KB Williams cartridge"
+#define CARTRIDGE_XEGS_256_DESC "XEGS 256 KB cartridge"
+#define CARTRIDGE_XEGS_512_DESC "XEGS 512 KB cartridge"
+#define CARTRIDGE_XEGS_1024_DESC "XEGS 1 MB cartridge"
+#define CARTRIDGE_MEGA_16_DESC "MegaCart 16 KB cartridge"
+#define CARTRIDGE_MEGA_32_DESC "MegaCart 32 KB cartridge"
+#define CARTRIDGE_MEGA_64_DESC "MegaCart 64 KB cartridge"
+#define CARTRIDGE_MEGA_128_DESC "MegaCart 128 KB cartridge"
+#define CARTRIDGE_MEGA_256_DESC "MegaCart 256 KB cartridge"
+#define CARTRIDGE_MEGA_512_DESC "MegaCart 512 KB cartridge"
+#define CARTRIDGE_MEGA_1024_DESC "MegaCart 1 MB cartridge"
+#define CARTRIDGE_SWXEGS_32_DESC "Switchable XEGS 32 KB cartridge"
+#define CARTRIDGE_SWXEGS_64_DESC "Switchable XEGS 64 KB cartridge"
+#define CARTRIDGE_SWXEGS_128_DESC "Switchable XEGS 128 KB cartridge"
+#define CARTRIDGE_SWXEGS_256_DESC "Switchable XEGS 256 KB cartridge"
+#define CARTRIDGE_SWXEGS_512_DESC "Switchable XEGS 512 KB cartridge"
+#define CARTRIDGE_SWXEGS_1024_DESC "Switchable XEGS 1 MB cartridge"
+#define CARTRIDGE_PHOENIX_8_DESC "Phoenix 8 KB cartridge"
+#define CARTRIDGE_BLIZZARD_16_DESC "Blizzard 16 KB cartridge"
+#define CARTRIDGE_ATMAX_128_DESC "Atarimax 128 KB Flash cartridge"
+#define CARTRIDGE_ATMAX_1024_DESC "Atarimax 1 MB Flash cartridge"
+#define CARTRIDGE_SDX_128_DESC "SpartaDOS X 128 KB cartridge"
+#define CARTRIDGE_OSS_8_DESC "OSS 8 KB cartridge"
+#define CARTRIDGE_OSS_043M_16_DESC "OSS two chip 16 KB cartridge (043M)"
+#define CARTRIDGE_BLIZZARD_4_DESC "Blizzard 4 KB cartridge"
+#define CARTRIDGE_AST_32_DESC "AST 32 KB cartridge"
+#define CARTRIDGE_ATRAX_SDX_64_DESC "Atrax SDX 64 KB cartridge"
+#define CARTRIDGE_ATRAX_SDX_128_DESC "Atrax SDX 128 KB cartridge"
+#define CARTRIDGE_TURBOSOFT_64_DESC "Turbosoft 64 KB cartridge"
+#define CARTRIDGE_TURBOSOFT_128_DESC "Turbosoft 128 KB cartridge"
+#define CARTRIDGE_ULTRACART_32_DESC "Ultracart 32 KB cartridge"
+#define CARTRIDGE_LOW_BANK_8_DESC "Low bank 8 KB cartridge"
+#define CARTRIDGE_SIC_128_DESC "SIC! 128 KB cartridge"
+#define CARTRIDGE_SIC_256_DESC "SIC! 256 KB cartridge"
+#define CARTRIDGE_SIC_512_DESC "SIC! 512 KB cartridge"
+#define CARTRIDGE_STD_2_DESC "Standard 2 KB cartridge"
+#define CARTRIDGE_STD_4_DESC "Standard 4 KB cartridge"
+#define CARTRIDGE_RIGHT_4_DESC "Right slot 4 KB cartridge"
+#define CARTRIDGE_BLIZZARD_32_DESC "Blizzard 32 KB cartridge"
+#define CARTRIDGE_MEGAMAX_2048_DESC "MegaMax 2 MB cartridge"
+#define CARTRIDGE_THECART_128M_DESC "The!Cart 128 MB cartridge"
+#define CARTRIDGE_MEGA_4096_DESC "Flash MegaCart 4 MB cartridge"
+#define CARTRIDGE_MEGA_2048_DESC "MegaCart 2 MB cartridge"
+#define CARTRIDGE_THECART_32M_DESC "The!Cart 32 MB cartridge"
+#define CARTRIDGE_THECART_64M_DESC "The!Cart 64 MB cartridge"
+#define CARTRIDGE_XEGS_8F_64_DESC "XEGS 64 KB cartridge (banks 8-15)"
+
+/* this bit didn't come from atari800 */
+static cart_t cart_types[CARTRIDGE_LAST_SUPPORTED + 1];
+#define UI_MENU_ACTION(index, desc) \
+ cart_types[index].size = CARTRIDGE_kb[index]*1024; \
+ cart_types[index].name = desc;
+
+/* from atari800-3.1.0/src/cartridge.c */
+int const CARTRIDGE_kb[CARTRIDGE_LAST_SUPPORTED + 1] = {
+ 0,
+ 8, /* CARTRIDGE_STD_8 */
+ 16, /* CARTRIDGE_STD_16 */
+ 16, /* CARTRIDGE_OSS_034M_16 */
+ 32, /* CARTRIDGE_5200_32 */
+ 32, /* CARTRIDGE_DB_32 */
+ 16, /* CARTRIDGE_5200_EE_16 */
+ 40, /* CARTRIDGE_5200_40 */
+ 64, /* CARTRIDGE_WILL_64 */
+ 64, /* CARTRIDGE_EXP_64 */
+ 64, /* CARTRIDGE_DIAMOND_64 */
+ 64, /* CARTRIDGE_SDX_64 */
+ 32, /* CARTRIDGE_XEGS_32 */
+ 64, /* CARTRIDGE_XEGS_64_07 */
+ 128, /* CARTRIDGE_XEGS_128 */
+ 16, /* CARTRIDGE_OSS_M091_16 */
+ 16, /* CARTRIDGE_5200_NS_16 */
+ 128, /* CARTRIDGE_ATRAX_128 */
+ 40, /* CARTRIDGE_BBSB_40 */
+ 8, /* CARTRIDGE_5200_8 */
+ 4, /* CARTRIDGE_5200_4 */
+ 8, /* CARTRIDGE_RIGHT_8 */
+ 32, /* CARTRIDGE_WILL_32 */
+ 256, /* CARTRIDGE_XEGS_256 */
+ 512, /* CARTRIDGE_XEGS_512 */
+ 1024, /* CARTRIDGE_XEGS_1024 */
+ 16, /* CARTRIDGE_MEGA_16 */
+ 32, /* CARTRIDGE_MEGA_32 */
+ 64, /* CARTRIDGE_MEGA_64 */
+ 128, /* CARTRIDGE_MEGA_128 */
+ 256, /* CARTRIDGE_MEGA_256 */
+ 512, /* CARTRIDGE_MEGA_512 */
+ 1024, /* CARTRIDGE_MEGA_1024 */
+ 32, /* CARTRIDGE_SWXEGS_32 */
+ 64, /* CARTRIDGE_SWXEGS_64 */
+ 128, /* CARTRIDGE_SWXEGS_128 */
+ 256, /* CARTRIDGE_SWXEGS_256 */
+ 512, /* CARTRIDGE_SWXEGS_512 */
+ 1024, /* CARTRIDGE_SWXEGS_1024 */
+ 8, /* CARTRIDGE_PHOENIX_8 */
+ 16, /* CARTRIDGE_BLIZZARD_16 */
+ 128, /* CARTRIDGE_ATMAX_128 */
+ 1024, /* CARTRIDGE_ATMAX_1024 */
+ 128, /* CARTRIDGE_SDX_128 */
+ 8, /* CARTRIDGE_OSS_8 */
+ 16, /* CARTRIDGE_OSS_043M_16 */
+ 4, /* CARTRIDGE_BLIZZARD_4 */
+ 32, /* CARTRIDGE_AST_32 */
+ 64, /* CARTRIDGE_ATRAX_SDX_64 */
+ 128, /* CARTRIDGE_ATRAX_SDX_128 */
+ 64, /* CARTRIDGE_TURBOSOFT_64 */
+ 128, /* CARTRIDGE_TURBOSOFT_128 */
+ 32, /* CARTRIDGE_ULTRACART_32 */
+ 8, /* CARTRIDGE_LOW_BANK_8 */
+ 128, /* CARTRIDGE_SIC_128 */
+ 256, /* CARTRIDGE_SIC_256 */
+ 512, /* CARTRIDGE_SIC_512 */
+ 2, /* CARTRIDGE_STD_2 */
+ 4, /* CARTRIDGE_STD_4 */
+ 4, /* CARTRIDGE_RIGHT_4 */
+ 32, /* CARTRIDGE_TURBO_HIT_32 */
+ 2048, /* CARTRIDGE_MEGA_2048 */
+ 128*1024, /* CARTRIDGE_THECART_128M */
+ 4096, /* CARTRIDGE_MEGA_4096 */
+ 2048, /* CARTRIDGE_MEGA_2048 */
+ 32*1024, /* CARTRIDGE_THECART_32M */
+ 64*1024, /* CARTRIDGE_THECART_64M */
+ 64 /* CARTRIDGE_XEGS_64_8F */
+};
+
+/* Adapted from from atari800-3.1.0/src/ui.c, by s/,$/;/ */
+void init() {
+ UI_MENU_ACTION(CARTRIDGE_STD_8, CARTRIDGE_STD_8_DESC);
+ UI_MENU_ACTION(CARTRIDGE_STD_16, CARTRIDGE_STD_16_DESC);
+ UI_MENU_ACTION(CARTRIDGE_OSS_034M_16, CARTRIDGE_OSS_034M_16_DESC);
+ UI_MENU_ACTION(CARTRIDGE_5200_32, CARTRIDGE_5200_32_DESC);
+ UI_MENU_ACTION(CARTRIDGE_DB_32, CARTRIDGE_DB_32_DESC);
+ UI_MENU_ACTION(CARTRIDGE_5200_EE_16, CARTRIDGE_5200_EE_16_DESC);
+ UI_MENU_ACTION(CARTRIDGE_5200_40, CARTRIDGE_5200_40_DESC);
+ UI_MENU_ACTION(CARTRIDGE_WILL_64, CARTRIDGE_WILL_64_DESC);
+ UI_MENU_ACTION(CARTRIDGE_EXP_64, CARTRIDGE_EXP_64_DESC);
+ UI_MENU_ACTION(CARTRIDGE_DIAMOND_64, CARTRIDGE_DIAMOND_64_DESC);
+ UI_MENU_ACTION(CARTRIDGE_SDX_64, CARTRIDGE_SDX_64_DESC);
+ UI_MENU_ACTION(CARTRIDGE_XEGS_32, CARTRIDGE_XEGS_32_DESC);
+ UI_MENU_ACTION(CARTRIDGE_XEGS_07_64, CARTRIDGE_XEGS_07_64_DESC);
+ UI_MENU_ACTION(CARTRIDGE_XEGS_128, CARTRIDGE_XEGS_128_DESC);
+ UI_MENU_ACTION(CARTRIDGE_OSS_M091_16, CARTRIDGE_OSS_M091_16_DESC);
+ UI_MENU_ACTION(CARTRIDGE_5200_NS_16, CARTRIDGE_5200_NS_16_DESC);
+ UI_MENU_ACTION(CARTRIDGE_ATRAX_128, CARTRIDGE_ATRAX_128_DESC);
+ UI_MENU_ACTION(CARTRIDGE_BBSB_40, CARTRIDGE_BBSB_40_DESC);
+ UI_MENU_ACTION(CARTRIDGE_5200_8, CARTRIDGE_5200_8_DESC);
+ UI_MENU_ACTION(CARTRIDGE_5200_4, CARTRIDGE_5200_4_DESC);
+ UI_MENU_ACTION(CARTRIDGE_RIGHT_8, CARTRIDGE_RIGHT_8_DESC);
+ UI_MENU_ACTION(CARTRIDGE_WILL_32, CARTRIDGE_WILL_32_DESC);
+ UI_MENU_ACTION(CARTRIDGE_XEGS_256, CARTRIDGE_XEGS_256_DESC);
+ UI_MENU_ACTION(CARTRIDGE_XEGS_512, CARTRIDGE_XEGS_512_DESC);
+ UI_MENU_ACTION(CARTRIDGE_XEGS_1024, CARTRIDGE_XEGS_1024_DESC);
+ UI_MENU_ACTION(CARTRIDGE_MEGA_16, CARTRIDGE_MEGA_16_DESC);
+ UI_MENU_ACTION(CARTRIDGE_MEGA_32, CARTRIDGE_MEGA_32_DESC);
+ UI_MENU_ACTION(CARTRIDGE_MEGA_64, CARTRIDGE_MEGA_64_DESC);
+ UI_MENU_ACTION(CARTRIDGE_MEGA_128, CARTRIDGE_MEGA_128_DESC);
+ UI_MENU_ACTION(CARTRIDGE_MEGA_256, CARTRIDGE_MEGA_256_DESC);
+ UI_MENU_ACTION(CARTRIDGE_MEGA_512, CARTRIDGE_MEGA_512_DESC);
+ UI_MENU_ACTION(CARTRIDGE_MEGA_1024, CARTRIDGE_MEGA_1024_DESC);
+ UI_MENU_ACTION(CARTRIDGE_SWXEGS_32, CARTRIDGE_SWXEGS_32_DESC);
+ UI_MENU_ACTION(CARTRIDGE_SWXEGS_64, CARTRIDGE_SWXEGS_64_DESC);
+ UI_MENU_ACTION(CARTRIDGE_SWXEGS_128, CARTRIDGE_SWXEGS_128_DESC);
+ UI_MENU_ACTION(CARTRIDGE_SWXEGS_256, CARTRIDGE_SWXEGS_256_DESC);
+ UI_MENU_ACTION(CARTRIDGE_SWXEGS_512, CARTRIDGE_SWXEGS_512_DESC);
+ UI_MENU_ACTION(CARTRIDGE_SWXEGS_1024, CARTRIDGE_SWXEGS_1024_DESC);
+ UI_MENU_ACTION(CARTRIDGE_PHOENIX_8, CARTRIDGE_PHOENIX_8_DESC);
+ UI_MENU_ACTION(CARTRIDGE_BLIZZARD_16, CARTRIDGE_BLIZZARD_16_DESC);
+ UI_MENU_ACTION(CARTRIDGE_ATMAX_128, CARTRIDGE_ATMAX_128_DESC);
+ UI_MENU_ACTION(CARTRIDGE_ATMAX_1024, CARTRIDGE_ATMAX_1024_DESC);
+ UI_MENU_ACTION(CARTRIDGE_SDX_128, CARTRIDGE_SDX_128_DESC);
+ UI_MENU_ACTION(CARTRIDGE_OSS_8, CARTRIDGE_OSS_8_DESC);
+ UI_MENU_ACTION(CARTRIDGE_OSS_043M_16, CARTRIDGE_OSS_043M_16_DESC);
+ UI_MENU_ACTION(CARTRIDGE_BLIZZARD_4, CARTRIDGE_BLIZZARD_4_DESC);
+ UI_MENU_ACTION(CARTRIDGE_AST_32, CARTRIDGE_AST_32_DESC);
+ UI_MENU_ACTION(CARTRIDGE_ATRAX_SDX_64, CARTRIDGE_ATRAX_SDX_64_DESC);
+ UI_MENU_ACTION(CARTRIDGE_ATRAX_SDX_128, CARTRIDGE_ATRAX_SDX_128_DESC);
+ UI_MENU_ACTION(CARTRIDGE_TURBOSOFT_64, CARTRIDGE_TURBOSOFT_64_DESC);
+ UI_MENU_ACTION(CARTRIDGE_TURBOSOFT_128, CARTRIDGE_TURBOSOFT_128_DESC);
+ UI_MENU_ACTION(CARTRIDGE_ULTRACART_32, CARTRIDGE_ULTRACART_32_DESC);
+ UI_MENU_ACTION(CARTRIDGE_LOW_BANK_8, CARTRIDGE_LOW_BANK_8_DESC);
+ UI_MENU_ACTION(CARTRIDGE_SIC_128, CARTRIDGE_SIC_128_DESC);
+ UI_MENU_ACTION(CARTRIDGE_SIC_256, CARTRIDGE_SIC_256_DESC);
+ UI_MENU_ACTION(CARTRIDGE_SIC_512, CARTRIDGE_SIC_512_DESC);
+ UI_MENU_ACTION(CARTRIDGE_STD_2, CARTRIDGE_STD_2_DESC);
+ UI_MENU_ACTION(CARTRIDGE_STD_4, CARTRIDGE_STD_4_DESC);
+ UI_MENU_ACTION(CARTRIDGE_RIGHT_4, CARTRIDGE_RIGHT_4_DESC);
+ UI_MENU_ACTION(CARTRIDGE_BLIZZARD_32, CARTRIDGE_BLIZZARD_32_DESC);
+ UI_MENU_ACTION(CARTRIDGE_MEGAMAX_2048, CARTRIDGE_MEGAMAX_2048_DESC);
+ UI_MENU_ACTION(CARTRIDGE_THECART_128M, CARTRIDGE_THECART_128M_DESC);
+ UI_MENU_ACTION(CARTRIDGE_MEGA_4096, CARTRIDGE_MEGA_4096_DESC);
+ UI_MENU_ACTION(CARTRIDGE_MEGA_2048, CARTRIDGE_MEGA_2048_DESC);
+ UI_MENU_ACTION(CARTRIDGE_THECART_32M, CARTRIDGE_THECART_32M_DESC);
+ UI_MENU_ACTION(CARTRIDGE_THECART_64M, CARTRIDGE_THECART_64M_DESC);
+ UI_MENU_ACTION(CARTRIDGE_XEGS_8F_64, CARTRIDGE_XEGS_8F_64_DESC);
+}
+
+static int type = -1; /* -1 = guess */
+static int extracting = 0;
+static const char *outfile = NULL;
+static FILE *output;
+static const char *inputfiles[MAX_INPUT_FILES+1];
+static int inputcount = 0;
+static int checksum = 0;
+static int keep_outfile = 0;
+static unsigned char buf[CARTBUFLEN];
+
+void list_types() {
+ int i;
+ for(i = 1; i <= CARTRIDGE_LAST_SUPPORTED; i++) {
+ printf("%d %d %s\n", i, cart_types[i].size, cart_types[i].name);
+ }
+}
+
+void usage() {
+ puts("mkcart v20150421 - create atari800 CART image from raw binaries");
+ puts("\nUsage: mkcart -oCARTFILE -tTYPE RAWFILE [RAWFILE ...]");
+ puts( " mkcart -cCARTFILE");
+ puts( " mkcart -xRAWFILE CARTFILE");
+ puts( " mkcart -l");
+ printf("\n -tTYPE Cartridge type (1-%d), default = guess (poorly!)\n",
+ CARTRIDGE_LAST_SUPPORTED);
+ puts( " -oCARTFILE Create CARTFILE from RAWFILE(s)");
+ puts( " -cCARTFILE Check integrity of file (checksum and size)");
+ puts( " -xRAWFILE Create raw binary from CARTFILE (remove header)");
+ puts( " -l List all supported -t types and exit");
+ puts( " -h, -? This help message");
+}
+
+void open_output() {
+ if(!outfile) {
+ fprintf(stderr, "No output file given, use -o option\n");
+ exit(1);
+ }
+ if( !(output = fopen(outfile, "wb")) ) {
+ perror(outfile);
+ exit(1);
+ }
+}
+
+FILE *open_input(const char *fname) {
+ FILE *f;
+
+ f = fopen(fname, "rb");
+ if(!f) {
+ perror(fname);
+ exit(1);
+ }
+ return f;
+}
+
+int has_cart_header(const unsigned char *b) {
+ return ( (buf[0] == 'C') &&
+ (buf[1] == 'A') &&
+ (buf[2] == 'R') &&
+ (buf[3] == 'T') );
+}
+
+void write_header() {
+ int i, j, size = 0, checkhdr;
+ FILE *f;
+ size_t got;
+
+ for(i = 0; i < inputcount; i++) {
+ f = open_input(inputfiles[i]);
+
+ if(extracting) {
+ /* read and check header insead of writing one */
+ if(fread(buf, 1, 16, f) < 16) {
+ perror(inputfiles[i]);
+ exit(-1);
+ }
+ if(!has_cart_header(buf)) {
+ fprintf(stderr, "%s doesn't have a CART header\n", inputfiles[i]);
+ exit(-1);
+ }
+ return;
+ }
+
+ checkhdr = 1;
+
+ while( (got = fread(buf, 1, CARTBUFLEN, f)) > 0) {
+ if(checkhdr) { /* only do this on first chunk read */
+ if(has_cart_header(buf)) {
+ fprintf(stderr,
+ "warning: raw file %s appears to have a CART header\n",
+ inputfiles[i]);
+ }
+ checkhdr = 0;
+ }
+ if(got < CARTBUFLEN) {
+ fprintf(stderr, "warning: %s size not a multiple of %d bytes\n",
+ inputfiles[i], CARTBUFLEN);
+ }
+ for(j = 0; j < got; j++) checksum += buf[j];
+ size += got;
+ }
+ if(ferror(f)) {
+ perror(inputfiles[i]);
+ exit(1);
+ }
+ fclose(f);
+ }
+
+ if(type > 0 && size != cart_types[type].size) {
+ fprintf(stderr,
+ "warning: cart type %d (%s) must be %d bytes, "
+ "but we read %d from our input files\n",
+ type, cart_types[type].name, cart_types[type].size, size);
+ }
+
+ if(type < 1) {
+ for(i = 1; i <= CARTRIDGE_LAST_SUPPORTED; i++) {
+ if(size == (cart_types[i].size)) {
+ type = i;
+ fprintf(stderr, "warning: no -t option, guessing type %d (%s)\n",
+ i, cart_types[i].name);
+ break;
+ }
+ }
+ if(type < 1) {
+ fprintf(stderr,
+ "fatal: no -t option, no type matches file size %d bytes\n",
+ size);
+ exit(-1);
+ }
+ }
+
+ /* more like assembly than C, but it avoids endian issues */
+ buf[0] = 'C';
+ buf[1] = 'A';
+ buf[2] = 'R';
+ buf[3] = 'T';
+ buf[4] = buf[5] = buf[6] = 0;
+ buf[7] = type;
+ buf[8] = (checksum >> 24) & 0xff;
+ buf[9] = (checksum >> 16) & 0xff;
+ buf[10] = (checksum >> 8) & 0xff;
+ buf[11] = checksum & 0xff;
+ buf[12] = buf[13] = buf[14] = buf[15] = 0;
+
+ i = fwrite(buf, 1, 16, output);
+ if(i < 0) {
+ perror(outfile);
+ exit(-1);
+ } else if(i < 16) {
+ fprintf(stderr, "short write on %s\n", outfile);
+ exit(-1);
+ }
+ /* leave output open here */
+}
+
+void write_data() {
+ int i;
+ FILE *f;
+ size_t got;
+
+ for(i = 0; i < inputcount; i++) {
+ f = open_input(inputfiles[i]);
+ if(extracting) fread(buf, 1, 16, f); /* skip header */
+ while( (got = fread(buf, 1, CARTBUFLEN, f)) > 0) {
+ if( (fwrite(buf, 1, got, output)) < got ) {
+ perror(outfile);
+ exit(-1);
+ }
+ }
+ if(ferror(f)) {
+ perror(inputfiles[i]);
+ exit(1);
+ }
+ fclose(f);
+ }
+
+ /* if we made it here with no errors, the output file is good */
+ keep_outfile = 1;
+}
+
+void add_file(const char *filename) {
+ if(inputcount > MAX_INPUT_FILES) {
+ fprintf(stderr, "Too many input files (limit is %d, sorry)\n",
+ MAX_INPUT_FILES);
+ exit(1);
+ }
+ inputfiles[inputcount++] = filename;
+}
+
+int extract4(const unsigned char *b) {
+ return ( (b[0] << 24) |
+ (b[1] << 16) |
+ (b[2] << 8) |
+ (b[3] ) );
+}
+
+void check_file(const char *filename) {
+ int j, hdr_checksum, hdr_type, hdr_unused, ok = 1;
+ FILE *f;
+ int got, size, hdr_size;
+
+ f = open_input(filename);
+ got = fread(buf, 1, 16, f);
+ if(got < 0) {
+ perror(filename);
+ exit(1);
+ } else if(got < 16) {
+ fprintf(stderr, "%s is only %d bytes long, not a valid CART\n",
+ filename, (int)got);
+ exit(1);
+ }
+
+ if(!has_cart_header(buf)) {
+ fprintf(stderr, "%s missing CART header\n", filename);
+ exit(1);
+ }
+
+ printf("%s has CART header\n", filename);
+
+ hdr_type = extract4(buf + 4);
+ hdr_checksum = extract4(buf + 8);
+ hdr_unused = extract4(buf + 12);
+
+ if(hdr_type < 1 || hdr_type > CARTRIDGE_LAST_SUPPORTED) {
+ fprintf(stderr, "%s has invalid cart type %d (should be 1-%d)\n",
+ filename, hdr_type, CARTRIDGE_LAST_SUPPORTED);
+ exit(1);
+ }
+
+ printf("%s is type %d: %s (%d bytes)\n",
+ filename, hdr_type, cart_types[hdr_type].name, cart_types[hdr_type].size);
+
+ if(hdr_unused) {
+ fprintf(stderr, "warning: %s unused area in CART header is non-zero\n", filename);
+ }
+
+ hdr_size = CARTRIDGE_kb[hdr_type] * 1024;
+
+ while( (got = fread(buf, 1, CARTBUFLEN, f)) > 0) {
+ if(got < CARTBUFLEN) {
+ fprintf(stderr, "warning: %s data size not a multiple of %d bytes\n",
+ filename, CARTBUFLEN);
+ }
+ for(j = 0; j < got; j++) checksum += buf[j];
+ size += got;
+ }
+ if(ferror(f)) {
+ perror(filename);
+ exit(1);
+ }
+ fclose(f);
+
+ if(size != hdr_size) {
+ ok = 0;
+ fprintf(stderr,
+ "%s header says the data size should be %d bytes, but we read %d, ",
+ filename, hdr_size, size);
+ }
+
+ if(size > hdr_size) {
+ fprintf(stderr, "junk at the end? downloaded in ASCII mode?\n");
+ } else if(size < hdr_size) {
+ fprintf(stderr, "truncated?\n");
+ } else {
+ printf("%s has correct data size, %d bytes\n", filename, size);
+ }
+
+ if(hdr_checksum == checksum) {
+ printf("%s has valid checksum\n", filename);
+ } else {
+ ok = 0;
+ fprintf(stderr, "%s has BAD checksum\n", filename);
+ }
+
+ printf("%s results: %s\n", filename, (ok ? "OK" : "FAILED"));
+ exit(!ok);
+}
+
+void cleanup() {
+ if(outfile && !keep_outfile) unlink(outfile); /* ignore error here */
+}
+
+int main(int argc, char **argv) {
+ init();
+ atexit(cleanup);
+
+ if(argc < 2) {
+ usage();
+ exit(0);
+ }
+
+ while(++argv, --argc > 0) {
+ if(argv[0][0] == '-') {
+ switch(argv[0][1]) {
+ case 'l':
+ list_types();
+ exit(0);
+ break;
+
+ case 't':
+ type = atoi(&argv[0][2]);
+ if(type < 1 || type > CARTRIDGE_LAST_SUPPORTED) {
+ fprintf(stderr, "Invalid -t, use -t1 thru -t%d (not -t 1)\n\n",
+ CARTRIDGE_LAST_SUPPORTED);
+ usage();
+ exit(1);
+ }
+ break;
+
+ case 'o':
+ if(argv[0][2]) {
+ outfile = &argv[0][2];
+ } else {
+ fprintf(stderr, "Invalid -o, use -ofilename (not -o filename)\n\n");
+ exit(1);
+ }
+ break;
+
+ case 'x':
+ if(argv[0][2]) {
+ outfile = &argv[0][2];
+ extracting = 1;
+ } else {
+ fprintf(stderr, "Invalid -x, use -xfilename (not -x filename)\n\n");
+ exit(1);
+ }
+ break;
+
+ case 'c':
+ if(argv[0][2]) {
+ check_file(&argv[0][2]); /* exits */
+ } else {
+ fprintf(stderr, "Invalid -c, use -cfilename (not -c filename)\n\n");
+ exit(1);
+ }
+ break;
+
+ case 'h':
+ case '?':
+ usage();
+ exit(0);
+ break;
+
+ default:
+ fprintf(stderr, "Invalid option %s\n\n", *argv);
+ usage();
+ exit(1);
+ break;
+ }
+ } else { /* argv[0][0] != '-' */
+ add_file(*argv);
+ }
+ }
+
+ open_output();
+ write_header();
+ write_data();
+ exit(0);
+}