X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=sim%2Fm32c%2Fmem.c;h=d7e26828ebb5c287a805f9d51242104366b9ac48;hb=5fd104addfddb68844fb8df67be832ee98ad9888;hp=edae7bf4df9373e36e127b86ff9ecd41da590628;hpb=4744ac1bb0d2f2294c7762577262fdcafb67883b;p=deliverable%2Fbinutils-gdb.git
diff --git a/sim/m32c/mem.c b/sim/m32c/mem.c
index edae7bf4df..d7e26828eb 100644
--- a/sim/m32c/mem.c
+++ b/sim/m32c/mem.c
@@ -1,6 +1,6 @@
/* mem.c --- memory for M32C simulator.
-Copyright (C) 2005, 2007 Free Software Foundation, Inc.
+Copyright (C) 2005-2020 Free Software Foundation, Inc.
Contributed by Red Hat, Inc.
This file is part of the GNU simulators.
@@ -19,14 +19,29 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see . */
+#include "config.h"
#include
#include
#include
+#include
+#include
+#include
+#include
+#ifdef HAVE_SYS_SELECT_H
+#include
+#endif
+#ifdef HAVE_TERMIOS_H
+#include
+#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)
@@ -38,8 +53,20 @@ along with this program. If not, see . */
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]++
@@ -62,16 +89,25 @@ init_mem (void)
}
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)
@@ -103,7 +139,7 @@ mcs (int isput, int bytes)
}
void
-mem_usage_stats ()
+mem_usage_stats (void)
{
int i, j;
int rstart = 0;
@@ -138,7 +174,7 @@ mem_usage_stats ()
/* 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),
@@ -156,7 +192,7 @@ s (int address, char *dir)
#define S(d) if (trace) s(address, d)
static void
-e ()
+e (void)
{
if (!trace)
return;
@@ -167,7 +203,9 @@ e ()
#define E() if (trace) e()
-void
+extern int m32c_disassemble;
+
+static void
mem_put_byte (int address, unsigned char value)
{
unsigned char *m;
@@ -199,21 +237,65 @@ mem_put_byte (int address, unsigned char value)
}
}
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;
@@ -283,42 +365,119 @@ mem_put_si (int address, unsigned long value)
}
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;
}
@@ -395,3 +554,61 @@ sign_ext (int v, int bits)
}
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