| package xdc.rov; |
| |
| import xdc.rov.IMemoryImage; |
| import xdc.rov.Sections; |
| import xdc.rov.TargetEncoder; |
| |
| /*! |
| * ======== MemoryImage ======== |
| * This class wraps an IMemoryImage implementation to provide support for |
| * features needed across all memory readers. |
| * This includes: |
| * - Common error messages |
| * - Checking of abort flag |
| * - Checking memory read address against section map |
| */ |
| public class MemoryImage { |
| |
| /* The IMemoryImage implementation used to perform the memory reads. */ |
| private IMemoryImage memReader; |
| |
| /* |
| * Sections object defining all of the valid data sections for the |
| * current application. |
| */ |
| private Sections sections; |
| |
| /* The number of bits in a MAU */ |
| private int bitsPerChar; |
| |
| /* Target encoder used for encoding MAUs to bytes */ |
| private TargetEncoder enc = null; |
| |
| /* Flag to indicate that memory reads should not be performed. */ |
| private Boolean abortFlag = false; |
| |
| /* Message to throw if the memory read failed at a VALID address. */ |
| private static final String validFail = |
| "This read is at a VALID address according to the " + |
| "application's section map, but the IMemoryImage memory " + |
| "read failed."; |
| |
| /* Message to throw if the memory read failed at an INVALID address. */ |
| private static final String invalidFail = |
| "This read is at an INVALID address according to the " + |
| "application's section map. The application is likely " + |
| "either uninitialized or corrupt."; |
| |
| /*! |
| * ======== AbortedException ======== |
| */ |
| public class AbortedException extends Exception { |
| private static final long serialVersionUID = 1L; |
| |
| public AbortedException(String msg) { |
| super(msg); |
| } |
| } |
| |
| /* |
| * ======== Constructor ======== |
| */ |
| public MemoryImage(IMemoryImage memReader, TargetType.Endianess endian, |
| int bitsPerChar) |
| { |
| this.memReader = memReader; |
| |
| this.bitsPerChar = bitsPerChar; |
| |
| /* Retrieve the section map from the IMemoryImage implementation. */ |
| sections = memReader.getSections(); |
| |
| /* Create the TargetEncoder, used for encoding MAUs to bytes. */ |
| enc = new TargetEncoder(endian, bitsPerChar); |
| } |
| |
| /*! |
| * ======== readMaus ======== |
| * Read an array of data from target memory. The size of each element in |
| * the array is a target MAU (minimal addressable unit). This is a byte on |
| * byte addressable targets and 2 bytes on 16-bit targets such as 28x and |
| * 55x. |
| * |
| * @param(addr) Address of the data to fetch. |
| * @param(numMaus) Number of bytes to read. |
| * @param(addrCheck) Indicates whether the memory image should validate |
| * the read by comparing the address to section |
| * information, if available |
| * |
| */ |
| public int[] readMaus(long addr, int numMaus, boolean addrCheck) |
| throws Exception |
| { |
| /* Check for abort command at beginning and end of read */ |
| if (getAbortFlag()) { |
| throw (new AbortedException("abort")); |
| } |
| |
| /* Verify that memory request falls within valid section */ |
| if (addrCheck) { |
| /* If the read doesn't fit within a section, throw an error */ |
| if (!sections.isValidDataRead(addr, numMaus)) { |
| throw (new Exception(getReadFailMsg(addr, numMaus) + "\n" + |
| invalidFail)); |
| } |
| } |
| |
| /* Create the buffer */ |
| int[] buffer = new int[numMaus]; |
| |
| boolean res; |
| |
| if (!traceEnable) { |
| /* Call down to the device to perform the read. */ |
| res = memReader.readMaus(buffer, addr, numMaus); |
| } |
| else { |
| /* Time the memory read */ |
| long start = System.currentTimeMillis(); |
| |
| /* Call down to the device to perform the read. */ |
| res = memReader.readMaus(buffer, addr, numMaus); |
| |
| /* End time. */ |
| long end = System.currentTimeMillis(); |
| |
| debugPrint("Memory read took " + (end - start) + "ms"); |
| } |
| |
| /* Check the return code, non-zero indicates a problem. */ |
| if (!res) { |
| /* |
| * If an address check was performed, then this read is failing at |
| * a valid address. This is a serious error and indicates a |
| * problem with the IMemoryImage reader. |
| */ |
| if (addrCheck) { |
| throw (new Exception(getReadFailMsg(addr, numMaus) + "\n" + |
| validFail)); |
| } |
| /* |
| * If no address check was performed, we can't say whether the |
| * address was valid or invalid. |
| */ |
| else { |
| throw (new Exception(getReadFailMsg(addr, numMaus))); |
| } |
| } |
| |
| /* Check for abort command at beginning and end of read */ |
| if (getAbortFlag()) { |
| throw (new AbortedException("abort")); |
| } |
| |
| return (buffer); |
| } |
| |
| /*! |
| * ======== readBytes ======== |
| * Read an array of bytes from target memory. |
| * |
| * @param(addr) Address of the data to fetch. |
| * @param(numBytes) Number of bytes to read. |
| * @param(addrCheck) Indicates whether the memory image should validate |
| * the read by comparing the address to section |
| * information, if available |
| */ |
| public byte[] readBytes(long addr, int numBytes, boolean addrCheck) |
| throws Exception |
| { |
| /* We can only read MAUs, so calculate the number of MAUs to read. */ |
| int bytesPerMau = (bitsPerChar / 8); |
| int numMaus = numBytes / bytesPerMau; |
| |
| /* Read the data. */ |
| int[] lBuf = readMaus(addr, numMaus, addrCheck); |
| |
| /* Return the values in a byte array. */ |
| byte[] bBuf = new byte[numBytes]; |
| |
| /* If the MAU is a byte, just copy the values. */ |
| if (bitsPerChar == 8) { |
| for (int i = 0; i < lBuf.length; i++) { |
| bBuf[i] = (byte) lBuf[i]; |
| } |
| } |
| /* Otherwise, encode the MAUs into bytes */ |
| else { |
| int offset = 0; |
| for (int i = 0; i < lBuf.length; i++) { |
| enc.encodeBytes(bBuf, offset, lBuf[i], bytesPerMau); |
| offset += bytesPerMau; |
| } |
| } |
| |
| return (bBuf); |
| } |
| |
| /* |
| * ======== getReadFailMsg ======== |
| * Returns a string stating that the given memory read failed. |
| */ |
| String getReadFailMsg(long addr, int length) |
| { |
| return ("Target memory read failed at address: 0x" + |
| Long.toHexString(addr) + ", length: " + length); |
| } |
| |
| /* |
| * ======== getAbortFlag ======== |
| * Synchronized method for checking the abort flag. |
| */ |
| public boolean getAbortFlag() |
| { |
| synchronized (abortFlag) { |
| return(abortFlag); |
| } |
| } |
| |
| /* |
| * ======== setAbortFlag ======== |
| */ |
| public void setAbortFlag(boolean val) |
| { |
| synchronized (abortFlag) { |
| abortFlag = val; |
| } |
| } |
| |
| /*! |
| * ======== setSections ======== |
| */ |
| public void setSections(Sections sections) |
| { |
| this.sections = sections; |
| } |
| |
| /* |
| * ======== getSections ======== |
| */ |
| public Sections getSections() |
| { |
| return (sections); |
| } |
| |
| /* |
| * Initialize 'traceEnable' based on the xdc.rov.traceEnable environment |
| * variable. |
| */ |
| private static boolean traceEnable; |
| static { |
| String traceEnableStr = System.getProperty("xdc.rov.traceEnable"); |
| traceEnable = (traceEnableStr != null) && traceEnableStr.equals("true"); |
| } |
| |
| public static void debugPrint(String str) { |
| if (traceEnable) { |
| System.out.println("[MemoryReader] " + str); |
| } |
| } |
| } |