Permalink
Switch branches/tags
Nothing to show
Find file Copy path
5e0a9ac Sep 18, 2016
1 contributor

Users who have contributed to this file

1833 lines (1583 sloc) 44.5 KB
/*
File: bl08.c
Version: 1.0.0.1
Copyright (c) 2004,2008 Kustaa Nyholm
Copyright (c) 2008 Robert Larice (SWI return to MON, QY2 chip)
Copyright (c) 2010 Tormod Volden
Copyright (c) 2013 Jaromir Sukuba (added A and B ROM routines entry instances,
dozen new supported chips, reset polarity)
http://jaromir.xf.cz/
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2.0 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// This code compiles cleanly with i686-apple-darwin8-gcc-4.0.1 with command:
// gcc -Wall -std=c99 -pedantic -o bl08 bl08.c
// and uses only POSIX standard headers so this should be pretty
// easy to port anywhere: Mac OS X, Linux , MinGW, Cygwin
//
// Having said that I'm pretty sure there is implicit assumptions that
// int is 32 bits, char is signed 8 bits
// I also expect that extending this code to handle S-records in the +2G range
// will uncover more implicit assumptions.
//
// cheers Kusti
#include <stdlib.h>
#include <fcntl.h>
#include <termios.h>
#include <stdarg.h>
#include <ctype.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <signal.h>
#if defined(__linux__)
# include <sys/wait.h>
# include <sys/ioctl.h>
#else
// Terrible hack here because POSIX says 'ioctl()' is in <stropts.h> but
// for example Mac OS X Tiger does not have this header, OTOH I think
// that <sys/ioctl.h> is not POSIX either so how do you write
// actual POSIX compliant code that compiles cleanly on POSIX...
extern int ioctl (int filedes, int command, ...);
// End of hack
#endif
#define PIDFILENAME "bl08PIDfile.temp"
//char* COM = "/dev/tty.usbserial-FTOXM3NX";
char* COM = "/dev/ttyS0";
typedef struct {
char* str;
int val;
} pair;
pair portPins[]= {
{"LE",TIOCM_LE},
{"DTR",TIOCM_DTR},
{"RTS",TIOCM_RTS},
{"ST",TIOCM_ST},
{"SR",TIOCM_SR},
{"CTS",TIOCM_CTS},
{"CAR",TIOCM_CAR},
{"CD",TIOCM_CD},
{"RNG",TIOCM_RNG},
{"RI",TIOCM_RI},
{"DSR",TIOCM_DSR}
};
int forcePins[sizeof(portPins)/sizeof(portPins[0])] = {0};
pair baudrates[]= {
// Some common, but non POSIX baudrates here
#ifdef B14400
{"14400",B14400},
#endif
#ifdef B57600
{"57600",B57600},
#endif
#ifdef B115200
{"115200",B115200},
#endif
#ifdef B230400
{"230400",B230400},
#endif
{"0",B0},
{"50",B50},
{"75",B75},
{"110",B110},
{"134",B134},
{"150",B150},
{"200",B200},
{"300",B300},
{"600",B600},
{"1200",B1200},
{"1800",B1800},
{"2400",B2400},
{"4800",B4800},
{"9600",B9600},
{"19200",B19200},
{"38400",B38400},
};
int baudRate=B9600;
int com;
char version[] = "1.0.0.1";
unsigned char image[ 0x10000 ]; // HC908 memory image
unsigned char scode[8]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
// EARRNG, CTRLBYT parameter
#define ERARRNG_PAGE_ERASE 0x00
#define ERARRNG_MASS_ERASE 0x40
// These will be initialized by setCPUtype()
int CPUSPEED; // 2 x Fbus freq, e.g. ext osc 16 MHz -> Fbus == 4 Mh => CPUSPEED==2
int RAM;
int FLASH; // Flash start address
int PUTBYTE; // Receive byte routine address
int GETBYTE; // Receive byte routine address
int RDVRRNG; // Read/verify flash routine address
int ERARRNG; // Erase flash routine address
int PRGRNGE; // Flash programming routine address
int FLBPR; // Flash block proctection register address
int MONRTN; // Monitor mode return jump address
int EADDR; // For FLBPR in Flash the mass erase must use FLBPR as the erase address
int MONTYPE; // 0 - type A, 1 - type B instance, difference in ROM routines calling, see AN2874
// These will be calculated
int MONDATA; // Flashing routines parameter block address (==RAM+8)
int CTRLBYT; // Address of flashing routine control variable (==MONDATA+0)
int CPUSPD; // Address of flashing routine cpu speed variable (==MONDATA+1)
int LADDR; // Address of flashing routine last address variable (==MONDATA+2)
int DATABUF; // Flashing routines data buffer address (==MONDATA+4)
int PAGESIZE; // Databuffer size
int WORKRAM; // Work storage needed for calling flashing routines
int WORKTOP; // Topmost work storage address
// HC908GZ16 Memory usage (note for some HC908 variants the ROM routines use memory starting from 0x80):
// 0x40 - 0x47 reserved for future ROM routine expansion needs
// 0x48 - 0x4B ROM routine parameters
// 0x4C - 0x6C ROM routine data buffer (64 bytes as used in this code)
// 0xAC - 0xFF Working storage for calling the ROM routines (about 17 bytes used)
int tickP1=15;
int tickP2=1023;
int verbose = 1;
int size = sizeof(image);
int useStdin=0;
int dumpStart=0;
int dumpSize=0;
char* dumpFormat="hex";
int eraseFlash=0;
int verify=0;
char* executeCode=NULL;
int pageErase=0;
int uploadOnly=0;
int terminalMode=0;
int connected=0;
int useFastProg=0;
int resetPulse=0;
int resetPolarity=0;
int killPrevious=0;
int loadOnly=0;
void comErr(char *fmt, ...) {
char buf[ 500 ];
va_list va;
va_start(va, fmt);
vsnprintf(buf, sizeof(buf), fmt, va);
fprintf(stderr,"%s", buf);
perror(COM);
va_end(va);
abort();
}
void flsprintf(FILE* f, char *fmt, ...) {
char buf[ 500 ];
va_list va;
va_start(va, fmt);
vsnprintf(buf, sizeof(buf), fmt, va);
fprintf(f,"%s", buf);
fflush(f);
va_end(va);
}
void ioctlErrCheck(int e) {
if (e) {
flsprintf(stdout,"ioctl returned %d\n",e);
abort();
}
}
void setHandshake() {
int i,s;
ioctlErrCheck(ioctl(com, TIOCMGET, &s));
for (i=0; i<sizeof(forcePins)/sizeof(forcePins[0]); i++) {
int v=forcePins[i]-1;
if (v==1)
s &= ~portPins[i].val;
if (v==0)
s |= portPins[i].val;
}
ioctlErrCheck(ioctl(com, TIOCMSET, &s));
}
void initSerialPort() {
com = open(COM, O_RDWR | O_NOCTTY | O_NDELAY);
if (com <0)
comErr("Failed to open serial port\n");
fcntl(com, F_SETFL, 0);
struct termios opts;
tcgetattr(com, &opts);
opts.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
opts.c_cflag |= (CLOCAL | CREAD);
opts.c_cflag &= ~PARENB;
opts.c_cflag |= CSTOPB; // two stop bits
opts.c_cflag &= ~CSIZE;
opts.c_cflag |= CS8;
opts.c_oflag &= ~OPOST;
opts.c_iflag &= ~INPCK;
opts.c_iflag &= ~(IXON | IXOFF | IXANY);
opts.c_cc[ VMIN ] = 0;
opts.c_cc[ VTIME ] = 10;//0.1 sec
cfsetispeed(&opts, baudRate);
cfsetospeed(&opts, baudRate);
setHandshake();
if (tcsetattr(com, TCSANOW, &opts) != 0) {
perror(COM);
abort();
}
tcflush(com,TCIOFLUSH); // just in case some crap is the buffers
/*
if (!terminalMode) {
char buf = -2;
while (read(com, &buf, 1)>0) {
if (verbose)
flsprintf(stderr,"Unexpected data from serial port: %02X\n",buf & 0xFF);
}
}
*/
}
void putByte(int byte) {
char buf = byte;
if (verbose>3)
flsprintf(stdout,"TX: 0x%02X\n", byte);
int n = write(com, &buf, 1);
if (n != 1)
comErr("Serial port failed to send a byte, write returned %d\n", n);
}
int getByte() {
char buf;
int n = read(com, &buf, 1);
if (verbose>3)
flsprintf(stdout,n<1?"RX: fail\n":"RX: 0x%02X\n", buf & 0xFF);
if (n == 1)
return buf & 0xFF;
comErr("Serial port failed to receive a byte, read returned %d\n", n);
return -1; // never reached
}
// This reads away break 'character' from the serial line
void flushBreak() {
int i;
for (i=0; i<2; ++i) {
char buf;
int n = read(com, &buf, 1);
if (verbose>3)
flsprintf(stdout,n<1?"FL: nothing\n":"FL: 0x%02X\n", buf & 0xFF);
}
}
void sendByte(int byte) {
byte &= 0xFF;
putByte(byte);
char buf;
if (read(com, &buf, 1)!=1)
comErr("Loopback failed, nothing was received\n");
int rx=buf &0xFF;
if (byte != rx)
comErr("Loopback failed, sent 0x%02X, got 0x%02X\n", byte, rx);
rx = getByte();
if (byte != rx)
comErr("Target echo failed, sent 0x%02X, got 0x%02X\n", byte, rx);
}
void readMemory(int addr, int n,int tick) {
if (verbose>2)
flsprintf(stdout,"Read memory address %04X size %04X\n",addr,n);
unsigned char* p = &image[ addr ];
sendByte(0x4A); // Monitor mode READ command
sendByte(addr >> 8);
sendByte(addr & 0xFF);
*(p++) = getByte();
n--;
int tc=0;
while (n>0) {
sendByte(0x1A); // Monitor mode IREAD command
int b1 = getByte();
int b2 = getByte();
*(p++) = b1;
n--;
if (n > 0)
*(p++) = b2;
n--;
if (tick) {
tc++;
if ((tc & tickP1)==0)
flsprintf(stdout,".");
//if ((tc & tickP2)==0)
// flsprintf(stdout,"\n");
}
}
}
/*
void writeMemory(int addr, int n, int tick) {
if (verbose>2)
flsprintf(stdout,"Write memory address %04X size %04X\n",addr,n);
unsigned char* p = &image[ addr ];
char buf;
int i;
putByte(0x49); // Monitor mode WRITE command
putByte(addr >> 8);
putByte(addr & 0xFF);
putByte(*(p++));
for (i=0;i<4;i++)
{
read(com, &buf, 1);
flsprintf(stdout,"%02X ",buf);
}
int tc=1;
while (n>1) {
putByte(0x19); // Monitor mode IWRITE command
putByte(*(p++));
n -= 1;
if (tick) {
tc++;
if ((tc & tickP1)==0)
flsprintf(stdout,".");
//if ((tc & tickP2)==0)
// flsprintf(stdout,"\n");
}
}
for (i=0;i<(n-1);i++)
{
read(com, &buf, 1);
flsprintf(stdout,"%02X ",buf);
}
flsprintf(stdout,"--\n");
}
*/
void writeMemory(int addr, int n, int tick) {
if (verbose>2)
flsprintf(stdout,"Write memory address %04X size %04X\n",addr,n);
unsigned char* p = &image[ addr ];
sendByte(0x49); // Monitor mode WRITE command
sendByte(addr >> 8);
sendByte(addr & 0xFF);
sendByte(*(p++));
int tc=1;
while (n>1) {
sendByte(0x19); // Monitor mode IWRITE command
sendByte(*(p++));
n -= 1;
if (tick) {
tc++;
if ((tc & tickP1)==0)
flsprintf(stdout,".");
//if ((tc & tickP2)==0)
// flsprintf(stdout,"\n");
}
}
}
void connectTarget() {
int j;
if (connected)
return;
flsprintf(stdout, "Security code: ");
for (j = 0; j<8; ++j) {
sendByte(scode[j]);
flsprintf(stdout, ".");
}
flsprintf(stdout, " ");
flushBreak();
readMemory(RAM, 1 , 0);
connected=1;
if ((image[ RAM ] & 0x40) == 0)
flsprintf(stdout,"failed\n");
else
flsprintf(stdout,"passed\n");
// in case FLBPR is RAM based we clear it first by just writing it
image[FLBPR]=0xFF;
writeMemory(FLBPR,1,0);
}
void dumpMemory(int addr, int n) {
unsigned char* p = &image[ addr ];
int i;
for (i = 0; i<n; ++i) {
if ((i&0xF) == 0)
flsprintf(stdout,"%04X ", addr+i);
flsprintf(stdout,"%02X ", *(p++) & 0xFF);
if ((i&0xF) == 7)
flsprintf(stdout," ");
if ((i&0xF) == 15)
flsprintf(stdout,"\n");
}
if ((i&0xF) != 0)
flsprintf(stdout,"\n");
}
void dumpMemorySrec(int addr, int size) {
unsigned char* p = &image[ addr ];
while (size>0) {
int n = size>16 ? 16 : size;
int bc=2+n+1;
flsprintf(stdout,"S1%02X%04X",bc,addr);
int s=(addr >> 8) + (addr & 0xFF) + bc;
int i;
for (i=0; i<n; ++i) {
int bty=*p & 0xFF;
s += bty;
flsprintf(stdout,"%02X",bty);
++p;
++addr;
}
size -= n;
flsprintf(stdout,"%02X\n",~s & 0xFF);
}
}
int readSP() {
if (verbose>2)
flsprintf(stdout,"Read Stack Pointer\n");
sendByte(0x0C); // Monitor mode READSP command
return (((getByte() << 8) | (getByte() & 0xFF)) - 1) & 0xFFFF;
}
int runFrom(int PC, int A, int CC, int HX) {
int SP=readSP();
if (verbose>2)
flsprintf(stdout,"Execute code PC=%04X A=%02X CC=%02X H:X=%04X SP=%04X\n",PC,A,CC,HX,SP);
image[ SP + 1 ] = HX >> 8;
image[ SP + 2 ] = CC;
image[ SP + 3 ] = A;
image[ SP + 4 ] = HX & 0xFF;
image[ SP + 5 ] = PC >> 8;
image[ SP + 6 ] = PC & 0xFF;
writeMemory(SP + 1 , 6 , 0);
sendByte(0x28); // Monitor mode RUN command
return SP;
}
int lastMon=-1;
/*
mass erase - callMonitor(ERARRNG , ERARRNG_MASS_ERASE, 0, EADDR, 0);
program - callMonitor(PRGRNGE, 0 , 0, addr , addr+n-1);
read at verify - callMonitor(RDVRRNG, 0 , 1 , addr , addr+n-1);
page erase - callMonitor(ERARRNG, ERARRNG_PAGE_ERASE, 0, a, 0);
*/
int callMonitor_A(int mon, int ctrlbyt, int accu, int faddr, int laddr) {
int SP;
image[ CTRLBYT ] = ctrlbyt; // CTRLBYT BIT 6 = 1 = > mass erase
image[ CPUSPD ] = CPUSPEED; // CPUSPD = 16 MHz ext clock = > 4 MHz Fbus speed = > 8
image[ LADDR ] = laddr>>8;
image[ LADDR+1 ] = laddr&0xFF;
writeMemory(MONDATA, 4, 0);
if (WORKRAM>0xFF) {
flsprintf(stderr,"Work RAM must be on zero page\n");
abort();
}
if (lastMon!=mon) {
// construct small HC908 code fragment to call the monitor function and return results
int i = WORKRAM;
image[ i++ ] = 0xCD; // JSR mon ; calls the monitor routine
image[ i++ ] = mon>>8;
image[ i++ ] = mon&0xFF;
image[ i++ ] = 0x83; // SWI ; return to monitor
if (WORKRAM>=WORKTOP) { // leave some stack space for monitor routines
flsprintf(stderr,"Not enough WORKRAM on target\n");
abort();
}
writeMemory(WORKRAM , i-WORKRAM , 0);
lastMon=mon;
}
// now execute the fragment
runFrom(WORKRAM, accu, 0x00, faddr);
// SWI drops into MON, which will send a BREAK
{ char buf;
if (read(com, &buf, 1) != 1)
comErr("ERROR: waiting for MON, nothing was received\n");
if(buf != 0)
comErr("ERROR: unexpected swi answer read %x\n", buf);
}
SP = readSP();
readMemory(SP + 1 , 6 , 0);
if (verbose>2)
flsprintf(stdout, "SP=%02x SP+1..6: hi(X)=%02x CC=%02x A=%02x lo(X)=%02x hi(PC)=%02x lo(PC)=%02x\n",
SP,
image[SP+1], // hi(X)
image[SP+2], // CC
image[SP+3], // A
image[SP+4], // lo(X)
image[SP+5], // hi(PC)
image[SP+6]); // lo(PC)
return ((image[SP+2] & 0xff) << 8) | (image[SP+3] & 0xff); // return condition codes and accu
}
/*
int cca=callMonitor_B(RDVRRNG, 0 , 1 , addr , n);
callMonitor_B(PRGRNGE, 0 , 0, addr , n);
callMonitor_B(ERARRNG , 0, 0, 0xFFFF, 0);
MONDATA = RAM+8;
CTRLBYT = MONDATA+0;
CPUSPD = MONDATA+1;
LADDR = MONDATA+2;
DATABUF = MONDATA+4;
WORKRAM = DATABUF + PAGESIZE;
*/
int callMonitor_B(int mon, int ctrlbyt, int accu, int addr, int len) {
int SP;
//CTRLBYT = MONDATA
image[ MONDATA + 0 ] = CPUSPEED;
image[ MONDATA + 1 ] = len;
image[ MONDATA + 2 ] = addr>>8;
image[ MONDATA + 3 ] = addr&0xFF;
writeMemory(MONDATA, 4, 0);
if (WORKRAM>0xFF) {
flsprintf(stderr,"Work RAM must be on zero page\n");
abort();
}
if (lastMon!=mon) {
// construct small HC908 code fragment to call the monitor function and return results
int i = WORKRAM;
image[ i++ ] = 0x45; //LDHX MONDATA
image[ i++ ] = MONDATA>>8;
image[ i++ ] = MONDATA;
image[ i++ ] = 0xCD; // JSR mon ; calls the monitor routine
image[ i++ ] = mon>>8;
image[ i++ ] = mon&0xFF;
image[ i++ ] = 0x83; // SWI ; return to monitor
if (WORKRAM>=WORKTOP) { // leave some stack space for monitor routines
flsprintf(stderr,"Not enough WORKRAM on target\n");
abort();
}
writeMemory(WORKRAM , i-WORKRAM , 0);
lastMon=mon;
}
// now execute the fragment
runFrom(WORKRAM, accu, 0x00, addr);
// SWI drops into MON, which will send a BREAK
{ char buf;
if (read(com, &buf, 1) != 1)
comErr("ERROR: waiting for MON, nothing was received\n");
if(buf != 0)
comErr("ERROR: unexpected swi answer read %x\n", buf);
}
SP = readSP();
readMemory(SP + 1 , 6 , 0);
if (verbose>2)
flsprintf(stdout, "SP=%02x SP+1..6: hi(X)=%02x CC=%02x A=%02x lo(X)=%02x hi(PC)=%02x lo(PC)=%02x\n",
SP,
image[SP+1], // hi(X)
image[SP+2], // CC
image[SP+3], // A
image[SP+4], // lo(X)
image[SP+5], // hi(PC)
image[SP+6]); // lo(PC)
return ((image[SP+2] & 0xff) << 8) | (image[SP+3] & 0xff); // return condition codes and accu
}
int fastProg(int faddr,int n) {
static int n_addr;
static int last_n;
flsprintf(stdout, "-------------------------FP %04X, %04X\n",faddr,n);
if (WORKRAM>0xFF) {
flsprintf(stderr,"Work RAM must be on zero page\n");
abort();
}
if (lastMon!=-1) {
int SP = readSP();
image[ CTRLBYT ] = 0; // CTRLBYT =0
image[ CPUSPD ] = CPUSPEED; // CPUSPD = 16 MHz ext clock = > 4 MHz Fbus speed = > 8
// construct small HC908 code fragment to call the monitor function and return results
int i = WORKRAM;
image[ i++ ] = 0x9D; // NOP / reserve space
image[ i++ ] = 0x9D; // NOP / reserve space
image[ i++ ] = 0x35; // STHX WORKRAM (dir)
image[ i++ ] = WORKRAM;
image[ i++ ] = 0x45; // LDHX #DATABUF
image[ i++ ] = DATABUF>>8;
image[ i++ ] = DATABUF&0xFF;
image[ i++ ] = 0xCD; // JSR GETBYTE ; calls the monitor routine
image[ i++ ] = GETBYTE>>8;
image[ i++ ] = GETBYTE&0xFF;
// image[ i++ ] = 0xFE9C>>8; ; // 0xFE9C = GET WITH echo
// image[ i++ ] = 0xFE9C&0xFF;
image[ i++ ] = 0xF7; // STA ,X
image[ i++ ] = 0x5C; // INCX
image[ i++ ] = 0xA3; // cpx #DATABUF+n
n_addr=i;
image[ i++ ] = 0; // place holder
image[ i++ ] = 0x25; // BLO *-10
image[ i++ ] = (-9)&0xFF;
image[ i++ ] = 0x55; // LDHX WORKRAM (dir)
image[ i++ ] = WORKRAM;
image[ i++ ] = 0xCD; // JSR PRGRNGE ; calls the monitor routine
image[ i++ ] = PRGRNGE>>8;
image[ i++ ] = PRGRNGE&0xFF;
image[ i++ ] = 0x45; // LDHX #SP+1 ; restore stack pointer
image[ i++ ] = (SP+1) >> 8;
image[ i++ ] = (SP+1) & 0xFF;
image[ i++ ] = 0x94; // TXS
image[ i++ ] = 0xCC; // JMP back to MON (this is the only way)
image[ i++ ] = MONRTN>>8;
image[ i++ ] = MONRTN&0xFF;
if (WORKRAM>=WORKTOP) { // leave some stack space for monitor routines
flsprintf(stderr,"Not enough WORKRAM on target\n");
abort();
}
writeMemory(WORKRAM , i-WORKRAM , 0);
dumpMemorySrec(WORKRAM , i-WORKRAM);
lastMon=-1;
}
if (last_n!=n) {
image[ n_addr ] = DATABUF+n;
writeMemory(n_addr,1,0);
last_n=n;
}
int laddr = faddr+n-1;
image[ LADDR ] = laddr>>8;
image[ LADDR+1 ] = laddr&0xFF;
writeMemory(LADDR, 2, 0);
// now execute the fragment
runFrom(WORKRAM+2, 0x00, 0x00, faddr); // NOTE! to override flash security and erase FLBPR at be used as the erase address for mass erase
flsprintf(stdout, "-------------------------EXE\n");
int i;
for (i=0; i<n; ++i)
putByte(image[faddr+i]);
for (i=0; i<n; ++i)
getByte();
readSP();
return 0;
}
/*
PAGESIZE = 64;
MONDATA = RAM+8;
CTRLBYT = MONDATA+0;
CPUSPD = MONDATA+1;
LADDR = MONDATA+2;
DATABUF = MONDATA+4;
WORKRAM = DATABUF + PAGESIZE;
WORKTOP = 0xF0; // this leaves 16 bytes for stack, the deepest ROM routines use 11 so there some for myself too
*/
int fastProg2(int faddr,int progn) {
if (WORKRAM>0xFF) {
flsprintf(stderr,"Work RAM must be on zero page\n");
abort();
}
int SP = readSP();
image[ CTRLBYT ] = 0; // CTRLBYT =0
image[ CPUSPD ] = CPUSPEED; // CPUSPD= 16 MHz ext => 4 MHz Fbus = > 8
// construct small HC908 code fragment to call the monitor function
int i = WORKRAM;
int j;
int FADDR=i;
image[ i++ ] = faddr>>8; // FADDR initial contents
image[ i++ ] = faddr&0xFF;
int PROGN=i;
image[ i++ ] = progn>>8; // PROGN initial contents
image[ i++ ] = progn&0xFF;
int start=i;
flsprintf(stdout,"helper start %04x\n",i);
if (lastMon!=-1) {
image[ i++ ] = 0x55 ; // LDHX PROGN get bytes left to program
image[ i++ ] = PROGN;
image[ i++ ] = 0x27 ; // BEQ DONE branch if all done
int patchDone=i;
image[ i++ ] = 0 ;
image[ i++ ] = 0x65 ; // CPHX #PAGESIZE only page full at a time
image[ i++ ] = 0 ;
image[ i++ ] = PAGESIZE;
image[ i++ ] = 0x25 ; // BLO DOIT
image[ i++ ] = 2 ;
image[ i++ ] = 0xAE ; // LDX #PAGESIZE
image[ i++ ] = PAGESIZE;
image[ i++ ] = 0x9F ; // TXA
image[ i++ ] = 0x87 ; // PSHA
image[ i++ ] = 0xB6 ; // LDA PROGN+1
image[ i++ ] = PROGN+1;
image[ i++ ] = 0x9E; // SUB 1,SP
image[ i++ ] = 0xE0;
image[ i++ ] = 1;
image[ i++ ] = 0xB7 ; // STA PROGN+1
image[ i++ ] = PROGN+1;
image[ i++ ] = 0xB6 ; // LDA PROGN
image[ i++ ] = PROGN;
image[ i++ ] = 0xA2 ; // SBC #0
image[ i++ ] = 0 ;
image[ i++ ] = 0xB7 ; // STA PROGN
image[ i++ ] = PROGN;
image[ i++ ] = 0x9F ; // TXA
image[ i++ ] = 0x4A ; // DECA
image[ i++ ] = 0xBB ; // ADD FADDR+1
image[ i++ ] = FADDR+1;
image[ i++ ] = 0xB7 ; // STA LADDR+1
image[ i++ ] = LADDR+1;
image[ i++ ] = 0xB6 ; // LDA FADDR
image[ i++ ] = FADDR;
image[ i++ ] = 0xA9 ; // ADC #0
image[ i++ ] = 0 ;
image[ i++ ] = 0xB7 ; // STA LADDR
image[ i++ ] = LADDR;
image[ i++ ] = 0x45; // LDHX #DATABUF
image[ i++ ] = DATABUF>>8;
image[ i++ ] = DATABUF&0xFF;
image[ i++ ] = 0x86 ;// PULA
int getMore=i;
image[ i++ ] = 0x87 ; // PSHA
image[ i++ ] = 0xCD; // JSR GETBYTE
image[ i++ ] = GETBYTE>>8;
image[ i++ ] = GETBYTE&0xFF;
image[ i++ ] = 0xF7; // STA ,X
image[ i++ ] = 0x5C; // INCX
image[ i++ ] = 0x86 ; // PULA
image[ i++ ] = 0x4A ; // DECA
image[ i++ ] = 0x26 ; // BNE GETMORE
j=i;
image[ i++ ] = (getMore-(j+1))&0xFF ;
image[ i++ ] = 0x55 ; // LDHX FADDR
image[ i++ ] = FADDR;
image[ i++ ] = 0xCD; // JSR PRGRNGE
image[ i++ ] = PRGRNGE>>8;
image[ i++ ] = PRGRNGE&0xFF;
image[ i++ ] = 0x8B; // PSHH Annoyingly JB8 RDVRNG leaves H:X off by one
image[ i++ ] = 0x89; // PSHX compared to GZ16 necessiating this pus/pul sequence
image[ i++ ] = 0x55 ;// LDHX FADDR
image[ i++ ] = FADDR;
image[ i++ ] = 0xA6 ; // LDAA #1
image[ i++ ] = 1 ;
image[ i++ ] = 0xCD; // JSR RDVRRNG
image[ i++ ] = RDVRRNG>>8;
image[ i++ ] = RDVRRNG&0xFF;
image[ i++ ] = 0x88; // PULX
image[ i++ ] = 0x8A; // PULH
image[ i++ ] = 0x35 ; // STHX FADDR
image[ i++ ] = FADDR;
image[ i++ ] = 0xCD; // JSR PUTBYTE
image[ i++ ] = PUTBYTE>>8;
image[ i++ ] = PUTBYTE&0xFF;
image[ i++ ] = 0x20 ; // BRA start
j=i;
image[ i++ ] = (start-(j+1))&0xFF;
image[patchDone] = (i-(patchDone+1))&0xFF;
image[ i++ ] = 0x45; // LDHX #SP+1 ; restore stack pointer
image[ i++ ] = (SP+1) >> 8;
image[ i++ ] = (SP+1) & 0xFF;
image[ i++ ] = 0x94; // TXS
image[ i++ ] = 0xCC; // JMP back to MON (this is the only way)
image[ i++ ] = MONRTN>>8;
image[ i++ ] = MONRTN&0xFF;
flsprintf(stdout,"helper end %04x\n",i);
/*
if (i>=WORKTOP) { // leave some stack space for monitor routines
flsprintf(stderr,"Not enough WORKRAM on target\n");
abort();
}
*/
writeMemory(WORKRAM , i-WORKRAM , 0);
lastMon=-1;
}
else
writeMemory(WORKRAM , 4 , 0);
runFrom(start, 0x00, 0x00, 0);
while (progn) {
int n = progn < PAGESIZE ? progn : PAGESIZE;
int sum=0;
for (i=0; i<n; ++i) {
putByte(image[faddr+i]);
}
for (i=0; i<n; ++i) {
int b=getByte();
//flsprintf(stderr,"%d %02X\n",i,b);
sum = (sum+b)&0xFF;
if (b != image[faddr+i])
flsprintf(stderr,"Program data transfer error, at %04X sent %02X got %02X\n",faddr+i,image[faddr+i],b);
}
int back=getByte();
//flsprintf(stderr,"%02X\n",back);
if (back != sum) {
flsprintf(stderr,"Program checksum failure, at %04X size %04X checksum calculated %02X received %02X\n",faddr,n,sum,back);
abort();
}
progn -= n;
faddr += n;
if (verbose)
flsprintf(stdout,".");
}
return 0;
}
void massErase() {
// NOTE! to override flash security and erase FLBPR must be used as the erase address for mass erase
if (verbose)
flsprintf(stdout,"Mass erase\n");
if (MONTYPE == 0)
callMonitor_A(ERARRNG , ERARRNG_MASS_ERASE, 0, EADDR, 0);
if (MONTYPE == 1)
callMonitor_B(ERARRNG , 0, 0, 0xFFFF, 0);
}
void flashProgram(int addr,int size,int verify) {
if (addr < FLASH) {
flsprintf(stdout,"Programming address %04X below flash start address %04X\n",addr,FLASH);
abort();
}
if (useFastProg) {
if (verbose)
flsprintf(stdout,"Program %04X - %04X ",addr,addr+size-1);
fastProg(addr,size);
if (verbose)
flsprintf(stdout,"\n");
}
else {
while (size>0) {
int n=size <= PAGESIZE ? size : PAGESIZE;
if (verbose)
flsprintf(stdout,"Program %04X - %04X ",addr,addr+n-1);
memcpy(&image[ DATABUF ] , &image[addr] , n);
writeMemory(DATABUF , n , verbose);
if (MONTYPE == 0)
callMonitor_A(PRGRNGE, 0 , 0, addr , addr+n-1);
if (MONTYPE == 1)
callMonitor_B(PRGRNGE, 0 , 0, addr , n);
if (verify) {
int cca;
int sum=0;
int i;
if (MONTYPE == 0)
cca=callMonitor_A(RDVRRNG, 0 , 1 , addr , addr+n-1);
if (MONTYPE == 1)
cca=callMonitor_B(RDVRRNG, 0 , 1 , addr , n);
for (i=0; i<n; ++i)
sum = (sum + image[addr+i]) & 0xFF;
int back= cca & 0xFF; // get Accu from target
if (sum != back) {
flsprintf(stderr,"Program checksum failure, at %04X size %04X checksum calculated %02X received %02X\n",addr,n,sum,back);
abort();
}
if (!(cca & 0x0100)) { // check Carry bit from target
flsprintf(stderr,"Verify failed\n");
abort();
}
if (verbose)
flsprintf(stdout,"OK");
}
if (verbose)
flsprintf(stdout,"\n");
addr += n;
size -= n;
}
}
}
int readSrec(int verbose,FILE* sf,unsigned char* image, int size, int base, int* ranges, int rn) {
if (verbose)
flsprintf(stdout,"Reading S-records\n");
memset(image,0xff,size);
char line[2+2+255*2+2+1]; // Sx + count + 255 bytes for data address & checksum + CR/LF +nul (in windows)
int amax=0;
int rc=0;
while (fgets(line,sizeof(line),sf)!=NULL) {
int o=0;
if (line[0]=='S') {
unsigned int n,a;
sscanf(line+2,"%2x",&n);
n--;
if (line[1]=='1') {
sscanf(line+4,"%4x",&a);
n=n-2;
o=8;
}
if (line[1]=='2') {
sscanf(line+4,"%6x",&a);
n=n-4;
o=10;
}
if (line[1]=='3') {
sscanf(line+4,"%8x",&a);
n=n-6;
o=12;
}
if (o!=0) {
int i,j;
if (ranges) {
for (i=0; i<rc; i+=2) {
int rlo=ranges[i];
int rhi=rlo+ranges[i+1];
if (!((a+n<=rlo) || (rhi<=a))) {
flsprintf(stderr,"Overlapping S-record ranges %04X,%04X and %0x4 %04X\n",rlo,rhi-rlo,a,n);
abort();
}
}
if (rc + 2 >= rn)
return -1;
ranges[rc]=a;
ranges[rc+1]=n;
rc += 2;
int cf=0;
do compact: {
for (i=0; i<rc; i+=2) {
for (j=i+2; j<rc; j+=2) {
cf=1;
if (ranges[i]+ranges[i+1]==ranges[j])
ranges[i+1] += ranges[j+1];
else if (ranges[i]==ranges[j]+ranges[j+1])
ranges[i]-=ranges[j+1];
else
cf=0;
if (cf) {
for (i=j+2; i<rc; i++)
ranges[i]=ranges[i+2];
rc-=2;
cf=0;
goto compact;
}
}
}
} while (cf);
}
for (i=0; i<n; ++i) {
unsigned int d;
sscanf(line+o+i*2,"%2x",&d);
if ( (a >= base) && (a < base+size)) {
image[ a - base ] = d;
a++;
amax = a>amax ? a : amax;
}
}
}
}
if (verbose>1)
flsprintf(stdout,">>> %s",line);
if (verbose && o==0)
flsprintf(stdout,"Line ignored: %s\n",line);
}
if (verbose) {
if (ranges) {
int i;
for (i=0; i<rc; i+=2)
flsprintf(stdout,"S-record data address %06X size %06X\n",ranges[i],ranges[i+1]);
}
flsprintf(stdout,"\n");
}
return rc;
}
void printHelp() {
flsprintf(stdout,"bl08 burns MC68HC908 Flash memory from S-record file(s) using Monitor mode\n");
flsprintf(stdout,"Usage: \n");
flsprintf(stdout," bl08 [-aBbcdefhiklmnpqrstuvwxy] [filename...]\n");
flsprintf(stdout," -a address Set dump memory address (needs -s option too)\n");
flsprintf(stdout," -B baudrate Set baud rate for target communication\n");
flsprintf(stdout," -b speed Set baud rate using speed_t value as defined in termios.h.\n");
flsprintf(stdout," The value is passed directly to cfsetXspeed() and can be\n");
flsprintf(stdout," used to set non-Posix baud rates. On MacOSX the value is\n");
flsprintf(stdout," equivalent to actual baud rate, whereas on Linux it is\n");
flsprintf(stdout," very different. If in doubt, use the -B option instead.\n");
flsprintf(stdout," -c device Set serial com device used to communicate with target\n");
flsprintf(stdout," (default '/dev/ttyS0')\n");
flsprintf(stdout," -d dumpformat Set dump format, supported formats are: 'srec'\n");
flsprintf(stdout," -e Erase target using mass erase mode, clearing security bytes\n");
flsprintf(stdout," -f Use fast programming method\n");
flsprintf(stdout," -g address Go execute target code from address or use '-g reset'\n");
flsprintf(stdout," -h Print out this help text\n");
flsprintf(stdout," -i Read input (S-records) from standard input\n");
flsprintf(stdout," -k Kill previous instance of bl08\n");
flsprintf(stdout," -l verbosity Set verbosity level, valid values are 0-4, default 1\n");
flsprintf(stdout," -m Terminal emulator mode\n");
flsprintf(stdout," -n Print bl08 version number\n");
flsprintf(stdout," -o param=value Override target parameter value\n");
flsprintf(stdout," param = ROMBASE,FLASH,PUTBYTE,GETBYTE,RDVRRNG,MONRTN\n");
flsprintf(stdout," ERARRNG,PRGRNGE,FLBPR,MONDATA,PAGESIZE,EADDR,RAM\n");
flsprintf(stdout," -p Use page erase when programming flash\n");
flsprintf(stdout," -q Run quietly, same as -l 0\n");
flsprintf(stdout," -s size Set dump memory size\n");
flsprintf(stdout," -r pulse Pulse DTR for pulse milliseconds\n");
flsprintf(stdout," -R pulse Pulse DTR for pulse milliseconds with opposite polarity\n");
flsprintf(stdout," r is OK for transitor directly on DTR pin\n");
flsprintf(stdout," R is OK for transitor on MAX232 (inverted) pin, as usual\n");
flsprintf(stdout," on classic RS232 MON08 boards, \n");
flsprintf(stdout," -t cputype Set CPU type, valid values are: gz16, jb8, qy2, qy4, jk1,\n");
flsprintf(stdout," jk3, jk8, jl16, gr4, gr8, kx2, kx8\n");
flsprintf(stdout," -u Upload only (do not program flash)\n");
flsprintf(stdout," -v Verify when programming \n");
flsprintf(stdout," -w pin=value Set serial port pin state\n");
flsprintf(stdout," pin=LE,DTR,RTS,ST,SR,CTS,CAR,CD,RNG,RI,DSR\n");
flsprintf(stdout," val=1/0, 1=negative pin voltage\n");
flsprintf(stdout," -x cpuspeed Set CPU speed, typically set for Fbus (in MHz) x 4 \n");
flsprintf(stdout," -y string Security code, as a string of hex bytes\n");
flsprintf(stdout," -z Do not program, do no upload, just read in the S-rec file \n");
flsprintf(stdout," addresses and sizes in decimal, for hex prefix with '0x'\n");
// Example
exit(0);
}
void termEmu()
{
int STDIN=0;
int STDOUT=1;
// get rid of stuff that has been echoed to us
tcflush(com,TCIFLUSH ); // .. then get rid of the echoes and what ever...
struct termios newtio,oldtio;
tcgetattr(STDIN,&oldtio); // we do not want to change the console setting forever, so keep the old
tcgetattr(STDIN,&newtio); // configure the console to return as soon as it a key is pressed
newtio.c_lflag = 0;
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 1;
tcsetattr(STDIN,TCSANOW,&newtio);
flsprintf(stdout,"\nTerminal mode, press CTRL-C to exit.\n");
fd_set readfs;
int maxfd;
int res;
char buf[2];
maxfd = com+1;
while (1) {
// wait for something from console or serial port
FD_SET(STDIN, &readfs);
FD_SET(com, &readfs);
struct timeval tout;
tout.tv_usec = 10;
tout.tv_sec = 0;
select(maxfd, &readfs, NULL, NULL, &tout);
// copy console stuff to the serial port
if (FD_ISSET(STDIN,&readfs)) {
res=read(STDIN,buf,1);
if (buf[0]==3) break; // CTRL-C terminates terminal mode
write(com,buf,res);
}
// copy serial port stuff to console
if (FD_ISSET(com,&readfs)){
res=read(com,buf,1);
write(STDOUT,buf,res);
fflush(stdout);
}
}
tcsetattr(0,TCSANOW,&oldtio); // restore console settings
/// close(con);
}
void setCPUtype(char* cpu) {
if (strcmp("gz16",cpu)==0 || strcmp("mc68hc908gz16",cpu)==0) {
// These settings depend on the CPU version
CPUSPEED=8;
FLASH=0xC000;
PUTBYTE=0xFEAF;
GETBYTE=0x1C00;
RDVRRNG=0x1C03;
ERARRNG=0x1C06;
PRGRNGE=0x1C09;
MONRTN=0xFE20;
FLBPR=0xFF7E;
EADDR=FLBPR;
RAM = 0x40;
MONTYPE = 0;
}
else if (strcmp("jb8",cpu)==0 || strcmp("mc68hc908jb8",cpu)==0) {
// These settings depend on the CPU version
CPUSPEED=12; // typically run at 6 MHz, bus freq 3 Mhz
FLASH=0xDC00;
PUTBYTE=0xFED6;
GETBYTE=0xFC00;
RDVRRNG=0xFC03;
ERARRNG=0xFC06;
PRGRNGE=0xFC09;
MONRTN=0xFE55;
FLBPR=0xFE09;
EADDR=FLASH;
RAM = 0x40;
MONTYPE = 0;
}
else if (strcmp("qy2",cpu)==0 || strcmp("mc68hc908qy",cpu)==0) {
// These settings depend on the CPU version
FLASH=0xF800;
PUTBYTE=0xFEA1;
GETBYTE=0x2800;
RDVRRNG=0x2803;
ERARRNG=0x2806;
PRGRNGE=0x2809;
MONRTN=0xFE26;
FLBPR=0xFFBE;
EADDR=FLASH;
RAM = 0x80;
MONTYPE = 0;
}
else if (strcmp("qy4",cpu)==0 || strcmp("mc68hc908q4",cpu)==0) {
// These settings depend on the CPU version
FLASH=0xEE00;
PUTBYTE=0xFEA1;
GETBYTE=0x2800;
RDVRRNG=0x2803;
ERARRNG=0x2806;
PRGRNGE=0x2809;
MONRTN=0xFE26;
FLBPR=0xFFBE;
EADDR=FLASH;
RAM = 0x80;
MONTYPE = 0;
}
else if (strcmp("jk8",cpu)==0 || strcmp("mc68hc908jk8",cpu)==0) {
// These settings depend on the CPU version
FLASH=0xDC00;
PUTBYTE=0xFF00;
GETBYTE=0xFC00;
RDVRRNG=0xFC03;
ERARRNG=0xFCBE;
PRGRNGE=0xFC06;
MONRTN=0xFE6C;
FLBPR=0xFFCF;
EADDR=FLASH;
RAM = 0x60;
MONTYPE = 1;
}
else if (strcmp("jk3",cpu)==0 || strcmp("mc68hc908jk3",cpu)==0) {
// These settings depend on the CPU version
FLASH=0xEC00;
PUTBYTE=0x0000;
GETBYTE=0xFC00;
RDVRRNG=0xFC03;
ERARRNG=0xFC06;
PRGRNGE=0xFC09;
MONRTN=0x0000;
FLBPR=0xFE09;
EADDR=FLASH;
RAM = 0x80;
MONTYPE = 0;
}
else if (strcmp("jk1",cpu)==0 || strcmp("mc68hc908jk1",cpu)==0) {
// These settings depend on the CPU version
FLASH=0xF600;
PUTBYTE=0x0000;
GETBYTE=0xFC00;
RDVRRNG=0xFC03;
ERARRNG=0xFC06;
PRGRNGE=0xFC09;
MONRTN=0x0000;
FLBPR=0xFE09;
EADDR=FLASH;
RAM = 0x80;
MONTYPE = 0;
}
else if (strcmp("jl16",cpu)==0 || strcmp("mc68hc908jl16",cpu)==0) {
// These settings depend on the CPU version
FLASH=0xBC00;
PUTBYTE=0x0000;
GETBYTE=0xFF00;
RDVRRNG=0xFF30;
ERARRNG=0xFCBE;
PRGRNGE=0xFC06;
MONRTN=0x0000;
FLBPR=0xFFCF;
EADDR=FLASH;
RAM = 0x60;
MONTYPE = 1;
}
else if (strcmp("gr8",cpu)==0 || strcmp("mc68hc908gr8",cpu)==0) {
// These settings depend on the CPU version
FLASH=0xE000;
PUTBYTE=0x0000;
GETBYTE=0x1C99;
RDVRRNG=0x1CAD;
ERARRNG=0x1DA0;
PRGRNGE=0x1CEC;
MONRTN=0x0000;
FLBPR=0xFF7E;
EADDR=FLASH;
RAM = 0x40;
MONTYPE = 0;
}
else if (strcmp("gr4",cpu)==0 || strcmp("mc68hc908gr4",cpu)==0) {
// These settings depend on the CPU version
FLASH=0xEE00;
PUTBYTE=0x0000;
GETBYTE=0x1C99;
RDVRRNG=0x1CAD;
ERARRNG=0x1DA0;
PRGRNGE=0x1CEC;
MONRTN=0x0000;
FLBPR=0xFF7E;
EADDR=FLASH;
RAM = 0x40;
MONTYPE = 0;
}
else if (strcmp("kx2",cpu)==0 || strcmp("mc68hc908kx2",cpu)==0) {
// These settings depend on the CPU version
FLASH=0xF600;
PUTBYTE=0x0000;
GETBYTE=0x1000;
RDVRRNG=0x1003;
ERARRNG=0x1006;
PRGRNGE=0x1009;
MONRTN=0x0000;
FLBPR=0xFF7E;
EADDR=FLASH;
RAM = 0x40;
MONTYPE = 0;
}
else if (strcmp("kx8",cpu)==0 || strcmp("mc68hc908kx8",cpu)==0) {
// These settings depend on the CPU version
FLASH=0xE000;
PUTBYTE=0x0000;
GETBYTE=0x1000;
RDVRRNG=0x1003;
ERARRNG=0x1006;
PRGRNGE=0x1009;
MONRTN=0x0000;
FLBPR=0xFF7E;
EADDR=FLASH;
RAM = 0x40;
MONTYPE = 0;
}
else {
flsprintf(stderr,"Unsupported CPU type '%s'\n",cpu);
flsprintf(stderr,"The supported CPU types are:\n");
flsprintf(stderr,"\tmc68hc908gz16 (gz16)\n");
flsprintf(stderr,"\tmc68hc908jb8 (jb8)\n");
flsprintf(stderr,"\tmc68hlc908qy2 (qy2)\n");
abort();
}
// These are independent of CPU type
PAGESIZE = 64;
MONDATA = RAM+8;
CTRLBYT = MONDATA+0;
CPUSPD = MONDATA+1;
LADDR = MONDATA+2;
DATABUF = MONDATA+4;
WORKRAM = DATABUF + PAGESIZE;
WORKTOP = 0xF0; // this leaves 16 bytes for stack, the deepest ROM routines use 11 so there some for myself too
if (DATABUF+PAGESIZE>0xFF) {
flsprintf(stderr,"bl08 limitation, DATABUF+PAGESIZE>0xFF, DATABUF=%04X, PAGESIZE=%04X\n",DATABUF,PAGESIZE);
abort();
}
}
int getIntArg(char* arg) {
if (strlen(arg)>=2 && memcmp(arg,"0x",2)==0) {
unsigned int u;
sscanf(arg+2,"%X",&u);
return u;
}
else {
int d;
sscanf(arg,"%d",&d);
return d;
}
}
void parseOverride(char* str) {
char* vp=strstr(str,"=");
if (!vp) {
flsprintf(stderr,"Bad override syntax, no '=' found\n");
abort();
}
*vp=0;
vp++;
int val=getIntArg(vp);
if (strcmp("ROMBASE",str)==0) {
GETBYTE=val+0;
RDVRRNG=val+3;
ERARRNG=val+6;
PRGRNGE=val+9;
}
else if (strcmp("FLASH",str)==0) FLASH=val;
else if (strcmp("PUTBYTE",str)==0) PUTBYTE=val;
else if (strcmp("GETBYTE",str)==0) GETBYTE=val;
else if (strcmp("RDVRRNG",str)==0) RDVRRNG=val;
else if (strcmp("ERARRNG",str)==0) ERARRNG=val;
else if (strcmp("PRGRNGE",str)==0) PRGRNGE=val;
else if (strcmp("FLBPR",str)==0) FLBPR=val;
else if (strcmp("RAM",str)==0) RAM=val;
else if (strcmp("MONDATA",str)==0) MONDATA=val;
else if (strcmp("PAGESIZE",str)==0) PAGESIZE=val;
else if (strcmp("MONRTN",str)==0) MONRTN=val;
else if (strcmp("EADDR",str)==0) EADDR=val;
else {
flsprintf(stderr,"Attempt to override unrecognized variable %s\n",str);
abort();
}
}
void parseIOControl(char* str) {
char* vp=strstr(str,"=");
if (!vp) {
flsprintf(stderr,"Bad pin control syntax, no '=' found\n");
abort();
}
*vp=0;
vp++;
int val=getIntArg(vp);
if (val!=0 && val!=1) {
flsprintf(stderr,"Bad pin control value %d (not 1/0)\n",val);
abort();
}
int i;
for (i=0; i<sizeof(portPins)/sizeof(portPins[0]); i++) {
if (strcmp(portPins[i].str,str)==0) {
forcePins[i]=val+1;
return;
}
}
flsprintf(stderr,"Attempt to set unrecognized pin %s\n",str);
abort();
}
void parseBaudrate(char* str) {
int i;
for (i=0; i<sizeof(baudrates)/sizeof(baudrates[0]); ++i) {
if (strcmp(baudrates[i].str,str)==0) {
baudRate=baudrates[i].val;
return;
}
}
flsprintf(stderr,"Attempt to set unrecognized baud rate %s\n",str);
abort();
}
void parseTermSpeed(char* str) {
if (sscanf(str,"%d",&baudRate)!=1) {
flsprintf(stderr,"Failed to set terminal speed %s\n",str);
abort();
}
}
void setSecurityCode(char* str) {
int i;
int consumed;
for (i=0; i<8 && *str; ++i) {
if (sscanf(str," %2hhx%n",&scode[i],&consumed)!=1) {
flsprintf(stderr,"Bad security code: %s\n",str);
abort();
}
str += consumed;
while (*str==' ') str++; /* tolerate spaces */
if (*str==':') str++; /* and one colon */
}
if (i<8) {
flsprintf(stderr,"Found only %d bytes in security code\n",i);
abort();
}
}
void parseArgs(int argc, char *argv[]) {
int c;
while ((c = getopt (argc, argv, "a:B:b:c:d:efg:hikl:mno:pqr:R:s:t:uvw:x:y:z")) != -1) {
switch (c) {
case 'a' :
dumpStart=getIntArg(optarg);
break;
case 'B' :
parseBaudrate(optarg);
break;
case 'b' :
parseTermSpeed(optarg);
break;
case 'c' :
COM=optarg;
break;
case 'd' :
dumpFormat=optarg;
break;
case 'e' :
eraseFlash = 1;
break;
case 'f' :
useFastProg = 1;
break;
case 'g' :
executeCode=optarg;
break;
case 'h' :
printHelp();
break;
case 'i' :
useStdin = 1;
break;
case 'k' :
killPrevious = 1;
break;
case 'l' :
sscanf(optarg,"%d",&verbose);
break;
case 'm' :
terminalMode=1;
break;
case 'n' :
flsprintf(stdout,"%s\n",version);
break;
case 'o' :
parseOverride(optarg);
break;
case 'p' :
pageErase=1;
break;
case 'q' :
verbose=0;
break;
case 'r' :
resetPolarity = 0;
resetPulse=getIntArg(optarg);
break;
case 'R' :
resetPolarity = 1;
resetPulse=getIntArg(optarg);
break;
case 's' :
dumpSize=getIntArg(optarg);
break;
case 't' :
setCPUtype(optarg);
break;
case 'u' :
uploadOnly=1;
break;
case 'v' :
verify=1;
break;
case 'w' :
parseIOControl(optarg);
break;
case 'x' :
sscanf(optarg,"%d",&CPUSPEED);
break;
case 'y' :
setSecurityCode(optarg);
break;
case 'z' :
loadOnly=1;
break;
case '?' :
if (isprint (optopt))
flsprintf(stderr,"Unknown option `-%c'.\n", optopt);
else
flsprintf(stderr,"Unknown option character `\\x%x'.\n",optopt);
default:
flsprintf(stderr,"Bug, unhandled option '%c'\n",c);
abort ();
}
}
if (argc<=1)
printHelp();
}
void generateReset() {
struct timespec tspec;
int s;
if (verbose)
flsprintf(stderr,"Applying %dms reset.\n",resetPulse);
ioctlErrCheck(ioctl(com, TIOCMGET, &s));
if (resetPolarity == 0)
s |= TIOCM_DTR;
else
s &= ~TIOCM_DTR;
ioctlErrCheck(ioctl(com, TIOCMSET, &s));
tspec.tv_sec=resetPulse/1000;
tspec.tv_nsec=(resetPulse%1000)*1000000;
nanosleep(&tspec,0);
if (resetPolarity == 0)
s &= ~TIOCM_DTR;
else
s |= TIOCM_DTR;
ioctlErrCheck(ioctl(com, TIOCMSET, &s));
tspec.tv_sec=0;
tspec.tv_nsec=1000000; /* wait at least 1 ms */
nanosleep(&tspec,0);
}
void deletePidFile() {
int stat=remove(PIDFILENAME);
if (stat)
flsprintf(stderr,"remove returned %d\n",stat);
}
void killPreviousInstance() {
atexit(deletePidFile);
int pid;
FILE* pidf=fopen(PIDFILENAME,"r");
if (pidf) {
fscanf(pidf,"%d",&pid);
int stat=kill(pid,SIGKILL);
if (stat!=0)
flsprintf(stderr,"kill returned %d\n",stat);
fclose(pidf);
waitpid(pid,&stat,0);
if (WIFEXITED(stat)==0)
flsprintf(stderr,"waitpid returned %d\n",WIFEXITED(stat));
}
pidf=fopen(PIDFILENAME,"w");
fprintf(pidf,"%d\n",getpid());
fclose(pidf);
}
int main(int argc, char *argv[]) {
// default values
setCPUtype("gz16");
parseArgs(argc,argv);
if (killPrevious)
killPreviousInstance();
if (verbose)
flsprintf(stdout,"bl08 - MC68HC908 Bootloader - version %s\n",version);
memset(image,0xFF,sizeof(image));
int maxrc=256;
int ranges[maxrc];
int rc=0;
if (useStdin)
rc += readSrec(verbose , stdin , image , sizeof(image) , 0x0000 , ranges+rc , maxrc - rc);
int i;
for (i=optind; i<argc; i++) {
char* filename=argv[i];
FILE* sf = fopen(filename, "r");
if (sf == NULL) {
flsprintf(stderr,"Failed to open '%s'\n", filename);
abort();
}
int rn=readSrec(verbose , sf , image , sizeof(image) , 0x0000 , ranges+rc , maxrc - rc);
if (rn<0) {
flsprintf(stderr,"Too many discontinuous data ranges in S-record file '%s'\n",filename);
abort();
}
rc += rn;
fclose(sf);
}
if (!loadOnly) {
initSerialPort();
if (resetPulse)
generateReset();
if (eraseFlash) {
connectTarget();
massErase();
}
if (rc>0) {
connectTarget();
if (pageErase) {
for (i=0; i<rc; ) {
int addr=ranges[ i++ ];
int size=ranges[ i++ ];
int a = addr / PAGESIZE * PAGESIZE;
while (a<addr+size) {
if (verbose)
flsprintf(stdout,"Erase %04X - %04X\n",a,PAGESIZE);
if (MONTYPE == 0)
callMonitor_A(ERARRNG, ERARRNG_PAGE_ERASE, 0, a, 0);
a += PAGESIZE;
}
}
}
else
massErase();
int i;
for (i=0; i<rc;) {
int addr=ranges[ i++ ];
int size=ranges[ i++ ];
if (uploadOnly) {
if (verbose)
flsprintf(stdout,"Uploading memory contents\n");
writeMemory(addr,size,verbose);
if (verbose)
flsprintf(stdout,"\n");
}
else
flashProgram(addr , size , verify);
if (verbose>1) {
flsprintf(stdout,"Reading back memory/flash content\n");
readMemory(addr , size, verbose);
flsprintf(stdout,"\n");
dumpMemory(addr , size);
}
}
}
if (executeCode) {
connectTarget();
int addr;
if (strcmp("reset",executeCode)==0) {
readMemory(0xFFFE,2,0);
addr=((image[0xFFFE]&0xFF)<<8) | (image[0xFFFF]&0xFF);
/* Unlocked flash reads as 0xAD everywhere */
if (addr == 0xADAD) {
flsprintf(stdout,"Could not read reset vector, flash security locked?\n");
abort();
}
}
else
addr=getIntArg(executeCode);
if (verbose)
flsprintf(stdout,"Execute code from %04X\n",addr);
runFrom(addr,0,0,0);
}
if (terminalMode)
termEmu();
}
if (dumpSize>0) {
if (!loadOnly) {
connectTarget();
if (verbose)
flsprintf(stdout,"Reading memory\n");
readMemory(dumpStart,dumpSize, verbose);
}
if (verbose)
flsprintf(stdout,"\n");
if (dumpFormat) {
if (strcmp("srec",dumpFormat)==0)
dumpMemorySrec(dumpStart,dumpSize);
else if (strcmp("hex",dumpFormat)==0)
dumpMemory(dumpStart,dumpSize);
else
flsprintf(stderr,"Unknown dump format '%s'\n",dumpFormat);
}
}
return 0;
}