https://hal.archives-ouvertes.fr/hal-03445821
Raw File
arch.c
/*
   Copyright Universite de Versailles Saint-Quentin en Yvelines 2009
   AUTHORS: Sebastien Briais, Sid Touati

   This file is part of GDD.
   
   GDD is free software: you can redistribute it and/or modify it
   under the terms of the GNU Lesser General Public License as
   published by the Free Software Foundation, either version 3 of the
   License, or (at your option) any later version.
   
   GDD 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
   Lesser General Public License for more details.
   
   You should have received a copy of the GNU Lesser General Public
   License along with GDD.  If not, see
   <http://www.gnu.org/licenses/>.
*/
#include <SCEDA/common.h>
#include "arch.h"
#include "opcode.h"
#include "util.h"

/* Include string hash and match functions */
#include "stringutil.h"

static unsigned int GDD_opcode_hash(GDD_Opcode *op) {
  return string_hash(GDD_opcode_mnemonic(op));
}

static int GDD_opcode_match(GDD_Opcode *op1, GDD_Opcode *op2) {
  return string_match(GDD_opcode_mnemonic(op1), GDD_opcode_mnemonic(op2));
}

typedef struct {
  char *name;
  int nb;
} TypeEntry;

static void type_entry_delete(TypeEntry *te) {
  free(te->name);
  free(te);
}

static unsigned int type_entry_hash(TypeEntry *te) {
  return string_hash(te->name);
}

static int type_entry_match(TypeEntry *t1, TypeEntry *t2) {
  return string_match(t1->name, t2->name);
}

/** Create a new architecture 

    @return an architecture */
GDD_Arch *GDD_arch_create() {
  GDD_Arch *arch = (GDD_Arch *)safe_malloc(sizeof(GDD_Arch));
  arch->opcodes = SCEDA_hashset_create((SCEDA_delete_fun)GDD_opcode_delete, 
				    (SCEDA_match_fun)GDD_opcode_match, 
				    (SCEDA_hash_fun)GDD_opcode_hash);
  arch->types = SCEDA_hashset_create((SCEDA_delete_fun)type_entry_delete,
				  (SCEDA_match_fun)type_entry_match,
				  (SCEDA_hash_fun)type_entry_hash);
  return arch;
}

/** Delete an architecture 

    @param[in] arch = architecture

    It will also delete the opcodes. */
void GDD_arch_delete(GDD_Arch *arch) {
  SCEDA_hashset_delete(arch->opcodes);
  SCEDA_hashset_delete(arch->types);
  free(arch);
}

/** Add an opcode to an architecture.

    @param[in] arch = architecture
    @param[in] op = opcode

    @return 0 in case of success, 1 if opcode was already present (not
    changed), -1 otherwise
*/
int GDD_arch_add_opcode(GDD_Arch *arch, GDD_Opcode *op) {
  return SCEDA_hashset_add(arch->opcodes, op);
}

/** Get the opcode of given mnemonic.

    @param[in] arch = architecture
    @param[in] mnemo = mnemonic

    @return the opcode of given mnemonic or NULL if not found */
GDD_Opcode *GDD_arch_get_opcode(GDD_Arch *arch, const char *mnemo) {
  GDD_Opcode tmp;
  tmp.mnemo = (char *)mnemo;
  GDD_Opcode *op = &tmp;
  if(SCEDA_hashset_lookup(arch->opcodes, (void **)&op) == 0) {
    return op;
  }
  return NULL;
}

/** Add registers of given type to the architecture.
    
    @param[in] arch = architecture
    @param[in] type = considered type
    @param[in] nb = number of registers (should be > 0)

    @return 0 in case of success, 1 if registers of the given type
    were already in the architecture (not modified), -1 otherwise */
int GDD_arch_add_regtype(GDD_Arch *arch, const char *type, int nb) {
  if(nb <= 0) {
    return -1;
  }
  TypeEntry *te = (TypeEntry *)safe_malloc(sizeof(TypeEntry));
  te->name = safe_strdup(type);
  te->nb = nb;
  return SCEDA_hashset_add(arch->types, te);
}

/** Get the number of registers of given type. 

    @param[in] arch = architecture 
    @param[in] type = considered type 

    @return the number of registers of considered type */
int GDD_arch_get_regtype(GDD_Arch *arch, const char *type) {
  TypeEntry tmp;
  tmp.name = (char *)type;
  TypeEntry *te = &tmp;
  if(SCEDA_hashset_lookup(arch->types, (void **)&te) == 0) {
    return te->nb;
  }
  return 0;
}

/** Modify the number of available registers of given type in the
    architecture.

    @param[in] arch = architecture
    @param[in] type = considered type
    @param[in] nb = new number of registers

    @return 0 in case of success, -1 otherwise */
int GDD_arch_set_regtype(GDD_Arch *arch, const char *type, int nb) {
  TypeEntry tmp;
  tmp.name = (char *)type;
  TypeEntry *te = &tmp;
  if(SCEDA_hashset_lookup(arch->types, (void **)&te) == 0) {
    te->nb = nb;
    return 0;
  }
  return -1;
}

/** Print the description of an architecture.

    @param[in] stream = file stream where to print
    @param[in] arch = architecture */
void GDD_arch_fprint(FILE *stream, GDD_Arch *arch) {
  SCEDA_HashSetIterator hiter;
  SCEDA_hashset_iterator_init(arch->types, &hiter);
  while(SCEDA_hashset_iterator_has_next(&hiter)) {
    TypeEntry *te = SCEDA_hashset_iterator_next(&hiter);
    fprintf(stream, "%d registers of type %s\n", te->nb, te->name);
  }
  SCEDA_hashset_iterator_cleanup(&hiter);

  SCEDA_hashset_iterator_init(arch->opcodes, &hiter);
  while(SCEDA_hashset_iterator_has_next(&hiter)) {
    GDD_Opcode *op = SCEDA_hashset_iterator_next(&hiter);
    fprintf(stream,"--\n");
    GDD_opcode_fprint(stream, op);
  }
  SCEDA_hashset_iterator_cleanup(&hiter);
  fprintf(stream,"--\n");
}

/** Return the next type in the iterator.

    @param[in] iter = iterator

    @return the type */
char *GDD_arch_types_iterator_next(GDD_ArchTypesIterator *aiter) {
  TypeEntry *t = SCEDA_hashset_iterator_next(aiter);
  return t->name;
}
back to top