diff options
author | DJ Delorie <dj@redhat.com> | 2009-11-24 19:22:45 +0000 |
---|---|---|
committer | DJ Delorie <dj@redhat.com> | 2009-11-24 19:22:45 +0000 |
commit | 4f8d4a386168d6152f3006187c5ecf722eb27d67 (patch) | |
tree | e86bf5972e5f09f8c37230b21c220a65a116e734 /sim/rx/mem.c | |
parent | e4d2e6658e104829003a91249ffe27ae1afb0b34 (diff) | |
download | gdb-4f8d4a386168d6152f3006187c5ecf722eb27d67.zip gdb-4f8d4a386168d6152f3006187c5ecf722eb27d67.tar.gz gdb-4f8d4a386168d6152f3006187c5ecf722eb27d67.tar.bz2 |
[sim]
* rx: New directory.
* configure.ac: Add entry for Renesas RX.
* configure: Regenerate.
[include/gdb]
* sim-rx.h: New.
Diffstat (limited to 'sim/rx/mem.c')
-rw-r--r-- | sim/rx/mem.c | 552 |
1 files changed, 552 insertions, 0 deletions
diff --git a/sim/rx/mem.c b/sim/rx/mem.c new file mode 100644 index 0000000..9209e2b --- /dev/null +++ b/sim/rx/mem.c @@ -0,0 +1,552 @@ +/* mem.c --- memory for RX simulator. + +Copyright (C) 2005, 2007, 2008, 2009 Free Software Foundation, Inc. +Contributed by Red Hat, Inc. + +This file is part of the GNU simulators. + +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. + +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 this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* This slows down the simulator and we get some false negatives from + gcc, like when it uses a long-sized hole to hold a byte-sized + variable, knowing that it doesn't care about the other bits. But, + if you need to track down a read-from-unitialized bug, set this to + 1. */ +#define RDCHECK 0 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "mem.h" +#include "cpu.h" +#include "syscalls.h" +#include "misc.h" +#include "err.h" + +#define L1_BITS (10) +#define L2_BITS (10) +#define OFF_BITS (12) + +#define L1_LEN (1 << L1_BITS) +#define L2_LEN (1 << L2_BITS) +#define OFF_LEN (1 << OFF_BITS) + +static unsigned char **pt[L1_LEN]; +static unsigned char **ptr[L1_LEN]; + +/* [ get=0/put=1 ][ byte size ] */ +static unsigned int mem_counters[2][5]; + +#define COUNT(isput,bytes) \ + if (verbose && enable_counting) mem_counters[isput][bytes]++ + +void +init_mem (void) +{ + int i, j; + + for (i = 0; i < L1_LEN; i++) + if (pt[i]) + { + for (j = 0; j < L2_LEN; j++) + if (pt[i][j]) + free (pt[i][j]); + free (pt[i]); + } + memset (pt, 0, sizeof (pt)); + memset (ptr, 0, sizeof (ptr)); + memset (mem_counters, 0, sizeof (mem_counters)); +} + +enum mem_ptr_action +{ + MPA_WRITING, + MPA_READING, + MPA_CONTENT_TYPE +}; + +static unsigned char * +mem_ptr (unsigned long address, enum mem_ptr_action action) +{ + 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) + execution_error (SIM_ERR_NULL_POINTER_DEREFERENCE, 0); + + if (pt[pt1] == 0) + { + pt[pt1] = (unsigned char **) calloc (L2_LEN, sizeof (char **)); + ptr[pt1] = (unsigned char **) calloc (L2_LEN, sizeof (char **)); + } + if (pt[pt1][pt2] == 0) + { + if (action == MPA_READING) + execution_error (SIM_ERR_READ_UNWRITTEN_PAGES, address); + + pt[pt1][pt2] = (unsigned char *) malloc (OFF_LEN); + memset (pt[pt1][pt2], 0, OFF_LEN); + ptr[pt1][pt2] = (unsigned char *) malloc (OFF_LEN); + memset (ptr[pt1][pt2], MC_UNINIT, OFF_LEN); + } + else if (action == MPA_READING + && ptr[pt1][pt2][pto] == MC_UNINIT) + execution_error (SIM_ERR_READ_UNWRITTEN_BYTES, address); + + if (action == MPA_WRITING) + { + if (ptr[pt1][pt2][pto] == MC_PUSHED_PC) + execution_error (SIM_ERR_CORRUPT_STACK, address); + ptr[pt1][pt2][pto] = MC_DATA; + } + + if (action == MPA_CONTENT_TYPE) + return ptr[pt1][pt2] + pto; + + return pt[pt1][pt2] + pto; +} + +static inline int +is_reserved_address (unsigned int address) +{ + return (address >= 0x00020000 && address < 0x00080000) + || (address >= 0x00100000 && address < 0x01000000) + || (address >= 0x08000000 && address < 0xff000000); +} + +static void +used (int rstart, int i, int j) +{ + int rend = i << (L2_BITS + OFF_BITS); + rend += j << OFF_BITS; + if (rstart == 0xe0000 && rend == 0xe1000) + return; + printf ("mem: %08x - %08x (%dk bytes)\n", rstart, rend - 1, + (rend - rstart) / 1024); +} + +static char * +mcs (int isput, int bytes) +{ + return comma (mem_counters[isput][bytes]); +} + +void +mem_usage_stats () +{ + int i, j; + int rstart = 0; + int pending = 0; + + for (i = 0; i < L1_LEN; i++) + if (pt[i]) + { + for (j = 0; j < L2_LEN; j++) + if (pt[i][j]) + { + if (!pending) + { + pending = 1; + rstart = (i << (L2_BITS + OFF_BITS)) + (j << OFF_BITS); + } + } + else if (pending) + { + pending = 0; + used (rstart, i, j); + } + } + else + { + if (pending) + { + pending = 0; + used (rstart, i, 0); + } + } + /* mem foo: 123456789012 123456789012 123456789012 123456789012 + 123456789012 */ + printf (" byte short 3byte long" + " opcode\n"); + if (verbose > 1) + { + /* Only use comma separated numbers when being very verbose. + Comma separated numbers are hard to parse in awk scripts. */ + 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), + mcs (1, 3), mcs (1, 4)); + } + else + { + printf ("mem get: %12u %12u %12u %12u %12u\n", + mem_counters[0][1], mem_counters[0][2], + mem_counters[0][3], mem_counters[0][4], + mem_counters[0][0]); + printf ("mem put: %12u %12u %12u %12u\n", + mem_counters [1][1], mem_counters [1][2], + mem_counters [1][3], mem_counters [1][4]); + } +} + +unsigned long +mem_usage_cycles (void) +{ + unsigned long rv = mem_counters[0][0]; + rv += mem_counters[0][1] * 1; + rv += mem_counters[0][2] * 2; + rv += mem_counters[0][3] * 3; + rv += mem_counters[0][4] * 4; + rv += mem_counters[1][1] * 1; + rv += mem_counters[1][2] * 2; + rv += mem_counters[1][3] * 3; + rv += mem_counters[1][4] * 4; + return rv; +} + +static int tpr = 0; +static void +s (int address, char *dir) +{ + if (tpr == 0) + printf ("MEM[%08x] %s", address, dir); + tpr++; +} + +#define S(d) if (trace) s(address, d) +static void +e () +{ + if (!trace) + return; + tpr--; + if (tpr == 0) + printf ("\n"); +} + +static char +mtypec (int address) +{ + unsigned char *cp = mem_ptr (address, MPA_CONTENT_TYPE); + return "udp"[*cp]; +} + +#define E() if (trace) e() + +void +mem_put_byte (unsigned int address, unsigned char value) +{ + unsigned char *m; + char tc = ' '; + + if (trace) + tc = mtypec (address); + m = mem_ptr (address, MPA_WRITING); + if (trace) + printf (" %02x%c", value, tc); + *m = value; + switch (address) + { + case 0x00e1: + { + static int old_led = -1; + static char *led_on[] = + { "\033[31m O ", "\033[32m O ", "\033[34m O " }; + static char *led_off[] = { "\033[0m · ", "\033[0m · ", "\033[0m · " }; + int i; + if (old_led != value) + { + fputs (" ", stdout); + for (i = 0; i < 3; i++) + if (value & (1 << i)) + fputs (led_off[i], stdout); + else + fputs (led_on[i], stdout); + fputs ("\033[0m\r", stdout); + fflush (stdout); + old_led = value; + } + } + break; + + case 0x3aa: /* uart1tx */ + { + static int pending_exit = 0; + if (value == 0) + { + if (pending_exit) + { + step_result = RX_MAKE_EXITED(value); + return; + } + pending_exit = 1; + } + else + putchar(value); + } + break; + + default: + if (is_reserved_address (address)) + generate_access_exception (); + } +} + +void +mem_put_qi (int address, unsigned char value) +{ + S ("<="); + mem_put_byte (address, value & 0xff); + E (); + COUNT (1, 1); +} + +void +mem_put_hi (int address, unsigned short value) +{ + S ("<="); + if (rx_big_endian) + { + mem_put_byte (address, value >> 8); + mem_put_byte (address + 1, value & 0xff); + } + else + { + mem_put_byte (address, value & 0xff); + mem_put_byte (address + 1, value >> 8); + } + E (); + COUNT (1, 2); +} + +void +mem_put_psi (int address, unsigned long value) +{ + S ("<="); + if (rx_big_endian) + { + mem_put_byte (address, value >> 16); + mem_put_byte (address + 1, (value >> 8) & 0xff); + mem_put_byte (address + 2, value & 0xff); + } + else + { + mem_put_byte (address, value & 0xff); + mem_put_byte (address + 1, (value >> 8) & 0xff); + mem_put_byte (address + 2, value >> 16); + } + E (); + COUNT (1, 3); +} + +void +mem_put_si (int address, unsigned long value) +{ + S ("<="); + if (rx_big_endian) + { + mem_put_byte (address + 0, (value >> 24) & 0xff); + mem_put_byte (address + 1, (value >> 16) & 0xff); + mem_put_byte (address + 2, (value >> 8) & 0xff); + mem_put_byte (address + 3, value & 0xff); + } + else + { + mem_put_byte (address + 0, value & 0xff); + mem_put_byte (address + 1, (value >> 8) & 0xff); + mem_put_byte (address + 2, (value >> 16) & 0xff); + mem_put_byte (address + 3, (value >> 24) & 0xff); + } + E (); + COUNT (1, 4); +} + +void +mem_put_blk (int address, void *bufptr, int nbytes) +{ + S ("<="); + if (enable_counting) + mem_counters[1][1] += nbytes; + while (nbytes--) + mem_put_byte (address++, *(unsigned char *) bufptr++); + E (); +} + +unsigned char +mem_get_pc (int address) +{ + unsigned char *m = mem_ptr (address, MPA_READING); + COUNT (0, 0); + return *m; +} + +static unsigned char +mem_get_byte (unsigned int address) +{ + unsigned char *m; + + S ("=>"); + m = mem_ptr (address, MPA_READING); + switch (address) + { + case 0x3ad: /* uart1c1 */ + E(); + return 2; /* transmitter empty */ + break; + default: + if (trace) + printf (" %02x%c", *m, mtypec (address)); + if (is_reserved_address (address)) + generate_access_exception (); + break; + } + E (); + return *m; +} + +unsigned char +mem_get_qi (int address) +{ + unsigned char rv; + S ("=>"); + rv = mem_get_byte (address); + COUNT (0, 1); + E (); + return rv; +} + +unsigned short +mem_get_hi (int address) +{ + unsigned short rv; + S ("=>"); + if (rx_big_endian) + { + rv = mem_get_byte (address) << 8; + rv |= mem_get_byte (address + 1); + } + else + { + rv = mem_get_byte (address); + rv |= mem_get_byte (address + 1) << 8; + } + COUNT (0, 2); + E (); + return rv; +} + +unsigned long +mem_get_psi (int address) +{ + unsigned long rv; + S ("=>"); + if (rx_big_endian) + { + rv = mem_get_byte (address + 2); + rv |= mem_get_byte (address + 1) << 8; + rv |= mem_get_byte (address) << 16; + } + else + { + rv = mem_get_byte (address); + rv |= mem_get_byte (address + 1) << 8; + rv |= mem_get_byte (address + 2) << 16; + } + COUNT (0, 3); + E (); + return rv; +} + +unsigned long +mem_get_si (int address) +{ + unsigned long rv; + S ("=>"); + if (rx_big_endian) + { + rv = mem_get_byte (address + 3); + rv |= mem_get_byte (address + 2) << 8; + rv |= mem_get_byte (address + 1) << 16; + rv |= mem_get_byte (address) << 24; + } + else + { + rv = mem_get_byte (address); + rv |= mem_get_byte (address + 1) << 8; + rv |= mem_get_byte (address + 2) << 16; + rv |= mem_get_byte (address + 3) << 24; + } + COUNT (0, 4); + E (); + return rv; +} + +void +mem_get_blk (int address, void *bufptr, int nbytes) +{ + S ("=>"); + if (enable_counting) + mem_counters[0][1] += nbytes; + while (nbytes--) + *(char *) bufptr++ = mem_get_byte (address++); + E (); +} + +int +sign_ext (int v, int bits) +{ + if (bits < 32) + { + v &= (1 << bits) - 1; + if (v & (1 << (bits - 1))) + v -= (1 << bits); + } + return v; +} + +void +mem_set_content_type (int address, enum mem_content_type type) +{ + unsigned char *mt = mem_ptr (address, MPA_CONTENT_TYPE); + *mt = type; +} + +void +mem_set_content_range (int start_address, int end_address, enum mem_content_type type) +{ + while (start_address < end_address) + { + int sz, ofs; + unsigned char *mt; + + sz = end_address - start_address; + ofs = start_address % L1_LEN; + if (sz + ofs > L1_LEN) + sz = L1_LEN - ofs; + + mt = mem_ptr (start_address, MPA_CONTENT_TYPE); + memset (mt, type, sz); + + start_address += sz; + } +} + +enum mem_content_type +mem_get_content_type (int address) +{ + unsigned char *mt = mem_ptr (address, MPA_CONTENT_TYPE); + return *mt; +} |