/*
 * Copyright (c) 2002, The Tendra Project <http://www.ten15.org/>
 * 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 unmodified, 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
 *
 *
 *    		 Crown Copyright (c) 1997
 *
 *    This TenDRA(r) Computer Program is subject to Copyright
 *    owned by the United Kingdom Secretary of State for Defence
 *    acting through the Defence Evaluation and Research Agency
 *    (DERA).  It is made available to Recipients with a
 *    royalty-free licence for its use, reproduction, transfer
 *    to other parties and amendment for any purpose not excluding
 *    product development provided that any such use et cetera
 *    shall be deemed to be acceptance of the following conditions:-
 *
 *        (1) Its Recipients shall ensure that this Notice is
 *        reproduced upon any copies or amended versions of it;
 *
 *        (2) Any amended version of it shall be clearly marked to
 *        show both the nature of and the organisation responsible
 *        for the relevant amendment or amendments;
 *
 *        (3) Its onward transfer from a recipient to another
 *        party shall be deemed to be that party's acceptance of
 *        these conditions;
 *
 *        (4) DERA gives no warranty or assurance as to its
 *        quality or suitability for any purpose and DERA accepts
 *        no liability whatsoever in relation to any use to which
 *        it may be put.
 *
 * $TenDRA: tendra/src/installers/mips/common/getregs.c,v 1.6 2004/06/28 03:31:05 bp Exp $
 */


/******************************************************************
 *		getregs.c
 *
 *	Routines for choosing temporary registers. The next free
 *register is chosen cyclically from the registers 8-15, 24 and 25 for
 *fixed point and 4-10 and 16-18 in floating point (a factor of 2 is involved here) by examining the bit pattern of the parameter. If the current proc allows it, regs 4-7 may also be used as t-regs - this is the function of chooseafter25 etc. The parameter is usuallytaken from a value of type
 * space (which has bits for fixed and floating regs).
 *A clear bit indicates that the corresponding register is free for use.

******************************************************************/
#include "config.h"
#include "common_types.h"
#include "procrectypes.h"
#include "exptypes.h"
#include "expmacs.h"
#include "exp.h"
#include "regexps.h"
#include "tags.h"
#include "expmacs.h"
#include "bitsmacs.h"
#include "flags.h"
#include "getregs.h"
#include "basicread.h"

extern  procrec * procrecs;
static long useable_fixed;
static long useable_float;

#define for8  0x100		/* bit pattern for $8,  bit 9 is set */
#define for15    0x8000		/* bit pattern for $15, bit 16 is set */
#define for24 0x1000000		/* etc ... */
#define for25 0x2000000

#define for0  0x1
#define for4  0x10
#define for5  0x20
#define for9  0x200


long  choosefix = for8;		/* first fixed reg to be allocated */
long  choosefloat = for0;	/* first float reg to be allocated */

int   currentfix = 8;
int   currentfloat = 2;
static int   maxfixed;
static int   maxfloat = 9;
static int minfixed;
static long formin;


void
settempregs(exp tg)
{
	/* tg is a proc; sets up useable_fixed etc
	 *				   depending on how the proc treats its
	 *				   parameters; if they are destined for
	 *				   store or s-registers we can use some of
	 *				    regs 4-7 */
	procrec * pr = &procrecs[no(tg)];
	bool leaf = ((pr->needsproc).propsneeds & anyproccall)==0;
	exp stg = son(tg);
	currentfix = 8;
	currentfloat = 0;
	choosefix = for8;
	choosefloat = for0;
	useable_fixed = 0x8300fffc;
	/* r31 (lnk) /r24-25/ r8-r15/ r4-r7 (pars) /r2-r3*/
	useable_float = 0x3ff;	/* f0-f2 (resreg) f4-f10 f12-f14 (pars)
							 *  					f16-f18*/
	if (leaf) {
		useable_fixed &= ~0x80000000;
		maxfixed = 25;
	}
	else maxfixed = 31;
	
	if (PIC_code) {
		useable_fixed &= ~0x02000000;
		if (maxfixed==25) maxfixed = 24;
	}
	
	if (((pr->needsproc).propsneeds & uses2_bit) != 0) {
		useable_fixed &= ~0x4;
		minfixed = 3;
		formin = 0x8;
	}
	else {
		minfixed = 2;
		formin = 0x4;
	}
	
	while (name(stg)==ident_tag && isparam(stg)) {
		if ((props(stg) & inreg_bits) !=0) {
			useable_fixed &= ~ (1<<no(stg));
		}
		else
			if ((props(stg) & infreg_bits) != 0) {
				useable_float &= ~(1<<no(stg));
			}
		stg = bro(son(stg));
	}
	
}

int
getreg(long fixed)
{	/* get a free temporary fixed pt reg */
	int   reg = -1;
	long  start = choosefix;
	
	
	for (;;) {
		if ((choosefix & fixed) == 0) {
			reg = currentfix;
		}
	  cycle:
		if (currentfix >= maxfixed) {
			currentfix = minfixed;
			choosefix = formin;
		}
		else {
			currentfix +=1;
			choosefix <<= 1;
		}
		
		if ((choosefix & useable_fixed) != 0) {
			if (reg >=0) break;
			else continue;
		}
		if (choosefix == start) {
			failer("Too many fixed regs required");
    		break;
		}
		goto cycle;
	}
	return reg;
}


int
getfreg(long fl)
{	/* get a free temporary floating reg */
	int   reg = -1;
	long  start = choosefloat;
	
	for (;;) {
		if ((choosefloat & fl) == 0) {
			reg = currentfloat;
		}
	  cycle:
		if (currentfloat >= maxfloat) {
			currentfloat = 0;
			choosefloat = for0;
		}
		else {
			currentfloat +=1;
			choosefloat <<= 1;
		}
		
		if ((choosefloat & useable_float) != 0) {
			if (reg >=0) break;
			else continue;
		}
		if (choosefloat == start) {
			failer("Too many float regs required");
    		break;
		}
		goto cycle;
	}
	return reg;
}
