2013-10-28 13:19:25 +00:00

290 lines
5.4 KiB
C++

#define STAGEBASE 568
#if 0
static PROGMEM prog_uint32_t crc_table[16] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};
unsigned long crc_update(unsigned long crc, byte data)
{
uint_farptr_t tab = GET_FAR_ADDRESS(crc_table);
byte tbl_idx;
tbl_idx = crc ^ data;
crc = pgm_read_dword_far(tab + 4 * (tbl_idx & 0x0f)) ^ (crc >> 4);
tbl_idx = crc ^ (data >> 4);
crc = pgm_read_dword_far(tab + 4 * (tbl_idx & 0x0f)) ^ (crc >> 4);
return crc;
}
#else
static uint32_t crc_table[16] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};
unsigned long crc_update(unsigned long crc, byte data)
{
byte tbl_idx;
tbl_idx = crc ^ data;
crc = crc_table[tbl_idx & 0x0f] ^ (crc >> 4);
tbl_idx = crc ^ (data >> 4);
crc = crc_table[tbl_idx & 0x0f] ^ (crc >> 4);
return crc;
}
#endif
class GDflashbits {
public:
void begin(prog_uchar *s) {
src = s;
mask = 0x01;
}
byte get1(void) {
byte r = (pgm_read_byte_near(src) & mask) != 0;
mask <<= 1;
if (!mask) {
mask = 1;
src++;
}
return r;
}
unsigned short getn(byte n) {
unsigned short r = 0;
while (n--) {
r <<= 1;
r |= get1();
}
return r;
}
private:
prog_uchar *src;
byte mask;
};
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// far ptr version
class GDflashbitsF {
public:
void begin(uint_farptr_t s) {
src = s;
mask = 8;
m = pgm_read_byte_far(src++);
}
byte get1(void) {
byte r = (m & 1);
m >>= 1;
if (--mask == 0) {
mask = 8;
m = pgm_read_byte_far(src++);
}
return r;
}
unsigned short getn(byte n) {
unsigned short r = 0;
while (n--) {
r <<= 1;
r |= get1();
}
return r;
}
private:
uint_farptr_t src;
byte m, mask;
};
#endif
static byte history[264], hp;
int page, offset;
#define FLOCAL 2
#define SEL_local() digitalWrite(FLOCAL, LOW)
#define UNSEL_local() digitalWrite(FLOCAL, HIGH)
#define spix(n) SPI.transfer(n)
static void spipage(int n)
{
spix(n >> 7);
spix(n << 1);
spix(0);
}
static byte status()
{
SEL_local();
spix(0xd7); // read SPI flash status
byte status = spix(0);
UNSEL_local();
return status;
}
static void UNSEL_local_wait()
{
UNSEL_local();
while ((status() & 0x80) == 0)
;
}
static void pgcmd(byte cmd, int page)
{
SEL_local();
spix(cmd);
spipage(page);
}
static void supply(byte b)
{
history[hp++] = b;
if (offset == 0) {
if ((page & 7) == 0) {
pgcmd(0x50, page);
UNSEL_local_wait();
}
pgcmd(0x84, page);
}
spix(b);
if (++offset == 264) {
UNSEL_local();
pgcmd(0x88, page++);
UNSEL_local_wait();
offset = 0;
}
}
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
static GDflashbitsF GDFB;
static void GD_uncompress(uint_farptr_t src)
#else
static GDflashbits GDFB;
static void GD_uncompress(PROGMEM prog_uchar *src)
#endif
{
GDFB.begin(src);
byte b_off = GDFB.getn(4);
byte b_len = GDFB.getn(4);
byte minlen = GDFB.getn(2);
unsigned short items = GDFB.getn(16);
hp = 0;
offset = 0;
while (items--) {
if (GDFB.get1() == 0) {
supply(GDFB.getn(8));
} else {
int offset = -GDFB.getn(b_off) - 1;
int l = GDFB.getn(b_len) + minlen;
while (l--) {
supply(history[0xff & (hp + offset)]);
}
}
}
}
static unsigned long flash_crc(int page, int n)
{
SEL_local();
SPI.transfer(0x03);
spipage(page);
unsigned long crc = ~0;
unsigned long len = 264L * n;
while (len--) {
byte b = spix(0);
crc = crc_update(crc, b);
}
crc = ~crc;
UNSEL_local();
return crc;
}
static unsigned long flash_sum(int page, int n)
{
SEL_local();
SPI.transfer(0x03);
spipage(page);
unsigned long sum = 0;
unsigned long len = 264L * n;
while (len--) {
byte b = spix(0);
sum = sum + b;
}
UNSEL_local();
return sum;
}
#ifdef P0OFF
static byte ready(byte part, int sb = STAGEBASE)
{
switch (part) {
case 0: return flash_crc(sb + P0OFF, P0SIZE) == P0CRC;
case 1: return flash_crc(sb + P1OFF, P1SIZE) == P1CRC;
case 2: return flash_crc(sb + P2OFF, P2SIZE) == P2CRC;
case 3: return flash_crc(sb + P3OFF, P3SIZE) == P3CRC;
case 4: return flash_crc(P4OFF, P4SIZE) == P4CRC;
}
return 0;
}
static int atxy(int x, int y)
{
return (y << 6) + x;
}
static void common_show_status()
{
for (byte i = 0; i < 5; i++) {
byte y = 10 + 2 * i;
GD.putstr(0, y, "part ");
GD.wr(atxy(6, y), '0' + i);
GD.putstr(25, y, ready(i) ? "OK" : "--");
}
}
static int ready0123(int sb)
{
return ready(0, sb) && ready(1, sb) && ready(2, sb) && ready(3, sb);
}
#endif
static void common_setup(byte part)
{
GD.begin();
GD.wr(IOMODE, 'F');
pinMode(2, OUTPUT);
digitalWrite(2, HIGH);
GD.ascii();
#ifdef REVISION
// avoid sprintf because it bloats executable
GD.putstr(0, 0, "Flash loader");
char revmsg[] = "Firmware X.X";
revmsg[9] = '0' + (REVISION >> 4);
revmsg[11] = '0' + (REVISION & 0xf);
GD.putstr(0, 2, revmsg);
char partmsg[] = "part X";
partmsg[5] = '0' + part;
GD.putstr(0, 4, partmsg);
GD.putstr(0, 8, "loading");
GD.putstr(8, 8, partmsg);
common_show_status();
#endif
}