/*===========================================================================

  PROJECT	: JET-X CDMS
  PROGRAM	: CONVERT.C
  AUTHOR	: MARK COOKE
  COPYRIGHT : (C) Copyright 1996, Mark Cooke. All rights reserved.
  
  VERSION	: 1.2
  USAGE 	: CONVERT <INPUT.FILE> <BINOUTPUT.FILE> <HEXOUTPUT.FILE>

  FIXES
  -----

  22-Mar-96  Fix incorrect sequence at 0xFFF0.
  05-Apr-96  Remove Linefeed from output.
  09-Sep-97  Clean up and improve comments prior to general release.

  DESCRIPTION
  -----------
  
  This software is a revised version of the LST2BIN utility. It is written in
  a more structured manner, and the state machine has been bidden a fond (or
  maybe not so fond) farewell. Adding extra pattern matches to this code
  should be fairly straightforward.

  The output of this program is a binary image of the main 16K software rom.
  ===========================================================================*/

#define TARGET_WINDOWS 0 


#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

#if TARGET_WINDOWS
#include <io.h>
#endif

#include <fcntl.h>
#include <ctype.h>
#include <string.h>

char image[16*1024];


/* This procedure writes the 16K image array out as INTELHEX */
void writehex(char *name)
{
	char outb[60];
	long a,b,h,xsum;

	/* Try to create the output file. Error if it exists already */
	h = open(name, O_CREAT|O_EXCL|O_RDWR,S_IREAD|S_IWRITE);
	if (h == -1) {
		perror("Openning intelhex output file");
		return;
	}

	for (a = 0; a < 16*1024; a += 0x10) {

		/* Insert address and byte count into output buffer */
		sprintf(outb, ":10%.4X00",a+0xC000);

		/* Insert data bytes, and update checksum value */
		for (xsum = (((a+0xC000)>>8) & 0xFF) + (a & 0xFF),b=0; b<0x10; b++) {

			sprintf(&outb[b*2+9],"%.2X",(image[a+b] & 0xFF));
			xsum += image[a+b];
		
		}

		xsum = ((xsum & 0xFF) ^ 0xFF) + 1;

		/* Insert the checksum value */
		sprintf(&outb[41],"%.2X\n\0",(xsum & 0xFF));

		/* Write out completed line to output file */
		write(h, outb, 44);
	}

	/* Write out the end of file marker */
	write(h,":00000001FF\n\r\0",14);

	/* Close the output file */
	close(h);

	return;
}

int main(int argc, char **argv)
{
	char  buffer[2048];
	char  values[16][16];
	char *s;
	FILE *f_inp;
	int   f_out;
	long  size, n, addr, i, val;
	
	printf("CONVERT 1.1\n\n"
		   "Usage: Convert <LISTING> <OUTPUT.BIN> <OUTPUT.HEX>\n\n");

	if (argc != 4)
		exit(-1);

	/* Try to open the input file. Error if it can't be openned */
	f_inp = fopen(argv[1],"r");
	if (f_inp == NULL) {
		perror("Opening input file");
		exit(-1);
	}

	/* Try to create the output file. Error if it exists already */
	f_out = open(argv[2],O_WRONLY|O_CREAT|O_EXCL,0644);
	if (f_out == -1) {
		perror("Openning binary output file");
		fclose(f_inp);
		exit(-1);
	}

	/* Do the guts of the reading */
	while(fgets(buffer, sizeof(buffer), f_inp)) {

		/* Try to do the trivial cases first */
		if (buffer[0] != ' ')
			continue;

		s = strchr(buffer, '\t');
		if (s == NULL)
			continue;

		*s = ' ';
		s = strchr(s, '\t');
		if (s == NULL)
			continue;

		*s = '\0';

		if (strlen(buffer) < 16)
			continue;

		/* Look for non-numeric characters */
		for (i = 0; i < strlen(buffer); i ++) {

			if (!isxdigit(buffer[i]) && !isspace(buffer[i])) {
				if (buffer[i] != 'r')
					continue;
				else
					buffer[i] = ' ';
			}

		}

		/* try to pattern match */
		n = sscanf(buffer,"%s %s %s %s %s %s %s %s %s",
					&values[0][0], &values[1][0], &values[2][0],
					&values[3][0], &values[4][0], &values[5][0],
					&values[6][0], &values[7][0], &values[8][0]);

		if (n < 3)
			continue;

		if (sscanf(&values[1][0], "%lx", &addr) != 1)
			continue;

		if (addr < 0x0000C000)
			continue;

		if (addr >= 0x0000FFF0)
			fprintf(stderr,"WARNING: CODE MAY BE TOO LARGE.\n");

		addr = addr - 0x0000C000;

		for (i = 2; i < n; i ++) {

			sscanf(&values[i][0], "%lx", &val);
			if (strlen(&values[i][0]) == 4) {
				image[addr]   = val & 0xFF;
				image[addr+1] = val >> 8;
				addr += 2;
			}
			else {
				image[addr] = val;
				addr ++;
			}
		}
	}

	fclose(f_inp);

	/* Add on the tags for the reset vectors to the top of the ROM */
	image[0xFFF0 - 0xC000] = 0xEA;
	image[0xFFF1 - 0xC000] = 0x00;
	image[0xFFF2 - 0xC000] = 0xC0;
	image[0xFFF3 - 0xC000] = 0x00;
	image[0xFFF4 - 0xC000] = 0x00;

	/* Write out the 16K binary image file */
	size = write(f_out,image,16*1024);
	if (size < 0) {
		perror("Writing binary output image");
		close(f_out);
		exit(-1);
	}

	if (size != 16*1024) {
		fprintf(stderr,"Short write on binary output file\n");
		close(f_out);
		exit(-1);
	}

	close(f_out);

	/* Write out a hex file */
	writehex(argv[3]);

	printf("Conversion completed.\n\n");

	return 1;
}
