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