diff options
Diffstat (limited to 'gdb/arc-memory.c')
-rw-r--r-- | gdb/arc-memory.c | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/gdb/arc-memory.c b/gdb/arc-memory.c new file mode 100644 index 00000000000..806efb0d3c2 --- /dev/null +++ b/gdb/arc-memory.c @@ -0,0 +1,445 @@ +/* Target dependent code for ARC processor family, for GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + Contributed by ARC International (www.arc.com) + + Author: + Richard Stuckey <richard.stuckey@arc.com> + + This file is part of GDB. + + 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/>. */ + +/******************************************************************************/ +/* */ +/* Outline: */ +/* This module implements operations for reading data from and writing */ +/* data to target memory. */ +/* */ +/* The operations may be required to transfer arbitrary amounts of data */ +/* to/from arbitrary addresses in memory; however, the supplied transfer */ +/* operations must be assumed to be able only to transfer multiple words */ +/* of data to/from word-aligned addresses. */ +/* */ +/* This gives the general case: */ +/* */ +/* word boundaries */ +/* | */ +/* ------------------------------------------------- */ +/* | | | | | | */ +/* ----------------------------------------------------------- */ +/* | g g L L | W W W W | W W W W | W W W W | T T e e | */ +/* ----------------------------------------------------------- */ +/* ^ */ +/* |-------------------------------------| */ +/* | len */ +/* addr */ +/* */ +/* where addr is the base address of the data to be transferred */ +/* len is the number of bytes of data to be transferred */ +/* W denotes a byte that can be transfered in a whole word */ +/* L denotes a leading byte */ +/* T denotes a trailing byte */ +/* g denotes a gap byte */ +/* e denotes a end gap byte */ +/* */ +/* There may be 0 .. BYTES_IN_WORD - 1 leading bytes, 0 or more whole */ +/* words, and 0 .. BYTES_IN_WORD - 1 trailing bytes. If the given address */ +/* is word-aligned, there is no gap and hence no leading bytes. */ +/* */ +/* There is also a pathological case: */ +/* */ +/* word boundaries */ +/* | */ +/* --------- */ +/* | | */ +/* ----------------------------------------------------------- */ +/* | g B B e | */ +/* ----------------------------------------------------------- */ +/* ^ */ +/* |-| */ +/* | len */ +/* addr */ +/* */ +/* where 1 .. BYTES_IN_WORD - 2 bytes of data in the middle of a word */ +/* must be transfered. */ +/* */ +/* In a write operation, it is necessary to preserve the contents of the */ +/* gap and end gap bytes, if any - this is done by first reading the word */ +/* which contains those bytes, constructing a new word which contains */ +/* those bytes and the new bytes, and writing the new value back to that */ +/* location. */ +/* */ +/******************************************************************************/ + +/* system header files */ + +/* gdb header files */ +#include "defs.h" + +/* ARC header files */ +#include "arc-memory.h" +#include "arc-tdep.h" + + +/* -------------------------------------------------------------------------- */ +/* local types */ +/* -------------------------------------------------------------------------- */ + +typedef struct +{ + unsigned int leading_bytes; + unsigned int trailing_bytes; + unsigned int words; +} Layout; + + +/* -------------------------------------------------------------------------- */ +/* local functions */ +/* -------------------------------------------------------------------------- */ + +/* Split a memory chunk up into its layout - see diagram in file header. */ + +static Layout +split (ARC_Address addr, unsigned int bytes) +{ + unsigned int gap = addr % BYTES_IN_WORD; + Layout layout; + + layout.leading_bytes = (gap == 0) ? 0 : (BYTES_IN_WORD - gap); + layout.trailing_bytes = (addr + bytes) % BYTES_IN_WORD; + layout.words = (bytes - layout.leading_bytes + - layout.trailing_bytes) / BYTES_IN_WORD; + + DEBUG("%u leading bytes, %u words, %u trailing bytes\n", + layout.leading_bytes, layout.words, layout.trailing_bytes); + + return layout; +} + + +/* Read part of a word of data from memory; the given address must be word-aligned. */ + +static unsigned int +read_partial_word (TargetOperations *ops, + ARC_Address addr, + ARC_Byte *data, + unsigned int bytes, + unsigned int offset) /* Offset of required bytes within word. */ +{ + ARC_Byte word[BYTES_IN_WORD]; + + /* Read the word: only some bytes of this are required. */ + if (ops->read_memory(addr, word, 1) > 0) + { + unsigned int i; + + for (i = 0; i < bytes; i++) + data[i] = word[offset + i]; + + /* Have read the specified number of bytes. */ + return bytes; + } + + /* Failed: no data read. */ + return 0; +} + + +/* Write part of a word of data to memory; the given address must be word-aligned. */ + +static unsigned int +write_partial_word (TargetOperations *ops, + ARC_Address addr, + ARC_Byte *data, + unsigned int bytes, + unsigned int offset) /* Offset of required bytes within word. */ +{ + ARC_Byte word[BYTES_IN_WORD]; + + /* First read the word of memory that will be overwritten. */ + if (ops->read_memory(addr, word, 1) > 0) + { + unsigned int i; + + /* Next replace the bytes in that word that are to be written. */ + for (i = 0; i < bytes; i++) + word[offset + i] = data[i]; + + /* Now write it! */ + if (ops->write_memory(addr, word, 1) > 0) + /* Have written the specified number of bytes. */ + return bytes; + } + + /* Failed: no data written. */ + return 0; +} + + +/* -------------------------------------------------------------------------- */ +/* externally visible functions */ +/* -------------------------------------------------------------------------- */ + +/* Read a chunk of data from target memory. + Returns number of bytes read. */ + +unsigned int +arc_read_memory (TargetOperations *ops, + ARC_Address address, + ARC_Byte *data, + unsigned int bytes) +{ + unsigned int gap = address % BYTES_IN_WORD; + unsigned int total_read = 0; + + ENTERARGS("address 0x%08X, bytes %u", address, bytes); + + /* Special fast case for reading a single word. */ + if (gap == 0 && bytes == BYTES_IN_WORD) + { + DEBUG("read single word\n"); + + /* N.B. assumes that 'data' is word-aligned, or that host does not care! */ + total_read = ops->read_memory(address, data, 1); + } + /* Pathological case: bytes in middle of word. */ + else if (gap > 0 && gap + bytes < BYTES_IN_WORD) + { + DEBUG("read pathological\n"); + + total_read = read_partial_word(ops, + address - gap, /* Word-aligned address. */ + data, + bytes, + gap); + } + else /* The general case. */ + { + Layout chunk = split(address, bytes); + + if (chunk.leading_bytes > 0) + { + /* Read the first few bytes. */ + total_read = read_partial_word(ops, + address - gap, /* Word-aligned addres. */ + data, + chunk.leading_bytes, + gap); + data += chunk.leading_bytes; + address += chunk.leading_bytes; + } + + if (chunk.words > 0) + { + unsigned int bytes_read = ops->read_memory(address, data, chunk.words); + + total_read += bytes_read; + address += bytes_read; + data += bytes_read; + } + + if (chunk.trailing_bytes > 0) + { + /* Read the last few bytes of data. */ + total_read += read_partial_word(ops, + address, // Word-aligned address. */ + data, + chunk.trailing_bytes, + 0); + } + } + + DEBUG("read %u bytes\n", total_read); + + return total_read; +} + + +/* Write a chunk of data to target memory. + Returns number of bytes written. */ + +unsigned int +arc_write_memory (TargetOperations *ops, + ARC_Address address, + ARC_Byte *data, + unsigned int bytes) +{ + unsigned int gap = address % BYTES_IN_WORD; + unsigned int total_written = 0; + + ENTERARGS("address 0x%08X, bytes %u", address, bytes); + + /* Useful debugging code: just change 0 to 1. */ + if (0) + { + unsigned int i; + for (i = 0; i < bytes; i++) + { + DEBUG("%02X", data[i]); + if ((i + 1) % 16 == 0) + DEBUG("\n"); + } + DEBUG("\n"); + } + + /* Special fast case for writing a single word. */ + if (gap == 0 && bytes == BYTES_IN_WORD) + { + DEBUG("write single word (%02X %02X %02X %02X)\n", data[0], data[1], data[2], data[3]); + + total_written = ops->write_memory(address, data, 1); + } + /* Pathological case: bytes in middle of word. */ + else if (gap > 0 && gap + bytes < BYTES_IN_WORD) + { + DEBUG("write pathological\n"); + + total_written = write_partial_word(ops, + address - gap, /* Word-aligned address. */ + data, + bytes, + gap); + } + else /* general case */ + { + Layout chunk = split(address, bytes); + + if (chunk.leading_bytes > 0) + { + /* Write the first few bytes. */ + total_written = write_partial_word(ops, + address - gap, /* Word-aligned address. */ + data, + chunk.leading_bytes, + gap); + data += chunk.leading_bytes; + address += chunk.leading_bytes; + } + + if (chunk.words > 0) + { + unsigned int bytes_written = ops->write_memory(address, data, chunk.words); + + total_written += bytes_written; + address += bytes_written; + data += bytes_written; + } + + if (chunk.trailing_bytes > 0) + { + /* Write the last few bytes of data. */ + total_written += write_partial_word(ops, + address, /* Word-aligned address. */ + data, + chunk.trailing_bytes, + 0); + } + } + + DEBUG("written %u bytes\n", total_written); + + return total_written; +} + + +/* Write a repeated pattern of data to memory; + the start of each pattern is always word-aligned, so if the given address is + not word-aligned, the first partial word written will contain trailing bytes + of the pattern. */ + +unsigned int +arc_write_pattern (TargetOperations *ops, + ARC_Address address, + ARC_Word pattern, + unsigned int bytes) +{ + unsigned int gap = address % BYTES_IN_WORD; + unsigned int total_written = 0; + + ENTERARGS("address 0x%08X, pattern 0x%08X, bytes %u", address, pattern, bytes); + + /* Special fast case for writing a single word. */ + if (gap == 0 && bytes == BYTES_IN_WORD) + { + DEBUG("write single word (%08X)\n", pattern); + + total_written = ops->write_memory(address, (ARC_Byte*) &pattern, 1); + } + /* Pathological case: bytes in middle of word. */ + else if (gap > 0 && gap + bytes < BYTES_IN_WORD) + { + DEBUG("write pathological\n"); + + total_written = write_partial_word(ops, + address - gap, /* Word-aligned address. */ + ((ARC_Byte*) &pattern) + gap , + bytes, + gap); + } + else /* General case. */ + { + Layout chunk = split(address, bytes); + + if (chunk.leading_bytes > 0) + { + /* Write the first few bytes. */ + total_written = write_partial_word(ops, + address - gap, /* Word-aligned address. */ + ((ARC_Byte*) &pattern) + gap , + chunk.leading_bytes, + gap); + + address += chunk.leading_bytes; + } + + /* If we have been given a fill_memory operation. */ + if (ops->fill_memory) + { + /* Write the complete words of data in one go. */ + unsigned int bytes_written = ops->fill_memory(address, pattern, chunk.words); + + total_written += bytes_written; + address += bytes_written; + } + else + { + /* Write all the complete words of data, one word at a time. */ + while (chunk.words--) + { + unsigned int bytes_written = ops->write_memory(address, (ARC_Byte*) &pattern, 1); + + total_written += bytes_written; + address += bytes_written; + } + } + + if (chunk.trailing_bytes > 0) + { + /* Write the last few bytes of data. */ + total_written += write_partial_word(ops, + address, /* Word-aligned address. */ + ((ARC_Byte*) &pattern), + chunk.trailing_bytes, + 0); + } + } + + DEBUG("written %u bytes\n", total_written); + + return total_written; +} + +/******************************************************************************/ |