-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathjrisc_inst.c
296 lines (234 loc) · 6.85 KB
/
jrisc_inst.c
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
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
/*
* SPDX-License-Identifier: CC0-1.0
*
* Author: James Jones
*/
#include "jrisc_base.h"
#include "jrisc_ctx.h"
#include "jrisc_inst.h"
#include <stddef.h>
#include <assert.h>
const struct JRISC_Instruction
jriscInstructionTable[] = {
#define JRISC_OP(opName, opNum, regSrcType, regDstType, swapRegs, cpus) \
{ \
/* .opName = */ JRISC_op_##opName, \
/* .opCode = */ opNum, \
/* .regSrc.type = */ { regSrcType }, \
/* .regDst.type = */ { regDstType }, \
/* .swapRegs = */ swapRegs, \
/* .cpu = */ cpus, \
/* .longImmediate = */ 0 \
},
#include "jrisc_optable.h"
#undef JRISC_OP
};
static const struct JRISC_Instruction *
jriscInstructionsFromOpCode(uint8_t opCode)
{
unsigned i;
/*
* Table is sorted on raw op code values, and is a superset of those values.
* Any operations associated with this opCode will appear no earlier than
* <opCode> entries into the table.
*/
for (i = opCode; i < JRISC_invalidOpName; i++) {
if (jriscInstructionTable[i].opCode == opCode) {
return &jriscInstructionTable[i];
}
}
return NULL;
}
static bool
jriscInstructionMatchesRaw(const struct JRISC_Instruction *instruction,
uint8_t opCode,
uint8_t rawSrc,
enum JRISC_CPU cpu)
{
/* The instruction's raw opcode number must match that specified */
if (instruction->opCode != opCode) return false;
/* The instruction must be compatible with the specified CPU */
if ((instruction->cpu != JRISC_both) &&
(instruction->cpu != cpu)) return false;
/* The pack & unpack instructions are differentiated by their rawSrc val */
if ((instruction->opName == JRISC_op_pack) && (rawSrc != 0)) return false;
if ((instruction->opName == JRISC_op_unpack) && (rawSrc != 1)) return false;
return true;
}
static enum JRISC_Error
jriscValidateReg(uint8_t raw, enum JRISC_Reg *regOut)
{
if (raw & ~JRISC_REG_MASK) {
return JRISC_ERROR_invalidReg;
}
*regOut = (enum JRISC_Reg)raw;
return JRISC_success;
}
static enum JRISC_Error
jriscValidateCondition(uint8_t raw, uint8_t *conditionOut)
{
if (raw & ~JRISC_REG_MASK) {
return JRISC_ERROR_invalidValue;
}
*conditionOut = raw;
return JRISC_success;
}
static enum JRISC_Error
jriscValidateImmediate(uint8_t raw, uint8_t *immediateOut)
{
if (raw & ~JRISC_REG_MASK) {
return JRISC_ERROR_invalidValue;
}
*immediateOut = raw;
return JRISC_success;
}
static enum JRISC_Error
jriscValidateFlag(uint8_t raw, bool *flagOut)
{
if (raw & ~0x1) {
return JRISC_ERROR_invalidValue;
}
*flagOut = (bool)raw;
return JRISC_success;
}
static enum JRISC_Error
jriscRegFromRaw(uint8_t raw,
enum JRISC_RegType type,
struct JRISC_OpReg *regOut)
{
struct JRISC_OpReg out = { type };
enum JRISC_Error ret = JRISC_success;
switch (type) {
case JRISC_indirect: /* Fall through */
case JRISC_reg:
ret = jriscValidateReg(raw, &out.val.reg);
if (ret != JRISC_success) return ret;
break;
case JRISC_condition:
ret = jriscValidateCondition(raw, &out.val.condition);
if (ret != JRISC_success) return ret;
break;
case JRISC_pcoffset: /* Fall through */
case JRISC_simmediate: /* Fall through */
case JRISC_shlimmediate: /* Fall through */
case JRISC_uimmediate: /* Fall through */
case JRISC_zuimmediate: /* Fall through*/
ret = jriscValidateImmediate(raw, &out.val.uimmediate);
if (ret != JRISC_success) return ret;
if (((type == JRISC_pcoffset) || (type == JRISC_simmediate)) &&
(out.val.uimmediate & 0x10)) {
out.val.simmediate = out.val.simmediate | 0xe0;
}
break;
case JRISC_flag:
ret = jriscValidateFlag(raw, &out.val.flag);
if (ret != JRISC_success) return ret;
break;
case JRISC_unused:
/* Nothing to do. Could validate it is zero and warn */
break;
default:
return JRISC_ERROR_invalidRegType;
}
*regOut = out;
return ret;
}
uint8_t
jriscRegToRaw(const struct JRISC_OpReg *reg)
{
switch (reg->type) {
case JRISC_indirect: /* Fall through */
case JRISC_reg:
return (uint8_t)reg->val.reg;
case JRISC_condition:
return reg->val.condition;
case JRISC_shlimmediate: /* Fall through */
case JRISC_uimmediate: /* Fall through */
case JRISC_zuimmediate:
return reg->val.uimmediate;
case JRISC_pcoffset: /* Fall through */
case JRISC_simmediate:
return (uint8_t)(reg->val.simmediate & JRISC_REG_MASK);
case JRISC_flag:
return reg->val.flag ? 1 : 0;
case JRISC_unused:
return 0;
default:
assert(!"Unreachable!");
return 0;
}
}
static const struct JRISC_Instruction *
jriscNextInstruction(const struct JRISC_Instruction *current)
{
uint8_t opNameVal = current->opName;
if ((opNameVal + 1) >= JRISC_invalidOpName) return NULL;
return ++current;
}
enum JRISC_Error
jriscInstructionRead(struct JRISC_Context *context,
enum JRISC_CPU cpu,
struct JRISC_Instruction *instructionOut)
{
const struct JRISC_Instruction *templates;
const struct JRISC_Instruction *match = NULL;
struct JRISC_Instruction out;
enum JRISC_Error ret;
uint32_t address;
uint16_t rawImmediate;
uint16_t raw;
uint8_t rawCode;
uint8_t rawSrc;
uint8_t rawDst;
ret = context->read(context, sizeof(raw), &raw, &address);
if (ret != JRISC_success) return ret;
/* XXX swap at appropriate times */
raw = (raw << 8) | (raw >> 8);
rawCode = raw >> JRISC_OPCODE_SHIFT;
rawSrc = (raw >> JRISC_REGSRC_SHIFT) & JRISC_REG_MASK;
rawDst = raw & JRISC_REG_MASK;
templates = jriscInstructionsFromOpCode(rawCode);
if (!templates) return JRISC_ERROR_invalidOpCode;
do {
if (jriscInstructionMatchesRaw(templates, rawCode, rawSrc, cpu)) {
match = templates;
break;
}
} while ((templates = jriscNextInstruction(templates)) &&
(templates->opCode == rawCode));
if (!match) return JRISC_ERROR_invalidOpCode;
out = *match;
out.address = address;
ret = jriscRegFromRaw(rawSrc, match->regSrc.type, &out.regSrc);
if (ret != JRISC_success) return ret;
ret = jriscRegFromRaw(rawDst, match->regDst.type, &out.regDst);
if (ret != JRISC_success) return ret;
/*
* movei is special: Its immediate value is taken from the two following
* "instruction" slots.
*/
if (out.opName == JRISC_op_movei) {
ret = context->read(context, sizeof(rawImmediate), &rawImmediate, NULL);
if (ret != JRISC_success) return ret;
/* XXX swap at appropriate times */
rawImmediate = (rawImmediate << 8) | (rawImmediate >> 8);
out.longImmediate = rawImmediate;
ret = context->read(context, sizeof(rawImmediate), &rawImmediate, NULL);
if (ret != JRISC_success) return ret;
/* XXX swap at appropriate times */
rawImmediate = (rawImmediate << 8) | (rawImmediate >> 8);
out.longImmediate |= (uint32_t)rawImmediate << 16;
}
*instructionOut = out;
return ret;
}
uint16_t
jriscInstructionLongImmediateLow(const struct JRISC_Instruction *instruction)
{
return instruction->longImmediate & 0xffff;
}
uint16_t
jriscInstructionLongImmediateHigh(const struct JRISC_Instruction *instruction)
{
return instruction->longImmediate >> 16;
}