286 lines
8.0 KiB
Java
286 lines
8.0 KiB
Java
/*
|
|
* Copyright © 2010 Keith Packard <keithp@keithp.com>
|
|
*
|
|
* 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 2 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, write to the Free Software Foundation, Inc.,
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
|
*/
|
|
|
|
package org.altusmetrum.altoslib_14;
|
|
|
|
import java.io.*;
|
|
|
|
public class AltosDebug {
|
|
|
|
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;
|
|
|
|
|
|
private AltosLink link;
|
|
|
|
boolean debug_mode;
|
|
|
|
void ensure_debug_mode() throws InterruptedException {
|
|
if (!debug_mode) {
|
|
link.printf("D\n");
|
|
link.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");
|
|
}
|
|
|
|
public void close() {
|
|
try {
|
|
link.close();
|
|
} catch (InterruptedException ie) {
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Write target memory
|
|
*/
|
|
public void write_memory(int address, byte[] bytes, int start, int len) throws InterruptedException {
|
|
ensure_debug_mode();
|
|
// dump_memory("write_memory", address, bytes, start, len);
|
|
link.printf("O %x %x\n", len, address);
|
|
for (int i = 0; i < len; i++)
|
|
link.printf("%02x", bytes[start + i]);
|
|
}
|
|
|
|
public void write_memory(int address, byte[] bytes) throws InterruptedException {
|
|
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];
|
|
|
|
link.flush_input();
|
|
ensure_debug_mode();
|
|
link.printf("I %x %x\n", length, address);
|
|
int i = 0;
|
|
int start = 0;
|
|
while (i < length) {
|
|
String line = link.get_reply();
|
|
if (line == null)
|
|
throw new IOException("No reply");
|
|
|
|
line = line.trim();
|
|
if (!AltosLib.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) ((AltosLib.fromhex(line.charAt(j*2)) << 4) +
|
|
AltosLib.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, InterruptedException {
|
|
int i = 0;
|
|
ensure_debug_mode();
|
|
while (i < bytes.length) {
|
|
int this_time = bytes.length - i;
|
|
if (this_time > 8)
|
|
this_time = 0;
|
|
link.printf("P");
|
|
for (int j = 0; j < this_time; j++)
|
|
link.printf(" %02x", bytes[i+j]);
|
|
link.printf("\n");
|
|
i += this_time;
|
|
}
|
|
}
|
|
|
|
public void write_byte(byte b) throws IOException, InterruptedException {
|
|
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 {
|
|
|
|
link.flush_input();
|
|
ensure_debug_mode();
|
|
link.printf("G %x\n", length);
|
|
int i = 0;
|
|
byte[] data = new byte[length];
|
|
while (i < length) {
|
|
String line = link.get_reply();
|
|
|
|
if (line == null)
|
|
throw new IOException("Timeout in read_bytes");
|
|
line = line.trim();
|
|
String tokens[] = line.split("\\s+");
|
|
for (int j = 0; j < tokens.length; j++) {
|
|
if (!AltosLib.ishex(tokens[j]) ||
|
|
tokens[j].length() != 2)
|
|
throw new IOException(
|
|
String.format
|
|
("Invalid read_bytes reply \"%s\"", line));
|
|
try {
|
|
if (i + j >= length)
|
|
throw new IOException(
|
|
String.format
|
|
("Invalid read_bytes reply \"%s\"", line));
|
|
else
|
|
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() throws InterruptedException {
|
|
try {
|
|
byte[] bytes = read_memory(0x00, 0x200);
|
|
AltosHexfile hexfile = new AltosHexfile (bytes, 0x00);
|
|
return new AltosRomconfig(hexfile);
|
|
} catch (IOException ie) {
|
|
}
|
|
return new AltosRomconfig();
|
|
}
|
|
|
|
/*
|
|
* Reset target
|
|
*/
|
|
public void reset() {
|
|
link.printf ("R\n");
|
|
}
|
|
|
|
public AltosDebug (AltosLink link) {
|
|
this.link = link;
|
|
}
|
|
}
|