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