/* * avarice - The "avarice" program. * Copyright (C) 2001 Scott Finneran * Copyright (C) 2002, 2003, 2004 Intel Corporation * Copyright (C) 2005,2006 Joerg Wunsch * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 * as published by the Free Software Foundation. * * 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * * This file implements access to the target memory for the mkII protocol. * * $Id: jtag2rw.cc,v 1.5 2006/08/08 21:27:34 joerg_wunsch Exp $ */ #include #include #include #include #include #include #include #include #include #include "avarice.h" #include "jtag.h" #include "jtag2.h" #include "remote.h" /** Return the memory space code for the memory space indicated by the high-order bits of 'addr'. Also clear these high order bits in 'addr' **/ uchar jtag2::memorySpace(unsigned long &addr) { int mask; // We can't just mask the bits off, because 0x10000->0x1ffff are // valid code addresses if (addr & DATA_SPACE_ADDR_OFFSET) { mask = addr & ADDR_SPACE_MASK; addr &= ~ADDR_SPACE_MASK; } else mask = 0; switch (mask) { case EEPROM_SPACE_ADDR_OFFSET: if (!useDebugWire && programmingEnabled) return MTYPE_EEPROM_PAGE; else return MTYPE_EEPROM; case FUSE_SPACE_ADDR_OFFSET: return MTYPE_FUSE_BITS; case LOCK_SPACE_ADDR_OFFSET: return MTYPE_LOCK_BITS; case SIG_SPACE_ADDR_OFFSET: return MTYPE_SIGN_JTAG; // ... return MTYPE_OSCCAL_BYTE; // ... return MTYPE_CAN; case BREAKPOINT_SPACE_ADDR_OFFSET: return MTYPE_EVENT; case DATA_SPACE_ADDR_OFFSET: return MTYPE_SRAM; default: if (useDebugWire || programmingEnabled) return MTYPE_FLASH_PAGE; else return MTYPE_SPM; } } uchar *jtag2::jtagRead(unsigned long addr, unsigned int numBytes) { uchar *response; int responseSize; if (numBytes == 0) { response = new uchar[1]; response[0] = '\0'; return response; } debugOut("jtagRead "); uchar whichSpace = memorySpace(addr); bool needProgmode = whichSpace >= MTYPE_FLASH_PAGE; unsigned int pageSize = 0; unsigned int offset = 0; bool wasProgmode = programmingEnabled; if (needProgmode && !programmingEnabled) enableProgramming(); unsigned char *cachePtr = NULL; unsigned int *cacheBaseAddr = NULL; switch (whichSpace) { // Pad to even byte count for flash memory. // Even MTYPE_SPM appears to cause a RSP_FAILED // otherwise. case MTYPE_SPM: offset = addr & 1; addr &= ~1; numBytes = (numBytes + 1) & ~1; break; case MTYPE_FLASH_PAGE: pageSize = global_p_device_def->flash_page_size; cachePtr = flashCache; cacheBaseAddr = &flashCachePageAddr; break; case MTYPE_EEPROM_PAGE: pageSize = global_p_device_def->eeprom_page_size; cachePtr = eepromCache; cacheBaseAddr = &eepromCachePageAddr; break; } uchar command[10] = { CMND_READ_MEMORY }; command[1] = whichSpace; if (pageSize > 0) { u32_to_b4(command + 2, pageSize); response = new uchar[numBytes]; unsigned int mask = pageSize - 1; unsigned int pageAddr = addr & ~mask; unsigned int chunksize = numBytes; unsigned int targetOffset = 0; if (addr + numBytes >= pageAddr + pageSize) // Chunk would cross a page boundary, reduce it // appropriately. chunksize -= (addr + numBytes - (pageAddr + pageSize)); offset = addr - pageAddr; while (numBytes > 0) { uchar *resp; if (pageAddr == *cacheBaseAddr) { // quickly fetch from page cache memcpy(response + targetOffset, cachePtr + offset, chunksize); } else { // read from device, cache result, and copy over our part u32_to_b4(command + 6, pageAddr); check(doJtagCommand(command, sizeof command, resp, responseSize), "Failed to read target memory space"); memcpy(cachePtr, resp + 1, pageSize); *cacheBaseAddr = pageAddr; memcpy(response + targetOffset, cachePtr + offset, chunksize); delete [] resp; } numBytes -= chunksize; targetOffset += chunksize; chunksize = numBytes > pageSize? pageSize: numBytes; pageAddr += pageSize; } } else { u32_to_b4(command + 2, numBytes); u32_to_b4(command + 6, addr); check(doJtagCommand(command, sizeof command, response, responseSize), "Failed to read target memory space"); if (offset > 0) memmove(response, response + 1 + offset, responseSize - 1 - offset); else memmove(response, response + 1, responseSize - 1); } if (needProgmode && !wasProgmode) disableProgramming(); return response; } bool jtag2::jtagWrite(unsigned long addr, unsigned int numBytes, uchar buffer[]) { if (numBytes == 0) return true; debugOut("jtagWrite "); uchar whichSpace = memorySpace(addr); // Hack to detect the start of a GDB "load" command. Iff this // address is tied to flash ROM, and it is address 0, and the size // is larger than 4 bytes, assume it's the first block of a "load" // command. If so, chip erase the device, and switch over to // programming mode to speed up things (drastically). if (whichSpace == MTYPE_SPM && addr == 0 && numBytes > 4) { debugOut("Detected GDB \"load\" command, erasing flash.\n"); //whichSpace = MTYPE_FLASH_PAGE; // this will turn on progmode eraseProgramMemory(); } bool needProgmode = whichSpace >= MTYPE_FLASH_PAGE; unsigned int pageSize = 0; bool wasProgmode = programmingEnabled; if (needProgmode && !programmingEnabled) enableProgramming(); switch (whichSpace) { case MTYPE_FLASH_PAGE: pageSize = global_p_device_def->flash_page_size; break; case MTYPE_EEPROM_PAGE: pageSize = global_p_device_def->eeprom_page_size; break; } if (pageSize > 0) { unsigned int mask = pageSize - 1; addr &= ~mask; check(numBytes == pageSize, "jtagWrite(): numByte does not match page size"); } uchar *command = new uchar [10 + numBytes]; command[0] = CMND_WRITE_MEMORY; command[1] = whichSpace; if (pageSize) { u32_to_b4(command + 2, pageSize); u32_to_b4(command + 6, addr); } else { u32_to_b4(command + 2, numBytes); u32_to_b4(command + 6, addr); } memcpy(command + 10, buffer, numBytes); uchar *response; int responseSize; check(doJtagCommand(command, 10 + numBytes, response, responseSize), "Failed to write target memory space"); delete [] command; delete [] response; if (needProgmode && !wasProgmode) disableProgramming(); return true; }