83ea5bcbf9f0c9abc1068fbfb317187f1eaaa2d7
[fw/altos] / ao-tools / altosui / AltosDebug.java
1 /*
2  * Copyright © 2010 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 package altosui;
19
20 import java.lang.*;
21 import java.io.*;
22 import java.util.concurrent.LinkedBlockingQueue;
23 import java.util.LinkedList;
24 import java.util.Iterator;
25 import altosui.AltosSerial;
26 import altosui.AltosRomconfig;
27
28 public class AltosDebug extends AltosSerial {
29
30         public static final byte WR_CONFIG =            0x1d;
31         public static final byte RD_CONFIG =            0x24;
32         public static final byte CONFIG_TIMERS_OFF =            (1 << 3);
33         public static final byte CONFIG_DMA_PAUSE =             (1 << 2);
34         public static final byte CONFIG_TIMER_SUSPEND =         (1 << 1);
35         public static final byte SET_FLASH_INFO_PAGE =          (1 << 0);
36
37         public static final byte GET_PC =               0x28;
38         public static final byte READ_STATUS =          0x34;
39         public static final byte STATUS_CHIP_ERASE_DONE =       (byte) (1 << 7);
40         public static final byte STATUS_PCON_IDLE =             (1 << 6);
41         public static final byte STATUS_CPU_HALTED =            (1 << 5);
42         public static final byte STATUS_POWER_MODE_0 =          (1 << 4);
43         public static final byte STATUS_HALT_STATUS =           (1 << 3);
44         public static final byte STATUS_DEBUG_LOCKED =          (1 << 2);
45         public static final byte STATUS_OSCILLATOR_STABLE =     (1 << 1);
46         public static final byte STATUS_STACK_OVERFLOW =        (1 << 0);
47
48         public static final byte SET_HW_BRKPNT =        0x3b;
49         public static byte       HW_BRKPNT_N(byte n)    { return (byte) ((n) << 3); }
50         public static final byte HW_BRKPNT_N_MASK =             (0x3 << 3);
51         public static final byte HW_BRKPNT_ENABLE =             (1 << 2);
52
53         public static final byte HALT =                 0x44;
54         public static final byte RESUME =               0x4c;
55         public static       byte DEBUG_INSTR(byte n)    { return (byte) (0x54|(n)); }
56         public static final byte STEP_INSTR =           0x5c;
57         public static        byte STEP_REPLACE(byte n)  { return  (byte) (0x64|(n)); }
58         public static final byte GET_CHIP_ID =          0x68;
59
60
61         static boolean ishex(int c) {
62                 if ('0' <= c && c <= '9')
63                         return true;
64                 if ('a' <= c && c <= 'f')
65                         return true;
66                 if ('A' <= c && c <= 'F')
67                         return true;
68                 return false;
69         }
70
71         static boolean ishex(String s) {
72                 for (int i = 0; i < s.length(); i++)
73                         if (!ishex(s.charAt(i)))
74                                 return false;
75                 return true;
76         }
77         static boolean isspace(int c) {
78                 switch (c) {
79                 case ' ':
80                 case '\t':
81                         return true;
82                 }
83                 return false;
84         }
85
86         static int fromhex(int c) {
87                 if ('0' <= c && c <= '9')
88                         return c - '0';
89                 if ('a' <= c && c <= 'f')
90                         return c - 'a' + 10;
91                 if ('A' <= c && c <= 'F')
92                         return c - 'A' + 10;
93                 return -1;
94         }
95
96         boolean debug_mode;
97
98         void ensure_debug_mode() {
99                 if (!debug_mode) {
100                         printf("D\n");
101                         debug_mode = true;
102                 }
103         }
104
105         void dump_memory(String header, int address, byte[] bytes, int start, int len) {
106                 System.out.printf("%s\n", header);
107                 for (int j = 0; j < len; j++) {
108                         if ((j & 15) == 0) {
109                                 if (j != 0)
110                                         System.out.printf("\n");
111                                 System.out.printf ("%04x:", address + j);
112                         }
113                         System.out.printf(" %02x", bytes[start + j]);
114                 }
115                 System.out.printf("\n");
116         }
117
118         /*
119          * Write target memory
120          */
121         public void write_memory(int address, byte[] bytes, int start, int len) {
122                 ensure_debug_mode();
123 //              dump_memory("write_memory", address, bytes, start, len);
124                 printf("O %x %x\n", len, address);
125                 for (int i = 0; i < len; i++)
126                         printf("%02x", bytes[start + i]);
127         }
128
129         public void write_memory(int address, byte[] bytes) {
130                 write_memory(address, bytes, 0, bytes.length);
131         }
132
133         /*
134          * Read target memory
135          */
136         public byte[] read_memory(int address, int length)
137                 throws IOException, InterruptedException {
138                 byte[]  data = new byte[length];
139
140                 flush_reply();
141                 ensure_debug_mode();
142                 printf("I %x %x\n", length, address);
143                 int i = 0;
144                 int start = 0;
145                 while (i < length) {
146                         String  line = get_reply().trim();
147                         if (!ishex(line) || line.length() % 2 != 0)
148                                 throw new IOException(
149                                         String.format
150                                         ("Invalid reply \"%s\"", line));
151                         int this_time = line.length() / 2;
152                         for (int j = 0; j < this_time; j++)
153                                 data[start + j] = (byte) ((fromhex(line.charAt(j*2)) << 4) +
154                                                   fromhex(line.charAt(j*2+1)));
155                         start += this_time;
156                         i += this_time;
157                 }
158 //              dump_memory("read_memory", address, data, 0, length);
159
160                 return data;
161         }
162
163         /*
164          * Write raw bytes to the debug link using the 'P' command
165          */
166         public void write_bytes(byte[] bytes) throws IOException {
167                 int i = 0;
168                 ensure_debug_mode();
169                 while (i < bytes.length) {
170                         int this_time = bytes.length - i;
171                         if (this_time > 8)
172                                 this_time = 0;
173                         printf("P");
174                         for (int j = 0; j < this_time; j++)
175                                 printf(" %02x", bytes[i+j]);
176                         printf("\n");
177                         i += this_time;
178                 }
179         }
180
181         public void write_byte(byte b) throws IOException {
182                 byte[] bytes = { b };
183                 write_bytes(bytes);
184         }
185
186         /*
187          * Read raw bytes from the debug link using the 'G' command
188          */
189         public byte[] read_bytes(int length)
190                 throws IOException, InterruptedException {
191
192                 flush_reply();
193                 ensure_debug_mode();
194                 printf("G %x\n", length);
195                 int i = 0;
196                 byte[] data = new byte[length];
197                 while (i < length) {
198                         String line = get_reply().trim();
199                         String tokens[] = line.split("\\s+");
200                         for (int j = 0; j < tokens.length; j++) {
201                                 if (!ishex(tokens[j]) ||
202                                     tokens[j].length() != 2)
203                                         throw new IOException(
204                                                 String.format
205                                                 ("Invalid read_bytes reply \"%s\"", line));
206                                 try {
207                                         data[i + j] = (byte) Integer.parseInt(tokens[j], 16);
208                                 } catch (NumberFormatException ne) {
209                                         throw new IOException(
210                                                 String.format
211                                                 ("Invalid read_bytes reply \"%s\"", line));
212                                 }
213                         }
214                         i += tokens.length;
215                 }
216                 return data;
217         }
218
219         public byte read_byte() throws IOException, InterruptedException {
220                 return read_bytes(1)[0];
221         }
222
223         public byte debug_instr(byte[] instruction) throws IOException, InterruptedException {
224                 byte[] command = new byte[1 + instruction.length];
225                 command[0] = DEBUG_INSTR((byte) instruction.length);
226                 for (int i = 0; i < instruction.length; i++)
227                         command[i+1] = instruction[i];
228                 write_bytes(command);
229                 return read_byte();
230         }
231
232         public byte resume() throws IOException, InterruptedException {
233                 write_byte(RESUME);
234                 return read_byte();
235         }
236
237         public int read_uint16() throws IOException, InterruptedException {
238                 byte[] d = read_bytes(2);
239                 return ((int) (d[0] & 0xff) << 8) | (d[1] & 0xff);
240         }
241
242         public int read_uint8()  throws IOException, InterruptedException {
243                 byte[] d = read_bytes(1);
244                 return (int) (d[0] & 0xff);
245         }
246
247         public int get_chip_id() throws IOException, InterruptedException {
248                 write_byte(GET_CHIP_ID);
249                 return read_uint16();
250         }
251
252         public int get_pc() throws IOException, InterruptedException {
253                 write_byte(GET_PC);
254                 return read_uint16();
255         }
256
257         public byte read_status() throws IOException, InterruptedException {
258                 write_byte(READ_STATUS);
259                 return read_byte();
260         }
261
262         static final byte LJMP                  = 0x02;
263
264         public void set_pc(int pc) throws IOException, InterruptedException {
265                 byte high = (byte) (pc >> 8);
266                 byte low = (byte) pc;
267                 byte[] jump_mem = { LJMP, high, low };
268                 debug_instr(jump_mem);
269         }
270
271         public boolean check_connection() throws IOException, InterruptedException {
272                 byte reply = read_status();
273                 if ((reply & STATUS_CHIP_ERASE_DONE) == 0)
274                         return false;
275                 if ((reply & STATUS_PCON_IDLE) != 0)
276                         return false;
277                 if ((reply & STATUS_POWER_MODE_0) == 0)
278                         return false;
279                 return true;
280         }
281
282         public AltosRomconfig romconfig() {
283                 try {
284                         byte[] bytes = read_memory(0xa0, 10);
285                         return new AltosRomconfig(bytes, 0);
286                 } catch (IOException ie) {
287                 } catch (InterruptedException ie) {
288                 }
289                 return new AltosRomconfig();
290         }
291
292         /*
293          * Reset target
294          */
295         public void reset() {
296                 printf ("R\n");
297         }
298 }