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