/* auxilliary file for cfile.c 	*/
/* sccs id	@(#)dfile.c	1.1 04/21/94		*/

/* this file contains stuff for generating an 'online subroutine' 
   which should be identical in operation to 'dcall' in sfile.s.
   This will be called 'ocall'. */ 

/* opcode defines */
#define HP800_LDO	0x0d
#define HP800_LDIL	0x08
#define HP800_BLE	0x39

/* some useful macros */
#define LOW_SIGN_EXT5(imm)                                              \
	((((imm) & 0xf) << 1) | (((imm) & 0x10) ? 1:0))

#define LOW_SIGN_EXT11(imm)                                             \
	((((imm) & 0x3ff) << 1) | (((imm) & 0x400) ? 1:0))

#define LOW_SIGN_EXT14(imm)                                             \
	((((imm) & 0x1fff) << 1) | (((imm) & 0x2000) ? 1:0))

#define ASSEMBLE_3(imm)                                                 \
	((((imm) & 0x4) ? 1:0) | (((imm) & 0x3) << 1))

#define ASSEMBLE_12(imm)                                                \
	((((imm) & 0x800) ? 1:0) | (((imm) & 0x400) ? 4:0) |            \
	(((imm) & 0x3ff) << 3))

#define ASSEMBLE_17(imm)                                                \
	((((imm) & 0x10000) ? 1:0) | (((imm) & 0xf800) << 5) |          \
	(((imm) & 0x400) ? 4:0) | (((imm) & 0x3ff) << 3))

#define ASSEMBLE_21(imm)                                                \
	((((imm) & 0x100000) ? 1:0) | (((imm) & 0xffe00) >> 8) |        \
	(((imm) & 0x180) << 7) | (((imm) & 0x7c) << 14) |               \
	(((imm) & 0x03) << 12))

#define hp800_imm14instr(opc, dst, src, imm14)                          \
	(((opc) << 26) | ((src) << 21) | ((dst) << 16) | LOW_SIGN_EXT14(imm14))

#define hp800_imm21instr(opc, dst, imm21)                               \
	(((opc) << 26) | ((dst) << 21) | ASSEMBLE_21(imm21))

#define hp800_branchimm17(opc, cond, src, imm, nul)                     \
	(((opc) << 26) | ((src) << 21) | ASSEMBLE_17(imm) |             \
	((nul) ? 2:0) | ((cond) << 13))

#define Hi21BitsOf(bigkonst)    (((long)(bigkonst)) >> 11)
#define Lo11BitsOf(bigkonst)    (((long)(bigkonst)) & 0x7ff)

#define OFFLINE_SPACE_ID	1

extern wrapc();

/* generate an online version of 'dcall' in malloc'd data space at opcodePtr.
   The function returns a pointer to the last instruction of the procodure. */
int *gen_ocall(int *opcodePtr)
{
	int *dest = (int *)wrapc;

	/* generate the online subroutine code. This should look like

		(6BC23FD9)      STW     %r2,-20(0,%r30)
		(37DE0080)  	LDO     64(%r30),%r30
				LDIL    L'wrapc,%r1
				BLE     R'wrapc,(%sr4,%r1)
		(081F0242)  	COPY    %r31,%r2
		(4BC23F59)  	LDW     -84(0,%r30),%r2
		(004010A1)  	LDSID   (0,2),1
		(00011820)  	MTSP    1,0
		(E0400000)  	BE      0(0,2)
		(37DE3F81)  	LDO     -64(%r30),%r30

	*/
	*opcodePtr++ = 0x6BC23FD9;
	*opcodePtr++ = 0x37DE0080;
	*opcodePtr++ = hp800_imm21instr(HP800_LDIL, 1, Hi21BitsOf(dest));
	*opcodePtr++ = hp800_branchimm17(HP800_BLE, OFFLINE_SPACE_ID, 1, Lo11BitsOf(dest)/4, 0);
	*opcodePtr++ = 0x081F0242;
	*opcodePtr++ = 0x4BC23F59;
	*opcodePtr++ = 0x004010A1;
	*opcodePtr++ = 0x00011820;
	*opcodePtr++ = 0xE0400000;
	*opcodePtr   = 0x37DE3F81;

	return opcodePtr;
}
