1/* mem.c --- memory for M32C simulator.
2
3Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011
4Free Software Foundation, Inc.
5Contributed by Red Hat, Inc.
6
7This file is part of the GNU simulators.
8
9This program is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
11the Free Software Foundation; either version 3 of the License, or
12(at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21
22
23#include "config.h"
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <ctype.h>
28#include <sys/time.h>
29#include <sys/types.h>
30#include <unistd.h>
31#ifdef HAVE_SYS_SELECT_H
32#include <sys/select.h>
33#endif
34#ifdef HAVE_TERMIOS_H
35#include <termios.h>
36#endif
37
38#include "mem.h"
39#include "cpu.h"
40#include "syscalls.h"
41#include "misc.h"
42#ifdef TIMER_A
43#include "int.h"
44#include "timer_a.h"
45#endif
46
47#define L1_BITS  (10)
48#define L2_BITS  (10)
49#define OFF_BITS (12)
50
51#define L1_LEN  (1 << L1_BITS)
52#define L2_LEN  (1 << L2_BITS)
53#define OFF_LEN (1 << OFF_BITS)
54
55static unsigned char **pt[L1_LEN];
56
57#ifdef HAVE_TERMIOS_H
58int m32c_console_ifd = 0;
59#endif
60int m32c_console_ofd = 1;
61#ifdef HAVE_TERMIOS_H
62int m32c_use_raw_console = 0;
63#endif
64
65#ifdef TIMER_A
66Timer_A timer_a;
67#endif
68
69/* [ get=0/put=1 ][ byte size ] */
70static unsigned int mem_counters[2][5];
71
72#define COUNT(isput,bytes)                                      \
73  if (verbose && enable_counting) mem_counters[isput][bytes]++
74
75void
76init_mem (void)
77{
78  int i, j;
79
80  for (i = 0; i < L1_LEN; i++)
81    if (pt[i])
82      {
83	for (j = 0; j < L2_LEN; j++)
84	  if (pt[i][j])
85	    free (pt[i][j]);
86	free (pt[i]);
87      }
88  memset (pt, 0, sizeof (pt));
89  memset (mem_counters, 0, sizeof (mem_counters));
90}
91
92static unsigned char *
93mem_ptr (address)
94{
95  static int recursing = 0;
96  int pt1 = (address >> (L2_BITS + OFF_BITS)) & ((1 << L1_BITS) - 1);
97  int pt2 = (address >> OFF_BITS) & ((1 << L2_BITS) - 1);
98  int pto = address & ((1 << OFF_BITS) - 1);
99
100  if (address == 0 && !recursing)
101    {
102      recursing = 1;
103      put_reg (pc, m32c_opcode_pc);
104      printf ("NULL pointer dereference at pc=0x%x\n", get_reg (pc));
105      step_result = M32C_MAKE_HIT_BREAK ();
106#if 0
107      /* This code can be re-enabled to help diagnose NULL pointer
108         bugs that aren't debuggable in GDB.  */
109      m32c_dump_all_registers ();
110      exit (1);
111#endif
112    }
113
114  if (pt[pt1] == 0)
115    pt[pt1] = (unsigned char **) calloc (L2_LEN, sizeof (char **));
116  if (pt[pt1][pt2] == 0)
117    {
118      pt[pt1][pt2] = (unsigned char *) malloc (OFF_LEN);
119      memset (pt[pt1][pt2], 0, OFF_LEN);
120    }
121
122  return pt[pt1][pt2] + pto;
123}
124
125static void
126used (int rstart, int i, int j)
127{
128  int rend = i << (L2_BITS + OFF_BITS);
129  rend += j << OFF_BITS;
130  if (rstart == 0xe0000 && rend == 0xe1000)
131    return;
132  printf ("mem:   %08x - %08x (%dk bytes)\n", rstart, rend - 1,
133	  (rend - rstart) / 1024);
134}
135
136static char *
137mcs (int isput, int bytes)
138{
139  return comma (mem_counters[isput][bytes]);
140}
141
142void
143mem_usage_stats ()
144{
145  int i, j;
146  int rstart = 0;
147  int pending = 0;
148
149  for (i = 0; i < L1_LEN; i++)
150    if (pt[i])
151      {
152	for (j = 0; j < L2_LEN; j++)
153	  if (pt[i][j])
154	    {
155	      if (!pending)
156		{
157		  pending = 1;
158		  rstart = (i << (L2_BITS + OFF_BITS)) + (j << OFF_BITS);
159		}
160	    }
161	  else if (pending)
162	    {
163	      pending = 0;
164	      used (rstart, i, j);
165	    }
166      }
167    else
168      {
169	if (pending)
170	  {
171	    pending = 0;
172	    used (rstart, i, 0);
173	  }
174      }
175  /*       mem foo: 123456789012 123456789012 123456789012 123456789012
176            123456789012 */
177  printf ("                 byte        short      pointer         long"
178	  "        fetch\n");
179  printf ("mem get: %12s %12s %12s %12s %12s\n", mcs (0, 1), mcs (0, 2),
180	  mcs (0, 3), mcs (0, 4), mcs (0, 0));
181  printf ("mem put: %12s %12s %12s %12s\n", mcs (1, 1), mcs (1, 2),
182	  mcs (1, 3), mcs (1, 4));
183}
184
185static int tpr = 0;
186static void
187s (int address, char *dir)
188{
189  if (tpr == 0)
190    printf ("MEM[%0*x] %s", membus_mask == 0xfffff ? 5 : 6, address, dir);
191  tpr++;
192}
193
194#define S(d) if (trace) s(address, d)
195static void
196e ()
197{
198  if (!trace)
199    return;
200  tpr--;
201  if (tpr == 0)
202    printf ("\n");
203}
204
205#define E() if (trace) e()
206
207extern int m32c_disassemble;
208
209void
210mem_put_byte (int address, unsigned char value)
211{
212  unsigned char *m;
213  address &= membus_mask;
214  m = mem_ptr (address);
215  if (trace)
216    printf (" %02x", value);
217  *m = value;
218  switch (address)
219    {
220    case 0x00e1:
221      {
222	static int old_led = -1;
223	static char *led_on[] =
224	  { "\033[31m O ", "\033[32m O ", "\033[34m O " };
225	static char *led_off[] = { "\033[0m � ", "\033[0m � ", "\033[0m � " };
226	int i;
227	if (old_led != value)
228	  {
229	    fputs ("  ", stdout);
230	    for (i = 0; i < 3; i++)
231	      if (value & (1 << i))
232		fputs (led_off[i], stdout);
233	      else
234		fputs (led_on[i], stdout);
235	    fputs ("\033[0m\r", stdout);
236	    fflush (stdout);
237	    old_led = value;
238	  }
239      }
240      break;
241#ifdef TIMER_A
242      /* M32C Timer A */
243    case 0x346:		/* TA0low */
244      timer_a.count = (timer_a.count & 0xff00) | value;
245      timer_a.reload = timer_a.count;
246      break;
247    case 0x347:		/* TA0high */
248      timer_a.count = (timer_a.count & 0x00ff) | (value << 8);
249      timer_a.reload = timer_a.count;
250      break;
251    case 0x340:		/* TABSR */
252      timer_a.bsr = value;
253      break;
254    case 0x356:		/* TA0MR */
255      timer_a.mode = value;
256      break;
257    case 0x35f:		/* TCSPR */
258      timer_a.tcspr = value;
259      break;
260    case 0x006c:		/* TA0IC */
261      timer_a.ic = value;
262      break;
263
264      /* R8C Timer RA */
265    case 0x100:		/* TRACR */
266      timer_a.bsr = value;
267      break;
268    case 0x102:		/* TRAMR */
269      timer_a.mode = value;
270      break;
271    case 0x104:		/* TRA */
272      timer_a.count = value;
273      timer_a.reload = value;
274      break;
275    case 0x103:		/* TRAPRE */
276      timer_a.tcspr = value;
277      break;
278    case 0x0056:		/* TA0IC */
279      timer_a.ic = value;
280      break;
281#endif
282
283    case 0x2ea:		/* m32c uart1tx */
284    case 0x3aa:		/* m16c uart1tx */
285      {
286	static int pending_exit = 0;
287	if (value == 0)
288	  {
289	    if (pending_exit)
290	      {
291		step_result = M32C_MAKE_EXITED (value);
292		return;
293	      }
294	    pending_exit = 1;
295	  }
296	else
297	  {
298	    write (m32c_console_ofd, &value, 1);
299	  }
300      }
301      break;
302
303    case 0x400:
304      m32c_syscall (value);
305      break;
306
307    case 0x401:
308      putchar (value);
309      break;
310
311    case 0x402:
312      printf ("SimTrace: %06lx %02x\n", regs.r_pc, value);
313      break;
314
315    case 0x403:
316      printf ("SimTrap: %06lx %02x\n", regs.r_pc, value);
317      abort ();
318    }
319}
320
321void
322mem_put_qi (int address, unsigned char value)
323{
324  S ("<=");
325  mem_put_byte (address, value & 0xff);
326  E ();
327  COUNT (1, 1);
328}
329
330void
331mem_put_hi (int address, unsigned short value)
332{
333  if (address == 0x402)
334    {
335      printf ("SimTrace: %06lx %04x\n", regs.r_pc, value);
336      return;
337    }
338  S ("<=");
339  mem_put_byte (address, value & 0xff);
340  mem_put_byte (address + 1, value >> 8);
341  E ();
342  COUNT (1, 2);
343}
344
345void
346mem_put_psi (int address, unsigned long value)
347{
348  S ("<=");
349  mem_put_byte (address, value & 0xff);
350  mem_put_byte (address + 1, (value >> 8) & 0xff);
351  mem_put_byte (address + 2, value >> 16);
352  E ();
353  COUNT (1, 3);
354}
355
356void
357mem_put_si (int address, unsigned long value)
358{
359  S ("<=");
360  mem_put_byte (address, value & 0xff);
361  mem_put_byte (address + 1, (value >> 8) & 0xff);
362  mem_put_byte (address + 2, (value >> 16) & 0xff);
363  mem_put_byte (address + 3, (value >> 24) & 0xff);
364  E ();
365  COUNT (1, 4);
366}
367
368void
369mem_put_blk (int address, const void *bufptr, int nbytes)
370{
371  S ("<=");
372  if (enable_counting)
373    mem_counters[1][1] += nbytes;
374  while (nbytes--)
375    mem_put_byte (address++, *(const unsigned char *) bufptr++);
376  E ();
377}
378
379unsigned char
380mem_get_pc ()
381{
382  unsigned char *m = mem_ptr (regs.r_pc & membus_mask);
383  COUNT (0, 0);
384  return *m;
385}
386
387#ifdef HAVE_TERMIOS_H
388static int console_raw = 0;
389static struct termios oattr;
390
391static int
392stdin_ready ()
393{
394  fd_set ifd;
395  int n;
396  struct timeval t;
397
398  t.tv_sec = 0;
399  t.tv_usec = 0;
400  FD_ZERO (&ifd);
401  FD_SET (m32c_console_ifd, &ifd);
402  n = select (1, &ifd, 0, 0, &t);
403  return n > 0;
404}
405
406void
407m32c_sim_restore_console ()
408{
409  if (console_raw)
410    tcsetattr (m32c_console_ifd, TCSANOW, &oattr);
411  console_raw = 0;
412}
413#endif
414
415static unsigned char
416mem_get_byte (int address)
417{
418  unsigned char *m;
419  address &= membus_mask;
420  m = mem_ptr (address);
421  switch (address)
422    {
423#ifdef HAVE_TERMIOS_H
424    case 0x2ed:		/* m32c uart1c1 */
425    case 0x3ad:		/* m16c uart1c1 */
426
427      if (!console_raw && m32c_use_raw_console)
428	{
429	  struct termios attr;
430	  tcgetattr (m32c_console_ifd, &attr);
431	  tcgetattr (m32c_console_ifd, &oattr);
432	  /* We want each key to be sent as the user presses them.  */
433	  attr.c_lflag &= ~(ICANON | ECHO | ECHOE);
434	  tcsetattr (m32c_console_ifd, TCSANOW, &attr);
435	  console_raw = 1;
436	  atexit (m32c_sim_restore_console);
437	}
438
439      if (stdin_ready ())
440	return 0x02;		/* tx empty and rx full */
441      else
442	return 0x0a;		/* transmitter empty */
443
444    case 0x2ee:		/* m32c uart1 rx */
445      {
446	char c;
447	read (m32c_console_ifd, &c, 1);
448	if (m32c_console_ifd == 0 && c == 3)	/* Ctrl-C */
449	  {
450	    printf ("Ctrl-C!\n");
451	    exit (0);
452	  }
453
454	if (m32c_console_ifd != 1)
455	  {
456	    if (isgraph (c))
457	      printf ("\033[31m%c\033[0m", c);
458	    else
459	      printf ("\033[31m%02x\033[0m", c);
460	  }
461	return c;
462      }
463#endif
464
465#ifdef TIMER_A
466    case 0x346:		/* TA0low */
467      return timer_a.count & 0xff;
468    case 0x347:		/* TA0high */
469      return (timer_a.count >> 8) & 0xff;
470    case 0x104:		/* TRA */
471      return timer_a.count;
472#endif
473
474    default:
475      /* In case both cases above are not included.  */
476      ;
477    }
478
479  S ("=>");
480  if (trace)
481    printf (" %02x", *m);
482  E ();
483  return *m;
484}
485
486unsigned char
487mem_get_qi (int address)
488{
489  unsigned char rv;
490  S ("=>");
491  rv = mem_get_byte (address);
492  COUNT (0, 1);
493  E ();
494  return rv;
495}
496
497unsigned short
498mem_get_hi (int address)
499{
500  unsigned short rv;
501  S ("=>");
502  rv = mem_get_byte (address);
503  rv |= mem_get_byte (address + 1) * 256;
504  COUNT (0, 2);
505  E ();
506  return rv;
507}
508
509unsigned long
510mem_get_psi (int address)
511{
512  unsigned long rv;
513  S ("=>");
514  rv = mem_get_byte (address);
515  rv |= mem_get_byte (address + 1) * 256;
516  rv |= mem_get_byte (address + 2) * 65536;
517  COUNT (0, 3);
518  E ();
519  return rv;
520}
521
522unsigned long
523mem_get_si (int address)
524{
525  unsigned long rv;
526  S ("=>");
527  rv = mem_get_byte (address);
528  rv |= mem_get_byte (address + 1) << 8;
529  rv |= mem_get_byte (address + 2) << 16;
530  rv |= mem_get_byte (address + 3) << 24;
531  COUNT (0, 4);
532  E ();
533  return rv;
534}
535
536void
537mem_get_blk (int address, void *bufptr, int nbytes)
538{
539  S ("=>");
540  if (enable_counting)
541    mem_counters[0][1] += nbytes;
542  while (nbytes--)
543    *(char *) bufptr++ = mem_get_byte (address++);
544  E ();
545}
546
547int
548sign_ext (int v, int bits)
549{
550  if (bits < 32)
551    {
552      v &= (1 << bits) - 1;
553      if (v & (1 << (bits - 1)))
554	v -= (1 << bits);
555    }
556  return v;
557}
558
559#if TIMER_A
560void
561update_timer_a ()
562{
563  if (timer_a.bsr & 1)
564    {
565      timer_a.prescale--;
566      if (timer_a.prescale < 0)
567	{
568	  if (A24)
569	    {
570	      switch (timer_a.mode & 0xc0)
571		{
572		case 0x00:
573		  timer_a.prescale = 0;
574		  break;
575		case 0x40:
576		  timer_a.prescale = 8;
577		  break;
578		case 0x80:
579		  timer_a.prescale = timer_a.tcspr & 0x0f;
580		  break;
581		case 0xc0:
582		  timer_a.prescale = 32;
583		  break;
584		}
585	    }
586	  else
587	    {
588	      timer_a.prescale = timer_a.tcspr;
589	    }
590	  timer_a.count--;
591	  if (timer_a.count < 0)
592	    {
593	      timer_a.count = timer_a.reload;
594	      if (timer_a.ic & 7)
595		{
596		  if (A24)
597		    mem_put_qi (0x6c, timer_a.ic | 0x08);
598		  else
599		    mem_put_qi (0x56, timer_a.ic | 0x08);
600		}
601	    }
602	}
603    }
604
605  if (regs.r_flags & FLAGBIT_I	/* interrupts enabled */
606      && timer_a.ic & 0x08	/* timer A interrupt triggered */
607      && (timer_a.ic & 0x07) > ((regs.r_flags >> 12) & 0x07))
608    {
609      if (A24)
610	trigger_peripheral_interrupt (12, 0x06c);
611      else
612	trigger_peripheral_interrupt (22, 0x056);
613    }
614}
615#endif
616