/*
	File:	cgas.c
	Author:	John van Groningen
*/

#include <stdio.h>
#include <string.h>

#define MODULES
#define USE_LABEL_VALUE
/* #define COUNT_RELEASES */
#undef GENERATE_MPW_OBJECT_CODE

#include "cgport.h"

#ifndef G_POWER

#include "cg.h"
#include "cgrconst.h"
#include "cgtypes.h"
#include "cgiconst.h"
#include "cgcode.h"
#include "cginstructions.h"
#include "cgas.h"

#define for_all(v,l,n) for(v=(l);v!=NULL;v=v->n)

extern LABEL *index_error_label;

#pragma segment Code5

enum {
	LBEGIN=1,
	LEND,
	LIMPORT,
	LLABEL,
	LCODE,
	LDATA,
	LREFERENCE,
	LUDATA,
	LC_REFERENCE,
	LLABEL_VALUE,
	LCOMMENT,
	LMODULE
};

#define LLABEL_TEXT		0
#define LLABEL_DATA		1
#define LLABEL_EXTERN	2
#define LLABEL_OFFSET	4

#define REFERENCE_PC		16
#define REFERENCE_OFFSET	8
#define REFERENCE_A5		4
#define REFERENCE_LONG		2
#define REFERENCE_DATA		1

#define LCR_WORD	2
#define LCR_BYTE	0
#define LCR_OFFSET	8

FILE *output_file;

#ifdef THINK_C
#	define IO_BUFFER_SIZE 16384
#else
#	define IO_BUFFER_SIZE 8192
#endif

struct object_buffer {
	struct object_buffer *next;
	int size;
	unsigned char data [IO_BUFFER_SIZE];
};

static struct object_buffer *first_buffer,*current_buffer;

static int buffer_free;
static unsigned char *buffer_p;

static void initialize_object_buffers (VOID)
{
	struct object_buffer *new_buffer;
	
	new_buffer=(struct object_buffer*)memory_allocate (sizeof (struct object_buffer));
	
	new_buffer->size=0;
	new_buffer->next=NULL;
	
	first_buffer=new_buffer;
	current_buffer=new_buffer;
	
	buffer_free=IO_BUFFER_SIZE;
	buffer_p=new_buffer->data;
}

static void write_c (int c)
{
	if (buffer_free>0){
		--buffer_free;
		*buffer_p++=c;
	} else {
		struct object_buffer *new_buffer;

		current_buffer->size=IO_BUFFER_SIZE;
	
		new_buffer=(struct object_buffer*)memory_allocate (sizeof (struct object_buffer));
	
		new_buffer->size=0;
		new_buffer->next=NULL;
	
		current_buffer->next=new_buffer;
		current_buffer=new_buffer;
	
		buffer_free=IO_BUFFER_SIZE-1;
		buffer_p=new_buffer->data;

		*buffer_p++=c;
	}
}

static void flush_object_buffer (VOID)
{
	current_buffer->size=IO_BUFFER_SIZE-buffer_free;
}

/* object optimizer */

static struct object_buffer *s_buffer,*d_buffer;
static int s_free,d_free;
static unsigned char *s_buffer_p,*d_buffer_p;

static int s_read (VOID)
{
	while (s_free==0){
		s_buffer=s_buffer->next;
		if (s_buffer==NULL)
			internal_error_in_function ("s_read");
		s_free=s_buffer->size;
		s_buffer_p=s_buffer->data;
	}
	
	--s_free;
	return *s_buffer_p++;
}

static void d_write (int c)
{
	while (d_free==0){
		d_buffer=d_buffer->next;
		if (d_buffer==NULL)
			internal_error_in_function ("d_write");
		d_free=d_buffer->size;
		d_buffer_p=d_buffer->data;
	}
	
	--d_free;
	*d_buffer_p++=c;
}

static void optimize_buffers (VOID)
{	
	int c;

	s_buffer=d_buffer=first_buffer;
	s_free=d_free=first_buffer->size;
	s_buffer_p=d_buffer_p=first_buffer->data;
	
	c=s_read();

	for (;;){
		d_write (c);
		switch (c){
			case LCODE:
			{
				int size,n,t;
				unsigned char buffer[256];
	
				n=0;			
				size=s_read();
				for (;;){
					t=size;
					while (t--)
						buffer[n++]=s_read();
					if (size & 1)
						s_read();
					c=s_read();
					if (c!=LCODE)
						break;
					else {
						size=s_read();
						if (size+n>=256){
							t=n;
							d_write (t);
							for (n=0; n<t; ++n)
								d_write (buffer[n]);
							if (t & 1)
								d_write (0);
							d_write (LCODE);
							n=0;
						}
					}
				}
				t=n;
				d_write (t);
				for (n=0; n<t; ++n)
					d_write (buffer[n]);
				if (t & 1)
					d_write (0);
				continue;
			}
			case LDATA:
			{
				int size;
				
				size=s_read();
				d_write (size);
				if (size & 1)
					d_write (s_read());
				while (size--)
					d_write (s_read());
				c=s_read();
				continue;
			}
			case LUDATA:
				d_write (s_read());
				d_write (s_read());
				c=s_read();
				continue;
			case LLABEL_VALUE:
				d_write (s_read());
				d_write (s_read());
				d_write (s_read());
				c=s_read();
				continue;
			case LREFERENCE:
			{
				int flags;
				
				flags=s_read();
				d_write (flags);
				d_write (s_read());
				d_write (s_read());
				if (flags & REFERENCE_OFFSET){
					d_write (s_read());
					d_write (s_read());
				}
				c=s_read();
				continue;
			}
			case LC_REFERENCE:
			{
				int flags;
				
				flags=s_read();
				d_write (flags);
				d_write (s_read());
				d_write (s_read());
				d_write (s_read());
				d_write (s_read());
				if (flags & LCR_OFFSET){
					d_write (s_read());
					d_write (s_read());
				}
				c=s_read();
				continue;
			}
			case LLABEL:
			{	
				int flags;
				
				flags=s_read();
				d_write (flags);
				d_write (s_read());
				d_write (s_read());
				if (flags & LLABEL_OFFSET){
					d_write (s_read());
					d_write (s_read());
				}
				if (flags & LLABEL_EXTERN){
					int size;

					size=s_read();
					d_write (size);
					if (!(size & 1))
						d_write (s_read());
					while (size--)
						d_write (s_read());
				}
				c=s_read();
				continue;
			}
			case LIMPORT:
			{
				int size;
				
				d_write (s_read());
				d_write (s_read());
				d_write (s_read());
				size=s_read();
				d_write (size);
				if (!(size & 1))
					d_write (s_read());
				while (size--)
					d_write (s_read());
				c=s_read();
				continue;
			}
			case LMODULE:
				d_write (s_read());
				c=s_read();
				continue;
			case LBEGIN:
				d_write (s_read());
				d_write (s_read());
				d_write (s_read());
				c=s_read();
				continue;
			case LEND:
				d_write (s_read());
				break;
			default:
				internal_error_in_function ("optimize_buffers");
		}
		break;
	}
	
	d_buffer->size-=d_free;
	
	{
		struct object_buffer *buffer,*next_buffer;

		for (buffer=d_buffer->next; buffer!=NULL; buffer=next_buffer){
			next_buffer=buffer->next;

			memory_free (buffer);
		}
	}
	
	d_buffer->next=NULL;
}

/* end object optimizer */

#ifdef GENERATE_MPW_OBJECT_CODE
/* mpw object conversion */

static int c_read (VOID)
{
	while (s_free==0){
		struct object_buffer *old_buffer;

		old_buffer=s_buffer;
		s_buffer=s_buffer->next;

		memory_free (old_buffer);

		if (s_buffer==NULL)
			internal_error_in_function ("c_read");
		s_free=s_buffer->size;
		s_buffer_p=s_buffer->data;
	}
	
	--s_free;
	return *s_buffer_p++;
}

static void c_write (int c)
{
	if (d_free==0){
		struct object_buffer *new_buffer;

		d_buffer->size=IO_BUFFER_SIZE;
	
		new_buffer=(struct object_buffer*)memory_allocate (sizeof (struct object_buffer));
		new_buffer->size=0;
		new_buffer->next=NULL;
		
		d_buffer->next=new_buffer;
		d_buffer=new_buffer;

		d_free=IO_BUFFER_SIZE;
		d_buffer_p=d_buffer->data;
	}
	
	--d_free;
	*d_buffer_p++=c;
}

enum { 
	O_FIRST=1,
	O_LAST,
	O_COMMENT,
	O_DICTIONARY,
	O_MODULE,
	O_ENTRY,
	O_SIZE,
	O_CONTENTS,
	O_REFERENCE,
	O_C_REFERENCE
};

static void convert_to_mpw_object_code (VOID)
{
	struct object_buffer *first_d_buffer;
	int c,code_module_id,data_module_id,segment_id;
	long code_offset,data_offset;

	first_d_buffer=(struct object_buffer*)memory_allocate (sizeof (struct object_buffer));
	first_d_buffer->size=0;
	first_d_buffer->next=NULL;

	d_buffer=first_d_buffer;
	d_free=IO_BUFFER_SIZE;
	d_buffer_p=d_buffer->data;

	s_buffer=first_buffer;
	s_free=first_buffer->size;
	s_buffer_p=first_buffer->data;
	
	segment_id=next_label_id++;
	code_module_id=next_label_id++;
	data_module_id=next_label_id++;

	code_offset=-1;
	data_offset=-1;
	
	c=c_read();

	for (;;){
		switch (c){
			case LCODE:
			{
				int size,n,t;
				unsigned char buffer[256];

				c_write (O_CONTENTS);
				c_write (8);
	
				n=0;			

				size=c_read();
				c_write ((size+8)>>8);
				c_write (size+8);

				c_write (code_offset>>24);
				c_write (code_offset>>16);
				c_write (code_offset>>8);
				c_write (code_offset);

				code_offset+=size;

				t=size;
				while (t--)
					buffer[n++]=c_read();
				if (size & 1)
					c_read();
				
				t=n;
				for (n=0; n<t; ++n)
					c_write (buffer[n]);
				if (t & 1)
					c_write (0);
				
				c=c_read();
				continue;
			}
			case LDATA:
			{
				int size;

				c_write (O_CONTENTS);
				c_write (9);

				size=c_read();
				c_write ((size+8)>>8);
				c_write (size+8);
				
				c_write (data_offset>>24);
				c_write (data_offset>>16);
				c_write (data_offset>>8);
				c_write (data_offset);
				
				data_offset+=size;
				
				if (size & 1)
					c_write (c_read());
				while (size--)
					c_write (c_read());
				c=c_read();
				continue;
			}
			case LUDATA:
				internal_error_in_function ("convert_to_mpw_object_code");
				break;
			case LLABEL_VALUE:
			{
				int flags,id_h,id_l;
				
				flags=c_read();
				id_h=c_read();
				id_l=c_read();

				if (flags & (REFERENCE_PC | REFERENCE_OFFSET))
					internal_error_in_function ("convert_to_mpw_object_code");

				if (flags & REFERENCE_LONG){
					if (flags & REFERENCE_DATA){
						c_write (O_CONTENTS);
						c_write (9);
						
						c_write (0);
						c_write (4+8);
	
						c_write (data_offset>>24);
						c_write (data_offset>>16);
						c_write (data_offset>>8);
						c_write (data_offset);
					} else {
						c_write (O_CONTENTS);
						c_write (8);
						
						c_write (0);
						c_write (4+8);
						
						c_write (code_offset>>24);
						c_write (code_offset>>16);
						c_write (code_offset>>8);
						c_write (code_offset);
					}
					c_write (0);					
					c_write (0);					
					c_write (0);					
					c_write (0);					
				} else {
					if (flags & REFERENCE_DATA){
						c_write (O_CONTENTS);
						c_write (9);
						
						c_write (0);
						c_write (2+8);
	
						c_write (data_offset>>24);
						c_write (data_offset>>16);
						c_write (data_offset>>8);
						c_write (data_offset);
					} else {
						c_write (O_CONTENTS);
						c_write (8);
						
						c_write (0);
						c_write (2+8);
						
						c_write (code_offset>>24);
						c_write (code_offset>>16);
						c_write (code_offset>>8);
						c_write (code_offset);
					}
					c_write (0);					
					c_write (0);					
				}
					
				c_write (O_REFERENCE);
				c_write ( (flags & REFERENCE_A5 ? 128 : 0)
						| (flags & REFERENCE_LONG ? 0 : 16)
						| (flags & REFERENCE_DATA ? 1 : 0));

				c_write (0);
				c_write (8);

				c_write (id_h);
				c_write (id_l);

				if (flags & REFERENCE_DATA){
					c_write (data_offset>>8);
					c_write (data_offset);

					if (flags & REFERENCE_LONG)
						data_offset+=4;
					else
						data_offset+=2;
				} else {
					c_write (code_offset>>8);
					c_write (code_offset);
					
					if (flags & REFERENCE_LONG)
						code_offset+=4;
					else
						code_offset+=2;
				}
				
				c=c_read();
				continue;
			}
			case LREFERENCE:
			{
				int flags;

				flags=c_read();

				c_write (O_REFERENCE);
				c_write ( (flags & REFERENCE_A5 ? 128 : 0)
						| (flags & REFERENCE_LONG ? 0 : 16)
						| (flags & REFERENCE_DATA ? 1 : 0));

				c_write (0);
				c_write (8);

				c_write (c_read());
				c_write (c_read());

				if (flags & REFERENCE_DATA){
					c_write (data_offset>>8);
					c_write (data_offset);
				} else {
					c_write (code_offset>>8);
					c_write (code_offset);
				}

				if (flags & REFERENCE_OFFSET)
					internal_error_in_function ("convert_to_mpw_object_code");

				c=c_read();
				continue;
			}
			case LC_REFERENCE:
			{
				int flags;

				flags=c_read();

				c_write (O_C_REFERENCE);
				c_write ((flags & LCR_WORD ? 16 : 0) | (flags & LCR_BYTE ? 32 : 0));
				
				c_write (0);
				c_write (10);
				
				c_write (c_read());
				c_write (c_read());

				c_write (c_read());
				c_write (c_read());
				if (flags & LCR_OFFSET)
					internal_error_in_function ("convert_to_mpw_object_code");

				c_write (code_offset>>8);
				c_write (code_offset);

				c=c_read();
				continue;
			}
			case LLABEL:
			{	
				int flags,id_h,id_l;
				
				flags=c_read();
				id_h=c_read();
				id_l=c_read();

				if (flags & LLABEL_EXTERN){
					int size;

					size=c_read();

					c_write (O_DICTIONARY);
					c_write (0);
					
					c_write (0);
					c_write (size+7);
					
					c_write (id_h);
					c_write (id_l);
				
					c_write (size);
					if (!(size & 1))
						c_write (c_read());
					while (size--)
						c_write (c_read());
				}

				c_write (O_ENTRY);
				c_write ((flags & LLABEL_DATA ? 1 : 0) | (flags & LLABEL_EXTERN ? 8 : 0));

				c_write (id_h);
				c_write (id_l);

				if (flags & LLABEL_DATA){
					c_write (data_offset>>24);
					c_write (data_offset>>16);
					c_write (data_offset>>8);
					c_write (data_offset);
				} else {
					c_write (code_offset>>24);
					c_write (code_offset>>16);
					c_write (code_offset>>8);
					c_write (code_offset);
				}

				if (flags & LLABEL_OFFSET)
					internal_error_in_function ("convert_to_mpw_object_code");

				c=c_read();
				continue;
			}
			case LIMPORT:
			{
				int size,id_l,id_h;

				c_read();

				id_h=c_read();
				id_l=c_read();
				size=c_read();
		
				c_write (O_DICTIONARY);
				c_write (0);
				
				c_write (0);
				c_write (size+7);
				
				c_write (id_h);
				c_write (id_l);
			
				c_write (size);
			
				if (!(size & 1))
					c_write (c_read());
				while (size--)
					c_write (c_read());

				c=c_read();
				continue;
			}
			case LMODULE:
			{
				int flag;
				
				flag=c_read();

				if (code_offset!=0){
					c_write (O_MODULE);
					c_write (0);
	
					c_write (code_module_id>>8);
					c_write (code_module_id);
					code_module_id=next_label_id++;
					
					c_write (segment_id>>8);
					c_write (segment_id);
					
					code_offset=0;
				}

				if (data_offset!=0){
					c_write (O_MODULE);
					c_write (1);
	
					c_write (data_module_id>>8);
					c_write (data_module_id);
					data_module_id=next_label_id++;
					
					c_write (0);
					c_write (0);
					
					data_offset=0;
				}
				c=c_read();
				continue;
			}
			case LBEGIN:
				c_read();
				c_read();
				c_read();
				
				c_write (O_FIRST);
				c_write (1);
				c_write (0);
				c_write (2);
				
				c_write (O_DICTIONARY);
				c_write (0);
				
				c_write (0);
				c_write (7+1);
				
				c_write (segment_id>>8);
				c_write (segment_id);
			
				c_write (1);
				c_write ('m');

				c=c_read();
				continue;
			case LEND:
				c_read();
				c_write (O_LAST);
				c_write (0);
				break;
			default:
				internal_error_in_function ("convert_to_mpw_object_code");
		}
		break;
	}
	
 	d_buffer->size=IO_BUFFER_SIZE-d_free;
	d_buffer->next=NULL;

	{
		struct object_buffer *buffer,*next_buffer;

		for (buffer=s_buffer; buffer!=NULL; buffer=next_buffer){
			next_buffer=buffer->next;

			memory_free (buffer);
		}
	}	

	first_buffer=first_d_buffer;
}

/* end mpw object conversion */
#endif

static void write_object_buffers_and_release_memory (VOID)
{
	struct object_buffer *buffer,*next_buffer;
	
	for (buffer=first_buffer; buffer!=NULL; buffer=next_buffer){
		int size;
		
		size=buffer->size;
		
		if (fwrite (buffer->data,1,size,output_file)!=size)
			error ("Write error");
		
		next_buffer=buffer->next;
		
		memory_free (buffer);
	}
	
	first_buffer=NULL;
}

/* #define write_c(c) putc((c),output_file) */

static void write_w (UWORD i)
{
	write_c (i>>8);
	write_c (i);
}

static void write_l (register ULONG i)
{
	write_c (i>>24);
	write_c (i>>16);
	write_c (i>>8);
	write_c (i);
}

static void write_block (void *buffer,int length)
{
	char *p;
	
	if (length){
		p=(char*)buffer;
		do
			write_c (*p++);
		while (--length);
	}
	/*
	if (fwrite (buffer,1,length,output_file)!=length)
		error ("Write error");
	*/
}

static void write_s (char string[])
{
	int length;

	length=strlen (string);
	if (length>255)
		length=255;
		
	write_c (length);
	write_block (string,length);
	if (!(length & 1))
		write_c (0);
}

#ifdef MODULES
void start_new_module (int flag)
{
	write_c (LMODULE);
	write_c (flag);
}
#endif

static void import_label (int id,char label_name[])
{
	write_c (LIMPORT);
	write_c (0);
	write_w (id);
	write_s (label_name);	
}

void define_local_label (int id,int flag)
{
	write_c (LLABEL);
	write_c (flag);
	write_w (id);
}

static void define_local_text_label (int id)
{
	write_c (LLABEL);
	write_c (LLABEL_TEXT);
	write_w (id);
}

void define_external_label (int id,int flag,char label_name[])
{
	write_c (LLABEL);
	write_c (flag | LLABEL_EXTERN);
	write_w (id);
	write_s (label_name);
}

void store_word_in_data_section (UWORD i)
{
	write_c (LDATA);
	write_c (2);
	write_w (i);
}

void store_long_word_in_data_section (ULONG i)
{
	write_c (LDATA);
	write_c (4);
	write_l (i);
}

void store_label_in_data_section (int label_id)
{
#ifdef USE_LABEL_VALUE
	write_c (LLABEL_VALUE);
	write_c (REFERENCE_LONG | REFERENCE_DATA);
	write_w (label_id);
#else
	write_c (LREFERENCE);
	write_c (REFERENCE_LONG | REFERENCE_DATA);
	write_w (label_id);
	write_c (LDATA);
	write_c (4);
	write_l (0);
#endif
}

void store_descriptor_in_code_section (int label_id)
{
	write_c (LLABEL_VALUE);
	write_c (REFERENCE_A5 | REFERENCE_LONG);
	write_w (label_id);
}

void store_descriptor_in_data_section (int label_id)
{
	write_c (LLABEL_VALUE);
	write_c (REFERENCE_DATA | REFERENCE_A5 | REFERENCE_LONG);
	write_w (label_id);
}

void store_label_offset_in_data_section (int label_id)
{
#ifdef USE_LABEL_VALUE
	write_c (LLABEL_VALUE);
	write_c (REFERENCE_DATA | REFERENCE_A5);
	write_w (label_id);
#else
	write_c (LREFERENCE);
	write_c (REFERENCE_DATA | REFERENCE_A5);
	write_w (label_id);
	write_c (LDATA);
	write_c (2);
	write_w (0);
#endif
}

void store_label_offset_in_code_section (int label_id)
{
#ifdef USE_LABEL_VALUE
	write_c (LLABEL_VALUE);
	write_c (REFERENCE_A5);
	write_w (label_id);
#else
	write_c (LREFERENCE);
	write_c (REFERENCE_A5);
	write_w (label_id);
	write_c (LCODE);
	write_c (2);
	write_w (0);
#endif
}

static void store_text_label_in_text_section (LABEL *label)
{
	if (label->label_id<0)
		label->label_id=next_label_id++;

#ifdef USE_LABEL_VALUE
	write_c (LLABEL_VALUE);
	write_c (0);	
	write_w (label->label_id);
#else
	write_c (LREFERENCE);
	write_c (0);	
	write_w (label->label_id);
	write_c (LCODE);
	write_c (2);
	write_w (0);
#endif
}

void store_c_string_in_data_section (char *string,int length)
{
	int t_length;
	
/*	t_length=(length+1+1) & ~1; */
	t_length=(length+1+3) & ~3;
	
	if (t_length+1>255)
		internal_error ("String too long in 'store_c_string_in_data_section'");
	
	write_c (LDATA);
	write_c (t_length);
	write_block (string,length);
	write_c (0);
/*
	if (!(length & 1))
		write_c (0);
*/
	while (++length,length<t_length)
		write_c (0);		
}

void store_abc_string_in_data_section (char *string,int length)
{
	int t_length=(length+4+3) & ~3;

	if (t_length>255)
		internal_error ("String too long in 'store_abc_string_in_data_section'");
	
	write_c (LDATA);
	write_c (t_length);
	write_l (length);
	write_block (string,length);
	while (length & 3){
		write_c (0);
		++length;
	}
}

void store_c_string_in_code_section (char *string,int length)
{
	int t_length=(length+1+1) & ~1;
	
	if (t_length+1>255)
		internal_error ("String too long in 'store_c_string_in_code_section'");
	
	write_c (LCODE);
	write_c (t_length);
	write_block (string,length);
	write_c (0);
	if (!(length & 1))
		write_c (0);
}

void store_abc_string_in_code_section (char *string,int length)
{
	int t_length=(length+4+3) & ~3;

	if (t_length>255)
		internal_error ("String too long in 'store_abc_string_in_code_section'");

	write_c (LCODE);
	write_c (t_length);
	write_l (length);
	write_block (string,length);
	while (length & 3){
		write_c (0);
		++length;
	}
}

static void write_number_of_arguments (int number_of_arguments)
{
	write_c (LCODE);
	write_c (2);
	write_w (number_of_arguments);
}

void store_descriptor_string_in_code_section
	(char *string,int length,int string_code_label_id,LABEL *string_label)
{
	int t_length;
	
	t_length=(length+4+3) & ~3;
	
	if (t_length>255)
		internal_error ("String too long in 'store_descriptor_string_in_code_section'");
		
	write_c (LLABEL);
	write_c (LLABEL_TEXT);
	write_w (string_code_label_id);

	write_c (LCODE);
	write_c (6);

	write_w (040772);		/* LEA 4+2(PC),A0 */
	write_w (4);
	write_w (0x4e75);		/* RTS */

	write_c (LMODULE);
	write_c (1);

	write_c (LLABEL);
	write_c (LLABEL_TEXT);
	write_w (string_label->label_id);

	write_c (LCODE);
	write_c (t_length);

	write_l (length);
	write_block (string,length);
	while (length & 3){
		write_c (0);
		++length;
	}
}

static WORD write_indirect_node_entry_jump (LABEL *label)
{
	register int new_label_id;
		
	new_label_id=next_label_id++;
	
	if (label->label_flags & EA_LABEL){
		int label_arity;
		extern LABEL *eval_upd_labels[],*eval_fill_label;
		LABEL *eval_upd_label;

		label_arity=label->label_arity;
		
		if (label_arity<-2)
			label_arity=1;
		
		if (label_arity>=0 && label->label_ea_label!=eval_fill_label){
			write_c (LCODE);
			write_c (2);
			write_w (042700);
	
			write_c (LLABEL_VALUE);
			write_c (0);
			if (label->label_ea_label->label_id<0)
				label->label_ea_label->label_id=next_label_id++;
			write_w (label->label_ea_label->label_id);
	
			write_c (LCODE);
			write_c (2);
			write_w (047300);
	
			write_c (LLABEL_VALUE);
			write_c (0);
			eval_upd_label=eval_upd_labels[label_arity];
			if (eval_upd_label->label_id<0)
				eval_upd_label->label_id=next_label_id++;
			write_w (eval_upd_label->label_id);
		} else {
			write_c (LCODE);
			write_c (2);
			write_w (047300);
	
			write_c (LLABEL_VALUE);
			write_c (0);
			if (label->label_ea_label->label_id<0)
				label->label_ea_label->label_id=next_label_id++;
			write_w (label->label_ea_label->label_id);
			
			write_c (LCODE);
			write_c (4);
			write_w (0x4e71);
			write_w (0x4e71);
		}

		if (label->label_arity<0 || parallel_flag){
			LABEL *descriptor_label;

			descriptor_label=label->label_descriptor;

			if (descriptor_label->label_id<0)
				descriptor_label->label_id=next_label_id++;

			store_label_offset_in_code_section (descriptor_label->label_id);
		} else
			write_number_of_arguments (0);
	} else
		if (label->label_arity<0 || parallel_flag){
			LABEL *descriptor_label;

			descriptor_label=label->label_descriptor;

			if (descriptor_label->label_id<0)
				descriptor_label->label_id=next_label_id++;

			store_label_offset_in_code_section (descriptor_label->label_id);
		}

	write_number_of_arguments (label->label_arity);
	
	define_local_text_label (new_label_id);
	
	write_w ((LCODE<<8)+2);
	write_w (047300);
	
#ifdef USE_LABEL_VALUE
	write_w (LLABEL_VALUE<<8);
	write_w (label->label_id);
#else
	write_w (LREFERENCE<<8);
	write_w (label->label_id);
			
	write_w ((LCODE<<8)+2);
	write_w (0);
#endif
	
	return new_label_id;
}

static void write_indirect_defered_jump (LABEL *label)
{
	LABEL *node_label;

	if (EMPTY_label->label_id<0)
		EMPTY_label->label_id=next_label_id++;
	store_label_offset_in_code_section (EMPTY_label->label_id);

	write_number_of_arguments (label->label_arity);
	
	if (label->label_id<0)
		label->label_id=next_label_id++;
	define_local_text_label (label->label_id);
	
	write_w ((LCODE<<8)+2);
	write_w (047300);

	node_label=label->label_descriptor;
	if (node_label->label_id<0)
		node_label->label_id=next_label_id++;
#ifdef USE_LABEL_VALUE
	write_w (LLABEL_VALUE<<8);
	write_w (node_label->label_id);
#else
	write_w (LREFERENCE<<8);
	write_w (node_label->label_id);
			
	write_w ((LCODE<<8)+2);
	write_w (0);
#endif
}

#ifdef COUNT_RELEASES
static int node_entry_count_label_id;
#endif

static void import_labels (register struct label_node *label_node)
{
	register LABEL *label;
	
	if (label_node==NULL)
		return;
	
	label=&label_node->label_node_label;
	
	if (!(label->label_flags & LOCAL_LABEL) && label->label_number==0){
		if (label->label_id<0)
			label->label_id=next_label_id++;
		import_label (label->label_id,label->label_name);
		if (label->label_flags & NODE_ENTRY_LABEL){
#ifdef MODULES
			start_new_module (0);
#endif
			label->label_id=write_indirect_node_entry_jump (label);
		}
	}
	
	import_labels (label_node->label_node_left);
	import_labels (label_node->label_node_right);
}

static void write_indirect_jumps_for_defer_labels (void)
{
	struct local_label *local_label;
	
	for (local_label=local_labels; local_label!=NULL; local_label=local_label->local_label_next){
		LABEL *label;
		
		label=&local_label->local_label_label;
		if (label->label_flags & DEFERED_LABEL){
#ifdef MODULES
			start_new_module (0);
#endif
			write_indirect_defered_jump (label);
		}
	}
}

static void write_labels (register struct block_label *labels)
{
	for (; labels!=NULL; labels=labels->block_label_next)
		if (labels->block_label_label->label_number==0){
			register LABEL *label;
			register int id;
			
			label=labels->block_label_label;
			id=label->label_id;
			if (id<0){
				id=next_label_id++;
				label->label_id=id;
			}
			
			if (label->label_flags & EXPORT_LABEL)
				define_external_label (id,LLABEL_TEXT,label->label_name);
			else
				define_local_text_label (id);
		}
}

enum { SIZE_LONG, SIZE_WORD, SIZE_BYTE };

static void as_addressing_mode_instruction (struct parameter *parameter,int opcode,int size_flag)
{
	UWORD buffer[10],*code_buf_p,*end_buf_p;
	
	code_buf_p=buffer;
	end_buf_p=code_buf_p;
	*end_buf_p++=(LCODE<<8)+2;
	++end_buf_p;
	
	switch (parameter->parameter_type){
		case P_REGISTER:
		{
			int reg=parameter->parameter_data.reg.r;
			if (is_d_register (reg))
				opcode |= 000 | d_reg_num (reg);
			else
				opcode |= 010 | a_reg_num (reg);
			break;
		}
		case P_INDIRECT:
		{
			int offset=parameter->parameter_offset;
			if (offset==0){
				opcode |= 020 | a_reg_num (parameter->parameter_data.reg.r);
			} else {
				opcode |= 050 | a_reg_num (parameter->parameter_data.reg.r);
				((UBYTE*)code_buf_p)[1]+=2;
				*end_buf_p++ = offset;
			}
			break;
		}
		case P_POST_INCREMENT:
			opcode |= 030 | a_reg_num (parameter->parameter_data.reg.r);
			break;
		case P_PRE_DECREMENT:
			opcode |= 040 | a_reg_num (parameter->parameter_data.reg.r);
			break;
		case P_LABEL:
		{
			LABEL *label;
			
			opcode |= 055;
			
			label=parameter->parameter_data.l;
			if (label->label_id<0)
				label->label_id=next_label_id++;
#ifdef USE_LABEL_VALUE
			*end_buf_p++=(LLABEL_VALUE<<8)+REFERENCE_A5;
			*end_buf_p++=label->label_id;
#else
			*end_buf_p++=(LREFERENCE<<8)+REFERENCE_A5;
			*end_buf_p++=label->label_id;

			*end_buf_p++=(LCODE<<8)+2;
			*end_buf_p++=0;
#endif
			break;
		}
		case P_DESCRIPTOR_NUMBER:
		{
			LABEL *label;
			
			opcode |= 074;
			
			if (size_flag==SIZE_LONG){
				((UBYTE*)code_buf_p)[1]+=2;
				*end_buf_p++=0xffff;
			}
			
			label=parameter->parameter_data.l;
			if (label->label_id<0)
				label->label_id=next_label_id++;

#ifdef USE_LABEL_VALUE
			if (parameter->parameter_offset==0){
				*end_buf_p++=(LLABEL_VALUE<<8)+REFERENCE_A5;
				*end_buf_p++=label->label_id;		
			} else {
#endif
			*end_buf_p++=(LREFERENCE<<8)+REFERENCE_A5;
			*end_buf_p++=label->label_id;
			
			code_buf_p=end_buf_p;
			*end_buf_p++=(LCODE<<8)+2;
			*end_buf_p++=parameter->parameter_offset << 2;
#ifdef USE_LABEL_VALUE
			}
#endif
			break;
		}
		case P_IMMEDIATE:
			opcode |= 074;
			if (size_flag==SIZE_LONG){
				((UBYTE*)code_buf_p)[1]+=4;
				*(*(ULONG**)&end_buf_p)++ = parameter->parameter_data.i;
			} else {
				((UBYTE*)code_buf_p)[1]+=2;
				*end_buf_p++ = parameter->parameter_data.i;
			}
			break;
/* CHANGED 27-7-92 */
		case P_INDEXED:
		{
			struct index_registers *index_registers;
			int offset;
			
			offset=parameter->parameter_offset;
			index_registers=parameter->parameter_data.ir;
			
			((UBYTE*)code_buf_p)[1]+=2;
			*end_buf_p++ = 0x800 | (d_reg_num (index_registers->d_reg.r)<<12) 
							| ((offset>>2) & 0xff) | ((offset & 3)<<9);
			opcode |= 060 | a_reg_num (index_registers->a_reg.r);
			break;
		}
/* */
		default:
			internal_error_in_function ("as_addressing_mode_instruction");
	}
	
	buffer[1]=opcode;
	write_block (buffer,(UBYTE*)end_buf_p-(UBYTE*)buffer);
}

static void as_immediate_data_alterable_addressing_mode
	(int opcode,UWORD buffer[],UWORD *code_buf_p,UWORD *end_buf_p,struct parameter *parameter)
{
	switch (parameter->parameter_type){
		case P_REGISTER:
		{
			int reg=parameter->parameter_data.reg.r;
			if (is_d_register (reg))
				opcode |= 000 | d_reg_num (reg);
			else
				internal_error_in_function ("as_immediate_data_alterable_addressing mode");
			break;
		}
		case P_INDIRECT:
		{
			int offset=parameter->parameter_offset;
			if (offset==0){
				opcode |= 020 | a_reg_num (parameter->parameter_data.reg.r);
			} else {
#ifdef USE_LABEL_VALUE
				if (code_buf_p==NULL){
					code_buf_p=end_buf_p;
					*end_buf_p++=LCODE<<8;
				}
#endif
				opcode |= 050 | a_reg_num (parameter->parameter_data.reg.r);
				((UBYTE*)code_buf_p)[1]+=2;
				*end_buf_p++ = offset;
			}
			break;
		}
		case P_POST_INCREMENT:
			opcode |= 030 | a_reg_num (parameter->parameter_data.reg.r);
			break;
		case P_PRE_DECREMENT:
			opcode |= 040 | a_reg_num (parameter->parameter_data.reg.r);
			break;
		case P_LABEL:
		{
			LABEL *label;
			
			opcode |= 055;
			
			label=parameter->parameter_data.l;
			if (label->label_id<0)
				label->label_id=next_label_id++;
#ifdef USE_LABEL_VALUE
			*end_buf_p++=(LLABEL_VALUE<<8)+REFERENCE_A5;
			*end_buf_p++=label->label_id;
#else
			*end_buf_p++=(LREFERENCE<<8)+REFERENCE_A5;
			*end_buf_p++=label->label_id;
			
			*end_buf_p++=(LCODE<<8)+2;
			*end_buf_p++=0;
#endif
			break;
		}
/* CHANGED 27-7-92 */
		case P_INDEXED:
		{
			struct index_registers *index_registers;
			int offset;
			
			offset=parameter->parameter_offset;
			index_registers=parameter->parameter_data.ir;
#ifdef USE_LABEL_VALUE
			if (code_buf_p==NULL){
				code_buf_p=end_buf_p;
				*end_buf_p++=LCODE<<8;
			}
#endif
			((UBYTE*)code_buf_p)[1]+=2;
			*end_buf_p++ = 0x800 | (d_reg_num (index_registers->d_reg.r)<<12) 
							| ((offset>>2) & 0xff) | ((offset & 3)<<9);
			opcode |= 060 | a_reg_num (index_registers->a_reg.r);
			break;
		}
/* */
		default:
			internal_error_in_function ("as_immediate_data_alterable_addressing_mode");
	}
	
	buffer[1]=opcode;
	write_block (buffer,(UBYTE*)end_buf_p-(UBYTE*)buffer);
}

static void as_data_addressing_mode (	int opcode,UWORD buffer[],UWORD *code_buf_p,
										UWORD *end_buf_p,struct parameter *parameter,int size_flag)
{
	switch (parameter->parameter_type){
		case P_REGISTER:
		{
			int reg=parameter->parameter_data.reg.r;
			if (is_d_register (reg))
				opcode |= 000 | d_reg_num (reg);
			else
				internal_error_in_function ("as_data_addressing mode");
			break;
		}
		case P_INDIRECT:
		{
			int offset=parameter->parameter_offset;
			if (offset==0){
				opcode |= 020 | a_reg_num (parameter->parameter_data.reg.r);
			} else {
				opcode |= 050 | a_reg_num (parameter->parameter_data.reg.r);
				((UBYTE*)code_buf_p)[1]+=2;
				*end_buf_p++ = offset;
			}
			break;
		}
		case P_POST_INCREMENT:
			opcode |= 030 | a_reg_num (parameter->parameter_data.reg.r);
			break;
		case P_PRE_DECREMENT:
			opcode |= 040 | a_reg_num (parameter->parameter_data.reg.r);
			break;
		case P_LABEL:
		{
			LABEL *label;
			
			opcode |= 055;
			
			label=parameter->parameter_data.l;
			if (label->label_id<0)
				label->label_id=next_label_id++;
#ifdef USE_LABEL_VALUE
			*end_buf_p++=(LLABEL_VALUE<<8)+REFERENCE_A5;
			*end_buf_p++=label->label_id;			
#else
			*end_buf_p++=(LREFERENCE<<8)+REFERENCE_A5;
			*end_buf_p++=label->label_id;
			
			*end_buf_p++=(LCODE<<8)+2;
			*end_buf_p++=0;
#endif
			break;
		}
		case P_DESCRIPTOR_NUMBER:
		{
			LABEL *label;
			
			opcode |= 074;
			
			if (size_flag==SIZE_LONG){
				((UBYTE*)code_buf_p)[1]+=2;
				*end_buf_p++=0xffff;
			}
			
			label=parameter->parameter_data.l;
			if (label->label_id<0)
				label->label_id=next_label_id++;
#ifdef USE_LABEL_VALUE
			if (parameter->parameter_offset==0){
				*end_buf_p++=(LLABEL_VALUE<<8)+REFERENCE_A5;
				*end_buf_p++=label->label_id;
			} else {
#endif
			*end_buf_p++=(LREFERENCE<<8)+REFERENCE_A5;
			*end_buf_p++=label->label_id;
			
			*end_buf_p++=(LCODE<<8)+2;
			*end_buf_p++=parameter->parameter_offset << 2;
#ifdef USE_LABEL_VALUE
			}
#endif
			break;
		}
		case P_IMMEDIATE:
			opcode |= 074;
			if (size_flag==SIZE_LONG){
				((UBYTE*)code_buf_p)[1]+=4;
				*(*(ULONG**)&end_buf_p)++ = parameter->parameter_data.i;
			} else {
				((UBYTE*)code_buf_p)[1]+=2;
				*end_buf_p++ = parameter->parameter_data.i;
			}
			break;
/* CHANGED 27-7-92 */
		case P_INDEXED:
		{
			struct index_registers *index_registers;
			int offset;
			
			offset=parameter->parameter_offset;
			index_registers=parameter->parameter_data.ir;
			
			((UBYTE*)code_buf_p)[1]+=2;
			*end_buf_p++ = 0x800 | (d_reg_num (index_registers->d_reg.r)<<12) 
							| ((offset>>2) & 0xff) | ((offset & 3)<<9);
			opcode |= 060 | a_reg_num (index_registers->a_reg.r);
			break;
		}
/* */
		default:
			internal_error_in_function ("as_data_addressing_mode");
	}
	
	buffer[1]=opcode;
	write_block (buffer,(UBYTE*)end_buf_p-(UBYTE*)buffer);
}

static void as_alterable_memory_addressing_mode_instruction (struct parameter *parameter,int opcode)
{
	UWORD buffer[10],*code_buf_p,*end_buf_p;
	
	code_buf_p=buffer;
	end_buf_p=code_buf_p;
	*end_buf_p++=(LCODE<<8)+2;
	++end_buf_p;
	
	switch (parameter->parameter_type){
		case P_INDIRECT:
		{
			int offset=parameter->parameter_offset;
			if (offset==0){
				opcode |= 020 | a_reg_num (parameter->parameter_data.reg.r);
			} else {
				opcode |= 050 | a_reg_num (parameter->parameter_data.reg.r);
				((UBYTE*)code_buf_p)[1]+=2;
				*end_buf_p++ = offset;
			}
			break;
		}
		case P_POST_INCREMENT:
			opcode |= 030 | a_reg_num (parameter->parameter_data.reg.r);
			break;
		case P_PRE_DECREMENT:
			opcode |= 040 | a_reg_num (parameter->parameter_data.reg.r);
			break;
		case P_LABEL:
		{
			LABEL *label;
			
			opcode |= 055;
			
			label=parameter->parameter_data.l;
			if (label->label_id<0)
				label->label_id=next_label_id++;
#ifdef USE_LABEL_VALUE
			*end_buf_p++=(LLABEL_VALUE<<8)+REFERENCE_A5;
			*end_buf_p++=label->label_id;
#else
			*end_buf_p++=(LREFERENCE<<8)+REFERENCE_A5;
			*end_buf_p++=label->label_id;
			
			code_buf_p=end_buf_p;
			*end_buf_p++=(LCODE<<8)+2;
			*end_buf_p++=0;
#endif
			break;
		}
/* CHANGED 27-7-92 */
		case P_INDEXED:
		{
			struct index_registers *index_registers;
			int offset;
			
			offset=parameter->parameter_offset;
			index_registers=parameter->parameter_data.ir;
			
			((UBYTE*)code_buf_p)[1]+=2;
			*end_buf_p++ = 0x800 | (d_reg_num (index_registers->d_reg.r)<<12) 
							| ((offset>>2) & 0xff) | ((offset & 3)<<9);
			opcode |= 060 | a_reg_num (index_registers->a_reg.r);
			break;
		}
/* */
		default:
			internal_error_in_function ("as_alterable_memory_addressing_mode_instruction");
	}
	
	buffer[1]=opcode;
	write_block (buffer,(UBYTE*)end_buf_p-(UBYTE*)buffer);
}

static void as_control_addressing_mode_instruction (struct parameter *parameter,int opcode)
{
	UWORD buffer[10],*end_buf_p;
	
	end_buf_p=buffer;
	*end_buf_p++=(LCODE<<8)+2;
	
	switch (parameter->parameter_type){
		case P_INDIRECT:
		{
			int offset=parameter->parameter_offset;
			if (offset==0){
				opcode |= 020 | a_reg_num (parameter->parameter_data.reg.r);
				*end_buf_p++=opcode;
			} else {
				opcode |= 050 | a_reg_num (parameter->parameter_data.reg.r);
				*end_buf_p++=opcode;
				((UBYTE*)buffer)[1]+=2;
				*end_buf_p++ = offset;
			}
			break;
		}
		case P_LABEL:
		{
			LABEL *label;
			
			label=parameter->parameter_data.l;
			if (label->label_id<0)
				label->label_id=next_label_id++;
			
			if (label->label_flags & DATA_LABEL){
				opcode |= 055;
				*end_buf_p++=opcode;
#ifdef USE_LABEL_VALUE
				*end_buf_p++=(LLABEL_VALUE<<8)+REFERENCE_A5;
#else
				*end_buf_p++=(LREFERENCE<<8)+REFERENCE_A5;
#endif
			} else {
				*end_buf_p++=opcode;
#ifdef USE_LABEL_VALUE
				*end_buf_p++=(LLABEL_VALUE<<8);
#else
				*end_buf_p++=(LREFERENCE<<8);
#endif
			}
			
			*end_buf_p++=label->label_id;
#ifndef USE_LABEL_VALUE
			*end_buf_p++=(LCODE<<8)+2;
			*end_buf_p++=0;
#endif
			break;
		}
/* CHANGED 27-7-92 */
		case P_INDEXED:
		{
			struct index_registers *index_registers;
			int offset;
			
			offset=parameter->parameter_offset;
			index_registers=parameter->parameter_data.ir;
			opcode |= 060 | a_reg_num (index_registers->a_reg.r);
			
			*end_buf_p++=opcode;
			((UBYTE*)buffer)[1]+=2;
			*end_buf_p++ = 0x800 | (d_reg_num (index_registers->d_reg.r)<<12) 
							| ((offset>>2) & 0xff) | ((offset & 3)<<9);
			break;
		}
/* */
		default:
			internal_error_in_function ("as_control_addressing_mode_instruction");
	}
	
	write_block (buffer,(UBYTE*)end_buf_p-(UBYTE*)buffer);
}

static void as_fp_instruction_p (int opcode,int fp_opcode,struct parameter *parameter)
{
	UWORD buffer[14],*code_buf_p,*end_buf_p;
				
	buffer[0]=(LCODE<<8)+4;
	buffer[2]=fp_opcode;

	code_buf_p=buffer;
	end_buf_p=&buffer[3];

	switch (parameter->parameter_type){
		case P_REGISTER:
		{
			int reg=parameter->parameter_data.reg.r;
			if (is_d_register (reg))
				opcode |= 000 | d_reg_num (reg);
			else
				internal_error_in_function ("as_fp_addressing mode");
			break;
		}
		case P_INDIRECT:
		{
			int offset=parameter->parameter_offset;
			if (offset==0){
				opcode |= 020 | a_reg_num (parameter->parameter_data.reg.r);
			} else {
				opcode |= 050 | a_reg_num (parameter->parameter_data.reg.r);
				((UBYTE*)code_buf_p)[1]+=2;
				*end_buf_p++ = offset;
			}
			break;
		}
		case P_POST_INCREMENT:
			opcode |= 030 | a_reg_num (parameter->parameter_data.reg.r);
			break;
		case P_PRE_DECREMENT:
			opcode |= 040 | a_reg_num (parameter->parameter_data.reg.r);
			break;
		case P_LABEL:
		{
			LABEL *label;
			
			opcode |= 055;
			
			label=parameter->parameter_data.l;
			if (label->label_id<0)
				label->label_id=next_label_id++;
#ifdef USE_LABEL_VALUE
			*end_buf_p++=(LLABEL_VALUE<<8)+REFERENCE_A5;
			*end_buf_p++=label->label_id;
#else
			*end_buf_p++=(LREFERENCE<<8)+REFERENCE_A5;
			*end_buf_p++=label->label_id;
			
			*end_buf_p++=(LCODE<<8)+2;
			*end_buf_p++=0;
#endif
			break;
		}
		case P_F_IMMEDIATE:
		{
			DOUBLE d;
			float f;

			opcode |= 074;
			
			d=*parameter->parameter_data.r;
			f=d;
			if (d==f){
				buffer[2]&=~0x1000;
				((UBYTE*)code_buf_p)[1]+=4;
				*(*(float**)&end_buf_p)++ = f;
			} else {
				((UBYTE*)code_buf_p)[1]+=8;
				*(*(DOUBLE**)&end_buf_p)++ = d;
			}
			break;
		}
		case P_IMMEDIATE:
		{
			opcode |= 074;
			((UBYTE*)code_buf_p)[1]+=4;
			*(*(ULONG**)&end_buf_p)++ = parameter->parameter_data.i;
			break;
		}
/* CHANGED 22-7-92 */
		case P_INDEXED:
		{
			struct index_registers *index_registers;
			int offset;
			
			offset=parameter->parameter_offset;
			index_registers=parameter->parameter_data.ir;
			
			((UBYTE*)code_buf_p)[1]+=2;
			*end_buf_p++ = 0x800 | (d_reg_num (index_registers->d_reg.r)<<12)
							| ((offset>>2) & 0xff) | ((offset & 3)<<9);
			opcode |= 060 | a_reg_num (index_registers->a_reg.r);
			break;
		}
/* */
		default:
			internal_error_in_function ("as_fp_instruction_p");
	}
	
	buffer[1]=opcode;
	write_block (buffer,(UBYTE*)end_buf_p-(UBYTE*)buffer);
}

static void as_move_instruction (register struct instruction *instruction,int size_flag)
{
	register UWORD opcode;
	UWORD buffer[14];
	register UWORD *code_buf_p,*end_buf_p;
	
	code_buf_p=buffer;
	end_buf_p=code_buf_p;
	*end_buf_p++=(LCODE<<8)+2;
	++end_buf_p;
	opcode= size_flag==SIZE_LONG ? 020000 : (size_flag==SIZE_WORD ? 030000 : 010000);
	
	switch (instruction->instruction_parameters[0].parameter_type){
		case P_REGISTER:
		{
			int reg=instruction->instruction_parameters[0].parameter_data.reg.r;
			if (is_d_register (reg))
				opcode |= 000 | d_reg_num (reg);
			else
				opcode |= 010 | a_reg_num (reg);
			break;
		}
		case P_INDIRECT:
		{
			int offset=instruction->instruction_parameters[0].parameter_offset;
			if (offset==0){
				opcode |= 020 | a_reg_num (instruction->instruction_parameters[0].parameter_data.reg.r);
			} else {
				opcode |= 050 | a_reg_num (instruction->instruction_parameters[0].parameter_data.reg.r);
				((UBYTE*)code_buf_p)[1]+=2;
				*end_buf_p++ = offset;
			}
			break;
		}
		case P_POST_INCREMENT:
			opcode |= 030 | a_reg_num (instruction->instruction_parameters[0].parameter_data.reg.r);
			break;
		case P_PRE_DECREMENT:
			opcode |= 040 | a_reg_num (instruction->instruction_parameters[0].parameter_data.reg.r);
			break;
		case P_LABEL:
		{
			LABEL *label;
			
			opcode |= 055;
			
			label=instruction->instruction_parameters[0].parameter_data.l;
			if (label->label_id<0)
				label->label_id=next_label_id++;
#ifdef USE_LABEL_VALUE
			*end_buf_p++=(LLABEL_VALUE<<8)+REFERENCE_A5;
			*end_buf_p++=label->label_id;
			code_buf_p=NULL;
#else
			*end_buf_p++=(LREFERENCE<<8)+REFERENCE_A5;
			*end_buf_p++=label->label_id;
			
			code_buf_p=end_buf_p;
			*end_buf_p++=(LCODE<<8)+2;
			*end_buf_p++=0;
#endif
			break;
		}
		case P_DESCRIPTOR_NUMBER:
		{
			LABEL *label;
			
			opcode |= 074;
			if (size_flag==SIZE_LONG){
				((UBYTE*)code_buf_p)[1]+=2;
				*end_buf_p++=0xffff;
			}
			
			label=instruction->instruction_parameters[0].parameter_data.l;
			if (label->label_id<0)
				label->label_id=next_label_id++;
#ifdef USE_LABEL_VALUE
			if (instruction->instruction_parameters[0].parameter_offset==0){
				*end_buf_p++=(LLABEL_VALUE<<8)+REFERENCE_A5;
				*end_buf_p++=label->label_id;
				code_buf_p=NULL;	
			} else {
#endif
			*end_buf_p++=(LREFERENCE<<8)+REFERENCE_A5;
			*end_buf_p++=label->label_id;
			
			code_buf_p=end_buf_p;
			*end_buf_p++=(LCODE<<8)+2;
			*end_buf_p++=instruction->instruction_parameters[0].parameter_offset << 2;
#ifdef USE_LABEL_VALUE
			}
#endif
			break;
		}
		case P_IMMEDIATE:
		{
			LONG i=instruction->instruction_parameters[0].parameter_data.i;
			
			/* MOVEQ ? */
			if (size_flag==SIZE_LONG && i<128 && i>=-128 
				&& instruction->instruction_parameters[1].parameter_type==P_REGISTER
				&& is_d_register (instruction->instruction_parameters[1].parameter_data.reg.r)){
					write_c (LCODE);
					write_c (2);
					write_c (0x70 | (d_reg_num 
						(instruction->instruction_parameters[1].parameter_data.reg.r)<<1));
					write_c (i);
					return;
			}
			
			/* CLR ? */
			if (i==0 && instruction->instruction_parameters[1].parameter_type!=P_REGISTER){
				buffer[0]=(LCODE<<8)+2;
				opcode=(size_flag==SIZE_LONG) ? 041200 : (size_flag==SIZE_WORD) ? 041100 : 041000 ;
			
				as_data_addressing_mode (opcode,buffer,buffer,&buffer[2],
										 &instruction->instruction_parameters[1],size_flag);
				return;
			}
			
			if (size_flag==SIZE_LONG){
				((UBYTE*)code_buf_p)[1]+=4;
				*(ULONG*)end_buf_p=i;
				end_buf_p+=2;
			} else {
				((UBYTE*)code_buf_p)[1]+=2;
				*end_buf_p++=i;
			}
			opcode |= 074;
			break;
		}
/* CHANGED 22-7-92 */
		case P_INDEXED:
		{
			struct index_registers *index_registers;
			int offset;
			
			offset=instruction->instruction_parameters[0].parameter_offset;
			
			index_registers=instruction->instruction_parameters[0].parameter_data.ir;
			
			((UBYTE*)code_buf_p)[1]+=2;
			*end_buf_p++ = 0x800 | (d_reg_num (index_registers->d_reg.r)<<12) 
							| ((offset>>2) & 0xff) | ((offset & 3)<<9);
			opcode |= 060 | a_reg_num (index_registers->a_reg.r);
			break;
		}
/* */
		default:
			internal_error_in_function ("as_move_instruction");
	}
	
	switch (instruction->instruction_parameters[1].parameter_type){
		case P_REGISTER:
		{
			int reg=instruction->instruction_parameters[1].parameter_data.reg.r;
			if (is_d_register (reg))
				opcode |= 0000 | (d_reg_num (reg)<<9);
			else
				opcode |= 0100 | (a_reg_num (reg)<<9);
			break;
		}
		case P_INDIRECT:
		{
			int offset=instruction->instruction_parameters[1].parameter_offset;
			if (offset==0){
				opcode |= 0200 | 
					(a_reg_num (instruction->instruction_parameters[1].parameter_data.reg.r)<<9);
			} else {
#ifdef USE_LABEL_VALUE
				if (code_buf_p==NULL){
					code_buf_p=end_buf_p;
					*end_buf_p++=LCODE<<8;
				}
#endif
				opcode |= 0500 | 
					(a_reg_num (instruction->instruction_parameters[1].parameter_data.reg.r)<<9);
				((UBYTE*)code_buf_p)[1]+=2;
				*end_buf_p++ = offset;
			}
			break;
		}
		case P_POST_INCREMENT:
			opcode |= 0300 | 
				(a_reg_num (instruction->instruction_parameters[1].parameter_data.reg.r)<<9);
			break;
		case P_PRE_DECREMENT:
			opcode |= 0400 | 
				(a_reg_num (instruction->instruction_parameters[1].parameter_data.reg.r)<<9);
			break;
		case P_LABEL:
		{
			LABEL *label;

			opcode |= 05200;
			
			label=instruction->instruction_parameters[1].parameter_data.l;
			if (label->label_id<0)
				label->label_id=next_label_id++;

#ifdef USE_LABEL_VALUE
			*end_buf_p++=(LLABEL_VALUE<<8)+REFERENCE_A5;
			*end_buf_p++=label->label_id;
#else
			*end_buf_p++=(LREFERENCE<<8)+REFERENCE_A5;
			*end_buf_p++=label->label_id;
			
			*end_buf_p++=(LCODE<<8)+2;
			*end_buf_p++=0;
#endif
			break;
		}
/* CHANGED 22-7-92 */
		case P_INDEXED:
		{
			struct index_registers *index_registers;
			int offset;

#ifdef USE_LABEL_VALUE
			if (code_buf_p==NULL){
				code_buf_p=end_buf_p;
				*end_buf_p++=LCODE<<8;
			}
#endif
			index_registers=instruction->instruction_parameters[1].parameter_data.ir;
			offset=instruction->instruction_parameters[1].parameter_offset;
			
			((UBYTE*)code_buf_p)[1]+=2;
			*end_buf_p++ = 0x800 | (d_reg_num (index_registers->d_reg.r)<<12)
							| ((offset>>2) & 0xff) | ((offset & 3)<<9);
			opcode |= 0600 | (a_reg_num (index_registers->a_reg.r)<<9);
			break;
		}
/* */
		default:
			internal_error_in_function ("as_move_instruction");
	}
	
	buffer[1]=opcode;
	write_block (buffer,(UBYTE*)end_buf_p-(UBYTE*)buffer);
}

static void as_lea_instruction (struct instruction *instruction)
{
	int opcode=040700 | (a_reg_num (instruction->instruction_parameters[1].parameter_data.reg.r)<<9);
	
	if (instruction->instruction_parameters[0].parameter_type==P_LABEL &&
		instruction->instruction_parameters[0].parameter_offset!=0)
	{
		UWORD buffer[10],*end_buf_p;
		LABEL *label;
		
		end_buf_p=buffer;
		*end_buf_p++=(LCODE<<8)+2;
		
		label=instruction->instruction_parameters[0].parameter_data.l;
		if (label->label_id<0)
			label->label_id=next_label_id++;
		
		if (label->label_flags & DATA_LABEL){
			opcode |= 055;
			*end_buf_p++=opcode;
			*end_buf_p++=(LREFERENCE<<8)+REFERENCE_A5;
		} else {
			*end_buf_p++=opcode;
			*end_buf_p++=(LREFERENCE<<8);
		}
		
		*end_buf_p++=label->label_id;
		*end_buf_p++=(LCODE<<8)+2;
		*end_buf_p++=instruction->instruction_parameters[0].parameter_offset;
		
		write_block (buffer,(UBYTE*)end_buf_p-(UBYTE*)buffer);	
	} else
		as_control_addressing_mode_instruction (&instruction->instruction_parameters[0],opcode);
}

static void as_add_instruction (struct instruction *instruction)
{
	int opcode;
	
	if (instruction->instruction_parameters[1].parameter_type==P_REGISTER){
		int reg=instruction->instruction_parameters[1].parameter_data.reg.r;

		/* ADDQ, SUBQ or LEA ? */
		if (instruction->instruction_parameters[0].parameter_type==P_IMMEDIATE){
			LONG i=instruction->instruction_parameters[0].parameter_data.i;
			
			if (i<=8 && i>=-8 && i!=0){
				write_c (LCODE);
				write_c (2);
				if (i>0)
					opcode=050200 | ((i & 7) << 9);
				else
					opcode=050600 | ((-i & 7) << 9);
				if (is_d_register (reg))
					opcode |= d_reg_num (reg);
				else
					opcode |= 010 | a_reg_num (reg);
				write_w (opcode);
				return;
			} else if (is_a_register (reg) && i>=-32768 && i<32768){
				write_c (LCODE);
				write_c (4);
				write_w (040750 | a_reg_num (reg) | (a_reg_num (reg)<<9));
				write_w (i);
				return;
			}
		}
		
		if (is_d_register (reg))
			opcode=0150200 + (d_reg_num (reg)<<9);
		else
			opcode=0150700 + (a_reg_num (reg)<<9);
			
		as_addressing_mode_instruction (&instruction->instruction_parameters[0],opcode,SIZE_LONG);
	} else if (instruction->instruction_parameters[0].parameter_type==P_REGISTER &&
		is_d_register (instruction->instruction_parameters[0].parameter_data.reg.r)){
			opcode=0150600 + 
				(d_reg_num (instruction->instruction_parameters[0].parameter_data.reg.r)<<9);
			as_alterable_memory_addressing_mode_instruction 
				(&instruction->instruction_parameters[1],opcode);
	} else
		/* ADDI not yet implemented */
		internal_error_in_function ("as_add_instruction");
}

static void as_sub_instruction (struct instruction *instruction)
{
	int opcode;
	
	if (instruction->instruction_parameters[1].parameter_type==P_REGISTER){
		int reg=instruction->instruction_parameters[1].parameter_data.reg.r;
		
		/* SUBQ, ADDQ or LEA ? */
		if (instruction->instruction_parameters[0].parameter_type==P_IMMEDIATE){
			LONG i=instruction->instruction_parameters[0].parameter_data.i;
			
			if (i<=8 && i>=-8 && i!=0){
				write_c (LCODE);
				write_c (2);
				if (i>0)
					opcode=050600 | ((i & 7) << 9);
				else
					opcode=050200 | ((-i & 7) << 9);
				if (is_d_register (reg))
					opcode |= d_reg_num (reg);
				else
					opcode |= 010 | a_reg_num (reg);
				write_w (opcode);
				return;
			} else if (is_a_register (reg) && i>-32768 && i<=32768){
				write_c (LCODE);
				write_c (4);
				write_w (040750 | a_reg_num (reg) | (a_reg_num (reg)<<9));
				write_w (-i);
				return;
			}

		}
		
		if (is_d_register (reg))
			opcode=0110200 + (d_reg_num (reg)<<9);
		else
			opcode=0110700 + (a_reg_num (reg)<<9);
			
		as_addressing_mode_instruction (&instruction->instruction_parameters[0],opcode,SIZE_LONG);
	} else if (instruction->instruction_parameters[0].parameter_type==P_REGISTER &&
		is_d_register (instruction->instruction_parameters[0].parameter_data.reg.r)){
			opcode=0110600 + 
				(d_reg_num (instruction->instruction_parameters[0].parameter_data.reg.r)<<9);
			as_alterable_memory_addressing_mode_instruction 
				(&instruction->instruction_parameters[1],opcode);
	} else
		/* SUBI not yet implemented */
		internal_error_in_function ("as_sub_instruction");
}

static void as_and_or_instruction (struct instruction *instruction,int opcode)
{
	UWORD buffer[14];
	int reg;
	
	if (instruction->instruction_parameters[1].parameter_type!=P_REGISTER ||
		is_a_register (reg=instruction->instruction_parameters[1].parameter_data.reg.r))
	{
		internal_error_in_function ("as_and_or_instruction");
		return;
	}
	
	opcode+=d_reg_num (reg)<<9;
							
	buffer[0]=(LCODE<<8)+2;	
	as_data_addressing_mode (opcode,buffer,buffer,&buffer[2],
							&instruction->instruction_parameters[0],SIZE_LONG);
}

static void as_eor_instruction (struct instruction *instruction)
{
	int reg_1,reg_2;
	
	if (instruction->instruction_parameters[1].parameter_type!=P_REGISTER ||
		is_a_register (reg_2=instruction->instruction_parameters[1].parameter_data.reg.r))
	{
		internal_error_in_function ("as_eor_instruction");
		return;
	}
	
	switch (instruction->instruction_parameters[0].parameter_type){
		case P_IMMEDIATE:
		{
			long m=instruction->instruction_parameters[0].parameter_data.i;
			
			if (m==-1){	/* replace EOR #-1,Dn by NOT Dn */
				write_c (LCODE);
				write_c (2);
				write_w (043200 | d_reg_num (reg_2));
			} else {
				write_c (LCODE);
				write_c (6);
				write_w (005200 | d_reg_num (reg_2));
				write_l (m);
			}
			return;
		}
		case P_REGISTER:
			if (is_d_register (reg_1=instruction->instruction_parameters[0].parameter_data.reg.r)){
				write_c (LCODE);
				write_c (2);
				write_w (0130600 | (d_reg_num (reg_1)<<9) | d_reg_num (reg_2));
				return;
			}
		default:
			internal_error_in_function ("as_eor_instruction");
	}
}

static void as_cmp_instruction (struct instruction *instruction,int size_flag)
{
	int opcode;
	
	if (instruction->instruction_parameters[1].parameter_type==P_REGISTER){
		int reg=instruction->instruction_parameters[1].parameter_data.reg.r;
		
		if (is_d_register (reg)){
			if (instruction->instruction_parameters[0].parameter_type==P_IMMEDIATE &&
				instruction->instruction_parameters[0].parameter_data.i==0){
				/* CMPI #0 becomes TST */
				write_c (LCODE);
				write_c (2);
				write_w ((size_flag==SIZE_LONG ? 045200 : 045100) | d_reg_num (reg));
				return;
			}
			opcode=0130200 + (d_reg_num (reg)<<9);
		} else
			opcode=0130700 + (a_reg_num (reg)<<9);
	
		as_addressing_mode_instruction (&instruction->instruction_parameters[0],opcode,size_flag);
	} else 
		switch (instruction->instruction_parameters[0].parameter_type){
			case P_IMMEDIATE:
			{
				UWORD buffer[14],*end_buf_p,opcode;
				LONG i;
				
				i=instruction->instruction_parameters[0].parameter_data.i;
				
				if (i==0){
					/* CMPI #0 becomes TST */
					buffer[0]=(LCODE<<8)+2;
					opcode= size_flag==SIZE_LONG ? 045200 : 045100;
					as_immediate_data_alterable_addressing_mode
						(opcode,buffer,buffer,&buffer[2],&instruction->instruction_parameters[1]);
				} else {
					if (size_flag==SIZE_LONG){
						buffer[0]=(LCODE<<8)+6;
						*(ULONG*)(&buffer[2])=i;
						end_buf_p=&buffer[4];
						opcode=06200;
					} else {
						buffer[0]=(LCODE<<8)+4;
						buffer[2]=i;
						end_buf_p=&buffer[3];
						opcode=06100;
					}
					as_immediate_data_alterable_addressing_mode
						(opcode,buffer,buffer,end_buf_p,&instruction->instruction_parameters[1]);
				}
				break;
			}
			case P_DESCRIPTOR_NUMBER:
			{
				UWORD buffer[14],*end_buf_p,*code_buf_p,opcode;
				LABEL *label;
			
				buffer[0]=(LCODE<<8)+2;
				code_buf_p=buffer;
				end_buf_p=&buffer[2];
				
				if (size_flag==SIZE_LONG){
					((UBYTE*)code_buf_p)[1]+=2;
					*end_buf_p++=0xffff;
					opcode=06200;
				} else
					opcode=06100;
				
				label=instruction->instruction_parameters[0].parameter_data.l;
				if (label->label_id<0)
					label->label_id=next_label_id++;
#ifdef USE_LABEL_VALUE
				if (instruction->instruction_parameters[0].parameter_offset==0){
					*end_buf_p++=(LLABEL_VALUE<<8)+REFERENCE_A5;
					*end_buf_p++=label->label_id;
					code_buf_p=NULL;
				} else {
#endif
				*end_buf_p++=(LREFERENCE<<8)+REFERENCE_A5;
				*end_buf_p++=label->label_id;
			
				code_buf_p=end_buf_p;
				*end_buf_p++=(LCODE<<8)+2;
				*end_buf_p++=instruction->instruction_parameters[0].parameter_offset << 2;
#ifdef USE_LABEL_VALUE
				}
#endif
				as_immediate_data_alterable_addressing_mode
					(opcode,buffer,code_buf_p,end_buf_p,&instruction->instruction_parameters[1]);
				break;
			}
			default:
				internal_error_in_function ("as_cmp_instruction");
		}
}

static void as_tst_instruction (struct instruction *instruction,int size_flag)
{
	UWORD buffer[14],opcode;
							
	buffer[0]=(LCODE<<8)+2;
	opcode=045200;
			
	as_data_addressing_mode (opcode,buffer,buffer,&buffer[2],
							&instruction->instruction_parameters[0],size_flag);
}

static void as_branch_instruction (struct instruction *instruction,int opcode)
{
	UWORD buffer[10];
	register UWORD *buf_p;
	LABEL *label;
	
	if (instruction->instruction_parameters[0].parameter_type!=P_LABEL)
		internal_error_in_function ("as_branch_instruction");
		
	label=instruction->instruction_parameters[0].parameter_data.l;
	if (label->label_id<0)
		label->label_id=next_label_id++;
	
	buf_p=buffer;
	*buf_p++=(LCODE<<8)+2;
	*buf_p++=opcode;

#if defined (USE_LABEL_VALUE) && !defined (GENERATE_MPW_OBJECT_CODE)
	*buf_p++=(LLABEL_VALUE<<8)+REFERENCE_PC;
	*buf_p++=label->label_id;
#else
	{
	int id;

	id=next_label_id++;
	*buf_p++=(LLABEL<<8);
	*buf_p++=id;
	*buf_p++=(LC_REFERENCE<<8)+LCR_WORD;
	*buf_p++=label->label_id;
	*buf_p++=id;
	*buf_p++=(LCODE<<8)+2;
	*buf_p++=0;
	}
#endif
	write_block (buffer,(UBYTE*)buf_p-(UBYTE*)buffer);
}

static void as_short_branch_instruction (struct instruction *instruction,int opcode)
{
	switch (instruction->instruction_parameters[0].parameter_type){
		case P_LABEL:
		{
			LABEL *label;
			UWORD buffer[10],*buf_p;
			int id;
			
			label=instruction->instruction_parameters[0].parameter_data.l;
			if (label->label_id<0)
				label->label_id=next_label_id++;
		
			id=next_label_id++;
			
			buf_p=buffer;
			*buf_p++=(LCODE<<8)+1;
			*buf_p++=opcode;
		
			*buf_p++=(LC_REFERENCE<<8)+LCR_BYTE;
			*buf_p++=label->label_id;
			*buf_p++=id;
		
			*buf_p++=(LCODE<<8)+1;
			*buf_p++=0;
		
			*buf_p++=(LLABEL<<8);
			*buf_p++=id;
		
			write_block (buffer,(UBYTE*)buf_p-(UBYTE*)buffer);
			return;
		}
		case P_IMMEDIATE:
		{
			int offset;
			
			offset=instruction->instruction_parameters[0].parameter_data.i;
					
			write_w ((LCODE<<8)+2);
			write_w (opcode+offset);
			return;
		}
		default:
			internal_error_in_function ("as_short_branch_instruction");
	}		
}

static void as_movem_instruction (struct instruction *instruction)
{
	UWORD opcode,register_list;
	UWORD buffer[10],*code_buf_p,*end_buf_p;
	register unsigned int n,arity;
	
	code_buf_p=buffer;
	end_buf_p=code_buf_p;
	*end_buf_p++=(LCODE<<8)+4;
	++end_buf_p;
	++end_buf_p;
	opcode=046300;
	
	switch (instruction->instruction_parameters[0].parameter_type){
		case P_INDIRECT:
		{
			int offset=instruction->instruction_parameters[0].parameter_offset;
			if (offset==0){
				opcode |= 020 | a_reg_num (instruction->instruction_parameters[0].parameter_data.reg.r);
			} else {
				opcode |= 050 | a_reg_num (instruction->instruction_parameters[0].parameter_data.reg.r);
				((UBYTE*)code_buf_p)[1]+=2;
				*end_buf_p++ = offset;
			}
			break;
		}
		case P_POST_INCREMENT:
			opcode |= 030 | a_reg_num (instruction->instruction_parameters[0].parameter_data.reg.r);
			break;
		case P_LABEL:
		{
			LABEL *label;
			
			opcode |= 055;
			
			label=instruction->instruction_parameters[0].parameter_data.l;
			if (label->label_id<0)
				label->label_id=next_label_id++;
#ifdef USE_LABEL_VALUE
			*end_buf_p++=(LLABEL_VALUE<<8)+REFERENCE_A5;
			*end_buf_p++=label->label_id;
#else
			*end_buf_p++=(LREFERENCE<<8)+REFERENCE_A5;
			*end_buf_p++=label->label_id;
			
			*end_buf_p++=(LCODE<<8)+2;
			*end_buf_p++=0;
#endif
			break;
		}
		case P_REGISTER:
		{
			int offset,reg;
			
			arity=instruction->instruction_arity;
		
			if (instruction->instruction_parameters[arity-1].parameter_type==P_PRE_DECREMENT){
				opcode = 044340 | a_reg_num (instruction->instruction_parameters[arity-1].parameter_data.reg.r);

				register_list=0;
				--arity;
				for (n=0; n<arity; ++n){
					register int reg;
					
					reg=instruction->instruction_parameters[n].parameter_data.reg.r;
					if (is_d_register (reg))
						register_list |= ((unsigned)0x8000>>d_reg_num (reg));
					else
						register_list |= ((unsigned)0x8000>>8+a_reg_num (reg));
				}
				
				buffer[1]=opcode;
				buffer[2]=register_list;
				write_block (buffer,(UBYTE*)end_buf_p-(UBYTE*)buffer);
				return;
			}
						
			if (instruction->instruction_arity!=2 
					|| instruction->instruction_parameters[1].parameter_type!=P_INDIRECT)
				internal_error_in_function ("as_movem_instruction");

			opcode=044300;
			offset=instruction->instruction_parameters[1].parameter_offset;
			if (offset==0){
				opcode |= 020 | a_reg_num (instruction->instruction_parameters[1].parameter_data.reg.r);
			} else {
				opcode |= 050 | a_reg_num (instruction->instruction_parameters[1].parameter_data.reg.r);
				((UBYTE*)code_buf_p)[1]+=2;
				*end_buf_p++ = offset;
			}
			
			reg=instruction->instruction_parameters[0].parameter_data.reg.r;
			if (is_d_register (reg))
				register_list = ((unsigned)1<<d_reg_num (reg));
			else
				register_list = ((unsigned)1<<8+a_reg_num (reg));
			
			buffer[1]=opcode;
			buffer[2]=register_list;
			write_block (buffer,(UBYTE*)end_buf_p-(UBYTE*)buffer);
			return;
		}
		default:
			internal_error_in_function ("as_movem_instruction");
	}
	
	register_list=0;
	
	arity=instruction->instruction_arity;
	for (n=1; n<arity; ++n){
		register int reg;
		
		reg=instruction->instruction_parameters[n].parameter_data.reg.r;
		if (is_d_register (reg))
			register_list |= ((unsigned)1<<d_reg_num (reg));
		else
			register_list |= ((unsigned)1<<8+a_reg_num (reg));
	}
	
	buffer[1]=opcode;
	buffer[2]=register_list;
	write_block (buffer,(UBYTE*)end_buf_p-(UBYTE*)buffer);
}

static void as_shift_instruction (struct instruction *instruction,int opcode)
{
	int reg_1,reg_2;
	
	if (instruction->instruction_parameters[1].parameter_type!=P_REGISTER ||
		!is_d_register (reg_2=instruction->instruction_parameters[1].parameter_data.reg.r))
	{
		internal_error_in_function ("as_shift_instruction");
		return;
	}
				
	switch (instruction->instruction_parameters[0].parameter_type){
		case P_IMMEDIATE:
		{
			LONG count;
			
			count=instruction->instruction_parameters[0].parameter_data.i;
		
			if (count<=0 || count>8)
				internal_error_in_function ("as_shift_instruction");
			
			write_c (LCODE);
			write_c (2);
			write_w (opcode | ((count & 7)<<9) | d_reg_num (reg_2));
			return;
		}
		case P_REGISTER:
			if (is_d_register (reg_1=instruction->instruction_parameters[0].parameter_data.reg.r)){
				write_c (LCODE);
				write_c (2);
				write_w (opcode | 040 | (d_reg_num (reg_1)<<9) | d_reg_num (reg_2));
				return;
			}
		default:
			internal_error_in_function ("as_shift_instruction");
	}
}

static void as_mul_instruction (struct instruction *instruction)
{
	UWORD buffer[14],opcode,reg;
							
	buffer[0]=(LCODE<<8)+4;
	reg=instruction->instruction_parameters[1].parameter_data.reg.r;
	buffer[2]=004000 | reg | (reg<<12);
	opcode=046000;
			
	as_data_addressing_mode (opcode,buffer,buffer,&buffer[3],
							&instruction->instruction_parameters[0],SIZE_LONG);
}

static void as_div_instruction (struct instruction *instruction)
{
	UWORD buffer[14],opcode,reg_n;
							
	buffer[0]=(LCODE<<8)+4;
	reg_n=d_reg_num (instruction->instruction_parameters[1].parameter_data.reg.r);
	buffer[2]=004000 | reg_n | (reg_n<<12);
	opcode=046100;
			
	as_data_addressing_mode (opcode,buffer,buffer,&buffer[3],
							&instruction->instruction_parameters[0],SIZE_LONG);
}

static void as_mod_instruction (struct instruction *instruction)
{
	UWORD buffer[14],opcode;
				
				
	buffer[0]=(LCODE<<8)+4;
	buffer[2]=004000 | instruction->instruction_parameters[1].parameter_data.reg.r
						| (instruction->instruction_parameters[2].parameter_data.reg.r<<12);
	opcode=046100;
			
	as_data_addressing_mode (opcode,buffer,buffer,&buffer[3],
							&instruction->instruction_parameters[0],SIZE_LONG);
}

static void as_bmove_instruction (struct instruction *instruction)
{
	UWORD buffer[5],opcode;
	
	buffer[0]=(LCODE<<8)+8;
	buffer[1]=0x6002;			/* BRA.S	*+4 */
	opcode=020000;
	switch (instruction->instruction_parameters[0].parameter_type){
		case P_POST_INCREMENT:
			opcode |= 030 | 
				a_reg_num (instruction->instruction_parameters[0].parameter_data.reg.r);
			break;
		case P_PRE_DECREMENT:
			opcode |= 040 |
				a_reg_num (instruction->instruction_parameters[0].parameter_data.reg.r);
			break;
		default:
			internal_error_in_function ("as_bmove_instruction");
	}
	switch (instruction->instruction_parameters[1].parameter_type){
		case P_POST_INCREMENT:
			opcode |= 0300 |
				(a_reg_num (instruction->instruction_parameters[1].parameter_data.reg.r)<<9);
			break;
		case P_PRE_DECREMENT:
			opcode |= 0400 |
				(a_reg_num (instruction->instruction_parameters[1].parameter_data.reg.r)<<9);
			break;
		default:
			internal_error_in_function ("as_bmove_instruction");
	}
	buffer[2]=opcode;	/* MOVE -(An)+,-(An)+ */
	buffer[3]=0x51c8+d_reg_num (instruction->instruction_parameters[2].parameter_data.reg.r);
	buffer[4]=-4;		/* DBRA Dn,*-2 */
	
	write_block (buffer,10);
}

static void as_exg_instruction (struct instruction *instruction)
{
	int opcode,reg_1,reg_2;
	
	reg_1=instruction->instruction_parameters[0].parameter_data.reg.r;
	reg_2=instruction->instruction_parameters[1].parameter_data.reg.r;
	if (is_d_register (reg_1))
		if (is_d_register (reg_2))
			opcode=0xc140+(d_reg_num (reg_1)<<9)+d_reg_num (reg_2);
		else
			opcode=0xc188+(d_reg_num (reg_1)<<9)+a_reg_num (reg_2);
	else
		if (is_d_register (reg_2))
			opcode=0xc188+(d_reg_num (reg_2)<<9)+a_reg_num (reg_1);
		else
			opcode=0xc148+(a_reg_num (reg_1)<<9)+a_reg_num (reg_2);
	
	write_c (LCODE);
	write_c (2);
	write_w (opcode);
}

static void as_extb_instruction (struct instruction *instruction)
{
	int reg;
	
	reg=d_reg_num (instruction->instruction_parameters[0].parameter_data.reg.r);

	if (!mc68000_flag){
		write_c (LCODE);
		write_c (2);
		write_w (044700 | d_reg_num (reg));
	} else {
		write_c (LCODE);
		write_c (4);
		write_w (044200 | d_reg_num (reg));
		write_w (044300 | d_reg_num (reg));
	}
}

static void as_ext_instruction (struct instruction *instruction)
{
	int reg=d_reg_num (instruction->instruction_parameters[0].parameter_data.reg.r);
	
	write_c (LCODE);
	write_c (2);
	write_w (044300+d_reg_num (reg));
}

static void as_set_condition_instruction (struct instruction *instruction,int opcode)
{
	int reg_1;
	
	if (instruction->instruction_parameters[0].parameter_type!=P_REGISTER ||
		!is_d_register (reg_1=instruction->instruction_parameters[0].parameter_data.reg.r))
	{
		internal_error_in_function ("as_set_condition_instruction");
		return;
	}
	
	if (!mc68000_flag){
		write_c (LCODE);
		write_c (4);
		write_w (opcode | d_reg_num (reg_1));
		write_w (044700 | d_reg_num (reg_1));
	} else {
		write_c (LCODE);
		write_c (6);
		write_w (opcode | d_reg_num (reg_1));
		write_w (044200 | d_reg_num (reg_1));
		write_w (044300 | d_reg_num (reg_1));
	}
}

static void as_fmove_instruction (struct instruction *instruction,int size_mask)
{
	if (instruction->instruction_parameters[0].parameter_type==P_F_REGISTER){
		int reg_1;
		
		reg_1=instruction->instruction_parameters[0].parameter_data.reg.r;
		
		if (instruction->instruction_parameters[1].parameter_type==P_F_REGISTER){
			int reg_2;
			
			reg_2=instruction->instruction_parameters[1].parameter_data.reg.r;
			write_c (LCODE);
			write_c (4);
			write_w (0xf200);
			write_w ((reg_1<<10) | (reg_2<<7));
		} else
			as_fp_instruction_p (0xf200,size_mask | 0x6000 | (reg_1<<7),
								 &instruction->instruction_parameters[1]);
	} else if (instruction->instruction_parameters[1].parameter_type==P_F_REGISTER){
		int reg_1;
		
		reg_1=instruction->instruction_parameters[1].parameter_data.reg.r;
		as_fp_instruction_p (0xf200,size_mask | 0x4000 | (reg_1<<7),
							 &instruction->instruction_parameters[0]);
	} else
		internal_error_in_function ("as_fmove_instruction");
}

static void as_fp_instruction (struct instruction *instruction,int function_code)
{
	int reg_1;
	
	if (instruction->instruction_parameters[1].parameter_type!=P_F_REGISTER){
		internal_error_in_function ("as_fp_instruction");
		return;
	}
	reg_1=instruction->instruction_parameters[1].parameter_data.reg.r;
		
	if (instruction->instruction_parameters[0].parameter_type==P_F_REGISTER){
		int reg_2;
		
		reg_2=instruction->instruction_parameters[0].parameter_data.reg.r;
		
		write_c (LCODE);
		write_c (4);
		write_w (0xf200);
		write_w (function_code | (reg_2<<10) | (reg_1<<7));
	} else
		as_fp_instruction_p (0xf200,function_code | (0x1400 | 0x4000) | (reg_1<<7),
							 &instruction->instruction_parameters[0]);
}

static void as_fp_set_condition_instruction (struct instruction *instruction,int c_code)
{
	as_fp_instruction_p (0171100,c_code,&instruction->instruction_parameters[0]);
	
	if (instruction->instruction_parameters[0].parameter_type==P_REGISTER){
		write_c (LCODE);
		write_c (2);
		write_w (044700 | d_reg_num (instruction->instruction_parameters[0].parameter_data.reg.r));
	}
}

static void as_jsr_schedule (int n_a_and_f_registers)
{
	write_c (LCODE);

	if (n_a_and_f_registers & 15){
		write_c (6);
		write_w (0xf227);
		if ((n_a_and_f_registers & 15)==1)
			write_w (0x6800);
		else
			write_w (0xe000 | (~(-1<<(n_a_and_f_registers & 15))) );
	} else
		write_c (2);

	write_w (047200);
	
	switch (n_a_and_f_registers>>4){
		case 0:		store_text_label_in_text_section (schedule_0_label);	break;
		case 1:		store_text_label_in_text_section (schedule_1_label);	break;
		case 2:		store_text_label_in_text_section (schedule_2_label);	break;
		case 3:		store_text_label_in_text_section (schedule_3_label);	break;
		case 256>>4:store_text_label_in_text_section (schedule_eval_label);	break;
		default:	internal_error_in_function ("as_jsr_schedule");
	}
	
	if (n_a_and_f_registers & 15){
		write_c (LCODE);
		write_c (4);
		write_w (0xf21f);
		if ((n_a_and_f_registers & 15)==1)
			write_w (0x4800);
		else
			write_w (0xd000 | ((0xff>>(n_a_and_f_registers & 15)) ^ 0xff) );
	}	
}

static void as_jmp_instruction (struct instruction *instruction)
{
	if (instruction->instruction_parameters[0].parameter_type==P_LABEL
		&& instruction->instruction_parameters[0].parameter_data.l->label_flags & LOCAL_LABEL)
	{
		if (parallel_flag){
			/* DBRA D6, */
			as_branch_instruction (instruction,0x51CE);
			/* JSR schedule */
			as_jsr_schedule (instruction->instruction_parameters[0].parameter_offset);
			/* BRA */
			as_branch_instruction (instruction,0x6000);
		} else
			as_branch_instruction (instruction,0x6000);
	} else {
		if (parallel_flag){
			int n_a_and_f_registers;

			if (instruction->instruction_parameters[0].parameter_type==P_LABEL)
				n_a_and_f_registers=instruction->instruction_parameters[0].parameter_offset;
			else
				n_a_and_f_registers=instruction->instruction_parameters[0].parameter_data.reg.u;

			if (n_a_and_f_registers!=128){
				/* DBRA D6,2+n(PC) */
				write_c (LCODE);
				write_c (4);
				write_w (0x51CE);
				
				if (n_a_and_f_registers & 15)
					write_w (14);
				else
					write_w (6);
				
				as_jsr_schedule (n_a_and_f_registers);
			}
		}
		as_control_addressing_mode_instruction (&instruction->instruction_parameters[0],047300);
	}
}

static void as_jsr_instruction (struct instruction *instruction)
{
	if (instruction->instruction_parameters[0].parameter_type==P_LABEL
		&& instruction->instruction_parameters[0].parameter_data.l->label_flags & LOCAL_LABEL)
	{
		if (parallel_flag){
			int n_a_and_f_registers;
			
			n_a_and_f_registers=instruction->instruction_parameters[0].parameter_offset;
			
			/* PEA 2+n(PC) */
			write_c (LCODE);
			write_c (4);
			write_w (044172);
			
			if (n_a_and_f_registers & 15)
				write_w (22);
			else
				write_w (14);
	
			/* DBRA D6, */
			as_branch_instruction (instruction,0x51CE);
			as_jsr_schedule (n_a_and_f_registers);
			/* BRA */
			as_branch_instruction (instruction,0x6000);
		} else
			as_branch_instruction (instruction,0x6100);
	} else {
		if (parallel_flag){
			int n_a_and_f_registers;

			if (instruction->instruction_parameters[0].parameter_type==P_LABEL)
				n_a_and_f_registers=instruction->instruction_parameters[0].parameter_offset;
			else
				n_a_and_f_registers=instruction->instruction_parameters[0].parameter_data.reg.u;

			/* DBRA D6,2+n(PC) */
			write_c (LCODE);
			write_c (4);
			write_w (0x51CE);
			
			if (n_a_and_f_registers & 15)
				write_w (14);
			else
				write_w (6);
			
			as_jsr_schedule (n_a_and_f_registers);
		}
		as_control_addressing_mode_instruction (&instruction->instruction_parameters[0],047200);
	}
}

struct call_and_jump {
	struct call_and_jump *cj_next;
	WORD cj_label_id;
	WORD cj_call_id;
	WORD cj_jump_id;
};

static struct call_and_jump *first_call_and_jump,*last_call_and_jump;

static void as_garbage_collect_test (register struct basic_block *block)
{
	int n_cells,label_id_1,label_id_2;
	struct call_and_jump *new_call_and_jump;

	label_id_1=next_label_id++;
	label_id_2=next_label_id++;
	
	new_call_and_jump=(struct call_and_jump*)allocate_memory_from_heap (sizeof (struct call_and_jump));
	
	new_call_and_jump->cj_next=NULL;
	new_call_and_jump->cj_label_id=label_id_1;
	new_call_and_jump->cj_jump_id=label_id_2;
	switch (block->block_n_begin_a_parameter_registers){
		case 0:		new_call_and_jump->cj_call_id=collect_0_label->label_id;	break;
		case 1:		new_call_and_jump->cj_call_id=collect_1_label->label_id;	break;
		case 2:		new_call_and_jump->cj_call_id=collect_2_label->label_id;	break;
		case 3:		new_call_and_jump->cj_call_id=collect_3_label->label_id;	break;
		default:	internal_error_in_function ("as_garbage_collect_test");
	}
	
	if (first_call_and_jump!=NULL)
		last_call_and_jump->cj_next=new_call_and_jump;
	else
		first_call_and_jump=new_call_and_jump;
	last_call_and_jump=new_call_and_jump;

	n_cells=block->block_n_new_heap_cells;
	if (n_cells<=8){
		/* SUBQ.L #n,D7 */
		write_c (LCODE);	
		write_c (4);
		write_w (050607+((n_cells & 7)<<9));
	} else if (n_cells<128
				&&	block->block_n_begin_d_parameter_registers <
					(parallel_flag ? N_DATA_PARAMETER_REGISTERS-1 : N_DATA_PARAMETER_REGISTERS))
	{
		write_c (LCODE);
		write_c (6);
		if (parallel_flag){
			/* MOVEQ #n,D5 */
			/* SUB.L D5,D7 */
			write_w (075000+n_cells);
			write_w (0117205);
		} else {
			/* MOVEQ #n,D6 */
			/* SUB.L D6,D7 */
			write_w (076000+n_cells);
			write_w (0117206);
		}
	} else {
		/* SUB.L #n,D7 */
		write_c (LCODE);
		write_c (8);
		write_w (0117274);
		write_l (n_cells);
	}
	
	/* BCS */
	write_c (0x65);
	write_c (0);
#if defined (USE_LABEL_VALUE) && !defined (GENERATE_MPW_OBJECT_CODE)
	write_c (LLABEL_VALUE);
	write_c (REFERENCE_PC);
	write_w (label_id_1);
#else	/* l3 */
	{
	int label_id;

	label_id=next_label_id++;
	define_local_text_label (label_id);
	/* l1 - l3 */
	write_c (LC_REFERENCE);
	write_c (LCR_WORD);
	write_w (label_id_1);
	write_w (label_id);
	write_c (LCODE);
	write_c (2);
	write_w (0);
	}
#endif
	
	/* l2 */
	define_local_text_label (label_id_2);
}

static void as_call_and_jump (struct call_and_jump *call_and_jump)
{
	/* l1 */
	define_local_text_label (call_and_jump->cj_label_id);
	/* JSR collect_n */
	write_c (LCODE);
	write_c (2);
	write_w (047200);
#ifdef USE_LABEL_VALUE
	write_c (LLABEL_VALUE);
#else
	write_c (LREFERENCE);
#endif
	write_c (0);
	write_w (call_and_jump->cj_call_id);
	write_c (LCODE);
#ifdef USE_LABEL_VALUE
	write_c (2);
#else
	write_c (4);
	write_w (0);
#endif
	/* JMP l2 */
	write_w (047300);
#ifdef USE_LABEL_VALUE
	write_c (LLABEL_VALUE);
	write_c (0);
	write_w (call_and_jump->cj_jump_id);
#else
	write_c (LREFERENCE);
	write_c (0);
	write_w (call_and_jump->cj_jump_id);
	write_c (LCODE);
	write_c (2);
	write_w (0);
#endif
}

static int local_stack_overflow_id;

static void init_stack_checking (VOID)
{
	local_stack_overflow_id=next_label_id++;
	define_local_text_label (local_stack_overflow_id);
		
	write_c (LCODE);
	write_c (2);
	write_w (047300);

#ifdef USE_LABEL_VALUE
	write_c (LLABEL_VALUE);
	write_c (0);
	write_w (stack_overflow_label->label_id);
#else
	write_c (LREFERENCE);
	write_c (0);
	write_w (stack_overflow_label->label_id);
	
	write_c (LCODE);
	write_c (2);
	write_w (0);
#endif
}

#define EXTRA_STACK_SPACE 2000 /* 300 */

static void as_check_stack (register struct basic_block *block)
{
	int size,n_d_parameters,n_a_parameters;
	int label_id,label_id_1,label_id_2;

	label_id=next_label_id++;

	if (parallel_flag){
		struct call_and_jump *new_call_and_jump;

		label_id_1=next_label_id++;
		label_id_2=next_label_id++;

		new_call_and_jump=(struct call_and_jump*)allocate_memory_from_heap (sizeof (struct call_and_jump));

		new_call_and_jump->cj_next=NULL;
		new_call_and_jump->cj_label_id=label_id_1;
		new_call_and_jump->cj_jump_id=label_id_2;
		switch (block->block_n_begin_a_parameter_registers){
			case 0:		new_call_and_jump->cj_call_id=realloc_0_label->label_id;	break;
			case 1:		new_call_and_jump->cj_call_id=realloc_1_label->label_id;	break;
			case 2:		new_call_and_jump->cj_call_id=realloc_2_label->label_id;	break;
			case 3:		new_call_and_jump->cj_call_id=realloc_3_label->label_id;	break;
			default:	internal_error_in_function ("as_garbage_collect_test");
		}

		if (first_call_and_jump!=NULL)
			last_call_and_jump->cj_next=new_call_and_jump;
		else
			first_call_and_jump=new_call_and_jump;
		last_call_and_jump=new_call_and_jump;
	}
	
	size=block->block_stack_check_size;
/*	if (parallel_flag) */
		size+=EXTRA_STACK_SPACE;
	n_d_parameters=block->block_n_begin_d_parameter_registers;
	n_a_parameters=block->block_n_begin_a_parameter_registers;
	
	if (size<=4){
		write_c (LCODE);
		write_c (4);
		/* CMPA.L A_STACK_POINTER,B_STACK_POINTER */
		write_w (0130710+a_reg_num (A_STACK_POINTER)+(a_reg_num (B_STACK_POINTER)<<9));
		/* BLS */
		write_w (0x6300);
	} else if (size<=127
			&&	n_d_parameters <
				(parallel_flag ? N_DATA_PARAMETER_REGISTERS-1 : N_DATA_PARAMETER_REGISTERS))
	{
		write_c (LCODE);
		write_c (8);
		if (parallel_flag){
			/* MOVEQ #size,D5 */
			write_w (0x7000+(d_reg_num (REGISTER_D5)<<9)+size);
			/* ADD.L A_STACK_POINTER,D5 */
			write_w (0150210+a_reg_num (A_STACK_POINTER)+(5<<9));
			/* CMP.L B_STACK_POINTER,D5 */
			write_w (0130210+a_reg_num (B_STACK_POINTER)+(5<<9));
		} else {
			/* MOVEQ #size,D6 */
			write_w (0x7000+(d_reg_num (REGISTER_D6)<<9)+size);
			/* ADD.L A_STACK_POINTER,D6 */
			write_w (0150210+a_reg_num (A_STACK_POINTER)+(6<<9));
			/* CMP.L B_STACK_POINTER,D6 */
			write_w (0130210+a_reg_num (B_STACK_POINTER)+(6<<9));		
		}
		/* BHI */
		write_w (0x6200);
	} else if (n_a_parameters<N_ADDRESS_PARAMETER_REGISTERS){
		write_c (LCODE);
		write_c (8);
		/* LEA size(A_STACK_POINTER),A2 */
		write_w (040750 + (2<<9) + a_reg_num (A_STACK_POINTER));
		write_w (size);
		/* CMPA.L B_STACK_POINTER,A2 */
		write_w (0130710+a_reg_num (B_STACK_POINTER)+(2<<9));
		/* BHI */
		write_w (0x6200);
	} else {
		write_c (LCODE);
		write_c (10);
		/* SUBA.L B_STACK_POINTER,A_STACK_POINTER */
		write_w (0110710+a_reg_num (B_STACK_POINTER)+(a_reg_num (A_STACK_POINTER)<<9));
		/* CMPA.W #-size,A_STACK_POINTER */
		write_w (0130374+(a_reg_num (A_STACK_POINTER)<<9));
		write_w (-size);
		/* ADDA.L B_STACK_POINTER,A_STACK_POINTER */
		write_w (0150710+a_reg_num (B_STACK_POINTER)+(a_reg_num (A_STACK_POINTER)<<9));
		/* BGT */
		write_w (0x6E00);
	}
	
	define_local_text_label (label_id);
	
	write_c (LC_REFERENCE);
	write_c (LCR_WORD);
	
	if (!parallel_flag){
		write_w (local_stack_overflow_id);
		write_w (label_id);
		write_c (LCODE);
		write_c (2);
		write_w (0);
	} else {
		write_w (label_id_1);
		write_w (label_id);
		write_c (LCODE);
		write_c (2);
		write_w (0);

		define_local_text_label (label_id_2);
	}
}

static void as_word_instruction (struct instruction *instruction)
{
	write_w ((LCODE<<8)+2);
	write_w ((int)instruction->instruction_parameters[0].parameter_data.i);
}

static void write_instructions (struct instruction *instructions)
{
	register struct instruction *instruction;
	
	for (instruction=instructions; instruction!=NULL; instruction=instruction->instruction_next){
		switch (instruction->instruction_icode){
			case IMOVE:
				as_move_instruction (instruction,SIZE_LONG);
				break;
			case ILEA:
				as_lea_instruction (instruction);
				break;
			case IADD:
				as_add_instruction (instruction);
				break;
			case ISUB:
				as_sub_instruction (instruction);
				break;
			case ICMP:
				as_cmp_instruction (instruction,SIZE_LONG);
				break;
			case ITST:
				as_tst_instruction (instruction,SIZE_LONG);
				break;
			case ITSTB:
				as_tst_instruction (instruction,SIZE_BYTE);
				break;
			case IJMP:
				as_jmp_instruction (instruction);
				break;
			case IJSR:
				as_jsr_instruction (instruction);
				break;
			case IRTS:
#ifdef COUNT_RELEASES
				if (parallel_flag && instruction->instruction_arity){
					write_c (LCODE);
					write_c (2);
					write_w (0x52ad);

					write_c (LLABEL_VALUE);
					write_c (REFERENCE_A5);
					write_w (node_entry_count_label_id);
				}
#endif
				write_w ((LCODE<<8)+2);
				write_w (047165);
				break;
			case IBGE:
				as_branch_instruction (instruction,0x6C00);
				break;
			case IBGT:
				as_branch_instruction (instruction,0x6E00);
				break;
			case IBHS:
				as_branch_instruction (instruction,0x6400);
				break;
			case IBLE:
				as_branch_instruction (instruction,0x6F00);
				break;
			case IBLT:
				as_branch_instruction (instruction,0x6D00);
				break;
			case IBEQ:
				as_branch_instruction (instruction,0x6700);
				break;
			case IBNE:
				as_branch_instruction (instruction,0x6600);
				break;
			case IBMI:
				as_short_branch_instruction (instruction,0x6b00);
				break;
			case IMOVEM:
				as_movem_instruction (instruction);
				break;
			case IMOVEW:
				as_move_instruction (instruction,SIZE_WORD);
				break;
			case IMOVEB:
				as_move_instruction (instruction,SIZE_BYTE);
				break;
			case ICMPW:
				as_cmp_instruction (instruction,SIZE_WORD);
				break;
			case ILSL:
				as_shift_instruction (instruction,0160610);
				break;
			case ILSR:
				as_shift_instruction (instruction,0160210);
				break;
			case IASR:
				as_shift_instruction (instruction,0160200);
				break;
			case IMUL:
				as_mul_instruction (instruction);
				break;
			case IDIV:
				as_div_instruction (instruction);
				break;
			case IMOD:
				as_mod_instruction (instruction);
				break;
			case IBMOVE:
				as_bmove_instruction (instruction);
				break;
			case IEXG:
				as_exg_instruction (instruction);
				break;
			case IAND:
				as_and_or_instruction (instruction,0140200);
				break;
			case IOR:
				as_and_or_instruction (instruction,0100200);
				break;
			case IEOR:
				as_eor_instruction (instruction);
				break;
			case ISEQ:
				as_set_condition_instruction (instruction,0x57c0);
				break;
			case ISGE:
				as_set_condition_instruction (instruction,0x5cc0);
				break;
			case ISGT:
				as_set_condition_instruction (instruction,0x5ec0);
				break;
			case ISLE:
				as_set_condition_instruction (instruction,0x5fc0);
				break;
			case ISLT:
				as_set_condition_instruction (instruction,0x5dc0);
				break;
			case ISNE:
				as_set_condition_instruction (instruction,0x56c0);
				break;	
			case IFMOVE:
				as_fmove_instruction (instruction,0x1400);
				break;
			case IFADD:
				as_fp_instruction (instruction,0x22);
				break;
			case IFSUB:
				as_fp_instruction (instruction,0x28);
				break;
			case IFCMP:
				as_fp_instruction (instruction,0x38);
				break;
			case IFDIV:
				as_fp_instruction (instruction,0x20);
				break;
			case IFMUL:
				as_fp_instruction (instruction,0x23);
				break;
			case IFREM:
				as_fp_instruction (instruction,0x25);
				break;
			case IFBEQ:
				as_branch_instruction (instruction,0xf281);
				break;
			case IFBGE:
				as_branch_instruction (instruction,0xf293);
				break;
			case IFBGT:
				as_branch_instruction (instruction,0xf292);
				break;
			case IFBLE:
				as_branch_instruction (instruction,0xf295);
				break;
			case IFBLT:
				as_branch_instruction (instruction,0xf294);
				break;
			case IFBNE:
				as_branch_instruction (instruction,0xf28e);
				break;
			case IFMOVEL:
				as_fmove_instruction (instruction,0);
				break;
			case IFACOS:
				as_fp_instruction (instruction,0x1c);
				break;
			case IFASIN:
				as_fp_instruction (instruction,0x0c);
				break;
			case IFATAN:
				as_fp_instruction (instruction,0x0a);
				break;
			case IFCOS:
				as_fp_instruction (instruction,0x1d);
				break;
			case IFEXP:
				as_fp_instruction (instruction,0x10);
				break;
			case IFLN:
				as_fp_instruction (instruction,0x14);
				break;
			case IFLOG10:
				as_fp_instruction (instruction,0x15);
				break;
			case IFNEG:
				as_fp_instruction (instruction,0x1a);
				break;
			case IFSIN:
				as_fp_instruction (instruction,0xe);
				break;
			case IFSQRT:
				as_fp_instruction (instruction,4);
				break;
			case IFTAN:
				as_fp_instruction (instruction,0xf);
				break;
			case IFSEQ:
				as_fp_set_condition_instruction (instruction,1);
				break;
			case IFSGE:
				as_fp_set_condition_instruction (instruction,0x13);
				break;
			case IFSGT:
				as_fp_set_condition_instruction (instruction,0x12);
				break;
			case IFSLE:
				as_fp_set_condition_instruction (instruction,0x15);
				break;
			case IFSLT:
				as_fp_set_condition_instruction (instruction,0x14);
				break;
			case IFSNE:
				as_fp_set_condition_instruction (instruction,0xe);
				break;
			case IWORD:
				as_word_instruction (instruction);
				break;
			case ISCHEDULE:
				as_jsr_schedule (instruction->instruction_parameters[0].parameter_data.i);
				break;
			case IEXTB:
				as_extb_instruction (instruction);
				break;
			case IEXT:
				as_ext_instruction (instruction);
				break;
			case IFTST:
			default:
				internal_error_in_function ("write_instructions");
		}
	}
}

static void write_code()
{
	register struct basic_block *block;
	register struct call_and_jump *call_and_jump;

	release_heap();
	
	first_call_and_jump=NULL;

	for_all (block,first_block,block_next){
#ifdef MODULES
		if (block->block_begin_module)
			start_new_module (block->block_link_module != 0);
#endif
		if (block->block_n_node_arguments>-100){
			LABEL *label;
			
			label=block->block_descriptor;

#ifdef CLOSURE_NAMES
			if (label!=NULL && block->block_descriptor_or_string!=0){
				unsigned char *string_p;
				char *string;
				ULONG string_length;
				int length;
				
				string=(char*)block->block_descriptor;
				string_length=strlen (string);
				
				string_p=(unsigned char*)string;
				length=string_length;

				write_c (LCODE);
				write_c ((string_length+7) & ~3);
				
				while (length>=4){
					write_l (*(ULONG*)string_p);
					string_p+=4;
					length-=4;
				}
				
				if (length>0){
					ULONG d;
					int shift;
							
					d=0;
					shift=24;
					while (length>0){
						d |= ((ULONG)string_p[0])<<shift;
						shift-=8;
						--length;
						++string_p;
					}
					write_l (d);
				}
				
				write_l ((string_length<<2) | (string_length<<10) | (string_length<<18) | (string_length<<26) | 0x00010203);
			}
#endif

			if (block->block_ea_label!=NULL){
				int n_node_arguments;
				extern LABEL *eval_fill_label,*eval_upd_labels[];

				n_node_arguments=block->block_n_node_arguments;
				if (n_node_arguments<-2)
					n_node_arguments=1;

				if (n_node_arguments>=0 && block->block_ea_label!=eval_fill_label){
					write_c (LCODE);
					write_c (2);
					write_w (042700);
	
					write_c (LLABEL_VALUE);
					write_c (0);
					if (block->block_ea_label->label_id<0)
						block->block_ea_label->label_id=next_label_id++;
					write_w (block->block_ea_label->label_id);
	
					write_c (LCODE);
					write_c (2);
					write_w (047300);
	
					write_c (LLABEL_VALUE);
					write_c (0);
					write_w (eval_upd_labels[n_node_arguments]->label_id);	
				} else {
					write_c (LCODE);
					write_c (2);
					write_w (047300);
	
					write_c (LLABEL_VALUE);
					write_c (0);
					if (block->block_ea_label->label_id<0)
						block->block_ea_label->label_id=next_label_id++;
					write_w (block->block_ea_label->label_id);
	
					write_c (LCODE);
					write_c (4);
					write_w (0x4e71);
					write_w (0x4e71);
				}
				if (block->block_descriptor!=NULL
					&& (block->block_n_node_arguments<0 || parallel_flag))
				{
					if (label->label_id<0)
						label->label_id=next_label_id++;
					store_label_offset_in_code_section (label->label_id);
				} else
					write_number_of_arguments (0);
			} else
				if (label!=NULL
					&& (block->block_n_node_arguments<0 || parallel_flag))
				{
					if (label->label_id<0)
						label->label_id=next_label_id++;
					store_label_offset_in_code_section (label->label_id);
				} 
				/* else
					write_number_of_arguments (0); */

			write_number_of_arguments (block->block_n_node_arguments);
		}
		
		write_labels (block->block_labels);
		if (block->block_n_new_heap_cells>0)
			as_garbage_collect_test (block);
		if (check_stack && block->block_stack_check_size>0)
			as_check_stack (block);
		write_instructions (block->block_instructions);
	}
	
	for_all (call_and_jump,first_call_and_jump,cj_next)
	{
#ifdef MODULES
		start_new_module (0);
#endif
		as_call_and_jump (call_and_jump);
	}
	
	release_heap();
}

void write_version_and_options (int version,int options)
{
#ifndef GENERATE_MPW_OBJECT_CODE
	putc (LCOMMENT,output_file);
	putc (4,output_file);

	putc (version>>8,output_file);
	putc (version,output_file);

	putc (options>>8,output_file);
	putc (options,output_file);
#endif
}

void write_depend (char *module_name)
{
#ifndef GENERATE_MPW_OBJECT_CODE
	int l,n;
	
	l=strlen (module_name);
	putc (LCOMMENT,output_file);
	putc (l,output_file);
	
	for (n=0; n<l; ++n)
		putc (module_name[n],output_file);

	if (l & 1)
		putc (0,output_file);
#endif
}

void initialize_assembler (FILE *output_file_d)
{
	output_file=output_file_d;

	setvbuf (output_file,NULL,_IOFBF,IO_BUFFER_SIZE);

	initialize_object_buffers();

#ifndef GENERATE_MPW_OBJECT_CODE
	putc (LBEGIN,output_file);
	putc (0,output_file);
	putc (0,output_file);
	putc (0,output_file);
#else
	write_c (LBEGIN);
	write_c (0);
	write_w (0);
#endif

	if (check_stack && !parallel_flag)
		init_stack_checking();
}

void assemble_code ()
{	
	import_labels (labels);

	write_indirect_jumps_for_defer_labels();

#ifdef COUNT_RELEASES
	if (parallel_flag){
		node_entry_count_label_id=next_label_id++;
		import_label (node_entry_count_label_id,"node_entry_count");
	}
#endif

	if (index_error_label!=NULL && !(index_error_label->label_flags & EXPORT_LABEL)){
		int new_index_error_label;
		
		new_index_error_label=next_label_id++;
		define_local_text_label (new_index_error_label);
		
		write_w ((LCODE<<8)+2);
		write_w (047300);
		
		write_w (LLABEL_VALUE<<8);
		write_w (index_error_label->label_id);
		
		index_error_label->label_id=new_index_error_label;
	}

	write_code();
	
	write_c (LEND);
	write_c (0);
	
	flush_object_buffer();
	
	optimize_buffers();

#ifdef GENERATE_MPW_OBJECT_CODE
	convert_to_mpw_object_code();
#endif
	
	write_object_buffers_and_release_memory();

#ifndef GENERATE_MPW_OBJECT_CODE
	fseek (output_file,2l,0);

	putc (next_label_id>>8,output_file);
	putc (next_label_id,output_file);
#endif
}

#endif