/* * Copyright © 2010 Keith Packard * * 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; version 2 of the License. * * 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-1307 USA. */ package altosui; import java.lang.*; import java.io.*; import java.util.concurrent.*; import java.util.*; import libaltosJNI.*; public class AltosDebug extends AltosSerial { public static final byte WR_CONFIG = 0x1d; public static final byte RD_CONFIG = 0x24; public static final byte CONFIG_TIMERS_OFF = (1 << 3); public static final byte CONFIG_DMA_PAUSE = (1 << 2); public static final byte CONFIG_TIMER_SUSPEND = (1 << 1); public static final byte SET_FLASH_INFO_PAGE = (1 << 0); public static final byte GET_PC = 0x28; public static final byte READ_STATUS = 0x34; public static final byte STATUS_CHIP_ERASE_DONE = (byte) (1 << 7); public static final byte STATUS_PCON_IDLE = (1 << 6); public static final byte STATUS_CPU_HALTED = (1 << 5); public static final byte STATUS_POWER_MODE_0 = (1 << 4); public static final byte STATUS_HALT_STATUS = (1 << 3); public static final byte STATUS_DEBUG_LOCKED = (1 << 2); public static final byte STATUS_OSCILLATOR_STABLE = (1 << 1); public static final byte STATUS_STACK_OVERFLOW = (1 << 0); public static final byte SET_HW_BRKPNT = 0x3b; public static byte HW_BRKPNT_N(byte n) { return (byte) ((n) << 3); } public static final byte HW_BRKPNT_N_MASK = (0x3 << 3); public static final byte HW_BRKPNT_ENABLE = (1 << 2); public static final byte HALT = 0x44; public static final byte RESUME = 0x4c; public static byte DEBUG_INSTR(byte n) { return (byte) (0x54|(n)); } public static final byte STEP_INSTR = 0x5c; public static byte STEP_REPLACE(byte n) { return (byte) (0x64|(n)); } public static final byte GET_CHIP_ID = 0x68; boolean debug_mode; void ensure_debug_mode() { if (!debug_mode) { printf("D\n"); flush_input(); debug_mode = true; } } void dump_memory(String header, int address, byte[] bytes, int start, int len) { System.out.printf("%s\n", header); for (int j = 0; j < len; j++) { if ((j & 15) == 0) { if (j != 0) System.out.printf("\n"); System.out.printf ("%04x:", address + j); } System.out.printf(" %02x", bytes[start + j]); } System.out.printf("\n"); } /* * Write target memory */ public void write_memory(int address, byte[] bytes, int start, int len) { ensure_debug_mode(); // dump_memory("write_memory", address, bytes, start, len); printf("O %x %x\n", len, address); for (int i = 0; i < len; i++) printf("%02x", bytes[start + i]); } public void write_memory(int address, byte[] bytes) { write_memory(address, bytes, 0, bytes.length); } /* * Read target memory */ public byte[] read_memory(int address, int length) throws IOException, InterruptedException { byte[] data = new byte[length]; flush_input(); ensure_debug_mode(); printf("I %x %x\n", length, address); int i = 0; int start = 0; while (i < length) { String line = get_reply().trim(); if (!Altos.ishex(line) || line.length() % 2 != 0) throw new IOException( String.format ("Invalid reply \"%s\"", line)); int this_time = line.length() / 2; for (int j = 0; j < this_time; j++) data[start + j] = (byte) ((Altos.fromhex(line.charAt(j*2)) << 4) + Altos.fromhex(line.charAt(j*2+1))); start += this_time; i += this_time; } // dump_memory("read_memory", address, data, 0, length); return data; } /* * Write raw bytes to the debug link using the 'P' command */ public void write_bytes(byte[] bytes) throws IOException { int i = 0; ensure_debug_mode(); while (i < bytes.length) { int this_time = bytes.length - i; if (this_time > 8) this_time = 0; printf("P"); for (int j = 0; j < this_time; j++) printf(" %02x", bytes[i+j]); printf("\n"); i += this_time; } } public void write_byte(byte b) throws IOException { byte[] bytes = { b }; write_bytes(bytes); } /* * Read raw bytes from the debug link using the 'G' command */ public byte[] read_bytes(int length) throws IOException, InterruptedException { flush_input(); ensure_debug_mode(); printf("G %x\n", length); int i = 0; byte[] data = new byte[length]; while (i < length) { String line = get_reply().trim(); String tokens[] = line.split("\\s+"); for (int j = 0; j < tokens.length; j++) { if (!Altos.ishex(tokens[j]) || tokens[j].length() != 2) throw new IOException( String.format ("Invalid read_bytes reply \"%s\"", line)); try { data[i + j] = (byte) Integer.parseInt(tokens[j], 16); } catch (NumberFormatException ne) { throw new IOException( String.format ("Invalid read_bytes reply \"%s\"", line)); } } i += tokens.length; } return data; } public byte read_byte() throws IOException, InterruptedException { return read_bytes(1)[0]; } public byte debug_instr(byte[] instruction) throws IOException, InterruptedException { byte[] command = new byte[1 + instruction.length]; command[0] = DEBUG_INSTR((byte) instruction.length); for (int i = 0; i < instruction.length; i++) command[i+1] = instruction[i]; write_bytes(command); return read_byte(); } public byte resume() throws IOException, InterruptedException { write_byte(RESUME); return read_byte(); } public int read_uint16() throws IOException, InterruptedException { byte[] d = read_bytes(2); return ((int) (d[0] & 0xff) << 8) | (d[1] & 0xff); } public int read_uint8() throws IOException, InterruptedException { byte[] d = read_bytes(1); return (int) (d[0] & 0xff); } public int get_chip_id() throws IOException, InterruptedException { write_byte(GET_CHIP_ID); return read_uint16(); } public int get_pc() throws IOException, InterruptedException { write_byte(GET_PC); return read_uint16(); } public byte read_status() throws IOException, InterruptedException { write_byte(READ_STATUS); return read_byte(); } static final byte LJMP = 0x02; public void set_pc(int pc) throws IOException, InterruptedException { byte high = (byte) (pc >> 8); byte low = (byte) pc; byte[] jump_mem = { LJMP, high, low }; debug_instr(jump_mem); } public boolean check_connection() throws IOException, InterruptedException { byte reply = read_status(); if ((reply & STATUS_CHIP_ERASE_DONE) == 0) return false; if ((reply & STATUS_PCON_IDLE) != 0) return false; if ((reply & STATUS_POWER_MODE_0) == 0) return false; return true; } public AltosRomconfig romconfig() { try { byte[] bytes = read_memory(0xa0, 10); return new AltosRomconfig(bytes, 0); } catch (IOException ie) { } catch (InterruptedException ie) { } return new AltosRomconfig(); } /* * Reset target */ public void reset() { printf ("R\n"); } public AltosDebug (AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException { super(in_device); } }