diff options
Diffstat (limited to 'mixlib')
51 files changed, 9979 insertions, 0 deletions
| diff --git a/mixlib/.cvsignore b/mixlib/.cvsignore new file mode 100644 index 0000000..71b540f --- /dev/null +++ b/mixlib/.cvsignore @@ -0,0 +1,7 @@ + +.deps +Makefile +Makefile.in +lex.yy.c +mix_eval_scanner.c +mix_scanner.c diff --git a/mixlib/Makefile.am b/mixlib/Makefile.am new file mode 100644 index 0000000..5091e88 --- /dev/null +++ b/mixlib/Makefile.am @@ -0,0 +1,33 @@ +## Process this file with automake to produce Makefile.in + +# Copyright (C) 2000 Free Software Foundation, Inc. +#   +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without  +# modifications, as long as this notice is preserved. +#  +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +SUBDIRS = testsuite +INCLUDES = -I$(includedir) -DG_LOG_DOMAIN=\"libmix\" + +noinst_LIBRARIES = libmix.a +libmix_a_SOURCES = mix.h mix.c \ +		   mix_types.h mix_types.c \ +		   mix_ins.h mix_ins.c     \ +	           mix_vm.h mix_vm.c xmix_vm.h xmix_vm.c \ +		   mix_vm_dump.h mix_vm_dump.c \ +		   mix_io.h mix_io.c xmix_io.h xmix_io.c \ +		   mix_symbol_table.h mix_symbol_table.c \ +		   mix_file.h mix_file.c \ +                   mix_code_file.h mix_code_file.c \ +		   mix_parser.h xmix_parser.h mix_parser.c mix_scanner.l \ +                   mix_device.h mix_device.c xmix_device.h xmix_device.c \ +                   mix_eval.h mix_eval.c xmix_eval.h mix_eval_scanner.l \ +		   mix_src_file.c mix_src_file.h \ +                   mix_vm_clock.c mix_vm_clock.h \ +		   mix_vm_command.c mix_vm_command.h + + diff --git a/mixlib/mix.c b/mixlib/mix.c new file mode 100644 index 0000000..305bb65 --- /dev/null +++ b/mixlib/mix.c @@ -0,0 +1,63 @@ +/* -*-c-*- -------------- mix.c : + * Implementation of the functions declared in mix.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#include "mix_types.h" +#include "mix_ins.h" +#include "mix_code_file.h" +#include "mix.h" + + +/* This function must be called before using the library */ +void  +mix_init_lib(void) +{ +  mix_init_types (); +  mix_init_ins (); +  mix_code_file_set_defext (MIX_CODE_DEFEXT); +} + + +/* This function must be called for deallocating the lib resources +   when it is no longer in use  +*/ +void +mix_release_lib (void) +{ +  /* clean the user defined code file extension (if any) */ +  mix_code_file_set_defext (NULL);  +  mix_release_ins (); +} + +const char *MIX_GPL_LICENSE =  +"Copyright (C) 2000, 2001 Free Software Foundation, Inc.\n"  +"GNU MDK is free software; you can redistribute it and/or modify\n" +"it under the terms of the GNU General Public License as published by\n" +"the Free Software Foundation; either version 2 of the License, or\n" +"(at your option) any later version.\n" +"GNU MDK is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" +"GNU General Public License for more details.\n" +"You should have received a copy of the GNU General Public License\n" +"along with this program; if not, write to the Free Software\n" +"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n"; + diff --git a/mixlib/mix.h b/mixlib/mix.h new file mode 100644 index 0000000..42eb4c9 --- /dev/null +++ b/mixlib/mix.h @@ -0,0 +1,65 @@ +/* -*-c-*- ---------------- mix.h : + * Initialisation of the mix library + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#ifndef MIX_H +#define MIX_H + +#ifdef HAVE_CONFIG_H +#	include <config.h> +#else +#	warning "config.h not found, package misconfigured." +#	define PACKAGE "mdk" +#	define VERSION "0.0" +#endif  + +#ifdef HAVE_LOCALE_H +#	include <locale.h> +#endif + +#ifdef HAVE_GETTEXT +#	include <libintl.h> +#	define gettext_noop(String)	(String) +#else +#	include <intl/libintl.h> +#endif  + +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include <glib.h> + +/* This function must be called before using the library */ +extern void  +mix_init_lib (void); + +/* This function must be called for deallocating the lib resources +   when it is no longer in use  +*/ +extern void +mix_release_lib (void); + + +extern const char *MIX_GPL_LICENSE; + + +#endif /* MIX_H */ + diff --git a/mixlib/mix_code_file.c b/mixlib/mix_code_file.c new file mode 100644 index 0000000..604f3cd --- /dev/null +++ b/mixlib/mix_code_file.c @@ -0,0 +1,326 @@ +/* -*-c-*- -------------- mix_code_file.c : + * Implementation of the functions declared in mix_code_file.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + +#include "mix.h" +#include "xmix_io.h" +#include "mix_code_file.h" + +/* mix_code_file_t type */ +static const gint32 SIGNATURE_ = 0xDEADBEEF;	/* release files */  +static const gint32 SIGNATURE_D_ = 0xBEEFDEAD;	/* debug files */ + +#define IS_DEBUG_(file) ((file)->header.signature == SIGNATURE_D_) +#define IS_RELEASE_(file) ((file)->header.signature == SIGNATURE_) + + +typedef struct mix_cfheader_t mix_cfheader_t; +struct mix_cfheader_t +{ +  gint32 signature; +  gint mj_ver; +  gint mn_ver; +  gint16 start; +  size_t path_len; +}; + +struct mix_code_file_t  +{ +  mix_file_t *file;			/* the underlying disk file */ +  mix_address_t address;		/* current address while reading */ +  mix_cfheader_t header;		/* file header */ +  gchar *source_path;			/* variable length part of the header*/ +  mix_symbol_table_t *symbol_table;	/* code files with debug info fill it*/ +}; + +#define to_io_(cf)  MIX_IOCHANNEL (cf->file) + +/* Code files are lists of tagged words. A MIX_INS_TAG_ denotes + * that the word is an instruction, whose address is the next to + * the previous instruction's one, while a MIX_ADDR_TAG_ indicates + * that the word is a new address origin for the next instructions. + * The tags are stored as bit patterns in bit 31 of the mix word. + */ +#define MIX_ADDR_TAG_ (MIX_WORD_SIGN_BIT<<1) + +#define is_ins_(word) (((word)&MIX_ADDR_TAG_) == MIX_WORD_ZERO) +#define is_addr_(word) (((word)&MIX_ADDR_TAG_) == MIX_ADDR_TAG_) +#define tag_ins_(word) (word) +#define tag_addr_(word) ((word)|MIX_ADDR_TAG_) +#define extract_ins_(tagged) (tagged) +#define extract_addr_(tagged) ((tagged)&MIX_SHORT_MAX) + +/* mix code files have a default extension (.mix) which is customizable */ +static const gchar *DEFEXT_ = NULL; + +const gchar * +mix_code_file_get_defext (void) +{ +  return DEFEXT_; +} + +gboolean +mix_code_file_set_defext (const gchar *ext) +{ +  if (DEFEXT_ != NULL)  g_free ((void *)DEFEXT_); +  DEFEXT_ =  (ext != NULL)? g_strdup (ext):NULL; +  return (DEFEXT_ != NULL || ext == NULL); +} + +/* create/destroy code files for read or write */ +static mix_code_file_t * +mix_code_file_new_ (const gchar *name, mix_fmode_t mode) +{ +  mix_code_file_t *result = g_new (mix_code_file_t, 1); +  if ( result != NULL )  +    { +      result->file = mix_file_new_with_def_ext (name, mode, DEFEXT_); +      result->address = MIX_SHORT_ZERO; +      result->symbol_table = NULL; +    } +  if ( result != NULL && result->file == NULL )  +    { +      g_free (result); +      result = NULL; +    } +  return result; +} + +mix_code_file_t * +mix_code_file_new_read (const gchar *name) +{ +  mix_code_file_t *result = mix_code_file_new_ (name, mix_io_READ); +  mix_cfheader_t *header; +  FILE *file; +  gboolean check;  +   +  if ( result == NULL )  +    return NULL; +   +  file = mix_file_to_FILE (result->file); +  header = &(result->header); +  check = fread (header, sizeof (mix_cfheader_t), 1, file); +   +  if ( check ) +    check = IS_RELEASE_ (result) || IS_DEBUG_ (result); +  if ( check ) +    {/* a code file is compatible if its major version is +	is the same as this package's and its minor version is <= */ +      gint major, minor; +      sscanf (VERSION, "%d.%d", &major, &minor); +      check = header->mj_ver == major && header->mn_ver <= minor; +    } +  if ( check ) +    {/* get source path */ +      result->source_path = g_strnfill (1 + header->path_len, '\0'); +      check =  result->source_path != NULL +	&& fgets (result->source_path, 1 + header->path_len, file) != NULL; +    } +  if ( check && IS_DEBUG_ (result) ) +    {/* read symbol table */ +      result->symbol_table = mix_symbol_table_new_from_file (file); +      check = result->symbol_table != NULL; +    } +  if ( !check )       +    { +      mix_code_file_delete (result); +      return NULL; +    } +  return result; +} + +mix_code_file_t * +mix_code_file_new_write(const gchar *name, mix_address_t addr,  +			const gchar *source_path, gboolean debug, +			const mix_symbol_table_t *table) +{ +  mix_code_file_t *result; +  FILE *file; +  gboolean check; +   +  result =  mix_code_file_new_ (name, mix_io_WRITE); +  if ( result == NULL || ( file = mix_file_to_FILE (result->file) ) == NULL )  +    return NULL; +  else if ( source_path != NULL ) +    { +      result->source_path = g_strdup (source_path/*, MAX_PATH_LEN_*/); +      if ( result->source_path == NULL )  +	{ +	  mix_code_file_delete (result); +	  return NULL; +	} +    } +  else +    result->source_path = NULL; +   +  result->header.signature = debug? SIGNATURE_D_:SIGNATURE_; +  sscanf (VERSION, "%d.%d", &result->header.mj_ver, &result->header.mn_ver); +  result->header.start = (gint16) addr; +  result->header.path_len = strlen (result->source_path); +  check =  write_data_ (to_io_ (result), &result->header, 1); +  if ( check && result->source_path != NULL ) +    check = fputs (result->source_path, file) != EOF; +  if ( check && debug ) +    mix_symbol_table_print (table, MIX_SYM_LINE, file, TRUE); +  if ( !check ) +    { +      mix_code_file_delete (result); +      return NULL; +    } +  return result; +} + +void +mix_code_file_delete (mix_code_file_t *file)  +{ +  g_return_if_fail (file != NULL); +  mix_file_delete (file->file); +  if ( file->source_path ) g_free (file->source_path); +  g_free (file); +} + + + +/* get general parameters from a code file */ +gboolean +mix_code_file_is_debug (const mix_code_file_t *file) +{ +  return (file == NULL ) ? FALSE : IS_DEBUG_ (file); +} + + +gint +mix_code_file_major_version (const mix_code_file_t *file) +{ +  g_return_val_if_fail (file != NULL, 0); +  return file->header.mj_ver; +} + +gint +mix_code_file_minor_version (const mix_code_file_t *file) +{ +  g_return_val_if_fail (file != NULL, 0); +  return file->header.mn_ver; +} + +mix_address_t +mix_code_file_get_start_addr (const mix_code_file_t *file) +{ +  g_return_val_if_fail (file != NULL, MIX_SHORT_ZERO); +  return mix_short_new (file->header.start); +} + +mix_symbol_table_t * +mix_code_file_get_symbol_table(mix_code_file_t *file) +{ +  mix_symbol_table_t *result = NULL; +  g_return_val_if_fail (file != NULL, NULL); +  result = file->symbol_table; +  file->symbol_table = NULL; +  return result; +} + +/* read instructions from a code file */ +gboolean +mix_code_file_is_eof (mix_code_file_t *file) +{ +  return is_eof_ (to_io_ (file)); +} + +gboolean +mix_code_file_get_ins (mix_code_file_t *file, mix_ins_desc_t *desc) +{ +  mix_word_t next; +  g_return_val_if_fail (file != NULL, FALSE); +  g_return_val_if_fail (desc != NULL, FALSE); +  while (TRUE)  +    { +      if ( ! mix_io_read_word_array (to_io_ (file), &next, 1) ) return FALSE; +      if ( is_addr_ (next) ) +	file->address = extract_addr_ (next); +      else if ( is_ins_ (next) )  +	{ +	  desc->ins = extract_ins_ (next); +	  desc->address = (file->address)++; +	  if ( IS_DEBUG_ (file) ) +	    { +	      mix_short_t lineno; +	      if ( !mix_io_read_short_array (to_io_ (file), &lineno, 1) ) +		return FALSE; +	      desc->lineno = mix_short_magnitude (lineno); +	    } +	  else +	    desc->lineno = 0; +	  return TRUE; +	}  +      else +	{ +	  g_assert_not_reached (); +	  return FALSE; +	} +    }; +} + +/* Write instructions to a code file */ +gboolean +mix_code_file_write_ins (mix_code_file_t *file, const mix_ins_desc_t *desc) +{ +  g_return_val_if_fail (desc != NULL, FALSE); +  return ( mix_code_file_set_address (file, desc->address) && +	   mix_code_file_write_next_ins (file, desc->ins, desc->lineno) ); +} + +gboolean +mix_code_file_write_next_ins (mix_code_file_t *file, mix_word_t ins,  +			      guint lineno) +{ +  g_return_val_if_fail (file != NULL, FALSE); +  if ( mix_io_write_word (to_io_ (file), tag_ins_ (ins))  +       && ( IS_RELEASE_ (file) +	    || mix_io_write_short (to_io_ (file), mix_short_new (lineno)) )  +       ) +    { +      ++(file->address); +      return TRUE; +    }  +  else +    return FALSE; +} + +gboolean +mix_code_file_set_address (mix_code_file_t *file, mix_address_t address) +{ +  g_return_val_if_fail(file != NULL, FALSE); +  if ( file->address != address ) { +    if ( !mix_io_write_word (to_io_ (file), +			     tag_addr_ (mix_short_to_word_fast (address))) ) +      return FALSE; +    file->address = address; +  } +  return TRUE; +} +   +/* get details about the source file */ +const gchar * +mix_code_file_get_source_path (const mix_code_file_t *file) +{ +  g_return_val_if_fail (file != NULL, NULL); +  return file->source_path; +} diff --git a/mixlib/mix_code_file.h b/mixlib/mix_code_file.h new file mode 100644 index 0000000..0678910 --- /dev/null +++ b/mixlib/mix_code_file.h @@ -0,0 +1,106 @@ +/* -*-c-*- ---------------- mix_code_file.h : + * Declaration of mix_code_file_t, a file containing compiled mix  + * instructions. + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#ifndef MIX_CODE_FILE_H +#define MIX_CODE_FILE_H + +#include "mix_file.h" +#include "mix_ins.h" +#include "mix_symbol_table.h" + +/* mix_code_file_t type */ +typedef struct mix_code_file_t mix_code_file_t; + +/* instructions are loaded at specific memory addresses and related to +   source line numbers +*/ +typedef struct mix_ins_desc_t mix_ins_desc_t; +struct mix_ins_desc_t  +{ +  mix_word_t ins;		/* a mix instruction coded into a word */ +  mix_address_t address;	/* the address of this instruction */ +  guint lineno;			/* source file line no. */ +}; + +/* mix code files have a default extension (.mix) which is customizable */ +extern const gchar * +mix_code_file_get_defext(void); + +extern gboolean +mix_code_file_set_defext(const gchar *ext); + +/* create/destroy code files for read or write */ +/* if -name- does not end with defext, it is automatically appended */ +extern mix_code_file_t * +mix_code_file_new_read(const gchar *name); + +/* open a code file for write with/out debug information */ +extern mix_code_file_t * +mix_code_file_new_write(const gchar *name, mix_address_t start, +			const gchar *source_path, gboolean debug, +			const mix_symbol_table_t *table); + +extern void +mix_code_file_delete(mix_code_file_t *file); + +/* get general parameters from a code file */ +extern gboolean +mix_code_file_is_debug(const mix_code_file_t *file); + +extern gint +mix_code_file_major_version(const mix_code_file_t *file); + +extern gint +mix_code_file_minor_version(const mix_code_file_t *file); + +extern mix_address_t +mix_code_file_get_start_addr(const mix_code_file_t *file); + +extern mix_symbol_table_t * +mix_code_file_get_symbol_table(mix_code_file_t *file); + +/* read instructions from a code file */ +extern gboolean +mix_code_file_is_eof(mix_code_file_t *file); + +extern gboolean +mix_code_file_get_ins(mix_code_file_t *file, mix_ins_desc_t *desc); + +/* write instructions to a code file */ +extern gboolean +mix_code_file_write_ins(mix_code_file_t *file, const mix_ins_desc_t *desc); + +extern gboolean +mix_code_file_write_next_ins(mix_code_file_t *file, mix_word_t ins,  +			     guint lineno); + +extern gboolean +mix_code_file_set_address(mix_code_file_t *file, mix_address_t address); + +/* get details about the source file */ +extern const gchar * +mix_code_file_get_source_path (const mix_code_file_t *file); +  + +#endif /* MIX_CODE_FILE_H */ + diff --git a/mixlib/mix_device.c b/mixlib/mix_device.c new file mode 100644 index 0000000..13e7150 --- /dev/null +++ b/mixlib/mix_device.c @@ -0,0 +1,163 @@ +/* -*-c-*- -------------- mix_device.c : + * Implementation of the functions declared in mix_device.h + * ------------------------------------------------------------------ + * Copyright (C) 2000, 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#include "mix_file.h" +#include "xmix_device.h" + +mix_device_t * +mix_device_new (mix_device_type_t type) +{ +  mix_device_t *result = NULL; +  g_return_val_if_fail (type < mix_dev_INVALID, NULL); +  result = g_new (mix_device_t, 1); +  result->type = type; +  if (type != mix_dev_CONSOLE) { +    result->file = MIX_IOCHANNEL(mix_file_new_with_def_ext (DEF_NAMES_[type], +							    FMODES_[type], +							    DEV_EXT_)); +  } else +    result->file = mix_io_new (stdout); +  result->vtable = DEF_DEV_VTABLE_; +  return result; +} + + + +mix_device_t * +mix_device_new_with_name (mix_device_type_t type, const gchar *name) +{ +  mix_device_t *result = NULL; +  g_return_val_if_fail (name != NULL, NULL); +  g_return_val_if_fail (type < mix_dev_INVALID, NULL); +  result = g_new (mix_device_t, 1);   +  result->type = type; +  if (type != mix_dev_CONSOLE) +    { +      result->file = MIX_IOCHANNEL(mix_file_new_with_def_ext (name, +							      FMODES_[type], +							      DEV_EXT_)); +    } +  else +    { +      result->file = mix_io_new (stdout); +    } +  result->vtable = DEF_DEV_VTABLE_; +  return result; +} + +/* +  Create a new device with a given type and stream +*/ +mix_device_t * +mix_device_new_with_file (mix_device_type_t type, FILE *file) +{ +  mix_device_t *result = NULL; +  g_return_val_if_fail (file != NULL, NULL); +  g_return_val_if_fail (type < mix_dev_INVALID, NULL); +  result = g_new (mix_device_t, 1); +  result->type = type; +  result->file = mix_io_new (file); +  result->vtable = DEF_DEV_VTABLE_; +  return result; +} + +void +mix_device_delete (mix_device_t *dev) +{ +  if (dev != NULL) +    { +      if (dev->type != mix_dev_CONSOLE && GET_FILE_(dev) != NULL) +	mix_file_delete (GET_FILE_(dev)); +      g_free (dev); +    } +} + +mix_device_type_t +mix_device_type (const mix_device_t *dev) +{ +  g_return_val_if_fail (dev != NULL, mix_dev_INVALID); +  return dev->type; +} + +const char * +mix_device_get_name (const mix_device_t *dev) +{ +  g_return_val_if_fail (dev != NULL, NULL); +  return mix_file_base_name(GET_FILE_(dev)); +} + +/* +  Get the device block size +*/ +size_t +mix_device_block_size (const mix_device_t *dev) +{ +  g_return_val_if_fail (dev != NULL, 0); +  return SIZES_[dev->type]; +} + +/* +  Get the device io mode +*/ +mix_device_mode_t +mix_device_mode (const mix_device_t *dev)  +{ +  g_return_val_if_fail (dev != NULL, 0); +  return MODES_[dev->type]; +} + +/* +  Write a block to the device. +*/ +gboolean +mix_device_write (mix_device_t *dev, const mix_word_t *block)  +{ +  g_return_val_if_fail (dev != NULL, FALSE); +  g_return_val_if_fail (block != NULL, FALSE); +  g_assert (dev->vtable != NULL); +  return (dev->vtable->write) (dev, block); +} + +gboolean +mix_device_read (mix_device_t *dev, mix_word_t *block)  +{ +  g_return_val_if_fail (dev != NULL, FALSE); +  g_return_val_if_fail (block != NULL, FALSE); +  g_assert (dev->vtable != NULL); +  return (dev->vtable->read) (dev, block); +} + +gboolean +mix_device_ioc (mix_device_t *dev, mix_short_t arg)  +{ +  g_return_val_if_fail (dev != NULL, FALSE); +  g_assert (dev->vtable != NULL); +  return (dev->vtable->ioc) (dev, arg); +} + +gboolean +mix_device_busy (const mix_device_t *dev) +{ +  g_return_val_if_fail (dev != NULL, FALSE); +  return (dev->vtable->busy) (dev); + +} diff --git a/mixlib/mix_device.h b/mixlib/mix_device.h new file mode 100644 index 0000000..7248d72 --- /dev/null +++ b/mixlib/mix_device.h @@ -0,0 +1,151 @@ +/* -*-c-*- ---------------- mix_device.h : + * Declaration of mix_device_t and associated methods. + * ------------------------------------------------------------------ + * Copyright (C) 2000, 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#ifndef MIX_DEVICE_H +#define MIX_DEVICE_H + +#include <stddef.h> +#include <stdio.h> +#include "mix.h" +#include "mix_types.h" + +/* +  A mix device, which derives from mix_io_channel_t +*/ +typedef struct mix_device_t mix_device_t; + +/* +  The device type +*/ +typedef enum { +  mix_dev_TAPE_0, +  mix_dev_TAPE_1, +  mix_dev_TAPE_2, +  mix_dev_TAPE_3, +  mix_dev_TAPE_4, +  mix_dev_TAPE_5, +  mix_dev_TAPE_6, +  mix_dev_TAPE_7, +  mix_dev_DISK_0, +  mix_dev_DISK_1, +  mix_dev_DISK_2, +  mix_dev_DISK_3, +  mix_dev_DISK_4, +  mix_dev_DISK_5, +  mix_dev_DISK_6, +  mix_dev_DISK_7, +  mix_dev_CARD_RD, +  mix_dev_CARD_WR, +  mix_dev_PRINTER, +  mix_dev_CONSOLE, +  mix_dev_PAPER_TAPE, +  mix_dev_INVALID +} mix_device_type_t; + +/* +  The device io mode +*/ +typedef enum { +  mix_dev_BIN, +  mix_dev_CHAR +} mix_device_mode_t; + +/* +  Create a new device with default name and given type. +*/ +extern mix_device_t * +mix_device_new (mix_device_type_t type); + +/* +  Create a new device with a given type and name. +*/ +extern mix_device_t * +mix_device_new_with_name (mix_device_type_t type, const gchar *name); + +/* +  Create a new device with a given type and stream +*/ +extern mix_device_t * +mix_device_new_with_file (mix_device_type_t type, FILE *file); + +/* +  Delete a device. +*/ +extern void +mix_device_delete(mix_device_t *dev); + + +/* +  Get a device type +*/ +extern mix_device_type_t +mix_device_type (const mix_device_t *dev); + + +/* +  Get a device name +*/ +extern const char * +mix_device_get_name (const mix_device_t *dev); + +/* +  Get the device block size +*/ +extern size_t +mix_device_block_size (const mix_device_t *dev); + +/* +  Get the device io mode +*/ +extern mix_device_mode_t +mix_device_mode (const mix_device_t *dev); + +/* +  Write a block to the device. +*/ +extern gboolean +mix_device_write (mix_device_t *dev, const mix_word_t *block); + +/* +  Read a block from the device. +*/ +extern gboolean +mix_device_read (mix_device_t *dev, mix_word_t *block); + +/* +  Perform an io control operation on the device. +  The parameter _arg_ is the operation's argument: +   0- rewind to beginning +   <0 - rewind the given number of blocks +   >0 - skip forward the given number of blocks +*/ +extern gboolean +mix_device_ioc (mix_device_t *dev, mix_short_t arg); + +/* +  Check if a device is busy +*/ +extern gboolean +mix_device_busy (const mix_device_t *dev); + +#endif /* MIX_DEVICE_H */ + diff --git a/mixlib/mix_eval.c b/mixlib/mix_eval.c new file mode 100644 index 0000000..b629852 --- /dev/null +++ b/mixlib/mix_eval.c @@ -0,0 +1,191 @@ +/* -*-c-*- -------------- mix_eval.c : + * Implementation of the functions declared in mix_eval.h + * ------------------------------------------------------------------ + *  Last change: Time-stamp: "01/02/20 00:23:58 jose" + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#include "xmix_eval.h" + + +static const gchar *errors_[] = { +  N_("Successful evaluation"), +  N_("Syntax error in expression"), +  N_("Out of range F-specification"), +  N_("Mismatched parenthesis"), +  N_("Undefined symbol"), +  N_("Internal error") +}; + + +/* create a new evaluator */ +mix_eval_t * +mix_eval_new (void)  +{ +  mix_eval_t *result = g_new (mix_eval_t, 1); +  result->table = mix_symbol_table_new (); +  if (result->table == NULL) { +    g_free (result); +    return NULL; +  } +  result->towner = TRUE; +  result->value = MIX_WORD_ZERO; +  result->errpos = 0; +  return result; +} + +/* create a new evaluator with an external symbol table */ +mix_eval_t * +mix_eval_new_with_table (mix_symbol_table_t *table) +{ +  mix_eval_t *result = g_new (mix_eval_t, 1); +  result->table = table; +  result->towner = FALSE; +  result->value = MIX_WORD_ZERO; +  result->errpos = 0; +  return result; +} + +/* delete */ +void +mix_eval_delete (mix_eval_t *eval) +{ +  g_return_if_fail (eval); +  if (eval->table && eval->towner) { +    mix_symbol_table_delete (eval->table); +  } +  g_free (eval); +} + +/* eval an expression */ +mix_eval_result_t +mix_eval_expression_with_loc (mix_eval_t *eval, const gchar *expr, +			      mix_short_t loc) +{ +  mix_eval_data_ data; +   +  if (expr == NULL || eval == NULL) +    return MIX_EVAL_INTERN; +  data.expr = g_strdup_printf ("%s\n", expr); +  data.table = eval->table; +  data.errpos = eval->errpos; +  data.value = eval->value; +  data.loc = loc; +  eval->result = mix_eval_expr (&data); +  if (eval->result == MIX_EVAL_OK) { +    eval->value = data.value; +    eval->errpos = -1; +  } else { +    eval->errpos = data.errpos; +  } +  g_free (data.expr); +     +  return eval->result; +} + +/* get the result of the last evaluation */ +mix_word_t +mix_eval_value (const mix_eval_t *eval)  +{ +  g_return_val_if_fail (eval != NULL, MIX_WORD_ZERO); +  return eval->value; +} + +/* get the last eval result code */ +mix_eval_result_t  +mix_eval_last_error (const mix_eval_t *eval)  +{ +  g_return_val_if_fail (eval != NULL, MIX_EVAL_INTERN); +  return eval->result; +} + +/* get the last error string */ +const gchar* +mix_eval_last_error_string (const mix_eval_t *eval)  +{ +  g_return_val_if_fail (eval != NULL, errors_[MIX_EVAL_INTERN]); +  return errors_[eval->result]; +} + +/* get the position of last error */ +guint +mix_eval_last_error_pos (const mix_eval_t *eval) +{ +  g_return_val_if_fail (eval != NULL, 0); +  return eval->errpos; +} + +/* add, or redefine, a symbol. see mix_symbol_table.h for +   possible outcomes. */ +gint +mix_eval_set_symbol (mix_eval_t *eval, const gchar *symbol, +		     mix_word_t value) +{ +  g_return_val_if_fail (eval != NULL && eval->table != NULL, +			MIX_SYM_FAIL); +  return mix_symbol_table_insert (eval->table, symbol, value); +} + +void +mix_eval_remove_symbol (mix_eval_t *eval, const gchar *symbol) +{ +  g_return_if_fail (eval != NULL && eval->table != NULL); +  mix_symbol_table_remove (eval->table, symbol); +} + +void +mix_eval_use_symbol_table (mix_eval_t *eval, +			   mix_symbol_table_t *table) +{ +  g_return_if_fail (eval != NULL); +  if (eval->table != NULL && eval->towner) +    mix_symbol_table_delete (eval->table); +  eval->table = table; +  eval->towner = FALSE; +} + +const mix_symbol_table_t * +mix_eval_symbol_table (const mix_eval_t *eval) +{ +  g_return_val_if_fail (eval != NULL, NULL); +  return eval->table; +} + +gboolean +mix_eval_set_symbols_from_table (mix_eval_t *eval, +				 const mix_symbol_table_t *table) +{ +  g_return_val_if_fail (eval != NULL, FALSE); +  if (eval->table != NULL) +    return mix_symbol_table_merge_table (eval->table, table); +  else +    return FALSE; +} + +gboolean +mix_eval_remove_symbols_from_table (mix_eval_t *eval, +				    const mix_symbol_table_t *table) +{ +  g_return_val_if_fail (eval != NULL, FALSE); +  if (eval->table != NULL) +    return mix_symbol_table_substract_table (eval->table, table); +  else +    return FALSE; +} diff --git a/mixlib/mix_eval.h b/mixlib/mix_eval.h new file mode 100644 index 0000000..a7f961f --- /dev/null +++ b/mixlib/mix_eval.h @@ -0,0 +1,110 @@ +/* -*-c-*- ---------------- mix_eval.h : + * mix_eval_t is an evaluator of MIX W-expressions + * ------------------------------------------------------------------ + *  Last change: Time-stamp: <01/02/20 00:23:58 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#ifndef MIX_EVAL_H +#define MIX_EVAL_H + +#include "mix.h" +#include "mix_types.h" +#include "mix_symbol_table.h" + +/* the evaluator type */ +typedef struct mix_eval_t mix_eval_t; + +/* possible evaluation outcomes*/ +typedef enum { +  MIX_EVAL_OK, /* sucess*/ +  MIX_EVAL_SYNTAX, /* syntax error */ +  MIX_EVAL_INV_FSPEC, /* out of range fspec */ +  MIX_EVAL_MIS_PAREN, /* mismatched parenthesis */ +  MIX_EVAL_UNDEF_SYM, /* undefined symbol */ +  MIX_EVAL_INTERN /* internal error */ +} mix_eval_result_t; + +/* create a new evaluator */ +extern mix_eval_t * +mix_eval_new (void); + +/* create a new evaluator with an external symbol table */ +extern mix_eval_t * +mix_eval_new_with_table (mix_symbol_table_t *table); + +/* delete */ +extern void +mix_eval_delete (mix_eval_t *eval); + +/* provide a new symbol table to be used */ +extern void +mix_eval_use_symbol_table (mix_eval_t *eval, +			   mix_symbol_table_t *table); + +extern const mix_symbol_table_t * +mix_eval_symbol_table (const mix_eval_t *eval); + +/* eval an expression providing a value for loc counter */ +extern mix_eval_result_t +mix_eval_expression_with_loc (mix_eval_t *eval, const gchar *expr, +			      mix_short_t loc); +/* eval an expression with null loc*/ +#define mix_eval_expression (eval,expr) \ +  mix_eval_expression_with_loc (eval, expr, MIX_SHORT_ZERO) + + +/* get the result of the last evaluation */ +extern mix_word_t +mix_eval_value (const mix_eval_t *eval); + +/* get the last eval result code */ +extern mix_eval_result_t  +mix_eval_last_error (const mix_eval_t *eval); + +/* get the last error string */ +extern const gchar* +mix_eval_last_error_string (const mix_eval_t *eval); + +/* get the position of last error */ +extern guint +mix_eval_last_error_pos (const mix_eval_t *eval); + +/* add, or redefine, a symbol. see mix_symbol_table.h for +   possible outcomes. */ +extern gint +mix_eval_set_symbol (mix_eval_t *eval, const gchar *symbol, +		     mix_word_t value); + +extern gboolean +mix_eval_set_symbols_from_table (mix_eval_t *eval, +				 const mix_symbol_table_t *table); + +extern void +mix_eval_remove_symbol (mix_eval_t *eval, const gchar *symbol); + +extern gboolean +mix_eval_remove_symbols_from_table (mix_eval_t *eval, +				    const mix_symbol_table_t *table); + + + +#endif /* MIX_EVAL_H */ + diff --git a/mixlib/mix_eval_scanner.l b/mixlib/mix_eval_scanner.l new file mode 100644 index 0000000..abf1879 --- /dev/null +++ b/mixlib/mix_eval_scanner.l @@ -0,0 +1,265 @@ +/* -*-c-*- ------------------ mix_eval_scanner.l : + * scanner used by mix_eval_t + * ------------------------------------------------------------------ + *  Last change: Time-stamp: <01/02/20 00:23:58 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + +%{ +#include "mix.h" +#include "xmix_eval.h" + +#define YY_DECL							\ +  mix_eval_result_t  mix_eval_expr (mix_eval_data_ *data) + +  /* keep track of current position in buffer */ +#define YY_USER_ACTION yypos += yyleng; + +#define RETURN_STATE(err)			\ +  do {						\ +    done = TRUE;                                \ +    state = err;				\ +    BEGIN (INITIAL);				\ +  } while (FALSE) + +#define CLEAN_UP()				\ +  do {						\ +    yy_delete_buffer (buffer);			\ +    g_free (expr_cp);				\ + } while (FALSE) + +static mix_word_t +  eval_binop_ (const gchar *op, mix_word_t x, mix_word_t y); +  +static int +  unput_word_ (mix_word_t word); +  +%} + +%option nomain +%option caseless +%option pointer +%option stack +%option noyywrap +%option noyy_top_state +%option noreject +%option outfile="lex.yy.c" + +%s  EVAL +%s  WEVAL + +ws	[ \t]+ +digit	[0-9] +letter	[A-Z] +number	[+-]?{digit}+ +mixchar [0-9A-Z .,'')(+*/=$<>@;:\-] +locsymbol   {digit}H +flocsymbol  {digit}F +blocsymbol  {digit}B +symbol	{digit}*{letter}+[A-Z0-9]* +binops	"+"|"-"|"/"|"//"|":" +binop	{binops}|"*" +atexpr	{digit}+|{symbol}|\* +expr	[+-]?{atexpr}({binop}{1}{atexpr})* +fpart   \({expr}\) +wexpr   {expr}({fpart})?(,{expr}({fpart})?)* +   + +%% + +%{ +  YY_BUFFER_STATE buffer; +  mix_word_t expr_val = MIX_WORD_ZERO, wexpr_val = MIX_WORD_ZERO; +  mix_word_t wexpr_val_tmp = MIX_WORD_ZERO; +  mix_eval_result_t state = MIX_EVAL_OK; +  gchar *expr_cp; +  gint yypos = -22; /* to account for padding */ +  gboolean is_fp = FALSE, done = FALSE; +  g_assert (data != NULL && data->expr != NULL); +  /* make room enough to unput computed values */ +  expr_cp = g_strdup_printf ("%-20s%s"," ", data->expr); +  buffer = yy_scan_string (expr_cp); +  data->errpos = -1; +%} +   + +<*><<EOF>> { +  CLEAN_UP (); +  return MIX_EVAL_INTERN; +} + +<INITIAL>{ +  {ws} /* eat whitespace */ +  . { +    if (!done && state == MIX_EVAL_OK) { +       yypos -= yyleng; yyless (0); +      yy_push_state (WEVAL); +    } else { +      CLEAN_UP (); +      if (state == MIX_EVAL_OK) return (MIX_EVAL_SYNTAX); +      data->errpos = yypos; +      return state; +    } +  } +  "\n" { +    CLEAN_UP(); +    if (state == MIX_EVAL_OK) +	data->value = wexpr_val; +    else +	data->errpos = yypos; +    return state; +  } +}			 + +<WEVAL>{ +  {number}"(" { +    is_fp = TRUE; +    wexpr_val_tmp = mix_word_new (atol (yytext)); +  } +  {number}")"  { +    glong val  = atol (yytext); +    if ( !is_fp ) {  +      RETURN_STATE (MIX_EVAL_MIS_PAREN); +    }  else if ( val < 0 || val > MIX_BYTE_MAX  +         || !mix_fspec_is_valid (mix_byte_new (val)) ) { +      RETURN_STATE (MIX_EVAL_INV_FSPEC); +    } else { +      is_fp = FALSE; +      wexpr_val = mix_word_store_field (mix_byte_new (val), +					wexpr_val_tmp,  +					wexpr_val); +    } +  } +  {number}/({ws}*\n)|[,()] { +    wexpr_val = mix_word_new (atol (yytext)); +  } +  {expr}/({ws}*\n)|[,()] { +    if (yytext[0] != '*') +      { +	yypos -= yyleng; +	yyless (0); +      } +    else +      { +	yypos -= yyleng - 1; +	expr_val = mix_short_to_word_fast (data->loc); +	yyless (1); +      } +    yy_push_state (EVAL); +  } +  ,/{expr} /* eat comma if followed by expression */ +  [\t\n ] { /* ok if not inside an f-part */ +    if ( is_fp ) { +      RETURN_STATE (MIX_EVAL_MIS_PAREN); +    } +    unput (yytext[yyleng-1]); --yypos; +    done = TRUE; +    yy_pop_state (); +  } +  .  RETURN_STATE (MIX_EVAL_SYNTAX); +} + +<EVAL>{ +  {binop}{digit}+ { +    const gchar *s = ( yytext[1] == '/' ) ? yytext+2 : yytext+1; +    mix_word_t value = mix_word_new (atol (s)); +    expr_val = eval_binop_ (yytext, expr_val, value); +  } +  {binop}{symbol} { +    const gchar *s = ( yytext[1] == '/' ) ? yytext+2 : yytext+1; +    if ( !mix_symbol_table_is_defined (data->table, s) ) { +      RETURN_STATE (MIX_EVAL_UNDEF_SYM); +    } +    expr_val = eval_binop_ (yytext, expr_val,  +			    mix_symbol_table_value (data->table, s)); +  } +  {binop}"*" { +    expr_val = eval_binop_ (yytext, expr_val,  +			    mix_short_to_word_fast (data->loc)); +  } +  "*"  yypos -= unput_word_ (mix_short_to_word_fast (data->loc)); +  {number}    expr_val = mix_word_new (atol (yytext)); +  {symbol} { +    if ( !mix_symbol_table_is_defined (data->table, yytext) ) { +      RETURN_STATE (MIX_EVAL_UNDEF_SYM); +    } +    expr_val = mix_symbol_table_value (data->table, yytext); +  } +  [,)(\n\t ]   { +    unput (yytext[0]); --yypos; +    yypos -= unput_word_ (expr_val); +    yy_pop_state (); +  } +   +  .   RETURN_STATE (MIX_EVAL_SYNTAX); +} + + +%% + +static mix_word_t +eval_binop_ (const gchar *op, mix_word_t x, mix_word_t y) +{ +  mix_word_t result = MIX_WORD_ZERO; +  switch (op[0]) +    { +    case '+':  +      result = mix_word_add (x,y);  +      break; +    case '-': +      result = mix_word_sub (x,y); +      break; +    case '*': +      mix_word_mul (x, y, NULL, &result); +      break; +    case ':': +      { +	mix_word_t a; +	mix_word_mul (x, 8, NULL, &a); +	result = mix_word_add (a, y); +	break; +      } +    case '/': +      if ( strlen (op) > 1 && op[1] == '/' ) { +	mix_word_div (x,MIX_WORD_ZERO,y, &result, NULL); +      } else { +	mix_word_div (MIX_WORD_ZERO, x, y, &result, NULL); +      } +      break; +    default: +      g_assert_not_reached (); +    } +  return result; +} + + +static int +unput_word_ (mix_word_t word)					 +{								 +  gchar *value;						 +  gint k, result;							 +  value = g_strdup_printf ("%s%ld",				 +			   mix_word_is_negative (word)? "-":"+", +			   mix_word_magnitude (word)); +  result = strlen (value); +  for (k = result - 1; k >= 0; --k)			 +    unput (value[k]);						 +  g_free (value); +  return result; +} diff --git a/mixlib/mix_file.c b/mixlib/mix_file.c new file mode 100644 index 0000000..023f4ef --- /dev/null +++ b/mixlib/mix_file.c @@ -0,0 +1,140 @@ +/* -*-c-*- -------------- mix_file.c : + * Implementation of the functions declared in mix_file.h + * ------------------------------------------------------------------ + * Copyright (C) 2000, 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#include "xmix_io.h" +#include "mix_file.h" + +const gchar *MIX_SRC_DEFEXT = ".mixal",  +  *MIX_LIST_DEFEXT = ".mls", *MIX_CODE_DEFEXT = ".mix"; + +/* file names completions */ +#define needs_completion_(name,defext) \ +  ( strcmp(name + strlen(name) - strlen(defext), defext) != 0 ) + +#define add_completion_(name, defext) \ +  g_strconcat(name, defext, NULL) + +/* The actual definition of mix_file_t */ +struct mix_file_t  +{ +  mix_iochannel_t parent; +  gchar *base_name; +  gchar *ext; +}; + +/* Creation/destruction of files */ +static mix_file_t * +open_file_(const gchar *name, mix_fmode_t mode) +{ +  mix_file_t *result; +  FILE *file; +   +  result = g_new(mix_file_t, 1); +  file = fopen(name, fmode_to_type_(mode)); +  if ( file == NULL ) { +    g_free (result); +    return NULL; +  } +  io_init_from_file_(MIX_IOCHANNEL(result), file); +  return result; +} +   +mix_file_t * +mix_file_new(const gchar *name, mix_fmode_t mode) +{ +  mix_file_t *result; +  gchar *bname; + +  if ( name == NULL ) return NULL; +  bname = g_strdup(name); +  if ( bname == NULL ) return NULL; +  result = open_file_(name, mode); +  if ( result == NULL ) +    { +      g_free(bname); +      return NULL; +    } +  result->base_name = bname; +  result->ext = NULL; +  return result; +} + +/* creates a file adding to its name the defext if missing */ +mix_file_t * +mix_file_new_with_def_ext(const gchar *name, mix_fmode_t mode,  +			  const gchar *defext) +{ +  const gchar *real_name; +  mix_file_t *result; +   +  if ( name == NULL ) return NULL; +  if ( defext == NULL ) return mix_file_new(name, mode); +  real_name =  needs_completion_(name, defext) ?  +    add_completion_(name, defext) : name; +  result = open_file_(real_name, mode); +  if ( real_name != name ) g_free((void *)real_name); +  if ( result  == NULL ) return NULL; +  result->ext = g_strdup(defext); +  if ( needs_completion_(name, defext) ) +    result->base_name = g_strdup(name); +  else +    result->base_name = g_strndup(name, strlen(name) - strlen(defext)); +  if ( result->ext == NULL || result->base_name == NULL ) +    { +      mix_file_delete(result); +      return NULL; +    } +  return result; +} + +void +mix_file_delete(mix_file_t *file) +{ +  g_return_if_fail(file != NULL); +  io_close_(MIX_IOCHANNEL(file)); +  if (file->base_name) g_free(file->base_name); +  if (file->ext) g_free(file->ext); +  g_free(file); +} + +/* convert to a standard FILE */ +extern FILE * +mix_file_to_FILE(const mix_file_t *file) +{ +  if ( file == NULL ) return NULL; +  return io_get_FILE_(file); +} + +/* Get the base name and extension of file */ +const gchar * +mix_file_base_name(const mix_file_t *file) +{ +  g_return_val_if_fail(file != NULL, NULL); +  return file->base_name; +} + +const gchar * +mix_file_extension(const mix_file_t *file) +{ +  g_return_val_if_fail(file != NULL, NULL); +  return file->ext; +} diff --git a/mixlib/mix_file.h b/mixlib/mix_file.h new file mode 100644 index 0000000..22bed74 --- /dev/null +++ b/mixlib/mix_file.h @@ -0,0 +1,61 @@ +/* -*-c-*- ---------------- mix_file.h : + * Declarations for the mix_file_t type. + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#ifndef MIX_FILE_H +#define MIX_FILE_H + +#include "mix_io.h" + +/* The mix_file_t type, deriving from mix_iochannel_t and  +   representing a disk file  +*/ +typedef struct mix_file_t mix_file_t; + +/* Creation/destruction of files */ +extern mix_file_t * +mix_file_new(const gchar *name, mix_fmode_t mode); + +/* creates a file adding to its name the defext if missing */ +extern mix_file_t * +mix_file_new_with_def_ext(const gchar *name, mix_fmode_t mode,  +			  const gchar *defext); + +extern void +mix_file_delete(mix_file_t *file); + +/* convert to a standard FILE */ +extern FILE * +mix_file_to_FILE(const mix_file_t *file); + +/* standard default extensions */ +extern const gchar *MIX_SRC_DEFEXT, *MIX_LIST_DEFEXT, *MIX_CODE_DEFEXT; + +/* Get the base name and extension of file */ +extern const gchar * +mix_file_base_name(const mix_file_t *file); + +extern const gchar * +mix_file_extension(const mix_file_t *file); + + +#endif /* MIX_FILE_H */ + diff --git a/mixlib/mix_ins.c b/mixlib/mix_ins.c new file mode 100644 index 0000000..2c5df08 --- /dev/null +++ b/mixlib/mix_ins.c @@ -0,0 +1,269 @@ +/* -*-c-*- ------------------ mix_ins.c : + * Implementation of the functions declared in mix_ins.h + * ------------------------------------------------------------------ + * Copyright (C) 1999 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + +#include "mix_ins.h" + + +struct mix_ins_desc_  +{ +  mix_opcode_t opcode; +  mix_fspec_t  def_fspec; +  const gchar  *string_rep; +  gboolean is_ext; +}; + +#define IDES_(c,f,s) {c,f,#s,FALSE} +#define IDESX_(c,f,s) {c,f,#s,TRUE} + +static const struct mix_ins_desc_ id_to_desc_[] =  { +  IDES_(0,0,NOP), IDES_(1,5,ADD), IDES_(2,5,SUB), IDES_(3,5,MUL), +  IDES_(4,5,DIV),  +  IDESX_(5,0,NUM), IDESX_(5,1,CHAR), IDESX_(5,2,HLT),   +  IDESX_(6,0,SLA), IDESX_(6,1,SRA), IDESX_(6,2,SLAX), IDESX_(6,3,SRAX),  +  IDESX_(6,4,SLC), IDESX_(6,5,SRC),  +  IDES_(7,1,MOVE), IDES_(8,5,LDA), IDES_(9,5,LD1), IDES_(10,5,LD2), +  IDES_(11,5,LD3), IDES_(12,5,LD4), IDES_(13,5,LD5),  +  IDES_(14,5,LD6), IDES_(15,5,LDX), IDES_(16,5,LDAN), IDES_(17,5,LD1N),  +  IDES_(18,5,LD2N), IDES_(19,5,LD3N), IDES_(20,5,LD4N), +  IDES_(21,5,LD5N), IDES_(22,5,LD6N), IDES_(23,5,LDXN),  +  IDES_(24,5,STA), IDES_(25,5,ST1), IDES_(26,5,ST2), IDES_(27,5,ST3),  +  IDES_(28,5,ST4), IDES_(29,5,ST5), IDES_(30,5,ST6), IDES_(31,5,STX),  +  IDES_(32,2,STJ), IDES_(33,5,STZ), IDES_(34,0,JBUS), IDES_(35,0,IOC),  +  IDES_(36,0,IN), IDES_(37,0,OUT), IDES_(38,0,JRED),  +  IDESX_(39,0,JMP), IDESX_(39,1,JSJ), IDESX_(39,2,JOV), IDESX_(39,3,JNOV),  +  IDESX_(39,4,JL), IDESX_(39,5,JE), IDESX_(39,6,JG), IDESX_(39,7,JGE), +  IDESX_(39,8,JNE), IDESX_(39,9,JLE), +  IDESX_(40,0,JAN), IDESX_(40,1,JAZ), IDESX_(40,2,JAP), IDESX_(40,3,JANN),  +  IDESX_(40,4,JANZ), IDESX_(40,5,JANP), +  IDESX_(41,0,J1N), IDESX_(41,1,J1Z), IDESX_(41,2,J1P), IDESX_(41,3,J1NN),  +  IDESX_(41,4,J1NZ), IDESX_(41,5,J1NP), +  IDESX_(42,0,J2N), IDESX_(42,1,J2Z), IDESX_(42,2,J2P), IDESX_(42,3,J2NN),  +  IDESX_(42,4,J2NZ), IDESX_(42,5,J2NP), +  IDESX_(43,0,J3N), IDESX_(43,1,J3Z), IDESX_(43,2,J3P), IDESX_(43,3,J3NN),  +  IDESX_(43,4,J3NZ), IDESX_(43,5,J3NP), +  IDESX_(44,0,J4N), IDESX_(44,1,J4Z), IDESX_(44,2,J4P), IDESX_(44,3,J4NN),  +  IDESX_(44,4,J4NZ), IDESX_(44,5,J4NP), +  IDESX_(45,0,J5N), IDESX_(45,1,J5Z), IDESX_(45,2,J5P), IDESX_(45,3,J5NN),  +  IDESX_(45,4,J5NZ), IDESX_(45,5,J5NP), +  IDESX_(46,0,J6N), IDESX_(46,1,J6Z), IDESX_(46,2,J6P), IDESX_(46,3,J6NN),  +  IDESX_(46,4,J6NZ), IDESX_(46,5,J6NP), +  IDESX_(47,0,JXN), IDESX_(47,1,JXZ), IDESX_(47,2,JXP), IDESX_(47,3,JXNN),  +  IDESX_(47,4,JXNZ), IDESX_(47,5,JXNP), +  IDESX_(48,0,INCA), IDESX_(48,1,DECA), IDESX_(48,2,ENTA), IDESX_(48,3,ENNA),  +  IDESX_(49,0,INC1), IDESX_(49,1,DEC1), IDESX_(49,2,ENT1), IDESX_(49,3,ENN1), +  IDESX_(50,0,INC2), IDESX_(50,1,DEC2), IDESX_(50,2,ENT2), IDESX_(50,3,ENN2), +  IDESX_(51,0,INC3), IDESX_(51,1,DEC3), IDESX_(51,2,ENT3), IDESX_(51,3,ENN3), +  IDESX_(52,0,INC4), IDESX_(52,1,DEC4), IDESX_(52,2,ENT4), IDESX_(52,3,ENN4),  +  IDESX_(53,0,INC5), IDESX_(53,1,DEC5), IDESX_(53,2,ENT5), IDESX_(53,3,ENN5),  +  IDESX_(54,0,INC6), IDESX_(54,1,DEC6), IDESX_(54,2,ENT6), IDESX_(54,3,ENN6),  +  IDESX_(55,0,INCX), IDESX_(55,1,DECX), IDESX_(55,2,ENTX), IDESX_(55,3,ENNX),  +  IDES_(56,5,CMPA), IDES_(57,5,CMP1), IDES_(58,5,CMP2), IDES_(59,5,CMP3),  +  IDES_(60,5,CMP4), IDES_(61,5,CMP5), IDES_(62,5,CMP6), IDES_(63,5,CMPX) +}; + +static const gsize ID_TO_DESC_SIZE_=  +                   sizeof(id_to_desc_)/sizeof(id_to_desc_[0]); + +/* To look for the mix_ins_id corresponding to a pair (fspec,opcode) +   we use an array indexed by opcode with values  +   (initial_ins, final_ins - initial_ins) +*/ +struct mix_opcode_desc_  +{ +  mix_ins_id_t init_id; +  guchar       inc; /* when inc == 0, the id does not depend on fspec */ +}; + +static struct mix_opcode_desc_ opcode_to_id_[MIX_BYTE_MAX + 1]; + +/* a hash table mapping strings to mix_ins_id's */ +static GHashTable *string_to_id_ = NULL; + +void +mix_init_ins(void)  +{ +  guint k; +  g_assert(ID_TO_DESC_SIZE_ == mix_INVALID_INS); +   +  for ( k = 0; k < MIX_BYTE_MAX + 1; ++k ) +    { +      opcode_to_id_[k].init_id = mix_INVALID_INS; +      opcode_to_id_[k].inc = 0; +    } +   +  for ( k = 0; k < ID_TO_DESC_SIZE_; ++k ) +    { +      if ( opcode_to_id_[id_to_desc_[k].opcode].init_id == mix_INVALID_INS ) +	opcode_to_id_[id_to_desc_[k].opcode].init_id = k; +      else +	++opcode_to_id_[id_to_desc_[k].opcode].inc; +    } + +  if ( string_to_id_ == NULL ) +    { +      string_to_id_ = g_hash_table_new(g_str_hash, g_str_equal); +      for ( k = 0; k < ID_TO_DESC_SIZE_; ++k) +	g_hash_table_insert(string_to_id_, (gpointer)id_to_desc_[k].string_rep, +			    GUINT_TO_POINTER(k)); +    } +   +} + +void +mix_release_ins(void) +{ +  g_hash_table_destroy(string_to_id_); +} + +/* Conversions between words and ins */ +mix_word_t +mix_ins_to_word(const mix_ins_t *ins) +{ +  g_return_val_if_fail(ins != NULL, MIX_WORD_ZERO); +  return  (mix_word_t)((ins->address<<18)| +		       ((ins->index&7)<<12)|(ins->fspec<<6)|(ins->opcode)); +} + +mix_ins_id_t +mix_word_to_ins(mix_word_t word, mix_ins_t *ins) +{ +  mix_ins_id_t result = mix_get_ins_id(mix_get_ins_opcode(word), +				       mix_get_ins_fspec(word)); +  		        +  g_return_val_if_fail(ins != NULL, result); +  mix_word_to_ins_uncheck(word,*ins); +  return result; +} + +/* Getting ins parameters */ +mix_opcode_t +mix_get_opcode_from_id(mix_ins_id_t id) +{ +  g_return_val_if_fail(id < ID_TO_DESC_SIZE_, MIX_BYTE_ZERO); +  return id_to_desc_[id].opcode; +} + +gboolean +mix_ins_id_is_extended(mix_ins_id_t id) +{ +  g_return_val_if_fail(id < ID_TO_DESC_SIZE_, FALSE); +  return id_to_desc_[id].is_ext; +} + + +mix_fspec_t +mix_get_fspec_from_id(mix_ins_id_t id) +{ +  g_return_val_if_fail(id < ID_TO_DESC_SIZE_, MIX_BYTE_ZERO); +  return id_to_desc_[id].def_fspec; +} + + +const gchar *  +mix_get_string_from_id(mix_ins_id_t id) +{ +  g_return_val_if_fail(id < ID_TO_DESC_SIZE_, NULL); +  return id_to_desc_[id].string_rep; +} + +mix_ins_id_t +mix_get_id_from_string(const gchar *name) +{ +  gpointer key, value; +  if ( !g_hash_table_lookup_extended(string_to_id_, (gpointer)name, +				     &key, &value) ) +    return mix_INVALID_INS; +  return (mix_ins_id_t)GPOINTER_TO_UINT(value); +} + + +mix_ins_id_t +mix_get_ins_id(mix_opcode_t code, mix_fspec_t fspec) +{ +  if ( opcode_to_id_[code].inc == 0 ) +    return opcode_to_id_[code].init_id; +  else if ( opcode_to_id_[code].inc < fspec ) +    return mix_INVALID_INS; +  else +    return (opcode_to_id_[code].init_id + fspec); +} + +/* Printable representation */ +extern gchar * /* this pointer must be freed by caller */ +mix_ins_to_string(const mix_ins_t *ins) +{ +  gboolean needs_f; +  gchar *result; +  mix_ins_id_t id; +   +  g_return_val_if_fail(ins != NULL, NULL); +  id = mix_ins_id_from_ins(*ins); +  needs_f = ins->fspec != id_to_desc_[id].def_fspec; +  if ( needs_f )  +    result =  g_strdup_printf("%s\t%s%d,%d(%d:%d)",   +			      mix_get_string_from_id(id), +			      mix_short_is_negative(ins->address)?"-":"", +			      mix_short_magnitude(ins->address), ins->index,  +			      mix_fspec_left(ins->fspec),  +			      mix_fspec_right(ins->fspec)); +  else +    result =  g_strdup_printf("%s\t%s%d,%d", mix_get_string_from_id(id), +			      mix_short_is_negative(ins->address)?"-":"", +			      mix_short_magnitude(ins->address), ins->index); +  return result; +} + +extern void +mix_ins_to_string_in_buffer (const mix_ins_t *ins, gchar *buf, guint len) +{ +  gboolean needs_f; +  mix_ins_id_t id; +   +  g_return_if_fail (ins != NULL); +  g_return_if_fail (buf != NULL); +  id = mix_ins_id_from_ins(*ins); +  needs_f = ins->fspec != id_to_desc_[id].def_fspec; +  if ( needs_f )  +    g_snprintf (buf, len, "%s\t%s%d,%d(%d:%d)",   +		mix_get_string_from_id(id), +		mix_short_is_negative(ins->address)?"-":"", +		mix_short_magnitude(ins->address), ins->index,  +		mix_fspec_left(ins->fspec),  +		mix_fspec_right(ins->fspec)); +  else +    g_snprintf(buf, len, "%s\t%s%d,%d", +	       mix_get_string_from_id(id), +	       mix_short_is_negative(ins->address)?"-":"", +	       mix_short_magnitude(ins->address), ins->index); +} + +   + +void +mix_ins_print(const mix_ins_t *ins) +{ +  g_return_if_fail(ins != NULL); +  g_print(mix_get_string_from_id(mix_ins_id_from_ins(*ins))); +  g_print(" %s%d,%d(%d:%d)", mix_short_is_negative(ins->address)?"-":"+", +	  mix_short_magnitude(ins->address), ins->index,  +	  mix_fspec_left(ins->fspec), mix_fspec_right(ins->fspec)); +} + diff --git a/mixlib/mix_ins.h b/mixlib/mix_ins.h new file mode 100644 index 0000000..7746e8c --- /dev/null +++ b/mixlib/mix_ins.h @@ -0,0 +1,195 @@ +/* -*-c-*- -------------------- mix_ins.h: + * This file declares types and functions for manipulating MIX + * instructions + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#ifndef MIX_INS_H +#define MIX_INS_H + +#include "mix_types.h" + + +/* Initialise and free mix_ins data */ +extern void +mix_init_ins(void); + +extern void +mix_release_ins(void); + +/* A MIX instruction is made up of address, index, fspec and op_code */ + +/*-- Address field: contains two bytes */ +typedef mix_short_t  mix_address_t; + +/*-- Index field: a value between 0 and 6 */ +typedef enum {  +  mix_I0, mix_I1, mix_I2, mix_I3, mix_I4, mix_I5, mix_I6 } mix_index_t; + +/*-- Instruction id: enumeration of MIX instruction set */ +typedef enum { +  mix_NOP,  mix_ADD, mix_SUB, mix_MUL, mix_DIV,  +  mix_NUM, mix_CHAR, mix_HLT,   +  mix_SLA, mix_SRA, mix_SLAX, mix_SRAX, mix_SLC, mix_SRC,  +  mix_MOVE, mix_LDA, mix_LD1, mix_LD2, mix_LD3, mix_LD4, mix_LD5,  +  mix_LD6,  mix_LDX, mix_LDAN, mix_LD1N, mix_LD2N, mix_LD3N, mix_LD4N, +  mix_LD5N, mix_LD6N, mix_LDXN, mix_STA, mix_ST1, mix_ST2, mix_ST3, mix_ST4,  +  mix_ST5, mix_ST6, mix_STX, mix_STJ, mix_STZ, mix_JBUS, mix_IOC, mix_IN,  +  mix_OUT, mix_JRED,  +  mix_JMP, mix_JSJ, mix_JOV, mix_JNOV, mix_JL, mix_JE, mix_JG, mix_JGE, +  mix_JNE, mix_JLE, +  mix_JAN, mix_JAZ, mix_JAP, mix_JANN, mix_JANZ, mix_JANP,  +  mix_J1N, mix_J1Z, mix_J1P, mix_J1NN, mix_J1NZ, mix_J1NP, +  mix_J2N, mix_J2Z, mix_J2P, mix_J2NN, mix_J2NZ, mix_J2NP, +  mix_J3N, mix_J3Z, mix_J3P, mix_J3NN, mix_J3NZ, mix_J3NP, +  mix_J4N, mix_J4Z, mix_J4P, mix_J4NN, mix_J4NZ, mix_J4NP, +  mix_J5N, mix_J5Z, mix_J5P, mix_J5NN, mix_J5NZ, mix_J5NP, +  mix_J6N, mix_J6Z, mix_J6P, mix_J6NN, mix_J6NZ, mix_J6NP, +  mix_JXN, mix_JXZ, mix_JXP, mix_JXNN, mix_JXNZ, mix_JXNP,  +  mix_INCA, mix_DECA, mix_ENTA, mix_ENNA,  +  mix_INC1, mix_DEC1, mix_ENT1, mix_ENN1, +  mix_INC2, mix_DEC2, mix_ENT2, mix_ENN2, +  mix_INC3, mix_DEC3, mix_ENT3, mix_ENN3, +  mix_INC4, mix_DEC4, mix_ENT4, mix_ENN4,  +  mix_INC5, mix_DEC5, mix_ENT5, mix_ENN5,  +  mix_INC6, mix_DEC6, mix_ENT6, mix_ENN6,  +  mix_INCX, mix_DECX, mix_ENTX, mix_ENNX,  +  mix_CMPA, mix_CMP1, mix_CMP2, mix_CMP3, mix_CMP4,  +  mix_CMP5, mix_CMP6, mix_CMPX, mix_INVALID_INS +} mix_ins_id_t; + +/* each one of the above id's has associated an opcode, a default +   fspec and a string representation */ +/* the opcode fits in a byte */ +typedef mix_byte_t mix_opcode_t; + +/* labels for each opcode */ +enum { +  mix_opNOP = 0, mix_opADD, mix_opSUB, mix_opMUL, mix_opDIV,  +  mix_opSPC, mix_opSLx, mix_opMOVE,  +  mix_opLDA, mix_opLD1, mix_opLD2, mix_opLD3, mix_opLD4, mix_opLD5,  +  mix_opLD6, mix_opLDX, mix_opLDAN, mix_opLD1N, mix_opLD2N, mix_opLD3N,  +  mix_opLD4N, mix_opLD5N, mix_opLD6N, mix_opLDXN,  +  mix_opSTA, mix_opST1, mix_opST2, mix_opST3, mix_opST4,  +  mix_opST5, mix_opST6, mix_opSTX, mix_opSTJ, mix_opSTZ,  +  mix_opJBUS, mix_opIOC, mix_opIN, mix_opOUT, mix_opJRED,  +  mix_opJMP, mix_opJAx, mix_opJ1x, mix_opJ2x, mix_opJ3x,  +  mix_opJ4x, mix_opJ5x, mix_opJ6x, mix_opJXx, +  mix_opINCA, mix_opINC1, mix_opINC2, mix_opINC3,  +  mix_opINC4, mix_opINC5, mix_opINC6, mix_opINCX, +  mix_opCMPA, mix_opCMP1, mix_opCMP2, mix_opCMP3, mix_opCMP4,  +  mix_opCMP5, mix_opCMP6, mix_opCMPX +}; +  +extern mix_opcode_t +mix_get_opcode_from_id(mix_ins_id_t id); + +extern mix_fspec_t +mix_get_fspec_from_id(mix_ins_id_t id); + +/* For extended instructions, both the opcode and fspec determine +   the id (i.e., an explicit fspec cannot be used) +*/ +extern gboolean +mix_ins_id_is_extended(mix_ins_id_t id); + +extern const gchar *  +mix_get_string_from_id(mix_ins_id_t id); + +extern mix_ins_id_t +mix_get_id_from_string(const gchar *name); + +extern mix_ins_id_t +mix_get_ins_id(mix_opcode_t code, mix_fspec_t fspec); + + +/*--  MIX instruction type */ +typedef struct mix_ins_t mix_ins_t; +struct mix_ins_t  +{ +  mix_address_t address; +  mix_index_t   index; +  mix_fspec_t   fspec; +  mix_opcode_t  opcode; +}; + +#define mix_ins_fill_from_id(ins,id)		\ +   do {						\ +     (ins).opcode = mix_get_opcode_from_id(id);	\ +     (ins).fspec = mix_get_fspec_from_id(id);	\ +   } while(FALSE) + + +/* A mix ins can be codified into a word */ +extern mix_word_t +mix_ins_to_word(const mix_ins_t *ins); + +extern mix_ins_id_t +mix_word_to_ins(mix_word_t w, mix_ins_t *ins); + +#define mix_word_add_address(word,addr) (word) |= ((addr)<<18)  + +/* decompose an instruction codified in a word into its parts */ +#define mix_get_ins_address(word) ((mix_address_t)((word)>>18)) +#define mix_get_ins_index(word)   ((mix_index_t)(((word)>>12)&7)) +#define mix_get_ins_fspec(word)   ((mix_fspec_t)(mix_byte_new((word)>>6))) +#define mix_get_ins_opcode(word)  ((mix_opcode_t)(mix_byte_new(word))) + +/* unchecked versions for speed */ +#define mix_ins_to_word_uncheck(ins)					\ + (mix_word_t)(((ins).address<<18)|					\ +	      (((ins).index&7)<<12)|((ins).fspec<<6)|((ins).opcode)) + +#define mix_word_to_ins_uncheck(word,ins)	\ +  do {						\ +    (ins).address = mix_get_ins_address(word);	\ +    (ins).index = mix_get_ins_index(word);	\ +    (ins).fspec = mix_get_ins_fspec(word);	\ +    (ins).opcode = mix_get_ins_opcode(word);	\ +  } while(FALSE) + +#define mix_ins_id_from_ins(ins)  mix_get_ins_id((ins).opcode,(ins).fspec) + + +/* Printable representation */ +extern gchar * /* this pointer must be freed by caller */ +mix_ins_to_string(const mix_ins_t *ins); + +extern void +mix_ins_to_string_in_buffer (const mix_ins_t *ins, gchar *buf, guint len); + +extern void +mix_ins_print(const mix_ins_t *ins); + + + +/* A MIX ins has an associated execution time */ +/* Initialise mix_ins data providing an interlock time for I/O devices */ +/* --------------------------------------> MOVE to VM +typedef guint mix_time_t; + +extern void +mix_init_ins_with_interlock_time(mix_time_t t); + +extern mix_time_t   +mix_ins_exec_time(const mix_ins_t *ins); +*/ + +#endif /* MIX_INS_H */ diff --git a/mixlib/mix_io.c b/mixlib/mix_io.c new file mode 100644 index 0000000..704a5c0 --- /dev/null +++ b/mixlib/mix_io.c @@ -0,0 +1,219 @@ +/* -*-c-*- --------------- mix_io.c : + * Implementation of the functions declared in mix_io.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#include "xmix_io.h" + +mix_iochannel_t * +mix_io_new (FILE *file) +{ +  mix_iochannel_t *result; +  g_return_val_if_fail (file != NULL, NULL); +  result = g_new (mix_iochannel_t, 1); +  result->file = file; +  return result; +} + +void +mix_io_delete (mix_iochannel_t *ch) +{ +  if (ch != NULL) +    { +      fclose (ch->file); +      g_free (ch); +    } +} + +FILE * +mix_io_to_FILE (mix_iochannel_t *ioc) +{ +  g_return_val_if_fail (ioc != NULL, FALSE); +  return ioc->file; +} + +gboolean +mix_io_eof (mix_iochannel_t *ioc) +{ +  g_return_val_if_fail (ioc != NULL, FALSE); +  return is_eof_ (ioc); +} + +gboolean +mix_io_is_ready (mix_iochannel_t *ioc) +{ +  g_return_val_if_fail (ioc != NULL, FALSE); +  return is_ready_ (ioc); +} + +gboolean +mix_io_write_byte (mix_iochannel_t *ioc, mix_byte_t b) +{ +  g_return_val_if_fail (ioc != NULL, FALSE); +  return write_data_ (ioc, &b, 1); +} + +gboolean +mix_io_write_byte_array (mix_iochannel_t *ioc, const mix_byte_t *b, +			 size_t s) +{ +  g_return_val_if_fail (ioc != NULL, FALSE); +  g_return_val_if_fail (b != NULL, FALSE); +  return write_data_ (ioc, b, s); +} + + +mix_byte_t +mix_io_read_byte (mix_iochannel_t *ioc) +{ +  mix_byte_t result = MIX_BYTE_ZERO; +  g_return_val_if_fail (ioc != NULL, result); +  g_return_val_if_fail (read_data_ (ioc, &result, 1), MIX_BYTE_ZERO); +  return result; +} +   +gboolean +mix_io_read_byte_array (mix_iochannel_t *ioc, mix_byte_t *b, size_t s) +{ +  g_return_val_if_fail (ioc != NULL, FALSE); +  g_return_val_if_fail (b != NULL, FALSE); +  return read_data_ (ioc, b, s); +} + +gboolean +mix_io_write_word (mix_iochannel_t *ioc, mix_word_t w) +{ +  g_return_val_if_fail (ioc != NULL, FALSE); +  return write_data_ (ioc, &w, 1); +} + +gboolean +mix_io_write_word_array (mix_iochannel_t *ioc, const mix_word_t *w, +			 size_t s) +{ +  g_return_val_if_fail (ioc != NULL, FALSE); +  g_return_val_if_fail (w != NULL, FALSE); +  return write_data_ (ioc, &w, s); +} + +mix_word_t +mix_io_read_word (mix_iochannel_t *ioc) +{ +  mix_word_t result = MIX_WORD_ZERO; +  g_return_val_if_fail (ioc != NULL, result); +  g_return_val_if_fail (read_data_ (ioc, &result, 1), MIX_WORD_ZERO); +  return result; +} + +gboolean +mix_io_read_word_array (mix_iochannel_t *ioc, mix_word_t *w, size_t s) +{ +  g_return_val_if_fail (ioc != NULL, FALSE); +  g_return_val_if_fail (w != NULL, FALSE); +  return read_data_ (ioc, w, s); +} + +gboolean +mix_io_write_short (mix_iochannel_t *ioc, mix_short_t w) +{ +  g_return_val_if_fail (ioc != NULL, FALSE); +  return write_data_ (ioc, &w, 1); +} + +gboolean +mix_io_write_short_array (mix_iochannel_t *ioc, const mix_short_t *w, +			  size_t s) +{ +  g_return_val_if_fail (ioc != NULL, FALSE); +  g_return_val_if_fail (w != NULL, FALSE); +  return write_data_ (ioc, &w, s); +} + +mix_short_t +mix_io_read_short (mix_iochannel_t *ioc) +{ +  mix_short_t result = MIX_SHORT_ZERO; +  g_return_val_if_fail (ioc != NULL, result); +  g_return_val_if_fail (read_data_ (ioc, &result, 1), MIX_SHORT_ZERO); +  return result; +} + +gboolean +mix_io_read_short_array (mix_iochannel_t *ioc, mix_short_t *w, size_t s) +{ +  g_return_val_if_fail (ioc != NULL, FALSE); +  g_return_val_if_fail (w != NULL, FALSE); +  return read_data_ (ioc, w, s); +} + +gboolean +mix_io_write_char (mix_iochannel_t *ioc, mix_char_t c) +{ +  guchar value = mix_char_to_ascii (c); +  g_return_val_if_fail (ioc != NULL, FALSE); +  return write_data_ (ioc, &value, 1); +} + +mix_char_t +mix_io_read_char (mix_iochannel_t *ioc) +{ +  guchar value; +  g_return_val_if_fail (ioc != NULL, MIX_CHAR_MAX); +  g_return_val_if_fail (read_data_ (ioc, &value, 1), MIX_CHAR_MAX); +  return mix_ascii_to_char (value); +} + +gboolean +mix_io_write_word_array_as_char  (mix_iochannel_t *ioc,  +				  const mix_word_t *w, size_t s) +{ +  guint k, j; +   +  g_return_val_if_fail  (ioc != NULL, FALSE); +  g_return_val_if_fail (w != NULL, FALSE); +   +  for (k = 0; k < s; k++) +    for (j = 1; j < 6; j++) +      { +	mix_char_t ch = mix_word_get_byte (w[k], j); +	guchar value = mix_char_to_ascii (ch); +	if (!write_data_ (ioc, &value, 1)) return FALSE; +      } +  return TRUE; +} + +gboolean +mix_io_read_word_array_as_char (mix_iochannel_t *ioc, +				mix_word_t *w, size_t s) +{ +  guint k, j; +   +  g_return_val_if_fail (ioc != NULL, FALSE); +  g_return_val_if_fail (w != NULL, FALSE); + +  for (k = 0; k < s; k++) +    for (j = 1; j < 6; j++) +      { +	guchar value; +	if (!read_data_ (ioc, &value, 1)) return FALSE; +	mix_word_set_byte (&w[k], j, mix_ascii_to_char (value)); +      } +  return TRUE; +} diff --git a/mixlib/mix_io.h b/mixlib/mix_io.h new file mode 100644 index 0000000..a63bda6 --- /dev/null +++ b/mixlib/mix_io.h @@ -0,0 +1,123 @@ +/* -*-c-*- ------------------ mix_io.h : + * Declarations for mix_iochannel_t and mix_file_t + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#ifndef MIX_IOCHANNEL_H +#define MIX_IOCHANNEL_H + +#include <stdio.h> +#include "mix_types.h" + +/* mix_iochannel_t: an object for input/output of mix types */ +typedef struct mix_iochannel_t mix_iochannel_t; + +/* Cast to mix_iochannel_t */ +#define MIX_IOCHANNEL(file)  (mix_iochannel_t *)(file) + +/* I/O channels can be created in different modes: */ +typedef enum {  +  mix_io_READ,			/* read existing file */ +  mix_io_WRITE,			/* write new file */ +  mix_io_RDWRT,			/* read/write existing from beginning */ +  mix_io_APPEND,		/* append to existing or new file */ +  mix_io_RAPPEND		/* read from beginning, append to end */ +} mix_fmode_t; + +/* Create from a file handle */ +extern mix_iochannel_t * +mix_io_new (FILE *file); + +/* Delete */ +extern void +mix_io_delete(mix_iochannel_t *ch); + +/* Convert to a FILE * */ +extern FILE * +mix_io_to_FILE (mix_iochannel_t *ioc); + +/* Read/write from/to an iochannel */ +extern gboolean +mix_io_eof(mix_iochannel_t *ioc); + +extern gboolean +mix_io_is_ready(mix_iochannel_t *ioc); + +extern gboolean +mix_io_write_byte(mix_iochannel_t *ioc, mix_byte_t b); + +extern gboolean +mix_io_write_byte_array(mix_iochannel_t *ioc, const mix_byte_t *b, +			size_t s); + + +extern mix_byte_t +mix_io_read_byte(mix_iochannel_t *ioc); + +extern gboolean +mix_io_read_byte_array(mix_iochannel_t *ioc, mix_byte_t *b, size_t s); + + +extern gboolean +mix_io_write_word(mix_iochannel_t *ioc, mix_word_t w); + + +extern gboolean +mix_io_write_word_array(mix_iochannel_t *ioc, const mix_word_t *w, +			size_t s); + +extern mix_word_t +mix_io_read_word(mix_iochannel_t *ioc); + +extern gboolean +mix_io_read_word_array(mix_iochannel_t *ioc, mix_word_t *w, size_t s); + +extern gboolean +mix_io_write_short(mix_iochannel_t *ioc, mix_short_t w); + + +extern gboolean +mix_io_write_short_array(mix_iochannel_t *ioc, const mix_short_t *w, +			size_t s); + +extern mix_short_t +mix_io_read_short(mix_iochannel_t *ioc); + +extern gboolean +mix_io_read_short_array(mix_iochannel_t *ioc, mix_short_t *w, size_t s); + + +extern gboolean +mix_io_write_char(mix_iochannel_t *ioc, mix_char_t c); + +extern mix_char_t +mix_io_read_char(mix_iochannel_t *ioc); + +extern gboolean +mix_io_write_word_array_as_char (mix_iochannel_t *ioc,  +				 const mix_word_t *w, size_t s); + +extern gboolean +mix_io_read_word_array_as_char (mix_iochannel_t *ioc, +				mix_word_t *w, size_t s); + + +#endif /* MIX_IOCHANNEL_H */ + diff --git a/mixlib/mix_parser.c b/mixlib/mix_parser.c new file mode 100644 index 0000000..6a58f3e --- /dev/null +++ b/mixlib/mix_parser.c @@ -0,0 +1,525 @@ +/* -*-c-*- -------------- mix_parser.c : + * Implementation of the functions declared in mix_parser.h and  + * xmix_parser.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + +#include "mix.h" +#include "mix_code_file.h" +#include "xmix_parser.h" + +/* The flex-generated scanner, according to file mix_parser.l */ +extern mix_parser_err_t +mix_flex_scan (mix_parser_t *parser); + +/*------------ mixparser.h functions -------------------------------------*/ + +/* error messages */ +static const gchar * const ERR_MESSAGE_[] = { +  N_("successful compilation"), +  N_("file not yet compiled"), +  N_("internal error"), +  N_("unable to open MIX source file"), +  N_("unable to open MIX output file"), +  N_("unexpected end of file"), +  N_("invalid location field"), +  N_("duplicated symbol"), +  N_("symbol too long"), +  N_("missing operator field"), +  N_("unexpected location symbol"), +  N_("invalid address field"), +  N_("invalid index field"), +  N_("invalid f-specification"), +  N_("invalid operation field"), +  N_("invalid expression"), +  N_("undefined symbol"), +  N_("mismatched parenthesis"), +  N_("unexpected f-specfication"), +  N_("missing symbol name"), +  N_("symbol is an instruction name"), +  N_("failed write access to code file"), +  N_("operand of ALF pseudo instruction has less than 5 chars"), +  N_("operand of ALF pseudo instruction has more than 5 chars") +}; + +static const guint NO_OF_MESSAGES_ = sizeof(ERR_MESSAGE_)/sizeof (gchar*); + +const gchar * +mix_parser_err_string (mix_parser_err_t error) +{ +  return (error < NO_OF_MESSAGES_) ? _(ERR_MESSAGE_[error]) : NULL; +} + +guint  +mix_parser_err_count (const mix_parser_t *parser) +{ +  return (parser) ? parser->err_count : 0; +} + +guint  +mix_parser_warning_count (const mix_parser_t *parser) +{ +  return (parser) ? parser->warn_count : 0; +} + +const gchar * +mix_parser_src_file_base_name (const mix_parser_t *parser) +{ +  return (parser) ? mix_file_base_name (parser->in_file) : NULL; +} + +const gchar * +mix_parser_src_file_extension (const mix_parser_t *parser) +{ +  return (parser) ? mix_file_extension (parser->in_file) : NULL; +} + + +/* Create/destroy a mix_parser */ +/* compare function for the table of ins */ +static gint +compare_shorts_ (gconstpointer s1, gconstpointer s2) +{ +  mix_short_t a = (mix_short_t)GPOINTER_TO_UINT(s1); +  mix_short_t b = (mix_short_t)GPOINTER_TO_UINT (s2); +  if ( mix_short_sign (a) == mix_short_sign (b) ) +    return mix_short_magnitude (a) - mix_short_magnitude (b); +  else if ( mix_short_magnitude (a) == 0 && mix_short_magnitude (b) == 0 ) +    return 0; +  else if ( mix_short_is_positive (a) )  +    return 1; +  return -1; +} + +mix_parser_t * +mix_parser_new (const gchar *in_file) +{ +  mix_parser_t *result; +  mix_file_t *f = mix_file_new_with_def_ext (in_file, mix_io_READ,  +					     MIX_SRC_DEFEXT); +   +  if ( f == NULL ) return NULL; +  result = g_new (mix_parser_t, 1); +  result->symbol_table = mix_symbol_table_new (); +  result->ls_table = mix_symbol_table_new (); +  result->cur_ls = 0; +  result->future_refs = g_hash_table_new (g_str_hash, g_str_equal); +  result->ins_table = g_tree_new (compare_shorts_); +  if ( result->symbol_table == NULL || result->future_refs == NULL +       || result->ins_table == NULL || result->ls_table == NULL ) +    { +      mix_symbol_table_delete (result->symbol_table); +      mix_symbol_table_delete (result->ls_table); +      g_hash_table_destroy (result->future_refs); +      g_tree_destroy (result->ins_table); +      mix_file_delete (f); +      g_free (result); +      g_warning (_("No system resources")); +      return NULL; +    } +  result->in_file = f; +  result->loc_count = MIX_SHORT_ZERO; +  result->status = MIX_PERR_NOCOMP; +  result->err_line = 0; +  result->err_count = 0; +  result->warn_count = 0; +  return result; +} + +static void +delete_list_vals_ (gpointer key, gpointer value, gpointer data) +{ +  g_free (key); +  g_slist_free ((GSList*)value); +} + +static int +delete_tree_vals_ (gpointer key, gpointer value, gpointer data) +{ +  g_free (value); +  return FALSE; +} + +void +mix_parser_delete (mix_parser_t *parser) +{ +  g_return_if_fail (parser != NULL); +  /* clear the GSList values of future_refs and its keys */ +  g_hash_table_foreach (parser->future_refs, delete_list_vals_, NULL); +  /* clear the ins_node_'s of the ins tree */ +  g_tree_traverse (parser->ins_table, delete_tree_vals_, G_IN_ORDER, NULL); +  /* destroy the tree and hash tables */ +  g_tree_destroy (parser->ins_table); +  mix_symbol_table_delete (parser->symbol_table); +  mix_symbol_table_delete (parser->ls_table); +  g_hash_table_destroy (parser->future_refs); +  mix_file_delete (parser->in_file); +  g_free (parser); +} + +/* Compile a mix source file */ +static gboolean +undef_warning_ (gpointer symbol, gpointer value, gpointer data) +{ +  mix_parser_log_error ((mix_parser_t *)data, MIX_PERR_UNDEF_SYM, 1, +			(const gchar *)symbol, TRUE); +  /* move the symbol to the symbol table */ +  mix_symbol_table_insert_static (((mix_parser_t *)data)->symbol_table, +				  symbol, MIX_WORD_ZERO); +  return TRUE; +} + +static void +update_future_refs_value_ (mix_parser_t *parser, const gchar *name, +			   mix_short_t value) +{ +  GSList *list = NULL; +  gpointer key; +   +  g_assert (parser != NULL && name != NULL); +  if ( g_hash_table_lookup_extended (parser->future_refs, name, &key,  +				     (gpointer *)&list) ) +    { +      GSList *tmp = list; +      ins_node_ *node; +      while ( tmp != NULL ) +	{ +	  node =  +	    (ins_node_ *)g_tree_lookup (parser->ins_table,tmp->data); +	  g_assert (node); +	  if (mix_get_ins_address (node->ins) == 1) { +	    value = mix_short_negative (value); +	    node->ins = mix_word_set_field (node->ins, +					    MIX_WORD_ZERO, +					    mix_fspec_new (1,2)); +	  } +	  mix_word_add_address (node->ins, value); +	  g_tree_insert (parser->ins_table, tmp->data, (gpointer)node); +	  tmp = g_slist_next (tmp); +	} +      g_hash_table_remove (parser->future_refs, name); +      g_free (key); +      g_slist_free (list); +    } +} + +#define update_future_refs_(parser,name) \ +  update_future_refs_value_(parser, name, (parser)->loc_count); + +static void +update_ls_ (gpointer symbol, gpointer value, gpointer parser) +{ /* add an instruction on current location and update refs to it */ +  mix_ins_t ins; +  mix_word_t w = (mix_word_t) GPOINTER_TO_UINT (value); +  mix_parser_t *par = (mix_parser_t *) parser; +   +  mix_word_to_ins_uncheck (w, ins); +  mix_parser_add_ins (par, &ins, 0); +  update_future_refs_ (par, (const gchar *)symbol); +  par->loc_count++; +} + +mix_parser_err_t +mix_parser_compile (mix_parser_t *parser) +{ +  g_return_val_if_fail (parser != NULL, MIX_PERR_INTERNAL); +  g_return_val_if_fail (parser->in_file != NULL, MIX_PERR_NOIN); +  g_return_val_if_fail (parser->symbol_table != NULL, MIX_PERR_INTERNAL); +  g_return_val_if_fail (parser->future_refs != NULL, MIX_PERR_INTERNAL); +  g_return_val_if_fail (parser->ins_table != NULL, MIX_PERR_INTERNAL); +   +  parser->status = mix_flex_scan (parser); +  if ( parser->status == MIX_PERR_OK ) +    { +      mix_symbol_table_foreach (parser->ls_table, update_ls_,  +				(gpointer)parser); +      g_hash_table_foreach_remove (parser->future_refs,  +				   undef_warning_, (gpointer)parser); +    } +   +  return parser->status; +} + +/* Write a compiled source to a code file */ +struct write_code_context_ +{ +  mix_code_file_t *file; +  mix_parser_t *parser; +}; + +static gint +write_code_ (gpointer address, gpointer ins_node, gpointer context) +{ +  mix_ins_desc_t desc; +  struct write_code_context_ *cntx = (struct write_code_context_ *)context; +  desc.ins = ((ins_node_ *)ins_node)->ins; +  desc.lineno = ((ins_node_ *)ins_node)->lineno; +  desc.address = (mix_address_t)GPOINTER_TO_UINT (address); +  if ( mix_code_file_write_ins (cntx->file, &desc) ) +    return FALSE; +  else  +    { +      cntx->parser->status = MIX_PERR_NOWRITE; +      return TRUE; +    } +} + +mix_parser_err_t +mix_parser_write_code (mix_parser_t *parser, const gchar *code_file,  +		       gboolean debug) +{ +  struct write_code_context_ context; +  const gchar *cfname = (code_file) ? +    code_file : mix_file_base_name (parser->in_file); +  gchar *dir; +  gchar *source_path; +     +  g_return_val_if_fail (parser != NULL, MIX_PERR_INTERNAL); +  if  (parser->status != MIX_PERR_OK ) return parser->status; +  context.parser = parser; +  dir = g_get_current_dir (); +  source_path = g_strconcat (dir, G_DIR_SEPARATOR_S, +			     mix_file_base_name (parser->in_file), NULL); +  context.file = mix_code_file_new_write (cfname, parser->start, source_path, +					  debug, parser->symbol_table); +  g_free (dir); +  g_free (source_path); +  if (context.file == NULL) return MIX_PERR_NOOUT; +  g_tree_traverse (parser->ins_table, write_code_,  +		   G_IN_ORDER, (gpointer)&context); +  mix_code_file_delete (context.file); +  return parser->status; +} + +/* Produce a listing file summarising the compilation */ +static gint +write_listing_ (gpointer address, gpointer ins, gpointer context) +{ +  guint k; +  FILE *file = (FILE *)context; +  ins_node_ *ins_node = (ins_node_ *)ins; +  mix_ins_t instruct; +  gchar *instext = NULL; + +  mix_ins_id_t id = mix_word_to_ins (ins_node->ins, &instruct); +  if (id != mix_INVALID_INS) +    instext = mix_ins_to_string (&instruct); +  fprintf (file, "%d\t%s ", GPOINTER_TO_INT (address), +	   mix_word_is_negative (ins_node->ins)? "-":"+"); +  for ( k = 1; k < 6; ++k ) +    fprintf (file, "%02d ", mix_word_get_byte (ins_node->ins, k)); +  fprintf (file, _("\t%s\t(line %d)\n"), instext? instext:"--DATA--", +	   ins_node->lineno); +  if (instext) g_free (instext); +  return FALSE; +} + +mix_parser_err_t +mix_parser_write_listing (mix_parser_t *parser, const gchar *list_file) +{ +  FILE *file; +  mix_file_t *mfile; +  const gchar *name; +   +  g_return_val_if_fail (parser != NULL, MIX_PERR_INTERNAL); +  if (parser->status != MIX_PERR_OK ) return parser->status; +  name = (list_file) ? list_file : mix_file_base_name (parser->in_file); +  mfile =  mix_file_new_with_def_ext (name, mix_io_WRITE, MIX_LIST_DEFEXT); +  if ( mfile == NULL ) return MIX_PERR_NOOUT; +  file = mix_file_to_FILE (mfile); +  fprintf (file, _("*** %s%s: compilation summary ***\n\n"),  +	   mix_file_base_name (parser->in_file),  +	   mix_file_extension (parser->in_file)); +  fputs ( _("*** Address / Compiled word / Symbolic rep / Source file line\n"), +	  file); +  g_tree_traverse (parser->ins_table, write_listing_,  +		   G_IN_ORDER, (gpointer)file); +  fprintf (file, _("\n*** Start address: %d\n"),  +	   mix_short_magnitude (parser->start)); +  fprintf (file, _("\n*** Symbol table\n")); +  mix_symbol_table_print (parser->symbol_table, MIX_SYM_ROWS, file, TRUE); +  fprintf (file, _("\n*** End of summary ***\n")); +  mix_file_delete (mfile); +  return parser->status; +} + +/* load a virtual machine's memory with the contents of a compiled file */ +static gint +load_vm_ (gpointer address, gpointer ins, gpointer vm) +{ +  mix_vm_set_addr_contents ((mix_vm_t*)vm, +			    (mix_address_t)GPOINTER_TO_UINT (address),  +			    ((ins_node_ *)ins)->ins); +  return FALSE; +} + +mix_parser_err_t +mix_parser_load_vm (const mix_parser_t *parser, mix_vm_t *vm) +{ +  g_return_val_if_fail (parser != NULL, MIX_PERR_INTERNAL); +  g_return_val_if_fail (vm != NULL, MIX_PERR_INTERNAL); +  g_return_val_if_fail (parser->status == MIX_PERR_OK, parser->status); +  mix_vm_reset (vm); +  g_tree_traverse (parser->ins_table, load_vm_, G_IN_ORDER, (gpointer)vm); +  mix_vm_set_start_addr (vm, parser->start); +  return parser->status; +} + + + +/*------------ xmiparser.h functions -------------------------------------*/ +/* functions to manipulate mix_parser_t during compilation */ + + +/* symbol table */ +/* Define a new symbol with value equal to the current loc_count + * and update future refs to this symbol + */ +mix_parser_err_t +mix_parser_define_symbol_here (mix_parser_t *parser, const gchar *name) +{ +  mix_word_t value = mix_short_to_word_fast (parser->loc_count); +  return mix_parser_define_symbol_value (parser, name, value); +} + +mix_parser_err_t +mix_parser_define_symbol_value (mix_parser_t *parser, const gchar *name, +				mix_word_t value) +{ +  g_assert (parser != NULL && name != NULL);   +   +  switch (mix_symbol_table_add (parser->symbol_table, name, value)) +    { +    case MIX_SYM_OK:  +      if ( parser->status == MIX_PERR_NOCOMP )  +	update_future_refs_value_ (parser, name, value); +      return MIX_PERR_OK; +    case MIX_SYM_LONG: return MIX_PERR_LONG_SYMBOL; +    case MIX_SYM_DUP: return MIX_PERR_DUP_SYMBOL; +    default: return MIX_PERR_INTERNAL; +    } +} + +/* Obtain the value of a symbol */ +void +mix_parser_set_future_ref (mix_parser_t *parser, const gchar *name) +{ +  const gchar *nname = name; +  GSList *list; + +  g_assert (parser != NULL && name != NULL); + +  if ( parser->status == MIX_PERR_NOCOMP ) +    { +      list =  g_hash_table_lookup (parser->future_refs, name); +      if ( list == NULL ) nname = g_strdup (name); +      list = g_slist_prepend (list, (gpointer)((guint)parser->loc_count)); +      g_hash_table_insert (parser->future_refs, (gpointer)nname, list); +    } +} + +/* Redefine the value of a local symbol as the current loc_count */ +void +mix_parser_manage_local_symbol (mix_parser_t *parser, const gchar *name, +				mix_short_t value) +{ +  gchar ref[3]; +  ref[2] = 0; +     +  g_assert (parser != NULL && name != NULL); +  g_assert (strlen(name) == 2); +   +  switch (name[1]) +    { +    case 'f': case 'F': +      mix_parser_set_future_ref (parser, name); +      break; +    case 'h': case 'H': +      ref[0] = name[0]; +      ref[1] = 'F'; +      if ( parser->status == MIX_PERR_NOCOMP )  +	update_future_refs_value_ (parser, ref, value); +      ref[1] = 'B'; +      mix_symbol_table_insert (parser->symbol_table, ref,  +			       mix_short_to_word_fast (value)); +      break; +    default: +      return; +    } +} + +/* Literal strings symbols */ +void +mix_parser_define_ls (mix_parser_t *parser, mix_word_t value) +{ +  gchar *name = g_strdup_printf ("%05d", parser->cur_ls++); +  mix_symbol_table_add (parser->ls_table, name, value); +  mix_parser_set_future_ref (parser, name); +  g_free (name); +} + +/* Compilation */ +void +mix_parser_add_ins (mix_parser_t *parser, const mix_ins_t *new_ins,  +		    guint lineno) +{ +  g_assert (parser != NULL && new_ins != NULL); +  mix_parser_add_raw (parser, mix_ins_to_word_uncheck (*new_ins), lineno); +} + +void +mix_parser_add_raw (mix_parser_t *parser, mix_word_t word, guint lineno) +{ +  g_assert (parser != NULL); +  if ( parser->status == MIX_PERR_NOCOMP || parser->status == MIX_PERR_OK ) +    { +      ins_node_ *node = g_new (ins_node_, 1); +      node->ins = word; +      node->lineno = lineno; +      g_tree_insert (parser->ins_table, (gpointer)((guint)parser->loc_count), +		     (gpointer)node); +    } +} + +/* Error handling */ +void  +mix_parser_log_error (mix_parser_t *parser, mix_parser_err_t error, +		      gint lineno, const gchar *comment, gboolean warn) +{ +  g_assert (parser != NULL); +  if ( warn ) +    parser->warn_count += 1; +  else +    { +      parser->err_count += 1; +      parser->err_line = lineno; +      parser->status = error; +    } +     +  fprintf (stderr, "%s%s:%d: %s: %s", +	   mix_file_base_name (parser->in_file),  +	   mix_file_extension (parser->in_file), +	   lineno, warn ? _("warning"):_("error"), _(ERR_MESSAGE_[error])); + +  if (comment != NULL) +    fprintf (stderr, ": %s\n", comment); +  else +    fputs ("\n", stderr); +} + diff --git a/mixlib/mix_parser.h b/mixlib/mix_parser.h new file mode 100644 index 0000000..f371430 --- /dev/null +++ b/mixlib/mix_parser.h @@ -0,0 +1,110 @@ +/* -*-c-*- ---------------- mix_parser.h : + * Declarations for mix_parser_t, which compiles a source file into + * a mix code file. + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#ifndef MIX_PARSER_H +#define MIX_PARSER_H + +#include <glib.h> +#include "mix_vm.h" + +/* The parser type */ +typedef struct mix_parser_t mix_parser_t; + +/* Create/destroy a mix_parser */ +extern mix_parser_t * +mix_parser_new(const gchar *in_file); + +extern void +mix_parser_delete(mix_parser_t *parser); + +/* Access source file name */ +extern const gchar * +mix_parser_src_file_base_name(const mix_parser_t *parser); + +extern const gchar * +mix_parser_src_file_extension(const mix_parser_t *parser); + +/* Compile a mix source file */ +/* compilation errors */ +typedef enum {  +  MIX_PERR_OK,		/* no error */ +  MIX_PERR_NOCOMP,	/* file not yet compiled */ +  MIX_PERR_INTERNAL,	/* internal error */ +  MIX_PERR_NOIN,	/* unable to open input file */ +  MIX_PERR_NOOUT,	/* unable to open output file */ +  MIX_PERR_UNEX_EOF,	/* unexpected end of file */ +  MIX_PERR_INV_LOC,	/* invalid loc field */ +  MIX_PERR_DUP_SYMBOL,	/* duplicated symbol */ +  MIX_PERR_LONG_SYMBOL,	/* symbol name too long */ +  MIX_PERR_NOOP,	/* missing op field */ +  MIX_PERR_UNEX_LOC,	/* unexpected location symbol */ +  MIX_PERR_INV_ADDRESS, /* invalid address field */ +  MIX_PERR_INV_IDX,	/* invalid index field */ +  MIX_PERR_INV_FSPEC,	/* invalid fspec */ +  MIX_PERR_INV_OP,	/* invalid operation */ +  MIX_PERR_INV_EXPR,	/* invalid expression */ +  MIX_PERR_UNDEF_SYM,	/* undefined symbol */ +  MIX_PERR_MIS_PAREN,	/* mismatched parenthesis */ +  MIX_PERR_UNEX_FSPEC,	/* unexpected f-spec */ +  MIX_PERR_MIS_SYM,	/* missing symbol name */ +  MIX_PERR_SYM_INS,	/* symbol has the same name as instruction */ +  MIX_PERR_NOWRITE,	/* failed code write */ +  MIX_PERR_SHORT_ALF,	/* short ALF operand */ +  MIX_PERR_LONG_ALF	/* too long ALF operand */ +} mix_parser_err_t; + +extern const gchar * +mix_parser_err_string(mix_parser_err_t error); + +extern mix_parser_err_t +mix_parser_compile(mix_parser_t *parser); + +extern guint  +mix_parser_warning_count(const mix_parser_t *parser); + +extern guint  +mix_parser_err_count(const mix_parser_t *parser); + +/* Write the compilation result to a code file with the given name. +   code_file is completed, if required, with the requisite extension; +   if code_file == NULL [source_file_name].[extension] is used. +   If debug == TRUE, debug information is written. +*/ +extern mix_parser_err_t +mix_parser_write_code(mix_parser_t *parser, const gchar *code_file, +		      gboolean debug); + +/* Write a "canonical" listing of a compiled source, i.e. a source +   file with all symbols substituted by their actual values after +   compilation. +*/ +extern mix_parser_err_t +mix_parser_write_listing(mix_parser_t *parser, const gchar *list_file); + +/* load a virtual machine's memory with the contents of a compiled file */ +extern mix_parser_err_t +mix_parser_load_vm(const mix_parser_t *parser, mix_vm_t *vm); + + +#endif /* MIX_PARSER_H */ + diff --git a/mixlib/mix_scanner.l b/mixlib/mix_scanner.l new file mode 100644 index 0000000..f961fe6 --- /dev/null +++ b/mixlib/mix_scanner.l @@ -0,0 +1,532 @@ +/* ------------------ mix_scanner.l : + * Lexical scanner used by mix_parser_t + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + +%{ +#include "mix.h" +#include "xmix_parser.h" + +#define YY_DECL mix_parser_err_t mix_flex_scan (mix_parser_t *parser) + +#define RESET()					\ +  do {						\ +    mix_ins_fill_from_id (ins, mix_NOP);	\ +    ins.address = 0;				\ +    ins.index = 0;				\ +    nof = FALSE;				\ +    lsf = FALSE;				\ +    if (symbol != NULL )			\ +     {						\ +       g_free (symbol);				\ +       symbol = NULL;				\ +     }						\ +    if (lsymbol != NULL)			\ +     {						\ +       g_free (lsymbol);			\ +       lsymbol = NULL;				\ +     }                       			\ +  } while (FALSE) + +#define NEXT()						\ +  do {							\ +    if (lsymbol != NULL)				\ +       mix_parser_manage_local_symbol (parser,lsymbol,  \ +				       loc);    	\ +    parser->loc_count++;				\ +    RESET ();						\ +    ++lineno;						\ +    BEGIN (INITIAL);					\ +  } while (FALSE) + +#define ADD_INS()				\ +  do {						\ +    mix_parser_add_ins (parser, &ins, lineno);	\ +    NEXT ();					\ +  } while (FALSE) + +#define ADD_RAW(value)				\ +  do {						\ +    mix_parser_add_raw (parser, value, lineno);	\ +    NEXT ();	               			\ +  } while (FALSE) + + +#define ENTER_EVAL()				\ +  do {						\ +    if (yytext[0] != '*')                       \ +      {                                         \ +        expr_val = MIX_WORD_ZERO;		\ +        yyless (0);				\ +      }                                         \ +    else                                        \ +      {                                         \ +        expr_val = mix_short_to_word_fast (parser->loc_count); \ +	yyless (1);                             \ +      }                                         \ +    yy_push_state (EVAL);			\ +  } while (FALSE) + +#define ENTER_WEVAL()				\ +  do {						\ +    wexpr_val = MIX_WORD_ZERO;			\ +    wexpr_val_tmp = MIX_WORD_ZERO;		\ +    is_fp = FALSE;                              \ +    yyless (0);					\ +    yy_push_state (WEVAL);			\ +  } while (FALSE) + +#define RETURN_ERROR(error, comment)				\ +  do {								\ +    char c;							\ +    mix_parser_log_error (parser,error,lineno,comment,FALSE);	\ +    while ( (c = input ()) != '\n' && c != EOF ) ;		\ +    if ( c == EOF ) return error; else ++lineno;		\ +    RESET ();							\ +    BEGIN (INITIAL);						\ +  } while (FALSE) + +  +static mix_word_t +  eval_binop_ (const gchar *op, mix_word_t x, mix_word_t y); +  +static void +  unput_word_ (mix_word_t word); +  +%} + +%option nomain +%option caseless +%option pointer +%option stack +%option noyywrap +%option noyy_top_state +%option noreject +%option outfile="lex.yy.c" + +%s  LOC +%s  OP +%s  ADDRESS +%s  INDEX +%s  FSPEC +%s  EVAL +%s  WEVAL +%s  ORIG +%s  CON +%s  EQU +%s  END + +ws	[ \t]+ +digit	[0-9] +letter	[A-Z] +number	[+-]?{digit}+ +mixchar [0-9A-Z .,'')(+*/=$<>@;:\-] +locsymbol   {digit}H +flocsymbol  {digit}F +blocsymbol  {digit}B +symbol	{digit}*{letter}+[A-Z0-9]* +binop	"+"|"-"|"*"|"/"|"//"|":" +atexpr	{digit}+|{symbol}|\* +expr	[+-]?{atexpr}({binop}{1}{atexpr})* +fpart   \({expr}\) +wexpr   {expr}({fpart})?(,{expr}({fpart})?)* +   + +%% + +%{ + +  mix_ins_t ins; +  gboolean nof = FALSE, is_fp = FALSE, end = FALSE, lsf = FALSE; +  mix_word_t expr_val = MIX_WORD_ZERO, wexpr_val = MIX_WORD_ZERO, +  wexpr_val_tmp = MIX_WORD_ZERO; +  gchar *symbol = NULL, *lsymbol = NULL; +  mix_address_t loc = MIX_SHORT_ZERO; +  guint lineno = 1; +  mix_ins_fill_from_id (ins, mix_NOP);		 +  ins.address = 0;				 +  ins.index = 0;				 +  parser->err_line = 0; +  yyin = mix_file_to_FILE (parser->in_file); +   +%} +   + +<*><<EOF>> { +  mix_parser_log_error (parser, MIX_PERR_UNEX_EOF, lineno, NULL, FALSE); +  return MIX_PERR_UNEX_EOF; +} + +<INITIAL>{ +  ^\*.*	/* eat comments */ +  .	{ +    if ( end ) return parser->status; +    yyless (0); +    BEGIN (LOC); +  } +  \n {  +    ++lineno; +    if ( end ) return parser->status;  +  } +}			 + +<LOC>{ +  {ws}+	BEGIN (OP); /* LOC field is empty */ +  {locsymbol} { /* manage local symbol */ +    loc = get_ploc_ (parser); +    lsymbol = g_strdup (yytext); +    if ( lsymbol == NULL ) { +      mix_parser_log_error (parser, MIX_PERR_INTERNAL, lineno, NULL, FALSE); +      return MIX_PERR_INTERNAL; +    } +    BEGIN (OP); +  } +  {locsymbol}/({ws}+EQU) {/* local symbol with value */ +    loc = get_ploc_ (parser); +    symbol = g_strdup (yytext); +    lsymbol = g_strdup (yytext); +    if ( symbol == NULL || lsymbol == NULL) { +      mix_parser_log_error (parser, MIX_PERR_INTERNAL, lineno, NULL, FALSE); +      return MIX_PERR_INTERNAL; +    } +    symbol[1] = 'B'; /* this will be referred as nB afterwards */ +    BEGIN (OP); +  }     +  {flocsymbol}|{blocsymbol} RETURN_ERROR (MIX_PERR_UNEX_LOC, yytext); +  {symbol}/({ws}+EQU) { /* store symbol name for future definition */ +    symbol = g_strdup (yytext); +    if ( symbol == NULL ) { +      mix_parser_log_error (parser, MIX_PERR_INTERNAL, lineno, NULL, FALSE); +      return MIX_PERR_INTERNAL; +    } +    BEGIN (OP); +  } +  {symbol} { /* define a new symbol */ +    mix_parser_err_t err; +    if ( mix_get_id_from_string (yytext) != mix_INVALID_INS ) +      mix_parser_log_error (parser, MIX_PERR_SYM_INS, lineno, yytext, TRUE); +    if ( (err = mix_parser_define_symbol_here (parser,yytext)) != MIX_PERR_OK ) +      mix_parser_log_error (parser, err, lineno, yytext, FALSE); +    BEGIN (OP); +  } +  .	RETURN_ERROR (MIX_PERR_INV_LOC, yytext); +  \n 	++lineno; /* empty line */ +} + +<OP>{ +  {ws} /* eat leading whitespace */ +  \n    RETURN_ERROR (MIX_PERR_NOOP, NULL); +  ORIG{ws}+  BEGIN (ORIG); +  CON{ws}+   BEGIN (CON); +  EQU{ws}+   BEGIN (EQU); +  END{ws}+   BEGIN (END); +  ALF{ws}+\"{mixchar}{5,}\"{ws}+.*\n | +  ALF{ws}+\"{mixchar}{5,}\"{ws}*\n { +    mix_byte_t bytes[5]; +    mix_word_t value; +    guint k, j = 4; + +    while ( yytext[j++] != '\"' ) ; +    for ( k = j; k < 5+j && yytext[k] != '\"'; ++k ) +      bytes[k-j] = mix_ascii_to_char (yytext[k]); +    if ( k-j < 5 ) +      mix_parser_log_error (parser, MIX_PERR_SHORT_ALF, lineno, NULL, TRUE); +    else if ( yytext[k] != '\"' ) +      mix_parser_log_error (parser, MIX_PERR_LONG_ALF, lineno, NULL, TRUE); + +    value = mix_bytes_to_word (bytes, 5); +     +    ADD_RAW (value); +   } +  [A-Z0-9]+{ws}*/\n |     +  [A-Z0-9]+{ws}+ { +    mix_ins_id_t id = mix_get_id_from_string (g_strchomp (yytext)); +    if ( id == mix_INVALID_INS ) +      mix_parser_log_error (parser, MIX_PERR_INV_OP, lineno, yytext, FALSE); +    else { +      mix_ins_fill_from_id (ins, id); +      nof = mix_ins_id_is_extended (id); +    } +    BEGIN (ADDRESS); +  } +  {expr} RETURN_ERROR (MIX_PERR_INV_OP, yytext); +  .  RETURN_ERROR (MIX_PERR_INV_OP, yytext);		 +} + + +<ORIG>{ +  {number}{ws}*\n   | +  {number}{ws}+.*\n { +    mix_word_t value = mix_word_new (atol (yytext)); +    parser->loc_count = mix_word_to_short_fast (value); +    ++lineno; +    BEGIN (INITIAL); +  } +} + +<CON>{ +  {number}{ws}*\n | +  {number}{ws}+.*\n  { +    mix_word_t value = mix_word_new (atol (yytext)); +    mix_word_to_ins_uncheck (value, ins); +    ADD_INS (); +  } +} + +<EQU>{ +  {number}{ws}*\n   | +  {number}{ws}+.*\n { +    mix_word_t value; +    gint def; +    if ( symbol == NULL ) RETURN_ERROR (MIX_PERR_MIS_SYM, NULL); +    value = mix_word_new (atol (yytext)); +    def = mix_parser_define_symbol_value (parser, symbol, value); +    if ( def == MIX_SYM_DUP )  RETURN_ERROR (MIX_PERR_DUP_SYMBOL, symbol); +    if ( def == MIX_SYM_LONG )  RETURN_ERROR (MIX_PERR_LONG_SYMBOL, symbol); +    ++lineno; +    BEGIN (INITIAL); +  } +} + +<END>{ +  {number}{ws}*\n   | +  {number}{ws}+.*\n { +    parser->start = mix_short_new (atol (yytext)); +    end = TRUE; +    if ( parser->status == MIX_PERR_NOCOMP ) parser->status = MIX_PERR_OK; +    return parser->status; +  } +} + +<ORIG,CON,EQU,END>{ +  {wexpr} ENTER_WEVAL (); +  . RETURN_ERROR (MIX_PERR_INV_OP, yytext); +} + + +<ADDRESS,INDEX,FSPEC>{locsymbol}  RETURN_ERROR (MIX_PERR_UNEX_LOC, yytext); + +<ADDRESS>{ +  =/[+-]?{number}=  lsf = TRUE; +  =/{expr}=     lsf = TRUE; +  [+-]?{number}={ws}*\n   | +  [+-]?{number}={ws}+.*\n { +    if (!lsf) RETURN_ERROR (MIX_PERR_INV_ADDRESS, yytext); +    mix_parser_define_ls (parser, mix_word_new (atol (yytext))); +    ADD_INS (); +  } +  [+-]?{number}{ws}+.*\n | +  [+-]?{number}[(,\n] { +    ins.address = mix_short_new (atol (yytext)); +    switch ( yytext[yyleng-1] ) { +    case '(' : BEGIN (FSPEC); break;  +    case ',' : BEGIN (INDEX); break; +    case '\n' : ADD_INS (); break; +    default: g_assert_not_reached (); +    } +  } +  ([+-]?{symbol})/[(,\n\t ] { +    gboolean neg = (yytext[0] == '-'); +    const gchar *s = (neg || yytext[0] == '+')? yytext+1 : yytext; +    if ( !mix_symbol_table_is_defined (parser->symbol_table, s) ) +      { +	mix_parser_set_future_ref (parser, s); +	if (neg) +	  mix_parser_log_error (parser, MIX_PERR_UNDEF_SYM, lineno, s, TRUE); +	unput (neg? '1':'0'); +      } +    else +      { +	mix_word_t v = mix_symbol_table_value (parser->symbol_table, s); +	if ( neg ) mix_word_reverse_sign (v); +	unput_word_ (v); +      } +  } +  {expr}/[(,=\n\t ] ENTER_EVAL (); +  \n    ADD_INS (); +  .	RETURN_ERROR (MIX_PERR_INV_ADDRESS, yytext); +} +	 + +<INDEX>{ +  {number}[\n(\t ] { +    int end = yytext[yyleng-1]; +    ins.index = mix_byte_new (atol (yytext)); +    if ( end == '\n' ) +      ADD_INS (); +    else if ( end == '(' ) +      BEGIN (FSPEC); +    else +      { /* eat rest of line (comment) */ +	while ( (end = input()) != '\n' && end != EOF ) ; +	if ( end == '\n' ) ADD_INS (); +	else RETURN_ERROR (MIX_PERR_UNEX_EOF, NULL); +      } +  } +  {expr}/[\n(\t ]  ENTER_EVAL (); +  \n	{ +    mix_parser_log_error (parser, MIX_PERR_INV_IDX, lineno++, NULL, FALSE); +    RESET ();  +    BEGIN (INITIAL); +  } +  .	RETURN_ERROR (MIX_PERR_INV_IDX, yytext); +} + +<FSPEC>{ +  {number}")"(({ws}+.*\n)|\n) { +    glong val  = atol (yytext); +    if ( val < 0 || val > MIX_BYTE_MAX )  +      RETURN_ERROR (MIX_PERR_INV_FSPEC, NULL); +    if ( ins.opcode != mix_opMOVE  +         && ( ins.opcode < mix_opJBUS || ins.opcode > mix_opJXx ) +         && !mix_fspec_is_valid (mix_byte_new (val)) ) +      RETURN_ERROR (MIX_PERR_INV_FSPEC, NULL); +    if ( nof )  +      mix_parser_log_error (parser, MIX_PERR_INV_FSPEC, +			    lineno, _("ignored"), TRUE); +    else +      { +	ins.fspec = mix_byte_new (val); +	ADD_INS (); +      } +  } +  {expr}/")"  { +    ENTER_EVAL (); +  } +  .	RETURN_ERROR (MIX_PERR_INV_FSPEC, yytext); +} + + +<EVAL>{ +  {binop}{digit}+ { +    const gchar *s = ( yytext[1] == '/' ) ? yytext+2 : yytext+1; +    mix_word_t value = mix_word_new (atol (s)); +    expr_val = eval_binop_ (yytext, expr_val, value); +  } +  {binop}{symbol} { +    const gchar *s = ( yytext[1] == '/' ) ? yytext+2 : yytext+1; +    if ( !mix_symbol_table_is_defined (parser->symbol_table, s) ) { +      mix_parser_log_error (parser, MIX_PERR_UNDEF_SYM, lineno, s, FALSE); +      yy_pop_state (); +    } +    expr_val = eval_binop_ (yytext, expr_val,  +			    mix_symbol_table_value (parser->symbol_table, s)); +  } +  {binop}"*" { +    expr_val = eval_binop_ (yytext, expr_val,  +			    mix_short_to_word_fast (parser->loc_count)); +  } +  "*"         unput_word_ (mix_short_to_word_fast (parser->loc_count)); +  {number}    expr_val = mix_word_new (atol (yytext)); +  {symbol} { +    if ( !mix_symbol_table_is_defined (parser->symbol_table, yytext) ) { +      mix_parser_log_error (parser, MIX_PERR_UNDEF_SYM, lineno, yytext, FALSE); +      yy_pop_state (); +    } +    expr_val = mix_symbol_table_value (parser->symbol_table, yytext); +  } +  [,)(=\n\t ]   unput (yytext[0]); unput_word_ (expr_val); yy_pop_state (); +  .   RETURN_ERROR (MIX_PERR_INV_EXPR, yytext); +} + +<WEVAL>{ +  {number}"(" { +    is_fp = TRUE; +    wexpr_val_tmp = mix_word_new (atol (yytext)); +  } +  {number}")"  { +    glong val  = atol (yytext); +    if ( !is_fp ) { +      mix_parser_log_error (parser, MIX_PERR_MIS_PAREN, lineno, NULL, FALSE); +      yy_pop_state (); +    } +    if ( val < 0 || val > MIX_BYTE_MAX  +         || !mix_fspec_is_valid (mix_byte_new (val)) ) { +      mix_parser_log_error (parser, MIX_PERR_INV_FSPEC, lineno, NULL, FALSE); +      yy_pop_state (); +    } +    is_fp = FALSE; +    wexpr_val = mix_word_store_field (mix_byte_new (val), wexpr_val_tmp,  +				      wexpr_val); +  } +  {number}/[,()\n\t ] wexpr_val = mix_word_new (atol (yytext)); +  {expr}/[,()\n\t ]  ENTER_EVAL (); +  ,/{expr} /* eat comma if followed by expression */ +  [\n\t ] { /* ok if not inside an f-part */ +    if ( is_fp ) { +      mix_parser_log_error (parser, MIX_PERR_MIS_PAREN, lineno, NULL, FALSE); +      yy_pop_state (); +     } +    unput (yytext[yyleng-1]); +    unput_word_ (wexpr_val); +    yy_pop_state (); +  } +  .  RETURN_ERROR (MIX_PERR_INV_EXPR, NULL); +} + +%% + +static mix_word_t +eval_binop_ (const gchar *op, mix_word_t x, mix_word_t y) +{ +  mix_word_t result = MIX_WORD_ZERO; +  switch (op[0]) +    { +    case '+':  +      result = mix_word_add (x,y);  +      break; +    case '-': +      result = mix_word_sub (x,y); +      break; +    case '*': +      mix_word_mul (x, y, NULL, &result); +      break; +    case ':': +      { +	mix_word_t a; +	mix_word_mul (x, 8, NULL, &a); +	result = mix_word_add (a, y); +	break; +      } +    case '/': +      if ( strlen (op) > 1 && op[1] == '/' ) { +	mix_word_div (x,MIX_WORD_ZERO,y, &result, NULL); +      } else { +	mix_word_div (MIX_WORD_ZERO, x, y, &result, NULL); +      } +      break; +    default: +      g_assert_not_reached (); +    } +  return result; +} + + +static void +unput_word_ (mix_word_t word)					 +{								 +  gchar *value;						 +  gint k;							 +  value = g_strdup_printf ("%s%ld",				 +			   mix_word_is_negative (word)? "-":"+", +			   mix_word_magnitude (word));		 +  for (k = strlen (value) - 1; k >= 0; --k)			 +    unput (value[k]);						 +  g_free (value);						 +} diff --git a/mixlib/mix_src_file.c b/mixlib/mix_src_file.c new file mode 100644 index 0000000..4e1489b --- /dev/null +++ b/mixlib/mix_src_file.c @@ -0,0 +1,157 @@ +/* -*-c-*- -------------- mix_src_file.c : + * Implementation of the functions declared in mix_src_file.h + * ------------------------------------------------------------------ + *  Last change: Time-stamp: "01/03/10 15:23:46 jose" + * ------------------------------------------------------------------ + * Copyright (C) 2000, 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + +#include <ctype.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include "mix_src_file.h" + +/* the MIXAL source file type */ +struct mix_src_file_t  +{ +  gchar *path;			/* the path to the disk file */ +  GPtrArray *lines;		/* an array of the file lines */ +  guint lineno;			/* the number of lines */ +}; + +/* format a source line */ +static gchar * +format_line_ (gchar *line) +{ +  const gchar *label, *op, *rest; +  gint k = 0; +   +  if (!line) return line; +  if (line[0] == '*' || strlen(line) == 0) +    return g_strdup (line); +   +  if (isspace (line[0])) +    { +      label = " "; +      while (line[k] && isspace (line[k])) ++k; +    } +  else +    { +      label = line; +      while (line[k] && !isspace (line[k])) ++k; +      while (line[k] && isspace (line[k])) ++k; +    } +   +  if (line[k]) +    { +      line[k - 1] = 0; +      op = line + k; +      while (line[k] && !isspace (line[k])) ++k; +      while (line[k] && isspace (line[k])) ++k; +      line[k - 1] = 0; +      rest = (line[k]) ? line + k: ""; +    } +  else +    { +      op = rest = ""; +    } +   +   +  return g_strdup_printf ("%-11s %-5s %s", label, op, rest); +} + +/* load the source file lines into memory */ +static gboolean +load_file_ (mix_src_file_t *file) +{ +  mix_file_t *mf = mix_file_new_with_def_ext (file->path, +					      mix_io_READ, +					      MIX_SRC_DEFEXT); +  if (mf != NULL) +    { +      enum {BUFFER_SIZE = 256}; +      static gchar BUFFER[BUFFER_SIZE]; +       +      FILE  *f = mix_file_to_FILE (mf); +      file->lines = g_ptr_array_new (); +      file->lineno = 0; +       +      while (fgets (BUFFER, BUFFER_SIZE, f) == BUFFER) +	{ +	  g_ptr_array_add (file->lines, (gpointer) format_line_ (BUFFER)); +	  file->lineno++; +	} +       +      mix_file_delete (mf); +      return TRUE; +    } +  return FALSE; +} + +/* create a new src file from an existing disk file */ +mix_src_file_t * +mix_src_file_new_for_read (const gchar *path) +{ +  mix_src_file_t *result = g_new (mix_src_file_t, 1); +  result->lines = NULL; +  result->path = g_strdup (path); +  result->lineno = 0; +  return result; +} + +/* destroy a src file object */ +void +mix_src_file_delete (mix_src_file_t *src) +{ +  g_return_if_fail (src != NULL); +  if (src->lines) g_ptr_array_free (src->lines, TRUE); +  g_free (src->path); +  g_free (src); +} + +/* get the source file path */ +const gchar * +mix_src_file_get_path (const mix_src_file_t *src) +{ +  g_return_val_if_fail (src != NULL, NULL); +  return src->path; +} + +/* get a given line of the source file */ +const gchar * +mix_src_file_get_line (const mix_src_file_t *src, guint lineno) +{ +  g_return_val_if_fail (src != NULL, NULL); +  if (src->lines == NULL && !load_file_ ((mix_src_file_t*)src)) +    return NULL; +  if (lineno > src->lineno || lineno == 0) +    return NULL; +  return (gchar *)g_ptr_array_index (src->lines, lineno - 1); +} + +/* get the total no. of lines in the file */ +guint +mix_src_file_get_line_no (const mix_src_file_t *src) +{ +  g_return_val_if_fail (src != NULL, 0); +  if (src->lines == NULL && !load_file_ ((mix_src_file_t*)src)) +    return 0; +  return src->lineno; +} + diff --git a/mixlib/mix_src_file.h b/mixlib/mix_src_file.h new file mode 100644 index 0000000..1392df2 --- /dev/null +++ b/mixlib/mix_src_file.h @@ -0,0 +1,57 @@ +/* -*-c-*- ---------------- mix_src_file.h : + * Declaration of mix_src_file_t, a type representing a MIXAL source + * file. + * ------------------------------------------------------------------ + *  Last change: Time-stamp: <01/02/20 00:23:58 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#ifndef MIX_SRC_FILE_H +#define MIX_SRC_FILE_H + +#include "mix_file.h" + +/* the MIXAL source file type */ +typedef struct mix_src_file_t mix_src_file_t; + +/* create a new src file from an existing disk file */ +extern mix_src_file_t * +mix_src_file_new_for_read (const gchar *path); + +/* destroy a src file object */ +extern void +mix_src_file_delete (mix_src_file_t *src); + +/* get the source file path */ +extern const gchar * +mix_src_file_get_path (const mix_src_file_t *src); + +/* get a given line of the source file */ +extern const gchar * +mix_src_file_get_line (const mix_src_file_t *src, guint lineno); + +/* get the total no. of lines in the file */ +extern guint +mix_src_file_get_line_no (const mix_src_file_t *src); + + + +#endif /* MIX_SRC_FILE_H */ + diff --git a/mixlib/mix_symbol_table.c b/mixlib/mix_symbol_table.c new file mode 100644 index 0000000..33874ea --- /dev/null +++ b/mixlib/mix_symbol_table.c @@ -0,0 +1,196 @@ +/* -*-c-*- -------------- mix_symbol_table.c : + * Implementation of the functions declared in mix_symbol_table.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + +#include <ctype.h> /* isdigit */ +#include "mix_symbol_table.h" + +/* Create an empty table */ +mix_symbol_table_t * +mix_symbol_table_new(void) +{ +  return g_hash_table_new(g_str_hash, g_str_equal); +} + +/* Create a table and populate it with the contents of a table stored +   in -file- using mix_symbol_table_print(table, MIX_SYM_LINE, file) +*/ +mix_symbol_table_t * +mix_symbol_table_new_from_file(FILE *file) +{ +  mix_symbol_table_t *result = mix_symbol_table_new(); +  if ( result != NULL ) +    { +      gchar sym[MIX_SYM_MAX_LEN + 1]; +      glong val; +       +      while ( getc(file) == ',' ) +	{ +	  if ( fscanf(file, "%s =%ld", sym, &val) != EOF ) +	      mix_symbol_table_add(result, sym, mix_word_new(val)); +	} +    } +  return result; +} + +/* Delete a table */ +static void +delete_hash_keys_(gpointer key, gpointer value, gpointer data) +{ +  g_free(key); +} + +void +mix_symbol_table_delete(mix_symbol_table_t *table) +{ +  g_hash_table_foreach(table, delete_hash_keys_, NULL); +  g_hash_table_destroy(table); +} + +/* add/remove symbols from other table */ +static void +add_symbol_(gpointer symbol, gpointer value, gpointer target) +{ +  mix_symbol_table_t *t = (mix_symbol_table_t *)target; +  gchar *s = (gchar *)symbol; +  mix_word_t v = mix_word_new(GPOINTER_TO_UINT(value)); +  mix_symbol_table_insert (t, s, v); +} + +static void +remove_symbol_(gpointer symbol, gpointer value, gpointer target) +{ +  mix_symbol_table_t *t = (mix_symbol_table_t *)target; +  gchar *s = (gchar *)symbol; +  mix_symbol_table_remove (t, s); +} + +gboolean +mix_symbol_table_merge_table (mix_symbol_table_t *table, +			      const mix_symbol_table_t *from) +{ +  g_return_val_if_fail (table != NULL, FALSE); +  if (from != NULL) +    { +      mix_symbol_table_foreach ((gpointer)from, add_symbol_, table); +    } +  return TRUE; +} + +gboolean +mix_symbol_table_substract_table (mix_symbol_table_t *table, +				  const mix_symbol_table_t *other) +{ +  g_return_val_if_fail (table != NULL, FALSE); +  if (other != NULL) +    { +      mix_symbol_table_foreach ((gpointer)other, remove_symbol_, table); +    } +  return TRUE; +} + + +/* Add/remove symbols one by one */ +gint +mix_symbol_table_add(mix_symbol_table_t *table,  +		     const gchar *sym, mix_word_t value) +{ +  gpointer key, val; +   +  if ( table == NULL || sym == NULL ) return MIX_SYM_FAIL; +  if ( strlen(sym) > MIX_SYM_MAX_LEN ) return  MIX_SYM_LONG; + +  if ( !g_hash_table_lookup_extended(table, sym, &key, &val) ) +    { +      key = g_strdup(sym); +      g_hash_table_insert(table, key, (gpointer)value); +      return MIX_SYM_OK; +    } +  else +    return MIX_SYM_DUP; +} + +/* Add or modify symbol if it exists */ +gint +mix_symbol_table_insert(mix_symbol_table_t *table,  +			const gchar *sym, mix_word_t new_value) +{ +  gpointer key, val; +   +  if ( table == NULL || sym == NULL ) return MIX_SYM_FAIL; +  if ( strlen(sym) > MIX_SYM_MAX_LEN ) return MIX_SYM_LONG; + +  if ( !g_hash_table_lookup_extended(table, sym, &key, &val) ) +      key = g_strdup(sym); +  g_hash_table_insert(table, key, (gpointer)new_value); +  return MIX_SYM_OK; +} + + +/* Symbols lookup */ +gboolean +mix_symbol_table_is_defined(const mix_symbol_table_t *table, const gchar *sym) +{ +  gpointer key, val; +  return g_hash_table_lookup_extended((GHashTable *)table, sym, &key, &val); +} + +/* Print table */ +#define is_local_sym_(sym) \ +  ((sym) && (strlen(sym)==2) && (sym[1] == 'B') && isdigit(sym[0])) + +static gboolean skip_ = FALSE; + +static void +print_sym_rows_(gpointer symbol, gpointer value, gpointer file) +{ +  char *s = (char *)symbol; +  if (skip_ && !is_local_sym_(s)) { +    mix_word_t word = (mix_word_t)GPOINTER_TO_UINT(value); +    fprintf((FILE *)file, "%s:  %s%ld\n", s,  +	    mix_word_is_negative(word)? "-":"", +	    mix_word_magnitude(word)); +  } +} + +static void +print_sym_line_(gpointer symbol, gpointer value, gpointer file) +{ +  char *s = (char *)symbol; +  if (skip_ && !is_local_sym_(s)) { +    mix_word_t word = (mix_word_t)GPOINTER_TO_UINT(value); +    fprintf((FILE *)file, ",%s =%s%ld", s,  +	    mix_word_is_negative(word)? "-":"", +	    mix_word_magnitude(word)); +  } +} + +void +mix_symbol_table_print(const mix_symbol_table_t *table, gint mode, +		       FILE *file, gboolean skiplocal) +{ +  GHFunc func = (mode == MIX_SYM_LINE)? print_sym_line_ : print_sym_rows_; +  skip_ = skiplocal; +  if ( table != NULL ) +    g_hash_table_foreach((GHashTable *)table, func, (gpointer)file); +  if ( mode == MIX_SYM_LINE ) putc(';', file); /* to mark end-of-table */ +} + +   diff --git a/mixlib/mix_symbol_table.h b/mixlib/mix_symbol_table.h new file mode 100644 index 0000000..4a22444 --- /dev/null +++ b/mixlib/mix_symbol_table.h @@ -0,0 +1,109 @@ +/* -*-c-*- ---------------- mix_symbol_table.h : + * Type mix_symbol_table_t and functions to manipulate it. + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#ifndef MIX_SYMBOL_TABLE_H +#define MIX_SYMBOL_TABLE_H + +#include <stdio.h> +#include "mix_types.h" + +/* A symbol table shall be implemented as a hash table */ +typedef GHashTable mix_symbol_table_t ; + +/* Maximum length of stored symbols */ +#define MIX_SYM_MAX_LEN  10 + +/* Create an empty table */ +extern mix_symbol_table_t * +mix_symbol_table_new (void); + +/* Create a table and populate it with the contents of a table stored +   in -file- using mix_symbol_table_print (table, MIX_SYM_LINE, file) +*/ +extern mix_symbol_table_t * +mix_symbol_table_new_from_file (FILE *file); + + +/* Delete a table */ +extern void +mix_symbol_table_delete (mix_symbol_table_t *table); + +/* add/remove symbols from other table */ +extern gboolean +mix_symbol_table_merge_table (mix_symbol_table_t *table, +			      const mix_symbol_table_t *from); + +extern gboolean +mix_symbol_table_substract_table (mix_symbol_table_t *table, +				  const mix_symbol_table_t *other); + +/* Add/remove symbols one by one */ +/* possible outcomes: */ +enum {  +  MIX_SYM_FAIL, /* attempt failed */ +  MIX_SYM_OK,  +  MIX_SYM_DUP,  /* duplicated symbol */ +  MIX_SYM_LONG  /* symbol too long: only MIX_SYM_MAX_LEN chars used */ +}; + +extern gint +mix_symbol_table_add (mix_symbol_table_t *table,  +		      const gchar *sym, mix_word_t value); + +#define mix_symbol_table_remove(table, sym) \ +  g_hash_table_remove (table, sym) + + +/* Add or modify symbol if it exists */ +extern gint +mix_symbol_table_insert (mix_symbol_table_t *table,  +			 const gchar *sym, mix_word_t new_value); + +/* Add or modify symbol if it exists, without copiying sym */ +#define mix_symbol_table_insert_static(table,sym,value)\ +	g_hash_table_insert (table,(gpointer)sym,GUINT_TO_POINTER (value)) + +/* Symbols lookup */ +extern gboolean +mix_symbol_table_is_defined (const mix_symbol_table_t *table, const gchar *sym); + +#define mix_symbol_table_value(table,sym)				    \ +  (mix_word_t)GPOINTER_TO_UINT  (g_hash_table_lookup ((GHashTable *)table, \ +                                (gpointer)sym)) + +/* Traverse the table */ +#define mix_symbol_table_foreach(table,func,data) \ +	g_hash_table_foreach (table,func,data) + +/* Print the table */ +enum { +  MIX_SYM_ROWS, /* each symbol/value in a row */ +  MIX_SYM_LINE  /* {,symbol =value}*; in a single row */ +}; + +extern void +mix_symbol_table_print (const mix_symbol_table_t *table, gint mode, +			FILE *file, gboolean skiplocal); + + +#endif /* MIX_SYMBOL_TABLE_H */ + diff --git a/mixlib/mix_types.c b/mixlib/mix_types.c new file mode 100644 index 0000000..40246cd --- /dev/null +++ b/mixlib/mix_types.c @@ -0,0 +1,566 @@ +/* -*-c-*- ------------------ mix_types.c : + *  Implementation file for mix_types.h declarations. + * ------------------------------------------------------------------ + * Copyright (C) 2000, 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + +#include "mix.h" +#include <limits.h> +#include "mix_types.h" + + +/*------------------------ initialisation stuff ------------------------*/ +/* flag telling whether a field spec is valid */ +static gboolean is_bad_field_[MIX_BYTE_MAX + 1]; +/* shift associated with a fspec */   +static guint shift_[MIX_BYTE_MAX + 1]; +/* mask associated with a fspec */ +static glong mask_[MIX_BYTE_MAX + 1]; + +/* maps from gchar's to mix_char_t */ +#define NONP_  (guchar)('?') +static mix_char_t ascii_to_mix_char_[UCHAR_MAX + 1]; +static guchar mix_char_to_ascii_[MIX_CHAR_MAX + 1] = { +  ' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'd', 'J', +  'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 's', 'p', 'S', 'T', +  'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', +  '7', '8', '9', '.', ',', '(', ')', '+', '-', '*', '/', '=', '$', +  '<', '>', '@', ';', ':', '\'' +}; + + +/* initialise the above arrays */ +void +mix_init_types (void) +{ +  guint lt, rt; +  for (lt = 0; lt < 8; ++lt) +    for (rt = 0; rt < 8; ++rt)  +      { +	guint F = 8 * lt + rt; +	is_bad_field_[F] = rt < lt || 5 < rt; +	if ( is_bad_field_[F] ) +	  shift_[F] = 0, mask_[F] = 0; +	else  +	  { +	    guint width = rt - (lt == 0 ? 1 : lt) + 1; +	    shift_[F] = 6 * (5 - rt); +	    mask_[F] = ((1L << (6 * width)) - 1) << shift_[F]; +	  }  +      } + +  for ( lt = 0; lt < UCHAR_MAX + 1; ++lt ) +    ascii_to_mix_char_[lt] = NONP_; +  for ( lt = 0; lt < MIX_CHAR_MAX + 1; ++lt ) +    ascii_to_mix_char_[mix_char_to_ascii_[lt]] = (guchar)lt; +} + +mix_char_t +mix_ascii_to_char (guchar c) +{ +  return ascii_to_mix_char_[c]; +} + + +guchar +mix_char_to_ascii (mix_char_t c) +{ +  return c > MIX_CHAR_MAX ? NONP_ : mix_char_to_ascii_[c]; +} + + +/*---------------------------- m_word_t --------------------------------- */ + +/* Create mix_word_t from an array of mix_byte_t */ +mix_word_t +mix_bytes_to_word (mix_byte_t *bytes, guint byteno) +{ +  mix_word_t result = 0; +  guint k; +   +  g_return_val_if_fail (bytes != NULL, MIX_WORD_ZERO); +  g_return_val_if_fail (byteno != 0, MIX_WORD_ZERO); +   +  if ( byteno > 5 ) byteno = 5; +  for ( k = 0; k < byteno; k++ ) +    result |= ((gulong)bytes[k]) << (6*(byteno-k-1)); + +  return result; +} + + +/* Field operations */ +mix_word_t /* the specified field or 0 if f is not valid */ +mix_word_get_field (mix_fspec_t f, mix_word_t word) +{ +  mix_word_t result; + +  g_return_val_if_fail (!is_bad_field_[f],MIX_WORD_ZERO); +   +  result = ( (word & mask_[f]) >> shift_[f] ); +  if (f < 8)      /* if f is of the form (0:R), retain the sign of word */ +    result |= mix_word_sign (word); + +  return result; +} + + +mix_word_t +mix_word_set_field (mix_fspec_t f, mix_word_t from, mix_word_t to) +{ +  mix_word_t result; +  glong m = mask_[f]; + +  g_return_val_if_fail (!is_bad_field_[f],to); +   +  if (f < 8)      /* if F is of the form (0:R), use the sign of -from- */ +    result =  (to & ~m & ~MIX_WORD_SIGN_BIT)  +      | ((from /*<< shift_[f]*/) & m) | mix_word_sign (from); +  else +    result = (to & ~m) | ((from /*<< shift_[f]*/) & m); +   +  return result; +} + +mix_word_t +mix_word_store_field (mix_fspec_t f, mix_word_t from, mix_word_t to) +{ +  mix_word_t result; +  glong m = mask_[f]; + +  g_return_val_if_fail (!is_bad_field_[f],to); +   +  if (f < 8)      /* if F is of the form (0:R), use the sign of -from- */ +    result =  (to & ~m & ~MIX_WORD_SIGN_BIT)  +      | ((from << shift_[f]) & m) | mix_word_sign (from); +  else +    result = (to & ~m) | ((from << shift_[f]) & m); +   +  return result; +} +   + + +gboolean +mix_fspec_is_valid (mix_fspec_t f) +{ +  return !(is_bad_field_[f]); +} + +mix_byte_t  +mix_word_get_byte (mix_word_t word,   /* word parsed */  +		   guint idx          /* byte: 1 to 5 */	  ) +{ +  mix_byte_t fspec = mix_fspec_new (idx,idx); + +  g_return_val_if_fail ((idx > 0 && idx < 6), MIX_BYTE_ZERO); +   +  return mix_byte_new (mix_word_get_field (fspec,word)); +} + + +extern void  +mix_word_set_byte (mix_word_t *into, guint idx,  mix_byte_t value) +{ +  mix_word_t from = value; +  mix_byte_t fspec = mix_fspec_new (idx,idx); + +  g_return_if_fail (into != NULL); +  g_return_if_fail (idx > 0 && idx < 6); +   +  from <<= shift_[fspec]; +  *into = mix_word_set_field (fspec,from,*into); +} + +/* Arithmetic operations */ +mix_word_t  +mix_word_add (mix_word_t x, mix_word_t y) +{ +  static const gulong MIX_WORD_MAX_SIM = 2*MIX_WORD_MAX + 1; +   +  gint32 result; +  if ( mix_word_sign (x) == mix_word_sign (y) ) +    { +      result = (mix_word_magnitude (x) + mix_word_magnitude (y)); +      if ( result >  MIX_WORD_MAX ) { +	/* for instance MIX_WORD_MAX + 1 = - MIX_WORD_MAX */ +	result = MIX_WORD_MAX_SIM - result; +	result |= mix_word_sign (mix_word_negative (x)); +      } else if ( result != 0 )       +	result |= mix_word_sign (x); +      /* keep positive sign for 0 so that w - w == -w + w */ +    } +  else +    { +      result = mix_word_magnitude (x) -  mix_word_magnitude (y); +      if (result < 0) +	result = -result|mix_word_sign (y); +      else if (result > 0) +	result = result|mix_word_sign (x); +      /* keep positive sign for 0 so that w - w == -w + w */ +    } +  +  g_assert ( result >= 0 ); +   +  return (mix_word_t)result; +} + +gboolean /* TRUE if overflow */ +mix_word_add_and_carry (mix_word_t x, mix_word_t y, +			mix_word_t *h, mix_word_t *l) +{ +  gboolean result; +     +  if ( mix_word_sign (x) == mix_word_sign (y) ) +    { +      guint32 sum = (mix_word_magnitude (x) + mix_word_magnitude (y)); +      if ( sum >  MIX_WORD_MAX )  +	{ +	  result = TRUE; +	  if ( l != NULL )  +	    { +	      *l = sum - MIX_WORD_MAX -1; +	      *l |= mix_word_sign (x); +	    } +	  if ( h != NULL )  +	    { +	      *h = sum >> 30; +	      *h |= mix_word_sign (x); +	    } +	}  +      else /* sum <= MIX_WORD_MAX */ +	{ +	  result = FALSE; +	  if ( h != NULL ) *h = 0; +	  if ( l != NULL )  +	    { +	      *l = sum; +	      if ( sum != 0 ) +		*l |= mix_word_sign (x); +	      /* keep positive sign for 0 so that w - w == -w + w */ +	    } +	} +    } +  else /* mix_word_sign (x) != mix_word_sign (y) */ +    { +      result = FALSE; +      if ( h != NULL ) *h = 0; +      if ( l != NULL )  +	{ +	  gint32 dif = mix_word_magnitude (x) -  mix_word_magnitude (y); +	  if ( dif < 0) +	    *l = (-dif)|mix_word_sign (y); +	  else if ( dif > 0) +	    *l = dif|mix_word_sign (x); +	  else /* keep positive sign for 0 so that w - w == -w + w */ +	    *l = MIX_WORD_ZERO; +	} +    } +  +  return result; +} +   + +void  +mix_word_mul (mix_word_t x, mix_word_t y,  +	      mix_word_t *high_word, mix_word_t *low_word) +{ +  guint32 sign = mix_word_sign (x) ^ mix_word_sign (y); +   +  /* +    x = x0 + x1 * 2 ^ 10 + x2 * 2 ^ 20 +    y = y0 + y1 * 2 ^ 10 + y2 * 2 ^ 20 +    x0, x1, x2, y0, y1, y2 are < 2 ^ 10 +  */ +  guint32 x0 = (x & 0x000003FF); +  guint32 x1 = (x & 0x000FFC00) >> 10; +  guint32 x2 = (x & 0x3FF00000) >> 20; +  guint32 y0 = (y & 0x000003FF); +  guint32 y1 = (y & 0x000FFC00) >> 10; +  guint32 y2 = (y & 0x3FF00000) >> 20; +   +  /* +    x * y = partial0 + +    partial1 * 2 ^ 10 + +    partial2 * 2 ^ 20 + +    partial3 * 2 ^ 30 + +    partial4 * 2 ^ 40 +    partial0 and partial4 are <     2 ^ 20 +    partial1 and partial3 are <     2 ^ 21 +    partial2 is               < 3 * 2 ^ 20 +  */ +  guint32 partial0 = x0 * y0; +  guint32 partial1 = x0 * y1 + x1 * y0; +  guint32 partial2 = x0 * y2 + x1 * y1 + x2 * y0; +  guint32 partial3 = x1 * y2 + x2 * y1; +  guint32 partial4 = x2 * y2; +   +  /*  sum1 has a place value of 1 and is < 2 ^ 32 */ +  guint32 sum1   = partial0 + (partial1 << 10); +  guint32 carry1 = (sum1 & 0xFFF00000) >> 20; +   +  /* sum2 has a place value of 2 ^ 20 and is < 2 ^ 32 */ +  guint32 sum2   = partial2 + (partial3 << 10) + carry1; +  guint32 carry2 = (sum2 & 0xFFF00000) >> 20; +   +  /* sum3 has a place value of 2 ^ 40 and is < 2 ^ 20 */ +  guint32 sum3   = partial4 + carry2; +   +  sum1 &= ~0xFFF00000; +  sum2 &= ~0xFFF00000; +   +  /* +    Now paste the three values back into two. +  */ +  if ( low_word != NULL ) { +    *low_word   = sum1 | ((sum2 & 0x000003FF) << 20); +    *low_word  |= sign; +  } +  if ( high_word != NULL ) { +    *high_word  = ((sum2 & 0x000FFC00) >> 10) | (sum3 << 10); +    *high_word |= sign; +  } +} + + +gboolean  +mix_word_div (mix_word_t n1, mix_word_t n0, mix_word_t d,  +	      mix_word_t *quotient, mix_word_t *remainder) +{ +  gboolean overflow = FALSE;   +  long magn1 = mix_word_magnitude (n1); +  long magd = mix_word_magnitude (d); +   +  if (magd == 0)  +    { +      overflow = TRUE; +      /* just so they have -some- valid value */ +      if ( quotient != NULL ) *quotient = 0; +      if ( remainder != NULL )  *remainder = 0;   +    }  +  else if (magn1 == 0)  +    {    /* special-cased for speed */ +      if ( quotient != NULL )  +	*quotient = (mix_word_sign (n1) ^ mix_word_sign (d))  +	  | (mix_word_magnitude (n0) / magd); +      if ( remainder != NULL ) +	*remainder = mix_word_sign (n1) | (mix_word_magnitude (n0) % magd); +    }  +  else if (magd <= magn1)  +    { +      overflow = TRUE; +      if ( quotient != NULL ) *quotient = 0; +      if ( remainder != NULL )  *remainder = 0; +    }  +  else  +    { +      long q = mix_word_magnitude (n0); +      long r = magn1; +      unsigned i; +      for (i = 30; i != 0; --i) { +	r <<= 1; +	if ( (q & (1L << 29)) != 0 ) +	  ++r; +	q = (q << 1) & ((1L << 30) - 1); +	if (magd <= r) +	  ++q, r -= magd; +      } +      if ( quotient != NULL ) +	*quotient = (mix_word_sign (n1) ^ mix_word_sign (d)) | q; +      if ( remainder != NULL ) +	*remainder = mix_word_sign(n1) | r; +    } +  return overflow; +} + +void  +mix_word_shift_right (mix_word_t A, mix_word_t X, gulong count,  +		      mix_word_t *pA, mix_word_t *pX) +{ +  if ( pX != NULL ) *pX = mix_word_sign (X); +  if ( pA != NULL ) *pA = mix_word_sign (A); +  if (count < 5) { +    if ( pA != NULL ) +      *pA |= mix_word_magnitude (A) >> (6 * count); +    if ( pX != NULL ) +      *pX |= MIX_WORD_MAX & ( (mix_word_magnitude (X) >> (6 * count))  +			      | (A << (30 - 6 * count)) ); +  } else if (count < 10 && pX != NULL) +    *pX |= mix_word_magnitude (A) >> (6 * count - 30); +  else +    ; +} + + +void  +mix_word_shift_left (mix_word_t A, mix_word_t X, gulong count,  +		     mix_word_t *pA, mix_word_t *pX) +{ +  if ( pX != NULL ) *pX = mix_word_sign (X); +  if ( pA != NULL ) *pA = mix_word_sign (A); +  if (count < 5) { +    if ( pX != NULL ) *pX |= MIX_WORD_MAX & (X << (6 * count)); +    if ( pA != NULL ) +      *pA |= MIX_WORD_MAX & ( (A << (6 * count)) | +			      (mix_word_magnitude (X) >> (30 - 6 * count)) ); +  } else if (count < 10 && pA != NULL) +    *pA |= MIX_WORD_MAX & (X << (6 * count - 30)); +  else +    ; +} + +void  +mix_word_shift_left_circular (mix_word_t A, mix_word_t X, gulong count,  +			      mix_word_t *pA, mix_word_t *pX) +{ +  mix_word_t A1, X1; +  guint c; +   +  count %= 10; +  A1 = count < 5 ? A : X; +  X1 = count < 5 ? X : A; +  c = 6 * (count < 5 ? count : count - 5); +  if ( pX != NULL ) +    *pX = mix_word_sign (X) +      | ( MIX_WORD_MAX & (X1 << c) ) | ( mix_word_magnitude (A1) >> (30 - c) ); +  if ( pA != NULL ) +    *pA = mix_word_sign (A) +      | ( MIX_WORD_MAX & (A1 << c) ) | ( mix_word_magnitude (X1) >> (30 - c) ); +} + +void  +mix_word_shift_right_circular (mix_word_t A, mix_word_t X, gulong count,  +			       mix_word_t *pA, mix_word_t *pX) +{ +  mix_word_t A1, X1; +  guint c; +   +  count %= 10; +  A1 = count < 5 ? A : X; +  X1 = count < 5 ? X : A; +  c = 6 * (count < 5 ? count : count - 5); +  if ( pX != NULL ) +    *pX = mix_word_sign (X) +      | ( mix_word_magnitude (X1) >> c ) | ( MIX_WORD_MAX & (A1 << (30 - c)) ); +  if ( pA != NULL ) +    *pA = mix_word_sign (A) +      | ( mix_word_magnitude (A1) >> c ) | ( MIX_WORD_MAX & (X1 << (30 - c)) ); +} + + +/* Printable representation */ +void  +mix_word_print_to_file (mix_word_t word, const char *message, FILE *f) +{ +  guint k; +  if ( message ) fprintf (f, "%s ", message); +  fprintf (f, "%s ", mix_word_sign (word) == 0 ? "+" : "-"); +  for ( k = 1; k < 6; ++k ) { +    fprintf (f, "%02d ", mix_word_get_byte (word,k)); +  } +  fprintf (f, "(%010ld)", mix_word_magnitude (word)); +} + +void  +mix_word_print_to_buffer (mix_word_t word, gchar *buf) +{ +  g_return_if_fail (buf != NULL); +  sprintf (buf, "%s %02d %02d %02d %02d %02d", +	   mix_word_sign (word) == 0 ? "+" : "-", +	   mix_word_get_byte (word, 1), +	   mix_word_get_byte (word, 2), +	   mix_word_get_byte (word, 3), +	   mix_word_get_byte (word, 4), +	   mix_word_get_byte (word, 5)); +} + +/* Conversions between words and shorts */ +mix_short_t +mix_word_to_short (mix_word_t word) +{ +  if  ( mix_word_is_negative (word) )  +    return ( (word & MIX_SHORT_MAX) | MIX_SHORT_SIGN_BIT ); +  else +    return (word & MIX_SHORT_MAX); +} + +mix_word_t +mix_short_to_word (mix_short_t s) +{ +  if ( mix_short_is_negative (s) ) +    return ((mix_word_t) (mix_short_magnitude (s) | MIX_WORD_SIGN_BIT)); +  else +    return ((mix_word_t)s); +} + +mix_short_t  +mix_short_add (mix_short_t x, mix_short_t y) +{ +  static const guint16 MIX_SHORT_MAX_SIM = 2*MIX_SHORT_MAX + 1; +   +  gint16 result; +  if ( mix_short_sign (x) == mix_short_sign (y) ) +    { +      result = (mix_short_magnitude (x) + mix_short_magnitude (y)); +      if ( result >  MIX_SHORT_MAX ) { +	/* for instance MIX_SHORT_MAX + 1 = - MIX_SHORT_MAX */ +	result = MIX_SHORT_MAX_SIM - result; +	result |= mix_short_sign (mix_short_negative (x)); +      } else if ( result != 0 )       +	result |= mix_short_sign (x); +      /* keep positive sign for 0 so that w - w == -w + w */ +    } +  else +    { +      result = mix_short_magnitude (x) -  mix_short_magnitude (y); +      if (result < 0) +	result = -result|mix_short_sign (y); +      else if (result > 0) +	result = result|mix_short_sign (x); +      /* keep positive sign for 0 so that w - w == -w + w */ +    } +  +  g_assert ( result >= 0 ); +   +  return (mix_short_t)result; +} + + +/* Printable representation */ +void +mix_short_print (mix_short_t s, const gchar *message) +{ +  if ( message ) g_print ("%s ", message); +  g_print ("%s ", mix_short_sign (s) == 0 ? "+" : "-"); +  g_print ("%02d %02d ", mix_byte_new (s>>6), mix_byte_new (s)); +  g_print ("(%04d)", mix_short_magnitude (s)); +} + +void +mix_short_print_to_buffer (mix_short_t s, gchar *buf) +{ +  g_return_if_fail (buf != NULL); +  sprintf (buf, "%s %02d %02d", +	   mix_short_sign (s) == 0 ? "+" : "-", +	   mix_byte_new (s>>6), mix_byte_new (s)); +  /* g_print ("(%04d)", mix_short_magnitude (s));*/ +} + + + + diff --git a/mixlib/mix_types.h b/mixlib/mix_types.h new file mode 100644 index 0000000..918046e --- /dev/null +++ b/mixlib/mix_types.h @@ -0,0 +1,291 @@ +/* -*-c-*- --------------- mix_types.h: + *  This file contains declarations for the basic types used in MIX: + *   mix_byte_t, mix_char_t, mix_short_t and mix_word_t. + * ------------------------------------------------------------------ + * Copyright (C) 2000, 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#ifndef MIX_TYPES_H +#define MIX_TYPES_H + +#include <stdio.h> +#include "mix.h" + +/* Initialisation function to be called before using the other + * functions in this file + */ +extern void +mix_init_types(void); + + +/*----------------- m_byte_t --------------------------------------------*/ +/* MIX byte type */ +typedef guint8 mix_byte_t; + +/* Maximum value stored in an mix_byte_t */ +#define MIX_BYTE_MAX ((1L << 6) - 1) + +/* Zero mix byte */ +#define MIX_BYTE_ZERO  ((mix_byte_t)0) + +/* Create a mix_byte_t from any native type */ +#define mix_byte_new(x) ((mix_byte_t)((x) & MIX_BYTE_MAX )) + +/* Operations */ +/* Addition */ +#define mix_byte_add(x,y) mix_byte_new((x) + (y)) +/* Substraction */ +#define mix_byte_sub(x,y) mix_byte_new((x) - (y)) +/* Product */ +#define mix_byte_mul(x,y) mix_byte_new((x) * (y)) +/* Quotient */ +#define mix_byte_div(x,y) mix_byte_new((x) / (y)) + + +/*----------------- mix_char_t --------------------------------------------*/ +/* MIX char type: chars are coded in MIX from 0 to MIX_CHAR_MAX */ +typedef guint8 mix_char_t; + +#define MIX_CHAR_MAX 55 + +/* Conversions for mix_char_t's */ +#define mix_char_to_byte(mchar) mix_byte_new(mchar) +#define mix_byte_to_char(byte)  ((mix_char_t)(byte&MIX_CHAR_MAX)) + +extern mix_char_t +mix_ascii_to_char(guchar c); + +extern guchar +mix_char_to_ascii(mix_char_t c); + + +/*----------------- mix_word_t --------------------------------------------*/ +/* + * Represented as a gint32 (glib ensures that this type has 32 + * bits). Bit 30 is the sign, higher bits are 0,  + * and bits 0-29 are the magnitude. + * Each MIX 'byte' is a 6-bit substring of the magnitude. + */ +typedef guint32  mix_word_t; + +/* Maximum value stored in an mix_word_t */ +#define MIX_WORD_MAX ((1L << 30) - 1) +/* Sign bit in a word */ +#define MIX_WORD_SIGN_BIT    (1L << 30) +/* Zero mix word */ +#define MIX_WORD_ZERO  ((mix_word_t)0) +/* Negative zero mix word */ +#define MIX_WORD_MINUS_ZERO  (MIX_WORD_ZERO | MIX_WORD_SIGN_BIT) + + +/* Create a mix_word_t from any native type */ +#define mix_word_new(x)						\ +( (x) < 0							\ +  ? ( MIX_WORD_SIGN_BIT | ((mix_word_t)(-(x)) & MIX_WORD_MAX) )	\ +  : ( (mix_word_t)(x) & MIX_WORD_MAX )				\ +)  + +/* Create a mix_word_t from individual bytes */ +#define mix_word_new_b(b1,b2,b3,b4,b5)				\ +((mix_word_t)(mix_byte_new(b5) + (mix_byte_new(b4)<<6) +	\ +	      (mix_byte_new(b3)<<12) + (mix_byte_new(b2)<<18) +	\ +	      (mix_byte_new(b1)<<24))) + +/* Create a negative mix_word_t from individual bytes */ +#define mix_word_new_bn(b1,b2,b3,b4,b5) \ +   mix_word_negative(mix_word_new_b(b1,b2,b3,b4,b5)) + +/* Create mix_word_t from an array of mix_byte_t */ +extern mix_word_t +mix_bytes_to_word(mix_byte_t *bytes, guint byteno); + +/* Access byte within a word */ +extern mix_byte_t /* byte -idx- or MIX_BYTE_ZERO if -idx- out of range */ +mix_word_get_byte(mix_word_t word,   /* word parsed */  +		  guint idx          /* byte: 1 to 5 */); + +/* Set a byte  within a mix_word_t  */ +extern void  +mix_word_set_byte(mix_word_t *into,   /* word to be modified */ +		  guint idx,          /* byte: 1 to 5 */ +		  mix_byte_t value    /* byte's value */); + + +/* Operations */ +/* Sign-related definitions */ +#define mix_word_negative(word)      ( (word) ^ MIX_WORD_SIGN_BIT ) +#define mix_word_reverse_sign(word)  ( word ^= MIX_WORD_SIGN_BIT ) +#define mix_word_sign(word)          ( (word) & MIX_WORD_SIGN_BIT ) +#define mix_word_magnitude(word)     ( (word) & (MIX_WORD_SIGN_BIT - 1) ) +#define mix_word_is_positive(word)   ( mix_word_sign(word) == 0 ) +#define mix_word_is_negative(word)   ( mix_word_sign(word) != 0 ) + + +/* Arithmetic operations */ +extern mix_word_t  +mix_word_add(mix_word_t x, mix_word_t y); +  +#define mix_word_sub(x,y)    ( mix_word_add((x),mix_word_negative(y)) ) + +/* Add two words filling a high word if needed. +   -high_word- and/or -low_word- can be NULL. +*/ +extern gboolean /* TRUE if overflow */ +mix_word_add_and_carry(mix_word_t x, mix_word_t y, +		       mix_word_t *high_word, mix_word_t *low_word); + +/* Product, stored in -high_word- and -low_word-, which +   can be NULL. +*/ +extern void  +mix_word_mul(mix_word_t x, mix_word_t y,  +	     mix_word_t *high_word, mix_word_t *low_word); + +/* Division. -quotient- and/or -remainder- can be NULL. */ +extern gboolean /* TRUE if overflow */  +mix_word_div(mix_word_t n1, mix_word_t n0, mix_word_t d,  +	     mix_word_t *quotient, mix_word_t *remainder); + +/* Shift operations */ +extern void  +mix_word_shift_left(mix_word_t A, mix_word_t X, gulong count,  +		    mix_word_t *pA, mix_word_t *pX); +extern void  +mix_word_shift_right(mix_word_t A, mix_word_t X, gulong count,  +		     mix_word_t *pA, mix_word_t *pX); +extern void  +mix_word_shift_left_circular(mix_word_t A, mix_word_t X, gulong count,  +			     mix_word_t *pA, mix_word_t *pX); +extern void  +mix_word_shift_right_circular(mix_word_t A, mix_word_t X, gulong count,  +			     mix_word_t *pA, mix_word_t *pX); + + + + +/* + * Fields within a word: a word containing the (L:R) + * bytes of the original one. L and R (with 0 <= L <= R < 6) + * are specified by a mix_fspec_t F = 8*L + R. + */ +typedef guint8 mix_fspec_t; + +#define mix_fspec_left(f) ( ((f)>>3) & 7 ) +#define mix_fspec_right(f) ( (f) & 7 ) +#define mix_fspec_new(L,R) ( mix_byte_new(8*(L) + (R)) ) + +extern gboolean +mix_fspec_is_valid(mix_fspec_t f); + +extern mix_word_t /* the specified field or 0 if f is not valid */ +mix_word_get_field(mix_fspec_t f, mix_word_t word); + +extern mix_word_t /* -to- with the field -f- from -from- or -to-  +		     if -f- is not a valid fspec  */ +mix_word_set_field(mix_fspec_t f, mix_word_t from, mix_word_t to); + +/* set field into a zero word */ +#define mix_word_extract_field(fspec,from_word) \ +    mix_word_set_field(fspec,from_word,MIX_WORD_ZERO) + +/* Store operation: the no. of bytes determined by -f- is taken + * from the right of -from- and stored into -to- in the location + *  specified by -f- + */ +extern mix_word_t +mix_word_store_field(mix_fspec_t f, mix_word_t from, mix_word_t to); + + +/* Printable representation */ +#define mix_word_print(word,message) \ +  mix_word_print_to_file (word, message, stdout) + +extern void +mix_word_print_to_file (mix_word_t word, const char *message, FILE *f); + +extern void +mix_word_print_to_buffer (mix_word_t word, gchar *buf); + + +/*----------------- mix_short_t ------------------------------------------*/ +typedef guint16 mix_short_t; + +#define MIX_SHORT_MAX  ((1L << 12) - 1) +#define MIX_SHORT_SIGN_BIT  ((mix_short_t)(1L << 12)) +#define MIX_SHORT_ZERO ((mix_short_t)0) +#define MIX_SHORT_MINUS_ZERO (MIX_SHORT_ZERO | MIX_SHORT_SIGN_BIT) + +/* Sign-related definitions */ +#define mix_short_negative(s)      ( (s) ^ MIX_SHORT_SIGN_BIT ) +#define mix_short_sign(s)          ( (s) & MIX_SHORT_SIGN_BIT ) +#define mix_short_magnitude(s)     	\ +   ( (s) & (MIX_SHORT_SIGN_BIT - 1) ) +#define mix_short_is_positive(s)   ( mix_short_sign(s) == 0 ) +#define mix_short_is_negative(s)   ( mix_short_sign(s) != 0 ) + +/* create short from a long */ +#define mix_short_new(val) \ +	((val)>= 0 ? (val)&MIX_SHORT_MAX : mix_short_negative(-(val))) + +/* Create shorts from individual bytes */ +#define mix_short_new_b(b1,b2) \ +((mix_short_t)((mix_byte_new(b1)<<6) + mix_byte_new(b2))) + +#define mix_short_new_bn(b1,b2) mix_short_negative(mix_short_new_b(b1,b2)) + +/* Conversions between words and shorts. Arithmetic operations +   on shorts are not provided but for addition: use words instead. +*/ +/* Make a short taking word's sign and its two least significant +   bytes (bytes no. 4 and 5) +*/ +extern mix_short_t +mix_word_to_short(mix_word_t word); + +extern  mix_word_t +mix_short_to_word(mix_short_t s); + +/* fast conversion (these macros' argument are evaluated twice */ +#define mix_word_to_short_fast(w)					\ +( mix_word_is_negative(w) ?						\ +  ((w) & MIX_SHORT_MAX)|MIX_SHORT_SIGN_BIT : (w)&MIX_SHORT_MAX ) + +#define mix_short_to_word_fast(s)					     \ +( mix_short_is_negative(s) ?						     \ +(mix_word_t) (mix_short_magnitude(s)|MIX_WORD_SIGN_BIT): (mix_word_t)(s) ) + + +extern mix_short_t +mix_short_add(mix_short_t x, mix_short_t y); + + +/* printable representation */ +extern void +mix_short_print(mix_short_t s, const gchar *message); + +extern void +mix_short_print_to_buffer (mix_short_t s, gchar *buf); + + + +#endif /* MIX_TYPES_H */ + + + + diff --git a/mixlib/mix_vm.c b/mixlib/mix_vm.c new file mode 100644 index 0000000..9a39247 --- /dev/null +++ b/mixlib/mix_vm.c @@ -0,0 +1,562 @@ +/* -*-c-*- ------------------ mix_vm.c : + * Implementation of the functions declared in mix_vm.h + * ------------------------------------------------------------------ + * Copyright (C) 2000, 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + +#include "mix.h" +#include "xmix_vm.h" + +static void +vm_reset_ (mix_vm_t *vm) +{ +  guint k; +  set_rA_ (vm, MIX_WORD_ZERO); +  set_rX_ (vm, MIX_WORD_ZERO); +  set_rJ_ (vm, MIX_WORD_ZERO); +  for ( k = 1; k < IREG_NO_+1; ++k ) +    set_rI_ (vm, k, MIX_WORD_ZERO); +  set_over_ (vm, FALSE); +  set_cmp_ (vm, mix_EQ); +  set_loc_ (vm, MIX_WORD_ZERO); +  for ( k = 0; k < MEM_CELLS_NO_; ++k) +    set_cell_ (vm, k, MIX_WORD_ZERO); +  halt_ (vm, FALSE); +  if (vm->symbol_table != NULL ) +    { +      mix_symbol_table_delete (vm->symbol_table); +      vm->symbol_table = NULL; +    } +  if (vm->line_table != NULL) +    { +      g_tree_destroy (vm->line_table); +      vm->line_table = NULL; +    } +  if (vm->address_table != NULL) +    { +      g_tree_destroy (vm->address_table); +      vm->address_table = NULL; +    } +  if (vm->src_file != NULL) +    { +      mix_src_file_delete (vm->src_file); +      vm->src_file = NULL; +    } +  bp_clear_all_ (vm); +} + + +/* Create/destroy a mix vm */ +mix_vm_t * +mix_vm_new (void) +{ +  int i; +   +  mix_vm_t *vm = g_new (struct mix_vm_t,1); +  vm->line_table = NULL; +  vm->address_table = NULL; +  vm->symbol_table = NULL; +   +  for (i = 0; i < BD_NO_; ++i) +    vm->devices[i] = NULL; +   +  vm->clock = mix_vm_clock_new (); +   +  vm_reset_ (vm); +  return vm; +} + + +void +mix_vm_delete (mix_vm_t * vm) +{ +  int i; +   +  g_return_if_fail (vm != NULL); +   +  if (vm->line_table != NULL) g_tree_destroy (vm->line_table); +  if (vm->address_table != NULL) g_tree_destroy (vm->address_table); +  if (vm->symbol_table != NULL) mix_symbol_table_delete (vm->symbol_table); +  if (vm->src_file != NULL) mix_src_file_delete (vm->src_file); +  for (i = 0; i < BD_NO_; ++i) +    mix_device_delete (vm->devices[i]); +  mix_vm_clock_delete (vm->clock); +  g_free (vm); +} + +/* connect devices to a virtual machine */ +mix_device_t * +mix_vm_connect_device (mix_vm_t *vm, mix_device_t *device) +{ +  mix_device_t *old; +  mix_device_type_t type; +   +  g_return_val_if_fail (vm != NULL, NULL); +  g_return_val_if_fail (device != NULL, NULL); +   +  type = mix_device_type (device); +  old = vm->devices[type]; +  vm->devices[type] = device; +   +  return old; +} + +/* Reset a vm  (set state as of a newly created one) */ +void +mix_vm_reset (mix_vm_t * vm) +{ +  g_return_if_fail (vm != NULL); +  vm_reset_ (vm); +} + +/* Set start address for execution */ +void +mix_vm_set_start_addr (mix_vm_t *vm, mix_address_t addr) +{ +  g_return_if_fail (vm != NULL); +  set_loc_ (vm, addr); +} + +/* Access to the vm's registers */ +mix_word_t +mix_vm_get_rA (const mix_vm_t *vm) +{ +  g_return_val_if_fail (vm != NULL, MIX_WORD_ZERO); +  return get_rA_ (vm); +} + +mix_word_t +mix_vm_get_rX (const mix_vm_t *vm) +{ +  g_return_val_if_fail (vm != NULL, MIX_WORD_ZERO); +  return get_rX_ (vm); +} + +mix_short_t +mix_vm_get_rJ (const mix_vm_t *vm) +{ +  g_return_val_if_fail (vm != NULL, MIX_SHORT_ZERO); +  return mix_word_to_short_fast (get_rJ_ (vm)); +} + +mix_short_t +mix_vm_get_rI (const mix_vm_t *vm, guint idx) +{ +  g_return_val_if_fail (vm != NULL, MIX_SHORT_ZERO); +  g_return_val_if_fail (IOK_ (idx), MIX_SHORT_ZERO); +  return mix_word_to_short_fast (get_rI_ (vm, idx)); +} + +void  +mix_vm_set_rA (mix_vm_t *vm, mix_word_t value) +{ +  g_return_if_fail (vm != NULL); +  set_rA_ (vm, value); +} + +void +mix_vm_set_rX (mix_vm_t *vm, mix_word_t value) +{ +  g_return_if_fail (vm != NULL); +  set_rX_ (vm, value); +} + +void  +mix_vm_set_rJ (mix_vm_t *vm, mix_short_t value) +{ +  g_return_if_fail (vm != NULL); +  g_return_if_fail (mix_short_is_positive (value)); +  set_rJ_ (vm, mix_short_to_word_fast (value)); +} + +void  +mix_vm_set_rI (mix_vm_t *vm, guint idx, mix_short_t value) +{ +  g_return_if_fail (vm != NULL); +  g_return_if_fail (IOK_ (idx)); +  set_rI_ (vm, idx, mix_short_to_word_fast (value)); +} + +/* Access to the comparison flag and overflow toggle */ +mix_cmpflag_t +mix_vm_get_cmpflag (const mix_vm_t *vm) +{ +  g_return_val_if_fail (vm != NULL, mix_EQ); +  return get_cmp_ (vm); +} + +void +mix_vm_set_cmpflag (mix_vm_t *vm, mix_cmpflag_t value) +{ +  g_return_if_fail (vm != NULL); +  set_cmp_ (vm, value); +} + +gboolean +mix_vm_get_overflow (const mix_vm_t *vm) +{ +  g_return_val_if_fail (vm != NULL, TRUE); +  return get_over_ (vm); +} + +void +mix_vm_set_overflow (mix_vm_t *vm, gboolean value) +{ +  g_return_if_fail (vm != NULL); +  set_over_ (vm, value); +} + +void +mix_vm_toggle_overflow (mix_vm_t *vm) +{ +  g_return_if_fail (vm != NULL); +  set_over_ (vm, !get_over_ (vm)); +} + +/* Access to memory cells */ +mix_word_t +mix_vm_get_addr_contents (const mix_vm_t *vm, mix_address_t addr) +{ +  g_return_val_if_fail (vm != NULL, MIX_WORD_ZERO); +  g_return_val_if_fail (MEMOK_ (addr), MIX_WORD_ZERO); +  return get_cell_ (vm, addr); +} + +void +mix_vm_set_addr_contents (mix_vm_t *vm, mix_address_t addr, mix_word_t value) +{ +  g_return_if_fail (vm != NULL); +  g_return_if_fail (MEMOK_ (addr)); +  set_cell_ (vm, addr, value); +} + +gboolean +mix_vm_is_halted (const mix_vm_t *vm) +{ +  return is_halted_ (vm); +} + +/* Execution of instructions */ +gboolean /* TRUE if success */ +mix_vm_exec_ins (mix_vm_t *vm, const mix_ins_t *ins) +{ +  g_return_val_if_fail (vm != NULL, FALSE); +  g_return_val_if_fail (ins != NULL, FALSE); +  return (*ins_handlers_[ins->opcode]) (vm,ins); +} + +/* comparison function for the line and address tables tree */ +static gint +cmp_uint_ (gconstpointer a, gconstpointer b) +{ +  return GPOINTER_TO_UINT (a) - GPOINTER_TO_UINT (b); +} + +gboolean +mix_vm_load_file (mix_vm_t *vm, const gchar *name) +{ +  mix_code_file_t *file; +  mix_ins_desc_t ins; +  const gchar *sp; +   +  g_return_val_if_fail (vm != NULL, FALSE); +  file = mix_code_file_new_read (name); +  if (file == NULL) return FALSE; +  vm_reset_ (vm); +  if ( mix_code_file_is_debug (file) ) +    { +      vm->symbol_table = mix_code_file_get_symbol_table (file); +      vm->line_table = g_tree_new (cmp_uint_); +      vm->address_table = g_tree_new (cmp_uint_); +    } + +  sp = mix_code_file_get_source_path (file); +  if (sp != NULL) +    vm->src_file = mix_src_file_new_for_read (sp); +   +  while ( mix_code_file_get_ins (file, &ins) )  +    { +      set_cell_ (vm, ins.address, ins.ins); +      if ( vm->line_table != NULL ) +	{ +	  g_tree_insert (vm->line_table,  +			 GUINT_TO_POINTER (ins.lineno), +			 GUINT_TO_POINTER ((guint)ins.address)); +	  g_tree_insert (vm->address_table,  +			 GUINT_TO_POINTER ((guint)ins.address), +			 GUINT_TO_POINTER (ins.lineno)); +	} +    } +  set_loc_ (vm, mix_code_file_get_start_addr (file)); +  set_start_ (vm, get_loc_ (vm)); +  mix_code_file_delete (file); +   +  return TRUE; +} + +const mix_src_file_t * +mix_vm_get_src_file (const mix_vm_t *vm) +{ +  g_return_val_if_fail (vm != NULL, NULL); +  return vm->src_file; +} + +const mix_symbol_table_t * +mix_vm_get_symbol_table (const mix_vm_t *vm) +{ +  g_return_val_if_fail (vm != NULL, NULL); +  return vm->symbol_table; +} + +mix_address_t  +mix_vm_get_prog_count (const mix_vm_t *vm) +{ +  g_return_val_if_fail (vm != NULL, MIX_SHORT_ZERO); +  return get_loc_ (vm); +} + +/* Get the source line number for a given address */ +guint +mix_vm_get_address_lineno (const mix_vm_t *vm, mix_address_t addr) +{ +  gpointer gp_addr = GUINT_TO_POINTER ((guint)addr); +  guint lineno; + +  g_return_val_if_fail (vm != NULL, 0); +  g_return_val_if_fail (MEMOK_ (addr), 0); +  lineno = GPOINTER_TO_UINT (g_tree_lookup (vm->address_table, gp_addr)); +  return lineno; +} + +/* Get the address for a given source line number */ +typedef struct  +{ +  guint lineno; +  mix_address_t result; +} addr_traverse_t; + +static gint +get_address_ (gpointer key, gpointer value, gpointer data) +{ +  addr_traverse_t *tr = (addr_traverse_t *)data; +  if (GPOINTER_TO_UINT (key) == tr->lineno) +    { +      tr->result = mix_short_new (GPOINTER_TO_UINT (value)); +      return TRUE; +    } +  return (GPOINTER_TO_UINT (key) < tr->lineno)? FALSE:TRUE; +} + +mix_address_t +mix_vm_get_lineno_address (const mix_vm_t *vm, guint lineno) +{ +  addr_traverse_t tr; +   +  g_return_val_if_fail (vm != NULL, MIX_VM_CELL_NO); +  if (!vm->line_table) return MIX_VM_CELL_NO; +  tr.lineno = lineno; +  tr.result = MIX_VM_CELL_NO; +  g_tree_traverse (vm->line_table, get_address_, G_IN_ORDER, (gpointer)&tr); +  return tr.result; +} + + +/* Reposition program counter and reset state so that a loaded +   program can be restarted. +*/ +void +mix_vm_reset_program (mix_vm_t *vm) +{ +  guint k; +  g_return_if_fail (vm != NULL); +  reset_loc_ (vm); +  halt_ (vm, FALSE); +  set_rA_ (vm, MIX_WORD_ZERO); +  set_rX_ (vm, MIX_WORD_ZERO); +  set_rJ_ (vm, MIX_WORD_ZERO); +  for ( k = 1; k < IREG_NO_+1; ++k ) +    set_rI_ (vm, k, MIX_WORD_ZERO); +  set_over_ (vm, FALSE); +  set_cmp_ (vm, mix_EQ); +} + +/* continue execution of instructions in memory */ +int +mix_vm_run (mix_vm_t *vm) +{ +  mix_ins_t ins; +  g_return_val_if_fail (vm != NULL, MIX_VM_ERROR); +   +  while ( !is_halted_ (vm) ) +    { +      mix_word_to_ins_uncheck (get_cell_ (vm, get_loc_ (vm)), ins); +      if ( !(*ins_handlers_[ins.opcode]) (vm,&ins) )  +	return MIX_VM_ERROR; +      else +	update_time_ (vm, &ins); +      if (bp_is_set_ (vm, get_loc_ (vm))) +	return MIX_VM_BREAK; +      if (get_loc_ (vm) >= MIX_VM_CELL_NO) halt_ (vm, TRUE); +    } +  return MIX_VM_HALT; +} + +/* execute next memory instruction */ +int +mix_vm_exec_next (mix_vm_t *vm) +{ +  mix_ins_t ins; +  g_return_val_if_fail (vm != NULL, MIX_VM_ERROR); +  if (get_loc_ (vm) >= MIX_VM_CELL_NO) halt_ (vm, TRUE); +  if (is_halted_ (vm)) return MIX_VM_HALT; +  mix_word_to_ins_uncheck (get_cell_ (vm, get_loc_ (vm)), ins); +  if (!(*ins_handlers_[ins.opcode]) (vm, &ins)) +    return MIX_VM_ERROR; +  else +    update_time_ (vm, &ins); +  if (is_halted_ (vm)) return MIX_VM_HALT; +  return bp_is_set_ (vm, get_loc_ (vm)) ? MIX_VM_BREAK : MIX_VM_OK; +} + +/* Breakpoints */ +gulong +mix_vm_get_break_lineno (const mix_vm_t *vm) +{ +  g_return_val_if_fail (vm != NULL, 0); +  if (vm->address_table == NULL) +    return 0; +  else +    { +      gpointer loc = GUINT_TO_POINTER ((guint)get_loc_ (vm)); +      return GPOINTER_TO_UINT (g_tree_lookup (vm->address_table,loc)); +    } +} + +typedef struct  +{ +  mix_vm_t *vm; +  guint lineno; +  gint result; +} bp_traverse_t; + +static gint +set_break_ (gpointer key, gpointer value, gpointer data) +{ +  bp_traverse_t *tr = (bp_traverse_t *)data; +  if (GPOINTER_TO_UINT (key) >= tr->lineno) +    { +      bp_set_ (tr->vm, mix_short_new (GPOINTER_TO_UINT (value))); +      tr->lineno = GPOINTER_TO_UINT (key); +      tr->result = MIX_VM_BP_OK; +      return TRUE; +    } +  return FALSE; +} + +gint /* if >0 the line no. of the break point */ +mix_vm_set_breakpoint (mix_vm_t *vm, guint lineno) +{ +  bp_traverse_t tr; +   +  g_return_val_if_fail (vm != NULL, MIX_VM_BP_ERROR); +  if (!vm->line_table) return MIX_VM_BP_NDEBUG; +  tr.lineno = lineno; +  tr.vm = vm; +  tr.result = MIX_VM_BP_INV_LINE; +  g_tree_traverse (vm->line_table, set_break_, G_IN_ORDER, (gpointer)&tr); +  if (tr.result == MIX_VM_BP_OK) +    return tr.lineno; +  else +    return tr.result; +} + +gint +mix_vm_set_breakpoint_address (mix_vm_t *vm, guint address)  +{ +  g_return_val_if_fail (vm != NULL, MIX_VM_BP_ERROR); +  if (address >= MIX_VM_CELL_NO) +    return MIX_VM_BP_INV_ADDRESS; +  else +    bp_set_ (vm, mix_short_new (address)); +  return MIX_VM_BP_OK; +} + +gboolean +mix_vm_has_breakpoint_at_address (const mix_vm_t *vm, guint address) +{ +  g_return_val_if_fail (vm != NULL, FALSE); +  if (address >= MIX_VM_CELL_NO) return FALSE; +  return  (bp_is_set_ (vm, address)); +} + +static gint +clear_break_ (gpointer key, gpointer value, gpointer data) +{ +  bp_traverse_t *tr = (bp_traverse_t *)data; +  if (GPOINTER_TO_UINT (key) == tr->lineno) +    { +      bp_clear_ (tr->vm, mix_short_new (GPOINTER_TO_UINT (value))); +      tr->result = MIX_VM_BP_OK; +      return TRUE; +    } +  else if (GPOINTER_TO_UINT (key) > tr->lineno) +    return TRUE; +   +  return FALSE; +} + +gint /* one of MIX_VM_BP_ */ +mix_vm_clear_breakpoint (mix_vm_t *vm, guint lineno) +{ +  bp_traverse_t tr; +   +  g_return_val_if_fail (vm != NULL, MIX_VM_BP_ERROR); +  if (!vm->line_table) return MIX_VM_BP_NDEBUG; +  tr.lineno = lineno; +  tr.vm = vm; +  tr.result = MIX_VM_BP_INV_LINE; +  g_tree_traverse (vm->line_table, clear_break_, G_IN_ORDER, (gpointer)&tr); +  return tr.result; +} + +gint +mix_vm_clear_breakpoint_address (mix_vm_t *vm, guint address)  +{ +  g_return_val_if_fail (vm != NULL, MIX_VM_BP_ERROR); +  if (address >= MIX_VM_CELL_NO) +    return MIX_VM_BP_INV_ADDRESS; +  else +    bp_clear_ (vm, mix_short_new (address)); +  return MIX_VM_BP_OK; +} + +void +mix_vm_clear_all_breakpoints (mix_vm_t *vm) +{ +  g_return_if_fail (vm != NULL); +  bp_clear_all_ (vm); +} + +/* Get the vm uptime, defined as the time spent executing instructions */ +mix_time_t +mix_vm_get_uptime (const mix_vm_t *vm) +{ +  g_return_val_if_fail (vm != NULL, 0); +  return mix_vm_clock_get_time (get_clock_ (vm)); +} + diff --git a/mixlib/mix_vm.h b/mixlib/mix_vm.h new file mode 100644 index 0000000..b64e197 --- /dev/null +++ b/mixlib/mix_vm.h @@ -0,0 +1,204 @@ +/* ---------------------- mix_vm.h : + * Types and functions implementing the MIX virtual machine + * ------------------------------------------------------------------ + * Copyright (C) 2000, 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#ifndef MIX_VM_H +#define MIX_VM_H + +#include "mix_types.h" +#include "mix_ins.h" +#include "mix_device.h" +#include "mix_code_file.h" +#include "mix_src_file.h" +#include "mix_symbol_table.h" +#include "mix_vm_clock.h" + +/* Comparison flag */ +typedef enum { mix_LESS, mix_EQ, mix_GREAT } mix_cmpflag_t; + +/* Number of memory cells in the virtual machine */ +enum { MIX_VM_CELL_NO = 4000 }; + +/* Opaque type for the mix virtual machine */ +typedef struct mix_vm_t mix_vm_t; + +/* Create/destroy a mix vm */ +extern mix_vm_t * +mix_vm_new(void); + +extern void +mix_vm_delete(mix_vm_t * vm); + +/* connect devices to a virtual machine */ +extern mix_device_t * /* previously connected device */ +mix_vm_connect_device (mix_vm_t *vm, mix_device_t *device); + +/* Reset a vm (set state as of a newly created one) */ +extern void +mix_vm_reset(mix_vm_t * vm); + +/* Set start address for execution */ +extern void +mix_vm_set_start_addr(mix_vm_t *vm, mix_address_t addr); + +/* Access to the vm's registers */ +extern mix_word_t +mix_vm_get_rA(const mix_vm_t *vm); + +extern mix_word_t +mix_vm_get_rX(const mix_vm_t *vm); + +extern mix_short_t +mix_vm_get_rJ(const mix_vm_t *vm); + +extern mix_short_t +mix_vm_get_rI(const mix_vm_t *vm, guint idx); + +extern void  +mix_vm_set_rA(mix_vm_t *vm, mix_word_t value); + +extern void +mix_vm_set_rX(mix_vm_t *vm, mix_word_t value); + +extern void  +mix_vm_set_rJ(mix_vm_t *vm, mix_short_t value); + +extern void  +mix_vm_set_rI(mix_vm_t *vm, guint idx, mix_short_t value); + + +/* Access to the comparison flag and overflow toggle */ +extern mix_cmpflag_t +mix_vm_get_cmpflag(const mix_vm_t *vm); + +extern void +mix_vm_set_cmpflag(mix_vm_t *vm, mix_cmpflag_t value); + +extern gboolean +mix_vm_get_overflow(const mix_vm_t *vm); + +extern void +mix_vm_set_overflow(mix_vm_t *vm, gboolean value); + +extern void +mix_vm_toggle_overflow(mix_vm_t *vm); + +extern gboolean +mix_vm_is_halted(const mix_vm_t *vm); + +/* Access to memory cells */ +extern mix_word_t +mix_vm_get_addr_contents(const mix_vm_t *vm, mix_address_t addr); + +extern void +mix_vm_set_addr_contents(mix_vm_t *vm, mix_address_t addr, mix_word_t value); + +/* Execution of instructions and programs */ +extern gboolean /* TRUE if success */ +mix_vm_exec_ins(mix_vm_t *vm, const mix_ins_t *ins); + +/* Load a code file into memory (-name- does not need the default extension)  + * resetting the vm's state + */ +extern gboolean +mix_vm_load_file(mix_vm_t *vm, const gchar *name); + +/* Get the source file object corresponding to the last loaded code file */ +extern const mix_src_file_t * +mix_vm_get_src_file (const mix_vm_t *vm); + +/* Get symbol table of loaded file */ +extern const mix_symbol_table_t * +mix_vm_get_symbol_table (const mix_vm_t *vm); + +/* Get current program counter */ +extern mix_address_t  +mix_vm_get_prog_count (const mix_vm_t *vm); + +/* Get the source line number for a given address */ +extern guint +mix_vm_get_address_lineno (const mix_vm_t *vm, mix_address_t addr); + +/* Get the address for a given source line number */ +extern mix_address_t +mix_vm_get_lineno_address (const mix_vm_t *vm, guint lineno); + +/* Reposition program counter and reset state so that a loaded +   program can be restarted. +*/ +extern void +mix_vm_reset_program (mix_vm_t *vm); + +/* continue execution of instructions in memory */ +/* Possible outcomes */ +enum { +  MIX_VM_ERROR,		/* error executing instructions */ +  MIX_VM_BREAK,		/* breakpoint found */ +  MIX_VM_HALT,		/* end of execution */ +  MIX_VM_OK		/* successful instruction execution */ +}; + +extern int +mix_vm_run (mix_vm_t *vm); + +/* execute next memory instruction */ +extern int +mix_vm_exec_next (mix_vm_t *vm); + +/* get the line no. of the last break or 0 if not found */ +extern gulong +mix_vm_get_break_lineno (const mix_vm_t *vm); + +/* Breakpoints */ +/* possible error outcomes */ +enum { +  MIX_VM_BP_ERROR = -4,		/* internal error */ +  MIX_VM_BP_NDEBUG = -3,	/* no debug info */ +  MIX_VM_BP_INV_ADDRESS = -2,   /* address out of range */ +  MIX_VM_BP_INV_LINE = -1,	/* invalid line no. */ +  MIX_VM_BP_OK = 0		/* success */ +}; + +extern gint /* if >0 the line no. of the break point */ +mix_vm_set_breakpoint (mix_vm_t *vm, guint lineno); + +extern gint /* one of MIX_VM_BP_ */ +mix_vm_set_breakpoint_address (mix_vm_t *vm, guint address); + +extern gint /* one of MIX_VM_BP_ */ +mix_vm_clear_breakpoint (mix_vm_t *vm, guint lineno); + +extern gint /* one of MIX_VM_BP_ */ +mix_vm_clear_breakpoint_address (mix_vm_t *vm, guint address) ; + +extern gboolean +mix_vm_has_breakpoint_at_address (const mix_vm_t *vm, guint address); + +extern void +mix_vm_clear_all_breakpoints (mix_vm_t *vm); + +/* Get the vm uptime, defined as the time spent executing instructions */ +extern mix_time_t +mix_vm_get_uptime (const mix_vm_t *vm); + + +#endif /* MIX_VM_H */ + diff --git a/mixlib/mix_vm_clock.c b/mixlib/mix_vm_clock.c new file mode 100644 index 0000000..41e7116 --- /dev/null +++ b/mixlib/mix_vm_clock.c @@ -0,0 +1,68 @@ +/* -*-c-*- -------------- mix_vm_clock.c : + * Implementation of the functions declared in mix_vm_clock.h + * ------------------------------------------------------------------ + *  Last change: Time-stamp: "01/02/20 00:23:58 jose" + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#include "mix_vm_clock.h" + +static const mix_time_t exec_times_[] = { +  1, 2, 2, 10, 12, 10, 2, 1,  +  2, 2, 2, 2 ,  2,  2, 2, 2, +  2, 2, 2, 2 ,  2,  2, 2, 2, +  2, 2, 2, 2 ,  2,  2, 2, 2, +  2, 2, 1, 1,   1,  1, 1, 1, +  1, 1, 1, 1,   1,  1, 1, 1, +  1, 1, 1, 1,   1,  1, 1, 1, +  2, 2, 2, 2 ,  2,  2, 2, 2 +}; + + +/* Create/delete a clock */ +mix_vm_clock_t * +mix_vm_clock_new () +{ +  mix_vm_clock_t *result = g_new (mix_vm_clock_t, 1); +  result->time = 0; +  return result; +} + +void +mix_vm_clock_delete (mix_vm_clock_t *clock) +{ +  g_return_if_fail (clock != NULL); +} + +/* Increase time with the units needed to execute ins */ +mix_time_t +mix_vm_clock_add_lapse (mix_vm_clock_t *clock, const mix_ins_t *ins) +{ +  mix_time_t t = 0; +  g_return_val_if_fail (clock != NULL, 0); +  if (ins != NULL) +    { +      t = exec_times_[ins->opcode]; +      if (ins->opcode == mix_MOVE) t += 2 * (ins->fspec); +    } +  clock->time += t; +  return t; +} + diff --git a/mixlib/mix_vm_clock.h b/mixlib/mix_vm_clock.h new file mode 100644 index 0000000..706115e --- /dev/null +++ b/mixlib/mix_vm_clock.h @@ -0,0 +1,55 @@ +/* -*-c-*- ---------------- mix_vm_clock.h : + * Declaration of mix_vm_clock_t, a clock for the MIX virtual machine. + * ------------------------------------------------------------------ + *  Last change: Time-stamp: <01/02/20 00:23:58 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#ifndef MIX_VM_CLOCK_H +#define MIX_VM_CLOCK_H + +#include "mix.h" +#include "mix_ins.h" + +/* the type of time unit */ +typedef gulong mix_time_t; + +/* the clock type */ +typedef struct mix_vm_clock_t +{ +  mix_time_t time; +} mix_vm_clock_t; + +/* Create/delete a clock */ +extern mix_vm_clock_t * +mix_vm_clock_new (); + +extern void +mix_vm_clock_delete (mix_vm_clock_t *clock); + +/* Increase time with the units needed to execute ins */ +extern mix_time_t /* the added lapse */ +mix_vm_clock_add_lapse (mix_vm_clock_t *clock, const mix_ins_t *ins); + +/* Get the time since creation */ +#define mix_vm_clock_get_time(clock) (clock? clock->time:0) + +#endif /* MIX_VM_CLOCK_H */ + diff --git a/mixlib/mix_vm_command.c b/mixlib/mix_vm_command.c new file mode 100644 index 0000000..9cc0d52 --- /dev/null +++ b/mixlib/mix_vm_command.c @@ -0,0 +1,1167 @@ +/* -*-c-*- -------------- mix_vm_command.c : + * Implementation of the functions declared in mix_vm_command.h + * ------------------------------------------------------------------ + *  Last change: Time-stamp: "01/03/15 15:57:52 jose" + * ------------------------------------------------------------------ + * Copyright (C) 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#include "mix_vm_command.h" +#include "mix_vm.h" +#include "mix_vm_dump.h" +#include "mix_eval.h" + +/* hooks */ +typedef struct  +{ +  mix_vm_cmd_hook_t func; +  gpointer data; +} hook_; + +typedef struct  +{ +  mix_vm_cmd_global_hook_t func; +  gpointer data; +} global_hook_; + +struct mix_vm_cmd_dispatcher_t  +{ +  mix_vm_t *vm;			/* the virtual machine */ +  gboolean result;		/* last command's outcome */ +  gchar *program;		/* the name of the last loaded program */ +  FILE *out;			/* message output file */ +  FILE *err;			/* error output file */ +  mix_dump_context_t *dump;	/* dump context for output */ +  mix_eval_t *eval;		/* evaluator for w-expressions */ +  gboolean trace;		/* tracing flag */ +  gboolean printtime;		/* printing times flag */ +  mix_time_t uptime;		/* total running time */ +  mix_time_t laptime;		/* last run time */ +  mix_time_t progtime;		/* current program running time */ +  hook_ pre_hooks[MIX_CMD_INVALID]; /* Pre-command hooks */ +  hook_ post_hooks[MIX_CMD_INVALID]; /* Post-command hooks */ +  global_hook_ global_pre;	/* global pre-command hook */ +  global_hook_ global_post;	/* global post-command hook */ +}; + +/* command handlers */ +typedef gboolean (*Function_)(mix_vm_cmd_dispatcher_t *, const gchar *); +#define DEC_FUN(name) \ +  static int cmd_##name (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) + +DEC_FUN (help_); +DEC_FUN (load_); +DEC_FUN (run_); +DEC_FUN (next_); +DEC_FUN (pc_); +DEC_FUN (psym_); +DEC_FUN (preg_); +DEC_FUN (pflags_); +DEC_FUN (pall_); +DEC_FUN (pmem_); +DEC_FUN (sreg_); +DEC_FUN (scmp_); +DEC_FUN (sover_); +DEC_FUN (smem_); +DEC_FUN (ssym_); +DEC_FUN (sbp_); +DEC_FUN (sbpa_); +DEC_FUN (cbp_); +DEC_FUN (cbpa_); +DEC_FUN (cabp_); +DEC_FUN (weval_); +DEC_FUN (w2d_); +DEC_FUN (tron_); +DEC_FUN (troff_); + +/* internal command info struct */ +typedef struct { +  const char *name;		/* User printable name of the function. */ +  Function_  func;		/* Function to call to do the job. */ +  const char *doc;		/* Documentation for this function.  */ +  const char *usage;		/* Usage */ +} command_; + +/* available commands (in the same order as the type enum) */ +      +command_ commands_[] = { +  { "help", cmd_help_, N_("Display this text"), "help [COMMAND]"}, +  { "load", cmd_load_, N_("Load a MIX code file"), "load FILENAME"}, +  { "run", cmd_run_, N_("Run loaded or given MIX code file"),  +    "run [FILENAME]"}, +  { "next", cmd_next_, N_("Execute next instruction(s)"),  +    "next [NO_OF_INS]"}, +  { "pc", cmd_pc_, N_("Print program counter value"), "pc" }, +  { "psym", cmd_psym_, N_("Print symbol value"), "psym [SYMBOLNAME]"}, +  { "preg", cmd_preg_, N_("Print register value"),  +    "preg [A | X | J | I[1-6]]"}, +  { "pflags", cmd_pflags_, N_("Print comparison and overflow flags"),  +    "pflags"}, +  { "pall", cmd_pall_, N_("Print all registers and flags"), "pall"}, +  { "pmem", cmd_pmem_, N_("Print memory contents in address range"),  +    "pmem FROM[-TO]"}, +  { "sreg", cmd_sreg_, N_("Set register value"),  +    "preg A | X | J | I[1-6] VALUE"}, +  { "scmp", cmd_scmp_, N_("Set comparison flag value"), "scmp L | E | G"}, +  { "sover", cmd_sover_, N_("Set overflow flag value"), "sover T | F" }, +  { "smem", cmd_smem_, N_("Set memory contents in given address"),  +    "smem ADDRESS VALUE"}, +  { "ssym", cmd_ssym_, N_("Set a symbol\'s value"), "ssym SYMBOL WEXPR"}, +  { "sbp", cmd_sbp_, N_("Set break point at given line"), "sbp LINENO"}, +  { "cbp", cmd_cbp_, N_("Clear break point at given line"), "cbp LINENO"}, +  { "sbpa", cmd_sbpa_, N_("Set break point at given address"), +    "sbpa ADDRESS"}, +  { "cbpa", cmd_cbpa_, N_("Clear break point at given address"), +    "cbpa ADDRESS"}, +  { "cabp", cmd_cabp_, N_("Clear all breakpoints"), "cabp"}, +  { "weval", cmd_weval_, N_("Evaluate a given W-expression"), "weval WEXPR"}, +  { "w2d", cmd_w2d_, N_("Convert a MIX word to its decimal value"), +    "w2d WORD"}, +  { "tron", cmd_tron_, N_("Turn on instruction tracing."), "tron"}, +  { "troff", cmd_troff_, N_("Turn off instruction tracing."), "troff"}, +  { NULL, NULL, NULL, NULL}, +}; + + +/* external interface */ + +/* conversion from/to commands to strings */ +const gchar * +mix_vm_command_to_string (mix_vm_command_t cmd) +{ +  if (cmd < MIX_CMD_INVALID) return commands_[cmd].name; +  else return NULL; +} + +mix_vm_command_t +mix_vm_command_from_string (const gchar *name) +{ +  /* inefficient linear search, i know */ +  gint cmd = 0; +  while (cmd < MIX_CMD_INVALID && strcmp (name, commands_[cmd].name)) +    ++cmd; +  return cmd; +} + +/* get help string about a command */ +const gchar * +mix_vm_command_help (mix_vm_command_t cmd) +{ +  if (cmd < MIX_CMD_INVALID) return commands_[cmd].doc; +  else return NULL; +} + +const gchar * +mix_vm_command_usage (mix_vm_command_t cmd) +{ +  if (cmd < MIX_CMD_INVALID) return commands_[cmd].usage; +  else return NULL; +} + +/* create a new command dispatcher */ +mix_vm_cmd_dispatcher_t * +mix_vm_cmd_dispatcher_new (FILE *out_fd, /* output messages file */ +			   FILE *err_fd /* error messages file */) +{ +  mix_vm_cmd_dispatcher_t *result = NULL; +  int k; +   +  g_return_val_if_fail (out_fd && err_fd, NULL); +   +  result = g_new (mix_vm_cmd_dispatcher_t, 1); +  result->result = TRUE; +  result->out = out_fd; +  result->err = err_fd; +  result->uptime = result->laptime = result->progtime = 0; +  result->printtime = TRUE; +  result->trace = FALSE; +  result->program = NULL; +  result->eval = mix_eval_new (); +  result->dump = mix_dump_context_new (out_fd,  +				       MIX_SHORT_ZERO, MIX_SHORT_ZERO, +				       MIX_DUMP_ALL); +  result->vm = mix_vm_new (); +  result->global_pre.func = result->global_post.func = NULL; +  result->global_pre.data = result->global_post.data = NULL; +  for (k =0; k < MIX_CMD_INVALID; ++k) +    { +      result->pre_hooks[k].func = result->post_hooks[k].func = NULL; +      result->pre_hooks[k].data = result->post_hooks[k].data = NULL; +    } +       +  return result; +} + +/* delete (does not close the fds in the constructor) */ +extern void +mix_vm_cmd_dispatcher_delete (mix_vm_cmd_dispatcher_t *dis) +{ +  g_return_if_fail (dis != NULL); +  mix_eval_delete (dis->eval); +  mix_dump_context_delete (dis->dump); +  mix_vm_delete (dis->vm); +  g_free (dis); +} + +/* install hooks */ +void +mix_vm_cmd_dispatcher_pre_hook (mix_vm_cmd_dispatcher_t *dis, +				mix_vm_command_t cmd, +				mix_vm_cmd_hook_t hook, gpointer data) +{ +  g_return_if_fail (dis != NULL); +  g_return_if_fail (cmd < MIX_CMD_INVALID); +  dis->pre_hooks[cmd].func = hook; +  dis->pre_hooks[cmd].data = data; +} + +void +mix_vm_cmd_dispatcher_post_hook (mix_vm_cmd_dispatcher_t *dis, +				 mix_vm_command_t cmd, +				 mix_vm_cmd_hook_t hook, gpointer data) +{ +  g_return_if_fail (dis != NULL); +  g_return_if_fail (cmd < MIX_CMD_INVALID); +  dis->post_hooks[cmd].func = hook; +  dis->post_hooks[cmd].data = data; +} + +void +mix_vm_cmd_dispatcher_global_pre_hook (mix_vm_cmd_dispatcher_t *dis, +				       mix_vm_cmd_global_hook_t hook, +				       gpointer data) +{ +  g_return_if_fail (dis != NULL); +  dis->global_pre.func = hook; +  dis->global_pre.data = data; +} + +void +mix_vm_cmd_dispatcher_global_post_hook (mix_vm_cmd_dispatcher_t *dis, +					mix_vm_cmd_global_hook_t hook, +					gpointer data) +{ +  g_return_if_fail (dis != NULL); +  dis->global_post.func = hook; +  dis->global_post.data = data; +} + +/* dispatch a command */ +gboolean /* TRUE if success, FALSE otherwise */ +mix_vm_cmd_dispatcher_dispatch (mix_vm_cmd_dispatcher_t *dis, +				mix_vm_command_t cmd, const gchar *arg) +{ +  g_return_val_if_fail (dis != NULL, FALSE); +   +  if (dis->global_pre.func) +    (dis->global_pre.func)(dis, cmd, arg, dis->global_pre.data); +   +  if (cmd < MIX_CMD_INVALID) +    { +      if (dis->pre_hooks[cmd].func) +	(dis->pre_hooks[cmd].func)(dis, arg, dis->pre_hooks[cmd].data); +      dis->result = (commands_[cmd].func)(dis, arg); +      if (dis->post_hooks[cmd].func) +	(dis->post_hooks[cmd].func)(dis, arg, dis->post_hooks[cmd].data); +    } +  else +    { +      fprintf (dis->err, "Unknown command. Try: help"); +    } + +  if (dis->global_post.func) +    (dis->global_post.func)(dis, cmd, arg, dis->global_post.data); + +  fflush (dis->out); +  fflush (dis->err); +  return dis->result; +} + +/* dispatch a command in text format */ +gboolean +mix_vm_cmd_dispatcher_dispatch_text (mix_vm_cmd_dispatcher_t *dis, +				     const gchar *text) +{ +  gchar *cp, *arg = ""; +  int k = 0; +  gboolean result; +   +  g_return_val_if_fail (dis != NULL, FALSE); +  g_return_val_if_fail (text != NULL, FALSE); +   +  cp = g_strdup (text); +  while (cp[k] && !isspace (cp[k])) ++k; +  if (cp[k]) +    { +      cp[k] = '\0'; ++k; +      while (cp[k] && isspace (cp[k])) ++k; +      arg = cp + k; +    } + +  result = mix_vm_cmd_dispatcher_dispatch (dis, +					   mix_vm_command_from_string (cp), +					   arg); +  g_free (cp); +  return result; +} + +/* get the last dispatch's result */ +gboolean +mix_vm_cmd_dispatcher_get_last_result (const mix_vm_cmd_dispatcher_t *dis) +{ +  g_return_val_if_fail (dis != NULL, FALSE); +  return dis->result; +} + +/* get total uptime */ +mix_time_t +mix_vm_cmd_dispatcher_get_uptime (const mix_vm_cmd_dispatcher_t *dis) +{ +  g_return_val_if_fail (dis != NULL, 0); +  return dis->uptime; +} + +/* get program total time */ +mix_time_t +mix_vm_cmd_dispatcher_get_progtime (const mix_vm_cmd_dispatcher_t *dis) +{ +  g_return_val_if_fail (dis != NULL, 0); +  return dis->progtime; +} + +/* get time lapse */ +mix_time_t +mix_vm_cmd_dispatcher_get_laptime (const mix_vm_cmd_dispatcher_t *dis) +{ +  g_return_val_if_fail (dis != NULL, 0); +  return dis->laptime; +} + +/* toggle time printing */ +void +mix_vm_cmd_dispatcher_print_time (mix_vm_cmd_dispatcher_t * dis, gboolean print) +{ +  g_return_if_fail (dis != NULL); +  dis->printtime = print; +} + +/* get the mix vm */ +const mix_vm_t * +mix_vm_cmd_dispatcher_get_vm (const mix_vm_cmd_dispatcher_t *dis) +{ +  g_return_val_if_fail (dis != NULL, NULL); +  return dis->vm; +} + + +/* trace current instruction */ +static void +trace_ (mix_vm_cmd_dispatcher_t *dis) +{ +  enum {BUFFER_LEN = 128}; +  static gchar STRINS[BUFFER_LEN]; +   +  const mix_src_file_t *file = mix_vm_get_src_file (dis->vm); +  const gchar *line = "\n"; +  mix_address_t loc = mix_vm_get_prog_count (dis->vm); +  mix_word_t ins = mix_vm_get_addr_contents (dis->vm, loc); +  mix_ins_t fins; +  mix_word_to_ins_uncheck (ins, fins); +  mix_ins_to_string_in_buffer (&fins, STRINS, BUFFER_LEN); +   +  if (file != NULL) +    { +      gulong b = mix_vm_get_break_lineno (dis->vm); +      if (b > 0) line = mix_src_file_get_line (file, b); +    } +   +  fprintf (dis->out, "%d: [%-15s]\t%s", (gint)loc, STRINS, line); +} + +/* run a program tracing executed instructions */ +static int +run_and_trace_ (mix_vm_cmd_dispatcher_t *dis) +{ +  int k = MIX_VM_OK; +  if (!dis->trace) +    return mix_vm_run (dis->vm); +  else while (k == MIX_VM_OK) +    { +      trace_ (dis); +      k = mix_vm_exec_next (dis->vm); +    } +  return k; +} + +/* print time statistics */ +static void +print_time_ (mix_vm_cmd_dispatcher_t *dis) +{ +  dis->laptime = mix_vm_get_uptime(dis->vm) - dis->uptime; +  dis->uptime += dis->laptime; +  dis->progtime += dis->laptime; +  if (dis->printtime) +    fprintf( dis->out, +	     _("Elapsed time: %ld /Total program time: %ld (Total uptime: %ld)\n"), +	     dis->laptime, dis->progtime, dis->uptime); +} + + +/* commands */ + +static gboolean +cmd_help_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  static const int NO_OF_COLS = 6; +   +  int i; +  int printed = 0; +      +  for (i = 0; commands_[i].name; i++) +    { +      if (!*arg || (strcmp (arg, commands_[i].name) == 0)) +	{ +	  fprintf (dis->out ,_("%s\t\t%s. Usage: %s\n"), commands_[i].name,  +		  _(commands_[i].doc), commands_[i].usage); +	  printed++; +	} +    } +   +  if (!printed) +    { +      fprintf (dis->out, +	       _("No commands match `%s'.  Possibilities are:\n"), arg); +      +      for (i = 0; commands_[i].name; i++) +	{ +	  if (printed == NO_OF_COLS) +	    { +	      printed = 0; +	      fprintf (dis->out, "\n"); +	    } +      +	  fprintf (dis->out, "%s\t", commands_[i].name); +	  printed++; +	} +      +      if (printed) +	fprintf (dis->out, "\n"); +    } +  return TRUE; +} + +static gboolean +cmd_load_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  errno = 0; +  if (arg == NULL || *arg == '\0') +    { +      fputs (_("Missing file name\n"), dis->err); +      return FALSE; +    } +  mix_eval_remove_symbols_from_table (dis->eval, +				      mix_vm_get_symbol_table (dis->vm)); +  if (!mix_vm_load_file (dis->vm, arg) ) +    { +      fprintf (dis->err, _("Cannot load %s: "), arg); +      if ( errno == 0 ) +	fputs (_("Wrong file format\n"), dis->err); +      else +	fprintf (dis->err, "%s\n", strerror (errno)); +      return FALSE; +    } + +  if (dis->program != arg) +    { +        if (dis->program) g_free (dis->program); +	dis->program = g_strdup (arg); +    } + +  mix_eval_set_symbols_from_table (dis->eval, +				   mix_vm_get_symbol_table (dis->vm)); + +  fprintf (dis->out, _("Program loaded. Start address: %d\n"), +	   mix_vm_get_prog_count (dis->vm)); +   +  dis->laptime = dis->progtime = 0; +  return TRUE; +} + + +static gboolean +cmd_run_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  if (arg != NULL && *arg != '\0' && cmd_load_ (dis, arg) != TRUE)  +      return FALSE; +   +  if (mix_vm_is_halted (dis->vm)) cmd_load_ (dis, dis->program); +     +  fputs (_("Running ...\n"), dis->out); + +  switch (run_and_trace_ (dis)) +    { +    case MIX_VM_HALT: +      fputs (_("... done\n"), dis->out); +      break; +    case MIX_VM_BREAK: +      { +	gulong line = mix_vm_get_break_lineno (dis->vm); +	if (line != 0) +	  fprintf (dis->out, +		   _("... stopped: breakpoint at line %ld (address %d)\n"),  +		  line, mix_vm_get_prog_count (dis->vm)); +	else +	  fprintf (dis->out, _("... stopped: breakpoint at address %d\n"), +		  mix_vm_get_prog_count (dis->vm)); +      } +      break; +    case MIX_VM_ERROR: +      fputs (_("... error executing loaded file"), dis->err); +      break; +    default: +      g_assert_not_reached (); +      break; +    } +  print_time_ (dis); + +  return TRUE; +} + +static gboolean +cmd_next_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  int ins_no = 1; +  int k; + +  if ( strlen (arg) != 0 ) +    { +      int k = 0; +      while (isdigit (arg[k])) +	k++; +      if (arg[k] != '\0') +	{ +	  fprintf (dis->err, _("Invalid argument: %s\n"), arg); +	  cmd_help_ (dis, "next"); +	  return FALSE; +	} +      ins_no = atoi (arg); +    } + +  if (mix_vm_is_halted (dis->vm)) cmd_load_ (dis, dis->program); +     +  while ( ins_no-- > 0 ) +    { +      if (dis->trace) trace_ (dis); +      k = mix_vm_exec_next (dis->vm); +      if (k == MIX_VM_HALT) +	{ +	  fprintf (dis->err, _("End of program reached at address %d\n"), +		   mix_vm_get_prog_count (dis->vm)); +	  break; +	} +      else if (k == MIX_VM_ERROR) +	{ +	  fprintf (dis->err, _("Error at address %d\n"), +		   mix_vm_get_prog_count (dis->vm)); +	  break; +	} +    } +  print_time_ (dis); + +  return TRUE; +} + +static gboolean +cmd_pc_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  fprintf (dis->out, "Current address: %d\n", mix_vm_get_prog_count (dis->vm)); +  return TRUE; +} + +static gboolean +cmd_psym_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  gboolean result = FALSE; +  const mix_symbol_table_t *table = mix_eval_symbol_table (dis->eval); +  if ( table == NULL ) +    fputs (_("Symbol table not available\n"), dis->err); +  else if (arg != NULL && *arg != '\0') +    { +      if ( mix_symbol_table_is_defined (table, arg) ) +	{ +	  mix_word_print (mix_symbol_table_value (table, arg), NULL); +	  putc ('\n', dis->out); +	  result = TRUE; +	} +      else +	fprintf (dis->out, _("%s: symbol not defined\n"), arg); +    } +  else +    { +      mix_symbol_table_print (table, MIX_SYM_ROWS, stdout, TRUE); +      result = TRUE; +    } +       +  return result; +} + +static gboolean +cmd_preg_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  mix_dump_context_set_opt (dis->dump, MIX_DUMP_NONE); +  if ( strlen (arg) == 0 ) +    mix_dump_context_add_opt (dis->dump, MIX_DUMP_rALL); +  else switch (*arg) +    { +    case 'A': +      mix_dump_context_add_opt (dis->dump, MIX_DUMP_rA); +      break; +    case 'X': +      mix_dump_context_add_opt (dis->dump, MIX_DUMP_rX); +      break; +    case 'J': +      mix_dump_context_add_opt (dis->dump, MIX_DUMP_rJ); +      break; +    case 'I': +      { +	if ( strlen (arg) == 1 ) +	  mix_dump_context_add_opt (dis->dump, MIX_DUMP_rIa); +	else +	  { +	    static gint32 opt[] = { MIX_DUMP_rI1, MIX_DUMP_rI2, +				    MIX_DUMP_rI3, MIX_DUMP_rI4, +				    MIX_DUMP_rI5, MIX_DUMP_rI6  +	    }; +	    int i = arg[1] - '1'; +	    if ( i < 0 || i > 5 ) +	      { +		fprintf (dis->err, _("Invalid I index: %d"), i); +		return FALSE; +	      } +	    mix_dump_context_add_opt (dis->dump, opt[i]); +	  } +      } +      break; +    default: +      fprintf (dis->err, _("Invalid argument: %s\n"), arg); +      return FALSE; +    } +  mix_vm_dump (dis->vm, dis->dump); +  return TRUE; +} + +static gboolean +cmd_pflags_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  mix_dump_context_set_opt (dis->dump, MIX_DUMP_CMP | MIX_DUMP_OVER); +  mix_vm_dump (dis->vm, dis->dump); +  return TRUE; +} + +static gboolean +cmd_pall_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  mix_dump_context_set_opt (dis->dump, MIX_DUMP_ALL_NOMEM); +  mix_vm_dump (dis->vm, dis->dump); +  return TRUE; +} + +static gboolean +cmd_pmem_ (mix_vm_cmd_dispatcher_t *dis, const gchar *carg) +{ +  glong begin = MIX_SHORT_ZERO, end = MIX_SHORT_ZERO; +  int i = 0; +  gboolean error = FALSE; +  gchar *arg = NULL; +   +  if ( strlen (carg) == 0 ) +    { +      fputs (_("Missing memory address\n"), dis->err); +      return FALSE; +    } +  arg = g_strdup (carg); +  while (isdigit (arg[i])) +    i++; +  while (isspace (arg[i])) +    i++; +  if (arg[i] == '\0') +      begin = end = atol (arg); +  else if (arg[i] == '-') +    { +      arg[i++] = '\0'; +      begin = atol (arg); +      arg = arg + i; +      i = 0; +      while (isdigit (arg[i])) +	i++; +      while (isspace (arg[i])) +	i++; +      if (arg[i] != '\0')  +	error = TRUE; +      else  +	end = atol (arg); +    } +  else +    error = TRUE; +   +  if (error) +    { +      fprintf (dis->err, _("Invalid argument: %s\n"), arg); +      cmd_help_ (dis, "pmem"); +    } +  else if ( end < begin || end > MIX_VM_CELL_NO - 1 ) +    { +      fprintf (dis->err, _("Invalid range: %ld-%ld\n"), begin, end); +      error = TRUE; +    } +  else +    { +      mix_dump_context_set_opt (dis->dump, MIX_DUMP_CELLS); +      mix_dump_context_range (dis->dump, mix_short_new (begin), +			      mix_short_new (end + 1)); +      mix_vm_dump (dis->vm, dis->dump); +    } +  g_free (arg); +  return !error; +} + +static gboolean +cmd_sreg_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  int i = 0; +  char reg = arg[0]; +  gboolean ok = TRUE; +  long value; +   +  i = (reg == 'I') ? 2 : 1; +  ok = strlen (arg) > 2 && isspace (arg[i]); +  if (ok) +    { +      while (isspace (arg[i])) i++; +      ok = isdigit (arg[i]) || arg[i] == '+' || arg[i] == '-'; +      if (ok) +	{ +	  value = atol (arg + i); +	  if (arg[i] == '+' || arg[i] == '-') i++; +	  while (isdigit (arg[i])) i++; +	  ok = (arg[i] == '\0'); +	  if (ok) +	    switch (reg) +	      { +	      case 'A': +		mix_vm_set_rA (dis->vm, mix_word_new (value)); +		break; +	      case 'X': +		mix_vm_set_rX (dis->vm, mix_word_new (value)); +		break; +	      case 'J': +		if ( value >= 0 ) +		  mix_vm_set_rJ (dis->vm, mix_short_new (value)); +		else +		  ok = FALSE; +		break; +	      case 'I': +		{ +		  guint k = arg[1] - '0'; +		  if ( k < 7 )  +		    mix_vm_set_rI (dis->vm, k, mix_short_new (value)); +		  else +		    ok = FALSE; +		} +		break; +	      default: +		ok = FALSE; +	      } +	} +    } +  if (!ok) +    { +      fprintf (dis->err, _("Invalid argument: %s\n"), arg); +      cmd_help_ (dis, "sreg"); +    } +     +  return ok; +} + +static gboolean +cmd_scmp_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  gboolean ok = (strlen (arg) == 1); +  if (ok) switch (arg[0]) +    { +    case 'L': +      mix_vm_set_cmpflag (dis->vm, mix_LESS); +      break; +    case 'E': +      mix_vm_set_cmpflag (dis->vm, mix_EQ); +      break; +    case 'G': +      mix_vm_set_cmpflag (dis->vm, mix_GREAT); +      break; +    default: +      ok = FALSE; +    } +  if (!ok) +    { +      fprintf (dis->err, _("Invalid argument: %s\n"), arg); +      cmd_help_ (dis, "scmp"); +    } +   +  return ok; +} + +static gboolean +cmd_sover_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  gboolean ok = (strlen (arg) == 1); +  if (ok) switch (arg[0]) +    { +    case 'T': +      mix_vm_set_overflow (dis->vm, TRUE); +      break; +    case 'F': +      mix_vm_set_overflow (dis->vm, FALSE); +      break; +    default: +      ok = FALSE; +    } +  if (!ok) +    { +      fprintf (dis->err, _("Invalid argument: %s\n"), arg); +      cmd_help_ (dis, "sover"); +    } +   +  return ok; +} + +static gboolean +cmd_smem_ (mix_vm_cmd_dispatcher_t *dis, const gchar *carg) +{ +  gboolean ok = (strlen (carg) > 2 && isdigit (carg[0])); +  gulong addr; +  glong value; +  int k = 0; +  gchar *arg = NULL; +   +  if (ok) +    { +      arg = g_strdup (carg); +      while (isdigit (arg[k])) k++; +      ok = isspace (arg[k]); +      if (ok) +	{ +	  arg[k++] = '\0'; +	  addr = atol (arg); +	  ok = addr < MIX_VM_CELL_NO; +	} +      if (ok) +	{ +	  while (isspace (arg[k])) k++; +	  value = atol (arg + k); +	  if ( arg[k] == '+' || arg[k] == '-' ) k++; +	  while (isdigit (arg[k])) k++; +	  ok = arg[k] == '\0'; +	} +    } + +  if (ok) +    mix_vm_set_addr_contents (dis->vm, mix_short_new (addr), +			      mix_word_new (value)); +  else +    { +      fprintf (dis->err, _("Invalid argument: %s\n"), arg); +      cmd_help_ (dis, "smem"); +    } +  g_free (arg); +   +  return ok; +} + +static gboolean +cmd_ssym_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  gboolean result = FALSE; +  if (arg == NULL || strlen(arg) == 0) +    { +      fprintf (dis->err, _("Missing arguments\n")); +      cmd_help_ (dis, "ssym"); +    } +  else +    { +      gchar *a = g_strdup (arg); +      gchar *s = strtok (a, " \t"); +      gchar *w = strtok (NULL, " \t"); +      if (w != NULL && strtok (NULL, " \t") == NULL) +	{ +	  cmd_weval_ (dis, w); +	  if (mix_eval_last_error (dis->eval) == MIX_EVAL_OK) { +	    mix_eval_set_symbol (dis->eval, s, mix_eval_value (dis->eval)); +	    result = TRUE; +	  } +	} +      else +	{ +	  fprintf (dis->err, _("Wrong argument number\n")); +	  cmd_help_ (dis, "ssym"); +	} +      g_free (a); +    } +  return result; +} + +static gboolean +cmd_sbp_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  glong lineno; +  glong k = 0; +  while (isdigit (arg[k])) k++; +  if (arg[k] != '\0') +    { +      fprintf (dis->err, _("Invalid argument: %s\n"), arg); +      cmd_help_ (dis, "sbp"); +      return FALSE; +    } +  lineno = atol (arg); +  switch (k = mix_vm_set_breakpoint (dis->vm, lineno)) +    { +    case MIX_VM_BP_INV_LINE: +      fprintf (dis->err, _("Line number %ld too high\n"), lineno); +      break; +    case MIX_VM_BP_ERROR: +      fputs (_("Could not set breakpoint. Internal error\n"), dis->err); +      break; +    case MIX_VM_BP_NDEBUG: +      fputs (_("Could not set breakpoint. No debug info available\n"), +	     dis->err); +      break; +    default: +      fprintf (dis->err, _("Breakpoint set at line %ld\n"), k); +      return TRUE; +    } +  return FALSE; +} + +static gboolean +cmd_sbpa_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  glong address; +  glong k = 0; +  while (isdigit (arg[k])) k++; +  if (arg[k] != '\0') +    { +      fprintf (dis->err, _("Invalid argument: %s\n"), arg); +      cmd_help_ (dis, "sbpa"); +      return FALSE; +    } +  address = atol (arg); +  switch (mix_vm_set_breakpoint_address (dis->vm, address)) +    { +    case MIX_VM_BP_INV_ADDRESS: +      fprintf (dis->err, _("Invalid address %ld\n"), address); +      break; +    case MIX_VM_BP_ERROR: +      fputs (_("Could not set breakpoint. Internal error\n"), dis->err); +      break; +    default: +      fprintf (dis->err, _("Breakpoint set at address %ld\n"), address); +      return TRUE; +    } +  return FALSE; +} + +static gboolean +cmd_cbp_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  glong lineno; +  int k = 0; +  while (isdigit (arg[k])) k++; +  if (arg[k] != '\0') +    { +      fprintf (dis->err, _("Invalid argument: %s\n"), arg); +      cmd_help_ (dis, "cbp"); +      return FALSE; +    } +  lineno = atol (arg); +  switch (mix_vm_clear_breakpoint (dis->vm, lineno)) +    { +    case MIX_VM_BP_INV_LINE: +      fprintf (dis->err, _("No breakpoint set at line %ld\n"), lineno); +      break; +    case MIX_VM_BP_ERROR: +      fputs (_("Could not set breakpoint. Internal error\n"), dis->err); +      break; +    case MIX_VM_BP_NDEBUG: +      fputs (_("No debug info available\n"), dis->err); +      break; +    case MIX_VM_BP_OK: +      fprintf (dis->err, _("Breakpoint cleared at line %ld\n"), lineno); +      return TRUE; +    default: +      g_assert_not_reached (); +      break; +    } +  return FALSE; +} + +static gboolean +cmd_cbpa_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  glong address; +  glong k = 0; +  while (isdigit (arg[k])) k++; +  if (arg[k] != '\0') +    { +      fprintf (dis->err, _("Invalid argument: %s\n"), arg); +      cmd_help_ (dis, "cbpa"); +      return FALSE; +    } +  address = atol (arg); +  switch (mix_vm_clear_breakpoint_address (dis->vm, address)) +    { +    case MIX_VM_BP_INV_ADDRESS: +      fprintf (dis->err, _("Invalid address %ld\n"), address); +      break; +    case MIX_VM_BP_ERROR: +      fputs (_("Could not clear breakpoint. Internal error\n"), dis->err); +      break; +    default: +      fprintf (dis->err, _("Breakpoint cleared at address %ld\n"), address); +      return TRUE; +    } +  return FALSE; +} + + +static gboolean +cmd_cabp_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  if (strlen (arg) != 0) +    { +      fprintf (dis->err, _("Invalid argument: %s\n"), arg); +      cmd_help_ (dis, "cabp"); +      return FALSE; +    } +  mix_vm_clear_all_breakpoints (dis->vm); +  return TRUE; +} + +static gboolean +cmd_weval_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  if ( strlen (arg) == 0 ) +    { +      cmd_help_ (dis, "weval"); +      return FALSE; +    } +   +  if (mix_eval_expression_with_loc (dis->eval, arg, +				    mix_vm_get_prog_count (dis->vm)) == +      MIX_EVAL_OK) +    { +      mix_word_print_to_file (mix_eval_value (dis->eval), NULL, dis->out); +      putc ('\n', dis->out); +      return TRUE; +    } +  else +    { +      gint pos = mix_eval_last_error_pos (dis->eval); +      gint k, len = strlen (arg); +      g_assert(pos > -1 && pos <= len); +      for (k = 0; k<pos; ++k) fputc (arg[k], dis->err); +      fputc ('\n', dis->err); +      for (k = 0; k<pos; ++k) fputc (' ', dis->err); +      for (k = pos; k < len; ++k) fputc (arg[k], dis->err); +      fprintf (dis->err, _("\nEvaluation error: %s\n"), +	       mix_eval_last_error_string (dis->eval)); +      return FALSE; +    } +} + +static gboolean +cmd_w2d_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  if ( strlen (arg) == 0 ) +    { +      cmd_help_ (dis, "w2d"); +      return FALSE; +    } +  else  +    { +      gchar *cp = g_strdup (arg), *a = cp; +      mix_byte_t bytes[5] = {0, 0, 0, 0, 0}; +      gchar *b; +      guint k = 0; +      gboolean is_n = (a[0] == '-'), success = TRUE; +      if (a[0] == '+' || a[0] == '-') ++a; +      b = strtok (a, " \t"); +      while (b != NULL && k < 5) +	{ +	  if (strlen (b) != 2 || !isdigit(b[0]) || !isdigit(b[1])) +	    { +	      fprintf (dis->err, _("Incorrect byte specification: %s\n"), b); +	      success = FALSE; +	      b = NULL; +	    } +	  else +	    { +	      bytes[k++] = mix_byte_new (atoi (b)); +	      b = strtok (NULL, " \t"); +	    } +	} +      if (success)  +	{ +	  if (strtok (NULL, "\t") != NULL) +	    { +	      fprintf (dis->err, +		       _("The expression %s does not fit in a word\n"), arg); +	      success = FALSE; +	    } +	  else +	    { +	      mix_word_t w = mix_bytes_to_word (bytes, k); +	      fprintf (dis->out, "%s%ld\n", is_n? "-":"+", +		       mix_word_magnitude (w)); +	    } +	} +      g_free (cp); +   +      return success; +    } +} + +static gboolean +cmd_tron_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  dis->trace = TRUE; +  fprintf (dis->out, _("Instruction tracing has been turned ON.\n")); +  return TRUE; +} + +static gboolean +cmd_troff_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ +  dis->trace = FALSE; +  fprintf (dis->out, _("Instruction tracing has been turned OFF.\n")); +  return TRUE; +} diff --git a/mixlib/mix_vm_command.h b/mixlib/mix_vm_command.h new file mode 100644 index 0000000..856c2d5 --- /dev/null +++ b/mixlib/mix_vm_command.h @@ -0,0 +1,160 @@ +/* -*-c-*- ---------------- mix_vm_command.h : + * declarations for mix_vm_command_t, describing commands issued to a vm + * ------------------------------------------------------------------ + *  Last change: Time-stamp: <01/03/15 15:57:36 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#ifndef MIX_VM_COMMAND_H +#define MIX_VM_COMMAND_H + +#include <stdio.h> +#include "mix.h" +#include "mix_vm.h" + +/* mix_vm_cmd_dispatcher encapsulates a virtual machine and helper +   objects, providing a command driven interface with output to +   provided files (in the posix sense). +*/ +typedef struct mix_vm_cmd_dispatcher_t mix_vm_cmd_dispatcher_t; + +/* mix_vm_cmd_dispatcher understands the commands of this type */ +typedef enum { +  MIX_CMD_HELP = 0,		/* echo help message */ +  MIX_CMD_LOAD,			/* load a mix program */ +  MIX_CMD_RUN,			/* run a loaded program */ +  MIX_CMD_NEXT,			/* run next instruction */ +  MIX_CMD_LOC,			/* print location pointer */ +  MIX_CMD_PSYM,			/* print symbol */ +  MIX_CMD_PREG,			/* print registry */ +  MIX_CMD_PFLAGS,		/* print comp and overf flags */ +  MIX_CMD_PALL,			/* print all registers and flags */ +  MIX_CMD_PMEM,			/* print memory cells */ +  MIX_CMD_SREG,			/* set register value */ +  MIX_CMD_SCMP,			/* set comparison flag value */ +  MIX_CMD_SOVER,		/* set overflow toggle value */ +  MIX_CMD_SMEM,			/* set memory cell value */ +  MIX_CMD_SSYM,			/* set symbol value */ +  MIX_CMD_SBP,			/* set breakpoint at lineno */ +  MIX_CMD_CBP,			/* clear breakpoint at lineno */ +  MIX_CMD_SBPA,			/* set breakpoint at address */ +  MIX_CMD_CBPA,			/* clear breakpoint at address */ +  MIX_CMD_CABP,			/* clear all breakpoints */ +  MIX_CMD_WEVAL,		/* evaluate a w-expression */ +  MIX_CMD_W2D,			/* print word in decimal notation */ +  MIX_CMD_TRON,			/* enable instruction traces */ +  MIX_CMD_TROFF,		/* disble instruction traces */ +  MIX_CMD_INVALID,		/* invalid command identifier */ +} mix_vm_command_t; + +/* hook functions, to be invoked before and/or after command execution */ +typedef void (*mix_vm_cmd_hook_t)(mix_vm_cmd_dispatcher_t *dis, +				  const gchar *arg, gpointer data); + +/* global hook functions */ +typedef void (*mix_vm_cmd_global_hook_t)(mix_vm_cmd_dispatcher_t *dis, +					 mix_vm_command_t cmd, +					 const gchar *arg, gpointer data); + +/* conversion from/to commands to strings */ +extern const gchar * +mix_vm_command_to_string (mix_vm_command_t cmd); + +extern mix_vm_command_t +mix_vm_command_from_string (const gchar *name); + +/* get help string about a command */ +extern const gchar * +mix_vm_command_help (mix_vm_command_t cmd); + +extern const gchar * +mix_vm_command_usage (mix_vm_command_t cmd); + + +/* create a new command dispatcher */ +extern mix_vm_cmd_dispatcher_t * +mix_vm_cmd_dispatcher_new (FILE *out_fd, /* output messages file */ +			   FILE *err_fd /* error messages file */); + +/* delete (does not close the fds in the constructor) */ +extern void +mix_vm_cmd_dispatcher_delete (mix_vm_cmd_dispatcher_t *dis); + +/* dispatch a command */ +extern gboolean /* TRUE if success, FALSE otherwise */ +mix_vm_cmd_dispatcher_dispatch (mix_vm_cmd_dispatcher_t *dis, +				mix_vm_command_t cmd, const gchar *arg); + +/* dispatch a command in text format */ +extern gboolean +mix_vm_cmd_dispatcher_dispatch_text (mix_vm_cmd_dispatcher_t *dis, +				     const gchar *text); + +/* get the last dispatch's result */ +extern gboolean +mix_vm_cmd_dispatcher_get_last_result (const mix_vm_cmd_dispatcher_t *dis); + +/* get total uptime */ +extern mix_time_t +mix_vm_cmd_dispatcher_get_uptime (const mix_vm_cmd_dispatcher_t *dis); + +/* get program total time */ +extern mix_time_t +mix_vm_cmd_dispatcher_get_progtime (const mix_vm_cmd_dispatcher_t *dis); + +/* get time lapse */ +extern mix_time_t +mix_vm_cmd_dispatcher_get_laptime (const mix_vm_cmd_dispatcher_t *dis); + +/* toggle time printing */ +extern void +mix_vm_cmd_dispatcher_print_time (mix_vm_cmd_dispatcher_t * dis, +				  gboolean print); + +/* install hooks */ +extern void +mix_vm_cmd_dispatcher_pre_hook (mix_vm_cmd_dispatcher_t *dis, +				mix_vm_command_t cmd, +				mix_vm_cmd_hook_t hook, gpointer data); + +extern void +mix_vm_cmd_dispatcher_post_hook (mix_vm_cmd_dispatcher_t *dis, +				 mix_vm_command_t cmd, +				 mix_vm_cmd_hook_t hook, gpointer data); + +extern void +mix_vm_cmd_dispatcher_global_pre_hook (mix_vm_cmd_dispatcher_t *dis, +				       mix_vm_cmd_global_hook_t hook, +				       gpointer data); + +extern void +mix_vm_cmd_dispatcher_global_post_hook (mix_vm_cmd_dispatcher_t *dis, +					mix_vm_cmd_global_hook_t hook, +					gpointer data); + + + +/* get the mix vm */ +extern const mix_vm_t * +mix_vm_cmd_dispatcher_get_vm (const mix_vm_cmd_dispatcher_t *dis); + + +#endif /* MIX_VM_COMMAND_H */ + diff --git a/mixlib/mix_vm_dump.c b/mixlib/mix_vm_dump.c new file mode 100644 index 0000000..91953fd --- /dev/null +++ b/mixlib/mix_vm_dump.c @@ -0,0 +1,147 @@ +/* ---------------------- mix_vm_dump.c : + * Implementation of the functions declared in mix_vm_dump.h + * ------------------------------------------------------------------ +** Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +**   +*/ + +#include "mix.h" +#include <unistd.h> +#include "xmix_vm.h" +#include "mix_vm_dump.h" + +/* Create/destroy a dump context */ +mix_dump_context_t * +mix_dump_context_new(FILE  *fd, mix_address_t begin, mix_address_t end, +		     guint32 options) +{ +  mix_dump_context_t *result = NULL; +   +  g_return_val_if_fail (fd != NULL, NULL); +   +  if ( begin > end ) begin = end; +  if ( end >= MEM_CELLS_NO_ ) end = MEM_CELLS_NO_; + +  result = g_new (mix_dump_context_t,1); +  result->options = options; +  result->begin = begin; +  result->end = end; +  result->channel = fd; +   +  return result; +} + +void +mix_dump_context_delete (mix_dump_context_t *dc) +{ +  g_return_if_fail (dc != NULL); +  g_free (dc); +} + +/* Use the dump context */ +#define WORD_FMT_   "%s %02d %02d %02d %02d %02d (%010ld)" +#define SHORT_FMT_  "%s %02d %02d (%04d)" +#define WORD_SIGN_(w)  mix_word_is_negative (w)? "-":"+" +#define SHORT_SIGN_(s) mix_short_is_negative (s)? "-":"+"  +#define WORD_ABS_(w)   mix_word_magnitude (w) +#define SHORT_ABS_(s)  mix_short_magnitude (s) +#define WORD_BYTE_(w,i) mix_byte_new (mix_word_magnitude (w)>>(6*(5-i))) +#define SHORT_BYTE_(s,i) mix_byte_new (mix_short_magnitude (s)>>(6*(2-i))) +#define WORD_ARGS_(w)  WORD_SIGN_ (w), WORD_BYTE_ (w,1), WORD_BYTE_ (w,2), \ +	   WORD_BYTE_ (w,3), WORD_BYTE_ (w,4), WORD_BYTE_ (w,5), WORD_ABS_ (w) +#define SHORT_ARGS_(s) SHORT_SIGN_ (s), SHORT_BYTE_ (s,1), SHORT_BYTE_ (s,2), \ +		       SHORT_ABS_ (s) + +void +mix_vm_dump (const mix_vm_t *vm, const mix_dump_context_t *dc) +{ +  guint j, i; +  FILE *f; +   +  g_return_if_fail (vm != NULL); +  g_return_if_fail (dc != NULL); +   +  f = dc->channel; +   +  if ( (dc->options & MIX_DUMP_rA) == MIX_DUMP_rA )  +    { +      mix_word_t rA = get_rA_ (vm); +      fprintf (f, "rA: " WORD_FMT_ "\n", WORD_ARGS_ (rA)); +    } + +  if ( (dc->options & MIX_DUMP_rX) == MIX_DUMP_rX )  +    { +      mix_word_t rX = get_rX_ (vm); +      fprintf (f, "rX: " WORD_FMT_ "\n", WORD_ARGS_ (rX)); +    } + +  if ( (dc->options & MIX_DUMP_rJ) == MIX_DUMP_rJ )  +    { +      mix_short_t rJ = get_rJ_ (vm); +      fprintf (f, "rJ: " SHORT_FMT_ "\n", SHORT_ARGS_ (rJ)); +    } +   +  for (j = 0, i = 0; j < IREG_NO_; ++j)  +    { +      if ( (dc->options & (MIX_DUMP_rI1<<j)) == (MIX_DUMP_rI1<<j) )  +	{ +	  mix_short_t rI = mix_word_to_short_fast (get_rI_ (vm, j+1)); +	  fprintf (f, "rI%d: " SHORT_FMT_ "\t", j+1, SHORT_ARGS_ (rI)); +	  i++; +	} +      if ( i%2 == 0 && i != 0 )	fprintf (f, "\n"); +    } + +  if ( i%2 == 1 ) fprintf (f, "\n"); +   +  if ( (dc->options & MIX_DUMP_OVER) == MIX_DUMP_OVER )  +    { +      fprintf (f, _("Overflow: %s\n"), get_over_ (vm)? "T":"F"); +    } +   +  if ( (dc->options & MIX_DUMP_CMP) == MIX_DUMP_CMP )  +    { +      const gchar *val = "?"; +      switch (get_cmp_ (vm))  +	{ +	case mix_LESS: +	  val = "L"; +	  break; +	case mix_GREAT: +	  val = "G"; +	  break; +	case mix_EQ: +	  val = "E"; +	  break; +	default: +	  g_assert_not_reached (); +	  break; +	} +      fprintf (f, _("Cmp: %s\n"), val); +    } +   +  if ( (dc->options & MIX_DUMP_CELLS) == MIX_DUMP_CELLS )  +    { +      for (j = dc->begin; j < dc->end; ++j)  +	{ +	  mix_word_t cell = get_cell_ (vm,j); +	  fprintf (f, "%04d: " WORD_FMT_ "\n", j, WORD_ARGS_ (cell)); +	} +    } +  fflush (f); +} + diff --git a/mixlib/mix_vm_dump.h b/mixlib/mix_vm_dump.h new file mode 100644 index 0000000..8c5e1bd --- /dev/null +++ b/mixlib/mix_vm_dump.h @@ -0,0 +1,91 @@ +/* ---------------------- mix_vm_dump.h : + * This file declares types and functions for dumping the contents + * of a mix virtual machine. + * ------------------------------------------------------------------ +** Copyright (C) 2000, 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +**   +*/ + + +#ifndef MIX_VM_DUMP_H +#define MIX_VM_DUMP_H + +#include <stdio.h> +#include "mix_vm.h" + +/* Dump context: a structure defining the properties of dumping */ +typedef struct mix_dump_context_t mix_dump_context_t; +struct mix_dump_context_t  +{ +  /* flags activating dumps (see enum below) */ +  guint32 options; +  /* range of addresses dumped: [begin,end) */ +  mix_address_t begin; +  mix_address_t end; +  /* IO channel for dumping */ +  FILE *channel; +}; + +/* Flags for activating dumps */ +#define MIX_DUMP_NONE 0 +#define MIX_DUMP_rA  1 +#define MIX_DUMP_rX  (1<<1) +#define MIX_DUMP_rJ  (1<<2) +#define MIX_DUMP_rI1 (1<<3) +#define MIX_DUMP_rI2 (1<<4) +#define MIX_DUMP_rI3 (1<<5) +#define MIX_DUMP_rI4 (1<<6) +#define MIX_DUMP_rI5 (1<<7) +#define MIX_DUMP_rI6 (1<<8) +#define MIX_DUMP_rIa MIX_DUMP_rI1|MIX_DUMP_rI2|MIX_DUMP_rI3  \ +		      |MIX_DUMP_rI4|MIX_DUMP_rI5|MIX_DUMP_rI6  +#define MIX_DUMP_rALL MIX_DUMP_rA|MIX_DUMP_rX|MIX_DUMP_rJ|MIX_DUMP_rIa +#define MIX_DUMP_OVER (1<<9) +#define MIX_DUMP_CMP  (1<<10) +#define MIX_DUMP_CELLS (1<<11) +#define MIX_DUMP_ALL  MIX_DUMP_rALL|MIX_DUMP_OVER|MIX_DUMP_CMP|MIX_DUMP_CELLS +#define MIX_DUMP_ALL_NOMEM MIX_DUMP_rALL|MIX_DUMP_OVER|MIX_DUMP_CMP + +/* Default output channel (stdout) */ +#define MIX_DUMP_DEF_CHANNEL (stdout) + +/* Create/destroy a dump context */ +extern mix_dump_context_t * +mix_dump_context_new (FILE *fd, mix_address_t begin, mix_address_t end, +		      guint32 options); + +extern void +mix_dump_context_delete(mix_dump_context_t *dc); + +/* Modify an existing dump context */ +#define mix_dump_context_add_opt(dc,opt) ((dc)->options |= (opt)) +#define mix_dump_context_del_opt(dc,opt) ((dc)->options &= ~(opt)) +#define mix_dump_context_set_opt(dc,opt) ((dc)->options = (opt)) +#define mix_dump_context_range(dc,first,last) 	\ +do {						\ +  (dc)->begin = first;				\ +  (dc)->end = last;				\ +} while (FALSE) + + +/* Use the dump context */ +extern void +mix_vm_dump(const mix_vm_t *vm, const mix_dump_context_t *dc); + +   +#endif /* MIX_VM_DUMP_H */ + diff --git a/mixlib/testsuite/.cvsignore b/mixlib/testsuite/.cvsignore new file mode 100644 index 0000000..c936d6c --- /dev/null +++ b/mixlib/testsuite/.cvsignore @@ -0,0 +1,28 @@ +.deps +Makefile +Makefile.in +cardwr.dev +disk0.dev +disk1.dev +disk2.dev +disk3.dev +disk4.dev +disk5.dev +disk6.dev +disk7.dev +mixdevtest +mixevaltest +mixinstest +mixparsertest +mixtypest +mixvminstest +paper.dev +printer.dev +tape0.dev +tape1.dev +tape2.dev +tape3.dev +tape4.dev +tape5.dev +tape6.dev +tape7.dev diff --git a/mixlib/testsuite/Makefile.am b/mixlib/testsuite/Makefile.am new file mode 100644 index 0000000..6e771c4 --- /dev/null +++ b/mixlib/testsuite/Makefile.am @@ -0,0 +1,28 @@ +# Copyright (C) 1999 Free Software Foundation, Inc. +#   +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without  +# modifications, as long as this notice is preserved. +#  +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +INCLUDES = -I..  +LDADD = $(top_builddir)/mixlib/libmix.a  + +check_PROGRAMS = mixtypest mixinstest mixvminstest mixparsertest mixdevtest mixevaltest +TESTS = $(check_PROGRAMS) + +mixtypest_SOURCES = test.h mix_types_t.c +mixinstest_SOURCES = test.h mix_ins_t.c +mixvminstest_SOURCES = test.h mix_vm_ins_t.c +mixparsertest_SOURCES = test.h mix_parser_t.c +mixdevtest_SOURCES = test.h mix_device_t.c +mixevaltest_SOURCES = test.h mix_eval_t.c + + + + + + diff --git a/mixlib/testsuite/mix_device_t.c b/mixlib/testsuite/mix_device_t.c new file mode 100644 index 0000000..da4c8f9 --- /dev/null +++ b/mixlib/testsuite/mix_device_t.c @@ -0,0 +1,76 @@ +/* -*-c-*- -------------- mix_device_t.c : + * Implementation of the functions declared in mix_device_t.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + +#include <stdlib.h> +#include <mix_device.h> + +/* Define VERBOSE_TEST if you want to get prints of the test */ +/* #define VERBOSE_TEST */ +#include "test.h" + +static int S_ = MIX_CHAR_MAX +1; + +int  +main (int argc, char **argv)  +{ +  mix_device_t *console; +  size_t s; +  mix_word_t **block; +  mix_char_t mchars[S_]; +  gchar chars[S_]; +  int i, j; +  int bno; +   +   +  INIT_TEST; +   +  console = mix_device_new (mix_dev_CONSOLE); +  s = mix_device_block_size (console); +  bno = S_/(s*5); +  if (bno == 0) bno = 1; +   +  block = g_new (mix_word_t *, bno); +  for (i = 0; i < bno; ++i) +    block[i] = g_new (mix_word_t, s); +   +  for (i = 0; i < S_; ++i) { +    chars[i] = mix_char_to_ascii (i); +    mchars[i] = mix_ascii_to_char (chars[i]); +    g_assert (mchars[i] == i); +  } +   +  for (i = 0; i < bno; ++i) { +    for (j = 0; j < s; ++j) { +      int n = i*s + 5*j; +      if (n < S_)  +	block[i][j] = mix_bytes_to_word (mchars + n, 5); +      else +	block[i][j] = 0; +    } +  } +    +  for (i = 0; i < bno; ++i) { +    mix_device_write (console, block[i]); +  } +   +   +  return EXIT_SUCCESS; +} diff --git a/mixlib/testsuite/mix_eval_t.c b/mixlib/testsuite/mix_eval_t.c new file mode 100644 index 0000000..83f9a5d --- /dev/null +++ b/mixlib/testsuite/mix_eval_t.c @@ -0,0 +1,119 @@ +/* -*-c-*- -------------- mix_eval_t.c : + * Test of mix_eval_t + * ------------------------------------------------------------------ + *  Last change: Time-stamp: "01/02/20 00:26:15 jose" + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#include <stdlib.h> +#include <mix_eval.h> +/* Define VERBOSE_TEST if you want to get prints of the test */ +/* #define VERBOSE_TEST */ +#include "test.h" + +typedef struct test_case_t +{ +  const gchar *expr; +  gint value; +  mix_eval_result_t result; +} test_case_t; + +#define ok_case(exp,val) {exp, val, MIX_EVAL_OK} +#define err_case(exp,err) {exp, 0, err} + +typedef struct sym_val_t +{ +  const gchar *sym; +  mix_word_t value; +} sym_val_t; + +#define new_symbol(sym,val) {sym, mix_word_new (val)} + +int  +main(int argc, char **argv) +{ +  size_t k; +  mix_eval_t *eval; +  mix_short_t loc = mix_short_new (30); +  sym_val_t symbols[] = { +    new_symbol ("s0", 43), +    new_symbol ("s1", -1234), +    new_symbol ("s2", 0), +    new_symbol ("s3", -20), +    new_symbol (NULL, 0) +  }; +   +  test_case_t cases[] = { +    ok_case ("2343", 2343), +    ok_case ("-890", -890), +    ok_case ("15+1015", 1030), +    ok_case ("1-481", -480), +    ok_case ("2300/10", 230), +    ok_case ("24*3", 72), +    ok_case ("2:5", 21), +    ok_case ("1//3", 357913941), +    ok_case ("12+*", 42), +    ok_case ("***", 900), +    ok_case ("1:3*2-4", 18), +    ok_case ("-1+5*20/6", 13), +    ok_case ("-1000(0,2),1", 1), +    ok_case ("s0-s2*3", 129), +    ok_case ("s3**", -600), +    ok_case ("s3(3:5)", 20), +    ok_case ("-s1", 1234), +    ok_case ("s1/10+s0", 166), +    err_case ("foo", MIX_EVAL_UNDEF_SYM), +    err_case ("11--2", MIX_EVAL_SYNTAX), +    err_case ("s2*foo*3", MIX_EVAL_UNDEF_SYM), +    err_case ("12/32),1", MIX_EVAL_MIS_PAREN), +    err_case ("2000(88)", MIX_EVAL_INV_FSPEC), +    ok_case (NULL, 0) +  }; +   +  INIT_TEST; +  g_print ("Entering mix_eval test..."); +  eval = mix_eval_new (); + +  for (k = 0; symbols[k].sym; ++k) +    mix_eval_set_symbol (eval, symbols[k].sym, symbols[k].value); +   +  for (k = 0; cases[k].expr; ++k) { +    mix_eval_result_t r = cases[k].result, s; +    g_print ("Evaluating \"%s\" = %d ...", +	       cases[k].expr, cases[k].value); +     +    s = mix_eval_expression_with_loc (eval, cases[k].expr, loc); +    g_assert (s == r); +    if ( s == MIX_EVAL_OK ) { +      mix_word_print (mix_eval_value (eval), "... "); +      g_print ("\n"); +      g_assert (mix_eval_value (eval) == mix_word_new(cases[k].value)); +    } else { +      g_print ("\n------->%s, at pos %d\n", +	       mix_eval_last_error_string (eval), +	       mix_eval_last_error_pos (eval)); +    } +  } +  mix_eval_delete (eval); + +  return EXIT_SUCCESS; +} + + diff --git a/mixlib/testsuite/mix_ins_t.c b/mixlib/testsuite/mix_ins_t.c new file mode 100644 index 0000000..f643b47 --- /dev/null +++ b/mixlib/testsuite/mix_ins_t.c @@ -0,0 +1,79 @@ +/*----------------------- mix_ins_t.c ------------------------------- + * Tests for mix_ins.h + *------------------------------------------------------------------- +** Copyright (C) 1999  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +**   +*/ + +#include <stdlib.h> +#include <mix_ins.h> + +/* Define VERBOSE_TEST if you want to get prints of the test */ +/* #define VERBOSE_TEST */ +#include "test.h" + + +int +main(int argc, const char**argv) +{ +  mix_word_t words[6]; +  mix_ins_t ins[3]; +  guint k; +   +  INIT_TEST; +   +  g_print("\n...ok.\nTesting mix_ins_id_t properties...\n"); +  for ( k = 0; k < mix_INVALID_INS; ++k ) +    { +      mix_opcode_t c = mix_get_opcode_from_id(k); +      mix_fspec_t f = mix_get_fspec_from_id(k); +      mix_ins_id_t id = mix_get_ins_id(c,f); +       +      g_print("%02d:%s (%1d:%1d),  ", +	      c, mix_get_string_from_id(k),  +	      mix_fspec_left(f), mix_fspec_right(f)); +      if ( (k+1)%3 == 0 ) g_print("\n"); + +      g_assert(id==k); +    } +   +  g_print("\n...ok.\nTesting mix_ins_t properties...\n"); +  for ( k = 1; k < mix_INVALID_INS; ++k ) +    { +      g_print("%d ",k); +      mix_ins_fill_from_id(ins[0], k); +      g_assert(mix_ins_id_from_ins(ins[0]) == k); +      ins[0].address = 0x0123; +      ins[0].index = mix_I2; +      words[2] = mix_ins_to_word(ins); +      g_assert(ins[0].address == mix_get_ins_address(words[2])); +      g_assert(ins[0].index == mix_get_ins_index(words[2])); +      g_assert(ins[0].fspec == mix_get_ins_fspec(words[2])); +      g_assert(ins[0].opcode == mix_get_ins_opcode(words[2])); +      g_assert(mix_word_to_ins(words[2],ins+1) == k); +      g_assert(ins[0].address == ins[1].address); +      g_assert(ins[0].index == ins[1].index); +      g_assert(ins[0].fspec == ins[1].fspec); +      g_assert(ins[0].opcode == ins[1].opcode); +    } +   +  g_print("\n...ok.\n"); +   +   +   +  return EXIT_SUCCESS; +} diff --git a/mixlib/testsuite/mix_parser_t.c b/mixlib/testsuite/mix_parser_t.c new file mode 100644 index 0000000..7bfa9d0 --- /dev/null +++ b/mixlib/testsuite/mix_parser_t.c @@ -0,0 +1,85 @@ +/* -*-c-*- -------------- mix_parser_t.c : + * Test of mix_parser_t + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + + +#include <stdlib.h> +#include <mix_parser.h> + +/* Define VERBOSE_TEST if you want to get prints of the test */ +/* #define VERBOSE_TEST */ +#include "test.h" + +static const gchar * const FILES_[] = { "test1" , "taocp145" +}; + +static const size_t FILE_NO_ = sizeof(FILES_)/sizeof(FILES_[0]); + +static void +test_code_(const gchar *name) +{ +  mix_parser_t *parser = mix_parser_new(name); +  mix_parser_err_t err; +  mix_code_file_t *code; +  mix_ins_desc_t ins; +   +  g_assert(parser); +  err =  mix_parser_compile(parser); +  if ( err != MIX_PERR_OK ) { +    g_print(mix_parser_err_string(err)); +    g_print("\n"); +  }    +  g_assert(err == MIX_PERR_OK); +  err = mix_parser_write_code(parser, name, FALSE); +  code = mix_code_file_new_read(name); +  g_assert(code); +  g_message("%s: Version: %d.%d", name, mix_code_file_major_version(code), +	    mix_code_file_minor_version(code)); +  mix_short_print(mix_code_file_get_start_addr(code), "Start address: "); +  g_print("\n"); +  while ( mix_code_file_get_ins(code, &ins) ) { +    mix_ins_t i; +    mix_word_to_ins_uncheck(ins.ins, i); +    mix_short_print(ins.address, "addr: "); +    g_print(" : "); +    mix_ins_print(&i); +    g_print("\n"); +  } +   +  mix_parser_delete(parser); +  mix_code_file_delete(code); +} + +int  +main(int argc, char **argv) +{ +  size_t k; +   +  INIT_TEST; + +  for (k = 0; k < FILE_NO_; ++k) +    // test_code_(FILES_[k]); +    ; +     + +  return EXIT_SUCCESS; +} + diff --git a/mixlib/testsuite/mix_types_t.c b/mixlib/testsuite/mix_types_t.c new file mode 100644 index 0000000..be9fb46 --- /dev/null +++ b/mixlib/testsuite/mix_types_t.c @@ -0,0 +1,361 @@ +/*----------------------- mix_types_t.c ----------------------------- + * Tests for mix_types.h + * ------------------------------------------------------------------ +* +** Copyright (C) 1999 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +**   +*/ + + +#include <stdlib.h> +#include <mix_types.h> + +/* Define VERBOSE_TEST if you want to get prints of the test */ +/* #define VERBOSE_TEST */ +#include "test.h" + +/* compare two words */ +static gboolean +word_compare_(mix_word_t w1, mix_word_t w2) +{ +  if ( mix_word_magnitude(w1) == 0 ) +    return ( mix_word_magnitude(w2) == 0 ); +  else +    return ( w1 == w2 ); +} + +  +/* create a word from an array of bytes and check the result */ +static void +test_word_from_bytes_(mix_word_t *word,  +		     mix_byte_t *bytes,  +		     unsigned byteno, +		     const char *message) +{ +  mix_byte_t r; +  unsigned int k; +   +  *word = mix_bytes_to_word(bytes,byteno); +  mix_word_print(*word,message); +  g_print("\n"); +  for ( k = 5-byteno; k < 5; ++k ) { +    PRINT_BYTE(r = mix_word_get_byte(*word,k+1)); +    g_print(" (k = %d)\n",k); +    g_assert( r  == bytes[k-5+byteno] ); +  } +} + + +/* test field access */ +static void +test_field_access_(mix_fspec_t l, mix_fspec_t r,  +		   mix_word_t from, mix_word_t to) +{ +  mix_fspec_t f  = mix_fspec_new(l,r); +  mix_word_t result; +   +  PRINT_BYTE(l); g_print(", "); +  PRINT_BYTE(r); g_print(", "); +  PRINT_BYTE(f); g_print("\n  "); +  mix_word_print(from, "from: "); +  mix_word_print(to, " to: "); +  g_assert( mix_fspec_left(f) == l ); +  g_assert( mix_fspec_right(f) == r ); +  result = mix_word_set_field(f,from,to); +  mix_word_print(result,"\n\tresult: "); +  g_assert( mix_word_get_field(f,from) == mix_word_get_field(f,result) ); +  g_print("\n"); +} + +/* test word addition */ +static void +test_word_add_(mix_word_t w1, mix_word_t w2) +{ +  mix_word_t r; +   +  r = mix_word_add(w1,w2); +  mix_word_print(w1,"\n"); +  mix_word_print(w2,NULL); +  mix_word_print(r," = "); +  g_assert( word_compare_(mix_word_sub(r,w1), w2) ); +  g_assert( word_compare_(mix_word_sub(r,w2), w1) ); +  /* while asserting the following, take into account that 0 != -0 +     for mix words, although they are logically equivalent +  */ +  g_assert( word_compare_(mix_word_sub(w1,r), mix_word_negative(w2)) ); +  g_assert( word_compare_(mix_word_sub(w2,r), mix_word_negative(w1)) ); +  g_assert( word_compare_(mix_word_add(w2,w1), r) ); +} + +/* test word multiplication */ +static void +test_word_mul_(mix_word_t w1, mix_word_t w2) +{ +  mix_word_t h, l, q, r = 0; +  mix_word_mul(w1,w2,&h,&l); +  mix_word_print(w1,"\n"); +  mix_word_print(w2,"*"); +  mix_word_print(h,"\n  ="); +  mix_word_print(l,NULL); +  if ( w1 != 0 ) { +    g_assert( mix_word_div(h,l,w1,&q,&r) == FALSE ); +    g_assert( mix_word_magnitude(r) == 0 ); +    g_assert( q == w2 ); +  } else { +    g_assert( mix_word_magnitude(l) == 0 && mix_word_magnitude(h) == 0 ); +  } +  if ( w2 != 0 ) { +    g_assert( mix_word_div(h,l,w2,&q,&r) == FALSE ); +    g_assert( mix_word_magnitude(r) == 0 ); +    g_assert( q == w1 ); +  } else { +    g_assert( mix_word_magnitude(l) == 0 && mix_word_magnitude(h) == 0 ); +  } +   +} + +/* test word division */ +static void +test_word_div_(mix_word_t h, mix_word_t l, mix_word_t by)  +{ +  mix_word_t q,r; +  gboolean overflow; + +  overflow = mix_word_div(h,l,by,&q,&r); +  +  mix_word_print(h,"\n\n"); +  mix_word_print(l,NULL); +  mix_word_print(by,"\n div by "); + +  if ( !overflow ) { +    mix_word_t h1, l1, h2; +    mix_word_print(q,"\n q = "); +    mix_word_print(r,"  r = "); +    mix_word_mul(by,q,&h1,&l1); +    mix_word_add_and_carry(l1,r,&h2,&l1); +    h1 = mix_word_add(h1,h2); +    g_assert( mix_word_magnitude(r) < mix_word_magnitude(by) ); +    g_assert( word_compare_(h1,h) ); +    g_assert( mix_word_magnitude(l1) == mix_word_magnitude(l) ); +  } else +    g_print("\n\t = overflow"); +    +} + +static void +test_mix_char_(void) +{ +  mix_char_t mchar; +  guchar achar; +  guint k; +  g_print("\nTesting mix_char_t. Table of mix_chars:\n"); +   +  for (k = 0; k < MIX_CHAR_MAX + 1; ++k) { +    mchar = k; +    achar = mix_char_to_ascii(mchar); +    g_print("%02d: %c, ",k,achar); +    if ( (k+1)%5 == 0 ) g_print("\n"); +    g_assert( mchar == mix_ascii_to_char(achar) ); +  } +  g_print("\n"); +} + + +/* main test driver for mix_types.h/c */ + +int main(int argc, char **argv) +{ +  unsigned int j,k; +  mix_byte_t bytes[5] = { 0, 3, 20, 30, 40 }; +  mix_byte_t r; +  mix_short_t ss[6]; +  mix_word_t words[6]; +   +  INIT_TEST; +   +  g_print("Testing mix_byte_t arithmetics...\n"); +  PRINT_BYTE(bytes[0]);  g_print(", "); +  PRINT_BYTE(bytes[1]);  g_print(", "); +  PRINT_BYTE(bytes[2]);  g_print(", "); +  PRINT_BYTE(bytes[3]);  g_print(", "); +  PRINT_BYTE(bytes[4]);  g_print("\n"); +  PRINT_BYTE(r = mix_byte_add(bytes[1],bytes[2])); +  g_print("\n"); g_assert(r == 23); +  PRINT_BYTE(r = mix_byte_add(bytes[3],bytes[4])); +  g_print("\n"); g_assert(r == 6); +  PRINT_BYTE(r = mix_byte_sub(bytes[0],bytes[1])); +  g_print("\n"); g_assert(r == 61); +  PRINT_BYTE(r = mix_byte_sub(bytes[4],bytes[3])); +  g_print("\n"); g_assert(r == 10); +  PRINT_BYTE(r = mix_byte_sub(bytes[1],bytes[4])); +  g_print("\n"); g_assert(r == 27); +  PRINT_BYTE(r = mix_byte_mul(bytes[0],bytes[1])); +  g_print("\n"); g_assert(r == 0); +  PRINT_BYTE(r = mix_byte_mul(bytes[1],bytes[2])); +  g_print("\n"); g_assert(r == 60); +  PRINT_BYTE(r = mix_byte_mul(bytes[1],bytes[4])); +  g_print("\n"); g_assert(r == 56); +  PRINT_BYTE(r = mix_byte_mul(bytes[4],bytes[1])); +  g_print("\n"); g_assert(r == 56); +  PRINT_BYTE(r = mix_byte_div(bytes[4],bytes[2])); +  g_print("\n"); g_assert(r == 2);  +  PRINT_BYTE(r = mix_byte_div(bytes[3],bytes[2])); +  g_print("\n"); g_assert(r == 1); + +  test_mix_char_(); + +  g_print("\nTesting word<->short conversions..."); +  words[0] = mix_bytes_to_word(bytes+1,5);  +  words[1] = mix_word_negative(words[0]); +  ss[0] = mix_word_to_short(words[0]); +  ss[1] = mix_word_to_short(words[1]); +  mix_word_print(words[0],"\nwords[0]="); +  mix_word_print(words[1],"\nwords[1]="); +  mix_short_print(ss[0],"\nss[0]="); +  mix_short_print(ss[1],"\nss[1]="); +  g_assert(mix_short_is_positive(ss[0])); +  g_assert(mix_short_is_negative(ss[1])); +  words[2] = mix_short_to_word(ss[0]); +  words[3] = mix_short_to_word(ss[1]); +  mix_word_print(words[2],"\nwords[2]="); +  mix_word_print(words[3],"\nwords[3]="); +  g_assert(mix_word_sign(words[0]) == mix_word_sign(words[2])); +  g_assert(mix_word_sign(words[1]) == mix_word_sign(words[3])); +  g_assert(mix_short_magnitude(ss[0]) == mix_word_magnitude(words[2])); +  g_assert(mix_short_magnitude(ss[1]) == mix_word_magnitude(words[3])); +  g_assert(mix_word_get_byte(words[0],4) == mix_word_get_byte(words[2],4)); +  g_assert(mix_word_get_byte(words[0],5) == mix_word_get_byte(words[2],5)); +  g_assert(mix_word_get_byte(words[1],4) == mix_word_get_byte(words[3],4)); +  g_assert(mix_word_get_byte(words[1],5) == mix_word_get_byte(words[3],5)); +  words[4] = mix_word_extract_field(mix_fspec_new(4,5),words[0]); +  words[5] = mix_word_extract_field(mix_fspec_new(4,5),words[1]); +  mix_word_reverse_sign(words[5]); +  g_assert(words[4] == words[2]); +  g_assert(words[5] == words[3]); +    +  g_print("Testing mix_word_t creation and byte access...\n"); +  test_word_from_bytes_(words,bytes,5,"word[0] created from bytes[0-4]"); +  test_word_from_bytes_(words+1,bytes,4,"\nword[1] created from bytes[0-3]"); +  test_word_from_bytes_(words+2,bytes,3,"\nword[2] created from bytes[0-2]"); +  words[3] = mix_word_negative(words[2]); +  g_assert( mix_word_negative(words[3]) == words[2] ); +  g_assert( mix_word_is_negative(words[3]) && !mix_word_is_negative(words[2])); +  mix_word_print(words[3],"\nword[3] created from -word[2]"); +  test_word_from_bytes_(words+4,bytes+2,2,"\nword[2] created from bytes[2-3]"); + +  g_print("\nTesting mix_word_t field access...\n"); +  mix_word_set_byte(words+3,1,12); +  mix_word_set_byte(words+3,2,58); +  g_assert( mix_word_get_byte(words[3],1) == 12 ); +  g_assert( mix_word_get_byte(words[3],2) == 58 ); +  test_field_access_(0,5,words[3],words[4]); +  test_field_access_(1,5,words[3],words[4]); +  test_field_access_(2,5,words[3],words[4]); +  test_field_access_(3,5,words[3],words[4]); +  test_field_access_(4,5,words[3],words[4]); +  test_field_access_(5,5,words[3],words[4]); +  test_field_access_(0,0,words[3],words[4]); + +  g_print("\n\nTesting mix_word_t arithmetics...\n"); +  words[0] = MIX_WORD_MAX; +  words[1] = mix_word_negative(words[0]); +  for ( k = 1; k < 6; ++k ) { +    mix_word_set_byte(words+2,k,5*k); +    mix_word_set_byte(words+4,k,10*(5-k)); +    mix_word_set_byte(words+3,k,21 + 3*k); +  } +  words[5] = 0; +   +  g_print("\n***addition***"); +  for ( k = 0; k < 6; ++k ) +    for ( j = 0; j <= k; ++j ) { +      test_word_add_(words[k],mix_word_negative(words[j])); +      test_word_add_(words[k],words[j]); +    } +  g_print("\n***product***"); +  for ( k = 0; k < 6; ++k ) +    for ( j = 0; j <= k; ++j ) { +      test_word_mul_(words[k],words[j]); +    } +  g_print("\n***division***"); +  for ( k = 0; k < 6; ++k ) { +    test_word_div_(words[k],0,words[0]); +    for ( j = 0; j <= k; ++j ) { +      test_word_div_(k,words[j],words[j]); +      test_word_div_(0,mix_word_add(mix_word_magnitude(words[j]),j),words[j]); +      test_word_div_(mix_word_negative(k),words[j],words[j]); +    } +  } + +  g_print("\nTesting shift operations...\n"); +  for ( k = 0; k < 10; ++k )  +    mix_word_set_byte(words+(k/5),1+(k%5),k+1); +    +  mix_word_print(words[0],"A = "); +  mix_word_print(words[1],"X = "); +  for ( k = 0; k < 11; ++k ) { +    mix_word_t A, X; +    unsigned int m; +     +    mix_word_shift_left(words[0],words[1],k,&A,&X); +    g_print("\nShift left %d:\n",k); +    mix_word_print(A,"A "); +    mix_word_print(X,"X "); +    for ( m = 0; m < 10 - k; ++m ) +      g_assert( mix_word_get_byte( m < 5 ? A:X, (m%5)+1 ) == +	      mix_word_get_byte(words[(m+k)/5], ((m+k)%5)+1) ); +    for ( ; m < 10; ++m ) +      g_assert( mix_word_get_byte( m < 5 ? A:X, (m%5)+1 ) == 0 ); +     +    mix_word_shift_right(words[0],words[1],k,&A,&X); +    g_print("\nShift right %d:\n",k); +    mix_word_print(A,"A "); +    mix_word_print(X,"X "); +    for ( m = 0; m < k; ++m ) +      g_assert( mix_word_get_byte( m < 5 ? A:X, (m%5)+1 ) == 0 ); +    for ( ; m < 10; ++m ) +      g_assert( mix_word_get_byte( m < 5 ? A:X, (m%5)+1 ) == +	      mix_word_get_byte(words[(m-k)/5], ((m-k)%5)+1) ); +     +    mix_word_shift_left_circular(words[0],words[1],k,&A,&X); +    g_print("\nShift left circular %d:\n",k); +    mix_word_print(A,"A "); +    mix_word_print(X,"X "); +    for ( m = 0; m < 10 - k; ++m ) +      g_assert( mix_word_get_byte( m < 5 ? A:X, (m%5)+1 ) == +	      mix_word_get_byte(words[(m+k)/5], ((m+k)%5)+1) ); +    for ( ; m < 10; ++m ) +      g_assert( mix_word_get_byte( m < 5 ? A:X, (m%5)+1 ) ==  +	      mix_word_get_byte(words[(m-10+k)/5], 1+((m-10+k)%5)) ); +    mix_word_shift_right_circular(A, X, k, &A, &X); +    g_print("\nRe-shiftting right...\n"); +    mix_word_print(A, "A "); +    mix_word_print(X, "X "); +    g_assert(A == words[0]); +    g_assert(X == words[1]); +  } +   +   +  g_print("\n"); +  return EXIT_SUCCESS; +} + +   + + + + diff --git a/mixlib/testsuite/mix_vm_ins_t.c b/mixlib/testsuite/mix_vm_ins_t.c new file mode 100644 index 0000000..55ce7f3 --- /dev/null +++ b/mixlib/testsuite/mix_vm_ins_t.c @@ -0,0 +1,500 @@ +/* ---------------------- mix_vm_ins_t.c : + * Tests for the virtual machine instruction handlers. + * ------------------------------------------------------------------ +** Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +**   +*/ + + +#include <stdlib.h> +/*#define VERBOSE_TEST*/ +#include "test.h" +#include "mix_vm.h" +#include "mix_vm_dump.h" + +typedef struct  +{ +  mix_word_t rA_b, rA_a; +  mix_word_t rX_b, rX_a; +  mix_short_t rJ_b, rJ_a; +  mix_short_t rI_b[6], rI_a[6]; +  gboolean over_b, over_a; +  mix_cmpflag_t cmp_b, cmp_a; +  mix_address_t begin, end; +  mix_word_t  *cells_b, *cells_a; +  const mix_ins_t *ins; +} test_desc_t; + +static void +set_cells_(test_desc_t *t, mix_address_t begin, mix_address_t end) +{ +  g_assert(begin <= end); +  t->begin = begin; +  t->end = end; +  t->cells_b = g_new(mix_word_t,end-begin); +  t->cells_a = g_new(mix_word_t,end-begin); +} + +static void  +free_cells_(test_desc_t *t) +{ +  g_assert(t); +  g_free(t->cells_a); +  g_free(t->cells_b); +  t->cells_a = t->cells_b = NULL; +  t->begin = t->end = 0; +} + + +static void +fill_test_desc_(test_desc_t *t, const mix_vm_t *vm, const mix_ins_t *ins) +{ +  guint k; +  g_assert(t); +  g_assert(vm); +   +  t->rA_b = t->rA_a = mix_vm_get_rA(vm); +  t->rX_b = t->rX_a = mix_vm_get_rX(vm); +  t->rJ_b = t->rJ_a = mix_vm_get_rJ(vm); +  for ( k = 0; k < 6; ++k ) +    t->rI_b[k] = t->rI_a[k] = mix_vm_get_rI(vm,k+1); +  t->cmp_b = t->cmp_a = mix_vm_get_cmpflag(vm); +  t->over_b = t->over_a = mix_vm_get_overflow(vm); +   +  for (k = 0; k < t->end-t->begin; ++k) +    t->cells_a[k] = t->cells_b[k] =  +      mix_vm_get_addr_contents(vm,t->begin+k); +  t->ins = ins; +} + + +static void +run_test_(test_desc_t *t, mix_vm_t *vm, mix_dump_context_t *dc) +{ +  guint k; +  g_assert(t); +  g_assert(vm); +     +  mix_vm_set_rA(vm, t->rA_b); +  mix_vm_set_rX(vm, t->rX_b); +  mix_vm_set_rJ(vm, t->rJ_b); +  for (k = 0; k < 6; ++k) mix_vm_set_rI(vm, k+1, t->rI_b[k]); +  for (k = t->begin; k < t->end; ++k) +    mix_vm_set_addr_contents(vm, k, t->cells_b[k-t->begin]); +  mix_vm_set_cmpflag(vm, t->cmp_b); +  mix_vm_set_overflow(vm, t->over_b); + +  mix_ins_print(t->ins); +  if (dc) { +    mix_dump_context_range(dc, t->begin, t->end); +    mix_vm_dump(vm,dc); +  } +  k = mix_vm_exec_ins(vm, t->ins); +  if (dc) mix_vm_dump(vm, dc); +  g_assert(k == TRUE); +  g_assert(mix_vm_get_rA(vm) == t->rA_a); +  g_assert(mix_vm_get_rX(vm) == t->rX_a); +  for (k = 0; k < 6; ++k) g_assert(mix_vm_get_rI(vm, k+1) == t->rI_a[k]); +  g_assert(mix_vm_get_cmpflag(vm) == t->cmp_a); +  g_assert(mix_vm_get_overflow(vm) == t->over_a); +  for (k = t->begin; k < t->end; ++k) +    g_assert(mix_vm_get_addr_contents(vm, k) == t->cells_a[k-t->begin]); +} + +   + +static void +test_arithmetics_(mix_vm_t *vm, mix_dump_context_t *dc) +{ +  test_desc_t test; +  mix_ins_t ins; + +  g_print("\nTesting arithmetic instructions...\n"); +  mix_vm_reset(vm); +  mix_ins_fill_from_id(ins,mix_ADD); +  ins.index = 0; +  ins.address = 1000; +  mix_vm_set_rA(vm,mix_word_new_b(19,18,1,2,22)); +  mix_vm_set_addr_contents(vm,1000,mix_word_new_b(1,36,5,0,50)); +  set_cells_(&test,1000,1001); +  fill_test_desc_(&test,vm,&ins); +  test.rA_a = mix_word_new_b(20,54,6,3,8); +  run_test_(&test, vm, dc); + +  mix_ins_fill_from_id(ins,mix_SUB); +  mix_vm_set_rA(vm,mix_word_new_bn(19,18,0,0,9)); +  mix_vm_set_addr_contents(vm,1000,mix_word_new_bn(31,16,2,22,0)); +  fill_test_desc_(&test,vm,&ins); +  test.rA_a = mix_word_new_b(11,62,2,21,55); +  run_test_(&test, vm, dc); + +  mix_ins_fill_from_id(ins,mix_MUL); +  mix_vm_set_rA(vm,mix_word_new_b(1,1,1,1,1)); +  mix_vm_set_addr_contents(vm,1000, mix_word_new_b(1,1,1,1,1)); +  fill_test_desc_(&test,vm,&ins); +  test.rA_a = mix_word_new_b(0,1,2,3,4); +  test.rX_a = mix_word_new_b(5,4,3,2,1); +  run_test_(&test, vm, dc); + +  ins.fspec = mix_fspec_new(1,1); +  mix_vm_set_rA(vm,mix_word_new_bn(0,0,0,1,48)); +  mix_vm_set_addr_contents(vm,1000,mix_word_new_bn(2,16,2,22,0)); +  fill_test_desc_(&test,vm,&ins); +  test.rA_a = MIX_WORD_MINUS_ZERO; +  test.rX_a = mix_word_new_bn(0,0,0,3,32); +  run_test_(&test, vm, dc); + +  mix_vm_set_rA(vm,mix_word_new_bn(0,0,0,1,48)); +  mix_vm_set_addr_contents(vm,1000,mix_word_new_b(2,0,34,33,1)); +  fill_test_desc_(&test,vm,&ins); +  test.rA_a = MIX_WORD_MINUS_ZERO; +  test.rX_a = mix_word_new_bn(0,0,0,3,32); +  run_test_(&test, vm, dc); + +  ins.fspec = mix_fspec_new(0,5); +  mix_vm_set_rA(vm,mix_word_new_bn(50,0,1,48,4)); +  mix_vm_set_addr_contents(vm,1000,mix_word_new_bn(2,0,0,0,0)); +  fill_test_desc_(&test,vm,&ins); +  test.rA_a = mix_word_new_b(1,36,0,3,32); +  test.rX_a = mix_word_new_b(8,0,0,0,0); +  run_test_(&test, vm, dc); + +  mix_ins_fill_from_id(ins,mix_DIV); +  mix_vm_set_rA(vm,MIX_WORD_ZERO); +  mix_vm_set_rX(vm,mix_word_new_b(0,0,0,0,17)); +  mix_vm_set_addr_contents(vm,1000, mix_word_new_b(0,0,0,0,3)); +  fill_test_desc_(&test,vm,&ins); +  test.rA_a = mix_word_new_b(0,0,0,0,5); +  test.rX_a = mix_word_new_b(0,0,0,0,2); +  run_test_(&test, vm, dc); + +  mix_vm_set_rA(vm,MIX_WORD_ZERO); +  mix_vm_set_rX(vm,mix_word_new_bn(0,0,0,0,17)); +  mix_vm_set_addr_contents(vm,1000, mix_word_new_b(0,0,0,0,3)); +  fill_test_desc_(&test,vm,&ins); +  test.rA_a = mix_word_new_b(0,0,0,0,5); +  test.rX_a = mix_word_new_b(0,0,0,0,2); +  run_test_(&test, vm, dc); + +  mix_vm_set_rA(vm, MIX_WORD_MINUS_ZERO); +  mix_vm_set_rX(vm, mix_word_new_b(19,19,0,3,1)); +  mix_vm_set_addr_contents(vm,1000, mix_word_new_bn(0,0,0,2,0)); +  fill_test_desc_(&test,vm,&ins); +  test.rA_a = mix_word_new_b(0,9,41,32,1); +  test.rX_a = mix_word_new_bn(0,0,0,1,1); +  run_test_(&test, vm, dc); + +  free_cells_(&test); +} + +static void +test_shift_(mix_vm_t *vm, mix_dump_context_t *dc) +{ +  test_desc_t test; +  mix_ins_t ins; + +  g_print("Testing shift instructions...\n"); +  mix_vm_reset(vm); +  set_cells_(&test,0,0); +  fill_test_desc_(&test,vm,&ins); +  mix_ins_fill_from_id(ins,mix_SRAX); +  ins.index = 0; +  ins.address = 1; +  test.rA_b = mix_word_new_b(1,2,3,4,5); +  test.rX_b = mix_word_new_bn(6,7,8,9,10); +  test.rA_a = mix_word_new_b(0,1,2,3,4); +  test.rX_a = mix_word_new_bn(5,6,7,8,9); +  run_test_(&test, vm, dc); + +  mix_ins_fill_from_id(ins, mix_SLA); +  ins.address = 2; +  fill_test_desc_(&test, vm, &ins); +  test.rA_a = mix_word_new_b(2,3,4,0,0); +  run_test_(&test, vm, dc); + +  mix_ins_fill_from_id(ins, mix_SRC); +  ins.address = 4; +  fill_test_desc_(&test, vm, &ins); +  test.rA_a = mix_word_new_b(6,7,8,9,2); +  test.rX_a = mix_word_new_bn(3,4,0,0,5); +  run_test_(&test, vm, dc); + +  mix_ins_fill_from_id(ins, mix_SRA); +  ins.address = 2; +  fill_test_desc_(&test, vm, &ins); +  test.rA_a = mix_word_new_b(0,0,6,7,8); +  run_test_(&test, vm, dc); + +  mix_ins_fill_from_id(ins, mix_SLC); +  ins.address = 501; +  fill_test_desc_(&test, vm, &ins); +  test.rA_a = mix_word_new_b(0,6,7,8,3); +  test.rX_a = mix_word_new_bn(4,0,0,5,0); +  run_test_(&test, vm, dc); +} + +static void +test_spc_(mix_vm_t *vm, mix_dump_context_t *dc) +{ +  test_desc_t test; +  mix_ins_t ins; + +  g_print("Testing special instructions...\n"); +  mix_vm_reset(vm); +  set_cells_(&test,0,0); +  fill_test_desc_(&test,vm,&ins); +  mix_ins_fill_from_id(ins,mix_NUM); +  ins.index = 0; +  ins.address = 0; +  test.rA_b = mix_word_new_bn(0,0,31,32,39); +  test.rX_b = mix_word_new_b(37,57,47,30,30); +  test.rA_a = mix_word_negative(12977700); +  test.rX_a = test.rX_b; +  run_test_(&test, vm, dc); + +  mix_ins_fill_from_id(ins, mix_INCA);  +  ins.address = 1;  +  fill_test_desc_(&test, vm, &ins);  +  test.rA_a = mix_word_negative(12977699); +  run_test_(&test, vm, dc); + +  mix_ins_fill_from_id(ins, mix_CHAR);  +  fill_test_desc_(&test, vm, &ins);  +  test.rA_a = mix_word_new_bn(30,30,31,32,39); +  test.rX_a = mix_word_new_b(37,37,36,39,39); +  run_test_(&test, vm, dc); +   +  mix_ins_fill_from_id(ins, mix_HLT); +  fill_test_desc_(&test, vm, &ins); +  run_test_(&test, vm, dc); +  g_assert(mix_vm_is_halted(vm)); +   +} + +static void +test_move_(mix_vm_t *vm, mix_dump_context_t *dc) +{ +  test_desc_t test; +  mix_ins_t ins; +  guint k; + +  g_print("Testing move instruction...\n"); +  mix_vm_reset(vm); +  set_cells_(&test,0,10); +  fill_test_desc_(&test,vm,&ins); +  mix_ins_fill_from_id(ins,mix_MOVE); +   +  ins.index = 0; +  ins.address = 0; +  ins.fspec = 5; +  for ( k = 0; k < 5; ++k ) +    test.cells_b[k] = test.cells_a[k+5] = test.cells_a[k] =mix_word_new(100*k); +       +  test.rI_b[0] = 5; +  test.rI_a[0] = 10; +  run_test_(&test,vm,dc); +   +  free_cells_(&test); +} + +   + +static void +test_load_(mix_vm_t *vm, mix_dump_context_t *dc) +{ +  test_desc_t test; +  mix_ins_t ins; +  mix_ins_id_t ids[4] = {mix_LDA, mix_LDX, mix_LDAN, mix_LDXN}; +  mix_word_t r_a[14] = { mix_word_new_bn(1,16,3,5,4), +			mix_word_new_b(1,16,3,5,4), +			mix_word_new_b(0,0,3,5,4), +			mix_word_new_bn(0,0,1,16,3), +			mix_word_new_b(0,0,0,0,5), +			MIX_WORD_MINUS_ZERO, +			mix_word_new_b(0,0,0,0,1), +			mix_word_new_b(1,16,3,5,4), +			mix_word_new_b(1,16,3,5,4), +			mix_word_new_b(0,0,3,5,4), +			mix_word_new_b(0,0,1,16,3), +			mix_word_new_b(0,0,0,0,5), +			MIX_WORD_ZERO, +			mix_word_new_b(0,0,0,0,1)}; +  mix_fspec_t fs[11] = {5,13,29,3,36,0,9,0,0,0,0}; +  mix_address_t a_a[11] = { MIX_SHORT_MINUS_ZERO, +			    mix_short_new_bn(0,1), +			    mix_short_new_bn(1,16), +			    mix_short_new_bn(16,3), +			    mix_short_new_bn(3,5), +			    mix_short_new_bn(5,4), +			    mix_short_new_b(1,16), +			    mix_short_new_b(16,3), +			    mix_short_new_b(5,4), +			    mix_short_new_b(5,4), +			    mix_short_new_b(3,5)}; +  mix_word_t val = mix_word_new_bn(1,16,3,5,4); +  gint j; +     +  g_print("Testing load instructions...\n"); +  set_cells_(&test,2000,2001); +  ins.index = 1; +  ins.address = mix_short_negative(50); +   +  mix_vm_reset(vm); +  mix_vm_set_addr_contents(vm, 2000, val); +         +  for (j = 0; j < 4; ++j) +    { +      gint k; +      mix_ins_fill_from_id(ins,ids[j]); +      for ( k = 0; k < 7; ++k ) { +	fill_test_desc_(&test,vm,&ins); +	ins.fspec = fs[k]; +	switch (ids[j])  +	  { +	  case mix_LDA: test.rA_a = r_a[k]; break; +	  case mix_LDX: test.rX_a = r_a[k]; break; +	  case mix_LDAN: test.rA_a = r_a[k+7]; break; +	  case mix_LDXN: test.rX_a = r_a[k+7]; break; +	  default: g_assert_not_reached(); +	  } +	test.rI_b[0] = test.rI_a[0] = 2050; +	run_test_(&test, vm, dc); +      } +    } +  ins.index = 0; +  ins.address = 2000; +  fs[0] = 0; fs[1] = 1; fs[2] = 2; fs[3] = 3; fs[4] = 4; fs[5] = 5; +  fs[6] = 10; fs[7] = 11; fs[8] = 37; fs[9] = 29; fs[10] = 12; +   +  mix_vm_reset(vm); +  mix_vm_set_addr_contents(vm, 2000, val); +  for ( j = 0; j < 14; j++ ) +    { +      guint k; +      if (j == 6 || j == 7 ) continue; /* mix_LDX, mix_LDAN */ +      mix_ins_fill_from_id(ins, mix_LD1 + j); +      for (k = 0; k < 11; ++k) +	{ +	  fill_test_desc_(&test, vm, &ins); +	  ins.fspec = fs[k]; +	  if ( j < 6  ) +	    test.rI_a[j] = a_a[k]; +	  else /* mix_LDiN */ +	    test.rI_a[j-8] = mix_short_magnitude(a_a[k]); +	  run_test_(&test, vm, dc); +	} +    } + +  free_cells_(&test); +} + + +static void +test_store_(mix_vm_t *vm, mix_dump_context_t *dc) +{ +  test_desc_t test; +  mix_ins_t ins; +  mix_word_t reg = mix_word_new_b(6,7,8,9,0); +  mix_word_t add = mix_word_new_bn(1,2,3,4,5); +  mix_word_t addr[6] = { mix_word_new_b(6,7,8,9,0), +			  mix_word_new_bn(6,7,8,9,0), +			  mix_word_new_bn(1,2,3,4,0), +			  mix_word_new_bn(1,0,3,4,5), +			  mix_word_new_bn(1,9,0,4,5), +			  mix_word_new_b(0,2,3,4,5)}; +  mix_word_t addri[6] = { mix_word_new_b(0,0,0,9,0), +			  mix_word_new_bn(0,0,0,9,0), +			  mix_word_new_bn(1,2,3,4,0), +			  mix_word_new_bn(1,0,3,4,5), +			  mix_word_new_bn(1,9,0,4,5), +			  mix_word_new_b(0,2,3,4,5)}; +  mix_word_t addrz[6] = { mix_word_new_b(0,0,0,0,0), +			  mix_word_new_bn(0,0,0,0,0), +			  mix_word_new_bn(1,2,3,4,0), +			  mix_word_new_bn(1,0,3,4,5), +			  mix_word_new_bn(1,0,0,4,5), +			  mix_word_new_b(0,2,3,4,5)}; +  mix_fspec_t fs[6] = {5,13,45,18,19,1}; +  gint i,j; + +  g_print("Testing store instructions...\n"); + +  set_cells_(&test,2000,2001); +  ins.index = 0; +  ins.address = 2000; +   +  mix_vm_reset(vm); +  fill_test_desc_(&test,vm,&ins); +  test.rA_a = test.rA_b = test.rX_a = test.rX_b = reg; +  test.rJ_a = test.rJ_b = mix_word_to_short(reg); +  for (j = 0; j < 6; ++j) +    test.rI_a[j] = test.rI_b[j] = test.rJ_a; +  test.cells_b[0] = add; +           +  for (i = 0; i < 10; ++i) +    { +      mix_ins_fill_from_id(ins,mix_STA+i); +      for (j = 0; j < 6; ++j) +	{ +	  ins.fspec = fs[j]; +	  if (i == 0 || i == 7 ) /* mix_STA, mix_STX */ +	    test.cells_a[0] = addr[j]; +	  else if ( i < 9 ) /* mix_STi, mix_STJ */ +	    test.cells_a[0] = addri[j]; +	  else /* mix_STZ */ +	    test.cells_a[0] = addrz[j]; +	  run_test_(&test,vm,dc); +	} +    } +   +  free_cells_(&test); +} + + + +int +main(int argc, const char **argv) +{ +  mix_vm_t *vm; +  mix_dump_context_t *dc; +   +  INIT_TEST; + +  vm = mix_vm_new(); + +#ifdef VERBOSE_TEST +  dc = mix_dump_context_new(MIX_DUMP_DEF_CHANNEL, 0, 0, MIX_DUMP_ALL); +#else +  dc = NULL; +#endif + +  test_arithmetics_(vm, dc); +  test_shift_(vm, dc); +  test_spc_(vm,dc); +  test_move_(vm,dc); +  test_load_(vm,dc); +  test_store_(vm,dc); +   +  mix_vm_delete(vm); + +#ifdef VERBOSE_TEST +  mix_dump_context_delete(dc); +#endif + +  return EXIT_SUCCESS; +} + diff --git a/mixlib/testsuite/test.h b/mixlib/testsuite/test.h new file mode 100644 index 0000000..6bf6306 --- /dev/null +++ b/mixlib/testsuite/test.h @@ -0,0 +1,44 @@ +/* +** Copyright (C) 1999 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +**   +*/ + +/* Common definitions for test programs */ + +#ifndef TEST_H +#define TEST_H + +#include <glib.h> +#include <mix.h> + +#define PRINT_BYTE(byte) g_print("%s = %02d",#byte,byte) + +#ifdef VERBOSE_TEST /* get printed information  */ +#define INIT_TEST \ + do { g_set_print_handler(NULL); mix_init_lib(); } while(FALSE); +#else /* no printed information */ +static void +dummy_print_f_(const gchar *m) +{ +  /* no output */ +} +#define INIT_TEST \ +do { g_set_print_handler(dummy_print_f_); mix_init_lib(); } while(FALSE); +#endif /* VERBOSE_TEST */ + + +#endif /* TEST_H */ diff --git a/mixlib/xmix_device.c b/mixlib/xmix_device.c new file mode 100644 index 0000000..4754015 --- /dev/null +++ b/mixlib/xmix_device.c @@ -0,0 +1,131 @@ +/* -*-c-*- -------------- xmix_device.c : + * Implementation of the functions declared in xmix_device.h + * ------------------------------------------------------------------ + *  Last change: Time-stamp: "01/03/02 23:14:57 jose" + * ------------------------------------------------------------------ + * Copyright (C) 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#include "xmix_device.h" + +const char *DEV_EXT_ = ".dev"; + +const char *DEF_NAMES_[] = { +  "tape0", "tape1", "tape2", "tape3", "tape4", "tape5", "tape6", "tape7", +  "disk0", "disk1", "disk2", "disk3", "disk4", "disk5", "disk6", "disk7", +  "cardrd", "cardwr", "printer", "console", "paper" +}; + +const size_t SIZES_[] = { +  100, 100, 100, 100, 100, 100, 100, 100, +  100, 100, 100, 100, 100, 100, 100, 100, +  16, 16, 24, 14, 14 +}; + +const mix_device_mode_t MODES_[] = { +  mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, mix_dev_BIN,   +  mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, mix_dev_BIN,   +  mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, +  mix_dev_BIN, mix_dev_CHAR, mix_dev_CHAR, mix_dev_CHAR, mix_dev_CHAR, +  mix_dev_CHAR +}; + +const mix_fmode_t FMODES_[] = { +  mix_io_RDWRT,  mix_io_RDWRT,  mix_io_RDWRT,  mix_io_RDWRT, +  mix_io_RDWRT,  mix_io_RDWRT,  mix_io_RDWRT,  mix_io_RDWRT, +  mix_io_RDWRT,  mix_io_RDWRT,  mix_io_RDWRT,  mix_io_RDWRT, +  mix_io_RDWRT,  mix_io_RDWRT,  mix_io_RDWRT,  mix_io_RDWRT, +  mix_io_READ, mix_io_WRITE, mix_io_WRITE, mix_io_WRITE, mix_io_WRITE +}; + +/* +  Write a block to the device. +*/ +static gboolean +write_ (mix_device_t *dev, const mix_word_t *block)  +{ +  gboolean result; + +  if (FMODES_[dev->type] == mix_io_READ) return FALSE; +  if (MODES_[dev->type] == mix_dev_CHAR) +    result = mix_io_write_word_array_as_char (GET_CHANNEL_ (dev), +					      block, SIZES_[dev->type]); +  else +    result = mix_io_write_word_array (GET_CHANNEL_ (dev), +				      block, SIZES_[dev->type]); +  if (result && mix_device_mode(dev) == mix_dev_CHAR)  +    putc ('\n', mix_io_to_FILE (GET_CHANNEL_ (dev))); + +  fflush (mix_io_to_FILE (GET_CHANNEL_ (dev))); +   +  return result; +} + +static gboolean +read_ (mix_device_t *dev, mix_word_t *block)  +{ +  if (FMODES_[dev->type] == mix_io_WRITE) return FALSE; +  if (MODES_[dev->type] == mix_dev_CHAR) +    return mix_io_read_word_array_as_char (GET_CHANNEL_ (dev), +					   block, SIZES_[dev->type]); +  else +    return mix_io_read_word_array (GET_CHANNEL_ (dev), +				   block, SIZES_[dev->type]); +} + +static gboolean +ioc_ (mix_device_t *dev, mix_short_t arg)  +{ +  int m; +  FILE *file; +   +  m = mix_short_magnitude(arg); +  if (mix_short_is_negative(arg)) m = -m; +  m *= sizeof (mix_word_t) * SIZES_[dev->type]; +  file = mix_io_to_FILE (GET_CHANNEL_(dev)); +   +  if (dev->type >= mix_dev_TAPE_0 && dev->type <= mix_dev_TAPE_7) +    { +      if (m == 0) rewind (file); +      else fseek (file, m, SEEK_CUR); +    } +  if (dev->type >= mix_dev_DISK_0 && dev->type <= mix_dev_DISK_7) +    { +      g_return_val_if_fail (m == 0, FALSE); +      // position disk +    } +  if (dev->type == mix_dev_PAPER_TAPE) +    { +      g_return_val_if_fail (m == 0, FALSE); +      rewind (file); +    } +  return TRUE; +} + +static gboolean +busy_ (const mix_device_t *dev) +{ +  return (!mix_io_is_ready (GET_CHANNEL_(dev))); +} + +static mix_device_vtable_t VTABLE_ = { +  write_, read_, ioc_, busy_ +}; + +const mix_device_vtable_t * DEF_DEV_VTABLE_ = &VTABLE_; diff --git a/mixlib/xmix_device.h b/mixlib/xmix_device.h new file mode 100644 index 0000000..45fd7d3 --- /dev/null +++ b/mixlib/xmix_device.h @@ -0,0 +1,77 @@ +/* -*-c-*- ---------------- xmix_device.h : + * Protected declarations for mix_device_t + * ------------------------------------------------------------------ + *  Last change: Time-stamp: <01/03/02 01:15:22 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#ifndef XMIX_DEVICE_H +#define XMIX_DEVICE_H + +#include "mix_file.h" +#include "mix_device.h" + +/* table of overridable device operations */ +typedef gboolean (*mix_dev_write_func_t) (mix_device_t *, const mix_word_t *); +typedef gboolean (*mix_dev_read_func_t) (mix_device_t *, mix_word_t *); +typedef gboolean (*mix_dev_ioc_func_t) (mix_device_t *, mix_short_t); +typedef gboolean (*mix_dev_busy_func_t) (const mix_device_t *); + +typedef struct mix_device_vtable_t +{ +  mix_dev_write_func_t write; +  mix_dev_read_func_t  read; +  mix_dev_ioc_func_t   ioc; +  mix_dev_busy_func_t  busy; +} mix_device_vtable_t; + +/* default vtable */ +extern const mix_device_vtable_t *DEF_DEV_VTABLE_; + +/* +  Actual definition of a mix device, which can be cast to +  a mix file. +*/ +struct mix_device_t  +{ +  mix_iochannel_t *file; +  mix_device_type_t type; +  const mix_device_vtable_t *vtable; +}; + +#define GET_CHANNEL_(dev) (dev->file) +#define GET_FILE_(dev) ((mix_file_t *)(dev->file)) + +/* default extension for device files */ +extern const char *DEV_EXT_; +/* default names for device files */ +extern const char *DEF_NAMES_[]; +/* block sizes for devices */ +extern const size_t SIZES_[]; +/* io modes for devices */ +extern const mix_device_mode_t MODES_[]; +/* files modes for devices */ +extern const mix_fmode_t FMODES_[]; + + + + +#endif /* XMIX_DEVICE_H */ + diff --git a/mixlib/xmix_eval.h b/mixlib/xmix_eval.h new file mode 100644 index 0000000..b43803a --- /dev/null +++ b/mixlib/xmix_eval.h @@ -0,0 +1,55 @@ +/* -*-c-*- ---------------- xmix_eval.h : + * Definition of opaque types in mix_eval.h + * ------------------------------------------------------------------ + *  Last change: Time-stamp: <01/02/20 00:25:14 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#ifndef XMIX_EVAL_H +#define XMIX_EVAL_H + +#include "mix_eval.h" + +/* the evaluator type */ +struct mix_eval_t  +{ +  mix_symbol_table_t *table;	/* symbol table */ +  gboolean towner;		/* true if owns the table */ +  mix_eval_result_t result;	/* last evaluation result */ +  gint errpos;			/* location of last error */ +  mix_word_t value;		/* last computed value */ +}; + +/* flex scanner data/result struct */ +typedef struct mix_eval_data_  +{ +  gchar *expr; +  const mix_symbol_table_t *table; +  mix_word_t value; +  mix_short_t loc; +  gint errpos; +} mix_eval_data_; + +/* flex scanner prototype */ +extern +mix_eval_result_t mix_eval_expr (mix_eval_data_ *data); + +#endif /* XMIX_EVAL_H */ + diff --git a/mixlib/xmix_io.c b/mixlib/xmix_io.c new file mode 100644 index 0000000..7511949 --- /dev/null +++ b/mixlib/xmix_io.c @@ -0,0 +1,57 @@ +/* -*-c-*- ------------------ xmix_io.c : + * Implementation of the functions declared in xmix_io.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include "xmix_io.h" + +const char *io_OPENTYPE_[5] = { "r", "w", "w+", "a", "a+" }; + + +/* initialise a mix_iochannel from a file descriptor */ +gboolean +io_init_from_fdesc_(mix_iochannel_t *ioc, int fdesc) +{ +  FILE *file; +  mix_fmode_t mode; +  int flags = fcntl(fdesc, F_GETFL); + +  if ( (flags&O_RDONLY) == O_RDONLY )  +    mode = mix_io_READ; +  else if ( (flags&O_WRONLY) == O_WRONLY ) +    mode = mix_io_WRITE; +  else if ( (flags&O_RDWR) == O_RDWR ) +    mode = mix_io_RDWRT; +  else  +    return FALSE; +   +  file = fdopen(fdesc, fmode_to_type_(mode)); +  g_return_val_if_fail(file != NULL, FALSE); +   +  io_init_from_file_(ioc, file); +   +  return TRUE; +} + + + diff --git a/mixlib/xmix_io.h b/mixlib/xmix_io.h new file mode 100644 index 0000000..19cbe04 --- /dev/null +++ b/mixlib/xmix_io.h @@ -0,0 +1,64 @@ +/* -*-c-*- ------------------ xmix_io.h : + * Implementation of mix_iochannel_t and mix_file_t + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#ifndef XMIX_IOCHANNEL_H +#define XMIX_IOCHANNEL_H + +#include <stdio.h> +#include "mix_io.h" + +/* the actual definition of mix_iochannel_t */ +struct mix_iochannel_t  +{ +  FILE *file; +}; + + +extern const char * io_OPENTYPE_[5]; + +#define fmode_to_type_(mode) ( (mode) < 6 ? io_OPENTYPE_[(mode)]:NULL ) + +/* initialisation */ +extern gboolean +io_init_from_fdesc_(mix_iochannel_t *ioc, int fdesc); + +#define io_init_from_file_(ioc,f) (ioc)->file = f + +#define io_close_(ioc)  fclose((ioc)->file) + +/* write/read data */ +#define write_data_(ioc,data,no)  \ + ( (no) == fwrite((const void*)(data), sizeof(*(data)), (no), (ioc)->file) ) + +#define read_data_(ioc,data,no)  \ + ( (no) == fread((void*)(data), sizeof(*(data)), (no), (ioc)->file) ) + +/* state */ +#define is_eof_(ioc)  ( feof((ioc)->file) != 0 ) +#define is_ready_(ioc) ( ferror((ioc)->file) == 0 ) + +/* conversions */ +#define io_get_FILE_(ioc)  (MIX_IOCHANNEL(ioc))->file + + +#endif /* XMIX_IOCHANNEL_H */ + diff --git a/mixlib/xmix_parser.h b/mixlib/xmix_parser.h new file mode 100644 index 0000000..1915a0d --- /dev/null +++ b/mixlib/xmix_parser.h @@ -0,0 +1,107 @@ +/* -*-c-*- ---------------- xmix_parser.h : + * Declarations for the implementation of mix_parser_t + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#ifndef XMIX_PARSER_H +#define XMIX_PARSER_H + +#include "mix_ins.h" +#include "mix_file.h" +#include "mix_symbol_table.h" +#include "mix_parser.h" + +/* mix_parser_t definition */ +struct mix_parser_t  +{ +  mix_file_t  *in_file;     /* the source file to be compiled */  +  mix_symbol_table_t *symbol_table;  +  mix_symbol_table_t *ls_table;  /* literal strings symbols */ +  guint cur_ls;             /* current literal string symbol */ +  GHashTable *future_refs;  /* a map from symbol name to list of addresses */ +  GTree *ins_table;         /* a table of compiled instructions */ +  mix_address_t loc_count;  /* current memory location during compilation */ +  mix_parser_err_t status;  /* outcome of compilation */ +  guint err_line;           /* line of the last error */ +  guint err_count;          /* no. of errors during compilation */ +  guint warn_count;         /* no. of warnings during compilation */ +  mix_address_t start;      /* start address of the compiled code */ +}; + +/* each node of the ins_table stores a mix_word_t with the instruction +   and a source code line (for debugging and listing)  +*/ +typedef struct ins_node_ +{ +  mix_word_t ins; +  guint lineno; +} ins_node_; + + +/* functions to manipulate mix_parser_t during compilation */ + +/* access loc counter */ +#define get_ploc_(parser) ((parser)->loc_count) + +/* symbol table */ +/* Define a new symbol with given value  + * and update previously set refs to this symbol  + */ +extern mix_parser_err_t +mix_parser_define_symbol_value (mix_parser_t *parser, const gchar *name, +				mix_word_t value); + +/* Define a new symbol with value equal to the current loc_count  + * and update previously set refs to this symbol  + */ +extern mix_parser_err_t  +mix_parser_define_symbol_here(mix_parser_t *parser, const gchar *name); + +/* Set a reference to future symbol here */ +extern void +mix_parser_set_future_ref(mix_parser_t *parser, const gchar *name); + +/* Redefine the value of a local symbol as the current loc_count */ +extern void +mix_parser_manage_local_symbol(mix_parser_t *parser, const gchar *name, +			       mix_short_t value); + +/* Literal strings symbols */ +extern void +mix_parser_define_ls (mix_parser_t *parser, mix_word_t value); + +/* Compilation */ +/* Add instruction with address the current loc_count */ +extern void +mix_parser_add_ins(mix_parser_t *parser, const mix_ins_t *new_ins,  +		   guint lineno); +extern void +mix_parser_add_raw(mix_parser_t *parser, mix_word_t word, guint lineno); + +/* Error handling */ +extern void  +mix_parser_log_error(mix_parser_t *parser, mix_parser_err_t error, +		     gint lineno, const gchar *comment, gboolean warn); + + + + +#endif /* XMIX_PARSER_H */ + diff --git a/mixlib/xmix_vm.c b/mixlib/xmix_vm.c new file mode 100644 index 0000000..e614cb4 --- /dev/null +++ b/mixlib/xmix_vm.c @@ -0,0 +1,567 @@ +/* ---------------------- xmix_vm.c : + * Implementation of the functions declared in xmix_vm.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + + +#include "xmix_vm.h" + +/* auxiliar functions */ +G_INLINE_FUNC mix_address_t +get_M_(const mix_vm_t *vm, const mix_ins_t *ins); +G_INLINE_FUNC mix_word_t +get_V_(const mix_vm_t *vm, const mix_ins_t *ins); +G_INLINE_FUNC mix_device_t * +get_dev_ (mix_vm_t *vm, mix_fspec_t type); + +G_INLINE_FUNC mix_address_t +get_M_(const mix_vm_t *vm, const mix_ins_t *ins) +{ +  if ( ins->index == 0 ) +    return ins->address; +  else +    return mix_short_add(ins->address,  +			 mix_word_to_short_fast(get_rI_(vm, ins->index))); +} + +G_INLINE_FUNC mix_word_t +get_V_(const mix_vm_t *vm, const mix_ins_t *ins) +{ +  return mix_word_get_field(ins->fspec, get_cell_(vm, get_M_(vm,ins))); +} + +G_INLINE_FUNC mix_device_t * +get_dev_ (mix_vm_t *vm, mix_fspec_t type)  +{ +  if (type >= BD_NO_) return NULL; +  if (vm->devices[type] == NULL) +    vm->devices[type] = mix_device_new (type); +  return vm->devices[type]; +} + +/* Instruction handlers */ + +static gboolean  +nop_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ +  g_assert(ins->opcode == mix_opNOP); +  inc_loc_(vm); +  return TRUE; +} + +static gboolean  +add_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ +  mix_word_t val = get_V_(vm, ins); +  g_assert(ins->opcode == mix_opADD || ins->opcode == mix_opSUB); +  if ( ins->opcode == mix_opSUB ) mix_word_reverse_sign(val); +  if ( mix_word_add_and_carry(get_rA_(vm), val, NULL, &get_rA_(vm)) ) +    set_over_(vm,TRUE); +  inc_loc_(vm); +  return TRUE; +} + + +static gboolean  +mul_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ +  g_assert(ins->opcode == mix_opMUL); +  mix_word_mul(get_rA_(vm), get_V_(vm,ins), &get_rA_(vm), &get_rX_(vm)); +  inc_loc_(vm); +  return TRUE; +} + +static gboolean  +div_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ +  g_assert(ins->opcode == mix_opDIV); +  if ( mix_word_div(get_rA_(vm), get_rX_(vm), get_V_(vm,ins), +		    &get_rA_(vm), &get_rX_(vm)) ) +    set_over_(vm,TRUE); +  inc_loc_(vm); +  return TRUE; +} + +static gboolean  +spc_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ +  g_assert(ins->opcode == mix_opSPC); +   +  switch (mix_ins_id_from_ins(*ins)) { +  case mix_HLT: halt_(vm, TRUE); break; +  case mix_CHAR: +    {  +      guint32 num = mix_word_magnitude(get_rA_(vm)); +      mix_char_t z = mix_ascii_to_char('0'); +      guint i; +      for (i = 5; 0 < i; --i, num /= 10) +	mix_word_set_byte(&get_rX_(vm), i, z + num % 10); +      for (i = 5; 0 < i; --i, num /= 10) +	mix_word_set_byte(&get_rA_(vm), i, z + num % 10); +      break; +    } +  case mix_NUM:  +    {  +      guint i; +      mix_word_t num = MIX_WORD_ZERO; +      mix_word_t ten = 10; +      for (i = 1; i <= 5; ++i) { +	mix_word_mul(ten, num, NULL, &num); +	mix_word_add_and_carry(num, mix_word_get_byte(get_rA_(vm),i)%10, +			       NULL, &num); +      } +      for (i = 1; i <= 5; ++i) { +	mix_word_mul(ten, num, NULL, &num); +	mix_word_add_and_carry(num, mix_word_get_byte(get_rX_(vm),i)%10, +			       NULL, &num); +      } +      set_rA_(vm, +	      mix_word_is_negative(get_rA_(vm)) ? mix_word_negative(num):num); +      break; +    } +  default: return FALSE; +  } +  inc_loc_(vm); +  return TRUE; +} + +static gboolean  +sla_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ +  mix_short_t n = get_M_(vm,ins); +   +  g_assert(ins->opcode == mix_opSLx); +  g_return_val_if_fail(mix_short_is_positive(n), FALSE); +   +  switch ( mix_ins_id_from_ins(*ins) ) { +  case mix_SLA: +    mix_word_shift_left(get_rA_(vm), MIX_WORD_ZERO, n, &get_rA_(vm), NULL); +    break; +  case mix_SRA: +    mix_word_shift_right(get_rA_(vm), MIX_WORD_ZERO, n, &get_rA_(vm), NULL); +    break; +  case mix_SLAX: +    mix_word_shift_left(get_rA_(vm), get_rX_(vm), n,  +			&get_rA_(vm), &get_rX_(vm)); +    break; +  case mix_SRAX: +    mix_word_shift_right(get_rA_(vm), get_rX_(vm), n,  +			&get_rA_(vm), &get_rX_(vm)); +    break; +  case mix_SLC: +    mix_word_shift_left_circular(get_rA_(vm), get_rX_(vm), n,  +				 &get_rA_(vm), &get_rX_(vm)); +    break; +  case mix_SRC: +    mix_word_shift_right_circular(get_rA_(vm), get_rX_(vm), n,  +				  &get_rA_(vm), &get_rX_(vm)); +    break; +  default: +    return FALSE; +  } +   +  inc_loc_(vm); +  return TRUE; +} + +static gboolean  +mov_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ +  mix_short_t from = get_M_(vm,ins),  +    to = mix_word_to_short_fast(get_rI_(vm,1)); +  guint k, delta = ins->fspec; +   +  g_assert(ins->opcode == mix_opMOVE); +  g_return_val_if_fail(mix_short_is_positive(from), FALSE); +  g_return_val_if_fail(mix_short_is_positive(to), FALSE); +  g_return_val_if_fail(MEMOK_(from + delta -1), FALSE); +  g_return_val_if_fail(MEMOK_(to + delta - 1), FALSE); +   +  for (k = 0; k < delta; ++k) +    set_cell_(vm, to+k, get_cell_(vm, from+k)); +  set_rI_(vm, 1, to+delta); +  inc_loc_(vm); +  return TRUE; +} + +static gboolean +lda_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ +  gint r = 0; +  mix_word_t val; +  mix_ins_id_t id = mix_ins_id_from_ins(*ins); +     +  g_assert(id >= mix_LDA && id <= mix_LDXN); +   +  val = get_V_(vm, ins); +  if ( id > mix_LDX && mix_fspec_left(ins->fspec) == 0)  +    mix_word_reverse_sign(val); +  if ( (id > mix_LDA && id < mix_LDX) || (id > mix_LDAN && id < mix_LDXN) ) +    /* Bytes 1-3 of I regs are always null */ +    val = mix_word_set_field(mix_fspec_new(1,3),MIX_WORD_ZERO,val); +         +  switch (id) { +  case mix_LDA: case mix_LDAN: r = A_; break; +  case mix_LDX: case mix_LDXN: r = X_; break; +  case mix_LD1: case mix_LD1N: r = I1_; break; +  case mix_LD2: case mix_LD2N: r = I2_; break; +  case mix_LD3: case mix_LD3N: r = I3_; break; +  case mix_LD4: case mix_LD4N: r = I4_; break; +  case mix_LD5: case mix_LD5N: r = I5_; break; +  case mix_LD6: case mix_LD6N: r = I6_; break; +  default: g_assert_not_reached(); +  } +  set_reg_(vm, r, val); +  inc_loc_(vm); +  return TRUE; +} + + +static gboolean +sta_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ +  mix_address_t addr = get_M_(vm, ins); +  mix_ins_id_t id = mix_ins_id_from_ins(*ins); +  mix_word_t from; +   +  g_assert(id >= mix_STA && id <= mix_STZ); +  switch (id) { +  case mix_STA: from = get_rA_(vm); break; +  case mix_STX: from = get_rX_(vm); break; +  case mix_STJ: from = get_rJ_(vm); break; +  case mix_STZ: from = MIX_WORD_ZERO; break; +  default: from = get_rI_(vm, id - mix_ST1 + 1); break; +  } +  set_cell_(vm, addr, +	    mix_word_store_field(ins->fspec, from,  get_cell_(vm, addr))); +  inc_loc_(vm); +  return TRUE; +} + +static gboolean  +jbs_handler_ (mix_vm_t *vm, const mix_ins_t *ins) +{ +  g_assert (ins->opcode == mix_opJBUS); +  g_return_val_if_fail (ins->fspec < BD_NO_, TRUE); +  g_return_val_if_fail (get_dev_ (vm, ins->fspec) != NULL, TRUE); +  if ( mix_device_busy (get_dev_ (vm, ins->fspec)) ) { +      set_rJ_(vm, get_loc_ (vm)); +      set_loc_ (vm, get_M_ (vm, ins)); +  } else inc_loc_ (vm); +  return TRUE; +} + +static gboolean  +ioc_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ +  mix_address_t addr; +  mix_device_t *dev; +  gboolean result; +   +  g_assert(ins->opcode == mix_opIOC); +  addr = get_M_ (vm, ins); +  g_return_val_if_fail (ins->fspec < BD_NO_, TRUE); +  dev = get_dev_ (vm, ins->fspec); +  g_return_val_if_fail (dev != NULL, TRUE); +  result = +    mix_device_ioc (dev, addr); +     +  inc_loc_(vm); +  return result; +} + +static gboolean  +inp_handler_ (mix_vm_t *vm, const mix_ins_t *ins) +{ +  mix_address_t addr; +  mix_device_t *dev; +  gboolean result; +   +  g_assert(ins->opcode == mix_opIN); +  addr = get_M_ (vm, ins); +  g_return_val_if_fail (ins->fspec < BD_NO_, TRUE); +  g_return_val_if_fail (MEMOK_(addr), TRUE); +  dev = get_dev_ (vm, ins->fspec); +  g_return_val_if_fail ( dev != NULL, TRUE); +  g_return_val_if_fail (MEM_CELLS_NO_ - addr > mix_device_block_size(dev), +			TRUE); +  result = +    mix_device_read (dev, get_cell_ptr_ (vm, addr)); +     +  inc_loc_(vm); +  return result; +} + +static gboolean  +out_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ +  mix_address_t addr; +  mix_device_t *dev; +  gboolean result; +   +  g_assert(ins->opcode == mix_opOUT); +  addr = get_M_ (vm, ins); +  g_return_val_if_fail (ins->fspec < BD_NO_, TRUE); +  g_return_val_if_fail (MEMOK_(addr), TRUE); +  dev = get_dev_ (vm, ins->fspec); +  g_return_val_if_fail ( dev != NULL, TRUE); +  g_return_val_if_fail (MEM_CELLS_NO_ - addr > mix_device_block_size(dev), +			TRUE); +  result = +    mix_device_write (dev, get_cell_ptr_ (vm, addr)); +   +  inc_loc_(vm); +  return result; +} + +static gboolean  +jrd_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ +  g_assert(ins->opcode == mix_opJRED); +  g_return_val_if_fail (ins->fspec < BD_NO_, TRUE); +  g_return_val_if_fail (get_dev_ (vm, ins->fspec) != NULL, TRUE); +  inc_loc_ (vm); +  if ( !mix_device_busy (get_dev_ (vm, ins->fspec)) )  +    { +      set_rJ_(vm, get_loc_(vm)); +      set_loc_ (vm, get_M_ (vm, ins)); +    } +  return TRUE; +} + +static gboolean +jmp_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ +  gboolean jump = FALSE; +  mix_address_t addr = get_M_(vm, ins); +  mix_ins_id_t id = mix_ins_id_from_ins(*ins); +   +  g_assert(ins->opcode == mix_opJMP); +  g_return_val_if_fail(MEMOK_(addr), FALSE); +  switch ( id ) { +  case mix_JMP: +  case mix_JSJ: +    jump = TRUE; +    break; +  case mix_JOV: +    jump = get_over_(vm); +    if (jump) set_over_(vm, FALSE); +    break; +  case mix_JNOV: +    jump = !get_over_(vm); +    set_over_(vm, FALSE); +    break; +  case mix_JL: +    jump = ( get_cmp_(vm) == mix_LESS ); +    break; +  case mix_JE: +    jump = ( get_cmp_(vm) == mix_EQ ); +    break; +  case mix_JG: +    jump = ( get_cmp_(vm) == mix_GREAT ); +    break; +  case mix_JGE: +    jump = ( get_cmp_(vm) != mix_LESS ); +    break; +  case mix_JNE: +    jump = ( get_cmp_(vm) != mix_EQ ); +    break; +  case mix_JLE: +    jump = ( get_cmp_(vm) != mix_GREAT ); +    break; +  default: +    return FALSE; +  } +   +  inc_loc_(vm); +  if ( jump ) { +    if ( id != mix_JSJ ) set_rJ_(vm, get_loc_(vm)); +    set_loc_(vm, addr); +  } +  return TRUE; +} + +static gboolean +jpx_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ +  gboolean jump = FALSE; +  mix_address_t addr = get_M_(vm, ins); +  mix_ins_id_t id = mix_ins_id_from_ins(*ins); +  mix_word_t val; +     +  g_assert(ins->opcode >= mix_opJAx || ins->opcode <= mix_opJXx); +  g_return_val_if_fail(MEMOK_(addr), FALSE); +   +  switch (ins->opcode) { +  case mix_opJAx: val = get_rA_(vm); break; +  case mix_opJXx: val = get_rX_(vm); break; +  default: val = get_rI_(vm, ins->opcode - mix_opJAx); +  } +   +  switch (id) { +  case mix_JAN: case mix_JXN: +  case mix_J1N: case mix_J2N: case mix_J3N: +  case mix_J4N: case mix_J5N: case mix_J6N: +    jump = mix_word_is_negative(val) && val != MIX_WORD_MINUS_ZERO; +    break; +  case mix_JAZ: case mix_JXZ: +  case mix_J1Z: case mix_J2Z: case mix_J3Z: +  case mix_J4Z: case mix_J5Z: case mix_J6Z: +    jump = mix_word_magnitude(val) == MIX_WORD_ZERO; +    break; +  case mix_JAP: case mix_JXP: +  case mix_J1P: case mix_J2P: case mix_J3P: +  case mix_J4P: case mix_J5P: case mix_J6P: +    jump = mix_word_is_positive(val) && val != MIX_WORD_ZERO; +    break; +  case mix_JANN: case mix_JXNN: +  case mix_J1NN: case mix_J2NN: case mix_J3NN: +  case mix_J4NN: case mix_J5NN: case mix_J6NN: +    jump = mix_word_magnitude(val) == MIX_WORD_ZERO  +      || mix_word_is_positive(val); +    break; +  case mix_JANZ: case mix_JXNZ: +  case mix_J1NZ: case mix_J2NZ: case mix_J3NZ: +  case mix_J4NZ: case mix_J5NZ: case mix_J6NZ: +    jump = mix_word_magnitude(val) != MIX_WORD_ZERO; +    break; +  case mix_JANP: case mix_JXNP: +  case mix_J1NP: case mix_J2NP: case mix_J3NP: +  case mix_J4NP: case mix_J5NP: case mix_J6NP: +    jump = mix_word_magnitude(val) == MIX_WORD_ZERO +      || mix_word_is_negative(val); +    break; +  default: +    return FALSE; +  } +   +  inc_loc_(vm); +  if ( jump ) { +    set_rJ_(vm, get_loc_(vm)); +    set_loc_(vm, addr); +  } +  return TRUE; +} + +static gboolean +ina_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ +  mix_word_t val = mix_short_to_word_fast(get_M_(vm, ins)); +  mix_ins_id_t id = mix_ins_id_from_ins(*ins); +  gint r; +   +  g_assert(id >= mix_INCA && id <= mix_ENNX); +   +  switch (ins->opcode) { +  case mix_opINCA: r = A_; break; +  case mix_opINCX: r = X_; break; +  default: r = I1_ + ins->opcode - mix_opINC1; +  } +   +  switch (id) { +  case mix_ENTA: case mix_ENTX: +    break; +  case mix_ENT1: case mix_ENT2: case mix_ENT3:  +  case mix_ENT4: case mix_ENT5: case mix_ENT6:  +    val = mix_word_set_field(mix_fspec_new(1,3), MIX_WORD_ZERO, val); +    break; +  case mix_INCA: case mix_INCX: +    if ( mix_word_add_and_carry(val, get_reg_(vm, r), NULL, &val) ) +      set_over_(vm, TRUE); +    break; +  case mix_INC1: case mix_INC2: case mix_INC3:  +  case mix_INC4: case mix_INC5: case mix_INC6: +    mix_word_add_and_carry(val, get_reg_(vm,r), NULL, &val); +    val = mix_word_set_field(mix_fspec_new(1,3), MIX_WORD_ZERO, val); +    break; +  case mix_DECA: case mix_DECX: +    if ( mix_word_add_and_carry(mix_word_negative(val), get_reg_(vm, r), +				NULL, &val) ) +      set_over_(vm, TRUE); +    break; +  case mix_DEC1: case mix_DEC2: case mix_DEC3:  +  case mix_DEC4: case mix_DEC5: case mix_DEC6:  +    mix_word_add_and_carry(mix_word_negative(val), get_reg_(vm,r), NULL, &val); +    val = mix_word_set_field(mix_fspec_new(1,3), MIX_WORD_ZERO, val); +    break; +  case mix_ENN1: case mix_ENN2: case mix_ENN3:  +  case mix_ENN4: case mix_ENN5: case mix_ENN6:  +    val = mix_word_set_field(mix_fspec_new(1,3), MIX_WORD_ZERO, val); +    /* fallthrough */ +  case mix_ENNA: case mix_ENNX: +    mix_word_reverse_sign(val); +    break; +  default: +    return FALSE; +  } +  set_reg_(vm, r, val); +  inc_loc_(vm); +  return TRUE; +} + +static gboolean +cmp_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ +  g_assert(ins->opcode >= mix_opCMPA && ins->opcode <= mix_opCMPX); + +  if ( ins->fspec == 0 ) { /* shortcut: +0 == -0 */ +    set_cmp_(vm, mix_EQ); +  } else { +    mix_word_t v = get_V_(vm, ins); +    mix_word_t reg; +    mix_cmpflag_t flag; +     +    switch (ins->opcode) { +    case mix_opCMPA: +      reg = get_rA_(vm); +      break; +    case mix_opCMPX: +      reg = get_rX_(vm); +      break; +    default: +      reg = get_rI_(vm, ins->opcode - mix_opCMPA); +      break; +    } +    reg = mix_word_get_field(ins->fspec, reg); +    mix_word_add_and_carry(reg, mix_word_negative(v), NULL, ®); +    if ( mix_word_magnitude(reg) == MIX_WORD_ZERO ) flag = mix_EQ; +    else if ( mix_word_is_positive(reg) ) flag = mix_GREAT; +    else flag = mix_LESS; +    set_cmp_(vm, flag); +  } +  inc_loc_(vm); +  return TRUE; +} + +ins_handler_t_ ins_handlers_[MIX_BYTE_MAX + 1] = {  +  nop_handler_, add_handler_, add_handler_, mul_handler_, div_handler_, +  spc_handler_, sla_handler_, mov_handler_, lda_handler_, lda_handler_, +  lda_handler_, lda_handler_, lda_handler_, lda_handler_, lda_handler_, +  lda_handler_, lda_handler_, lda_handler_, lda_handler_, lda_handler_, +  lda_handler_, lda_handler_, lda_handler_, lda_handler_, sta_handler_, +  sta_handler_, sta_handler_, sta_handler_, sta_handler_, sta_handler_, +  sta_handler_, sta_handler_, sta_handler_, sta_handler_, jbs_handler_, +  ioc_handler_, inp_handler_, out_handler_, jrd_handler_, jmp_handler_, +  jpx_handler_, jpx_handler_, jpx_handler_, jpx_handler_, jpx_handler_, +  jpx_handler_, jpx_handler_, jpx_handler_, ina_handler_, ina_handler_, +  ina_handler_, ina_handler_, ina_handler_, ina_handler_, ina_handler_, +  ina_handler_, cmp_handler_, cmp_handler_, cmp_handler_, cmp_handler_, +  cmp_handler_, cmp_handler_, cmp_handler_, cmp_handler_,  +}; diff --git a/mixlib/xmix_vm.h b/mixlib/xmix_vm.h new file mode 100644 index 0000000..cfbf65a --- /dev/null +++ b/mixlib/xmix_vm.h @@ -0,0 +1,117 @@ +/* ---------------------- xmix_vm.h : + * This file contains internal declarations used in the implementation + * of the mix_vm_t type. + * ------------------------------------------------------------------ + * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *   + */ + + +#ifndef XMIX_VM_H +#define XMIX_VM_H + +#include "mix_symbol_table.h" +#include "mix_device.h" +#include "mix_src_file.h" +#include "mix_vm.h" + +/* The mix_vm_t type */ +enum {IREG_NO_ = 6, BD_NO_ = 21, MEM_CELLS_NO_ = MIX_VM_CELL_NO}; +struct mix_vm_t  +{ +  mix_word_t reg[IREG_NO_+3]; +  mix_word_t cell[MEM_CELLS_NO_]; +  gboolean overflow; +  mix_cmpflag_t cmpflag; +  mix_short_t loc_count; +  gboolean is_halted; +  mix_device_t * devices[BD_NO_];  +  mix_address_t start_addr;	/* start address of loaded file */ +  GTree *line_table;		/* source line no -> address  */ +  GTree *address_table;		/* adress -> source line no */ +  gint8 bp[MEM_CELLS_NO_/8];	/* each bit signals a break point */ +  mix_vm_clock_t *clock;		/* the vm clock */ +  mix_symbol_table_t *symbol_table; +  mix_src_file_t *src_file;	/* source of last loaded code file */ +}; + +/* Macros for accessing/modifying the above structure. + * Warning: the arguments of these macros must not have side-effects. + */ +#define IOK_(idx) ( (idx) > 0 && (idx) < IREG_NO_+1 ) +#define MEMOK_(addr) ( mix_short_is_positive(addr) && (addr) < MEM_CELLS_NO_ ) +#define REGOK_(r) ( (r) >= 0 && (r) < IREG_NO_ + 3 ) + +enum { A_ = 0, X_, J_, I1_, I2_, I3_, I4_, I5_, I6_ }; + +#define get_reg_(vm, r) ((vm)->reg[r]) +#define get_rA_(vm)  get_reg_(vm, A_) +#define get_rX_(vm)  get_reg_(vm, X_) +#define get_rJ_(vm)  get_reg_(vm, J_) +#define get_rI_(vm,idx) get_reg_(vm, I1_ + (idx) - 1) +#define get_cell_(vm,addr) ( MEMOK_(addr) ? vm->cell[addr] : MIX_WORD_ZERO ) +#define get_cell_ptr_(vm,addr) ( MEMOK_(addr) ? (vm->cell) + addr : NULL ) +#define get_cmp_(vm) (vm->cmpflag) +#define get_over_(vm) (vm->overflow) +#define get_loc_(vm)  (vm->loc_count) +#define get_clock_(vm) (vm->clock) + +#define set_reg_(vm,r,x)			\ +do {						\ +  if ( REGOK_(r) ) vm->reg[r] = (x);		\ +} while (FALSE) + +#define set_rA_(vm,x)  set_reg_(vm,A_,x) +#define set_rX_(vm,x)  set_reg_(vm,X_,x) +#define set_rJ_(vm,x)  set_reg_(vm,J_,(x)&MIX_SHORT_MAX) +#define set_rI_(vm,idx,x)  set_reg_(vm,(idx) + I1_ - 1,x) + +#define set_cell_(vm,addr,x) 			\ +do {						\ +  if ( MEMOK_(addr) ) (vm)->cell[addr] = (x);	\ +} while (FALSE) + +#define set_cmp_(vm,x) (vm)->cmpflag = (x) +#define set_over_(vm,x) (vm)->overflow = (x) +#define set_loc_(vm,x)  (vm)->loc_count = (x)&MIX_SHORT_MAX + +#define inc_loc_(vm)   				\ +do {						\ +  vm->loc_count++;				\ +  vm->loc_count &= MIX_SHORT_MAX;		\ +} while(FALSE) + +#define is_halted_(vm) ((vm)->is_halted) +#define halt_(vm,val) ((vm)->is_halted = (val)) +#define set_start_(vm,val) ((vm)->start_addr = (val)) +#define reset_loc_(vm) set_loc_ (vm, vm->start_addr) +#define update_time_(vm,ins) mix_vm_clock_add_lapse (get_clock_(vm), ins) + +/* Breakpoints handling */ +#define bp_clear_all_(vm)	memset (vm->bp, 0, MEM_CELLS_NO_/8) +#define bp_set_(vm,addr)	vm->bp[(addr)>>3] |= 1 << ((addr)&7) +#define bp_clear_(vm,addr)	vm->bp[(addr)>>3] &= ~(1 << ((addr)&7)) +#define bp_is_set_(vm,addr)	vm->bp[(addr)>>3] & (1 << ((addr)&7)) + +/* Instruction handlers */ +typedef gboolean (*ins_handler_t_)(mix_vm_t *,const mix_ins_t *); + +extern ins_handler_t_ ins_handlers_[MIX_BYTE_MAX + 1]; + + +#endif /* XMIX_VM_H */ + | 
