/*
 * Z-80 assembler.
 * Output Intel compatable
 * hex files.
 */
#include	"as.h"

#define	NHEX	32			/* Longest record */

VALUE	hexla;
VALUE	hexpc;
char	hexb[NHEX];
char	*hexp	= &hexb[0];

/*
 * Output a word. Use the
 * standard Z-80 ordering (low
 * byte then high byte).
 */
outaw(w)
{
	outab(w);
	outab(w >> 8);
}

/*
 * Output an absolute
 * byte to the code and listing
 * streams.
 */
outab(b)
{
	if (pass != 0) {
		if (cp < &cb[NCODE])
			*cp++ = b;
		outbyte(b);
	}
	++dot;
}

/*
 * Put out the end of file
 * hex item at the very end of 
 * the object file.
 */
outeof()
{
	outflush();
	fprintf(ofp, ":00000001FF\n");
}

/*
 * Output a hex byte. Flush
 * the buffer if no room. Store the
 * byte in the buffer, for future
 * checksumming. Remember the load
 * address for flushing.
 */
outbyte(b)
{
	if (hexp>=&hexb[NHEX] || hexpc!=dot) {
		outflush();
		hexp = &hexb[0];
	}
	if (hexp == &hexb[0]) {
		hexla = dot;
		hexpc = dot;
	}
	*hexp++ = b;
	++hexpc;
}

/*
 * Flush out a block of
 * code to the hex file. Figure
 * out the length word and the
 * checksum byte.
 */
outflush()
{
	register char	*p;
	register int	b;
	register int	c;

	if ((b = hexp-&hexb[0]) != 0) {
		putc(':', ofp);
		outhex(b);
		outhex(hexla >> 8);
		outhex(hexla);
		outhex(0);
		c = b + (hexla>>8) + hexla;
		p = &hexb[0];
		while (p < hexp) {
			b = *p++;
			outhex(b);
			c += b;
		}
		outhex(-c);
		putc('\n', ofp);
	}
}

/*
 * Put out "b", as a 
 * two character hex value.
 * We cannot use printf because
 * of case problems on VMS.
 * Upper case ascii.
 */
outhex(b)
{
	static	char	hex[] = {
		'0',	'1',	'2',	'3',
		'4',	'5',	'6',	'7',
		'8',	'9',	'A',	'B',
		'C',	'D',	'E',	'F'
	};

	putc(hex[(b>>4)&0x0F], ofp);
	putc(hex[b&0x0F], ofp);
}
