cpu.c revision 1.6
1/* cpu.c --- CPU for RL78 simulator.
2
3   Copyright (C) 2011-2016 Free Software Foundation, Inc.
4   Contributed by Red Hat, Inc.
5
6   This file is part of the GNU simulators.
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 3 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program.  If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "config.h"
23#include <stdio.h>
24#include <string.h>
25#include <stdlib.h>
26
27#include "opcode/rl78.h"
28#include "mem.h"
29#include "cpu.h"
30
31int verbose = 0;
32int trace = 0;
33int rl78_in_gdb = 1;
34int timer_enabled = 2;
35int rl78_g10_mode = 0;
36int g13_multiply = 0;
37int g14_multiply = 0;
38
39#define REGISTER_ADDRESS 0xffee0
40
41typedef struct {
42  unsigned char x;
43  unsigned char a;
44  unsigned char c;
45  unsigned char b;
46  unsigned char e;
47  unsigned char d;
48  unsigned char l;
49  unsigned char h;
50} RegBank;
51
52static void trace_register_init ();
53
54/* This maps PSW to a pointer into memory[] */
55static RegBank *regbase_table[256];
56
57#define regbase regbase_table[memory[RL78_SFR_PSW]]
58
59#define REG(r) ((regbase)->r)
60
61void
62init_cpu (void)
63{
64  int i;
65
66  init_mem ();
67
68  memset (memory+REGISTER_ADDRESS, 0x11, 8 * 4);
69  memory[RL78_SFR_PSW] = 0x06;
70  memory[RL78_SFR_ES] = 0x0f;
71  memory[RL78_SFR_CS] = 0x00;
72  memory[RL78_SFR_PMC] = 0x00;
73
74  for (i = 0; i < 256; i ++)
75    {
76      int rb0 = (i & RL78_PSW_RBS0) ? 1 : 0;
77      int rb1 = (i & RL78_PSW_RBS1) ? 2 : 0;
78      int rb = rb1 | rb0;
79      regbase_table[i] = (RegBank *)(memory + (3 - rb) * 8 + REGISTER_ADDRESS);
80    }
81
82  trace_register_init ();
83
84  /* This means "by default" */
85  timer_enabled = 2;
86}
87
88SI
89get_reg (RL78_Register regno)
90{
91  switch (regno)
92    {
93    case RL78_Reg_None:
94      /* Conditionals do this.  */
95      return 0;
96
97    default:
98      abort ();
99    case RL78_Reg_X:	return REG (x);
100    case RL78_Reg_A:	return REG (a);
101    case RL78_Reg_C:	return REG (c);
102    case RL78_Reg_B:	return REG (b);
103    case RL78_Reg_E:	return REG (e);
104    case RL78_Reg_D:	return REG (d);
105    case RL78_Reg_L:	return REG (l);
106    case RL78_Reg_H:	return REG (h);
107    case RL78_Reg_AX:	return REG (a) * 256 + REG (x);
108    case RL78_Reg_BC:	return REG (b) * 256 + REG (c);
109    case RL78_Reg_DE:	return REG (d) * 256 + REG (e);
110    case RL78_Reg_HL:	return REG (h) * 256 + REG (l);
111    case RL78_Reg_SP:	return memory[RL78_SFR_SP] + 256 * memory[RL78_SFR_SP+1];
112    case RL78_Reg_PSW:	return memory[RL78_SFR_PSW];
113    case RL78_Reg_CS:	return memory[RL78_SFR_CS];
114    case RL78_Reg_ES:	return memory[RL78_SFR_ES];
115    case RL78_Reg_PMC:	return memory[RL78_SFR_PMC];
116    case RL78_Reg_MEM:	return memory[RL78_SFR_MEM];
117    }
118}
119
120extern unsigned char initted[];
121
122SI
123set_reg (RL78_Register regno, SI val)
124{
125  switch (regno)
126    {
127    case RL78_Reg_None:
128      abort ();
129    case RL78_Reg_X:	REG (x) = val; break;
130    case RL78_Reg_A:	REG (a) = val; break;
131    case RL78_Reg_C:	REG (c) = val; break;
132    case RL78_Reg_B:	REG (b) = val; break;
133    case RL78_Reg_E:	REG (e) = val; break;
134    case RL78_Reg_D:	REG (d) = val; break;
135    case RL78_Reg_L:	REG (l) = val; break;
136    case RL78_Reg_H:	REG (h) = val; break;
137    case RL78_Reg_AX:
138      REG (a) = val >> 8;
139      REG (x) = val & 0xff;
140      break;
141    case RL78_Reg_BC:
142      REG (b) = val >> 8;
143      REG (c) = val & 0xff;
144      break;
145    case RL78_Reg_DE:
146      REG (d) = val >> 8;
147      REG (e) = val & 0xff;
148      break;
149    case RL78_Reg_HL:
150      REG (h) = val >> 8;
151      REG (l) = val & 0xff;
152      break;
153    case RL78_Reg_SP:
154      if (val & 1)
155	{
156	  printf ("Warning: SP value 0x%04x truncated at pc=0x%05x\n", val, pc);
157	  val &= ~1;
158	}
159      {
160	int old_sp = get_reg (RL78_Reg_SP);
161	if (val < old_sp)
162	  {
163	    int i;
164	    for (i = val; i < old_sp; i ++)
165	      initted[i + 0xf0000] = 0;
166	  }
167      }
168      memory[RL78_SFR_SP] = val & 0xff;
169      memory[RL78_SFR_SP + 1] = val >> 8;
170      break;
171    case RL78_Reg_PSW:	memory[RL78_SFR_PSW] = val; break;
172    case RL78_Reg_CS:	memory[RL78_SFR_CS] = val; break;
173    case RL78_Reg_ES:	memory[RL78_SFR_ES] = val; break;
174    case RL78_Reg_PMC:	memory[RL78_SFR_PMC] = val; break;
175    case RL78_Reg_MEM:	memory[RL78_SFR_MEM] = val; break;
176    }
177  return val;
178}
179
180int
181condition_true (RL78_Condition cond_id, int val)
182{
183  int psw = get_reg (RL78_Reg_PSW);
184  int z = (psw & RL78_PSW_Z) ? 1 : 0;
185  int cy = (psw & RL78_PSW_CY) ? 1 : 0;
186
187  switch (cond_id)
188    {
189    case RL78_Condition_T:
190      return val != 0;
191    case RL78_Condition_F:
192      return val == 0;
193    case RL78_Condition_C:
194      return cy;
195    case RL78_Condition_NC:
196      return !cy;
197    case RL78_Condition_H:
198      return !(z | cy);
199    case RL78_Condition_NH:
200      return z | cy;
201    case RL78_Condition_Z:
202      return z;
203    case RL78_Condition_NZ:
204      return !z;
205    default:
206      abort ();
207    }
208}
209
210const char * const
211reg_names[] = {
212  "none",
213  "x",
214  "a",
215  "c",
216  "b",
217  "e",
218  "d",
219  "l",
220  "h",
221  "ax",
222  "bc",
223  "de",
224  "hl",
225  "sp",
226  "psw",
227  "cs",
228  "es",
229  "pmc",
230  "mem"
231};
232
233static char *
234psw_string (int psw)
235{
236  static char buf[30];
237  const char *comma = "";
238
239  buf[0] = 0;
240  if (psw == 0)
241    strcpy (buf, "-");
242  else
243    {
244#define PSW1(bit, name) if (psw & bit) { strcat (buf, comma); strcat (buf, name); comma = ","; }
245      PSW1 (RL78_PSW_IE, "ie");
246      PSW1 (RL78_PSW_Z, "z");
247      PSW1 (RL78_PSW_RBS1, "r1");
248      PSW1 (RL78_PSW_AC, "ac");
249      PSW1 (RL78_PSW_RBS0, "r0");
250      PSW1 (RL78_PSW_ISP1, "i1");
251      PSW1 (RL78_PSW_ISP0, "i0");
252      PSW1 (RL78_PSW_CY, "cy");
253    }
254  printf ("%s", buf);
255  return buf;
256}
257
258static unsigned char old_regs[32];
259static int old_psw;
260static int old_sp;
261
262int trace_register_words;
263
264void
265trace_register_changes (void)
266{
267  int i;
268  int any = 0;
269
270  if (!trace)
271    return;
272
273#define TB(name,nv,ov) if (nv != ov) { printf ("%s: \033[31m%02x \033[32m%02x\033[0m ", name, ov, nv); ov = nv; any = 1; }
274#define TW(name,nv,ov) if (nv != ov) { printf ("%s: \033[31m%04x \033[32m%04x\033[0m ", name, ov, nv); ov = nv; any = 1; }
275
276  if (trace_register_words)
277    {
278#define TRW(name, idx) TW (name, memory[REGISTER_ADDRESS + (idx)], old_regs[idx])
279      for (i = 0; i < 32; i += 2)
280	{
281	  char buf[10];
282	  int o, n, a;
283	  switch (i)
284	    {
285	    case 0: strcpy (buf, "AX"); break;
286	    case 2: strcpy (buf, "BC"); break;
287	    case 4: strcpy (buf, "DE"); break;
288	    case 6: strcpy (buf, "HL"); break;
289	    default: sprintf (buf, "r%d", i); break;
290	    }
291	  a = REGISTER_ADDRESS + (i ^ 0x18);
292	  o = old_regs[i ^ 0x18] + old_regs[(i ^ 0x18) + 1] * 256;
293	  n = memory[a] + memory[a + 1] * 256;
294	  TW (buf, n, o);
295	  old_regs[i ^ 0x18] = n;
296	  old_regs[(i ^ 0x18) + 1] = n >> 8;
297	}
298    }
299  else
300    {
301      for (i = 0; i < 32; i ++)
302	{
303	  char buf[10];
304	  if (i < 8)
305	    {
306	      buf[0] = "XACBEDLH"[i];
307	      buf[1] = 0;
308	    }
309	  else
310	    sprintf (buf, "r%d", i);
311#define TRB(name, idx) TB (name, memory[REGISTER_ADDRESS + (idx)], old_regs[idx])
312	  TRB (buf, i ^ 0x18);
313	}
314    }
315  if (memory[RL78_SFR_PSW] != old_psw)
316    {
317      printf ("PSW: \033[31m");
318      psw_string (old_psw);
319      printf (" \033[32m");
320      psw_string (memory[RL78_SFR_PSW]);
321      printf ("\033[0m ");
322      old_psw = memory[RL78_SFR_PSW];
323      any = 1;
324    }
325  TW ("SP", mem_get_hi (RL78_SFR_SP), old_sp);
326  if (any)
327    printf ("\n");
328}
329
330static void
331trace_register_init (void)
332{
333  memcpy (old_regs, memory + REGISTER_ADDRESS, 8 * 4);
334  old_psw = memory[RL78_SFR_PSW];
335  old_sp = mem_get_hi (RL78_SFR_SP);
336}
337