/* -*-c-*- -------------- mix_predicate.c :
* Implementation of the functions declared in mix_predicate.h
* ------------------------------------------------------------------
* $Id: mix_predicate.c,v 1.6 2005/09/20 19:43:13 jao Exp $
* ------------------------------------------------------------------
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "mix_vm.h"
#include "mix_predicate.h"
/* predicate data */
typedef union pred_data_t
{
mix_word_t regA;
mix_word_t regX;
mix_short_t regI;
mix_cmpflag_t cmp;
gboolean over;
mix_word_t mem;
} pred_data_t;
/* the predicate function type */
typedef gboolean (*mix_predicate_fun_t) (mix_predicate_t *pred,
const mix_vm_t *vm);
/* the predicate type */
struct mix_predicate_t
{
mix_predicate_type_t type;
pred_data_t data;
guint control;
};
/* predicate funcs */
static gboolean
pred_func_rA (mix_predicate_t *pred, const mix_vm_t *vm)
{
mix_word_t val = mix_vm_get_rA (vm);
if (pred->data.regA == val) return FALSE;
pred->data.regA = val;
return TRUE;
}
static gboolean
pred_func_rX (mix_predicate_t *pred, const mix_vm_t *vm)
{
mix_word_t val = mix_vm_get_rX (vm);
if (pred->data.regX == val) return FALSE;
pred->data.regX = val;
return TRUE;
}
static gboolean
pred_func_rI (mix_predicate_t *pred, const mix_vm_t *vm)
{
mix_short_t val = (pred->control == 0) ? mix_vm_get_rJ (vm)
: mix_vm_get_rI (vm, pred->control);
if (pred->data.regI == val) return FALSE;
pred->data.regI = val;
return TRUE;
}
static gboolean
pred_func_mem (mix_predicate_t *pred, const mix_vm_t *vm)
{
mix_word_t val =
mix_vm_get_addr_contents (vm, (mix_address_t)pred->control);
if (pred->data.mem == val) return FALSE;
pred->data.mem = val;
return TRUE;
}
static gboolean
pred_func_cmp (mix_predicate_t *pred, const mix_vm_t *vm)
{
mix_cmpflag_t val = mix_vm_get_cmpflag (vm);
if (pred->data.cmp == val) return FALSE;
pred->data.cmp = val;
return TRUE;
}
static gboolean
pred_func_over (mix_predicate_t *pred, const mix_vm_t *vm)
{
gboolean val = mix_vm_get_overflow (vm);
if (pred->data.over == val) return FALSE;
pred->data.over = val;
return TRUE;
}
static mix_predicate_fun_t PRED_FUNCS_[] = {
pred_func_rA, pred_func_rX, pred_func_rI, pred_func_rI, pred_func_rI,
pred_func_rI, pred_func_rI, pred_func_rI, pred_func_rI,
pred_func_over, pred_func_cmp, pred_func_mem
};
/* create predicates based on vm status */
mix_predicate_t *
mix_predicate_new (mix_predicate_type_t type)
{
mix_predicate_t *result;
g_return_val_if_fail (type <= MIX_PRED_MEM, NULL);
result = g_new (mix_predicate_t, 1);
result->type = type;
result->data.regA = MIX_WORD_ZERO;
if (type >= MIX_PRED_REG_I1 && type <= MIX_PRED_REG_I6)
result->control = 1 + type - MIX_PRED_REG_I1;
else
result->control = 0;
return result;
}
/* delete a predicate */
void
mix_predicate_delete (mix_predicate_t *predicate)
{
g_return_if_fail (predicate != NULL);
g_free (predicate);
}
/* return the predicate's type */
mix_predicate_type_t
mix_predicate_get_type (const mix_predicate_t *pred)
{
g_return_val_if_fail (pred != NULL, MIX_PRED_INVALID);
return pred->type;
}
/* test a predicate */
gboolean
mix_predicate_eval(mix_predicate_t *pred, const mix_vm_t *vm)
{
g_return_val_if_fail (pred != NULL, FALSE);
g_return_val_if_fail (vm != NULL, FALSE);
return PRED_FUNCS_[pred->type] (pred, vm);
}
/* change mem address of a MIX_PRED_MEM predicate */
void
mix_predicate_set_mem_address (mix_predicate_t *predicate,
mix_address_t address)
{
g_return_if_fail (predicate != NULL);
predicate->control = address;
}
/* get message about predicate evaluation */
const gchar *
mix_predicate_get_message (const mix_predicate_t *predicate)
{
enum {SIZE = 256};
static gchar BUFFER[SIZE];
static const gchar *CMP_STRINGS[] = { "L", "E", "G"};
g_return_val_if_fail (predicate != NULL, NULL);
switch (predicate->type)
{
case MIX_PRED_REG_A:
g_snprintf (BUFFER, SIZE, _("Register A changed to %s%ld"),
mix_word_is_negative (predicate->data.regA)? "-" : "+",
mix_word_magnitude (predicate->data.regA));
break;
case MIX_PRED_REG_X:
g_snprintf (BUFFER, SIZE, _("Register X changed to %s%ld"),
mix_word_is_negative (predicate->data.regX)? "-" : "+",
mix_word_magnitude (predicate->data.regX));
break;
case MIX_PRED_REG_J:
g_snprintf (BUFFER, SIZE, _("Register J changed to %d"),
mix_short_magnitude (predicate->data.regI));
break;
case MIX_PRED_REG_I1: case MIX_PRED_REG_I2: case MIX_PRED_REG_I3:
case MIX_PRED_REG_I4: case MIX_PRED_REG_I5: case MIX_PRED_REG_I6:
g_snprintf (BUFFER, SIZE, _("Register I%d changed to %s%d"),
predicate->control,
mix_short_is_negative (predicate->data.regI)? "-" : "+",
mix_short_magnitude (predicate->data.regI));
break;
case MIX_PRED_CMP:
g_snprintf (BUFFER, SIZE, _("Comparison flag changed to %s"),
CMP_STRINGS[predicate->data.cmp]);
break;
case MIX_PRED_OVER:
g_snprintf (BUFFER, SIZE, _("Overflow toggled %s"),
predicate->data.over ? "ON" : "OFF");
break;
case MIX_PRED_MEM:
g_snprintf (BUFFER, SIZE, _("Memory address %d changed to %s%ld"),
predicate->control,
mix_word_is_negative (predicate->data.mem)? "-" : "+",
mix_word_magnitude (predicate->data.mem));
break;
default:
g_assert_not_reached ();
}
return BUFFER;
}
syntax highlighted by Code2HTML, v. 0.9.1