/* ldaddr.c */

#include <stdio.h>
#include "corewar.h"

static unsigned  ldlen = -1;
static aval_t  *plist;

static unsigned  ld_conflict(aval_t addr1, aval_t addr2);


void  ld_init(unsigned maxloads)  {
	unsigned  i;

	if (ldlen != maxloads)  {
		if (ldlen != -1)
			free(plist);
		plist = (aval_t *)tmalloc(maxloads * sizeof(aval_t));
	}
	ldlen = maxloads;
	for (i = 0;  i < maxloads;  ++i)
		plist[i] = AVAL_NOGOOD;
}

	
aval_t  ld_addr(unsigned ldnum)  {
	aval_t  newaddr;
	unsigned  i, good_load;
	unsigned  andmask;

	if (plist[ldnum] != AVAL_NOGOOD)
		return(plist[ldnum]);
	for (andmask = 0;  (andmask & (coresize-1)) != (coresize-1);
	     andmask = ((andmask << 1) | 1));
	do  {
		good_load = TRUE;
		do  {  /* Get a perfectly even distribution of load addresses. */
			newaddr = ((unsigned)random() & andmask);
		} while (newaddr >= coresize);
		for (i = 0;  i < ldlen;  ++i)
			if (ld_conflict(newaddr, plist[i]))
				good_load = FALSE;
	} while (!good_load);
	plist[ldnum] = newaddr;
	return(newaddr);
}


static unsigned  ld_conflict(aval_t addr1, aval_t addr2)  {
	aval_t  temp;

	if ((addr1 == AVAL_NOGOOD) || (addr2 == AVAL_NOGOOD))
		return(FALSE);
	if (addr1 > addr2)  {
		temp = addr1;
		addr1 = addr2;
		addr2 = temp;
	}
	if (addr1 + maxprogsize > addr2)
		return(TRUE);
	if (addr1 + coresize < addr2 + maxprogsize)
		return(TRUE);
	return(FALSE);
}


aval_t  ld_undo(unsigned ldnum)  {
	aval_t  old_ldaddr;

	old_ldaddr = plist[ldnum];
	plist[ldnum] = AVAL_NOGOOD;
	return(old_ldaddr);
}
