altosui: Finish device programming code
[fw/altos] / ao-tools / altosui / AltosFlash.java
index bab60c1fbcdd110ce748ae7ecd53ca69cf5b9b26..0f92d6e7bf2ffb82d27fa31aa0fde7cb240e73d5 100644 (file)
@@ -33,17 +33,274 @@ import altosui.AltosHexfile;
 public class AltosFlash {
        File            file;
        FileInputStream input;
-       Thread          thread;
        AltosHexfile    image;
        JFrame          frame;
        AltosDevice     debug_dongle;
        AltosDebug      debug;
        AltosRomconfig  rom_config;
+       ActionListener  listener;
+       boolean         aborted;
+
+       static final byte MOV_direct_data       = (byte) 0x75;
+       static final byte MOV_DPTR_data16       = (byte) 0x90;
+       static final byte MOV_A_data            = (byte) 0x74;
+       static final byte MOVX_atDPTR_A         = (byte) 0xf0;
+       static final byte MOVX_A_atDPTR         = (byte) 0xe0;
+       static final byte INC_DPTR              = (byte) 0xa3;
+       static final byte TRAP                  = (byte) 0xa5;
+
+       static final byte JB                    = (byte) 0x20;
+
+       static final byte MOV_A_direct          = (byte) 0xe5;
+       static final byte MOV_direct1_direct2   = (byte) 0x85;
+       static final byte MOV_direct_A          = (byte) 0xf5;
+       static final byte MOV_R0_data           = (byte) (0x78 | 0);
+       static final byte MOV_R1_data           = (byte) (0x78 | 1);
+       static final byte MOV_R2_data           = (byte) (0x78 | 2);
+       static final byte MOV_R3_data           = (byte) (0x78 | 3);
+       static final byte MOV_R4_data           = (byte) (0x78 | 4);
+       static final byte MOV_R5_data           = (byte) (0x78 | 5);
+       static final byte MOV_R6_data           = (byte) (0x78 | 6);
+       static final byte MOV_R7_data           = (byte) (0x78 | 7);
+       static final byte DJNZ_R0_rel           = (byte) (0xd8 | 0);
+       static final byte DJNZ_R1_rel           = (byte) (0xd8 | 1);
+       static final byte DJNZ_R2_rel           = (byte) (0xd8 | 2);
+       static final byte DJNZ_R3_rel           = (byte) (0xd8 | 3);
+       static final byte DJNZ_R4_rel           = (byte) (0xd8 | 4);
+       static final byte DJNZ_R5_rel           = (byte) (0xd8 | 5);
+       static final byte DJNZ_R6_rel           = (byte) (0xd8 | 6);
+       static final byte DJNZ_R7_rel           = (byte) (0xd8 | 7);
+
+       static final byte P1DIR                 = (byte) 0xFE;
+       static final byte P1                    = (byte) 0x90;
+
+       /* flash controller */
+       static final byte FWT                   = (byte) 0xAB;
+       static final byte FADDRL                = (byte) 0xAC;
+       static final byte FADDRH                = (byte) 0xAD;
+       static final byte FCTL                  = (byte) 0xAE;
+       static final byte FCTL_BUSY             = (byte) 0x80;
+       static final byte FCTL_BUSY_BIT         = (byte) 7;
+       static final byte FCTL_SWBSY            = (byte) 0x40;
+       static final byte FCTL_SWBSY_BIT        = (byte) 6;
+       static final byte FCTL_CONTRD           = (byte) 0x10;
+       static final byte FCTL_WRITE            = (byte) 0x02;
+       static final byte FCTL_ERASE            = (byte) 0x01;
+       static final byte FWDATA                = (byte) 0xAF;
+
+       static final byte ACC                   = (byte) 0xE0;
+
+       /* offsets within the flash_page program */
+       static final int FLASH_ADDR_HIGH        = 8;
+       static final int FLASH_ADDR_LOW         = 11;
+       static final int RAM_ADDR_HIGH          = 13;
+       static final int RAM_ADDR_LOW           = 14;
+       static final int FLASH_WORDS_HIGH       = 16;
+       static final int FLASH_WORDS_LOW        = 18;
+       static final int FLASH_TIMING           = 21;
+
+       /* sleep mode control */
+       static final int SLEEP                  = (byte) 0xbe;
+       static final int  SLEEP_USB_EN          = (byte) 0x80;
+       static final int  SLEEP_XOSC_STB        = (byte) 0x40;
+       static final int  SLEEP_HFRC_STB        = (byte) 0x20;
+       static final int  SLEEP_RST_MASK        = (byte) 0x18;
+       static final int   SLEEP_RST_POWERON    = (byte) 0x00;
+       static final int   SLEEP_RST_EXTERNAL   = (byte) 0x10;
+       static final int   SLEEP_RST_WATCHDOG   = (byte) 0x08;
+       static final int  SLEEP_OSC_PD          = (byte) 0x04;
+       static final int  SLEEP_MODE_MASK       = (byte) 0x03;
+       static final int   SLEEP_MODE_PM0       = (byte) 0x00;
+       static final int   SLEEP_MODE_PM1       = (byte) 0x01;
+       static final int   SLEEP_MODE_PM2       = (byte) 0x02;
+       static final int   SLEEP_MODE_PM3       = (byte) 0x03;
+
+       /* clock controller */
+       static final byte CLKCON                = (byte) 0xC6;
+       static final byte  CLKCON_OSC32K        = (byte) 0x80;
+       static final byte  CLKCON_OSC           = (byte) 0x40;
+       static final byte  CLKCON_TICKSPD       = (byte) 0x38;
+       static final byte  CLKCON_CLKSPD        = (byte) 0x07;
+
+       static final byte[] flash_page_proto = {
+
+               MOV_direct_data, P1DIR, (byte) 0x02,
+               MOV_direct_data, P1,    (byte) 0xFF,
+
+               MOV_direct_data, FADDRH, 0,     /* FLASH_ADDR_HIGH */
+
+               MOV_direct_data, FADDRL, 0,     /* FLASH_ADDR_LOW */
+
+               MOV_DPTR_data16, 0, 0,          /* RAM_ADDR_HIGH, RAM_ADDR_LOW */
+
+               MOV_R7_data, 0,                 /* FLASH_WORDS_HIGH */
+
+               MOV_R6_data, 0,                 /* FLASH_WORDS_LOW */
+
+
+               MOV_direct_data, FWT, 0x20,     /* FLASH_TIMING */
+
+               MOV_direct_data, FCTL, FCTL_ERASE,
+/* eraseWaitLoop: */
+               MOV_A_direct,           FCTL,
+               JB, ACC|FCTL_BUSY_BIT, (byte) 0xfb,
+
+               MOV_direct_data, P1, (byte) 0xfd,
+
+               MOV_direct_data, FCTL, FCTL_WRITE,
+/* writeLoop: */
+               MOV_R5_data, 2,
+/* writeWordLoop: */
+               MOVX_A_atDPTR,
+               INC_DPTR,
+               MOV_direct_A, FWDATA,
+               DJNZ_R5_rel, (byte) 0xfa,               /* writeWordLoop */
+/* writeWaitLoop: */
+               MOV_A_direct, FCTL,
+               JB, ACC|FCTL_SWBSY_BIT, (byte) 0xfb,    /* writeWaitLoop */
+               DJNZ_R6_rel, (byte) 0xf1,               /* writeLoop */
+               DJNZ_R7_rel, (byte) 0xef,                       /* writeLoop */
+
+               MOV_direct_data, P1DIR, (byte) 0x00,
+               MOV_direct_data, P1,    (byte) 0xFF,
+               TRAP,
+       };
+
+       public byte[] make_flash_page(int flash_addr, int ram_addr, int byte_count) {
+               int flash_word_addr = flash_addr >> 1;
+               int flash_word_count = ((byte_count + 1) >> 1);
+
+               byte[] flash_page = new byte[flash_page_proto.length];
+               for (int i = 0; i < flash_page.length; i++)
+                       flash_page[i] = flash_page_proto[i];
+
+               flash_page[FLASH_ADDR_HIGH]  = (byte) (flash_word_addr >> 8);
+               flash_page[FLASH_ADDR_LOW]   = (byte) (flash_word_addr);
+               flash_page[RAM_ADDR_HIGH]    = (byte) (ram_addr >> 8);
+               flash_page[RAM_ADDR_LOW]     = (byte) (ram_addr);
+
+               byte flash_words_low = (byte) (flash_word_count);
+               byte flash_words_high = (byte) (flash_word_count >> 8);
+               /* the flashing code has a minor 'bug' */
+               if (flash_words_low != 0)
+                       flash_words_high++;
+
+               flash_page[FLASH_WORDS_HIGH] = (byte) flash_words_high;
+               flash_page[FLASH_WORDS_LOW]  = (byte) flash_words_low;
+               return flash_page;
+       }
+
+       static byte[] set_clkcon_fast = {
+               MOV_direct_data, CLKCON, 0x00
+       };
+
+       static byte[] get_sleep = {
+               MOV_A_direct, SLEEP
+       };
+
+       public void clock_init() throws IOException, InterruptedException {
+               debug.debug_instr(set_clkcon_fast);
+
+               byte    status;
+               do {
+                       status = debug.debug_instr(get_sleep);
+               } while ((status & SLEEP_XOSC_STB) == 0);
+       }
+
+       void action(String s, int percent) {
+               if (listener != null && !aborted)
+                       listener.actionPerformed(new ActionEvent(this,
+                                                                percent,
+                                                                s));
+       }
+
+       void action(int part, int total) {
+               int percent = 100 * part / total;
+               action(String.format("%d/%d (%d%%)",
+                                    part, total, percent),
+                      percent);
+       }
 
        public void flash() throws IOException, FileNotFoundException, InterruptedException {
                if (!check_rom_config())
                        throw new IOException("Invalid rom config settings");
+               if (image.address + image.data.length > 0x8000)
+                       throw new IOException(String.format("Flash image too long %d",
+                                                           image.address +
+                                                           image.data.length));
+               if ((image.address & 0x3ff) != 0)
+                       throw new IOException(String.format("Flash image must start on page boundary (is 0x%x)",
+                                                           image.address));
+               int ram_address = 0xf000;
+               int flash_prog = 0xf400;
+
+               /*
+                * Store desired config values into image
+                */
                rom_config.write(image);
+               /*
+                * Bring up the clock
+                */
+               clock_init();
+
+               int remain = image.data.length;
+               int flash_addr = image.address;
+               int image_start = 0;
+
+               action(0, image.data.length);
+               while (remain > 0 && !aborted) {
+                       int this_time = remain;
+                       if (this_time > 0x400)
+                               this_time = 0x400;
+
+                       /* write the data */
+                       debug.write_memory(ram_address, image.data,
+                                          image_start, this_time);
+
+                       /* write the flash program */
+                       byte[] flash_page = make_flash_page(flash_addr,
+                                                           ram_address,
+                                                           this_time);
+                       debug.write_memory(flash_prog, flash_page);
+
+                       debug.set_pc(flash_prog);
+                       int pc = debug.get_pc();
+                       debug.resume();
+                       Thread.sleep(100);
+                       for (int times = 0; times < 10; times++) {
+                               byte status = debug.read_status();
+                               if ((status & AltosDebug.STATUS_CPU_HALTED) != 0)
+                                       break;
+                               Thread.sleep(100);
+                       }
+
+                       byte[] check = debug.read_memory(flash_addr, this_time);
+                       for (int i = 0; i < this_time; i++)
+                               if (check[i] != image.data[image_start + i])
+                                       throw new IOException(String.format("Flash write failed at 0x%x (%02x != %02x)",
+                                                                           image.address + image_start + i,
+                                                                           check[i], image.data[image_start + i]));
+                       remain -= this_time;
+                       flash_addr += this_time;
+                       image_start += this_time;
+
+                       action(image.data.length - remain, image.data.length);
+               }
+               if (!aborted) {
+                       action("done", 100);
+                       debug.set_pc(image.address);
+                       debug.resume();
+               }
+               debug.close();
+       }
+
+       public void abort() {
+               aborted = true;
+               debug.close();
+       }
+
+       public void addActionListener(ActionListener l) {
+               listener = l;
        }
 
        public boolean check_rom_config() {
@@ -56,6 +313,10 @@ public class AltosFlash {
                rom_config = romconfig;
        }
 
+       public AltosRomconfig romconfig() {
+               return rom_config;
+       }
+
        public void open() throws IOException, FileNotFoundException, InterruptedException {
                input = new FileInputStream(file);
                image = new AltosHexfile(input);