158 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* $Header$ */
 | 
						|
/*	B L O C K   S T O R I N G   A N D   L O A D I N G	*/
 | 
						|
 | 
						|
#include <em.h>
 | 
						|
#include "arith.h"
 | 
						|
#include "sizes.h"
 | 
						|
#include "atw.h"
 | 
						|
#ifndef STB
 | 
						|
#include "label.h"
 | 
						|
#include "stack.h"
 | 
						|
#endif STB
 | 
						|
 | 
						|
/*	Because EM does not support the loading and storing of
 | 
						|
	objects having other sizes than word fragment and multiple,
 | 
						|
	we need to have a way of transferring these objects, whereby
 | 
						|
	we simulate "loi" and "sti": the address of the source resp.
 | 
						|
	destination is located on top of stack and a call is done
 | 
						|
	to load_block() resp. store_block().
 | 
						|
	===============================================================
 | 
						|
	# Loadblock() works on the stack as follows: ([ ] indicates the
 | 
						|
	# position of the stackpointer)
 | 
						|
	# lower address--->
 | 
						|
	# 1)	| &object
 | 
						|
	# 2)	| ... ATW(sz) bytes ... | sz | &stack_block | &object
 | 
						|
	# 3)	| ... ATW(sz) bytes ...
 | 
						|
	===============================================================
 | 
						|
	Loadblock() pushes ATW(sz) bytes directly onto the stack!
 | 
						|
 | 
						|
	Store_block() works on the stack as follows:
 | 
						|
	lower address--->
 | 
						|
	1)	| ... ATW(sz) bytes ... | &object
 | 
						|
	2)	| ... ATW(sz) bytes ... | &object | &stack_block | sz
 | 
						|
	3)	<empty>
 | 
						|
 | 
						|
	If sz is a legal argument for "loi" or "sti", just one EM
 | 
						|
	instruction is generated.
 | 
						|
	In the other cases, the notion of alignment is taken into account:
 | 
						|
	we only push an object of the size accepted by EM onto the stack,
 | 
						|
	while we need a loop to store the stack block into a memory object.
 | 
						|
*/
 | 
						|
store_block(sz, al)
 | 
						|
	arith sz;
 | 
						|
	int al;
 | 
						|
{
 | 
						|
	if (
 | 
						|
		((sz == al) && (word_align % al == 0)) ||
 | 
						|
		(
 | 
						|
			(sz % word_size == 0 || word_size % sz == 0) &&
 | 
						|
			(al % word_align == 0)
 | 
						|
		)
 | 
						|
	)	/* Lots of Irritating Stupid Parentheses */
 | 
						|
		C_sti(sz);
 | 
						|
	else {
 | 
						|
#ifndef STB
 | 
						|
		arith src, dst, src_offs, dst_offs;
 | 
						|
 | 
						|
		/* allocate two pointer temporaries */
 | 
						|
		src = tmp_pointer_var(&src_offs);
 | 
						|
		dst = tmp_pointer_var(&dst_offs);
 | 
						|
 | 
						|
		/* load the addresses */
 | 
						|
		C_lal(dst);
 | 
						|
		C_sti(pointer_size);
 | 
						|
		C_lor((arith)1);	/* push current sp */
 | 
						|
		C_lal(src);
 | 
						|
		C_sti(pointer_size);
 | 
						|
		copy_loop(sz, src, dst);
 | 
						|
		C_asp(ATW(sz));
 | 
						|
		free_tmp_var(dst_offs);
 | 
						|
		free_tmp_var(src_offs);
 | 
						|
#else STB
 | 
						|
		/*	address of destination lies on the stack	*/
 | 
						|
 | 
						|
		/*	push address of first byte of block on stack onto
 | 
						|
			the stack by computing it from the current stack
 | 
						|
			pointer position
 | 
						|
		*/
 | 
						|
		C_lor((arith)1);	/* push current sp		*/
 | 
						|
		C_adp(pointer_size);	/* set & to 1st byte of block	*/
 | 
						|
		C_loc(sz);		/* number of bytes to transfer	*/
 | 
						|
		C_cal("__stb");		/* call transfer routine	*/
 | 
						|
		C_asp(pointer_size + pointer_size + int_size + ATW(sz));
 | 
						|
#endif STB
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
load_block(sz, al)
 | 
						|
	arith sz;
 | 
						|
	int al;
 | 
						|
{
 | 
						|
	arith esz = ATW(sz);	/* effective size == actual # pushed bytes */
 | 
						|
 | 
						|
	if ((sz == al) && (word_align % al == 0))
 | 
						|
		C_loi(sz);
 | 
						|
	else
 | 
						|
	if (al % word_align == 0)
 | 
						|
		C_loi(esz);
 | 
						|
	else {
 | 
						|
#ifndef STB
 | 
						|
		arith src, dst, src_offs, dst_offs;
 | 
						|
 | 
						|
		/* allocate two pointer temporaries */
 | 
						|
		src = tmp_pointer_var(&src_offs);
 | 
						|
		dst = tmp_pointer_var(&dst_offs);
 | 
						|
 | 
						|
		C_lal(src);
 | 
						|
		C_sti(pointer_size);
 | 
						|
		C_asp(-esz);		/* allocate stack block */
 | 
						|
		C_lor((arith)1);	/* push & of stack block as dst	*/
 | 
						|
		C_lal(dst);
 | 
						|
		C_sti(pointer_size);
 | 
						|
		copy_loop(sz, src, dst);
 | 
						|
		free_tmp_var(dst_offs);
 | 
						|
		free_tmp_var(src_offs);
 | 
						|
#else STB
 | 
						|
		C_asp(-(esz - pointer_size));	/* allocate stack block */
 | 
						|
		C_lor((arith)1);	/* push & of stack block as dst	*/
 | 
						|
		C_dup(pointer_size);		/* fetch source address	*/
 | 
						|
		C_adp(esz - pointer_size);
 | 
						|
		C_loi(pointer_size);
 | 
						|
		C_loc(sz);			/* # bytes to copy	*/
 | 
						|
		C_cal("__stb");			/* library copy routine	*/
 | 
						|
		C_asp(int_size + pointer_size + pointer_size);
 | 
						|
#endif STB
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
#ifndef STB
 | 
						|
copy_loop(sz, src, dst)
 | 
						|
	arith sz, src, dst;
 | 
						|
{
 | 
						|
	/* generate inline byte-copy loop */
 | 
						|
	label l_cont = text_label(), l_stop = text_label();
 | 
						|
 | 
						|
	C_loc(sz);		/* amount of bytes */
 | 
						|
	C_df_ilb(l_cont);
 | 
						|
	C_dup(word_size);
 | 
						|
	C_zle(l_stop);
 | 
						|
	C_dec();
 | 
						|
	C_lal(src);
 | 
						|
	C_loi(pointer_size);
 | 
						|
	C_dup(pointer_size);
 | 
						|
	C_adp((arith)1);
 | 
						|
	C_lal(src);
 | 
						|
	C_sti(pointer_size);
 | 
						|
	C_loi((arith)1);
 | 
						|
	C_lal(dst);
 | 
						|
	C_loi(pointer_size);
 | 
						|
	C_dup(pointer_size);
 | 
						|
	C_adp((arith)1);
 | 
						|
	C_lal(dst);
 | 
						|
	C_sti(pointer_size);
 | 
						|
	C_sti((arith)1);
 | 
						|
	C_bra(l_cont);
 | 
						|
	C_df_ilb(l_stop);
 | 
						|
	C_asp(word_size);
 | 
						|
}
 | 
						|
#endif STB
 |