altosui & altoslib: Move a pile of debug/programming bits to altoslib
[fw/altos] / altosui / AltosFlash.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.awt.event.*;
21 import javax.swing.*;
22 import java.io.*;
23 import org.altusmetrum.altoslib_1.*;
24 import org.altusmetrum.altosuilib_1.*;
25
26 public class AltosFlash {
27         File            file;
28         FileInputStream input;
29         AltosHexfile    image;
30         JFrame          frame;
31         AltosDevice     debug_dongle;
32         AltosDebug      debug;
33         AltosRomconfig  rom_config;
34         ActionListener  listener;
35         boolean         aborted;
36
37         static final byte MOV_direct_data       = (byte) 0x75;
38         static final byte MOV_DPTR_data16       = (byte) 0x90;
39         static final byte MOV_A_data            = (byte) 0x74;
40         static final byte MOVX_atDPTR_A         = (byte) 0xf0;
41         static final byte MOVX_A_atDPTR         = (byte) 0xe0;
42         static final byte INC_DPTR              = (byte) 0xa3;
43         static final byte TRAP                  = (byte) 0xa5;
44
45         static final byte JB                    = (byte) 0x20;
46
47         static final byte MOV_A_direct          = (byte) 0xe5;
48         static final byte MOV_direct1_direct2   = (byte) 0x85;
49         static final byte MOV_direct_A          = (byte) 0xf5;
50         static final byte MOV_R0_data           = (byte) (0x78 | 0);
51         static final byte MOV_R1_data           = (byte) (0x78 | 1);
52         static final byte MOV_R2_data           = (byte) (0x78 | 2);
53         static final byte MOV_R3_data           = (byte) (0x78 | 3);
54         static final byte MOV_R4_data           = (byte) (0x78 | 4);
55         static final byte MOV_R5_data           = (byte) (0x78 | 5);
56         static final byte MOV_R6_data           = (byte) (0x78 | 6);
57         static final byte MOV_R7_data           = (byte) (0x78 | 7);
58         static final byte DJNZ_R0_rel           = (byte) (0xd8 | 0);
59         static final byte DJNZ_R1_rel           = (byte) (0xd8 | 1);
60         static final byte DJNZ_R2_rel           = (byte) (0xd8 | 2);
61         static final byte DJNZ_R3_rel           = (byte) (0xd8 | 3);
62         static final byte DJNZ_R4_rel           = (byte) (0xd8 | 4);
63         static final byte DJNZ_R5_rel           = (byte) (0xd8 | 5);
64         static final byte DJNZ_R6_rel           = (byte) (0xd8 | 6);
65         static final byte DJNZ_R7_rel           = (byte) (0xd8 | 7);
66
67         static final byte P1DIR                 = (byte) 0xFE;
68         static final byte P1                    = (byte) 0x90;
69
70         /* flash controller */
71         static final byte FWT                   = (byte) 0xAB;
72         static final byte FADDRL                = (byte) 0xAC;
73         static final byte FADDRH                = (byte) 0xAD;
74         static final byte FCTL                  = (byte) 0xAE;
75         static final byte FCTL_BUSY             = (byte) 0x80;
76         static final byte FCTL_BUSY_BIT         = (byte) 7;
77         static final byte FCTL_SWBSY            = (byte) 0x40;
78         static final byte FCTL_SWBSY_BIT        = (byte) 6;
79         static final byte FCTL_CONTRD           = (byte) 0x10;
80         static final byte FCTL_WRITE            = (byte) 0x02;
81         static final byte FCTL_ERASE            = (byte) 0x01;
82         static final byte FWDATA                = (byte) 0xAF;
83
84         static final byte ACC                   = (byte) 0xE0;
85
86         /* offsets within the flash_page program */
87         static final int FLASH_ADDR_HIGH        = 8;
88         static final int FLASH_ADDR_LOW         = 11;
89         static final int RAM_ADDR_HIGH          = 13;
90         static final int RAM_ADDR_LOW           = 14;
91         static final int FLASH_WORDS_HIGH       = 16;
92         static final int FLASH_WORDS_LOW        = 18;
93         static final int FLASH_TIMING           = 21;
94
95         /* sleep mode control */
96         static final int SLEEP                  = (byte) 0xbe;
97         static final int  SLEEP_USB_EN          = (byte) 0x80;
98         static final int  SLEEP_XOSC_STB        = (byte) 0x40;
99         static final int  SLEEP_HFRC_STB        = (byte) 0x20;
100         static final int  SLEEP_RST_MASK        = (byte) 0x18;
101         static final int   SLEEP_RST_POWERON    = (byte) 0x00;
102         static final int   SLEEP_RST_EXTERNAL   = (byte) 0x10;
103         static final int   SLEEP_RST_WATCHDOG   = (byte) 0x08;
104         static final int  SLEEP_OSC_PD          = (byte) 0x04;
105         static final int  SLEEP_MODE_MASK       = (byte) 0x03;
106         static final int   SLEEP_MODE_PM0       = (byte) 0x00;
107         static final int   SLEEP_MODE_PM1       = (byte) 0x01;
108         static final int   SLEEP_MODE_PM2       = (byte) 0x02;
109         static final int   SLEEP_MODE_PM3       = (byte) 0x03;
110
111         /* clock controller */
112         static final byte CLKCON                = (byte) 0xC6;
113         static final byte  CLKCON_OSC32K        = (byte) 0x80;
114         static final byte  CLKCON_OSC           = (byte) 0x40;
115         static final byte  CLKCON_TICKSPD       = (byte) 0x38;
116         static final byte  CLKCON_CLKSPD        = (byte) 0x07;
117
118         static final byte[] flash_page_proto = {
119
120                 MOV_direct_data, P1DIR, (byte) 0x02,
121                 MOV_direct_data, P1,    (byte) 0xFF,
122
123                 MOV_direct_data, FADDRH, 0,     /* FLASH_ADDR_HIGH */
124
125                 MOV_direct_data, FADDRL, 0,     /* FLASH_ADDR_LOW */
126
127                 MOV_DPTR_data16, 0, 0,          /* RAM_ADDR_HIGH, RAM_ADDR_LOW */
128
129                 MOV_R7_data, 0,                 /* FLASH_WORDS_HIGH */
130
131                 MOV_R6_data, 0,                 /* FLASH_WORDS_LOW */
132
133
134                 MOV_direct_data, FWT, 0x20,     /* FLASH_TIMING */
135
136                 MOV_direct_data, FCTL, FCTL_ERASE,
137 /* eraseWaitLoop: */
138                 MOV_A_direct,           FCTL,
139                 JB, ACC|FCTL_BUSY_BIT, (byte) 0xfb,
140
141                 MOV_direct_data, P1, (byte) 0xfd,
142
143                 MOV_direct_data, FCTL, FCTL_WRITE,
144 /* writeLoop: */
145                 MOV_R5_data, 2,
146 /* writeWordLoop: */
147                 MOVX_A_atDPTR,
148                 INC_DPTR,
149                 MOV_direct_A, FWDATA,
150                 DJNZ_R5_rel, (byte) 0xfa,               /* writeWordLoop */
151 /* writeWaitLoop: */
152                 MOV_A_direct, FCTL,
153                 JB, ACC|FCTL_SWBSY_BIT, (byte) 0xfb,    /* writeWaitLoop */
154                 DJNZ_R6_rel, (byte) 0xf1,               /* writeLoop */
155                 DJNZ_R7_rel, (byte) 0xef,                       /* writeLoop */
156
157                 MOV_direct_data, P1DIR, (byte) 0x00,
158                 MOV_direct_data, P1,    (byte) 0xFF,
159                 TRAP,
160         };
161
162         public byte[] make_flash_page(int flash_addr, int ram_addr, int byte_count) {
163                 int flash_word_addr = flash_addr >> 1;
164                 int flash_word_count = ((byte_count + 1) >> 1);
165
166                 byte[] flash_page = new byte[flash_page_proto.length];
167                 for (int i = 0; i < flash_page.length; i++)
168                         flash_page[i] = flash_page_proto[i];
169
170                 flash_page[FLASH_ADDR_HIGH]  = (byte) (flash_word_addr >> 8);
171                 flash_page[FLASH_ADDR_LOW]   = (byte) (flash_word_addr);
172                 flash_page[RAM_ADDR_HIGH]    = (byte) (ram_addr >> 8);
173                 flash_page[RAM_ADDR_LOW]     = (byte) (ram_addr);
174
175                 byte flash_words_low = (byte) (flash_word_count);
176                 byte flash_words_high = (byte) (flash_word_count >> 8);
177                 /* the flashing code has a minor 'bug' */
178                 if (flash_words_low != 0)
179                         flash_words_high++;
180
181                 flash_page[FLASH_WORDS_HIGH] = (byte) flash_words_high;
182                 flash_page[FLASH_WORDS_LOW]  = (byte) flash_words_low;
183                 return flash_page;
184         }
185
186         static byte[] set_clkcon_fast = {
187                 MOV_direct_data, CLKCON, 0x00
188         };
189
190         static byte[] get_sleep = {
191                 MOV_A_direct, SLEEP
192         };
193
194         public void clock_init() throws IOException, InterruptedException {
195                 if (debug != null) {
196                         debug.debug_instr(set_clkcon_fast);
197
198                         byte    status;
199                         for (int times = 0; times < 20; times++) {
200                                 Thread.sleep(1);
201                                 status = debug.debug_instr(get_sleep);
202                                 if ((status & SLEEP_XOSC_STB) != 0)
203                                         return;
204                         }
205                         throw new IOException("Failed to initialize target clock");
206                 }
207         }
208
209         void action(String in_s, int in_percent) {
210                 final String s = in_s;
211                 final int percent = in_percent;
212                 if (listener != null && !aborted) {
213                         Runnable r = new Runnable() {
214                                         public void run() {
215                                                 try {
216                                                         listener.actionPerformed(new ActionEvent(this,
217                                                                                                  percent,
218                                                                                                  s));
219                                                 } catch (Exception ex) {
220                                                 }
221                                         }
222                                 };
223                         SwingUtilities.invokeLater(r);
224                 }
225         }
226
227         void action(int part, int total) {
228                 int percent = 100 * part / total;
229                 action(String.format("%d/%d (%d%%)",
230                                      part, total, percent),
231                        percent);
232         }
233
234         void altos_run(int pc) throws IOException, InterruptedException {
235                 debug.set_pc(pc);
236                 int set_pc = debug.get_pc();
237                 if (pc != set_pc)
238                         throw new IOException("Failed to set target program counter");
239                 debug.resume();
240
241                 for (int times = 0; times < 20; times++) {
242                         byte status = debug.read_status();
243                         if ((status & AltosDebug.STATUS_CPU_HALTED) != 0)
244                                 return;
245                 }
246
247                 throw new IOException("Failed to execute program on target");
248         }
249
250         public void flash() {
251                 try {
252                         if (!check_rom_config())
253                                 throw new IOException("Invalid rom config settings");
254                         if (image.address + image.data.length > 0x8000)
255                                 throw new IOException(String.format("Flash image too long %d",
256                                                                     image.address +
257                                                                     image.data.length));
258                         if ((image.address & 0x3ff) != 0)
259                                 throw new IOException(String.format("Flash image must start on page boundary (is 0x%x)",
260                                                                     image.address));
261                         int ram_address = 0xf000;
262                         int flash_prog = 0xf400;
263
264                         /*
265                          * Store desired config values into image
266                          */
267                         rom_config.write(image);
268                         /*
269                          * Bring up the clock
270                          */
271                         clock_init();
272
273                         int remain = image.data.length;
274                         int flash_addr = image.address;
275                         int image_start = 0;
276
277                         action("start", 0);
278                         action(0, image.data.length);
279                         while (remain > 0 && !aborted) {
280                                 int this_time = remain;
281                                 if (this_time > 0x400)
282                                         this_time = 0x400;
283
284                                 if (debug != null) {
285                                         /* write the data */
286                                         debug.write_memory(ram_address, image.data,
287                                                            image_start, this_time);
288
289                                         /* write the flash program */
290                                         byte[] flash_page = make_flash_page(flash_addr,
291                                                                             ram_address,
292                                                                             this_time);
293                                         debug.write_memory(flash_prog, flash_page);
294
295                                         altos_run(flash_prog);
296                                         byte[] check = debug.read_memory(flash_addr, this_time);
297                                         for (int i = 0; i < this_time; i++)
298                                                 if (check[i] != image.data[image_start + i])
299                                                         throw new IOException(String.format("Flash write failed at 0x%x (%02x != %02x)",
300                                                                                             image.address + image_start + i,
301                                                                                             check[i], image.data[image_start + i]));
302                                 } else {
303                                         Thread.sleep(100);
304                                 }
305
306                                 remain -= this_time;
307                                 flash_addr += this_time;
308                                 image_start += this_time;
309
310                                 action(image.data.length - remain, image.data.length);
311                         }
312                         if (!aborted) {
313                                 action("done", 100);
314                                 if (debug != null) {
315                                         debug.set_pc(image.address);
316                                         debug.resume();
317                                 }
318                         }
319                         if (debug != null)
320                                 debug.close();
321                 } catch (IOException ie) {
322                         action(ie.getMessage(), -1);
323                         abort();
324                 } catch (InterruptedException ie) {
325                         abort();
326                 }
327         }
328
329         public void close() {
330                 if (debug != null)
331                         debug.close();
332         }
333
334         synchronized public void abort() {
335                 aborted = true;
336                 close();
337         }
338
339         public void addActionListener(ActionListener l) {
340                 listener = l;
341         }
342
343         public boolean check_rom_config() {
344                 if (debug == null)
345                         return true;
346                 if (rom_config == null)
347                         rom_config = debug.romconfig();
348                 return rom_config != null && rom_config.valid();
349         }
350
351         public void set_romconfig (AltosRomconfig romconfig) {
352                 rom_config = romconfig;
353         }
354
355         public AltosRomconfig romconfig() {
356                 if (!check_rom_config())
357                         return null;
358                 return rom_config;
359         }
360
361         public AltosFlash(File in_file, AltosDevice in_debug_dongle)
362                 throws IOException, FileNotFoundException, AltosSerialInUseException, InterruptedException {
363                 file = in_file;
364                 debug_dongle = in_debug_dongle;
365                 if (debug_dongle != null)
366                         debug = new AltosDebug(new AltosSerial(in_debug_dongle));
367                 input = new FileInputStream(file);
368                 image = new AltosHexfile(input);
369                 if (debug != null && !debug.check_connection()) {
370                         debug.close();
371                         throw new IOException("Debug port not connected");
372                 }
373         }
374 }