/*
 *  Copyright (C) 2004-2005  Anders Gavare.  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 *  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 *  SUCH DAMAGE.
 *
 *
 *  $Id: sgiprom_to_bin.c,v 1.5 2005/02/21 07:18:10 debug Exp $
 *
 *  sgiprom_to_bin.c
 *
 *  This program takes a textfile containing a SGI PROM memory dump of
 *  the following format:
 *
 *	>> dump -b 0xBFC00000:0xBFCF0000
 *	0xbfc00000:    b   f0    0   f0    0    0    0    0
 *	0xbfc00008:    b   f0    1   f6    0    0    0    0
 *	SAME
 *	0xbfc00200:    b   f0    3   c9    0    0    0    0
 *	0xbfc00208:    b   f0    1   f6    0    0    0    0
 *	SAME
 *	0xbfc00280:    b   f0    3   cb    0    0    0    0
 *	..
 *
 *  and turns it into a binary image.  Input is read from stdin.
 */

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define IP28

#ifdef IP26
 /* SGI Power Indigo2 (R8000) */
 #define BASE	(uint64_t)0x900000001fc00000
 #define BITS	64
#elif (defined IP28 || defined IP30)
 /* SGI Indigo2 R10000, Octane */
 #define BASE	(uint64_t)0xffffffffbfc00000
 #define BITS	64
#else 
 #define BASE	(uint64_t)0xbfc00000
 #define BITS	32
#endif


#define	MAX	200


int main(int argc, char *argv[])
{
	FILE *f;
	uint32_t previous_line[4];
	int same_flag = 0;
	off_t same_start_offset = 0;

	if (argc < 2) {
		fprintf(stderr, "usage: %s output_filename\n", argv[0]);
		fprintf(stderr, "input is read from stdin\n");
		exit(1);
	}

	f = fopen(argv[1], "w");

	while (!feof(stdin)) {
		char s[MAX];
		s[0] = 0;
		fgets(s, sizeof(s), stdin);

		while (s[0] == '\r') {
			memcpy(s, s+1, sizeof(s)-1);
			s[MAX-1] = '\0';
		}

		/*
		 * 32bits flavours:
		 *  >> dump -w -x 0xbfc00000:0xbfc80000
		 *  0xbfc00000:    bf000f0          0    bf001ef          0
		 *  ...
		 *
		 * 64bits flavours:
		 *  >> dump -w -x 0x900000001fc00000:0x900000001fd00000
		 *  0x900000001fc00000:   40a06800         40   40a06000         40
		 *  0x900000001fc00010:          0   10000012   3c0c9000          0
		 *  ...
		 */
#if (BITS == 64)
		if (s[0] == '0' && s[18]==':') {
#else
		if (s[0] == '0' && s[10]==':') {
#endif
			uint64_t x;
			int i;

			x = strtoull(s, NULL, 0);
			if (x < BASE) {
				printf("x = 0x%016llx, less than 0x%016llx. "
				    "aborting\n", x, BASE);
				exit(1);
			}
			x -= BASE;

			if (same_flag) {
				/*
				 *  We should fill from same_start_offset to
				 *  just before x, using previous_line data.
				 */
				off_t ofs;
				printf("same_flag set, filling until just before 0x%016llx\n", x);
				fseek(f, same_start_offset, SEEK_SET);
				for (ofs = same_start_offset; ofs < x; ofs += 4) {
					fwrite(previous_line, 1, sizeof(previous_line), f);
				}
				same_flag = 0;
			}

			printf("x = 0x%016llx\n", x);

			fseek(f, x, SEEK_SET);

			for (i=0; i<4; i++) {
				uint32_t w = 0;
#if (BITS == 64)
				char *ptr = s + 22;
#else
				char *ptr = s + 14;
#endif
				ptr += i * 11;
				ptr[8] = '\0';
				if (sscanf(ptr, "%x", &w) != 1)
					printf("no input\n");
				else
					fwrite(&w, 1, sizeof(w), f);
				previous_line[i] = w;
			}
			printf("\n");
		}

		/*  "SAME":  */
		if (s[0] == 'S' && s[1] == 'A') {
			/*
			 *  This should produce "same" output until the
			 *  next normal "0xbfc.." line.
			 */
			same_flag = 1;
			same_start_offset = ftell(f);
		}
	}

	fclose(f);

	return 0;
}

