www.pudn.com > OSBDM08.zip > cmd_processing.c


/* 
    Open Source BDM - processing of commands received over USB 
	 /* Prominent Notice-This software was modified from TBDML software - 12/05 
 
    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 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 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 
*/ 
 
#include "MC68HC908JB16.h" 
#include "bdm.h" 
#include "cmd_processing.h" 
#include "commands.h" 
#include "version.h" 
#include "usb.h" 
 
#include "led.h" 
 
extern char far __SEG_START_SSTACK[]; 
 
/* processes all commands received over USB */ 
/* the command is expected to be in command_buffer+1  */ 
/* returns number of bytes left in the buffer to be sent back as response */ 
unsigned char command_exec(void) { 
  led_state = LED_BLINK;                          /* blink the LED to indicate a command */ 
  if (bdm_status.target_type==HC12) { 
    if (command_buffer[1]==CMD_GET_LAST_STATUS) { 
      /* need to process this special command before status of the last command is lost */ 
      return(1);       
    } else { 
      command_buffer[0] = command_buffer[1];      /* assume the command will execute OK */ 
      switch (command_buffer[1]) { 
        /* get HW & SW version */ 
        case CMD_GET_VER: 
          *((unsigned int *)(command_buffer+1)) = VERSION; 
          return(3);                              /* return cmd + 2 bytes of version */ 
        /* set target type */                             
        case CMD_SET_TARGET: 
          bdm_status.target_type = command_buffer[2]; 
          return(1);                              /* confirm reception by transmitting cmd number back */ 
  			/* try to connect to the target */ 
        case CMD_CONNECT: 
          if (bdm12_connect()) { 
            command_buffer[0] = CMD_FAILED;       /* cannot connect */ 
          } 
          return(1); 
        /* reset */ 
        case CMD_RESET: 
          if (bdm_reset(command_buffer[2])) { 
            command_buffer[0] = CMD_FAILED;       /* reset line stuck */ 
          } 
          return(1); 
        /* return status of BDM communication */ 
        case CMD_GET_STATUS: 
          command_buffer[1]=0;  /* intel LSB */ 
          if (bdm_status.ackn==ACKN) command_buffer[1]|=0x01; /* target supports ACKN and the feature is enabled */ 
          if (bdm_status.reset==RESET_DETECTED) { 
            command_buffer[1]|=0x02;                          /* the target was resently reset externaly */ 
            if (RESET_IN==1) bdm_status.reset=NO_RESET_ACTIVITY; /* clear the flag if reset pin has gone high already */ 
          } 
          if (bdm_status.speed==SPEED_USER_SUPPLIED) command_buffer[1]|=0x18; else  /* do not blame me if it does not work... */ 
            if (bdm_status.speed==SYNC_SUPPORTED) command_buffer[1]|=0x08; else     /* SYNC feature used to detect speed */ 
              if (bdm_status.speed==SPEED_GUESSED) command_buffer[1]|=0x10;         /* speed guessed by trial & error */ 
          command_buffer[2]=0;  /* intel MSB */ 
          return(2); 
        /* read BDM byte */ 
        case CMD_READ_BD: 
          BDM12_CMD_BDREADB((unsigned int)256*command_buffer[3]+command_buffer[2],command_buffer+1); 
          return(2); 
        /* write BDM byte */ 
        case CMD_WRITE_BD: 
          BDM12_CMD_BDWRITEB((unsigned int)256*command_buffer[3]+command_buffer[2],command_buffer[4]); 
          return(1); 
        /* stop the target */ 
        case CMD_HALT: 
          BDM_CMD_BACKGROUND(); 
          return(1); 
        /* set comm speed to user supplied value */ 
        case CMD_SET_SPEED1:  
          { 
            unsigned char bdm_sts; 
            bdm_status.sync_length=(unsigned int)(256*command_buffer[3]+command_buffer[2]); /* save the speed */ 
            if (bdm_rx_tx_select()) { 
              command_buffer[0] = CMD_FAILED;       /* no Rx or Tx routine for this speed */ 
              bdm_status.speed = NO_INFO;           /* connection cannot be established at this speed */ 
              bdm_status.ackn = WAIT;               /* clear indication of ACKN feature */ 
              return(1); 
            } 
            bdm_status.speed = SPEED_USER_SUPPLIED; /* user told us */ 
          	bdm_ackn_init();                        /* try the ACKN feature */ 
          	BDM12_CMD_BDREADB(BDM12_STS_ADDR,&bdm_sts); 
          	if ((bdm_sts&0x80)==0) BDM12_CMD_BDWRITEB(BDM12_STS_ADDR,0x80|bdm_sts);	/* if BDM not enabled yet, enable it so it can be made active */ 
            return(1);           
          } 
        /* Read current speed */ 
        case CMD_READ_SPEED1: 
          command_buffer[2] = (bdm_status.sync_length)>>8;   /* store speed in little endian */ 
          command_buffer[1] = (bdm_status.sync_length)&0xff; 
          return(3); 
        /* Start code execution */ 
        case CMD_GO1: 
          BDM_CMD_GO(); 
          return(1); 
        /* Step over 1 instruction */ 
        case CMD_STEP1: 
          BDM_CMD_TRACE1(); 
          return(1); 
        /* read byte */ 
        case CMD_READ_8: 
          BDM12_CMD_READB((unsigned int)256*command_buffer[3]+command_buffer[2],command_buffer+1); 
          return(2); 
        /* read word */ 
        case CMD_READ_16: 
          BDM12_CMD_READW((unsigned int)256*command_buffer[3]+command_buffer[2],command_buffer+2); 
          command_buffer[1] = command_buffer[3];  /* swap bytes around for little endian */ 
          return(3); 
        /* read registers */ 
        case CMD_READ_REGS: 
          BDM12_CMD_READ_PC(command_buffer+2); 
          command_buffer[1] = command_buffer[3];  /* swap bytes around for little endian */ 
					BDM12_CMD_READ_SP(command_buffer+4); 
          command_buffer[3] = command_buffer[5];  /* swap bytes around for little endian */ 
					BDM12_CMD_READ_X(command_buffer+6); 
          command_buffer[5] = command_buffer[7];  /* swap bytes around for little endian */ 
					BDM12_CMD_READ_Y(command_buffer+8); 
          command_buffer[7] = command_buffer[9];  /* swap bytes around for little endian */ 
					BDM12_CMD_READ_D(command_buffer+10); 
          command_buffer[9] = command_buffer[11]; /* swap bytes around for little endian */ 
					BDM12_CMD_BDREADW(BDM12_CCR_ADDR,command_buffer+11);  /* CCR is in little endian format already */ 
          return(13); 
        /* read block of data from memory */ 
        case CMD_READ_BLOCK1:  
          { 
            /* NOTE: This command returns block of BYTES, endianism does not matter here!!! */ 
            unsigned char count = command_buffer[4]; 
            unsigned char count_orig = command_buffer[4]; 
            unsigned int addr = (unsigned int)256*command_buffer[3]+command_buffer[2]; 
            unsigned char *data_ptr = command_buffer+1; 
            if (count>MAX_DATA_SIZE) { 
              command_buffer[0] = CMD_FAILED; /* requested block is too long to fit into the buffer */ 
              return(1);   
            } 
            if (addr&0x0001) { 
              /* start address is odd, fetch the first byte separately */ 
              BDM12_CMD_READB(addr,data_ptr);   
              addr++; 
              data_ptr++; 
              count--; 
            } 
            while(count&0xfe) { 
              /* while there are at least 2 bytes to fetch */ 
              BDM12_CMD_READW(addr,data_ptr);    /* fetch a word */ 
              addr+=2;                           /* increment address */ 
              data_ptr+=2;                       /* increment pointer */ 
              count-=2;                          /* decrement count */ 
            } 
            if (count) { 
              /* there is one extra byte to read at the end of the block */   
              BDM12_CMD_READB(addr,data_ptr);   
            } 
            return(count_orig+1); 
          } 
        /* write byte */ 
        case CMD_WRITE_8: 
          BDM12_CMD_WRITEB((unsigned int)256*command_buffer[3]+command_buffer[2],command_buffer[4]); 
          return(1); 
        /* write word */ 
        case CMD_WRITE_16: 
          BDM12_CMD_WRITEW((unsigned int)256*command_buffer[3]+command_buffer[2],(unsigned int)256*command_buffer[5]+command_buffer[4]); 
          return(1);         
        /* write block of bytes to memory */ 
        case CMD_WRITE_BLOCK1:  
          { 
            unsigned char count = command_buffer[4]; 
            unsigned int addr = (unsigned int)256*command_buffer[3]+command_buffer[2]; 
            unsigned char *data_ptr = command_buffer+5; 
            if (addr&0x0001) { 
              /* start address is odd, write the first byte separately */ 
              BDM12_CMD_WRITEB(addr,*data_ptr);   
              addr++; 
              data_ptr++; 
              count--; 
            } 
            while(count&0xfe) { 
              /* while there are at least 2 bytes to fetch */ 
              BDM12_CMD_WRITEW(addr,*((unsigned int*)data_ptr)); /* write a word */ 
              addr+=2;                              /* increment address */ 
              data_ptr+=2;                          /* increment pointer */ 
              count-=2;                             /* decrement count */ 
            } 
            if (count) { 
              /* there is one extra byte to write at the end of the block */   
              BDM12_CMD_WRITEB(addr,*data_ptr);   
            } 
            return(1); 
          } 
        /* write to PC */ 
        case CMD_WRITE_REG_PC: 
          BDM12_CMD_WRITE_PC((unsigned int)256*command_buffer[3]+command_buffer[2]); 
          return(1); 
        /* write to SP */ 
        case CMD_WRITE_REG_SP: 
          BDM12_CMD_WRITE_SP((unsigned int)256*command_buffer[3]+command_buffer[2]); 
          return(1); 
        /* write to IX */ 
        case CMD_WRITE_REG_X: 
          BDM12_CMD_WRITE_X((unsigned int)256*command_buffer[3]+command_buffer[2]); 
          return(1); 
        /* write to IY */ 
        case CMD_WRITE_REG_Y: 
          BDM12_CMD_WRITE_Y((unsigned int)256*command_buffer[3]+command_buffer[2]); 
          return(1); 
        /* write to B:A */ 
        case CMD_WRITE_REG_D: 
          BDM12_CMD_WRITE_D((unsigned int)256*command_buffer[3]+command_buffer[2]); 
          return(1); 
        /* write to CCR */ 
        case CMD_WRITE_REG_CCR: 
					BDM12_CMD_BDWRITEW(BDM12_CCR_ADDR,*((unsigned int *)(command_buffer+2))); /* CCR is stored in little endian notation */ 
          return(1); 
        default:    /* unknown command */ 
          command_buffer[0] = CMD_UNKNOWN; 
          return(1);     
      } 
    } 
  } 
  //=========================================== 
  else if (bdm_status.target_type==HCS08) { 
    if (command_buffer[1]==CMD_GET_LAST_STATUS) { 
      /* need to process this special command before status of the last command is lost */ 
      return(1);       
    } else { 
      command_buffer[0] = command_buffer[1];      /* assume the command will execute OK */ 
      switch (command_buffer[1]) { 
        /* get HW & SW version */ 
        case CMD_GET_VER: 
          *((unsigned int *)(command_buffer+1)) = VERSION; 
          return(3);                              /* return cmd + 2 bytes of version */ 
        /* set target type */                             
        case CMD_SET_TARGET: 
          bdm_status.target_type = command_buffer[2]; 
          return(1);                              /* confirm reception by transmitting cmd number back */ 
  			/* try to connect to the target */ 
        case CMD_CONNECT: 
          if (bdm08_connect()) { 
            command_buffer[0] = CMD_FAILED;       /* cannot connect */ 
          } 
          return(1); 
        /* reset */ 
        case CMD_RESET: 
        		if (bdm08_stat()==0) { 
        			 if (bdm_reset(command_buffer[2])) { 
                  command_buffer[0] = CMD_FAILED;       /* reset line stuck */ 
                }				 
        		}  
        		else { 
        					 bdm_softreset(command_buffer[2]);        				 
     				}             
          return(1); 
        /* return status of BDM communication */ 
        case CMD_GET_STATUS: 
          command_buffer[1]=0;  /* intel LSB */ 
          if (bdm_status.ackn==ACKN) command_buffer[1]|=0x01; /* target supports ACKN and the feature is enabled */ 
          if (bdm_status.reset==RESET_DETECTED) { 
            command_buffer[1]|=0x02;                          /* the target was resently reset externaly */ 
            if (RESET_IN==1) bdm_status.reset=NO_RESET_ACTIVITY; /* clear the flag if reset pin has gone high already */ 
          } 
          if (bdm_status.speed==SPEED_USER_SUPPLIED) command_buffer[1]|=0x18; else  /* do not blame me if it does not work... */ 
            if (bdm_status.speed==SYNC_SUPPORTED) command_buffer[1]|=0x08; else     /* SYNC feature used to detect speed */ 
              if (bdm_status.speed==SPEED_GUESSED) command_buffer[1]|=0x10;         /* speed guessed by trial & error */ 
          command_buffer[2]=0;  /* intel MSB */ 
          return(2); 
        case CMD_READ_STATUS:  
          BDM08_CMD_READSTATUS(command_buffer+1); 
          return(2);      
        case CMD_WRITE_CONTROL:  
          BDM08_CMD_WRITECONTROL(command_buffer[2]); 
          return(2);     
        /* stop the target */ 
        case CMD_HALT: 
          BDM_CMD_BACKGROUND(); 
          return(1); 
        /* set comm speed to user supplied value */ 
        case CMD_SET_SPEED1:  
          { 
            unsigned char bdm_sts; 
            bdm_status.sync_length=(unsigned int)256*command_buffer[3]+command_buffer[2]; /* save the speed */ 
            if (bdm_rx_tx_select()) { 
              command_buffer[0] = CMD_FAILED;       /* no Rx or Tx routine for this speed */ 
              bdm_status.speed = NO_INFO;           /* connection cannot be established at this speed */ 
              bdm_status.ackn = WAIT;               /* clear indication of ACKN feature */ 
              return(1); 
            } 
            bdm_status.speed = SPEED_USER_SUPPLIED; /* user told us */ 
          	bdm_ackn_init();                        /* try the ACKN feature */ 
          	 BDM08_CMD_READSTATUS(&bdm_sts); 
  
          	if ((bdm_sts&0x80)==0) BDM12_CMD_BDWRITEB(BDM12_STS_ADDR,0x80|bdm_sts);	/* if BDM not enabled yet, enable it so it can be made active */ 
            return(1);           
          } 
        /* Read current speed */ 
        case CMD_READ_SPEED1: 
          command_buffer[2] = (bdm_status.sync_length)>>8;   /* store speed in little endian */ 
          command_buffer[1] = (bdm_status.sync_length)&0xff; 
          return(3); 
        /* Start code execution */ 
        case CMD_GO1: 
          BDM_CMD_GO(); 
          return(1); 
        /* Step over 1 instruction */ 
        case CMD_STEP1: 
          BDM_CMD_TRACE1(); 
          return(1); 
        /* read byte */ 
        case CMD_READ_8: 
          BDM08_CMD_READB((unsigned int)256*command_buffer[3]+command_buffer[2],command_buffer+1); 
          return(2); 
        /* read registers */ 
        case CMD_READ_REGS: 
         
          BDM08_CMD_READ_PC(command_buffer+2);   
          command_buffer[1] = command_buffer[3];  /* swap bytes around for little endian */ 
           
					BDM08_CMD_READ_SP(command_buffer+4);	 //S08 
          command_buffer[3] = command_buffer[5];  /* swap bytes around for little endian */ 
           
					BDM08_CMD_READ_HX(command_buffer+6); 
          command_buffer[5] = command_buffer[7];  /* swap bytes around for little endian */ 
           
					BDM08_CMD_READ_A(command_buffer+7); 
           
					BDM08_CMD_READ_CCR(command_buffer+8);					 
          return(13); 
        /* read block of data from memory */ 
        case CMD_READ_BLOCK1:  
          { 
            /* NOTE: This command returns block of BYTES, endianism does not matter here!!! */ 
            unsigned char count = command_buffer[4]; 
            unsigned char count_orig = command_buffer[4]; 
            unsigned int addr = (unsigned int)256*command_buffer[3]+command_buffer[2]; 
            unsigned char *data_ptr = command_buffer+1; 
            if (count>MAX_DATA_SIZE) { 
              command_buffer[0] = CMD_FAILED; /* requested block is too long to fit into the buffer */ 
              return(1);   
            } 
            if (addr&0x0001) { 
              /* start address is odd, fetch the first byte separately */ 
              BDM08_CMD_READB(addr,data_ptr);   
              addr++; 
              data_ptr++; 
              count--; 
            } 
            while(count&0xfe) { 
              BDM08_CMD_READB(addr,data_ptr);    /* fetch a word */ 
              addr+=1;                           /* increment address */ 
              data_ptr+=1;                       /* increment pointer */ 
              count-=1;                          /* decrement count */ 
            } 
            if (count) { 
              /* there is one extra byte to read at the end of the block */   
              BDM08_CMD_READB(addr,data_ptr);   
            } 
            return(count_orig+1); 
          } 
        /* write byte */ 
        case CMD_WRITE_8: 
          BDM08_CMD_WRITEB((unsigned int)256*command_buffer[3]+command_buffer[2],command_buffer[4]); 
          return(1); 
        /* write block of bytes to memory */ 
        case CMD_WRITE_BLOCK1:  
          { 
            unsigned char count = command_buffer[4]; 
            unsigned int addr = (unsigned int)256*command_buffer[3]+command_buffer[2]; 
            unsigned char *data_ptr = command_buffer+5; 
            if (addr&0x0001) { 
              /* start address is odd, write the first byte separately */ 
              BDM08_CMD_WRITEB(addr,*data_ptr);   
              addr++; 
              data_ptr++; 
              count--; 
            } 
            while(count&0xfe) { 
              /* while there are at least 2 bytes to fetch */ 
               BDM08_CMD_WRITEB(addr,*data_ptr);   
               addr+=1;                              /* increment address */ 
               data_ptr+=1;                          /* increment pointer */ 
               count-=1;                             /* decrement count */ 
            } 
            if (count) { 
              /* there is one extra byte to write at the end of the block */   
              BDM08_CMD_WRITEB(addr,*data_ptr);   
            } 
            return(1); 
          } 
        /* write to PC */ 
        case CMD_WRITE_REG_PC: 
          BDM08_CMD_WRITE_PC((unsigned int)256*command_buffer[3]+command_buffer[2]); 
          return(1); 
        /* write to SP */ 
        case CMD_WRITE_REG_SP: 
          BDM08_CMD_WRITE_SP((unsigned int)256*command_buffer[3]+command_buffer[2]); 
          return(1); 
        /* write to IX */ 
        case CMD_WRITE_REG_X: 
          BDM08_CMD_WRITE_HX((unsigned int)256*command_buffer[3]+command_buffer[2]); 
          return(1); 
        /* write to B:A */ 
        case CMD_WRITE_REG_D: 
          BDM08_CMD_WRITE_A(command_buffer[2]); 
          return(1); 
        /* write to CCR */ 
        case CMD_WRITE_REG_CCR: 
					BDM08_CMD_WRITE_CCR(command_buffer[2]); /* CCR is stored in little endian notation */ 
          return(1); 
        case CMD_WRITE_BKPT: 
					BDM08_CMD_WRITE_BKPT((unsigned int)256*command_buffer[3]+command_buffer[2]);  
					return(1); 
        case CMD_READ_BKPT: 
					BDM08_CMD_READ_BKPT(command_buffer+2);	 
					command_buffer[1] = command_buffer[3];  
          return(3);                         
        default:    /* unknown command */ 
          command_buffer[0] = CMD_UNKNOWN; 
          return(1);     
      } 
    } 
  } 
    /* only HC12/S12(X) supported at the moment */ 
    command_buffer[0] = CMD_UNKNOWN; 
    return(1);     
  }