1 /* radare - LGPL - Copyright 2014-2020 - condret, eagleoflqj	*/
2 
3 // http://datasheets.chipdb.org/Intel/MCS-4/datashts/MCS4_Data_Sheet_Nov71.pdf
4 // note: OPR of LD should be 1010 in the datasheet
5 
6 #include <r_types.h>
7 #include <r_util.h>
8 #include <r_asm.h>
9 #include <r_lib.h>
10 #include <ctype.h>
11 #include "../arch/i4004/i4004dis.c"
12 
disassemble(RAsm * a,RAsmOp * op,const ut8 * buf,int len)13 static int disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) {
14 	return i4004dis (op,buf,len);
15 }
16 
get_decimal(const char * s,int limit)17 static int get_decimal(const char *s, int limit) {
18 	int i, n;
19 	if (sscanf (s, "%d%n", &i, &n) == 1 && n == strlen (s) && i >= 0 && i <= limit) {
20 		return i;
21 	}
22 	return -1;
23 }
24 
get_int(const char * s,int limit)25 static int get_int(const char *s, int limit) {
26 	int i = get_decimal (s, limit), n;
27 	if (i >= 0) {
28 		return i;
29 	}
30 	if (!strncmp (s, "0x", 2) && sscanf (s, "%x%n", &i, &n) == 1 && n == strlen (s) && i <= limit) {
31 		return i;
32 	}
33 	return -1;
34 }
35 
get_reg(const char * s,int limit)36 static int get_reg(const char *s, int limit) {
37 	if (s[0] != 'r') {
38 		return -1;
39 	}
40 	return get_decimal (s + 1, limit);
41 }
42 
assemble(RAsm * a,RAsmOp * op,const char * str)43 static int assemble(RAsm *a, RAsmOp *op, const char *str) {
44 	ut8 buf[2];
45 	int len = 0;
46 	char *p = strchr(str, ' ');
47 	if (p) { // has arguments
48 		char mnemonic[4] = {0}, arg0[6] = {0}, arg1[5] = {0};
49 		size_t n = p - str;
50 		if (n > sizeof (mnemonic) - 1) {
51 			goto beach;
52 		}
53 		strncpy (mnemonic, str, n);
54 		while (*++p && isspace ((unsigned char)*p));
55 		n = strcspn (p, ", "); // next separator
56 		if (n > sizeof (arg0) - 1) {
57 			goto beach;
58 		}
59 		strncpy (arg0, p, n);
60 		p += n;
61 		if (*p) { // 2 arguments
62 			int comma = *p == ',';
63 			while (*++p) {
64 				if (*p == ',') {
65 					comma++;
66 				} else if (!isspace((unsigned char)*p)) {
67 					break;
68 				}
69 			}
70 			if (comma > 1 || strlen (p) > sizeof (arg1) - 1) {
71 				goto beach;
72 			}
73 			strcpy (arg1, p);
74 		}
75 		if (!strcmp (mnemonic, "jcn")) {
76 			int condition, address;
77 			if ((condition = get_int (arg0, 0xf)) < 0
78 				|| (address = get_int (arg1, 0xff)) < 0) {
79 				goto beach;
80 			}
81 			buf[0] = 0x10 | condition;
82 			buf[1] = address;
83 			len = 2;
84 		} else if (!strcmp (mnemonic, "fim")) {
85 			int reg, data;
86 			if ((reg = get_reg (arg0, 0xf)) < 0 || reg & 1 // reg pair => even index
87 				|| (data = get_int (arg1, 0xff)) < 0) {
88 				goto beach;
89 			}
90 			buf[0] = 0x20 | reg;
91 			buf[1] = data;
92 			len = 2;
93 		} else if (!strcmp (mnemonic, "isz")) {
94 			int reg, address;
95 			if ((reg = get_reg (arg0, 0xf)) < 0
96 				|| (address = get_int (arg1, 0xff)) < 0) {
97 				goto beach;
98 			}
99 			buf[0] = 0x70 | reg;
100 			buf[1] = address;
101 			len = 2;
102 		} else if (arg1[0]) { // must be one argument
103 			goto beach;
104 		}
105 		if (!strcmp (mnemonic, "src") || !strcmp (mnemonic, "fin") || !strcmp (mnemonic, "jin")) {
106 			int reg;
107 			if ((reg = get_reg (arg0, 0xf)) < 0 || reg & 1) {
108 				goto beach;
109 			}
110 			buf[0] = (mnemonic[0] == 's' ? 0x21 : mnemonic[0] == 'f' ? 0x30 : 0x31) | reg;
111 			len = 1;
112 		} else if (!strcmp (mnemonic, "jun") || !strcmp (mnemonic, "jms")) {
113 			int address;
114 			if ((address = get_int (arg0, 0xfff)) < 0) {
115 				goto beach;
116 			}
117 			buf[0] = (mnemonic[1] == 'u' ? 0x40 : 0x50) | (address >> 8);
118 			buf[1] = address & 0xff;
119 			len = 2;
120 		} else if (!strcmp (mnemonic, "bbl") || !strcmp (mnemonic, "ldm")) {
121 			int data;
122 			if ((data = get_int (arg0, 0xff)) < 0) {
123 				goto beach;
124 			}
125 			buf[0] = (mnemonic[0] == 'b' ? 0xc0 : 0xd0) | data;
126 			len = 1;
127 		} else {
128 			int reg;
129 			if ((reg = get_reg (arg0, 0xf)) < 0) {
130 				goto beach;
131 			}
132 			if (!strcmp (mnemonic, "inc")) {
133 				buf[0] = 0x60;
134 			} else if (!strcmp (mnemonic, "add")) {
135 				buf[0] = 0x80;
136 			} else if (!strcmp (mnemonic, "sub")) {
137 				buf[0] = 0x90;
138 			} else if (!strcmp (mnemonic, "ld")) {
139 				buf[0] = 0xa0;
140 			} else if (!strcmp (mnemonic, "xch")) {
141 				buf[0] = 0xb0;
142 			} else {
143 				goto beach;
144 			}
145 			buf[0] |= reg;
146 			len = 1;
147 		}
148 	} else if (!strcmp (str, "nop")) {
149 		buf[0] = 0x00;
150 		len = 1;
151 	} else {
152 		int i;
153 		for (i = 0; i < 16; i++) {
154 			if (!strcmp (str, i4004_e[i])) {
155 				buf[0] = 0xe0 | i;
156 				len = 1;
157 				goto beach;
158 			}
159 		}
160 		for (i = 0; i < 16; i++) {
161 			if (!strcmp (str, i4004_f[i])) {
162 				buf[0] = 0xf0 | i;
163 				len = 1;
164 				goto beach;
165 			}
166 		}
167 	}
168 beach:
169 	if (len) {
170 		r_strbuf_setbin (&op->buf, buf, len);
171 	}
172 	return op->size = len;
173 }
174 
175 RAsmPlugin r_asm_plugin_i4004 = {
176 	.name = "i4004",
177 	.desc = "Intel 4004 microprocessor",
178 	.arch = "i4004",
179 	.license = "LGPL3",
180 	.bits = 4,
181 	.endian = R_SYS_ENDIAN_NONE,
182 	.assemble = &assemble,
183 	.disassemble = &disassemble
184 };
185 
186 #ifndef R2_PLUGIN_INCORE
187 R_API RLibStruct radare_plugin = {
188 	.type = R_LIB_TYPE_ASM,
189 	.data = &r_asm_plugin_i4004,
190 	.version = R2_VERSION
191 };
192 #endif
193