2 * Copyright © 2010 Keith Packard <keithp@keithp.com>
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.
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.
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.
21 import java.awt.event.*;
23 import javax.swing.filechooser.FileNameExtensionFilter;
24 import javax.swing.table.*;
28 import java.util.prefs.*;
29 import java.util.concurrent.LinkedBlockingQueue;
30 import org.altusmetrum.AltosLib.*;
32 public class AltosFlash {
34 FileInputStream input;
37 AltosDevice debug_dongle;
39 AltosRomconfig rom_config;
40 ActionListener listener;
43 static final byte MOV_direct_data = (byte) 0x75;
44 static final byte MOV_DPTR_data16 = (byte) 0x90;
45 static final byte MOV_A_data = (byte) 0x74;
46 static final byte MOVX_atDPTR_A = (byte) 0xf0;
47 static final byte MOVX_A_atDPTR = (byte) 0xe0;
48 static final byte INC_DPTR = (byte) 0xa3;
49 static final byte TRAP = (byte) 0xa5;
51 static final byte JB = (byte) 0x20;
53 static final byte MOV_A_direct = (byte) 0xe5;
54 static final byte MOV_direct1_direct2 = (byte) 0x85;
55 static final byte MOV_direct_A = (byte) 0xf5;
56 static final byte MOV_R0_data = (byte) (0x78 | 0);
57 static final byte MOV_R1_data = (byte) (0x78 | 1);
58 static final byte MOV_R2_data = (byte) (0x78 | 2);
59 static final byte MOV_R3_data = (byte) (0x78 | 3);
60 static final byte MOV_R4_data = (byte) (0x78 | 4);
61 static final byte MOV_R5_data = (byte) (0x78 | 5);
62 static final byte MOV_R6_data = (byte) (0x78 | 6);
63 static final byte MOV_R7_data = (byte) (0x78 | 7);
64 static final byte DJNZ_R0_rel = (byte) (0xd8 | 0);
65 static final byte DJNZ_R1_rel = (byte) (0xd8 | 1);
66 static final byte DJNZ_R2_rel = (byte) (0xd8 | 2);
67 static final byte DJNZ_R3_rel = (byte) (0xd8 | 3);
68 static final byte DJNZ_R4_rel = (byte) (0xd8 | 4);
69 static final byte DJNZ_R5_rel = (byte) (0xd8 | 5);
70 static final byte DJNZ_R6_rel = (byte) (0xd8 | 6);
71 static final byte DJNZ_R7_rel = (byte) (0xd8 | 7);
73 static final byte P1DIR = (byte) 0xFE;
74 static final byte P1 = (byte) 0x90;
76 /* flash controller */
77 static final byte FWT = (byte) 0xAB;
78 static final byte FADDRL = (byte) 0xAC;
79 static final byte FADDRH = (byte) 0xAD;
80 static final byte FCTL = (byte) 0xAE;
81 static final byte FCTL_BUSY = (byte) 0x80;
82 static final byte FCTL_BUSY_BIT = (byte) 7;
83 static final byte FCTL_SWBSY = (byte) 0x40;
84 static final byte FCTL_SWBSY_BIT = (byte) 6;
85 static final byte FCTL_CONTRD = (byte) 0x10;
86 static final byte FCTL_WRITE = (byte) 0x02;
87 static final byte FCTL_ERASE = (byte) 0x01;
88 static final byte FWDATA = (byte) 0xAF;
90 static final byte ACC = (byte) 0xE0;
92 /* offsets within the flash_page program */
93 static final int FLASH_ADDR_HIGH = 8;
94 static final int FLASH_ADDR_LOW = 11;
95 static final int RAM_ADDR_HIGH = 13;
96 static final int RAM_ADDR_LOW = 14;
97 static final int FLASH_WORDS_HIGH = 16;
98 static final int FLASH_WORDS_LOW = 18;
99 static final int FLASH_TIMING = 21;
101 /* sleep mode control */
102 static final int SLEEP = (byte) 0xbe;
103 static final int SLEEP_USB_EN = (byte) 0x80;
104 static final int SLEEP_XOSC_STB = (byte) 0x40;
105 static final int SLEEP_HFRC_STB = (byte) 0x20;
106 static final int SLEEP_RST_MASK = (byte) 0x18;
107 static final int SLEEP_RST_POWERON = (byte) 0x00;
108 static final int SLEEP_RST_EXTERNAL = (byte) 0x10;
109 static final int SLEEP_RST_WATCHDOG = (byte) 0x08;
110 static final int SLEEP_OSC_PD = (byte) 0x04;
111 static final int SLEEP_MODE_MASK = (byte) 0x03;
112 static final int SLEEP_MODE_PM0 = (byte) 0x00;
113 static final int SLEEP_MODE_PM1 = (byte) 0x01;
114 static final int SLEEP_MODE_PM2 = (byte) 0x02;
115 static final int SLEEP_MODE_PM3 = (byte) 0x03;
117 /* clock controller */
118 static final byte CLKCON = (byte) 0xC6;
119 static final byte CLKCON_OSC32K = (byte) 0x80;
120 static final byte CLKCON_OSC = (byte) 0x40;
121 static final byte CLKCON_TICKSPD = (byte) 0x38;
122 static final byte CLKCON_CLKSPD = (byte) 0x07;
124 static final byte[] flash_page_proto = {
126 MOV_direct_data, P1DIR, (byte) 0x02,
127 MOV_direct_data, P1, (byte) 0xFF,
129 MOV_direct_data, FADDRH, 0, /* FLASH_ADDR_HIGH */
131 MOV_direct_data, FADDRL, 0, /* FLASH_ADDR_LOW */
133 MOV_DPTR_data16, 0, 0, /* RAM_ADDR_HIGH, RAM_ADDR_LOW */
135 MOV_R7_data, 0, /* FLASH_WORDS_HIGH */
137 MOV_R6_data, 0, /* FLASH_WORDS_LOW */
140 MOV_direct_data, FWT, 0x20, /* FLASH_TIMING */
142 MOV_direct_data, FCTL, FCTL_ERASE,
145 JB, ACC|FCTL_BUSY_BIT, (byte) 0xfb,
147 MOV_direct_data, P1, (byte) 0xfd,
149 MOV_direct_data, FCTL, FCTL_WRITE,
155 MOV_direct_A, FWDATA,
156 DJNZ_R5_rel, (byte) 0xfa, /* writeWordLoop */
159 JB, ACC|FCTL_SWBSY_BIT, (byte) 0xfb, /* writeWaitLoop */
160 DJNZ_R6_rel, (byte) 0xf1, /* writeLoop */
161 DJNZ_R7_rel, (byte) 0xef, /* writeLoop */
163 MOV_direct_data, P1DIR, (byte) 0x00,
164 MOV_direct_data, P1, (byte) 0xFF,
168 public byte[] make_flash_page(int flash_addr, int ram_addr, int byte_count) {
169 int flash_word_addr = flash_addr >> 1;
170 int flash_word_count = ((byte_count + 1) >> 1);
172 byte[] flash_page = new byte[flash_page_proto.length];
173 for (int i = 0; i < flash_page.length; i++)
174 flash_page[i] = flash_page_proto[i];
176 flash_page[FLASH_ADDR_HIGH] = (byte) (flash_word_addr >> 8);
177 flash_page[FLASH_ADDR_LOW] = (byte) (flash_word_addr);
178 flash_page[RAM_ADDR_HIGH] = (byte) (ram_addr >> 8);
179 flash_page[RAM_ADDR_LOW] = (byte) (ram_addr);
181 byte flash_words_low = (byte) (flash_word_count);
182 byte flash_words_high = (byte) (flash_word_count >> 8);
183 /* the flashing code has a minor 'bug' */
184 if (flash_words_low != 0)
187 flash_page[FLASH_WORDS_HIGH] = (byte) flash_words_high;
188 flash_page[FLASH_WORDS_LOW] = (byte) flash_words_low;
192 static byte[] set_clkcon_fast = {
193 MOV_direct_data, CLKCON, 0x00
196 static byte[] get_sleep = {
200 public void clock_init() throws IOException, InterruptedException {
202 debug.debug_instr(set_clkcon_fast);
205 for (int times = 0; times < 20; times++) {
207 status = debug.debug_instr(get_sleep);
208 if ((status & SLEEP_XOSC_STB) != 0)
211 throw new IOException("Failed to initialize target clock");
215 void action(String in_s, int in_percent) {
216 final String s = in_s;
217 final int percent = in_percent;
218 if (listener != null && !aborted) {
219 Runnable r = new Runnable() {
222 listener.actionPerformed(new ActionEvent(this,
225 } catch (Exception ex) {
229 SwingUtilities.invokeLater(r);
233 void action(int part, int total) {
234 int percent = 100 * part / total;
235 action(String.format("%d/%d (%d%%)",
236 part, total, percent),
240 void altos_run(int pc) throws IOException, InterruptedException {
242 int set_pc = debug.get_pc();
244 throw new IOException("Failed to set target program counter");
247 for (int times = 0; times < 20; times++) {
248 byte status = debug.read_status();
249 if ((status & AltosDebug.STATUS_CPU_HALTED) != 0)
253 throw new IOException("Failed to execute program on target");
256 public void flash() {
258 if (!check_rom_config())
259 throw new IOException("Invalid rom config settings");
260 if (image.address + image.data.length > 0x8000)
261 throw new IOException(String.format("Flash image too long %d",
264 if ((image.address & 0x3ff) != 0)
265 throw new IOException(String.format("Flash image must start on page boundary (is 0x%x)",
267 int ram_address = 0xf000;
268 int flash_prog = 0xf400;
271 * Store desired config values into image
273 rom_config.write(image);
279 int remain = image.data.length;
280 int flash_addr = image.address;
284 action(0, image.data.length);
285 while (remain > 0 && !aborted) {
286 int this_time = remain;
287 if (this_time > 0x400)
292 debug.write_memory(ram_address, image.data,
293 image_start, this_time);
295 /* write the flash program */
296 byte[] flash_page = make_flash_page(flash_addr,
299 debug.write_memory(flash_prog, flash_page);
301 altos_run(flash_prog);
302 byte[] check = debug.read_memory(flash_addr, this_time);
303 for (int i = 0; i < this_time; i++)
304 if (check[i] != image.data[image_start + i])
305 throw new IOException(String.format("Flash write failed at 0x%x (%02x != %02x)",
306 image.address + image_start + i,
307 check[i], image.data[image_start + i]));
313 flash_addr += this_time;
314 image_start += this_time;
316 action(image.data.length - remain, image.data.length);
321 debug.set_pc(image.address);
327 } catch (IOException ie) {
328 action(ie.getMessage(), -1);
330 } catch (InterruptedException ie) {
335 public void close() {
340 synchronized public void abort() {
345 public void addActionListener(ActionListener l) {
349 public boolean check_rom_config() {
352 if (rom_config == null)
353 rom_config = debug.romconfig();
354 return rom_config != null && rom_config.valid();
357 public void set_romconfig (AltosRomconfig romconfig) {
358 rom_config = romconfig;
361 public AltosRomconfig romconfig() {
362 if (!check_rom_config())
367 public AltosFlash(File in_file, AltosDevice in_debug_dongle)
368 throws IOException, FileNotFoundException, AltosSerialInUseException, InterruptedException {
370 debug_dongle = in_debug_dongle;
371 if (debug_dongle != null)
372 debug = new AltosDebug(in_debug_dongle);
373 input = new FileInputStream(file);
374 image = new AltosHexfile(input);
375 if (debug != null && !debug.check_connection()) {
377 throw new IOException("Debug port not connected");