/* mem.c --- memory for M32C simulator.
-Copyright (C) 2005 Free Software Foundation, Inc.
+Copyright (C) 2005-2016 Free Software Foundation, Inc.
Contributed by Red Hat, Inc.
This file is part of the GNU simulators.
-The GNU simulators are free software; you can redistribute them and/or
-modify them under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
-The GNU simulators are distributed in the hope that they will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with the GNU simulators; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA */
+along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#endif
#include "mem.h"
#include "cpu.h"
#include "syscalls.h"
#include "misc.h"
+#ifdef TIMER_A
+#include "int.h"
+#include "timer_a.h"
+#endif
#define L1_BITS (10)
#define L2_BITS (10)
static unsigned char **pt[L1_LEN];
+#ifdef HAVE_TERMIOS_H
+int m32c_console_ifd = 0;
+#endif
+int m32c_console_ofd = 1;
+#ifdef HAVE_TERMIOS_H
+int m32c_use_raw_console = 0;
+#endif
+
+#ifdef TIMER_A
+Timer_A timer_a;
+#endif
+
/* [ get=0/put=1 ][ byte size ] */
-static unsigned int mem_counters[2][4];
+static unsigned int mem_counters[2][5];
#define COUNT(isput,bytes) \
if (verbose && enable_counting) mem_counters[isput][bytes]++
}
static unsigned char *
-mem_ptr (address)
+mem_ptr (int address)
{
+ static int recursing = 0;
int pt1 = (address >> (L2_BITS + OFF_BITS)) & ((1 << L1_BITS) - 1);
int pt2 = (address >> OFF_BITS) & ((1 << L2_BITS) - 1);
int pto = address & ((1 << OFF_BITS) - 1);
- if (address == 0)
+ if (address == 0 && !recursing)
{
- printf ("NULL pointer dereference\n");
+ recursing = 1;
+ put_reg (pc, m32c_opcode_pc);
+ printf ("NULL pointer dereference at pc=0x%x\n", get_reg (pc));
+ step_result = M32C_MAKE_HIT_BREAK ();
+#if 0
+ /* This code can be re-enabled to help diagnose NULL pointer
+ bugs that aren't debuggable in GDB. */
+ m32c_dump_all_registers ();
exit (1);
+#endif
}
if (pt[pt1] == 0)
}
void
-mem_usage_stats ()
+mem_usage_stats (void)
{
int i, j;
int rstart = 0;
/* mem foo: 123456789012 123456789012 123456789012 123456789012
123456789012 */
printf (" byte short pointer long"
- " fetch\n");
+ " fetch\n");
printf ("mem get: %12s %12s %12s %12s %12s\n", mcs (0, 1), mcs (0, 2),
mcs (0, 3), mcs (0, 4), mcs (0, 0));
printf ("mem put: %12s %12s %12s %12s\n", mcs (1, 1), mcs (1, 2),
#define S(d) if (trace) s(address, d)
static void
-e ()
+e (void)
{
if (!trace)
return;
#define E() if (trace) e()
-void
+extern int m32c_disassemble;
+
+static void
mem_put_byte (int address, unsigned char value)
{
unsigned char *m;
}
}
break;
+#ifdef TIMER_A
+ /* M32C Timer A */
+ case 0x346: /* TA0low */
+ timer_a.count = (timer_a.count & 0xff00) | value;
+ timer_a.reload = timer_a.count;
+ break;
+ case 0x347: /* TA0high */
+ timer_a.count = (timer_a.count & 0x00ff) | (value << 8);
+ timer_a.reload = timer_a.count;
+ break;
+ case 0x340: /* TABSR */
+ timer_a.bsr = value;
+ break;
+ case 0x356: /* TA0MR */
+ timer_a.mode = value;
+ break;
+ case 0x35f: /* TCSPR */
+ timer_a.tcspr = value;
+ break;
+ case 0x006c: /* TA0IC */
+ timer_a.ic = value;
+ break;
+
+ /* R8C Timer RA */
+ case 0x100: /* TRACR */
+ timer_a.bsr = value;
+ break;
+ case 0x102: /* TRAMR */
+ timer_a.mode = value;
+ break;
+ case 0x104: /* TRA */
+ timer_a.count = value;
+ timer_a.reload = value;
+ break;
+ case 0x103: /* TRAPRE */
+ timer_a.tcspr = value;
+ break;
+ case 0x0056: /* TA0IC */
+ timer_a.ic = value;
+ break;
+#endif
- case 0x3aa: /* uart1tx */
+ case 0x2ea: /* m32c uart1tx */
+ case 0x3aa: /* m16c uart1tx */
{
static int pending_exit = 0;
if (value == 0)
{
if (pending_exit)
{
- step_result = M32C_MAKE_EXITED(value);
+ step_result = M32C_MAKE_EXITED (value);
return;
}
pending_exit = 1;
}
else
- putchar(value);
+ {
+ write (m32c_console_ofd, &value, 1);
+ }
}
break;
}
void
-mem_put_blk (int address, void *bufptr, int nbytes)
+mem_put_blk (int address, const void *bufptr, int nbytes)
{
S ("<=");
if (enable_counting)
mem_counters[1][1] += nbytes;
while (nbytes--)
- mem_put_byte (address++, *(unsigned char *) bufptr++);
+ mem_put_byte (address++, *(const unsigned char *) bufptr++);
E ();
}
unsigned char
-mem_get_pc ()
+mem_get_pc (void)
{
unsigned char *m = mem_ptr (regs.r_pc & membus_mask);
COUNT (0, 0);
return *m;
}
+#ifdef HAVE_TERMIOS_H
+static int console_raw = 0;
+static struct termios oattr;
+
+static int
+stdin_ready (void)
+{
+ fd_set ifd;
+ int n;
+ struct timeval t;
+
+ t.tv_sec = 0;
+ t.tv_usec = 0;
+ FD_ZERO (&ifd);
+ FD_SET (m32c_console_ifd, &ifd);
+ n = select (1, &ifd, 0, 0, &t);
+ return n > 0;
+}
+
+void
+m32c_sim_restore_console (void)
+{
+ if (console_raw)
+ tcsetattr (m32c_console_ifd, TCSANOW, &oattr);
+ console_raw = 0;
+}
+#endif
+
static unsigned char
mem_get_byte (int address)
{
unsigned char *m;
address &= membus_mask;
- S ("=>");
m = mem_ptr (address);
switch (address)
{
- case 0x3ad: /* uart1c1 */
- E();
- return 2; /* transmitter empty */
- break;
- default:
- if (trace)
- printf (" %02x", *m);
- break;
+#ifdef HAVE_TERMIOS_H
+ case 0x2ed: /* m32c uart1c1 */
+ case 0x3ad: /* m16c uart1c1 */
+
+ if (!console_raw && m32c_use_raw_console)
+ {
+ struct termios attr;
+ tcgetattr (m32c_console_ifd, &attr);
+ tcgetattr (m32c_console_ifd, &oattr);
+ /* We want each key to be sent as the user presses them. */
+ attr.c_lflag &= ~(ICANON | ECHO | ECHOE);
+ tcsetattr (m32c_console_ifd, TCSANOW, &attr);
+ console_raw = 1;
+ atexit (m32c_sim_restore_console);
+ }
+
+ if (stdin_ready ())
+ return 0x02; /* tx empty and rx full */
+ else
+ return 0x0a; /* transmitter empty */
+
+ case 0x2ee: /* m32c uart1 rx */
+ {
+ char c;
+ read (m32c_console_ifd, &c, 1);
+ if (m32c_console_ifd == 0 && c == 3) /* Ctrl-C */
+ {
+ printf ("Ctrl-C!\n");
+ exit (0);
+ }
+
+ if (m32c_console_ifd != 1)
+ {
+ if (isgraph (c))
+ printf ("\033[31m%c\033[0m", c);
+ else
+ printf ("\033[31m%02x\033[0m", c);
+ }
+ return c;
+ }
+#endif
+
+#ifdef TIMER_A
+ case 0x346: /* TA0low */
+ return timer_a.count & 0xff;
+ case 0x347: /* TA0high */
+ return (timer_a.count >> 8) & 0xff;
+ case 0x104: /* TRA */
+ return timer_a.count;
+#endif
+
+ default:
+ /* In case both cases above are not included. */
+ ;
}
+
+ S ("=>");
+ if (trace)
+ printf (" %02x", *m);
E ();
return *m;
}
}
return v;
}
+
+#if TIMER_A
+void
+update_timer_a (void)
+{
+ if (timer_a.bsr & 1)
+ {
+ timer_a.prescale--;
+ if (timer_a.prescale < 0)
+ {
+ if (A24)
+ {
+ switch (timer_a.mode & 0xc0)
+ {
+ case 0x00:
+ timer_a.prescale = 0;
+ break;
+ case 0x40:
+ timer_a.prescale = 8;
+ break;
+ case 0x80:
+ timer_a.prescale = timer_a.tcspr & 0x0f;
+ break;
+ case 0xc0:
+ timer_a.prescale = 32;
+ break;
+ }
+ }
+ else
+ {
+ timer_a.prescale = timer_a.tcspr;
+ }
+ timer_a.count--;
+ if (timer_a.count < 0)
+ {
+ timer_a.count = timer_a.reload;
+ if (timer_a.ic & 7)
+ {
+ if (A24)
+ mem_put_qi (0x6c, timer_a.ic | 0x08);
+ else
+ mem_put_qi (0x56, timer_a.ic | 0x08);
+ }
+ }
+ }
+ }
+
+ if (regs.r_flags & FLAGBIT_I /* interrupts enabled */
+ && timer_a.ic & 0x08 /* timer A interrupt triggered */
+ && (timer_a.ic & 0x07) > ((regs.r_flags >> 12) & 0x07))
+ {
+ if (A24)
+ trigger_peripheral_interrupt (12, 0x06c);
+ else
+ trigger_peripheral_interrupt (22, 0x056);
+ }
+}
+#endif