]>
Commit | Line | Data |
---|---|---|
3346cfda NC |
1 | /* Simulator for TI MSP430 and MSP430X |
2 | ||
ecd75fc8 | 3 | Copyright (C) 2013-2014 Free Software Foundation, Inc. |
3346cfda NC |
4 | Contributed by Red Hat. |
5 | Based on sim/bfin/bfin-sim.c which was contributed by Analog Devices, Inc. | |
6 | ||
7 | This file is part of simulators. | |
8 | ||
9 | This program is free software; you can redistribute it and/or modify | |
10 | it under the terms of the GNU General Public License as published by | |
11 | the Free Software Foundation; either version 3 of the License, or | |
12 | (at your option) any later version. | |
13 | ||
14 | This program is distributed in the hope that it will be useful, | |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | GNU General Public License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
21 | ||
22 | #include "config.h" | |
23 | #include <stdio.h> | |
24 | #include <stdlib.h> | |
25 | #include <string.h> | |
26 | #include <inttypes.h> | |
27 | #include <assert.h> | |
28 | #include "bfd.h" | |
29 | #include "opcode/msp430-decode.h" | |
30 | #include "sim-main.h" | |
31 | #include "dis-asm.h" | |
32 | #include "targ-vals.h" | |
33 | ||
34 | static int | |
35 | loader_write_mem (SIM_DESC sd, | |
36 | SIM_ADDR taddr, | |
37 | const unsigned char *buf, | |
38 | int bytes) | |
39 | { | |
40 | SIM_CPU *cpu = MSP430_CPU (sd); | |
41 | return sim_core_write_buffer (sd, cpu, write_map, buf, taddr, bytes); | |
42 | } | |
43 | ||
44 | static sim_cia | |
45 | msp430_pc_fetch (SIM_CPU *cpu) | |
46 | { | |
47 | return cpu->state.regs[0]; | |
48 | } | |
49 | ||
50 | static void | |
51 | msp430_pc_store (SIM_CPU *cpu, sim_cia newpc) | |
52 | { | |
53 | cpu->state.regs[0] = newpc; | |
54 | } | |
55 | ||
56 | static long | |
57 | lookup_symbol (SIM_DESC sd, const char *name) | |
58 | { | |
59 | struct bfd *abfd = STATE_PROG_BFD (sd); | |
60 | asymbol **symbol_table = STATE_SYMBOL_TABLE (sd); | |
61 | long number_of_symbols = STATE_NUM_SYMBOLS (sd); | |
62 | long i; | |
63 | ||
64 | if (symbol_table == NULL) | |
65 | { | |
66 | long storage_needed; | |
67 | ||
68 | storage_needed = bfd_get_symtab_upper_bound (abfd); | |
69 | if (storage_needed <= 0) | |
70 | return -1; | |
71 | ||
72 | STATE_SYMBOL_TABLE (sd) = symbol_table = xmalloc (storage_needed); | |
73 | STATE_NUM_SYMBOLS (sd) = number_of_symbols = | |
74 | bfd_canonicalize_symtab (abfd, symbol_table); | |
75 | } | |
76 | ||
77 | for (i = 0; i < number_of_symbols; i++) | |
78 | if (strcmp (symbol_table[i]->name, name) == 0) | |
79 | { | |
80 | long val = symbol_table[i]->section->vma + symbol_table[i]->value; | |
81 | return val; | |
82 | } | |
83 | return -1; | |
84 | } | |
85 | ||
86 | static int | |
87 | msp430_reg_fetch (SIM_CPU *cpu, int regno, unsigned char *buf, int len) | |
88 | { | |
89 | if (0 <= regno && regno < 16) | |
90 | { | |
91 | if (len == 2) | |
92 | { | |
93 | int val = cpu->state.regs[regno]; | |
94 | buf[0] = val & 0xff; | |
95 | buf[1] = (val >> 8) & 0xff; | |
96 | return 0; | |
97 | } | |
98 | else if (len == 4) | |
99 | { | |
100 | int val = cpu->state.regs[regno]; | |
101 | buf[0] = val & 0xff; | |
102 | buf[1] = (val >> 8) & 0xff; | |
103 | buf[2] = (val >> 16) & 0x0f; /* Registers are only 20 bits wide. */ | |
104 | buf[3] = 0; | |
105 | return 0; | |
106 | } | |
107 | else | |
108 | return -1; | |
109 | } | |
110 | else | |
111 | return -1; | |
112 | } | |
113 | ||
114 | static int | |
115 | msp430_reg_store (SIM_CPU *cpu, int regno, unsigned char *buf, int len) | |
116 | { | |
117 | if (0 <= regno && regno < 16) | |
118 | { | |
119 | if (len == 2) | |
120 | { | |
121 | cpu->state.regs[regno] = (buf[1] << 8) | buf[0]; | |
122 | return len; | |
123 | } | |
124 | ||
125 | if (len == 4) | |
126 | { | |
127 | cpu->state.regs[regno] = ((buf[2] << 16) & 0xf0000) | |
128 | | (buf[1] << 8) | buf[0]; | |
129 | return len; | |
130 | } | |
131 | } | |
132 | ||
133 | return -1; | |
134 | } | |
135 | ||
136 | static inline void | |
137 | msp430_initialize_cpu (SIM_DESC sd, SIM_CPU *cpu) | |
138 | { | |
139 | memset (&cpu->state, 0, sizeof (cpu->state)); | |
140 | } | |
141 | ||
142 | SIM_DESC | |
143 | sim_open (SIM_OPEN_KIND kind, | |
144 | struct host_callback_struct *callback, | |
145 | struct bfd *abfd, | |
146 | char **argv) | |
147 | { | |
148 | SIM_DESC sd = sim_state_alloc (kind, callback); | |
149 | char c; | |
150 | struct bfd *prog_bfd; | |
151 | ||
152 | /* Initialise the simulator. */ | |
153 | ||
154 | if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) != SIM_RC_OK) | |
155 | { | |
156 | sim_state_free (sd); | |
157 | return 0; | |
158 | } | |
159 | ||
160 | if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK) | |
161 | { | |
162 | sim_state_free (sd); | |
163 | return 0; | |
164 | } | |
165 | ||
166 | if (sim_parse_args (sd, argv) != SIM_RC_OK) | |
167 | { | |
168 | sim_state_free (sd); | |
169 | return 0; | |
170 | } | |
171 | ||
172 | CPU_PC_FETCH (MSP430_CPU (sd)) = msp430_pc_fetch; | |
173 | CPU_PC_STORE (MSP430_CPU (sd)) = msp430_pc_store; | |
174 | CPU_REG_FETCH (MSP430_CPU (sd)) = msp430_reg_fetch; | |
175 | CPU_REG_STORE (MSP430_CPU (sd)) = msp430_reg_store; | |
176 | ||
177 | /* Allocate memory if none specified by user. */ | |
178 | if (sim_core_read_buffer (sd, MSP430_CPU (sd), read_map, &c, 0x200, 1) == 0) | |
179 | sim_do_commandf (sd, "memory-region 0,0x10000"); | |
180 | if (sim_core_read_buffer (sd, MSP430_CPU (sd), read_map, &c, 0xfffe, 1) == 0) | |
181 | sim_do_commandf (sd, "memory-region 0xfffe,2"); | |
182 | if (sim_core_read_buffer (sd, MSP430_CPU (sd), read_map, &c, 0x10000, 1) == 0) | |
183 | sim_do_commandf (sd, "memory-region 0x10000,0x100000"); | |
184 | ||
185 | /* Check for/establish the a reference program image. */ | |
186 | if (sim_analyze_program (sd, | |
187 | (STATE_PROG_ARGV (sd) != NULL | |
188 | ? *STATE_PROG_ARGV (sd) | |
189 | : NULL), abfd) != SIM_RC_OK) | |
190 | { | |
191 | sim_state_free (sd); | |
192 | return 0; | |
193 | } | |
194 | ||
195 | prog_bfd = sim_load_file (sd, argv[0], callback, | |
196 | "the program", | |
197 | STATE_PROG_BFD (sd), | |
198 | 0 /* verbose */, | |
199 | 1 /* use LMA instead of VMA */, | |
200 | loader_write_mem); | |
201 | if (prog_bfd == NULL) | |
202 | { | |
203 | sim_state_free (sd); | |
204 | return 0; | |
205 | } | |
206 | ||
207 | /* Establish any remaining configuration options. */ | |
208 | if (sim_config (sd) != SIM_RC_OK) | |
209 | { | |
210 | sim_state_free (sd); | |
211 | return 0; | |
212 | } | |
213 | ||
214 | if (sim_post_argv_init (sd) != SIM_RC_OK) | |
215 | { | |
216 | sim_state_free (sd); | |
217 | return 0; | |
218 | } | |
219 | ||
220 | /* CPU specific initialization. */ | |
221 | assert (MAX_NR_PROCESSORS == 1); | |
222 | msp430_initialize_cpu (sd, MSP430_CPU (sd)); | |
223 | ||
224 | msp430_trace_init (STATE_PROG_BFD (sd)); | |
225 | ||
226 | MSP430_CPU (sd)->state.cio_breakpoint = lookup_symbol (sd, "C$$IO$$"); | |
227 | MSP430_CPU (sd)->state.cio_buffer = lookup_symbol (sd, "__CIOBUF__"); | |
228 | if (MSP430_CPU (sd)->state.cio_buffer == -1) | |
229 | MSP430_CPU (sd)->state.cio_buffer = lookup_symbol (sd, "_CIOBUF_"); | |
230 | ||
231 | return sd; | |
232 | } | |
233 | ||
234 | void | |
235 | sim_close (SIM_DESC sd, | |
236 | int quitting) | |
237 | { | |
238 | free (STATE_SYMBOL_TABLE (sd)); | |
239 | sim_state_free (sd); | |
240 | } | |
241 | ||
242 | SIM_RC | |
243 | sim_create_inferior (SIM_DESC sd, | |
244 | struct bfd *abfd, | |
245 | char **argv, | |
246 | char **env) | |
247 | { | |
248 | unsigned char resetv[2]; | |
249 | int c; | |
250 | int new_pc; | |
251 | ||
252 | c = sim_core_read_buffer (sd, MSP430_CPU (sd), read_map, resetv, 0xfffe, 2); | |
253 | ||
254 | new_pc = resetv[0] + 256 * resetv[1]; | |
255 | sim_pc_set (MSP430_CPU (sd), new_pc); | |
256 | msp430_pc_store (MSP430_CPU (sd), new_pc); | |
257 | ||
258 | return SIM_RC_OK; | |
259 | } | |
260 | ||
261 | typedef struct | |
262 | { | |
263 | SIM_DESC sd; | |
264 | int gb_addr; | |
265 | } Get_Byte_Local_Data; | |
266 | ||
267 | static int | |
268 | msp430_getbyte (void *vld) | |
269 | { | |
270 | Get_Byte_Local_Data *ld = (Get_Byte_Local_Data *)vld; | |
271 | char buf[1]; | |
272 | SIM_DESC sd = ld->sd; | |
273 | ||
274 | sim_core_read_buffer (sd, MSP430_CPU (sd), read_map, buf, ld->gb_addr, 1); | |
275 | ld->gb_addr ++; | |
276 | return buf[0]; | |
277 | } | |
278 | ||
279 | #define REG(N) MSP430_CPU (sd)->state.regs[(N)] | |
280 | #define PC REG(MSR_PC) | |
281 | #define SP REG(MSR_SP) | |
282 | #define SR REG(MSR_SR) | |
283 | ||
284 | static const char * | |
285 | register_names[] = | |
286 | { | |
287 | "PC", "SP", "SR", "CG", "R4", "R5", "R6", "R7", "R8", | |
288 | "R9", "R10", "R11", "R12", "R13", "R14", "R15" | |
289 | }; | |
290 | ||
291 | static void | |
292 | trace_reg_put (SIM_DESC sd, int n, unsigned int v) | |
293 | { | |
294 | if (TRACE_VPU_P (MSP430_CPU (sd))) | |
295 | trace_generic (sd, MSP430_CPU (sd), TRACE_VPU_IDX, | |
296 | "PUT: %#x -> %s", v, register_names [n]); | |
297 | REG (n) = v; | |
298 | } | |
299 | ||
300 | static unsigned int | |
301 | trace_reg_get (SIM_DESC sd, int n) | |
302 | { | |
303 | if (TRACE_VPU_P (MSP430_CPU (sd))) | |
304 | trace_generic (sd, MSP430_CPU (sd), TRACE_VPU_IDX, | |
305 | "GET: %s -> %#x", register_names [n], REG (n)); | |
306 | return REG (n); | |
307 | } | |
308 | ||
309 | #define REG_PUT(N,V) trace_reg_put (sd, N, V) | |
310 | #define REG_GET(N) trace_reg_get (sd, N) | |
311 | ||
312 | static int | |
313 | get_op (SIM_DESC sd, MSP430_Opcode_Decoded *opc, int n) | |
314 | { | |
315 | MSP430_Opcode_Operand *op = opc->op + n; | |
316 | int rv; | |
317 | int addr; | |
318 | unsigned char buf[4]; | |
319 | int incval = 0; | |
320 | ||
321 | switch (op->type) | |
322 | { | |
323 | case MSP430_Operand_Immediate: | |
324 | rv = op->addend; | |
325 | break; | |
326 | case MSP430_Operand_Register: | |
327 | rv = REG_GET (op->reg); | |
328 | break; | |
329 | case MSP430_Operand_Indirect: | |
330 | case MSP430_Operand_Indirect_Postinc: | |
331 | addr = op->addend; | |
332 | if (op->reg != MSR_None) | |
333 | { | |
334 | int reg; | |
335 | /* Index values are signed, but the sum is limited to 16 | |
336 | bits if the register < 64k, for MSP430 compatibility in | |
337 | MSP430X chips. */ | |
338 | if (addr & 0x8000) | |
339 | addr |= -1 << 16; | |
340 | reg = REG_GET (op->reg); | |
341 | addr += reg; | |
342 | if (reg < 0x10000 && ! opc->ofs_430x) | |
343 | addr &= 0xffff; | |
344 | } | |
345 | addr &= 0xfffff; | |
346 | switch (opc->size) | |
347 | { | |
348 | case 8: | |
349 | sim_core_read_buffer (sd, MSP430_CPU (sd), read_map, buf, addr, 1); | |
350 | rv = buf[0]; | |
351 | break; | |
352 | case 16: | |
353 | sim_core_read_buffer (sd, MSP430_CPU (sd), read_map, buf, addr, 2); | |
354 | rv = buf[0] | (buf[1] << 8); | |
355 | break; | |
356 | case 20: | |
357 | case 32: | |
358 | sim_core_read_buffer (sd, MSP430_CPU (sd), read_map, buf, addr, 4); | |
359 | rv = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); | |
360 | break; | |
361 | default: | |
362 | assert (! opc->size); | |
363 | break; | |
364 | } | |
365 | #if 0 | |
366 | /* Hack - MSP430X5438 serial port status register. */ | |
367 | if (addr == 0x5dd) | |
368 | rv = 2; | |
369 | #endif | |
370 | if (TRACE_MEMORY_P (MSP430_CPU (sd))) | |
371 | trace_generic (sd, MSP430_CPU (sd), TRACE_MEMORY_IDX, | |
372 | "GET: [%#x].%d -> %#x", addr, opc->size, rv); | |
373 | break; | |
374 | default: | |
375 | fprintf (stderr, "invalid operand %d type %d\n", n, op->type); | |
376 | abort (); | |
377 | } | |
378 | ||
379 | switch (opc->size) | |
380 | { | |
381 | case 8: | |
382 | rv &= 0xff; | |
383 | incval = 1; | |
384 | break; | |
385 | case 16: | |
386 | rv &= 0xffff; | |
387 | incval = 2; | |
388 | break; | |
389 | case 20: | |
390 | rv &= 0xfffff; | |
391 | incval = 4; | |
392 | break; | |
393 | case 32: | |
394 | rv &= 0xffffffff; | |
395 | incval = 4; | |
396 | break; | |
397 | } | |
398 | ||
399 | if (op->type == MSP430_Operand_Indirect_Postinc) | |
400 | REG_PUT (op->reg, REG_GET (op->reg) + incval); | |
401 | ||
402 | return rv; | |
403 | } | |
404 | ||
405 | static int | |
406 | put_op (SIM_DESC sd, MSP430_Opcode_Decoded *opc, int n, int val) | |
407 | { | |
408 | MSP430_Opcode_Operand *op = opc->op + n; | |
409 | int rv; | |
410 | int addr; | |
411 | unsigned char buf[4]; | |
412 | int incval = 0; | |
413 | ||
414 | switch (opc->size) | |
415 | { | |
416 | case 8: | |
417 | val &= 0xff; | |
418 | break; | |
419 | case 16: | |
420 | val &= 0xffff; | |
421 | break; | |
422 | case 20: | |
423 | val &= 0xfffff; | |
424 | break; | |
425 | case 32: | |
426 | val &= 0xffffffff; | |
427 | break; | |
428 | } | |
429 | ||
430 | switch (op->type) | |
431 | { | |
432 | case MSP430_Operand_Register: | |
433 | REG (op->reg) = val; | |
434 | REG_PUT (op->reg, val); | |
435 | break; | |
436 | case MSP430_Operand_Indirect: | |
437 | case MSP430_Operand_Indirect_Postinc: | |
438 | addr = op->addend; | |
439 | if (op->reg != MSR_None) | |
440 | { | |
441 | int reg; | |
442 | /* Index values are signed, but the sum is limited to 16 | |
443 | bits if the register < 64k, for MSP430 compatibility in | |
444 | MSP430X chips. */ | |
445 | if (addr & 0x8000) | |
446 | addr |= -1 << 16; | |
447 | reg = REG_GET (op->reg); | |
448 | addr += reg; | |
449 | if (reg < 0x10000) | |
450 | addr &= 0xffff; | |
451 | } | |
452 | addr &= 0xfffff; | |
453 | ||
454 | if (TRACE_MEMORY_P (MSP430_CPU (sd))) | |
455 | trace_generic (sd, MSP430_CPU (sd), TRACE_MEMORY_IDX, | |
456 | "PUT: [%#x].%d <- %#x", addr, opc->size, val); | |
457 | #if 0 | |
458 | /* Hack - MSP430X5438 serial port transmit register. */ | |
459 | if (addr == 0x5ce) | |
460 | putchar (val); | |
461 | #endif | |
462 | switch (opc->size) | |
463 | { | |
464 | case 8: | |
465 | buf[0] = val; | |
466 | sim_core_write_buffer (sd, MSP430_CPU (sd), write_map, buf, addr, 1); | |
467 | break; | |
468 | case 16: | |
469 | buf[0] = val; | |
470 | buf[1] = val >> 8; | |
471 | sim_core_write_buffer (sd, MSP430_CPU (sd), write_map, buf, addr, 2); | |
472 | break; | |
473 | case 20: | |
474 | case 32: | |
475 | buf[0] = val; | |
476 | buf[1] = val >> 8; | |
477 | buf[2] = val >> 16; | |
478 | buf[3] = val >> 24; | |
479 | sim_core_write_buffer (sd, MSP430_CPU (sd), write_map, buf, addr, 4); | |
480 | break; | |
481 | default: | |
482 | assert (! opc->size); | |
483 | break; | |
484 | } | |
485 | break; | |
486 | default: | |
487 | fprintf (stderr, "invalid operand %d type %d\n", n, op->type); | |
488 | abort (); | |
489 | } | |
490 | ||
491 | switch (opc->size) | |
492 | { | |
493 | case 8: | |
494 | rv &= 0xff; | |
495 | incval = 1; | |
496 | break; | |
497 | case 16: | |
498 | rv &= 0xffff; | |
499 | incval = 2; | |
500 | break; | |
501 | case 20: | |
502 | rv &= 0xfffff; | |
503 | incval = 4; | |
504 | break; | |
505 | case 32: | |
506 | rv &= 0xffffffff; | |
507 | incval = 4; | |
508 | break; | |
509 | } | |
510 | ||
511 | if (op->type == MSP430_Operand_Indirect_Postinc) | |
512 | { | |
513 | int new_val = REG_GET (op->reg) + incval; | |
514 | /* SP is always word-aligned. */ | |
515 | if (op->reg == MSR_SP && (new_val & 1)) | |
516 | new_val ++; | |
517 | REG_PUT (op->reg, new_val); | |
518 | } | |
519 | ||
520 | return rv; | |
521 | } | |
522 | ||
523 | static void | |
524 | mem_put_val (SIM_DESC sd, int addr, int val, int bits) | |
525 | { | |
526 | MSP430_Opcode_Decoded opc; | |
527 | ||
528 | opc.size = bits; | |
529 | opc.op[0].type = MSP430_Operand_Indirect; | |
530 | opc.op[0].addend = addr; | |
531 | opc.op[0].reg = MSR_None; | |
532 | put_op (sd, &opc, 0, val); | |
533 | } | |
534 | ||
535 | static int | |
536 | mem_get_val (SIM_DESC sd, int addr, int bits) | |
537 | { | |
538 | MSP430_Opcode_Decoded opc; | |
539 | ||
540 | opc.size = bits; | |
541 | opc.op[0].type = MSP430_Operand_Indirect; | |
542 | opc.op[0].addend = addr; | |
543 | opc.op[0].reg = MSR_None; | |
544 | return get_op (sd, &opc, 0); | |
545 | } | |
546 | ||
547 | #define CIO_OPEN (0xF0) | |
548 | #define CIO_CLOSE (0xF1) | |
549 | #define CIO_READ (0xF2) | |
550 | #define CIO_WRITE (0xF3) | |
551 | #define CIO_LSEEK (0xF4) | |
552 | #define CIO_UNLINK (0xF5) | |
553 | #define CIO_GETENV (0xF6) | |
554 | #define CIO_RENAME (0xF7) | |
555 | #define CIO_GETTIME (0xF8) | |
556 | #define CIO_GETCLK (0xF9) | |
557 | #define CIO_SYNC (0xFF) | |
558 | ||
559 | #define CIO_I(n) (parms[(n)] + parms[(n)+1] * 256) | |
560 | #define CIO_L(n) (parms[(n)] + parms[(n)+1] * 256 \ | |
561 | + parms[(n)+2] * 65536 + parms[(n)+3] * 16777216) | |
562 | ||
563 | static void | |
564 | msp430_cio (SIM_DESC sd) | |
565 | { | |
566 | /* A block of data at __CIOBUF__ describes the I/O operation to | |
567 | perform. */ | |
568 | ||
569 | unsigned char raw_parms[13]; | |
570 | unsigned char parms[8]; | |
571 | long length; | |
572 | int command; | |
573 | unsigned char buffer[512]; | |
574 | long ret_buflen = 0; | |
575 | long fd, addr, len, rv; | |
576 | ||
577 | sim_core_read_buffer (sd, MSP430_CPU (sd), 0, parms, | |
578 | MSP430_CPU (sd)->state.cio_buffer, 5); | |
579 | length = CIO_I (0); | |
580 | command = parms[2]; | |
581 | ||
582 | sim_core_read_buffer (sd, MSP430_CPU (sd), 0, parms, | |
583 | MSP430_CPU (sd)->state.cio_buffer + 3, 8); | |
584 | ||
585 | sim_core_read_buffer (sd, MSP430_CPU (sd), 0, buffer, | |
586 | MSP430_CPU (sd)->state.cio_buffer + 11, length); | |
587 | ||
588 | switch (command) | |
589 | { | |
590 | case CIO_WRITE: | |
591 | fd = CIO_I (0); | |
592 | len = CIO_I (2); | |
593 | ||
594 | rv = write (fd, buffer, len); | |
595 | parms[0] = rv & 0xff; | |
596 | parms[1] = rv >> 8; | |
597 | ||
598 | break; | |
599 | } | |
600 | ||
601 | sim_core_write_buffer (sd, MSP430_CPU (sd), 0, parms, | |
602 | MSP430_CPU (sd)->state.cio_buffer + 4, 8); | |
603 | if (ret_buflen) | |
604 | sim_core_write_buffer (sd, MSP430_CPU (sd), 0, buffer, | |
605 | MSP430_CPU (sd)->state.cio_buffer + 12, ret_buflen); | |
606 | } | |
607 | ||
608 | #define SRC get_op (sd, opcode, 1) | |
609 | #define DSRC get_op (sd, opcode, 0) | |
610 | #define DEST(V) put_op (sd, opcode, 0, (V)) | |
611 | ||
612 | static int | |
613 | msp430_dis_read (bfd_vma memaddr, | |
614 | bfd_byte *myaddr, | |
615 | unsigned int length, | |
616 | struct disassemble_info *dinfo) | |
617 | { | |
618 | SIM_DESC sd = dinfo->private_data; | |
619 | sim_core_read_buffer (sd, MSP430_CPU (sd), 0, myaddr, memaddr, length); | |
620 | return 0; | |
621 | } | |
622 | ||
623 | #define DO_ALU(OP,SOP,MORE) \ | |
624 | { \ | |
625 | int s1 = DSRC; \ | |
626 | int s2 = SRC; \ | |
627 | int result = s1 OP s2 MORE; \ | |
628 | if (TRACE_ALU_P (MSP430_CPU (sd))) \ | |
629 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, \ | |
630 | "ALU: %#x %s %#x %s = %#x", s1, SOP, s2, #MORE, result); \ | |
631 | DEST (result); \ | |
632 | } | |
633 | ||
634 | #define SIGN (1 << (opcode->size - 1)) | |
635 | #define POS(x) (((x) & SIGN) ? 0 : 1) | |
636 | #define NEG(x) (((x) & SIGN) ? 1 : 0) | |
637 | ||
638 | static int | |
639 | zero_ext (int v, int bits) | |
640 | { | |
641 | v &= ((1 << bits) - 1); | |
642 | return v; | |
643 | } | |
644 | ||
645 | static int | |
646 | sign_ext (int v, int bits) | |
647 | { | |
648 | int sb = 1 << (bits-1); /* Sign bit. */ | |
649 | int mb = (1 << (bits-1)) - 1; /* Mantissa bits. */ | |
650 | ||
651 | if (v & sb) | |
652 | v = v | ~mb; | |
653 | else | |
654 | v = v & mb; | |
655 | return v; | |
656 | } | |
657 | ||
658 | #define SX(v) sign_ext (v, opcode->size) | |
659 | #define ZX(v) zero_ext (v, opcode->size) | |
660 | ||
661 | static char * | |
662 | flags2string (int f) | |
663 | { | |
664 | static char buf[2][6]; | |
665 | static int bi = 0; | |
666 | char *bp = buf[bi]; | |
667 | ||
668 | bi = (bi + 1) % 2; | |
669 | ||
670 | bp[0] = f & MSP430_FLAG_V ? 'V' : '-'; | |
671 | bp[1] = f & MSP430_FLAG_N ? 'N' : '-'; | |
672 | bp[2] = f & MSP430_FLAG_Z ? 'Z' : '-'; | |
673 | bp[3] = f & MSP430_FLAG_C ? 'C' : '-'; | |
674 | bp[4] = 0; | |
675 | return bp; | |
676 | } | |
677 | ||
678 | /* Random number that won't show up in our usual logic. */ | |
679 | #define MAGIC_OVERFLOW 0x55000F | |
680 | ||
681 | static void | |
682 | do_flags (SIM_DESC sd, | |
683 | MSP430_Opcode_Decoded *opcode, | |
684 | int vnz_val, /* Signed result. */ | |
685 | int carry, | |
686 | int overflow) | |
687 | { | |
688 | int f = SR; | |
689 | int new_f = 0; | |
690 | int signbit = 1 << (opcode->size - 1); | |
691 | ||
692 | f &= ~opcode->flags_0; | |
693 | f &= ~opcode->flags_set; | |
694 | f |= opcode->flags_1; | |
695 | ||
696 | if (vnz_val & signbit) | |
697 | new_f |= MSP430_FLAG_N; | |
698 | if (! (vnz_val & ((signbit << 1) - 1))) | |
699 | new_f |= MSP430_FLAG_Z; | |
700 | if (overflow == MAGIC_OVERFLOW) | |
701 | { | |
702 | if (vnz_val != SX (vnz_val)) | |
703 | new_f |= MSP430_FLAG_V; | |
704 | } | |
705 | else | |
706 | if (overflow) | |
707 | new_f |= MSP430_FLAG_V; | |
708 | if (carry) | |
709 | new_f |= MSP430_FLAG_C; | |
710 | ||
711 | new_f = f | (new_f & opcode->flags_set); | |
712 | if (TRACE_ALU_P (MSP430_CPU (sd))) | |
713 | { | |
714 | if (SR != new_f) | |
715 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
716 | "FLAGS: %s -> %s", flags2string (SR), | |
717 | flags2string (new_f)); | |
718 | else | |
719 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
720 | "FLAGS: %s", flags2string (new_f)); | |
721 | } | |
722 | SR = new_f; | |
723 | } | |
724 | ||
725 | #define FLAGS(vnz,c) do_flags (sd, opcode, vnz, c, MAGIC_OVERFLOW) | |
726 | #define FLAGSV(vnz,c,v) do_flags (sd, opcode, vnz, c, v) | |
727 | ||
728 | /* These two assume unsigned 16-bit (four digit) words. | |
729 | Mask off unwanted bits for byte operations. */ | |
730 | ||
731 | static int | |
732 | bcd_to_binary (int v) | |
733 | { | |
734 | int r = ( ((v >> 0) & 0xf) * 1 | |
735 | + ((v >> 4) & 0xf) * 10 | |
736 | + ((v >> 8) & 0xf) * 100 | |
737 | + ((v >> 12) & 0xf) * 1000); | |
738 | return r; | |
739 | } | |
740 | ||
741 | static int | |
742 | binary_to_bcd (int v) | |
743 | { | |
744 | int r = ( ((v / 1) % 10) << 0 | |
745 | | ((v / 10) % 10) << 4 | |
746 | | ((v / 100) % 10) << 8 | |
747 | | ((v / 1000) % 10) << 12); | |
748 | return r; | |
749 | } | |
750 | ||
751 | static int | |
752 | syscall_read_mem (host_callback *cb, struct cb_syscall *sc, | |
753 | unsigned long taddr, char *buf, int bytes) | |
754 | { | |
755 | SIM_DESC sd = (SIM_DESC) sc->p1; | |
756 | SIM_CPU *cpu = (SIM_CPU *) sc->p2; | |
757 | ||
758 | return sim_core_read_buffer (sd, cpu, read_map, buf, taddr, bytes); | |
759 | } | |
760 | ||
761 | static int | |
762 | syscall_write_mem (host_callback *cb, struct cb_syscall *sc, | |
763 | unsigned long taddr, const char *buf, int bytes) | |
764 | { | |
765 | SIM_DESC sd = (SIM_DESC) sc->p1; | |
766 | SIM_CPU *cpu = (SIM_CPU *) sc->p2; | |
767 | ||
768 | return sim_core_write_buffer (sd, cpu, write_map, buf, taddr, bytes); | |
769 | } | |
770 | ||
771 | static const char * | |
772 | cond_string (int cond) | |
773 | { | |
774 | switch (cond) | |
775 | { | |
776 | case MSC_nz: | |
777 | return "NZ"; | |
778 | case MSC_z: | |
779 | return "Z"; | |
780 | case MSC_nc: | |
781 | return "NC"; | |
782 | case MSC_c: | |
783 | return "C"; | |
784 | case MSC_n: | |
785 | return "N"; | |
786 | case MSC_ge: | |
787 | return "GE"; | |
788 | case MSC_l: | |
789 | return "L"; | |
790 | case MSC_true: | |
791 | return "MP"; | |
792 | default: | |
793 | return "??"; | |
794 | } | |
795 | } | |
796 | ||
797 | /* Checks a CALL to address CALL_ADDR. If this is a special | |
798 | syscall address then the call is simulated and non-zero is | |
799 | returned. Otherwise 0 is returned. */ | |
800 | ||
801 | static int | |
802 | maybe_perform_syscall (SIM_DESC sd, int call_addr) | |
803 | { | |
804 | if (call_addr == 0x00160) | |
805 | { | |
806 | int i; | |
807 | ||
808 | for (i = 0; i < 16; i++) | |
809 | { | |
810 | if (i % 4 == 0) | |
811 | fprintf (stderr, "\t"); | |
812 | fprintf (stderr, "R%-2d %05x ", i, MSP430_CPU (sd)->state.regs[i]); | |
813 | if (i % 4 == 3) | |
814 | { | |
815 | int sp = SP + (3 - (i / 4)) * 2; | |
816 | unsigned char buf[2]; | |
817 | ||
818 | sim_core_read_buffer (sd, MSP430_CPU (sd), read_map, buf, sp, 2); | |
819 | ||
820 | fprintf (stderr, "\tSP%+d: %04x", sp - SP, | |
821 | buf[0] + buf[1] * 256); | |
822 | ||
823 | if (i / 4 == 0) | |
824 | { | |
825 | int flags = SR; | |
826 | ||
827 | fprintf (stderr, flags & 0x100 ? " V" : " -"); | |
828 | fprintf (stderr, flags & 0x004 ? "N" : "-"); | |
829 | fprintf (stderr, flags & 0x002 ? "Z" : "-"); | |
830 | fprintf (stderr, flags & 0x001 ? "C" : "-"); | |
831 | } | |
832 | ||
833 | fprintf (stderr, "\n"); | |
834 | } | |
835 | } | |
836 | return 1; | |
837 | } | |
838 | ||
839 | if ((call_addr & ~0x3f) == 0x00180) | |
840 | { | |
841 | /* Syscall! */ | |
842 | int syscall_num = call_addr & 0x3f; | |
843 | host_callback *cb = STATE_CALLBACK (sd); | |
844 | CB_SYSCALL sc; | |
845 | ||
846 | CB_SYSCALL_INIT (&sc); | |
847 | ||
848 | sc.func = syscall_num; | |
849 | sc.arg1 = MSP430_CPU (sd)->state.regs[12]; | |
850 | sc.arg2 = MSP430_CPU (sd)->state.regs[13]; | |
851 | sc.arg3 = MSP430_CPU (sd)->state.regs[14]; | |
852 | sc.arg4 = MSP430_CPU (sd)->state.regs[15]; | |
853 | ||
854 | if (TRACE_SYSCALL_P (MSP430_CPU (sd))) | |
855 | { | |
856 | const char *syscall_name = "*unknown*"; | |
857 | ||
858 | switch (syscall_num) | |
859 | { | |
860 | case TARGET_SYS_exit: | |
861 | syscall_name = "exit(%d)"; | |
862 | break; | |
863 | case TARGET_SYS_open: | |
864 | syscall_name = "open(%#x,%#x)"; | |
865 | break; | |
866 | case TARGET_SYS_close: | |
867 | syscall_name = "close(%d)"; | |
868 | break; | |
869 | case TARGET_SYS_read: | |
870 | syscall_name = "read(%d,%#x,%d)"; | |
871 | break; | |
872 | case TARGET_SYS_write: | |
873 | syscall_name = "write(%d,%#x,%d)"; | |
874 | break; | |
875 | } | |
876 | trace_generic (sd, MSP430_CPU (sd), TRACE_SYSCALL_IDX, | |
877 | syscall_name, sc.arg1, sc.arg2, sc.arg3, sc.arg4); | |
878 | } | |
879 | ||
880 | /* Handle SYS_exit here. */ | |
881 | if (syscall_num == 1) | |
882 | { | |
883 | sim_engine_halt (sd, MSP430_CPU (sd), NULL, | |
884 | MSP430_CPU (sd)->state.regs[0], | |
885 | sim_exited, sc.arg1); | |
886 | return 1; | |
887 | } | |
888 | ||
889 | sc.p1 = sd; | |
890 | sc.p2 = MSP430_CPU (sd); | |
891 | sc.read_mem = syscall_read_mem; | |
892 | sc.write_mem = syscall_write_mem; | |
893 | ||
894 | cb_syscall (cb, &sc); | |
895 | ||
896 | if (TRACE_SYSCALL_P (MSP430_CPU (sd))) | |
897 | trace_generic (sd, MSP430_CPU (sd), TRACE_SYSCALL_IDX, | |
898 | "returns %d", sc.result); | |
899 | ||
900 | MSP430_CPU (sd)->state.regs[12] = sc.result; | |
901 | return 1; | |
902 | } | |
903 | ||
904 | return 0; | |
905 | } | |
906 | ||
907 | static void | |
908 | msp430_step_once (SIM_DESC sd) | |
909 | { | |
910 | Get_Byte_Local_Data ld; | |
911 | unsigned char buf[100]; | |
912 | int i; | |
913 | int opsize; | |
914 | unsigned int opcode_pc; | |
915 | MSP430_Opcode_Decoded opcode_buf; | |
916 | MSP430_Opcode_Decoded *opcode = &opcode_buf; | |
917 | int s1, s2, result; | |
918 | int u1, u2, uresult; | |
919 | int c, reg; | |
920 | int sp; | |
921 | int carry_to_use; | |
922 | int n_repeats; | |
923 | int rept; | |
924 | int op_bytes, op_bits; | |
925 | ||
926 | PC &= 0xfffff; | |
927 | opcode_pc = PC; | |
928 | ||
929 | if (opcode_pc < 0x10) | |
930 | { | |
931 | fprintf (stderr, "Fault: PC(%#x) is less than 0x10\n", opcode_pc); | |
932 | sim_engine_halt (sd, MSP430_CPU (sd), NULL, | |
933 | MSP430_CPU (sd)->state.regs[0], | |
934 | sim_exited, -1); | |
935 | return; | |
936 | } | |
937 | ||
938 | if (PC == MSP430_CPU (sd)->state.cio_breakpoint | |
939 | && STATE_OPEN_KIND (sd) != SIM_OPEN_DEBUG) | |
940 | msp430_cio (sd); | |
941 | ||
942 | ld.sd = sd; | |
943 | ld.gb_addr = PC; | |
944 | opsize = msp430_decode_opcode (MSP430_CPU (sd)->state.regs[0], | |
945 | opcode, msp430_getbyte, &ld); | |
946 | PC += opsize; | |
947 | if (opsize <= 0) | |
948 | { | |
949 | fprintf (stderr, "Fault: undecodable opcode at %#x\n", opcode_pc); | |
950 | sim_engine_halt (sd, MSP430_CPU (sd), NULL, | |
951 | MSP430_CPU (sd)->state.regs[0], | |
952 | sim_exited, -1); | |
953 | return; | |
954 | } | |
955 | ||
956 | if (opcode->repeat_reg) | |
957 | n_repeats = (MSP430_CPU (sd)->state.regs[opcode->repeats] & 0x000f) + 1; | |
958 | else | |
959 | n_repeats = opcode->repeats + 1; | |
960 | ||
961 | op_bits = opcode->size; | |
962 | switch (op_bits) | |
963 | { | |
964 | case 8: | |
965 | op_bytes = 1; | |
966 | break; | |
967 | case 16: | |
968 | op_bytes = 2; | |
969 | break; | |
970 | case 20: | |
971 | case 32: | |
972 | op_bytes = 4; | |
973 | break; | |
974 | } | |
975 | ||
976 | if (TRACE_INSN_P (MSP430_CPU (sd))) | |
977 | { | |
978 | disassemble_info info; | |
979 | unsigned char b[10]; | |
980 | ||
981 | msp430_trace_one (opcode_pc); | |
982 | ||
983 | sim_core_read_buffer (sd, MSP430_CPU (sd), 0, b, opcode_pc, opsize); | |
984 | ||
985 | init_disassemble_info (&info, stderr, fprintf); | |
986 | info.private_data = sd; | |
987 | info.read_memory_func = msp430_dis_read; | |
988 | fprintf (stderr, "%#8x ", opcode_pc); | |
989 | for (i = 0; i < opsize; i += 2) | |
990 | fprintf (stderr, " %02x%02x", b[i+1], b[i]); | |
991 | for (; i < 6; i += 2) | |
992 | fprintf (stderr, " "); | |
993 | fprintf (stderr, " "); | |
994 | print_insn_msp430 (opcode_pc, &info); | |
995 | fprintf (stderr, "\n"); | |
996 | fflush (stdout); | |
997 | } | |
998 | ||
999 | if (TRACE_ANY_P (MSP430_CPU (sd))) | |
1000 | trace_prefix (sd, MSP430_CPU (sd), NULL_CIA, opcode_pc, | |
1001 | TRACE_LINENUM_P (MSP430_CPU (sd)), NULL, 0, ""); | |
1002 | ||
1003 | carry_to_use = 0; | |
1004 | switch (opcode->id) | |
1005 | { | |
1006 | case MSO_unknown: | |
1007 | break; | |
1008 | ||
1009 | /* Double-operand instructions. */ | |
1010 | case MSO_mov: | |
1011 | if (opcode->n_bytes == 2 | |
1012 | && opcode->op[0].type == MSP430_Operand_Register | |
1013 | && opcode->op[0].reg == MSR_CG | |
1014 | && opcode->op[1].type == MSP430_Operand_Immediate | |
1015 | && opcode->op[1].addend == 0 | |
1016 | /* A 16-bit write of #0 is a NOP; an 8-bit write is a BRK. */ | |
1017 | && opcode->size == 8) | |
1018 | { | |
1019 | /* This is the designated software breakpoint instruction. */ | |
1020 | PC -= opsize; | |
1021 | sim_engine_halt (sd, MSP430_CPU (sd), NULL, | |
1022 | MSP430_CPU (sd)->state.regs[0], | |
1023 | sim_stopped, SIM_SIGTRAP); | |
1024 | ||
1025 | } | |
1026 | else | |
1027 | { | |
1028 | /* Otherwise, do the move. */ | |
1029 | for (rept = 0; rept < n_repeats; rept ++) | |
1030 | { | |
1031 | DEST (SRC); | |
1032 | } | |
1033 | } | |
1034 | break; | |
1035 | ||
1036 | case MSO_addc: | |
1037 | for (rept = 0; rept < n_repeats; rept ++) | |
1038 | { | |
1039 | carry_to_use = (SR & MSP430_FLAG_C) ? 1 : 0; | |
1040 | u1 = DSRC; | |
1041 | u2 = SRC; | |
1042 | s1 = SX (u1); | |
1043 | s2 = SX (u2); | |
1044 | uresult = u1 + u2 + carry_to_use; | |
1045 | result = s1 + s2 + carry_to_use; | |
1046 | if (TRACE_ALU_P (MSP430_CPU (sd))) | |
1047 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
1048 | "ADDC: %#x + %#x + %d = %#x", | |
1049 | u1, u2, carry_to_use, uresult); | |
1050 | DEST (result); | |
1051 | FLAGS (result, uresult != ZX (uresult)); | |
1052 | } | |
1053 | break; | |
1054 | ||
1055 | case MSO_add: | |
1056 | for (rept = 0; rept < n_repeats; rept ++) | |
1057 | { | |
1058 | u1 = DSRC; | |
1059 | u2 = SRC; | |
1060 | s1 = SX (u1); | |
1061 | s2 = SX (u2); | |
1062 | uresult = u1 + u2; | |
1063 | result = s1 + s2; | |
1064 | if (TRACE_ALU_P (MSP430_CPU (sd))) | |
1065 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
1066 | "ADD: %#x + %#x = %#x", | |
1067 | u1, u2, uresult); | |
1068 | DEST (result); | |
1069 | FLAGS (result, uresult != ZX (uresult)); | |
1070 | } | |
1071 | break; | |
1072 | ||
1073 | case MSO_subc: | |
1074 | for (rept = 0; rept < n_repeats; rept ++) | |
1075 | { | |
1076 | carry_to_use = (SR & MSP430_FLAG_C) ? 1 : 0; | |
1077 | u1 = DSRC; | |
1078 | u2 = SRC; | |
1079 | s1 = SX (u1); | |
1080 | s2 = SX (u2); | |
1081 | uresult = ZX (~u2) + u1 + carry_to_use; | |
1082 | result = s1 - s2 + (carry_to_use - 1); | |
1083 | if (TRACE_ALU_P (MSP430_CPU (sd))) | |
1084 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
1085 | "SUBC: %#x - %#x + %d = %#x", | |
1086 | u1, u2, carry_to_use, uresult); | |
1087 | DEST (result); | |
1088 | FLAGS (result, uresult != ZX (uresult)); | |
1089 | } | |
1090 | break; | |
1091 | ||
1092 | case MSO_sub: | |
1093 | for (rept = 0; rept < n_repeats; rept ++) | |
1094 | { | |
1095 | u1 = DSRC; | |
1096 | u2 = SRC; | |
1097 | s1 = SX (u1); | |
1098 | s2 = SX (u2); | |
1099 | uresult = ZX (~u2) + u1 + 1; | |
1100 | result = SX (uresult); | |
1101 | if (TRACE_ALU_P (MSP430_CPU (sd))) | |
1102 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
1103 | "SUB: %#x - %#x = %#x", | |
1104 | u1, u2, uresult); | |
1105 | DEST (result); | |
1106 | FLAGS (result, uresult != ZX (uresult)); | |
1107 | } | |
1108 | break; | |
1109 | ||
1110 | case MSO_cmp: | |
1111 | for (rept = 0; rept < n_repeats; rept ++) | |
1112 | { | |
1113 | u1 = DSRC; | |
1114 | u2 = SRC; | |
1115 | s1 = SX (u1); | |
1116 | s2 = SX (u2); | |
1117 | uresult = ZX (~u2) + u1 + 1; | |
1118 | result = s1 - s2; | |
1119 | if (TRACE_ALU_P (MSP430_CPU (sd))) | |
1120 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
1121 | "CMP: %#x - %#x = %x", | |
1122 | u1, u2, uresult); | |
1123 | FLAGS (result, uresult != ZX (uresult)); | |
1124 | } | |
1125 | break; | |
1126 | ||
1127 | case MSO_dadd: | |
1128 | for (rept = 0; rept < n_repeats; rept ++) | |
1129 | { | |
1130 | carry_to_use = (SR & MSP430_FLAG_C) ? 1 : 0; | |
1131 | u1 = DSRC; | |
1132 | u2 = SRC; | |
1133 | uresult = bcd_to_binary (u1) + bcd_to_binary (u2) + carry_to_use; | |
1134 | result = binary_to_bcd (uresult); | |
1135 | if (TRACE_ALU_P (MSP430_CPU (sd))) | |
1136 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
1137 | "DADD: %#x + %#x + %d = %#x", | |
1138 | u1, u2, carry_to_use, result); | |
1139 | DEST (result); | |
1140 | FLAGS (result, uresult > ((opcode->size == 8) ? 99 : 9999)); | |
1141 | } | |
1142 | break; | |
1143 | ||
1144 | case MSO_and: | |
1145 | for (rept = 0; rept < n_repeats; rept ++) | |
1146 | { | |
1147 | u1 = DSRC; | |
1148 | u2 = SRC; | |
1149 | uresult = u1 & u2; | |
1150 | if (TRACE_ALU_P (MSP430_CPU (sd))) | |
1151 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
1152 | "AND: %#x & %#x = %#x", | |
1153 | u1, u2, uresult); | |
1154 | DEST (uresult); | |
1155 | FLAGS (uresult, uresult != 0); | |
1156 | } | |
1157 | break; | |
1158 | ||
1159 | case MSO_bit: | |
1160 | for (rept = 0; rept < n_repeats; rept ++) | |
1161 | { | |
1162 | u1 = DSRC; | |
1163 | u2 = SRC; | |
1164 | uresult = u1 & u2; | |
1165 | if (TRACE_ALU_P (MSP430_CPU (sd))) | |
1166 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
1167 | "BIT: %#x & %#x -> %#x", | |
1168 | u1, u2, uresult); | |
1169 | FLAGS (uresult, uresult != 0); | |
1170 | } | |
1171 | break; | |
1172 | ||
1173 | case MSO_bic: | |
1174 | for (rept = 0; rept < n_repeats; rept ++) | |
1175 | { | |
1176 | u1 = DSRC; | |
1177 | u2 = SRC; | |
1178 | uresult = u1 & ~ u2; | |
1179 | if (TRACE_ALU_P (MSP430_CPU (sd))) | |
1180 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
1181 | "BIC: %#x & ~ %#x = %#x", | |
1182 | u1, u2, uresult); | |
1183 | DEST (uresult); | |
1184 | } | |
1185 | break; | |
1186 | ||
1187 | case MSO_bis: | |
1188 | for (rept = 0; rept < n_repeats; rept ++) | |
1189 | { | |
1190 | u1 = DSRC; | |
1191 | u2 = SRC; | |
1192 | uresult = u1 | u2; | |
1193 | if (TRACE_ALU_P (MSP430_CPU (sd))) | |
1194 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
1195 | "BIS: %#x | %#x = %#x", | |
1196 | u1, u2, uresult); | |
1197 | DEST (uresult); | |
1198 | } | |
1199 | break; | |
1200 | ||
1201 | case MSO_xor: | |
1202 | for (rept = 0; rept < n_repeats; rept ++) | |
1203 | { | |
1204 | s1 = 1 << (opcode->size - 1); | |
1205 | u1 = DSRC; | |
1206 | u2 = SRC; | |
1207 | uresult = u1 ^ u2; | |
1208 | if (TRACE_ALU_P (MSP430_CPU (sd))) | |
1209 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
1210 | "XOR: %#x & %#x = %#x", | |
1211 | u1, u2, uresult); | |
1212 | DEST (uresult); | |
1213 | FLAGSV (uresult, uresult != 0, (u1 & s1) && (u2 & s1)); | |
1214 | } | |
1215 | break; | |
1216 | ||
1217 | /* Single-operand instructions. Note: the decoder puts the same | |
1218 | operand in SRC as in DEST, for our convenience. */ | |
1219 | ||
1220 | case MSO_rrc: | |
1221 | for (rept = 0; rept < n_repeats; rept ++) | |
1222 | { | |
1223 | u1 = SRC; | |
1224 | carry_to_use = u1 & 1; | |
1225 | uresult = u1 >> 1; | |
1226 | if (SR & MSP430_FLAG_C) | |
1227 | uresult |= (1 << (opcode->size - 1)); | |
1228 | if (TRACE_ALU_P (MSP430_CPU (sd))) | |
1229 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
1230 | "RRC: %#x >>= %#x", | |
1231 | u1, uresult); | |
1232 | DEST (uresult); | |
1233 | FLAGS (uresult, carry_to_use); | |
1234 | } | |
1235 | break; | |
1236 | ||
1237 | case MSO_swpb: | |
1238 | for (rept = 0; rept < n_repeats; rept ++) | |
1239 | { | |
1240 | u1 = SRC; | |
1241 | uresult = ((u1 >> 8) & 0x00ff) | ((u1 << 8) & 0xff00); | |
1242 | if (TRACE_ALU_P (MSP430_CPU (sd))) | |
1243 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
1244 | "SWPB: %#x -> %#x", | |
1245 | u1, uresult); | |
1246 | DEST (uresult); | |
1247 | } | |
1248 | break; | |
1249 | ||
1250 | case MSO_rra: | |
1251 | for (rept = 0; rept < n_repeats; rept ++) | |
1252 | { | |
1253 | u1 = SRC; | |
1254 | c = u1 & 1; | |
1255 | s1 = 1 << (opcode->size - 1); | |
1256 | uresult = (u1 >> 1) | (u1 & s1); | |
1257 | if (TRACE_ALU_P (MSP430_CPU (sd))) | |
1258 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
1259 | "RRA: %#x >>= %#x", | |
1260 | u1, uresult); | |
1261 | DEST (uresult); | |
1262 | FLAGS (uresult, c); | |
1263 | } | |
1264 | break; | |
1265 | ||
1266 | case MSO_rru: | |
1267 | for (rept = 0; rept < n_repeats; rept ++) | |
1268 | { | |
1269 | u1 = SRC; | |
1270 | c = u1 & 1; | |
1271 | uresult = (u1 >> 1); | |
1272 | if (TRACE_ALU_P (MSP430_CPU (sd))) | |
1273 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
1274 | "RRU: %#x >>= %#x", | |
1275 | u1, uresult); | |
1276 | DEST (uresult); | |
1277 | FLAGS (uresult, c); | |
1278 | } | |
1279 | break; | |
1280 | ||
1281 | case MSO_sxt: | |
1282 | for (rept = 0; rept < n_repeats; rept ++) | |
1283 | { | |
1284 | u1 = SRC; | |
1285 | if (u1 & 0x80) | |
1286 | uresult = u1 | 0xfff00; | |
1287 | else | |
1288 | uresult = u1 & 0x000ff; | |
1289 | if (TRACE_ALU_P (MSP430_CPU (sd))) | |
1290 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
1291 | "SXT: %#x -> %#x", | |
1292 | u1, uresult); | |
1293 | DEST (uresult); | |
1294 | FLAGS (uresult, c); | |
1295 | } | |
1296 | break; | |
1297 | ||
1298 | case MSO_push: | |
1299 | for (rept = 0; rept < n_repeats; rept ++) | |
1300 | { | |
1301 | int new_sp; | |
1302 | ||
1303 | new_sp = REG_GET (MSR_SP) - op_bytes; | |
1304 | /* SP is always word-aligned. */ | |
1305 | if (new_sp & 1) | |
1306 | new_sp --; | |
1307 | REG_PUT (MSR_SP, new_sp); | |
1308 | u1 = SRC; | |
1309 | mem_put_val (sd, SP, u1, op_bits); | |
1310 | if (opcode->op[1].type == MSP430_Operand_Register) | |
1311 | opcode->op[1].reg --; | |
1312 | } | |
1313 | break; | |
1314 | ||
1315 | case MSO_pop: | |
1316 | for (rept = 0; rept < n_repeats; rept ++) | |
1317 | { | |
1318 | int new_sp; | |
1319 | ||
1320 | u1 = mem_get_val (sd, SP, op_bits); | |
1321 | DEST (u1); | |
1322 | if (opcode->op[0].type == MSP430_Operand_Register) | |
1323 | opcode->op[0].reg ++; | |
1324 | new_sp = REG_GET (MSR_SP) + op_bytes; | |
1325 | /* SP is always word-aligned. */ | |
1326 | if (new_sp & 1) | |
1327 | new_sp ++; | |
1328 | REG_PUT (MSR_SP, new_sp); | |
1329 | } | |
1330 | break; | |
1331 | ||
1332 | case MSO_call: | |
1333 | u1 = SRC; | |
1334 | ||
1335 | if (maybe_perform_syscall (sd, u1)) | |
1336 | break; | |
1337 | ||
1338 | REG_PUT (MSR_SP, REG_GET (MSR_SP) - op_bytes); | |
1339 | mem_put_val (sd, SP, PC, op_bits); | |
1340 | if (TRACE_ALU_P (MSP430_CPU (sd))) | |
1341 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
1342 | "CALL: func %#x ret %#x, sp %#x", | |
1343 | u1, PC, SP); | |
1344 | REG_PUT (MSR_PC, u1); | |
1345 | break; | |
1346 | ||
1347 | case MSO_reti: | |
1348 | SR = mem_get_val (sd, SP, op_bits); | |
1349 | SP += 2; | |
1350 | PC = mem_get_val (sd, SP, op_bits); | |
1351 | SP += 2; | |
1352 | if (TRACE_ALU_P (MSP430_CPU (sd))) | |
1353 | trace_generic (sd, MSP430_CPU (sd), TRACE_ALU_IDX, | |
1354 | "RETI: pc %#x sr %#x", | |
1355 | PC, SR); | |
1356 | break; | |
1357 | ||
1358 | /* Jumps. */ | |
1359 | ||
1360 | case MSO_jmp: | |
1361 | i = SRC; | |
1362 | switch (opcode->cond) | |
1363 | { | |
1364 | case MSC_nz: | |
1365 | u1 = (SR & MSP430_FLAG_Z) ? 0 : 1; | |
1366 | break; | |
1367 | case MSC_z: | |
1368 | u1 = (SR & MSP430_FLAG_Z) ? 1 : 0; | |
1369 | break; | |
1370 | case MSC_nc: | |
1371 | u1 = (SR & MSP430_FLAG_C) ? 0 : 1; | |
1372 | break; | |
1373 | case MSC_c: | |
1374 | u1 = (SR & MSP430_FLAG_C) ? 1 : 0; | |
1375 | break; | |
1376 | case MSC_n: | |
1377 | u1 = (SR & MSP430_FLAG_N) ? 1 : 0; | |
1378 | break; | |
1379 | case MSC_ge: | |
1380 | u1 = (!!(SR & MSP430_FLAG_N) == !!(SR & MSP430_FLAG_V)) ? 1 : 0; | |
1381 | break; | |
1382 | case MSC_l: | |
1383 | u1 = (!!(SR & MSP430_FLAG_N) == !!(SR & MSP430_FLAG_V)) ? 0 : 1; | |
1384 | break; | |
1385 | case MSC_true: | |
1386 | u1 = 1; | |
1387 | break; | |
1388 | } | |
1389 | ||
1390 | if (u1) | |
1391 | { | |
1392 | if (TRACE_BRANCH_P (MSP430_CPU (sd))) | |
1393 | trace_generic (sd, MSP430_CPU (sd), TRACE_BRANCH_IDX, | |
1394 | "J%s: pc %#x -> %#x sr %#x, taken", | |
1395 | cond_string (opcode->cond), PC, i, SR); | |
1396 | PC = i; | |
1397 | if (PC == opcode_pc) | |
1398 | exit (0); | |
1399 | } | |
1400 | else | |
1401 | if (TRACE_BRANCH_P (MSP430_CPU (sd))) | |
1402 | trace_generic (sd, MSP430_CPU (sd), TRACE_BRANCH_IDX, | |
1403 | "J%s: pc %#x to %#x sr %#x, not taken", | |
1404 | cond_string (opcode->cond), PC, i, SR); | |
1405 | break; | |
1406 | ||
1407 | default: | |
1408 | fprintf (stderr, "error: unexpected opcode id %d\n", opcode->id); | |
1409 | exit (1); | |
1410 | } | |
1411 | } | |
1412 | ||
1413 | void | |
1414 | sim_engine_run (SIM_DESC sd, | |
1415 | int next_cpu_nr, | |
1416 | int nr_cpus, | |
1417 | int siggnal) | |
1418 | { | |
1419 | while (1) | |
1420 | { | |
1421 | msp430_step_once (sd); | |
1422 | if (sim_events_tick (sd)) | |
1423 | sim_events_process (sd); | |
1424 | } | |
1425 | } |