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