From 1c7d0b339d578511be239c175ef2096e6e8aa6e2 Mon Sep 17 00:00:00 2001
From: Ian C <ianc@noddybox.co.uk>
Date: Sat, 21 Aug 2004 01:15:19 +0000
Subject: Added new files

---
 Makefile  |  36 ++++++++++---
 int2tap.1 |   9 +++-
 int2tap.c | 132 ++++++++++++++++++++++++++++++++++++++++++++--
 intel.c   | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 intel.h   |  54 +++++++++++++++++++
 tap.c     | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tap.h     |  50 ++++++++++++++++++
 7 files changed, 616 insertions(+), 14 deletions(-)
 create mode 100644 intel.c
 create mode 100644 intel.h
 create mode 100644 tap.c
 create mode 100644 tap.h

diff --git a/Makefile b/Makefile
index 8a02f77..d4b4cb3 100644
--- a/Makefile
+++ b/Makefile
@@ -18,21 +18,43 @@
 # 
 # -------------------------------------------------------------------------
 # 
-# $Id: Makefile,v 1.1.1.1 2004-08-20 01:14:42 ianc Exp $
+# $Id: Makefile,v 1.2 2004-08-21 01:15:19 ianc Exp $
 # 
 
 # CFLAGS assumes that gcc is being used - simply change as required
 #
-CFLAGS	=	-g -Wall -Werror $(DEBUG)
+CFLAGS	=	-g -Wall -Werror
 
 TARGET	=	int2tap
 
+SOURCE	=	int2tap.c	\
+		intel.c		\
+		tap.c
 
-$(TARGET): $(TARGET).c
-	$(CC) $(CFLAGS) -o $(TARGET) $(TARGET).c
+OBJECTS	=	int2tap.o	\
+		intel.o		\
+		tap.o
 
-$(TARGET).txt: $(TARGET).1
-	nroff -man $(TARGET).1 | sed 's/.//g' > $(TARGET).txt
+$(TARGET): $(OBJECTS)
+	$(CC) $(CFLAGS) -o $(TARGET) $(OBJECTS)
 
 clean:
-	rm -f $(TARGET) core
+	rm -f $(TARGET) $(OBJECTS) core
+
+depend:
+	make clean
+	makedepend  -- $(CFLAGS) $(DEBUG) -- $(SOURCE)
+	if test -e Makefile ; then rm -f Makefile.bak ; fi
+
+# DO NOT DELETE THIS LINE -- make depend depends on it
+
+int2tap.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+int2tap.o: /usr/include/machine/ansi.h /usr/include/stdio.h
+int2tap.o: /usr/include/string.h /usr/include/stdarg.h /usr/include/time.h
+int2tap.o: /usr/include/sys/_posix.h /usr/include/errno.h
+intel.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+intel.o: /usr/include/machine/ansi.h /usr/include/string.h
+intel.o: /usr/include/stdio.h intel.h
+tap.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+tap.o: /usr/include/machine/ansi.h /usr/include/string.h /usr/include/stdio.h
+tap.o: tap.h
diff --git a/int2tap.1 b/int2tap.1
index e8cb4a6..12953b3 100644
--- a/int2tap.1
+++ b/int2tap.1
@@ -1,4 +1,4 @@
-.TH int2tap 1 "20 August 2004"
+.TH int2tap 1
 .SH NAME
 hex2tap \- Converts an Intel format segment dump to a Spectrum emulator
 TAP file.
@@ -20,6 +20,12 @@ TAP file.
 takes one or more Intel format segment files \- as produced by an assembler like
 .B tpasm(1)
 \- and produces a Spectrum compatible tape file (TAP file).
+.P
+The tape file will also optionally include a BASIC loader (see OPTIONS).
+This loader will do a CLEAR to the execution address (see
+.B -a
+in OPTIONS), and then load in the binary files in the same order they were on
+the command line.
 .SH OPTIONS
 .B int2tap
 accepts these switches
@@ -29,7 +35,6 @@ Just produce the binary file.  By default
 .B int2tap
 will generate a TAP file with two files in - a BASIC loader and then the
 code itself.  This switch disables the generation of the BASIC loader portion.
-disabled if this switch is provided (see USAGE).
 .TP
 .B \-s
 By default
diff --git a/int2tap.c b/int2tap.c
index 68902a2..b2fba26 100644
--- a/int2tap.c
+++ b/int2tap.c
@@ -20,6 +20,8 @@
 
     -------------------------------------------------------------------------
 
+    $Name$
+
 */
 static const char id[]="$Id$";
 
@@ -30,8 +32,11 @@ static const char id[]="$Id$";
 #include <time.h>
 #include <errno.h>
 
+#include "intel.h"
+#include "tap.h"
+
 
-/* ---------------------------------------- MACROS
+/* ---------------------------------------- GLOBALS
 */
 #undef TRUE
 #undef FALSE
@@ -39,19 +44,136 @@ static const char id[]="$Id$";
 #define TRUE	1
 #define FALSE	0
 
-
-/* ---------------------------------------- TYPES
-*/
+const char	*progname;
 
 
-/* ---------------------------------------- PROTOS
+/* ---------------------------------------- PRIVATE UTILS
 */
+static void Usage(void)
+{
+    fprintf(stderr,"%s: usage %s [ -b ] [ -s ] [ -a address ] "
+    			"output-file input-file ... \n",progname,progname);
+}
 
 
 /* ---------------------------------------- MAIN
 */
 int main(int argc, char *argv[])
 {
+    unsigned char mem[0x10000];
+    IntelInfo *info;
+    char *outname;
+    unsigned exec_addr;
+    int bin_only;
+    int split;
+    int addr_defined;
+    int base;
+    int no;
+    int f;
+    int done;
+
+    /* Set program name
+    */
+    if ((progname=strrchr(argv[0],'/')))
+    {
+    	progname++;
+    }
+    else
+    {
+	progname=argv[0];
+    }
+
+    /* Set defaults and parse args
+    */
+    addr_defined=FALSE;
+    bin_only=FALSE;
+    split=FALSE;
+
+    done=FALSE;
+    f=1;
+
+    while(f<argc && !done)
+    {
+    	if (argv[f][0]!='-')
+	{
+	    base=f;
+	    done=TRUE;
+	}
+	else
+	{
+	    switch(argv[f][1])
+	    {
+	    	case 'b':
+		    bin_only=TRUE;
+		    break;
+
+	    	case 's':
+		    split=TRUE;
+		    break;
+
+	    	case 'a':
+		    if (f>argc-2)
+		    {
+		    	Usage();
+		    }
+
+		    addr_defined=TRUE;
+
+		    exec_addr=(unsigned)strtoul(argv[++f],NULL,0);
+
+		    break;
+
+	    	default:
+		    Usage();
+		    break;
+	    }
+
+	    f++;
+	}
+    }
+
+    if (base>=argc-1)
+    {
+    	Usage();
+    }
+
+    outname=argv[base++];
+
+    no=argc-base;
+
+    if (!(info=malloc(sizeof *info * no)))
+    {
+    	fprintf(stderr,"%s: malloc failed\n",progname);
+    }
+
+    /* Process Intel files
+    */
+    for(f=0;f<no;f++)
+    {
+    	if (!IntelLoad(argv[base+f],mem,info+f))
+	{
+	    free(info);
+	    exit(EXIT_FAILURE);
+	}
+
+	printf("Memory altered from 0x%4.4x for 0x%4.4x bytes, base 0x%4.4x\n",
+		    info[f].low,info[f].len,info[f].addr);
+    }
+
+    /* TODO: Properly - just a quick test
+    */
+    printf("Creating %s\n",outname);
+
+    if (!TapOpen(outname))
+    {
+	free(info);
+	exit(EXIT_FAILURE);
+    }
+
+    TapWrite(mem,info[0].low,info[0].len,TRUE);
+
+    TapClose();
+
     return EXIT_SUCCESS;
 }
 
diff --git a/intel.c b/intel.c
new file mode 100644
index 0000000..3c65adf
--- /dev/null
+++ b/intel.c
@@ -0,0 +1,178 @@
+/*
+
+    int2tap - Convert an Intel segment file to a loadable Spectrum tape file
+
+    Copyright (C) 2004  Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    -------------------------------------------------------------------------
+
+*/
+static const char id[]="$Id$";
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "intel.h"
+
+static const char header_id[]=I2T_INTEL_H;
+
+extern const char *progname;
+
+
+/* ---------------------------------------- CONSTANTS
+*/
+#undef TRUE
+#undef FALSE
+
+#define TRUE	1
+#define FALSE	0
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static const unsigned ToHex(char c)
+{
+    if (c>='0' && c<='9')
+    {
+	return c-'0';
+    }
+
+    if (c>='A' && c<='F')
+    {
+	return c-'A'+10;
+    }
+
+    if (c>='a' && c<='f')
+    {
+	return c-'a'+10;
+    }
+
+    return 0;
+}
+
+
+
+/* ---------------------------------------- INTERFACES
+*/
+int IntelLoad(const char *filename,
+	      unsigned char mem [0x1000],
+	      IntelInfo *info)
+{
+    FILE *fp;
+    char buff[1024];
+    int done;
+    int addr_read;
+    int ret;
+
+    if (!(fp=fopen(filename,"r")))
+    {
+    	fprintf(stderr,"%s: Failed to open %s\n",progname,filename);
+	return FALSE;
+    }
+
+    addr_read=FALSE;
+    info->low=0xffff;
+    info->high=0x0000;
+
+    done=FALSE;
+    ret=FALSE;
+
+    while(!done)
+    {
+	if (!fgets(buff,sizeof buff,fp))
+	{
+	    fprintf(stderr,"%s: Missing EOF record in %s\n",progname,filename);
+	    done=TRUE;
+	}
+
+	if (!done && buff[0]!=':')
+	{
+	    fprintf(stderr,"%s: Invalid Intel HEX file %s\n",progname,filename);
+	    done=TRUE;
+	}
+
+	if (!done && buff[8]=='1')
+	{
+	    done=TRUE;
+	    ret=TRUE;
+	}
+
+	if (!done && (buff[8]=='2' || buff[8]=='3'))
+	{
+	    fprintf(stderr,"%s: Extended address in Intel HEX file %s\n",
+	    				progname,filename);
+	    done=TRUE;
+	}
+
+	if (!done)
+	{
+	    unsigned addr;
+	    unsigned len;
+	    unsigned f;
+
+	    len=ToHex(buff[1])<<4|ToHex(buff[2]);
+
+	    addr=ToHex(buff[3])<<12|ToHex(buff[4])<<8|
+		 ToHex(buff[5])<<4|ToHex(buff[6]);
+
+	    if (!addr_read)
+	    {
+	    	info->addr=addr;
+	    	addr_read=TRUE;
+	    }
+
+	    for(f=0;f<len && !done;f++)
+	    {
+		unsigned char b;
+
+		if (addr<info->low)
+		{
+		    info->low=addr;
+		}
+
+		if (addr>info->high)
+		{
+		    info->high=addr;
+		}
+
+		b=ToHex(buff[f*2+9])<<4|ToHex(buff[f*2+10]);
+		mem[addr++]=b;
+
+		if (addr==0)
+		{
+		    fprintf(stderr,"%s: Intel HEX file %s has "
+		    			"wrapped from 0xffff to 0x0000\n",
+						progname,filename);
+		    done=TRUE;
+		}
+	    }
+	}
+    }
+
+    if (info->low!=0xffff)
+    {
+    	info->len=(info->high-info->low)+1;
+    }
+
+    fclose(fp);
+
+    return ret;
+}
+
+
+/* END OF FILE */
diff --git a/intel.h b/intel.h
new file mode 100644
index 0000000..b34ef37
--- /dev/null
+++ b/intel.h
@@ -0,0 +1,54 @@
+/*
+
+    int2tap - Convert an Intel segment file to a loadable Spectrum tape file
+
+    Copyright (C) 2004  Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    -------------------------------------------------------------------------
+
+    $Id$
+
+*/
+
+#ifndef I2T_INTEL_H
+#define I2T_INTEL_H "$Id$"
+
+/* ---------------------------------------- TYPES 
+*/
+typedef struct
+{
+    unsigned addr;
+    unsigned low;
+    unsigned high;
+    unsigned len;
+} IntelInfo;
+
+/* ---------------------------------------- INTERFACES
+*/
+
+/* Loads an Intel segment file.  Returns FALSE for failure.
+   If it works, info.addr is filled with the address of the first byte
+   written from the file and info.low and info.high hold the lowest and
+   highest address written to respectively.
+*/
+int	IntelLoad(const char *filename,
+		  unsigned char mem [0x1000],
+		  IntelInfo *info);
+
+#endif
+
+/* END OF FILE */
diff --git a/tap.c b/tap.c
new file mode 100644
index 0000000..0c9b3c7
--- /dev/null
+++ b/tap.c
@@ -0,0 +1,171 @@
+/*
+
+    int2tap - Convert an Intel segment file to a loadable Spectrum tape file
+
+    Copyright (C) 2004  Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    -------------------------------------------------------------------------
+
+*/
+static const char id[]="$Id$";
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "tap.h"
+
+static const char header_id[]=I2T_TAP_H;
+
+
+/* ---------------------------------------- CONSTANTS
+*/
+#undef TRUE
+#undef FALSE
+
+#define TRUE	1
+#define FALSE	0
+
+
+/* ---------------------------------------- TYPES
+*/
+
+
+/* ---------------------------------------- GLOBALS
+*/
+extern const char	*progname;
+
+static FILE		*fp;
+static int		file_no;
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+unsigned char TapWord(unsigned w, unsigned char chk)
+{
+    putc(w&0xff,fp);
+    chk^=w&0xff;
+    putc(w>>8,fp);
+    chk^=w>>8;
+    return chk;
+}
+
+unsigned char TapByte(unsigned char c, unsigned char chk)
+{
+    putc(c,fp);
+    chk^=c;
+    return chk;
+}
+
+unsigned char TapString(char *p, int len, unsigned char chk)
+{
+    while(len--)
+    {
+    	chk=TapByte(*p++,chk);
+    }
+
+    return chk;
+}
+
+unsigned char TapStream(const unsigned char p[0x10000],
+			unsigned addr, unsigned len, unsigned char chk)
+{
+    while(len--)
+    {
+    	chk=TapByte(p[addr],chk);
+	addr=(addr+1)&0xffff;
+    }
+
+    return chk;
+}
+
+/* ---------------------------------------- INTERFACES
+*/
+
+int TapOpen(const char *filename)
+{
+    file_no=0;
+
+    if (!(fp=fopen(filename,"wb")))
+    {
+    	fprintf(stderr,"%s: Failed to create %s\n",progname,filename);
+    }
+
+    return fp!=NULL;
+}
+
+
+void TapWrite(const unsigned char mem[0x1000],
+	      unsigned addr, unsigned len, int is_code)
+{
+    char name[11]={0};
+    unsigned char chk;
+
+    sprintf(name,"%10.10d",file_no);
+    file_no=(file_no+1)%10000;
+
+    /* Output file header
+    */
+    chk=TapWord(19,chk);
+    chk=TapByte(0,chk);
+
+    if (is_code)
+    {
+	chk=TapByte(3,chk);
+    }
+    else
+    {
+	chk=TapByte(3,chk);
+    }
+
+    chk=TapString(name,10,chk);
+    chk=TapWord(len,chk);
+
+    if (is_code)
+    {
+    	chk=TapWord(addr,chk);
+	chk=TapWord(32768,chk);
+    }
+    else
+    {
+    	chk=TapWord(0,chk);
+	chk=TapWord(0,chk);
+    }
+
+    TapByte(chk,0);
+
+    /* Output file data
+    */
+    chk=0;
+
+    chk=TapWord(len+2,chk);
+    chk=TapStream(mem,addr,len,chk);
+    TapByte(chk,0);
+}
+
+
+void TapClose(void)
+{
+    if (fp)
+    {
+    	fclose(fp);
+	fp=NULL;
+    }
+}
+
+
+/* END OF FILE */
diff --git a/tap.h b/tap.h
new file mode 100644
index 0000000..38be2c6
--- /dev/null
+++ b/tap.h
@@ -0,0 +1,50 @@
+/*
+
+    int2tap - Convert an Intel segment file to a loadable Spectrum tape file
+
+    Copyright (C) 2004  Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    -------------------------------------------------------------------------
+
+    $Id$
+
+*/
+
+#ifndef I2T_TAP_H
+#define I2T_TAP_H "$Id$"
+
+/* ---------------------------------------- INTERFACES
+*/
+
+/* Opens the TAP file for writing.  Returns FALSE on failure.
+*/
+int	TapOpen(const char *filename);
+
+/* Write a block of memory to the TAP file.
+*/
+void	TapWrite(const unsigned char mem[0x1000],
+		 unsigned addr,
+		 unsigned len,
+		 int is_code);
+
+/* Close the TAP file.
+*/
+void	TapClose(void);
+
+#endif
+
+/* END OF FILE */
-- 
cgit v1.2.3