Rizin
unix-like reverse engineering framework and cli tools
asm.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2012 Karl Hobley <turbodog10@yahoo.co.uk>
2 // SPDX-FileCopyrightText: 2012 pancake <pancake@nopcode.org>
3 // SPDX-License-Identifier: MIT
4 
5 /* this code has been modified to be integrated into r2 */
6 /* pancake // nopcode.org */
7 
8 /* dcpu16asm.c - Assembler for the DCPU-16 CPU
9  version 4.1, 5 April 2012
10 
11  Copyright (C) 2012 Karl Hobley
12 
13  Permission is hereby granted, free of charge, to any person
14  obtaining a copy of this software and associated documentation
15  files (the "Software"), to deal in the Software without
16  restriction, including without limitation the rights to use, copy,
17  modify, merge, publish, distribute, sublicense, and/or sell copies
18  of the Software, and to permit persons to whom the Software is
19  furnished to do so, subject to the following conditions:
20 
21  The above copyright notice and this permission notice shall be
22  included in all copies or substantial portions of the Software.
23 
24  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
26  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 
32  Karl Hobley <turbodog10@yahoo.co.uk>
33 */
34 
35 #include <stdio.h>
36 #include <ctype.h>
37 #include <string.h>
38 #include "dcpu16.h"
39 
40 #define NOTEND 1 /* endian hack */
41 
42 static ut8 get_register_id(char reg) {
43  const char *regs = "ABCXYZIJ";
44  const char *p = strchr(regs, reg);
45  return p ? (int)(size_t)(p - regs) : 0;
46 }
47 
48 static void clean_line(char *oline, const char *line) {
49  int cn = 0, n = 0;
50 
51  while (line[cn] != 0 && line[cn] != '\n' && line[cn] != ';') {
52  if (line[cn] >= '!' && line[cn] <= '~') {
53  char current_char = line[cn];
54 
55  /* Convert to upper case */
56  if (current_char >= 'a' && current_char <= 'z')
57  current_char = toupper((unsigned char)current_char);
58 
59  /* Place in cleaned line */
60  oline[n] = current_char;
61  n++;
62  }
63  cn++;
64  }
65  oline[n] = 0;
66 }
67 
68 /*
69  * Convert a parameter string. eg, "A", "0x1234", "[0x1234]" into a 6 bit value
70  */
71 static ut8 decode_parameter(char *param, int *extra_word_needed, ut16 *extra_word_value) {
72  /* Check for square brackets */
73  int square_brackets = 0;
74  int first_sqbracket = 0, last_sqbracket = 0;
75  if (param[0] == '[') {
76  first_sqbracket = 1;
77  param++;
78  }
79  if (param[strlen(param) - 1] == ']') {
80  last_sqbracket = 1;
81  param[strlen(param) - 1] = 0;
82  }
83 
84  /* Check for errors */
85  if (first_sqbracket == 1) {
86  square_brackets = 1;
87  if (last_sqbracket != 1) {
88  fprintf(stderr, "Missing last square bracket\n");
89  return 0;
90  }
91  } else {
92  if (last_sqbracket == 1) {
93  fprintf(stderr, "Missing first square bracket\n");
94  return 0;
95  }
96  }
97 
98  /* Check if this is a hex literal */
99  if (param[0] == '0' && param[1] == 'X') {
100  /* Decode hex */
101  ut16 value = 0;
102  param = param + 2; /* Remove 0x */
103  int digit_count = strlen(param);
104  int digit_num = 0;
105  int reg = -1;
106  for (digit_num = 0; digit_num < digit_count; digit_num++) {
107  /* Get Digit value */
108  int digit_val = -1;
109  char current_digit = param[digit_num];
110  if (current_digit >= '0' && current_digit <= '9')
111  digit_val = current_digit - '0';
112  if (current_digit >= 'A' && current_digit <= 'F')
113  digit_val = current_digit - 'A' + 10;
114 
115  if (current_digit == '+' && square_brackets == 1) {
116  reg = get_register_id(param[digit_num + 1]);
117  digit_num++;
118  } else {
119  /* Check for errors */
120  if (digit_val == -1) {
121  fprintf(stderr, "invalid literal\n");
122  return 0;
123  }
124 
125  /* Merge into final number */
126  value = (value << 4) + digit_val;
127  }
128  }
129 
130  if (value <= 0x1f && square_brackets == 0)
131  return value + 0x20;
132 
133  *extra_word_needed = 1;
134  *extra_word_value = value;
135 
136  if (square_brackets == 1) {
137  if (reg != -1)
138  return 0x10 + reg;
139  return 0x1e;
140  }
141  return 0x1f;
142  }
143 
144  /* Check if this is a decimal literal */
145  if (param[0] >= '0' && param[0] <= '9') {
146  /* Decode decimal */
147  ut16 value = 0;
148  int digit_count = strlen(param);
149  int digit_num = 0;
150  int reg = -1;
151  for (digit_num = 0; digit_num < digit_count; digit_num++) {
152  /* Get Digit value */
153  int digit_val = -1;
154  char current_digit = param[digit_num];
155  if (current_digit >= '0' && current_digit <= '9')
156  digit_val = current_digit - '0';
157 
158  if (current_digit == '+' && square_brackets == 1) {
159  reg = get_register_id(param[digit_num + 1]);
160  digit_num++;
161  } else {
162  /* Check for errors */
163  if (digit_val == -1) {
164  fprintf(stderr, "invalid literal\n");
165  return 0;
166  }
167 
168  /* Merge into final number */
169  value = (value * 10) + digit_val;
170  }
171  }
172  if (value <= 0x1f && square_brackets == 0)
173  return value + 0x20;
174 
175  *extra_word_needed = 1;
176  *extra_word_value = value;
177 
178  if (square_brackets == 1) {
179  if (reg != -1)
180  return 0x10 + reg;
181  return 0x1e;
182  }
183  return 0x1f;
184  }
185 
186  /* Check if this is a register */
187  if (param[1] == 0) { /* This is a quick way to check that this is 1 character long */
188  ut8 reg = get_register_id(param[0]);
189  if (square_brackets == 1)
190  reg += 0x08;
191  return reg;
192  }
193 
194  /* Check if this is a word */
195  if (!strncmp("POP", param, 3))
196  return 0x18;
197  if (!strncmp("PEEK", param, 4))
198  return 0x19;
199  if (!strncmp("PUSH", param, 4))
200  return 0x1a;
201  if (!strncmp("SP", param, 2))
202  return 0x1b;
203  if (!strncmp("PC", param, 2))
204  return 0x1c;
205  if (!strncmp("O", param, 1))
206  return 0x1d;
207 
208  /* Must be a label, store a labelref */
209  *extra_word_needed = 1;
210  /* Allocate blank extra word, this will be where the
211  pointer to the label will be stored at link stage */
212  *extra_word_value = 0;
213  return 0x1f;
214 }
215 
216 int dcpu16_assemble(ut8 *out, const char *unoline) {
217  ut16 wordA = 0, wordB = 0;
218  int basic_opcode = 0;
219  int non_basic_opcode = 0;
220  char line[256] = { 0 }, *param;
221  int off = 0;
222  // uberflow!
223  clean_line(line, unoline);
224 
225  if (!(*line))
226  return 0;
227  if (strlen(line) < 4)
228  return 0;
229  param = line + 3; /* Cut off first 3 characters */
230 
231  /* Basic instructions */
232  // cmon! use an array
233  if (!strncmp("SET", line, 3))
234  basic_opcode = 0x1;
235  else if (!strncmp("ADD", line, 3))
236  basic_opcode = 0x2;
237  else if (!strncmp("SUB", line, 3))
238  basic_opcode = 0x3;
239  else if (!strncmp("MUL", line, 3))
240  basic_opcode = 0x4;
241  else if (!strncmp("DIV", line, 3))
242  basic_opcode = 0x5;
243  else if (!strncmp("MOD", line, 3))
244  basic_opcode = 0x6;
245  else if (!strncmp("SHL", line, 3))
246  basic_opcode = 0x7;
247  else if (!strncmp("SHR", line, 3))
248  basic_opcode = 0x8;
249  else if (!strncmp("AND", line, 3))
250  basic_opcode = 0x9;
251  else if (!strncmp("BOR", line, 3))
252  basic_opcode = 0xA;
253  else if (!strncmp("XOR", line, 3))
254  basic_opcode = 0xB;
255  else if (!strncmp("IFE", line, 3))
256  basic_opcode = 0xC;
257  else if (!strncmp("IFN", line, 3))
258  basic_opcode = 0xD;
259  else if (!strncmp("IFG", line, 3))
260  basic_opcode = 0xE;
261  else if (!strncmp("IFB", line, 3))
262  basic_opcode = 0xF;
263 
264  /* Non basic instructions */
265  if (basic_opcode == 0) {
266  if (!strncmp("JSR", line, 3)) {
267  non_basic_opcode = 0x1;
268  } else {
269  fprintf(stderr, "Unknown instruction\n");
270  return -1;
271  }
272  }
273 
274  /* Decode basic instructions */
275  if (basic_opcode != 0) {
276  ut8 paramA = 0, paramB = 0;
277 
278  /* Find comma */
279  int cn = 0;
280  while (cn < 256 && param[cn] != ',' && param[cn] != '\n' && param[cn] != 0)
281  cn++;
282 
283  if (param[cn] == ',') {
284  ut16 first_word;
285  int extraA = 0;
286  int extraB = 0;
287  char *pa, *pb;
288  /* Split parameter string to A and B */
289  param[cn] = 0;
290  pa = param;
291  pb = param + cn + 1;
292 
293  /* Increment address for the start word */
294  // current_address++;
295 
296  /* Parameter A */
297  paramA = decode_parameter(pa, &extraA, &wordA);
298  // if (extraA == 1) current_address++;
299 
300  /* Parameter B */
301  paramB = decode_parameter(pb, &extraB, &wordB);
302  // if (extraB == 1) current_address++;
303 
304  /* Put everything together */
305  first_word = ((paramB & 0x3F) << 10) | ((paramA & 0x3F) << 4) | (basic_opcode & 0xF);
306 
307  /* write opcode */
308 #if NOTEND
309  memcpy(out, &first_word, 2);
310  if (extraA == 1) {
311  memcpy(out + 2, &wordA, 2);
312  off = 4;
313  } else
314  off = 2;
315  if (extraB == 1) {
316  memcpy(out + off, &wordB, 2);
317  off += 2;
318  }
319 #else
320  out[0] = (first_word >> 8) & 0xff;
321  out[1] = first_word & 0xff;
322  if (extraA == 1) {
323  out[2] = (wordA >> 8) & 0xff;
324  out[3] = wordA & 0xff;
325  off = 4;
326  } else
327  off = 2;
328  if (extraB == 1) {
329  out[off] = (wordB >> 8) & 0xff;
330  out[off + 1] = wordB & 0xff;
331  off += 2;
332  }
333 #endif
334  } else {
335  fprintf(stderr, "Missing comma\n");
336  return -1;
337  }
338  }
339 
340  /* Non basic instructions */
341  if (non_basic_opcode == 0x1) { /* JSR */
342  int extraX = 0;
343  ut16 first_word, wordX = 0;
344  ut8 p = decode_parameter(param, &extraX, &wordX);
345 
346  first_word = ((p & 0x3F) << 10) | ((non_basic_opcode & 0x3F) << 4) | (basic_opcode & 0xF);
347 #if NOTEND
348  memcpy(out, &first_word, 2);
349  if (extraX == 1) {
350  memcpy(out + 2, &wordX, 2);
351  off = 4;
352  } else
353  off = 2;
354 #else
355  out[0] = (first_word >> 8) & 0xff;
356  out[1] = first_word & 0xff;
357  if (extraX == 1) {
358  out[2] = (wordX >> 8) & 0xff;
359  out[3] = wordX & 0xff;
360  off = 4;
361  } else
362  off = 2;
363 #endif
364  }
365  return off;
366 }
static char * regs[]
Definition: analysis_sh.c:203
int dcpu16_assemble(ut8 *out, const char *unoline)
Definition: asm.c:216
static void clean_line(char *oline, const char *line)
Definition: asm.c:48
static ut8 decode_parameter(char *param, int *extra_word_needed, ut16 *extra_word_value)
Definition: asm.c:71
static ut8 get_register_id(char reg)
Definition: asm.c:42
const lzma_allocator const uint8_t size_t uint8_t * out
Definition: block.h:528
static int value
Definition: cmd_api.c:93
uint16_t ut16
#define reg(n)
uint8_t ut8
Definition: lh5801.h:11
void * p
Definition: libc.cpp:67
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
int n
Definition: mipsasm.c:19
line
Definition: setup.py:34
int off
Definition: pal.c:13
#define toupper(c)
Definition: safe-ctype.h:147
static int
Definition: sfsocketcall.h:114