* Makefile.in: Add Timer A support.

* cpu.h (m32c_opcode_pc): New.
(in_gdb): New.
* gdb-if.c (sim_open): Add Timer A support.  Support unbuffered
console.
* int.c (trigger_interrupt): Manage the U flag properly.
(trigger_based_interrupt): Likewise.
(trigger_fixed_interrupt): New.
(trigger_peripheral_interrupt): New.
* int.h (trigger_peripheral_interrupt): New.
* m32c.opc: Use m32c_opcode_pc throughout, as needed.
(decode_m32c): Detect jump-to-zero with traceback.
(BRK): Try to do the right thing, keeping track of whether we're
in gdb or not, and if the user has provided a handler or not.
(GBRK): Alternate break opcode for gdb, in case the user's app
needs to use BRK for itself.
(BRK2): Implement.
* main.c: Add Timer A support.  Support TCP-based console.
(setup_tcp_console): New.
(main): Add Timer A support.  Support TCP-based console.
* mem.c: Add Timer A support.  Support TCP-based console.
(mem_ptr): Enhance NULL pointer detection.
(stdin_ready): New.
(m32c_sim_restore_console): New.
(mem_get_byte): Check for console input ready.
(update_timer_a): New.
* r8c.opc (SSTR): Use r0l, not r0h.
(REIT): Fix return frame logic.
* reg.c (print_flags): New.
(trace_register_changes): Use it.
(m32c_dump_all_registers): New.
* timer_a.h: New.

* load.c: Fix indentation.
* trace.c: Fix indentation.
* trace.h: Fix indentation.
This commit is contained in:
DJ Delorie
2008-06-06 19:18:15 +00:00
parent ebfe2e3fb6
commit 3877a1459b
18 changed files with 519 additions and 67 deletions

View File

@@ -22,11 +22,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/select.h>
#include <termios.h>
#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 +48,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
static unsigned char **pt[L1_LEN];
int m32c_console_ifd = 0;
int m32c_console_ofd = 1;
#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]++
@@ -64,14 +81,23 @@ init_mem (void)
static unsigned char *
mem_ptr (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)
@@ -138,7 +164,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),
@@ -167,6 +193,8 @@ e ()
#define E() if (trace) e()
extern int m32c_disassemble;
void
mem_put_byte (int address, unsigned char value)
{
@@ -199,21 +227,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;
case 0x3aa: /* uart1tx */
/* 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 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;
@@ -301,24 +373,94 @@ mem_get_pc ()
return *m;
}
static int console_raw = 0;
static struct termios attr, oattr;
static int
stdin_ready ()
{
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 ()
{
tcsetattr (m32c_console_ifd, TCSANOW, &oattr);
console_raw = 0;
}
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;
case 0x2ed: /* m32c uart1c1 */
case 0x3ad: /* m16c uart1c1 */
#if 0
if (!console_raw)
{
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);
}
#endif
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;
}
#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
}
S ("=>");
if (trace)
printf (" %02x", *m);
E ();
return *m;
}
@@ -395,3 +537,61 @@ sign_ext (int v, int bits)
}
return v;
}
#if TIMER_A
void
update_timer_a ()
{
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