/*
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/>.
*/
#ifndef __GDD_OPCODE_H
#define __GDD_OPCODE_H
/** \file opcode.h
\brief Opcode description */
#include <stdio.h>
#include <SCEDA/hashmap.h>
/** Type of opcodes */
typedef struct {
char *mnemo;
int latency;
int dflt_dr;
SCEDA_HashMap *delta_r;
SCEDA_HashMap *delta_w;
} GDD_Opcode;
/** Create a new opcode .
@param[in] mnemo = mnemonic
@param[in] latency = latency
@param[in] dflt_dr = default read delay offset
@return the opcode */
GDD_Opcode *GDD_opcode_create(const char *mnemo, int latency, int dflt_dr);
/** Delete an opcode.
@param[in] op = opcode */
void GDD_opcode_delete(GDD_Opcode *op);
/** Extend delta_r function (read delay offset) of given opcode.
@param[in] op = opcode
@param[in] type = considered type
@param[in] read = read delay offset for type
@return 0 in case of success, or -1 in case of failure (e.g. if
trying to redefine delta_r with another value).
*/
int GDD_opcode_extend_delta_r(GDD_Opcode *op, const char *type, int read);
/** Extend delta_w function (write delay offset) of given opcode.
@param[in] op = opcode
@param[in] type = considered type
@param[in] write = write delay offset for type
@return 0 in case of success, or -1 in case of failure (e.g. if
trying to redefine delta_r with another value).
*/
int GDD_opcode_extend_delta_w(GDD_Opcode *op, const char *type, int write);
/** Get the value of read delay offset
@param[in] op = opcode
@param[in] type = considered type
@return read delay offset (or default read delay offset)
if type == NULL, return default read delay offset
*/
int GDD_opcode_delta_r(GDD_Opcode *op, const char *type);
/** Get the value of write delay offset
@param[in] op = opcode
@param[in] type = considered type
@return write delay offset (0 by default) */
int GDD_opcode_delta_w(GDD_Opcode *op, const char *type);
/** Test whether an opcode is a value of given type.
@param[in] op = opcode
@param[in] type = type
@return TRUE if op is a value of type type, FALSE otherwise */
int GDD_opcode_is_value(GDD_Opcode *op, const char *type);
/** Print the description of an opcode, including its delay offsets.
@param[in] stream = file stream where to print
@param[in] op = opcode to print */
void GDD_opcode_fprint(FILE *stream, GDD_Opcode *op);
/** Get the mnemonic of an opcode
@param[in] op = opcode
@return the mnemonic of op
\hideinitializer */
#define GDD_opcode_mnemonic(op) ((op)->mnemo)
/** Get the latency of an opcode
@param[in] op = opcode
@return the latency of op
\hideinitializer */
#define GDD_opcode_latency(op) ((op)->latency)
#endif
/** \page opcode Opcodes
\section opcode_intro Introduction
An opcode is defined by its mnemonic and its latency. If \f$o\f$
is an opcode, we write \f$\mathop{mnemo}(o)\f$ for its mnemonic
and \f$\mathop{lat}(o)\f$ for its latency.
In our processor model, an opcode may also have different read or
write delay offsets for each register type. A default read delay
offset may be defined. If \f$t \in \mathcal{T}\f$ is a register
type, we write \f$\delta_r^t(o)\f$ for the read delay offset and
\f$\delta_w^t(o)\f$ for the write delay offset.
If, for a given type \f$t\f$, the write delay offset is not
defined, this means that the opcode does not produce a value of
type \f$t\f$. Otherwise, we say, by abuse of language, that it \em is
a value of type \f$t\f$.
Implicitly, we assume that the following inequalities hold \f$0 \leq
\delta_r^t(o) \leq \delta_w^t(o) < \mathop{lat}(o)\f$ (when
defined).
For convenient memory management, opcodes may be gathered into an
architecture (see \ref arch).
\section opcode_api API
\code
GDD_Opcode *GDD_opcode_create(const char *mnemo, int latency, int dflt_dr);
\endcode
Create a new opcode, with given mnemonic, latency and default read
delay offset.
\code
void GDD_opcode_delete(GDD_Opcode *op);
\endcode
Delete an opcode.
\code
int GDD_opcode_extend_delta_r(GDD_Opcode *op, const char *type, int read);
int GDD_opcode_extend_delta_w(GDD_Opcode *op, const char *type, int write);
\endcode
Define a read (resp. write) delay offset for the given register
type.
\code
int GDD_opcode_delta_r(GDD_Opcode *op, const char *type);
int GDD_opcode_delta_w(GDD_Opcode *op, const char *type);
\endcode
Return the read (resp. write) delay offset for the given register
type.
The default read delay offset is returned when delta_r is not defined on the given type.
When delta_w is not defined on the given type, it returns 0.
\code
int GDD_opcode_is_value(GDD_Opcode *op, const char *type);
\endcode
Test whether the given opcode procudes a value of given type. It
returns TRUE if and only if delta_w is defined on given type.
\code
char *GDD_opcode_mnemonic(GDD_Opcode *op);
\endcode
Return the mnemonic of the given opcode.
\code
int GDD_opcode_latency(GDD_Opcode *op);
\endcode
Return the latency of the given opcode.
\code
void GDD_opcode_fprint(FILE *stream, GDD_Opcode *op);
\endcode
Print the opcode on the given stream.
\section opcode_example Example
The following example creates an opcode for mnemonic "add" with a
latency of 2 and a default read delay offset of 0.
It then defines a read delay offset of 1 for register type "FR"
and a write delay offset of 1 for register types "GR" and "FR".
It then prints it on standard output.
Finally, the opcode is deleted.
\include "opcode/main.c"
*/