
/******************************************************************************
 *
 *                                  Cmd
 *
 * This module contains the command line interpreter of CMON. 
 * It is considered the main module of cmon so global constants are declared 
 * here.
 *
 * History:
 *   +----------+------------+------------------------------------------------+
 *   |   Date   |     by     |     Description                                |
 *   +----------+------------+------------------------------------------------+
 *   |          | Coby       | Written                                        |
 *   +----------+------------+------------------------------------------------+
 * 
 *****************************************************************************/


#include "cc_def.h"
#include "global_f.h"
#include "bpt.h"
#include "cmd.h"
#include "cpu.h"
#include "exec.h"
#include "io.h"
#include "mem.h"
#include "misc.h"
#include "user_cmd.h"
#include "sio_d.h"


/*--------------------------------------------------------------------------
 * 				
 * 				Variable definitions
 * 
 *------------------------------------------------------------------------*/

typedef struct {
        char        cmd_verb[5];
        void        (*func)();
} cmd_tab_type;


/* 
 * The following array contains all CMON commands which start with a "P",
 * except the "print register" commands.
 * For each such command there is a pointer to the function which handles it.
 */

private const cmd_tab_type p_cmd_tab[] = {
	/* The first two commands are used to skip the PBP comand */
	{"PBPC0" , NULL     },        /* Print BPC0 		             */
	{"PBPC1" , NULL     }, 	     /* Print BPC1 		             */
	{"PBP" , pbp_decode__     }, /* Print breakpoint (old spec)          */
#ifdef DSPM_SUPPORT
	{"PDBP" , pdbp_decode__     }, /* Print DSPM breakpoint              */
#endif
#ifdef MMU_SUPPORT
        {"PC"  , pc_decode__      }, /* Protection Create                    */
#endif  /* MMU_SUPPORT */
	{"PCON", pcon_decode__    }, /* Print CMON Configuration             */
	{"PMB" , pm_decode__      }, /* Print memory byte                    */
	{"PMD" , pm_decode__      }, /* Print memory double                  */
	{"PMW" , pm_decode__      }, /* Print memory word                    */
	{"POM" , pom_decode__     }, /* Print Operation Mode Byte            */
#ifdef MMU_SUPPORT
	{"PP"  , pp_decode__      }, /* Protection Print                     */
	{"PTM" , ptm_decode__     }, /* Print Translation Mode               */
#endif  /* MMU_SUPPORT */
        {""    , NULL             }  /* To signal the end of the table       */
};

/* 
 * The following array contains all CMON commands which start with a "C",
 * except the "change register" commands.
 * For each such command there is a pointer to the function which handles it.
 */

private const cmd_tab_type c_cmd_tab[] = {
#ifdef LAN_EXIST
	{"CON" , con_decode__	  }, /* Connect to host (LAN only) */
#endif
	/* The following two commands are used to skip the CBP comand */
	{"CBPC0" , NULL     },       /* Change BPC0 		             */
	{"CBPC1" , NULL     }, 	     /* Change BPC1 		             */
	{"CBP" , cbp_decode__	  }, /* Change Break Point  (old spec)       */
#ifdef DSPM_SUPPORT
	{"CDBP" , cdbp_decode__	  }, /* Change DSPM Break Point              */
#endif
        {"CMB" , cm_decode__      }, /* Change Memory Byte                   */
	{"CMD" , cm_decode__      }, /* Change Memory Double                 */
	{"CMW" , cm_decode__      }, /* Change Memory Word                   */
#ifdef MMU_SUPPORT
	{"CTM" , ctm_decode__     }, /* Change Translation Mode              */
#endif  /* MMU_SUPPORT */
	{"CX"  , cx_decode__      }, /* Call external procedure              */
	{"CUB"   , cub_decode__       }, /* Change Uart baud rate	     */
        {""    , NULL             }  /* To signal the end of the table       */
};
	
/*
 * The following array contains all CMON commands except those which start 
 * with a "P", "C", or "$".
 * For each such command there is a pointer to the function which handles it.
 * Notes:
 * 1. The 'binary load' command does not appear here. Only the BL command is 
 *    here. The reason is that this command only have a meaning during a 
 *    binary load, so it has to come following a BL command.
 * 2. The Reset and NMI acknowledge '!' command does not appear here.
 *    The reason is that this command only has a meaning after reset or NMI.
 *
 * 3. Commands are ordered in such a way that names are not a prefix
 *    of any of the next names.
 */

private const cmd_tab_type o_cmd_tab[] = {
#     ifdef NEW_SPEC
	{"BC"  , bc_decode__      }, /* Breakpoint Create                    */
	{"BD"  , bd_decode__      }, /* Breakpoint Delete                    */
#     endif /* NEW_SPEC */
	{"BL"  , bl_decode__      }, /* Start Load Data in Binary Format     */
	{"BO"  , bo_decode__      }, /* Run boot program                     */
#     ifdef NEW_SPEC
	{"BP"  , bp_decode__      }, /* Breakpoint Print                     */
#     endif /* NEW_SPEC */
        {"BAL"   , bal_decode__   }, /* Bal procedure                        */
        {"B"   , b_decode__       }, /* Begin external procedure             */
	{"DE"  , de_decode__      }, /* Direct Exception enable/disable      */
	{"D"   , d_decode__       }, /* Dump Memory (old spec)               */
	{"F"   , f_m_sr_decode__  }, /* Fill memory (old spec)               */
	{"G"   , g_decode__       }, /* Go                                   */
	{"IV"  , iv_decode__      }, /* Invalidate Instruction/Data Cache    */
	{"JS"  , js_decode__      }, /* Jump to subroutine                   */
	{"LH"  , lh_decode__      }, /* Load data in hexadecimal format      */
#ifdef LAN_EXIST
	{"LT"   ,lt_decode__      }, /* Resend lost packet		     */
#endif
	{"L"   , lh_decode__      }, /* Load hexadecimal data      (old spec)*/
	{"MF"  , m_decode__       }, /* Fill memory with data                */
	{"MM"  , m_decode__       }, /* Move block of data                   */
	{"MS"  , m_decode__       }, /* Search memory for data               */
	{"M"   , f_m_sr_decode__  }, /* Move memory (old spec)               */
	{"NP"  , np_decode__      }, /* Change to new protocol (B)           */
	{"NB"  , null_func__      }, /* New breakpoint scheam                */
	{"OMN" , om_decode__      }, /* Operation mode, Stand aside          */
	{"OMS" , om_decode__      }, /* Operation mode, Stand alone          */
#if (TRANSPARENT == TRUE)
	{"OMT" , om_decode__      }, /* Operation mode, Transparent          */
#endif
	{"OP"  , op_decode__      }, /* Change to old protocol (A)           */
	{"RI"  , ri_decode__      }, /* Reset INTBASE Register               */
	{"SR"  , f_m_sr_decode__  }, /* Search memory (old spec)             */
	{"ST"  , st_decode__      }, /* Step                                 */
	{"SU"  , sw_decode__      }, /* Step until  (old spec)               */
	{"SW"  , sw_decode__      }, /* Step while  (old spec)               */
	{"T"   , t_decode__       }, /* Run Diagnostic Tests Program         */
	{"VR"   , vr_decode__       }, /* Print version		             */
#     ifdef NEW_SPEC
	{"WC"  , wc_decode__      }, /* Watchpoint Create                    */
	{"WD"  , wd_decode__      }, /* Watchpoint Delete                    */
	{"WP"  , wp_decode__      }, /* Watchpoint Print                     */
#     endif /* NEW_SPEC */
        {""    , NULL             }  /* To signal the end of the table       */
};

/*
 * Declaration of internal functions
 */

private void process_cmd(/* cmd, response */);
private void process_p_cmd(/* cmd, response */);
private void process_c_cmd(/* cmd, response */);
private void process_o_cmd(/* cmd, response */);

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *                           Cmd_loop__(first_cmd)
 *
 * This is the main function of the command line processor.
 * It loops on the user commands. Each itteration reads a command, processes it
 * and prints its response.
 * If first_cmd is null, it starts by waiting for a new command. If not, this
 * is the first command processed.
 * Note that commands which send a multiple line response, send it by 
 * themselves. 
 *
 *---------------------------------------------------------------------------*/

public void cmd_loop__()
{
    l_str user_cmd, response;

    response[0] = '\0';
    
    while (TRUE) {
	read_message__(user_cmd, response);
	if (setjmp (return_env__) == 0) {
	    if (user_cmd[0] != '\0') {
		response[0] = '\0';
		process_cmd(user_cmd, response);
		if (response[0] != '\0') {
		    write_message__( response);
		}
	    }
	}
	else {
	    write_message__(response__);
	    strcpy(response, response__);
	}
        write_message__(ready_prompt__);
   }

} /* cmd_loop__ */





/*-----------------------------------------------------------------------------
 *
 *                         Process_cmd(cmd, response)
 *
 * This function receives a command which was entered by the user and checks 
 * its its first letter. Commands are divided to four groups, according to 
 * their first character: 'P', 'C' , '$' and all other commands. 
 * The appropriate function is called to process the command.
 * The response is returned to the caller.
 *
 *---------------------------------------------------------------------------*/

private void process_cmd(cmd, response)
    str cmd, response;
{

    switch (cmd[0]) {
        case ('P') :
            process_p_cmd(cmd, response);
            return;
        case ('C') :
            process_c_cmd(cmd, response);
            return;
        case ('$') :
            user_cmd_extension(cmd, response);
            return;
        default    :
            process_o_cmd(cmd, response);
            return;
    }
} /* process_cmd */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *                         Process_p_cmd(cmd, response)
 *
 * This function receives a command which starts with a 'P'. 
 * It checks if this is a command which is listed in the table. 
 * If not, it checks if it is a 'print register' command.
 * If not, the command is undefined and is passed to the user command driver.
 * The response is returened to the caller.
 *
 *---------------------------------------------------------------------------*/

private void process_p_cmd(cmd, response)
    str      cmd, response;
{
    unsigned cmd_ptr, verb_len;
    s_str    cmd_verb, reg_from_cmd;
    boolean  err;
    reg_desc *regp;

    /*
     * Identify  commands "P<space>XX..." as "PXX..."
     */
    
    if (cmd[1] == ' ') {
	cmd[1] = 'P';
	cmd ++;
    }
    
    /*
     * Find the command verb.
     */

    get_first_arg__(cmd, cmd_verb, &verb_len, S_SIZE,
                   /* accept null arg */ FALSE);

    /*
     * Check if the command is in the 'p command table'. 
     * If so, execute it and return.
     */

    for (cmd_ptr = 0; p_cmd_tab[cmd_ptr].cmd_verb[0] != '\0'; cmd_ptr++) {
        if (STRINGS_N_EQUAL(p_cmd_tab[cmd_ptr].cmd_verb, 
	    cmd_verb,strlen(p_cmd_tab[cmd_ptr].cmd_verb))) {
	    if (p_cmd_tab[cmd_ptr].func == NULL) {
		break;
	    }
	    else {
            	(*p_cmd_tab[cmd_ptr].func)(cmd, response);
            	return;
	    }
        }
    }

    /*
     * Check if the command is a 'print register' command.
     * If so, execute it and return.
     */

    strcpy(reg_from_cmd, &cmd_verb[1]);

    if((regp = search_reg_tab__(reg_from_cmd)) != NULL) {
        print_reg_val__(regp, response);
        return;
    }

    /*
     * The command is undefined.
     */

    user_cmd_extension(cmd, response);

} /* process_p_cmd */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *                           Process_c_cmd(cmd, response)
 *
 * This function receives a command which starts with a 'C'. 
 * It checks if this is a command which is listed in the table. 
 * If not, it checks if it is a 'change register' command.
 * If not, the command is undefined and is passed to the user command driver.
 * The response is returened to the caller.
 *
 *---------------------------------------------------------------------------*/

private void process_c_cmd(cmd, response)
    str      cmd, response;
{
    unsigned cmd_ptr, verb_len;
    s_str    cmd_verb, reg_from_cmd, value;
    boolean  err, verify;
    reg_desc *regp;


    /*
     * Identify  commands "C<space>XX..." as "CXX..."
     */
    
    if (cmd[1] == ' ') {
	cmd[1] = 'C';
	cmd ++;
    }
 
    /*
     * Find the command verb.
     */

    get_first_arg__(cmd, cmd_verb, &verb_len, S_SIZE,
                   /* accept null arg */ FALSE);

    /*
     * Check if the command is in the 'c command table'. 
     * If so, execute it and return.
     */

    for (cmd_ptr = 0; c_cmd_tab[cmd_ptr].cmd_verb[0] != '\0'; cmd_ptr++) {
        if (STRINGS_N_EQUAL(c_cmd_tab[cmd_ptr].cmd_verb,
	    cmd_verb,strlen(c_cmd_tab[cmd_ptr].cmd_verb))) {
	    if (c_cmd_tab[cmd_ptr].func == NULL) {
		break;
	    }
	    else {
                (*c_cmd_tab[cmd_ptr].func)(cmd, response);
            	return;
	    }
        }
    }

    /*
     * Check if the command is a 'change register' command.
     * If so, execute it and return.
     */

    strcpy(reg_from_cmd, &cmd_verb[1]);

    if((regp = search_reg_tab__(reg_from_cmd)) != NULL) {
	get_value_for_change__(&cmd[verb_len], value, &verify);
        change_reg_val__(regp, value, verify);
        return;
    }

    /*
     * The command is undefined.
     */

    user_cmd_extension(cmd, response);

} /* process_c_cmd */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *                         Process_o_cmd(cmd, response)
 *
 * This function receives a command which doesn't start with a 'P', 'C' or '$'.
 * It checks if this is a command which is listed in the table. 
 * If not, the command is undefined and is passed to the user command driver.
 * The response is returened to the caller.
 *
 *---------------------------------------------------------------------------*/

private void process_o_cmd(cmd, response)
    str      cmd, response;
{
    unsigned cmd_ptr, verb_len;
    s_str    cmd_verb;
    boolean  err;

    /*
     * Find the command verb.
     */

    get_first_arg__(cmd, cmd_verb, &verb_len, S_SIZE,
                   /* accept null arg */ FALSE);

    /*
     * Check if the command is in the 'other command table'. 
     * If so, execute it and return.
     */

    for (cmd_ptr = 0; o_cmd_tab[cmd_ptr].cmd_verb[0] != '\0'; cmd_ptr++) {
        if (STRINGS_N_EQUAL(o_cmd_tab[cmd_ptr].cmd_verb,
	    cmd_verb,strlen(o_cmd_tab[cmd_ptr].cmd_verb))) {
            (*o_cmd_tab[cmd_ptr].func)(cmd, response);
            return;
        }
    }

    /*
     * The command is undefined.
     */

    user_cmd_extension(cmd, response);

} /* process_o_cmd */



