/*
 * Adapted from....
 *
 * Remote debugging interface for 683xx via Background Debug Mode
 * needs a driver, which controls the BDM interface.
 * written by G.Magin
 * (C) 1995 Technische Universitaet Muenchen, Lehrstuhl fuer Prozessrechner
 * 
 * D.Jeff Dionne
 * (C) 1995, Dionne & Associates
 * 
 * V0.2 Enhancements:
 * Added command line arguments
 * Rewritten flash programming functions for more flexability
 *
 * Andrew Dennison <adennison@swin.edu.au>
 * December 1995
 *
 * Modified by Pavel Pisa  pisa@cmp.felk.cvut.cz 2000

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, 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.

 */

/*
 * NOTE:
 * This file is assumed to be runnable only on Linux/i386 because of
 * HW-restrictions: the driver is currently only available on i386-Linux 
 * So byte-swapping and alignment is handled directly, violating the 
 * GNU-coding standards. However, the "dirty spots" are restricted in this 
 * file.
 *
 * If anybody wants to port to e.g. Sparc, byte-sex has to be handled in
 * a more general way.
 */

#include <unistd.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <getopt.h>

#include <bfd.h>
#include "bdm.h"
#include "bdmlib.h"
#include "bdmflash.h"

/*
 * Global Types
 **************
 */
typedef caddr_t CORE_ADDR;

#define	END_MACRO	0
#define	BEGIN_MACRO	1
#define	NO_SUFFIX_MACRO	2
#define DEBUG_MESSAGES

#define swap_l(x) (x>>24) | ((x>>8)&0xff00) | ((x<<8)&0xff0000) | ((x&0xff)<<24)

#define AUTO_ADR_CSBOOT ((caddr_t)-100)
#define AUTO_ADR_CSX    ((caddr_t)-100+1)

typedef struct str_list_t{
  char **items;
  int count;
  int alloccnt;
}str_list_t;			/* to store list of filenames */

/*
 * Global Variables
 ******************
 */

char hashmark = 0;		/* flag set by "set hash" */
int bdm_autoreset = 0;		/* automatic reset before load */
int bdm_ttcu = 0;		/* time to come up for init by rom */
char *initname;			/* need reimplement !!!!!!!!! */
char *bdm_dev_name;		/* device name */
static char *entry_name=NULL;

int
mem_dump (char *buf)
{
  caddr_t adr;
  long len, l;
  int i, ret;
  u_char mem[16];
  char *dump_fname = NULL;
  FILE *dump_file = NULL;
  i = sscanf (buf, " %li %li %as", &l, &len, &dump_fname);
  if (i < 2)
    {
      printf ("use : dump address len [file]\n");
      return -1;
    }
  if(dump_fname && *dump_fname) 
    { dump_file=fopen(dump_fname,"wb");
      if(dump_file==NULL)
        {
          printf ("mem_dump : file \"%s\" open for write error\n", dump_fname);
          free(dump_fname);
          return -1;
        }
      free(dump_fname);
    }

  adr = (caddr_t) l;
  while (len)
    {
      l = len > 16 ? 16 : len;
      ret = bdmlib_read_block (adr, l, mem);
      if (ret != l)
	{
	  printf ("error to read 0x%lx len 0x%lx ret %d\n",
		  (u_long) adr, l, ret);
          if(dump_file!=NULL) 
            fclose(dump_file);
	  return -2;
	}
      printf ("%06lx:", (u_long) adr);
      for (i = 0; i < l; i++)
	printf (" %02x", mem[i]);
      printf ("\n");
      if(dump_file!=NULL) 
        fwrite(mem, l, 1, dump_file);
      len -= l;
      adr += l;
    }
  if(dump_file!=NULL) 
    fclose(dump_file);
  return 0;
}

int
mem_modify (char *buf)
{
  int ret;
  char *p;
  long addr;
  long count=0;
  long capacity=0;
  u_char *data=NULL;
  u_char val;

  while(*buf&&!isblank(*buf)) buf++;
  while(*buf&&isblank(*buf)) buf++;
  if(!*buf)
  { usage_error:
      if(data) free(data);
      printf ("use : modify address byte1 byte2 ...\n");
      return -1;
  }
  addr=strtol(buf,&p,0);
  if(p==buf) goto usage_error;
  buf=p;
  capacity=128;
  data=malloc(capacity);
  while(*buf&&isblank(*buf)) buf++;
  while(*buf){
    val=strtol(buf,&p,0);
    if(p==buf) goto usage_error;
    buf=p;
    if(count>=capacity){
      capacity*=2;
      data=realloc(data,capacity);
      if(!data) goto usage_error;
    }
    data[count++]=val;
    while(*buf&&isblank(*buf)) buf++;
  }
  
  ret=bdmlib_wrb_filt(bdmlib_bfilt, (caddr_t)addr, count, data);
  //if(ret!=count) 
  printf("bdmlib_wrb_filt: addr=0x%08lx count=%ld return=%ld\n",
           (long)addr,(long)count,(long)ret);

  if(data) free(data);
  return ret;
}

int
cpu_get_rpc(u_int32_t *val)
{
  int ret;
  u_int32_t rpc;
  if ((ret = bdmlib_get_sys_reg (BDM_REG_RPC, &rpc)) < 0)
    return ret;
  *val=swap_l(rpc);
  return 0;
}

int
cpu_stat (char *buf)
{
  int ret;
  u_int32_t rpc;
  ret = bdmlib_getstatus ();
  printf ("MCU ");
  if (ret & BDM_TARGETRESET)
    printf ("Reset ");
  if (ret & BDM_TARGETSTOPPED)
    printf ("Stopped ");
  if (ret & BDM_TARGETPOWER)
    printf ("NoPower ");
  if (ret & BDM_TARGETNC)
    printf ("NoConnect ");
  printf ("\n");
  if (ret & BDM_TARGETSTOPPED)
    {
      if ((ret = cpu_get_rpc (&rpc)) < 0)
	return ret;
      printf ("RPC=%x\n",rpc);
    }
  return 0;
}

int
flash_check_one (bdmlib_bfilt_t *filt, int autoset)
{
  flash_alg_info_t const *alg;
  caddr_t adr;
  flash_d_t readid[2];
  int ret;

  alg = (flash_alg_info_t *) filt->info;
  adr = filt->begin_adr;

  if(filt->flags&BDMLIB_FILT_AUTO)
  {
    autoset|=2;
    if(adr==filt->end_adr)
      autoset|=4;
  }

  if ((autoset & 4)&&(adr>=AUTO_ADR_CSBOOT)&&(adr<=AUTO_ADR_CSBOOT+12))
    {
      u_int32_t csx_opt, csx_base, csx_size;
      caddr_t cpu32csopt_adr;
      cpu32csopt_adr=(caddr_t)0xfffa48+(adr-AUTO_ADR_CSBOOT)*4;
      if (bdmlib_read_var (cpu32csopt_adr, BDM_SIZE_LONG, &csx_opt) >= 0)
	{
	  static u_int32_t csx_sizes[]={1<<11,1<<13,1<<14,1<<16,
					  1<<17,1<<18,1<<19,1<<20};
	  csx_base = (csx_opt >> 8) & 0xfff800;
	  filt->begin_adr = (caddr_t) csx_base;
	  csx_size = csx_sizes[(csx_opt >> 16) & 0x7];
	  filt->end_adr = (caddr_t) (csx_base + csx_size - 1);
	  if(adr==AUTO_ADR_CSBOOT)
	    printf ("Flash addresses taken from CSBOOT\n");
	  else
	    printf ("Flash addresses taken from CS%d\n",
	    			(int)(adr-AUTO_ADR_CSX));
	  printf ("Start %06lX End %06lX\n",
		  (long) filt->begin_adr, (long) filt->end_adr);
	}
    }

  adr = filt->begin_adr;

  ret = bdmflash_check_id (alg, adr, readid);
  if((ret >= 0)&&(autoset&4)&&(filt->begin_adr==filt->end_adr))
    filt->end_adr=filt->begin_adr+alg->addr_mask;
  printf ("Flash@%06lX-%06lX ManID %08X DevID %08X\n",
	  (long) adr, (long) filt->end_adr,
	  (unsigned) readid[0], (unsigned) readid[1]);
  if (ret >= 0)
    {
      printf ("Flash ID is OK\nUsed algorithm %s\n", alg->alg_name);
      return 1;
    }
  if (!autoset & 2)
    {
      printf ("Flash parameters are incorrect !!!\n");
      return -1;
    }
  alg = bdmflash_alg_probe (adr);
  if (alg == NULL)
    {
      printf ("Flash parameters cannot be probed\n");
      return -1;
    }
  ret = bdmflash_check_id (alg, adr, readid);
  if (ret < 0)
    {
      printf ("Probed parameters are incorrect\n");
      return -1;
    }
  filt->info = (void *) alg;
  if(filt->begin_adr==filt->end_adr)
    filt->end_adr=filt->begin_adr+alg->addr_mask;
  printf ("Probed flash parameters\n");
  printf ("Flash@%06lX-%06lX ManID %04X DevID %04X\n",
	  (long) filt->begin_adr, (long) filt->end_adr,
	  (unsigned) readid[0], (unsigned) readid[1]);
  printf ("Used algorithm %s\n", alg->alg_name);

  return 1;
}

int
flash_check(char *buf, int autoset)
{
  int ret;
  bdmlib_bfilt_t *filt = bdmlib_bfilt;
  printf("\n");
  while(filt)
  {
    if(filt->flags&BDMLIB_FILT_FLASH)
    {
      ret=flash_check_one(filt,autoset);
      printf("\n");
      if(ret<0)
	return ret;
    }
    filt=filt->next;
  }
  return 0;
}

int
flash_erase(void)
{
  int ret;
  bdmlib_bfilt_t *filt = bdmlib_bfilt;
  while(filt)
  {
    if(filt->flags&BDMLIB_FILT_FLASH)
    {
      ret=bdmflash_erase_filt (filt, (caddr_t) 0, 0);
      if(ret<0)
	return ret;
    }
    filt=filt->next;
  }
  return 0;
}

int
flash_blankck(void)
{
  int ret,sum=0;
  bdmlib_bfilt_t *filt = bdmlib_bfilt;
  while(filt)
  {
    if(filt->flags&BDMLIB_FILT_FLASH)
    {
      ret=bdmflash_blankck_filt (filt, (caddr_t) 0, 0);
      if(ret<0)
	return ret;
      sum+=ret;
    }
    filt=filt->next;
  }
  return sum;
}

/* bdmlib_propeller(stdout); */

int
flash_setup(char *buf)
{
  char *p,*r;
  int i;
  caddr_t begin_adr=(caddr_t)(0);
  caddr_t end_adr=(caddr_t)(0);
  char alg_name[32];
  flash_alg_info_t const *alg=NULL;
  bdmlib_bfilt_t *filt;

  while(*buf&&isblank(*buf)) buf++;
  if((p=strchr(buf,'@'))!=NULL){/* '@' character in specification */
    i=p-buf;
    if(i>=sizeof(alg_name)-1)
      i=sizeof(alg_name)-1;
    strncpy(alg_name,buf,i);
    alg_name[i]=0;
    p++;
    if(!strncmp(p,"csboot",6)){	/* take address from CSBOOT */
      p+=6;
      end_adr=begin_adr=AUTO_ADR_CSBOOT;
    }else if(!strncmp(p,"cs",2)){
      p+=2;
      end_adr=begin_adr=AUTO_ADR_CSX+strtoul(p,&r,0);
      if((p==r)||(begin_adr>AUTO_ADR_CSX+11)){
        fprintf(stderr,"%s : bad chipselect format\n",buf);
        return -1;
      }
      p=r;
    }else{			/* take begin address after '@' */
      end_adr=begin_adr=(caddr_t)strtoul(p,&r,0);
      if(p==r){
        fprintf(stderr,"%s : bad begin address format\n",buf);
        return -1;
      }
      p=r;
      if(*p=='+'){		/* take end address from size */
        end_adr=begin_adr+strtoul(++p,&r,0)-1;
        if(p==r){
          fprintf(stderr,"%s : bad size format\n",buf);
          return -1;
        }
        p=r;
      } else if(*p=='-') {	/* take absolute end address */
        end_adr=(caddr_t)strtoul(++p,&r,0);
        if(p==r){
          fprintf(stderr,"%s : bad end address format\n",buf);
          return -1;
        }
        p=r;
      }
    }
    while(*buf&&isblank(*buf)) buf++;
    if(*p){
      fprintf(stderr,"%s : extra characters in specification %s\n",buf,p);
      return -1;
    }
  }
  else {
    end_adr=begin_adr=AUTO_ADR_CSBOOT;
    strncpy(alg_name,buf,sizeof(alg_name)-1);
  }

  if(strcmp(alg_name,"auto")){
    int alg_indx=0;
    do{
      alg=flash_alg_infos[alg_indx++];
      if(alg==NULL){
        fprintf(stderr,"%s : unknown flash type or algorithm\n",alg_name);
        return -1;
      }
    }while(strcmp(alg_name,alg->alg_name));
  }

  filt=(bdmlib_bfilt_t*)malloc(sizeof(bdmlib_bfilt_t));
  if(filt==NULL){
    fprintf(stderr,"No memory for flash_setup\n");
    return -1;
  }

  filt->flags=BDMLIB_FILT_FLASH;
  if(alg==NULL){
    filt->flags|=BDMLIB_FILT_AUTO;
    filt->info=flash_alg_infos[0];
  } else filt->info=(void *)alg;
  filt->begin_adr=begin_adr;
  filt->end_adr=end_adr;
  if(begin_adr==end_adr){
    filt->flags|=BDMLIB_FILT_AUTO;
  };
  filt->filt_id=1;
  filt->wrb_filt=&bdmflash_wrb_filt;
  
  filt->next=bdmlib_bfilt;
  bdmlib_bfilt=filt;
  return 0;
}

int
str_list_add(str_list_t *list, char *str)
{
  char **p;
  int a;
  if(list->count>=list->alloccnt)
  { 
    a=list->alloccnt+5;
    if(list->items==NULL)
      p=(char**)malloc(sizeof(char *)*a);
    else  
      p=(char**)realloc(list->items,sizeof(char *)*a);
    if(p==NULL) return -1;
    list->items=p;
    list->alloccnt=a;
  } 
  list->items[list->count++]=str;
  return list->count;
}

void str_list_clear(str_list_t *list)
{
  while(list->count--)
  {
    if(list->items[list->count]!=NULL)
      free(list->items[list->count]);
  }
  list->alloccnt=list->count=0;
  if(list->items!=NULL) free(list->items);
  list->items=NULL;
}

/*
 * Main Program
 **************
 */
int
main (int argc, char *argv[])
{
  int done;
  int error;
  int ret;
  static int print_help = 0;		/* Help */
  static int reset = 0;			/* Reset target */
  static int check = 0;			/* Check flash configuration */
  static int erase = 0;			/* Erase flash */
  static int blankck = 0;		/* Check, that flash is blank */
  static int load = 0;			/* Load files to flash */
  static int run = 0;			/* Run target from entry point */
  static int script = 0;		/* Batch mode */
  static int bdm_delay = 0;		/* Delay/speed for BDM driver */
  static int set_mbar_fl = 0;		/* Set MBAR requested */
  static u_long mbar_val = 0;
  static u_long entry_pt=0;
  str_list_t files2load={0,};		/* List of filenames to load */
  int cmd;
  char buf[255];
  char *p;
  int i;

  /* initialize global flash control variables */
  initname = strdup ("ram_init.srec");	/* default init file for EFI332 */

  /* initialize name of bdm device */
  bdm_dev_name = strdup ("/dev/bdm");

  /* start bdmlib debugging */
  bdmlib_setdebug (0);

  /* Parse arguments and options. Taken from GDB. */
  {
    int c;
    /* When var field is 0, use flag field to record the equivalent
       short option (or arbitrary numbers starting at 10 for those
       with no equivalent).  */
    static struct option long_options[] =
    {
      {"help", no_argument, &print_help, 1},
      {"h", no_argument, &print_help, 1},
      {"flash", required_argument, 0, 'f'},
      {"f", required_argument, 0, 'f'},
      {"init-file", required_argument, 0, 'i'},
      {"i", required_argument, 0, 'i'},
      {"reset", no_argument, &reset, 1},
      {"r", no_argument, &reset, 1},
      {"check", no_argument, &check, 1},
      {"c", no_argument, &check, 1},
      {"erase", no_argument, &erase, 1},
      {"e", no_argument, &erase, 1},
      {"blankck", no_argument, &blankck, 1},
      {"b", no_argument, &blankck, 1},
      {"load", no_argument, &load, 1},
      {"l", no_argument, &load, 1},
      {"go", optional_argument, NULL, 'g'},
      {"g", no_argument, &run, 1},
      {"mbar", required_argument, NULL, 'M'},
      {"M", required_argument, NULL, 'M'},
      {"script", no_argument, &script, 1},
      {"s", no_argument, &script, 1},
      {"bdm-delay", required_argument, 0, 'd'},
      {"d", required_argument, 0, 'd'},
      {"bdm-device", required_argument, 0, 'D'},
      {"D", required_argument, 0, 'D'},
      {0, no_argument, 0, 0}
    };

    while (1)
      {
	int option_index;

	c = getopt_long_only (argc, argv, "",
			      long_options, &option_index);
	if (c == EOF)
	  break;

	/* Long option that takes an argument.  */
	if (c == 0 && long_options[option_index].flag == 0)
	  c = long_options[option_index].val;

	switch (c)
	  {
	  case 0:
	    /* Long option that just sets a flag.  */
	    break;
	  case 'f':
	    /* Setup flash region */
	    if(flash_setup(optarg)<0)
	      exit(1);
	    break;
	  case 'g':
	    /* Run target from default or optional entry point */
	    run=1;
	    if (optarg) {
		if (entry_name) free (entry_name);
		entry_name = strdup (optarg);
	    }
	    break;
	  case 'M':
	    /* Set MBAR register */
	    mbar_val=strtoul(optarg,&p,0);
	    set_mbar_fl=1;
	    if(optarg==p){
	      fprintf(stderr,"%s: bad numeric format for MBAR\n",argv[0]);
	      exit(1);
	    }
	    break;
	  case 'D':
	    if (bdm_dev_name)
	      free (bdm_dev_name);
	    bdm_dev_name = strdup (optarg);
	    break;
	  case 'i':
	    /* Init File */
	    if(initname)
	      free(initname);
	    initname = strdup (optarg);
	    break;
	  case 'd':
	    /* BDM driver delay */
	    bdm_delay=strtol(optarg,&p,0);
	    if(optarg==p){
	      fprintf(stderr,"%s: bad numeric format for BDM delay\n",argv[0]);
	      exit(1);
	    }
	    break;
	  case '?':
	    fprintf(stderr,
		"Use `%s --help' for a complete list of options.\n",
			argv[0]);
	    exit (1);
	  }
      }
  }

  if(print_help)
  {
     printf ("Usage bdm-load [OPTIONS] file1 ...\n"
	"\t-h --help            - this help information!\n"
	"\t-i --init-file=FILE  - object file to initialize processor\n"
	"\t-r --reset           - reset target CPU before other operations\n"
	"\t-c --check           - check flash setup (needed for auto)\n"
	"\t-e --erase           - erase flash\n"
	"\t-b --blankck         - blank check of flash\n"
	"\t-l --load            - download listed filenames\n"
	"\t   --go[=address]    - run target CPU from entry address\n"
	"\t-M --mbar=val        - setup 68360 MBAR register\n"
	"\t-s --script          - do actions and return\n"
	"\t-d --bdm-delay=d     - sets BDM driver speed/delay\n"
	"\t-D --bdm-device      - sets BDM device file\n"
	"\t-f --flash=TYPE@ADR  - select flash\n"
	"For flash TYPE@ADR can be\n"
	"  {<TYPE>|auto}[@{csboot|cs<x>|<start>{+<size>|-<end>}}]\n"
	"Examples\n"
	"  auto@csboot  amd29f400@0x800000-0x87ffff  auto@0+0x80000\n"
	"If auto type or cs address is used, check must be\n"
	"specified to take effect.\n"
	"Known flash types/algorithms :\n");
     for(i=0;flash_alg_infos[i]!=NULL;i++)
       printf("  %s",flash_alg_infos[i]->alg_name);
     printf("\n\n");
     exit (0);
  }

  while(optind<argc)
    str_list_add(&files2load,strdup(argv[optind++]));

#ifdef DEBUG_MESSAGES
  printf ("Init file is: %s\n", initname);
  for(i=0;i<files2load.count;i++){
    printf ("Object file : %s\n", files2load.items[i]);
  }
  printf ("Actions to do%s%s%s%s%s\n", (reset) ? " Reset" : "",
		(check) ? " Check" : "", (erase) ? " Erase" : "", 
		(blankck) ? " Blankck" : "", (load) ? " Load" : "");
#endif


  /* Connect to target */
  if((ret=bdmlib_open (bdm_dev_name)) != BDM_NO_ERROR) {
    printf("%s: Open \"%s\" reports %s\n",
    		argv[0],bdm_dev_name,bdmlib_geterror_str(ret));
    exit(1);
  }
  if((ret=bdmlib_setioctl (BDM_SPEED, bdm_delay)) != BDM_NO_ERROR) {
    printf("%s: Set bdm_delay failed with error %s\n",
    		argv[0],bdmlib_geterror_str(ret));
    exit(1);
  }
  hashmark = 1;
  if(set_mbar_fl) {
    printf ("MBAR setup to %08lX\n",mbar_val);
    if(bdmlib_set_mbar(mbar_val) != BDM_NO_ERROR) {
      printf("%s: MBAR setup failed with error %s\n",
    		argv[0],bdmlib_geterror_str(ret));
      exit(1);
    }
  }
  if(files2load.count>0)
    bdmlib_do_load_macro (files2load.items[0], BEGIN_MACRO);

  done = cmd = 0;

  do
    {
      error = 0;
      if (reset)
	{
	  /* bdmlib_init(); */
	  if(bdmlib_reset()<0)
	  {
	    printf ("Reset Failed\n");
	    error=4;
	  }
	  else 
	  {
	    if(cpu_stat(NULL)<0)
	    {
	      printf ("CPU Stat Failed\n");
	      error=4;
	    }
	    else
	    {
	      u_int32_t rpc;
	      reset = 0;
	      if(entry_pt==0)
	      {
	        cpu_get_rpc (&rpc);
	        entry_pt=rpc;
	      }
	    }
	  }
	}

      if (check && !error)
        {
          if(flash_check(NULL,0)<0)
	  {
	    printf ("Flash Check Failed\n");
	    error=3;
	  }
	  else
	    check = 0;
        }

      if (erase && !error)
	{
	  printf ("Erasing Flash...");
	  fflush (stdout);
	  if (flash_erase() >= 0)
	  {
	    printf ("done.\n");
	    erase = 0;
	  }
	  else
	  {
	    printf ("Erase Failed\n");
	    error = 2;
	  }
	}

      if (blankck && !error)
	{
	  int res;
	  printf ("Flash blank check ...\n");
	  res=flash_blankck();
          if(!res){
            printf("Flash blank check OK\n");
            blankck = 0;
	  }else{
	    error = 5;
	    if(res<0) printf("Flash blank check FAILED\n");
	    else printf("Flash is NOT erased\n");
	  }
	}

      if (load && !error)
	{
	  bdmlib_load_use_lma = 1;
          for(i=0;i<files2load.count;i++){
            printf("Loading file : %s\n",files2load.items[i]);
            fflush(stdout);
	    if((ret=bdmlib_load(files2load.items[i], entry_name, &entry_pt))<0)
	    {
	      printf ("Load Failed %d\n", ret);
	      error = 1; //break;
	    }
	  }
	  if(!error) load = 0;
	  bdmlib_load_use_lma = 0;
	}

      if (run && !error)
      {
	printf ("starting at 0x%lx\n", entry_pt);
	bdmlib_set_sys_reg (BDM_REG_RPC, entry_pt);
	bdmlib_go ();
	run=0;
      }

      if(script)
	exit(0);

      printf ("bdm-load %d> ", ++cmd);
      fgets (buf, 250, stdin);

      if (!strncmp (buf, "run", 3))
	{
	  run = 1;
	}

      if (!strncmp (buf, "reset", 5))
	{
	  reset = 1;
	}

      if (!strncmp (buf, "erase", 5))
	erase = 1;

      if (!strncmp (buf, "blankck", 5))
	blankck = 1;

      if (!strncmp (buf, "load", 4))
	{
	  load = 1;
	  if ((strlen (buf) > 5))
	    {
	      str_list_clear(&files2load);
	      str_list_add(&files2load,strdup(&buf[5]));
	    }
	}

      if (!strncmp (buf, "exit", 4) || !strncmp (buf, "quit", 4))
	done = 1;

      if (!strncmp (buf, "dump", 4))
	mem_dump (buf + 4);

      if (!strncmp (buf, "modify", 3))
	mem_modify (buf + 3);

      if (!strncmp (buf, "stat", 4))
	cpu_stat (buf + 4);

      if (!strncmp (buf, "check", 5))
	flash_check (buf + 5, 0);

      if (!strncmp (buf, "autoset", 5))
	flash_check (buf + 5, 0xff);

      if (!strncmp (buf, "stop", 5))
      {
        bdmlib_ioctl(BDM_STOP_CHIP);
        reset=check=erase=blankck=load=run=0;
      }

      if (!strncmp (buf, "make", 4))
	system (buf);

      if (!strncmp (buf, "help", 4) || !strncmp (buf, "?", 1)) 
      {
	printf("Next commands are accepted :\n"\
	       "  run     - enable full speed ran of target CPU\n"\
	       "  stop    - stop target CPU\n"\
	       "  reset   - reset target\n"\
	       "  erase	  - erase all configured FLASH chips\n"\
	       "  blankck - check blank state of chips\n"\
	       "  load    - loand all object files specified\n"\
	       "            at command line to RAM or FLASH\n"\
	       "            using VMA addresses, name of file to\n"\
	       "            can be optionaly specified after \"load\"\n"\
	       "  dump <from> <len>  - dump target memory\n"\
	       "  modify <from> <byte> ... - modify target memory (even flash)\n"\
	       "  state   - print target status\n"\
	       "  check   - check presence of configured chips\n"\
	       "  autoset - set FLASH chip types from their IDs\n"\
	       "  make <par> - call make command in current directory\n"\
	       "  quit    - leave loader\n"\
	       );
      }
    }
  while (!done);
  
  str_list_clear(&files2load);

  exit (0);
}
