cpu.c revision 1.9
1285242Sachim/* cpu.c --- CPU for RL78 simulator.
2285242Sachim
3285242Sachim   Copyright (C) 2011-2020 Free Software Foundation, Inc.
4285242Sachim   Contributed by Red Hat, Inc.
5285242Sachim
6285242Sachim   This file is part of the GNU simulators.
7285242Sachim
8285242Sachim   This program is free software; you can redistribute it and/or modify
9285242Sachim   it under the terms of the GNU General Public License as published by
10285242Sachim   the Free Software Foundation; either version 3 of the License, or
11285242Sachim   (at your option) any later version.
12285242Sachim
13285242Sachim   This program is distributed in the hope that it will be useful,
14285242Sachim   but WITHOUT ANY WARRANTY; without even the implied warranty of
15285242Sachim   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16285242Sachim   GNU General Public License for more details.
17285242Sachim
18285242Sachim   You should have received a copy of the GNU General Public License
19285242Sachim   along with this program.  If not, see <http://www.gnu.org/licenses/>.
20285242Sachim*/
21285242Sachim
22285242Sachim#include "config.h"
23285242Sachim#include <stdio.h>
24285242Sachim#include <string.h>
25285242Sachim#include <stdlib.h>
26285242Sachim
27285242Sachim#include "opcode/rl78.h"
28285242Sachim#include "mem.h"
29285242Sachim#include "cpu.h"
30285242Sachim
31285242Sachimint verbose = 0;
32285242Sachimint trace = 0;
33285242Sachimint rl78_in_gdb = 1;
34285242Sachimint timer_enabled = 2;
35285242Sachimint rl78_g10_mode = 0;
36285242Sachimint g13_multiply = 0;
37285242Sachimint g14_multiply = 0;
38285242Sachim
39285242Sachim#define REGISTER_ADDRESS 0xffee0
40285242Sachim
41285242Sachimtypedef struct {
42285242Sachim  unsigned char x;
43285242Sachim  unsigned char a;
44285242Sachim  unsigned char c;
45285242Sachim  unsigned char b;
46285242Sachim  unsigned char e;
47285242Sachim  unsigned char d;
48285242Sachim  unsigned char l;
49285242Sachim  unsigned char h;
50285242Sachim} RegBank;
51285242Sachim
52285242Sachimstatic void trace_register_init ();
53285242Sachim
54285242Sachim/* This maps PSW to a pointer into memory[] */
55285242Sachimstatic RegBank *regbase_table[256];
56285242Sachim
57285242Sachim#define regbase regbase_table[memory[RL78_SFR_PSW]]
58285242Sachim
59285242Sachim#define REG(r) ((regbase)->r)
60285242Sachim
61285242Sachimvoid
62285242Sachiminit_cpu (void)
63285242Sachim{
64285242Sachim  int i;
65285242Sachim
66285242Sachim  init_mem ();
67285242Sachim
68285242Sachim  memset (memory+REGISTER_ADDRESS, 0x11, 8 * 4);
69285242Sachim  memory[RL78_SFR_PSW] = 0x06;
70285242Sachim  memory[RL78_SFR_ES] = 0x0f;
71285242Sachim  memory[RL78_SFR_CS] = 0x00;
72285242Sachim  memory[RL78_SFR_PMC] = 0x00;
73285242Sachim
74285242Sachim  for (i = 0; i < 256; i ++)
75285242Sachim    {
76285242Sachim      int rb0 = (i & RL78_PSW_RBS0) ? 1 : 0;
77285242Sachim      int rb1 = (i & RL78_PSW_RBS1) ? 2 : 0;
78285242Sachim      int rb = rb1 | rb0;
79285242Sachim      regbase_table[i] = (RegBank *)(memory + (3 - rb) * 8 + REGISTER_ADDRESS);
80285242Sachim    }
81285242Sachim
82285242Sachim  trace_register_init ();
83285242Sachim
84285242Sachim  /* This means "by default" */
85285242Sachim  timer_enabled = 2;
86285242Sachim}
87285242Sachim
88285242SachimSI
89285242Sachimget_reg (RL78_Register regno)
90285242Sachim{
91285242Sachim  switch (regno)
92285242Sachim    {
93285242Sachim    case RL78_Reg_None:
94285242Sachim      /* Conditionals do this.  */
95285242Sachim      return 0;
96285242Sachim
97285242Sachim    default:
98285242Sachim      abort ();
99285242Sachim    case RL78_Reg_X:	return REG (x);
100285242Sachim    case RL78_Reg_A:	return REG (a);
101285242Sachim    case RL78_Reg_C:	return REG (c);
102285242Sachim    case RL78_Reg_B:	return REG (b);
103285242Sachim    case RL78_Reg_E:	return REG (e);
104285242Sachim    case RL78_Reg_D:	return REG (d);
105285242Sachim    case RL78_Reg_L:	return REG (l);
106285242Sachim    case RL78_Reg_H:	return REG (h);
107285242Sachim    case RL78_Reg_AX:	return REG (a) * 256 + REG (x);
108285242Sachim    case RL78_Reg_BC:	return REG (b) * 256 + REG (c);
109285242Sachim    case RL78_Reg_DE:	return REG (d) * 256 + REG (e);
110285242Sachim    case RL78_Reg_HL:	return REG (h) * 256 + REG (l);
111285242Sachim    case RL78_Reg_SP:	return memory[RL78_SFR_SP] + 256 * memory[RL78_SFR_SP+1];
112285242Sachim    case RL78_Reg_PSW:	return memory[RL78_SFR_PSW];
113285242Sachim    case RL78_Reg_CS:	return memory[RL78_SFR_CS];
114285242Sachim    case RL78_Reg_ES:	return memory[RL78_SFR_ES];
115285242Sachim    case RL78_Reg_PMC:	return memory[RL78_SFR_PMC];
116285242Sachim    case RL78_Reg_MEM:	return memory[RL78_SFR_MEM];
117285242Sachim    }
118285242Sachim}
119285242Sachim
120285242Sachimextern unsigned char initted[];
121285242Sachim
122285242SachimSI
123285242Sachimset_reg (RL78_Register regno, SI val)
124285242Sachim{
125285242Sachim  switch (regno)
126285242Sachim    {
127285242Sachim    case RL78_Reg_None:
128285242Sachim      abort ();
129285242Sachim    case RL78_Reg_X:	REG (x) = val; break;
130285242Sachim    case RL78_Reg_A:	REG (a) = val; break;
131285242Sachim    case RL78_Reg_C:	REG (c) = val; break;
132285242Sachim    case RL78_Reg_B:	REG (b) = val; break;
133285242Sachim    case RL78_Reg_E:	REG (e) = val; break;
134285242Sachim    case RL78_Reg_D:	REG (d) = val; break;
135285242Sachim    case RL78_Reg_L:	REG (l) = val; break;
136285242Sachim    case RL78_Reg_H:	REG (h) = val; break;
137285242Sachim    case RL78_Reg_AX:
138285242Sachim      REG (a) = val >> 8;
139285242Sachim      REG (x) = val & 0xff;
140285242Sachim      break;
141285242Sachim    case RL78_Reg_BC:
142285242Sachim      REG (b) = val >> 8;
143285242Sachim      REG (c) = val & 0xff;
144285242Sachim      break;
145285242Sachim    case RL78_Reg_DE:
146285242Sachim      REG (d) = val >> 8;
147285242Sachim      REG (e) = val & 0xff;
148285242Sachim      break;
149285242Sachim    case RL78_Reg_HL:
150285242Sachim      REG (h) = val >> 8;
151285242Sachim      REG (l) = val & 0xff;
152285242Sachim      break;
153285242Sachim    case RL78_Reg_SP:
154285242Sachim      if (val & 1)
155285242Sachim	{
156285242Sachim	  printf ("Warning: SP value 0x%04x truncated at pc=0x%05x\n", val, pc);
157285242Sachim	  val &= ~1;
158285242Sachim	}
159285242Sachim      {
160285242Sachim	int old_sp = get_reg (RL78_Reg_SP);
161285242Sachim	if (val < old_sp)
162285242Sachim	  {
163285242Sachim	    int i;
164285242Sachim	    for (i = val; i < old_sp; i ++)
165285242Sachim	      initted[i + 0xf0000] = 0;
166285242Sachim	  }
167285242Sachim      }
168285242Sachim      memory[RL78_SFR_SP] = val & 0xff;
169285242Sachim      memory[RL78_SFR_SP + 1] = val >> 8;
170285242Sachim      break;
171285242Sachim    case RL78_Reg_PSW:	memory[RL78_SFR_PSW] = val; break;
172285242Sachim    case RL78_Reg_CS:	memory[RL78_SFR_CS] = val; break;
173285242Sachim    case RL78_Reg_ES:	memory[RL78_SFR_ES] = val; break;
174285242Sachim    case RL78_Reg_PMC:	memory[RL78_SFR_PMC] = val; break;
175285242Sachim    case RL78_Reg_MEM:	memory[RL78_SFR_MEM] = val; break;
176285242Sachim    }
177285242Sachim  return val;
178285242Sachim}
179285242Sachim
180285242Sachimint
181285242Sachimcondition_true (RL78_Condition cond_id, int val)
182285242Sachim{
183285242Sachim  int psw = get_reg (RL78_Reg_PSW);
184285242Sachim  int z = (psw & RL78_PSW_Z) ? 1 : 0;
185285242Sachim  int cy = (psw & RL78_PSW_CY) ? 1 : 0;
186285242Sachim
187285242Sachim  switch (cond_id)
188285242Sachim    {
189285242Sachim    case RL78_Condition_T:
190285242Sachim      return val != 0;
191285242Sachim    case RL78_Condition_F:
192285242Sachim      return val == 0;
193285242Sachim    case RL78_Condition_C:
194285242Sachim      return cy;
195285242Sachim    case RL78_Condition_NC:
196285242Sachim      return !cy;
197285242Sachim    case RL78_Condition_H:
198285242Sachim      return !(z | cy);
199285242Sachim    case RL78_Condition_NH:
200285242Sachim      return z | cy;
201285242Sachim    case RL78_Condition_Z:
202285242Sachim      return z;
203285242Sachim    case RL78_Condition_NZ:
204285242Sachim      return !z;
205285242Sachim    default:
206285242Sachim      abort ();
207285242Sachim    }
208285242Sachim}
209285242Sachim
210285242Sachimconst char * const
211285242Sachimreg_names[] = {
212285242Sachim  "none",
213285242Sachim  "x",
214285242Sachim  "a",
215285242Sachim  "c",
216285242Sachim  "b",
217285242Sachim  "e",
218285242Sachim  "d",
219285242Sachim  "l",
220285242Sachim  "h",
221285242Sachim  "ax",
222285242Sachim  "bc",
223285242Sachim  "de",
224285242Sachim  "hl",
225285242Sachim  "sp",
226285242Sachim  "psw",
227285242Sachim  "cs",
228285242Sachim  "es",
229285242Sachim  "pmc",
230285242Sachim  "mem"
231285242Sachim};
232285242Sachim
233285242Sachimstatic char *
234285242Sachimpsw_string (int psw)
235285242Sachim{
236285242Sachim  static char buf[30];
237285242Sachim  const char *comma = "";
238285242Sachim
239285242Sachim  buf[0] = 0;
240285242Sachim  if (psw == 0)
241285242Sachim    strcpy (buf, "-");
242285242Sachim  else
243285242Sachim    {
244285242Sachim#define PSW1(bit, name) if (psw & bit) { strcat (buf, comma); strcat (buf, name); comma = ","; }
245285242Sachim      PSW1 (RL78_PSW_IE, "ie");
246285242Sachim      PSW1 (RL78_PSW_Z, "z");
247285242Sachim      PSW1 (RL78_PSW_RBS1, "r1");
248285242Sachim      PSW1 (RL78_PSW_AC, "ac");
249285242Sachim      PSW1 (RL78_PSW_RBS0, "r0");
250285242Sachim      PSW1 (RL78_PSW_ISP1, "i1");
251285242Sachim      PSW1 (RL78_PSW_ISP0, "i0");
252285242Sachim      PSW1 (RL78_PSW_CY, "cy");
253285242Sachim    }
254285242Sachim  printf ("%s", buf);
255285242Sachim  return buf;
256285242Sachim}
257285242Sachim
258285242Sachimstatic unsigned char old_regs[32];
259285242Sachimstatic int old_psw;
260285242Sachimstatic int old_sp;
261285242Sachim
262285242Sachimint trace_register_words;
263285242Sachim
264285242Sachimvoid
265285242Sachimtrace_register_changes (void)
266285242Sachim{
267285242Sachim  int i;
268285242Sachim  int any = 0;
269285242Sachim
270285242Sachim  if (!trace)
271285242Sachim    return;
272285242Sachim
273285242Sachim#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; }
274285242Sachim#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; }
275285242Sachim
276285242Sachim  if (trace_register_words)
277285242Sachim    {
278285242Sachim#define TRW(name, idx) TW (name, memory[REGISTER_ADDRESS + (idx)], old_regs[idx])
279285242Sachim      for (i = 0; i < 32; i += 2)
280285242Sachim	{
281285242Sachim	  char buf[10];
282285242Sachim	  int o, n, a;
283285242Sachim	  switch (i)
284285242Sachim	    {
285285242Sachim	    case 0: strcpy (buf, "AX"); break;
286285242Sachim	    case 2: strcpy (buf, "BC"); break;
287285242Sachim	    case 4: strcpy (buf, "DE"); break;
288285242Sachim	    case 6: strcpy (buf, "HL"); break;
289285242Sachim	    default: sprintf (buf, "r%d", i); break;
290285242Sachim	    }
291285242Sachim	  a = REGISTER_ADDRESS + (i ^ 0x18);
292285242Sachim	  o = old_regs[i ^ 0x18] + old_regs[(i ^ 0x18) + 1] * 256;
293285242Sachim	  n = memory[a] + memory[a + 1] * 256;
294285242Sachim	  TW (buf, n, o);
295285242Sachim	  old_regs[i ^ 0x18] = n;
296285242Sachim	  old_regs[(i ^ 0x18) + 1] = n >> 8;
297285242Sachim	}
298285242Sachim    }
299285242Sachim  else
300285242Sachim    {
301285242Sachim      for (i = 0; i < 32; i ++)
302285242Sachim	{
303285242Sachim	  char buf[10];
304285242Sachim	  if (i < 8)
305285242Sachim	    {
306285242Sachim	      buf[0] = "XACBEDLH"[i];
307285242Sachim	      buf[1] = 0;
308285242Sachim	    }
309285242Sachim	  else
310285242Sachim	    sprintf (buf, "r%d", i);
311285242Sachim#define TRB(name, idx) TB (name, memory[REGISTER_ADDRESS + (idx)], old_regs[idx])
312285242Sachim	  TRB (buf, i ^ 0x18);
313285242Sachim	}
314285242Sachim    }
315285242Sachim  if (memory[RL78_SFR_PSW] != old_psw)
316285242Sachim    {
317285242Sachim      printf ("PSW: \033[31m");
318285242Sachim      psw_string (old_psw);
319285242Sachim      printf (" \033[32m");
320285242Sachim      psw_string (memory[RL78_SFR_PSW]);
321285242Sachim      printf ("\033[0m ");
322285242Sachim      old_psw = memory[RL78_SFR_PSW];
323285242Sachim      any = 1;
324285242Sachim    }
325285242Sachim  TW ("SP", mem_get_hi (RL78_SFR_SP), old_sp);
326285242Sachim  if (any)
327285242Sachim    printf ("\n");
328285242Sachim}
329285242Sachim
330285242Sachimstatic void
331285242Sachimtrace_register_init (void)
332285242Sachim{
333285242Sachim  memcpy (old_regs, memory + REGISTER_ADDRESS, 8 * 4);
334285242Sachim  old_psw = memory[RL78_SFR_PSW];
335285242Sachim  old_sp = mem_get_hi (RL78_SFR_SP);
336285242Sachim}
337285242Sachim