summaryrefslogtreecommitdiffhomepage
path: root/mixlib/mix_ins.c
blob: 663591df5ae0fd957ff9745a02bc84ec4a57cd96 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/* -*-c-*- ------------------ mix_ins.c :
 * Implementation of the functions declared in mix_ins.h
 * ------------------------------------------------------------------
 * Copyright (C) 1999, 2003, 2007, 2010 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 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#include "mix_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)<<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));
}