Sophie

Sophie

distrib > Mandriva > 2007.0 > i586 > media > contrib-release > by-pkgid > 4c9f17ec5da473f7fb52041bb9197c5a > files > 142

kaffe-devel-1.1.8-0.20060723.1mdv2007.0.i586.rpm

#
# mnemonicizer.awk
# Interprets a "defs" file filled with definitions for a processor instruction
# set architecture (ISA).
#
# Copyright (c) 2002, 2004 The University of Utah and the Flux Group.
# All rights reserved.
#
# @JANOSVM_TOOL_LICENSE@
#

#
# The mnemonicizer is a simple tool that is meant to ease the burden of
# writing and reading jitter code.  Instead of writing raw bits culled from
# a programming reference or manually #defining a bunch of stuff we just write
# a short defs file that can be automagically translated.  Hopefully, this
# eases the maintenance burden by making it trivial to change the generated
# macros as well as making it easier for fresh eyes to understand the code.
#
# XXX This code probably very ppc specific at the moment...
#

BEGIN {
    if( ARGC < 2 )
    {
	printf("Usage: awk -f %s <defs file>\n", ARGV[0]);
	exit -1;
    }
}

# A comment, just ignore it.
#
# Usage: # Foo bar
# Result: [empty]
/^\#/ {
}

# A C++ style comment that the user wishes to be included in the file.
#
# Usage: // Foo bar
# Result: // Foo bar
/^\/\// {
    printf("%s\n", $0);
}

# Specify the prefix for all generated symbols.
#
# Usage: prefix <name>
# Result: [empty] XXX
/^prefix[\t ]/ {
    prefix = $2;
    tall_prefix = toupper(prefix);
    printf("\n");
    printf("#ifndef _%s_isa_h_\n", prefix);
    printf("#define _%s_isa_h_\n", prefix);
    printf("\n");
    printf("#ifndef %s_op_debug\n", prefix);
    printf("#define %s_op_ctxt 0\n", prefix);
    printf("#define %s_op_debug(x) 0\n", prefix);
    printf("#endif\n");
    printf("\n");
}

# Specify the C type for instructions.
#
# Usage: prefix <type>
# Result: typedef <type> <prefix>_code_t;
/^opcode_type[\t ]/ {
    printf("typedef ");
    for( lpc = 2; lpc <= NF; lpc++ )
    {
	printf("%s ", $lpc);
    }
    printf("%s_code_t;\n\n", prefix);
}

# Specify a bit encoded value.
#
# Usage: bit <name> <value>
# Result:
#   #define <tall prefix>_<tall name> <value>
# or
#   #define <tall prefix>_<tall name>(<params>) <value> | <params>
#
# The value is made up of zero's, one's, y's, and z's.  The zero's and one's
# give a fixed value while the z's correspond to a reserved value that should
# be zero for now, and the y's make the bitmask parameterized.
#
# XXX Only one y argument is allowed at the least significant bit position.
/^bits[\t ]/ {
    name = $2;
    value = 0;
    has_arg = 0;
    for( lpc = 1; lpc < (length($3) + 1); lpc++ )
    {
	ch = substr($3, lpc, 1);
	if( ch == "1" )
	{
	    value += 2 ^ (length($3) - lpc);
	}
	else if( ch == "0" || ch == "z" )
	{
	}
	else if( ch == "y" )
	{
	    has_arg = 1;
	}
    }
    bits[name] = value;
    if( has_arg )
    {
	printf("#define %s_%s(y) (0x%x | !!(y))\n\n",
	       tall_prefix, toupper(name), value);
    }
    else
    {
	printf("#define %s_%s 0x%x\n\n", tall_prefix, toupper(name), value);
    }
}

# Specify the number of registers.
#
# Usage: registers <int register count>
# Result: enum {
#   <tall prefix>_R0,
#   <tall prefix>_R1,
#   <tall prefix>_R2,
#   ...
# };
/^registers[\t ]/ {
    printf("enum {\n");
    for( lpc = 0; lpc < $2; lpc++ )
    {
	printf("\t%s_R%d,\n", tall_prefix, lpc);
    }
    printf("};\n\n");

    int_registers = int($2);
}

# Specify the number of floating point registers.
#
# Usage: float_registers <float register count>
# Result: enum {
#   <tall prefix>_FPR = <int register count>
#   <tall prefix>_FPR0,
#   <tall prefix>_FPR1,
#   ...
# };
/^float_registers[\t ]/ {
    printf("enum {\n");
    printf("\t%s_FPR = %d,\n", tall_prefix, int_registers - 1);
    for( lpc = 0; lpc < $2; lpc++ )
    {
	printf("\t%s_FPR%d,\n", tall_prefix, lpc);
    }
    printf("};\n\n");

    float_registers = int($2);
}

# Specify the Kaffe-specific attributes for integer registers.
#
# Usage: register_attribute <start reg> <end reg> <reg type> <reg flags>
# Result: The result of these aren't printed out till the end and have the
#   form:
# #define REGISTER_SET \
#   { /* r0 */ 0, 0, <reg type>, <reg flags>, 0, 0, 0 }, \
#   { /* r1 */ 0, 0, <reg type>, <reg flags>, 0, 0, 1 }, \
#   { /* r2 */ 0, 0, <reg type>, <reg flags>, 0, 0, 2 }, \
#   ...
#   { /* rN */ 0, 0, <reg type>, <reg flags>, 0, 0, N }, \
/^register_attribute[\t ]/ {
    for( lpc = $2; lpc <= $3; lpc++ )
    {
	register_attributes[lpc] = $4;
	if( NF >= 5 )
	    register_flags[lpc] = $5;
    }
}

# Specify the Kaffe-specific attributes for floating point registers.
#
# Usage: float_register_attribute <start reg> <end reg> <reg type> <reg flags>
# Result: Same as above, except the floating point registers are appended
#   to the end...
# #define REGISTER_SET \
#   { /* r0 */ 0, 0, <reg type>, <reg flags>, 0, 0, 0 }, \
#   { /* r1 */ 0, 0, <reg type>, <reg flags>, 0, 0, 1 }, \
#   { /* r2 */ 0, 0, <reg type>, <reg flags>, 0, 0, 2 }, \
#   ...
#   { /* rN */ 0, 0, <reg type>, <reg flags>, 0, 0, N }, \
/^float_register_attribute[\t ]/ {
    for( lpc = $2; lpc <= $3; lpc++ )
    {
	float_register_attributes[lpc] = $4;
	if( NF >= 5 )
	    float_register_flags[lpc] = $5;
    }
}

# Define a register alias.
#
# Usage: register_alias <name> <register index>
# Result: #define <tall prefix>_R<tall name> <tall prefix>_R<index>
/^register_alias[\t ]/ {
    printf("#define %s_R%s %s_R%d\n\n",
	   tall_prefix,
	   toupper($2),
	   tall_prefix,
	   $3);
}

# Define a floating point register alias.
#
# Usage: float_register_alias <name> <register index>
# Result: #define <tall prefix>_FPR<tall name> <tall prefix>_FPR<index>
/^float_register_alias[\t ]/ {
    printf("#define %s_FPR%s %s_FPR%d\n\n",
	   tall_prefix,
	   toupper($2),
	   tall_prefix,
	   $3);
}

# Define an opcode field.
#
# Usage: op_field <name> <begin offset> <end offset>
# Result:
#   #define <tall prefix>_<tall name>_OFFSET
#   #define <tall prefix>_<tall name>_MASK
#   #define <tall prefix>_SET_<tall name>(x)
#   #define <tall prefix>_GET_<tall name>(x)
#
# The begin and end offsets are inclusive and start at the most significant
# bit (e.g. 2 ^ 31 is offset 0).
/^op_field[\t ]/ {
    name = $2;
    offset = $3;
    size = $4 - offset + 1;
    op_fields[name] = offset;
    printf("#define %s_%s_OFFSET %dUL\n",
	   tall_prefix,
	   toupper(name),
	   32 - offset - size);
    printf("#define %s_%s_MASK (0x%xUL << %s_%s_OFFSET)\n",
	   tall_prefix,
	   toupper(name),
	   sizemask(size),
	   tall_prefix,
	   toupper(name));
    printf("#define %s_SET_%s(x) \\\n",
	   tall_prefix,
	   toupper(name));
    printf("\t(((x) & 0x%x) << %s_%s_OFFSET)\n",
	   sizemask(size),
	   tall_prefix,
	   toupper(name));
    printf("#define %s_GET_%s(x) \\\n",
	   tall_prefix,
	   toupper(name));
    printf("\t(((x) >> %s_%s_OFFSET) & 0x%x)\n",
	   tall_prefix,
	   toupper(name),
	   sizemask(size));
    printf("\n");
}

# Define a single bit opcode field.
#
# Usage: op_option <name> <offset>
# Result: 
#   #define <tall prefix>_<tall name>_OFFSET
#   #define <tall prefix>_OPTION_<tall name>
/^op_option[\t ]/ {
    name = $2;
    offset = $3;
    op_options[name] = offset;
    op_fields[name] = offset;
    printf("#define %s_%s_OFFSET %dUL\n",
	   tall_prefix,
	   toupper(name),
	   31 - offset);
    printf("#define %s_OPTION_%s (1L << %d)\n\n",
	   tall_prefix,
	   toupper(name),
	   31 - offset);
}

# Define an opcode.
#
# Usage: op <name> <op_field|op_option|int> [...]
# Result: #define <prefix>_op_<name>(...)
#
# Opcodes are defined using the op_fields and op_options that were previously
# defined as well as raw integers.  Any op_fields can be used with or without
# an argument (e.g. ra(1) vs. ra) to specify whether the generated macro should
# contain a parameter for the field.  The op_option fields are ignored because
# they are probably better served by or'ing the argument afterwards
# (e.g. op_blr() | PPC_OPTION_LK).  However, they must be given so that the
# bits they use are accounted for and to ensure proper placement of raw integer
# values.  Otherwise, the script is unable to properly fill in the fields.
#
#
# Example:
#
# prefix ppc
#
# # Define the opcode field.
# op_field opcd 0 5
# # Define the register fields.
# op_field ra 11 15
# op_field rb 16 20
# op_field rd 6 10
#
# op_option oe 21
# op_option rc 31
#
# # rd = ra + rb
# op add opcd(31) rd ra rb oe 266 rc
# # rd = r0 + rb
# op addto0 opcd(31) rd ra(0) rb oe 266 rc
#
#
# Example Output:
#
# ...
# #define ppc_op_add(rd, ra, rb) \
#   (PPC_SET_OPCD(31) |
#    PPC_SET_RD(rd) |
#    PPC_SET_RA(ra) |
#    PPC_SET_RB(rb) |
#    (266 << 1))
#
# #define ppc_op_addto0(rd, rb) \
#   (PPC_SET_OPCD(31) |
#    PPC_SET_RD(rd) |
#    PPC_SET_RA(0) |
#    PPC_SET_RB(rb) |
#    (266 << 1))
/^op[\t ]/ {
    name = $2;
    printf("#define %s_op_%s(", prefix, name);
    first_field = 1;
    for( lpc = 3; lpc <= NF; lpc++ )
    {
	if( $lpc in op_options )
	{
	}
	else if( $lpc in op_fields )
	{
	    printf("%s%s", (first_field ? "" : ", "), $lpc);
	    first_field = 0;
	}
    }
    printf(") \\\n");
    printf("\t((void)%s_op_debug((%s_op_ctxt, \"%%s:%s ", prefix, prefix, name);
    for( lpc = 3; lpc <= NF; lpc++ )
    {
	if( $lpc in op_options )
	{
	}
	else if( $lpc in op_fields )
	{
	    printf("%s(%%d) ", $lpc);
	}
    }
    printf("\", __FUNCTION__");
    for( lpc = 3; lpc <= NF; lpc++ )
    {
	if( $lpc in op_options )
	{
	}
	else if( $lpc in op_fields )
	{
	    printf(", %s", $lpc);
	}
    }
    printf(")), \\\n");
    printf("\t (");
    bar = "";
    the_bar = " | \\\n\t  ";
    for( lpc = 3; lpc <= NF; lpc++ )
    {
	if( split($lpc, args, "[()]") == 3 )
	{
	    if( args[2] in bits )
		args[2] = bits[args[2]];
	    if( args[1] in op_options )
	    {
		printf("%s%s_OPTION_%s",
		       bar, tall_prefix, toupper(args[1]));
	    }
	    else
	    {
		printf("%s%s_SET_%s(%s)",
		       bar, tall_prefix, toupper(args[1]), args[2]);
	    }
	    bar = the_bar;
	}
	else if( $lpc in op_options )
	{
	}
	else if( $lpc in op_fields )
	{
	    printf("%s%s_SET_%s(%s)", bar, tall_prefix, toupper($lpc), $lpc);
	    bar = the_bar;
	}
	else if( lpc < NF )
	{
	    if( split($(lpc + 1), args, "[()]") == 3 )
	    {
		field_name = args[1];
	    }
	    else
	    {
		field_name = $(lpc + 1);
	    }
	    printf("%s(%dUL << %d)", bar, $lpc, 32 - op_fields[field_name]);
	    bar = the_bar;
	}
	else
	{
	    printf("%s%d", bar, $lpc);
	    bar = the_bar;
	}
    }
    printf("))\n\n");
}

# Print out the REGISTER_SET define for Kaffe.
END {
    printf("#define REGISTER_SET \\\n");
    for( lpc = 0; lpc < int_registers; lpc++ )
    {
	attr = "Rint|Rref";
	flags = "0";
	if( lpc in register_attributes )
	    attr = register_attributes[lpc];
	if( lpc in register_flags )
	    flags = register_flags[lpc];
	printf("\t{ /* r%d */\t0, 0, %s,\t%s, 0, %d  }, \\\n",
	       lpc,
	       attr,
	       flags,
	       lpc);
    }
    for( lpc = 0; lpc < float_registers; lpc++ )
    {
	attr = "Rfloat|Rdouble";
	flags = "0";
	if( lpc in float_register_attributes )
	    attr = float_register_attributes[lpc];
	if( lpc in float_register_flags )
	    flags = float_register_flags[lpc];
	printf("\t{ /* fpr%d */\t0, 0, %s,\t%s, 0, %d  }, \\\n",
	       lpc,
	       attr,
	       flags,
	       int_registers + lpc);
    }
    printf("\n");
    printf("#define NR_REGISTERS %d\n", int_registers + float_registers);
    printf("\n");
    printf("#endif\n");
}

function sizemask(size,  lpc, retval)
{
    retval = (2 ^ size) - 1;
    return retval;
}