xref: /netbsd-src/external/gpl3/gdb/dist/sim/rl78/cpu.c (revision c38e7cc395b1472a774ff828e46123de44c628e9)
1 /* cpu.c --- CPU for RL78 simulator.
2 
3    Copyright (C) 2011-2017 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 
31 int verbose = 0;
32 int trace = 0;
33 int rl78_in_gdb = 1;
34 int timer_enabled = 2;
35 int rl78_g10_mode = 0;
36 int g13_multiply = 0;
37 int g14_multiply = 0;
38 
39 #define REGISTER_ADDRESS 0xffee0
40 
41 typedef 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 
52 static void trace_register_init ();
53 
54 /* This maps PSW to a pointer into memory[] */
55 static RegBank *regbase_table[256];
56 
57 #define regbase regbase_table[memory[RL78_SFR_PSW]]
58 
59 #define REG(r) ((regbase)->r)
60 
61 void
62 init_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 
88 SI
89 get_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 
120 extern unsigned char initted[];
121 
122 SI
123 set_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 
180 int
181 condition_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 
210 const char * const
211 reg_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 
233 static char *
234 psw_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 
258 static unsigned char old_regs[32];
259 static int old_psw;
260 static int old_sp;
261 
262 int trace_register_words;
263 
264 void
265 trace_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 
330 static void
331 trace_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