/* -*- Package: CMFS-I; Base: 10; Mode: C; -*- */
/*****************************************************************************
* 	  Copyright (c) 1988 Thinking Machines Corporation, Inc.,	     *
*		of Cambridge, Mass.   All rights reserved.		     *
*									     *
*  This notice is intended as a precaution against inadvertent publication   *
*  and does not constitute an admission or acknowledgement that publication  *
*  has occurred or constitute a waiver of confidentiality.		     *
*									     *
*  Connection Machine software is the proprietary and confidential property  *
*  of Thinking Machines Corporation.					     *
*****************************************************************************/

#ifndef lint
static char rcsid[] =
"$Header: /tmp_mnt/am/cm1/cm/src/io/examples/maxvideo/RCS/CM_transpose.c,v 1.1 89/12/07 16:17:39 nesheim Rel-5-2 $";
#endif

#include <stdio.h>
#if defined(symbolics)
#include <stdlib.h>
#endif

#include <cm/paris.h>
#include <cm/cm_file.h>
#include <cm/cm_param.h>

#define BITS_OF_PROCESSOR_ADDRESS	4	/* 16 processors per chip */
#define WEDGE_ADDRESS_LENGTH		12	/* 4096 processors */
#define BYTE_SWAPPING_BIT		3	/* 8 bits per byte */
#define WORD_SWAPPING_BIT		4	/* 16 bits per word */
#define TRANSPOSER_SIZE			32	/* number of bits per transposer */
#define LENGTH_OF_TRANSPOSER_SIZE	5	/* log2 (TRANSPOSER_SIZE) */
#define MAX_IO_WIDTH			256	/* Maximum size accepted by transposition */

/*
 *	This code transposes a series of values each of size bits 
 *	The two dimensions of the matrix are memory address and processor number
 *	at each of log n stages we transpose the lower memory quadrant, higher processor 
 *	number bits with the higher memory quadrant, lower processor ones (result is in-place)
 *	we need space equal to destination cube address plus size 
 *	requires size to be a power of two
 *	transposition_type is a flag which if set means that the data is to be transposed
 *	in a scheme related to the way I/O is done
 */
#if defined(lucid)
extern void CMFS_lisp_address_conversion();
static void (*address_conversion)() = CMFS_lisp_address_conversion;

int
CMFS_transpose_always(loc, size, transposition_type)
CM_memaddr_t loc;
unsigned size;
int transposition_type;
#else
int
CMFS_transpose_always(loc, size, transposition_type, address_conversion)
CM_memaddr_t loc;
unsigned size;
int transposition_type;
void (*address_conversion)();
#endif
{
#ifdef NOTDEF
	int len; 			 /* number of bits per transfer */
	int offset; 			 /* start position of bit */
        CM_memaddr_t higher_memory_quad; /* address of lower memory edge of higher memory quadrant */
        CM_memaddr_t lower_memory_quad;	 /* address of lower memory edge of lower memory quadrant */
	int length_iteration;	 	 /* which iteration of length - controls computation of 
					  * partners processor address
					  */
#endif
        CM_memaddr_t dest_proc_addr; 	 /* holds dest cube addr */
        CM_memaddr_t temp_memory;	 /* space equal to size */
	CM_memaddr_t old_context_flag;   /* location of stored context flag */
	extern int CMI_old_dvi_boards;
	
	dest_proc_addr = CM_allocate_stack_field(CM_cube_address_length + size + 1);
	temp_memory = CM_add_offset_to_field_id(dest_proc_addr, CM_cube_address_length);
	old_context_flag = CM_add_offset_to_field_id(dest_proc_addr, CM_cube_address_length + size);

	/* Save old context and turn on all processors */
	CM_move_always(old_context_flag, CM_context_flag, 1);
	CM_move_constant_always(CM_context_flag, 1L, 1);
	CM_my_cube_address(dest_proc_addr);

	if (CMI_count_bits((unsigned long)size) < 0) {
		fprintf(stderr, "Size of %d is not a power of 2\n", size);
		return(-1);
	}

	switch (transposition_type) {
		case CMFS_NORMAL:
			break;

		case CMFS_IO_READ_FROM_SERIAL_DATA:
			if (CMI_old_dvi_boards)	{
				CMI_io_swap_words_address_change(dest_proc_addr);
				CMI_io_swap_bytes_address_change(dest_proc_addr);
			}

			CMI_io_format_to_transpose_address_change(dest_proc_addr);
			/* send the data to the correct processor */
			CM_send_1L(temp_memory, dest_proc_addr, loc, size, CM_no_field);
			CM_move(loc, temp_memory, size);
			break;
 
		case CMFS_IO_WRITE_TO_SERIAL_DATA:
			/*
			 * First let the user munge the address and then finish it off to 
			 * match the hardware
			 */
			if (address_conversion != NULL)	{
				/* user supplied a routine */
				address_conversion(dest_proc_addr);
			}

			CMI_internal_to_transpose_address_change(dest_proc_addr, size);

			/* send the data to the correct processor */
			CM_send_1L(temp_memory, dest_proc_addr, loc, size, CM_no_field);
			CM_move(loc, temp_memory, size);
			break;

		default:
			fprintf(stderr, "Unknown transposition type = %d\n", transposition_type);
			return(-1);
	}
 
	CM_my_cube_address(dest_proc_addr);

	if (size == 32)	{
	    extern int HACK;
	    if (HACK) {
		register int i;
		for (i = 0; i < 4; i++)
		    CMI_transpose_smaller(dest_proc_addr, 
					  loc + (i*8),
					  8);
	    } else {
	    /* Use the sprint chip hardware */
	    _CMI_transpose_data_in_memory_ta(loc, loc);
	}
	}  else	if (size < TRANSPOSER_SIZE)	{
		CMI_transpose_smaller(dest_proc_addr, loc, size);
	}  else	if (size > TRANSPOSER_SIZE && size <= MAX_IO_WIDTH)	{
		CMI_transpose_larger(dest_proc_addr, loc, size, temp_memory);
	}  else	 {
		fprintf(stderr, "Illegal transposition size - requested %d while maximum is %d\n",
			size, MAX_IO_WIDTH);
	}
#ifdef NOTDEF
		{
            /* len is the size of the quadrant goes up in powers of two */
	    for (len = 1, length_iteration = 0;  len < size;   len *= 2, length_iteration++) {
		/* offset goes over the position of each block of 4 quadrants */
		/* relative to the memory location of the data */
		for (offset = 0;  offset < size;  offset += 2*len)	{
			/*	At each step exchange X and Y where they are of length len
			 *	and len processors away.
			 */
			/*     Processors ---->
			/*  M   |----|----|            */
                        /*  E   |----|--Y-|            */
                        /*  M   |----|----|            */
                        /*  O   |----|----|            */
			/*  R - =========== -          */
                        /*  Y   |----|----|            */
                        /*      |----|----|            */
                        /*  |   |-X--|----|            */
			/*  | - |----|----|            */
                        /*  v                          */
                        /*                             */
                        /*                             */
			lower_memory_quad = loc + offset;
                        higher_memory_quad = lower_memory_quad + len;
			
			/* select lower processors - dest_proc_addr has my_cube_address */
			CMI_select_lower_processor(dest_proc_addr, length_iteration);

			/* swap higher and lower memory in lower processor */
			CMI_swap_memory(lower_memory_quad, higher_memory_quad, temp_memory, len);

                        /* point to processor partner with which you will exchange */
			CMI_compute_partner_address(dest_proc_addr, length_iteration);

			/* have all processors send to temp_memory on their partners */
			CM_move_constant_always(CM_context_flag, 1, 1);
			CM_send_1L(temp_memory, dest_proc_addr, lower_memory_quad, len, CM_no_field);

			/* restore the address for the next iteration - assumes computation is reversible */
			CMI_compute_partner_address(dest_proc_addr, length_iteration);

			/* have all processors move the received data to lower_memory_quad */
			CM_move_always(lower_memory_quad, temp_memory, len);

			/* select lower processors - dest_proc_addr has my_cube_address */
			CMI_select_lower_processor(dest_proc_addr, length_iteration);

			/* swap higher and lower memory in lower processor */
			CMI_swap_memory(lower_memory_quad, higher_memory_quad, temp_memory, len);
		}
	    }
	}
#endif /* NOTDEF */

	CM_move_constant_always(CM_context_flag, 1L, 1);
	CM_my_cube_address(dest_proc_addr);

	switch (transposition_type) {
	    extern int HACK;

		case CMFS_NORMAL:
			break;

		case CMFS_IO_READ_FROM_SERIAL_DATA:
			if (HACK && (size == 32)) 
			    CMI_internal_from_transpose_address_change(dest_proc_addr, 8);
			else
			    CMI_internal_from_transpose_address_change(dest_proc_addr, size);

			if (address_conversion != NULL)	{
				/* user supplied a routine */
				address_conversion(dest_proc_addr);
			}

			/* send the data to the correct processor */
			CM_send_1L(temp_memory, dest_proc_addr, loc, size, CM_no_field);
			CM_move(loc, temp_memory, size);
			break;
 
		case CMFS_IO_WRITE_TO_SERIAL_DATA:
			CMI_io_format_from_transpose_address_change(dest_proc_addr);

			if (CMI_old_dvi_boards)	{
				CMI_io_swap_bytes_address_change(dest_proc_addr);
				CMI_io_swap_words_address_change(dest_proc_addr);
			}

			/* send the data to the correct processor */
			CM_send_1L(temp_memory, dest_proc_addr, loc, size, CM_no_field);
			CM_move(loc, temp_memory, size);
			break;

		default:
			fprintf(stderr, "Unknown transposition type = %d\n", transposition_type);
			return(-1);
	}
 
	/* Restore old context and stack pointers */
	CM_move_always(CM_context_flag, old_context_flag, 1);
        CM_deallocate_stack_through(dest_proc_addr);
	return(0);
}


CMI_swap_memory(destination1, destination2, temporary_space, len)
CM_memaddr_t destination1;
CM_memaddr_t destination2;
CM_memaddr_t temporary_space;		/* Must be at least of length len */
unsigned len;
{
	CM_move(temporary_space, destination1, len);
	CM_move(destination1, destination2, len);
	CM_move(destination2, temporary_space, len);
}


CMI_select_lower_processor(cube_address, count)
CM_cubeaddr_t cube_address;
int count;
{
	CM_lognot_always(CM_context_flag, cube_address + CM_purely_virtual_cube_address_length + count, 1);
}



CMI_compute_partner_address(cube_address, count)
CM_cubeaddr_t cube_address;
int count;
{
	CM_lognot_always(cube_address + CM_purely_virtual_cube_address_length + count,
			 cube_address + CM_purely_virtual_cube_address_length + count, 1);
}
 



CMI_io_format_to_transpose_address_change(dest_proc_addr)
CM_memaddr_t dest_proc_addr; 	 /* holds dest cube addr */
{
	int bits_to_shift;		 /* the number of bits of address to shift */
	CM_memaddr_t temp_memory;	 /* holds a scratch copy of part of the cube address */

	/* Send the data to appropriate processors so a simple transposition can occur */
	/* Have  :
	 *	____________________________________________________
	 *	| board - 3 | chip - 5 | processor - 4 | memory - 5|
	 *	____________________________________________________
	 * Want  :
	 *	____________________________________________________
	 *	| Processor - 4 | Board - 3 | Chip - 5 | memory - 5|
	 *	____________________________________________________
	 */

	temp_memory = CM_allocate_stack_field(BITS_OF_PROCESSOR_ADDRESS);

	/* Swap the address bits around to compute the address to send to */
	/* you only care about the physical processor numbers not the virtual part */
	dest_proc_addr += CM_purely_virtual_cube_address_length;

	/* keep bits within the wedge */
	bits_to_shift = (CM_cube_address_length < WEDGE_ADDRESS_LENGTH) ?
			 CM_cube_address_length - BITS_OF_PROCESSOR_ADDRESS :
			 WEDGE_ADDRESS_LENGTH - BITS_OF_PROCESSOR_ADDRESS;
	CM_move(temp_memory, dest_proc_addr, BITS_OF_PROCESSOR_ADDRESS);
	CM_move(dest_proc_addr, dest_proc_addr + BITS_OF_PROCESSOR_ADDRESS, bits_to_shift);
	CM_move(dest_proc_addr + bits_to_shift, temp_memory, BITS_OF_PROCESSOR_ADDRESS);
	CM_deallocate_stack_through(temp_memory);
}
 


CMI_io_format_from_transpose_address_change(dest_proc_addr)
CM_memaddr_t dest_proc_addr; 	 /* holds dest cube addr */
{
	int bits_to_shift;		 /* the number of bits of address to shift */
	CM_memaddr_t temp_memory;	 /* holds a scratch copy of part of the cube address */

	/* Send the data from appropriate processors so a simple transposition can occur */
	/* Have  :
	 *	____________________________________________________
	 *	| Processor - 4 | Board - 3 | chip - 5 | memory - 5|
	 *	____________________________________________________
	 * Want  :
	 *	____________________________________________________
	 *	| board - 3 | chip - 5 | processor - 4 | memory - 5|
	 *	____________________________________________________
	 */

	temp_memory = CM_allocate_stack_field(BITS_OF_PROCESSOR_ADDRESS);

	/* Swap the address bits around to compute the address to send to */
	/* you only care about the physical processor numbers not the virtual part */
	dest_proc_addr += CM_purely_virtual_cube_address_length;

	/* keep bits within the wedge */
	bits_to_shift = (CM_cube_address_length < WEDGE_ADDRESS_LENGTH) ?
			 CM_cube_address_length - BITS_OF_PROCESSOR_ADDRESS :
			 WEDGE_ADDRESS_LENGTH - BITS_OF_PROCESSOR_ADDRESS;
	CM_move(temp_memory, dest_proc_addr + bits_to_shift, BITS_OF_PROCESSOR_ADDRESS);
	CM_move(dest_proc_addr + BITS_OF_PROCESSOR_ADDRESS, dest_proc_addr, bits_to_shift);
	CM_move(dest_proc_addr, temp_memory, BITS_OF_PROCESSOR_ADDRESS);
	CM_deallocate_stack_through(temp_memory);
}
 




CMI_internal_from_transpose_address_change(dest_proc_addr, size)
CM_memaddr_t dest_proc_addr; 	 /* holds dest cube addr */
unsigned size;			 /* size of data item */
{
	int bits_to_shift;		 /* the number of bits of address to shift */
	unsigned bits_of_address; 	 /* number of bits in size */
	CM_memaddr_t temp_memory;	 /* holds a scratch copy of part of the cube address */

	/* Send the data back to its real destination processor */
	/* Have :
	 *	____________________________________________________
	 *	| processor - 4 | board - 3 | memory - 5 | chip - 5|
	 *	____________________________________________________
	 * Want  :
	 *	____________________________________________________
	 *	| memory - 5 | processor - 4 | board - 3 | chip - 5|
	 *	____________________________________________________
	 */

	bits_of_address = CMI_count_bits((unsigned long)size) +
	    CM_purely_virtual_cube_address_length;

	temp_memory = CM_allocate_stack_field(bits_of_address);

	/* Swap the address bits around to compute the address to send to */
	/* you do care about the virtual processor numbers */
	bits_to_shift = CM_cube_address_length - bits_of_address;
	CM_move(temp_memory, dest_proc_addr, bits_of_address);
	CM_move(dest_proc_addr, dest_proc_addr + bits_of_address, (unsigned)bits_to_shift);
	CM_move(dest_proc_addr + bits_to_shift, temp_memory, bits_of_address);
	CM_deallocate_stack_through(temp_memory);
}
 

CMI_internal_to_transpose_address_change(dest_proc_addr, size)
CM_memaddr_t dest_proc_addr; 	 /* holds dest cube addr */
unsigned size;			 /* size of data item */
{
	int bits_to_shift;		 /* the number of bits of address to shift */
	unsigned bits_of_address;	 /* number of bits in size */
	CM_memaddr_t temp_memory;	 /* holds a scratch copy of part of the cube address */

	/* Have  :
	 *	____________________________________________________
	 *	| memory - 5 | processor - 4 | board - 3 | chip - 5|
	 *	____________________________________________________
	 * Want (Have) :
	 *	____________________________________________________
	 *	| processor - 4 | board - 3 | memory - 5 | chip - 5|
	 *	____________________________________________________
	 */

	bits_of_address = CMI_count_bits((unsigned long)size) +
	    CM_purely_virtual_cube_address_length;

	temp_memory = CM_allocate_stack_field(bits_of_address);

	/* Swap the address bits around to compute the address to send to */
	/* you do care about the virtual processor numbers */
	bits_to_shift = CM_cube_address_length - bits_of_address;
	CM_move(temp_memory, dest_proc_addr + bits_to_shift, bits_of_address);
	CM_move(dest_proc_addr + bits_of_address, dest_proc_addr, (unsigned)bits_to_shift);
	CM_move(dest_proc_addr, temp_memory, bits_of_address);
	CM_deallocate_stack_through(temp_memory);
}
 

CMI_io_swap_bytes_address_change(dest_proc_addr)
CM_memaddr_t dest_proc_addr; 	 /* holds dest cube addr */
{
	/* Bytes 1 and 2 of each 32 bit quantity are swapped by the datavault hardware */

	/* you only care about the physical processor numbers not the virtual part */
	dest_proc_addr += CM_purely_virtual_cube_address_length;

	/* Select those processors fed by bytes 1 or 2 of the data transfers */
	CM_ne(dest_proc_addr + BITS_OF_PROCESSOR_ADDRESS + BYTE_SWAPPING_BIT,
	      dest_proc_addr + BITS_OF_PROCESSOR_ADDRESS + BYTE_SWAPPING_BIT + 1, 1);
	CM_move_always(CM_context_flag, CM_test_flag, 1);

	/* make each processor point to the correct one */
	CM_lognot(dest_proc_addr + BITS_OF_PROCESSOR_ADDRESS + BYTE_SWAPPING_BIT,
	          dest_proc_addr + BITS_OF_PROCESSOR_ADDRESS + BYTE_SWAPPING_BIT, 2);

	CM_move_constant_always(CM_context_flag, 1L, 1);
}
 



CMI_io_swap_words_address_change(dest_proc_addr)
CM_memaddr_t dest_proc_addr; 	 /* holds dest cube addr */
{
	/* Words (16 bits) 0 and 1 of each 32 bit quantity are swapped by the datavault hardware */

	/* you only care about the physical processor numbers not the virtual part */
	dest_proc_addr += CM_purely_virtual_cube_address_length;

	/* make each processor point to the correct one */
	CM_lognot(dest_proc_addr + BITS_OF_PROCESSOR_ADDRESS + WORD_SWAPPING_BIT,
	          dest_proc_addr + BITS_OF_PROCESSOR_ADDRESS + WORD_SWAPPING_BIT, 1);
}
 

CMI_transpose_smaller(dest_proc_addr, loc, size)
CM_memaddr_t dest_proc_addr; 
CM_memaddr_t loc;
unsigned size;
{
	/* stagger the data so we can use the sprint chip */
	CM_memaddr_t scratch_space;	/* memory to hold TRANSPOSER_SIZE data */
	int offset;			/* current offset within scratch_space */

	scratch_space = CM_allocate_stack_field(TRANSPOSER_SIZE);
	CM_move_always(scratch_space, loc, size);

	/* stagger the data every size bits so all processors will get data */
	for (offset = size;  offset < TRANSPOSER_SIZE;  offset += size)	{
		CM_u_ge_constant(dest_proc_addr + CM_purely_virtual_cube_address_length, 
				 (long)offset, LENGTH_OF_TRANSPOSER_SIZE);
		CM_move(CM_context_flag, CM_test_flag, 1);
		CM_move(scratch_space + offset, scratch_space + offset - size, size);
	}
	
    	_CMI_transpose_data_in_memory_ta(scratch_space, scratch_space);

	/* put the data back to its original memory address */
	for (offset = TRANSPOSER_SIZE - size;  offset > 0;  offset -= size)	{
		CM_move_constant_always(CM_context_flag, 1L, 1);
		CM_u_ge_constant(dest_proc_addr + CM_purely_virtual_cube_address_length, 
				 (long)offset, LENGTH_OF_TRANSPOSER_SIZE);
		CM_move(CM_context_flag, CM_test_flag, 1);
		CM_move(scratch_space + offset - size, scratch_space + offset, size);
	}

	CM_move_always(loc, scratch_space, size);
	CM_deallocate_stack_through(scratch_space);
}



/*
 * We must transpose data which has 1 bit per physical processor across size processors of
 * the machine into size bits per physical processor at memory location loc
 * size is greater than TRANSPOSER_SIZE
 */
CMI_transpose_larger(dest_proc_addr, loc, size, scratch_memory)
CM_memaddr_t dest_proc_addr; 		/* a field containing CM_my_cube_address */
CM_memaddr_t loc;
unsigned size;
CM_memaddr_t scratch_memory;		/* scratch memory area of length == size */
{
	CM_memaddr_t addr;
	unsigned len;
	CM_memaddr_t bit_of_address;	/* bit of physical address to swap on */

	/* First transpose all the data in TRANSPOSER_SIZE units */
	for (addr = loc;   addr < loc + size;   addr += TRANSPOSER_SIZE)
    		_CMI_transpose_data_in_memory_ta(addr, addr);
		
        /* len is the size of the quadrant goes up in powers of two */
	for (len = TRANSPOSER_SIZE, bit_of_address = LENGTH_OF_TRANSPOSER_SIZE;
	     len < size;   len *= 2, bit_of_address++) {
		/* addr goes over the position of each block of 4 quadrants */
		/* relative to the memory location of the data */
		for (addr = loc;  addr < loc + size;  addr += 2*len)	{
			CMI_swap_quadrants(dest_proc_addr, addr, len, bit_of_address, scratch_memory);
		}
	}
}



CMI_swap_quadrants(dest_proc_addr, loc, size, bit_of_address, scratch_memory)
CM_memaddr_t dest_proc_addr; 		/* a field containing CM_my_cube_address */
CM_memaddr_t loc;
unsigned size;				/* size of quadrant */
CM_memaddr_t bit_of_address;		/* bit of physical address to swap on */
CM_memaddr_t scratch_memory;		/* scratch memory area of length >= size */
{
	/*
	 * move the low half of the data in the odd processors and the high half of the data in
	 * the even processors
	 */

	/* turn on odd quadrant processors and move their data to scratch memory */
	CM_move_always(CM_context_flag, dest_proc_addr + CM_purely_virtual_cube_address_length 
					+ bit_of_address, 1);
	CM_move(scratch_memory, loc, size);

	/* turn off odd quadrant processors and turn on even ones and move data to scratch memory */
	CM_lognot_always(CM_context_flag, CM_context_flag, 1);
	CM_move(scratch_memory, loc + size, size);

	/* turn everyone back on and have them swap data between processors */
	CM_move_constant_always(CM_context_flag, 1L, 1);
	CM_lognot(dest_proc_addr + CM_purely_virtual_cube_address_length + bit_of_address,
		  dest_proc_addr + CM_purely_virtual_cube_address_length + bit_of_address,
		  1);
	CM_send_1L(scratch_memory + size, dest_proc_addr, scratch_memory,
		size, CM_no_field);

	/* restore dest_proc_addr to CM_my_cube_address */
	CM_lognot(dest_proc_addr + CM_purely_virtual_cube_address_length + bit_of_address,
		  dest_proc_addr + CM_purely_virtual_cube_address_length + bit_of_address,
		  1);

	/* turn on odd quadrant processors and move their data from scratch memory */
	CM_move_always(CM_context_flag, dest_proc_addr + CM_purely_virtual_cube_address_length 
					+ bit_of_address, 1);
	CM_move(loc, scratch_memory + size, size);

	/* turn off odd quadrant processors and turn on even ones, move data from scratch memory */
	CM_lognot_always(CM_context_flag, CM_context_flag, 1);
	CM_move(loc + size, scratch_memory + size, size);

	CM_move_constant_always(CM_context_flag, 1L, 1);
}

 

/*
 *	Convert data from cm to network standard byte ordering
 *	If data is longer than 32 bits, do it in 32 bit chunks
 *	Is this correct for doubles?
 */
void
CMFS_cm_to_standard_byte_order(destination, length)
CM_field_id_t destination;
int length;
{
	int actual_length;

	while (length > 0)	{
		actual_length = min(length, 32);

		switch (actual_length)	{
		    case 32:
			CM_swap_2_1L(destination, CM_add_offset_to_field_id(destination, 24), 8);
			CM_swap_2_1L(CM_add_offset_to_field_id(destination, 8), 
					CM_add_offset_to_field_id(destination, 16), 8);
			break;

		    case 16:
			CM_swap_2_1L(destination, CM_add_offset_to_field_id(destination, 8), 8);
			break;

		    case 8:
			break;

		    default:
			fprintf(stderr, "Incorrect argument to CMFS_vax_to_sun_byte_order of %d\n", length);
			abort();
		}

		length -= actual_length;
		destination = CM_add_offset_to_field_id(destination, 32);
	}
}
