/******************************************************************************
 *
 *                                  Bpt
 *
 * This module contains the functions which control the breakpoints and
 * watchpoints.
 *
 * History:
 *   +----------+------------+------------------------------------------------+
 *   |   Date   |     by     |     Description                                |
 *   +----------+------------+------------------------------------------------+
 *   |          | Coby       | Written                                        |
 *   +----------+------------+------------------------------------------------+
 * 
 *****************************************************************************/


#include "cc_def.h"
#include "global_f.h"
#include "bpt.h"
#include "cmd.h"
#include "cpu_d.h"
#include "exec.h"
#include "fpu_d.h"

#include "io.h"
#include "mem.h"
#include "traps.h"
#include "reset.h"



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

#define SW_BPT_NUM  16

/*
 * @old_spec@
 * increase number of watchpoints to use last one for emulating old specs
 * commands STEP UNTIL/WHILE.
 */


#ifdef NEW_SPEC
#   define WPT_NUM 33
#else
#   define WPT_NUM 1
#endif

/* 
 * The watch types available.
 */

typedef enum {
        UNTIL,
        WHILE
} watch_type;

/*
 * The memory and register watchpoint arrays.
 * They are defined as one unified type because there are common functions 
 * which work on both.
 */

public boolean     active_wpt__ = FALSE; 

typedef struct {
        boolean    active;
        unsigned   addr;
        reg_desc   *reg;
        boolean    low_specified;
        quad_word  low_value;
        boolean    high_specified;
        quad_word  high_value;
        boolean    mask_specified;
        quad_word  mask_value;
        char       width;
        watch_type type;        
        boolean    count_specified;
        unsigned   orig_count;
        unsigned   cur_count;
} wpt_entry;


	/* watch point arrays are forced to data section */
private wpt_entry      mem_wpt[WPT_NUM] = {{0}}, reg_wpt[WPT_NUM] ={{0}};

/*
 * The software breakpoint array
 */

typedef struct {
        boolean    active;
        address           addr;
        BPT_TYPE   contents;
        boolean    count_specified;
        unsigned   orig_count;
        unsigned   cur_count;
        wpt_entry  wpt;
} sw_bpt_entry;

private sw_bpt_entry  sw_bpt[SW_BPT_NUM] = {{0}}; /* force to data section */



/*
 * Define local functions
 */

private void restore_old_user_regs(/**/);
private boolean check_wpt_array(/*arg_type*/);
private void sw_bpt_delete (/*bpt_num */);
private void sw_bpt_create(/*bpt_num, hex_addr, flags*/);
private void sw_bpt_print(/*bpt_num, bc_cmd*/);
private void sw_bpt_delete(/*bpt_num*/);
private void mem_wpt_create(/*wpt_num, hex_addr, flags*/);
private void reg_wpt_create(/*wpt_num, reg_name, flags*/);
private void get_wpt_flags(/*wpt_flags, flags, cur_char, value_len*/);
private void get_wpt_low(/*wpt_flags, flags,cur_char,value_len,type_pos*/);
private void get_wpt_high(/*wpt_flags,flags,cur_char,value_len,type_pos*/);
private void get_wpt_mask(/*wpt_flags,flags,cur_char,value_len,type_pos*/);
private void check_wpt_type(/*wpt_flags, flag*/);
private void give_mem_wpt_default_values(/*wpt_flags*/);
private void give_reg_wpt_default_values(/*wpt_flags*/);
private void mem_wpt_print(/*wpt_num, wc_cmd*/);
private void reg_wpt_print(/*wpt_num, wc_cmd*/);
private void wp_add_flags(/*wpt_flags, wc_cmd, mem_wc, cur_char*/);
private void mem_wpt_delete(/*wpt_num*/);
private void reg_wpt_delete(/*wpt_num*/);
private void get_bpt_options(/*flags, bpt_num*/);
private int get_count_flag(/*count, flags, count_specified*/);
private int check_bpt_condition(/* bpt_num */);

/*
 * Symbols thats points to a BPT instructions.
 * used for return from BEGIN and CALL commands.
 *
 * Actully they are defined in cpu_ext.c 
 */
 
extern void call_bpt__();
extern void begin_bpt__();


/*^L*/
/*-----------------------------------------------------------------------------
 *
 *                       Remove_sw_bpt__()
 *
 * This function removes the software breakpoints upon return to monitor time.
 *
 *---------------------------------------------------------------------------*/

public void remove_sw_bpt__()
{
    int      i;
    boolean  available;

    for (i = 0; i < SW_BPT_NUM; i++) {
        if (sw_bpt[i].active) {
            mem_write__(BPT_INST_SIZE,  sw_bpt[i].addr, sw_bpt[i].contents,
                        TRUE);
            invalidate_cache__('I', FALSE, "", sw_bpt[i].addr, &available);
        }
    }

} /* remove_sw_bpt__ */



/*----------------------------------------------------------------------------
 *
 *               Place_back_sw_bpt__(user_pc, bpt_on_pc)
 *
 * This function restores the software breakpoints before return to the user
 * program. If a software breakpoint exists on the current pc, it is not 
 * restored. It will be restored after it is stepped over,and bpt_on_pc is set
 * true.
 *
 *---------------------------------------------------------------------------*/
public void place_back_sw_bpt__(user_pc, bpt_on_pc)
    address user_pc;
    boolean *bpt_on_pc;
{
    int      i;
    boolean  available;
    unsigned instr;
    

    *bpt_on_pc = FALSE;
    for (i = SW_BPT_NUM - 1; i >= 0; i--) {
        if (sw_bpt[i].active) {
            mem_read__(BPT_INST_SIZE, sw_bpt[i].addr, &instr);
            if (instr != BPT_CMD) {
                sw_bpt[i].contents = instr;
                if (sw_bpt[i].addr != user_pc) {
                    mem_write__(BPT_INST_SIZE, sw_bpt[i].addr, BPT_CMD, TRUE);
                    invalidate_cache__('I', FALSE, "", sw_bpt[i].addr,
		                         &available);
                }
                else {
                    *bpt_on_pc = TRUE;
                    bin_stepped_pc__ = (unsigned) sw_bpt[i].addr;
                }
            }
        }
    }

} /* place_back_sw_bpt__ */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *                       Check_sw_bpt__()
 *
 * This function checks the cause of the software breakpoint. It might be a
 * regular breakpoint, a breakpoint signaling the return from a call (JSR/CXP)
 * or a return from the users program (Begin).
 * It writes the appropriate message.
 *
 * Return value TRUE - if SW BPT was found 
 *              FALSE - otherwise
 *
 *---------------------------------------------------------------------------*/

public boolean check_sw_bpt__(trace_mode)
boolean trace_mode;
{
    unsigned i, user_psr;
    address         bin_pc;
    s_str        line;
    unsigned        inst;
    boolean available;

    /*
     * Get the current PC
     */

    get_reg_val__(&PC__, &bin_pc);    

    /*
     * "Disasemble" instruction of current pc to check for bpt instruction
     */
     mem_read__(BPT_INST_SIZE, bin_pc, &inst);
     if (inst != BPT_CMD) {
        return FALSE;
     }
     
    /*
     * Go over all the software breakpoints and check if they are active.
     * If so, check the address they are placed on. If triggered, a message 
     * is written.
     */

    for (i = 0; i <= SW_BPT_NUM; i++) {
        if (sw_bpt[i].active) {
            if (sw_bpt[i].addr == bin_pc) {
		/*
		 * Now check the breakpoint counter & condition expression
		 */
		if (check_bpt_condition(i)) {
		    /*
		     * Don't resume the execution if we are called from the
		     * trace routine
		     */
		    if (trace_mode)
			return FALSE;

		    /*
		     * Resume program execution
		     */

		    mem_write__(BPT_INST_SIZE, sw_bpt[i].addr, 
			sw_bpt[i].contents,  TRUE);
		    invalidate_cache__('I', FALSE,  "", sw_bpt[i].addr, 
			&available);
		    bin_stepped_pc__ = (unsigned) sw_bpt[i].addr;

		    get_reg_val__(&PSR__,  &user_psr);
		    SET_BIT(PSR_T,  user_psr);
		    trace_mode__ = STEP_BEFORE_GO;
		    put_reg_val__(&PSR__,  &user_psr);
		    exec_mode__ = USER_TIME;
		    leave_cmon__();
		}
		else {
                    	strcpy(line, "B ");
                    	bin_to_hex__( i, &line[2], 'B');
                        write_message__( line);
                        return TRUE;
		}
            }
        }
    }

    /*
     * Check if this is a return from call or we reached the end of the user
     * program. If so restore the users registers.
     */

    if ((bin_pc == (address) call_bpt__) AND (call_status__== CALL_ISSUED)) {
        restore_old_user_regs();
	call_status__ = BEGIN_ISSUED;
	write_message__( cxp_return__);
    }
    else  if ((bin_pc == (address) begin_bpt__) AND 
	      (call_status__ != NO_CALL_ISSUED)){
        restore_old_user_regs();
	call_status__ = NO_CALL_ISSUED;
	write_message__( program_end__);
    }
    else {
        write_message__(e_non_cmon_bpt__);
    }
    return TRUE;

} /* check_sw_bpt__ */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *                        Restore_old_user_regs()
 *
 * This function restors the users PC, MOD, SB, IS, and US to their values
 * before the BEGIN/JSR/CXP. Their values might have been ruined by the called
 * routine.
 *
 *---------------------------------------------------------------------------*/

#if (CORE_TYPE != SF)
private void restore_old_user_regs()
{

    
    put_reg_val__(&PC__, &old_user_pc__);
    put_reg_val__(&MO__,  &old_user_mod__);
    put_reg_val__(&SB__, &old_user_sb__);
    put_reg_val__(&IS__, &old_user_is__);
    put_reg_val__(&US__, &old_user_us__);

} /* restore_old_user_regs */
#else  /* CORE_TYPE == SF */

private void restore_old_user_regs()
{

    
    put_reg_val__(&PC__, &old_user_pc__);
    put_reg_val__(call_link_regp__, &old_user_gen_reg__);

} /* restore_old_user_regs */

#endif 

/*-----------------------------------------------------------------------------
 *
 *           Check_wpt__()
 *
 * This function checks the watchpoints to see if any of them was triggered
 * (their conditions is true). It returns an appropriate indication.
 * Only first watchpoint that is triggered is reported
 *
 *---------------------------------------------------------------------------*/

public boolean  check_wpt__()
{
    boolean  found;

    /*
     * Check the watchpoints.
     */

    found = check_wpt_array('M') OR check_wpt_array('R');


    return found;

} /* check_wpt__ */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *         Check_wpt_array()
 *
 * This function checks the specified watchpoints to see if any of them was 
 * triggered (their condition is true). It returns an appropriate indication.
 * 
 * The function sends indication to the use only for the first watchpoint 
 * that was triggerd and return to the caller.
 *---------------------------------------------------------------------------*/

private boolean check_wpt_array(arg_type)
    char      arg_type;

{
    quad_word value;
    unsigned  i, cur_char;
    boolean   cur_wpt_triggered;
    s_str     line;
    wpt_entry *wpta;

    /*
     * initialize variable according to reg_wpt
     */
     
    if (arg_type == 'R') {
	wpta = reg_wpt;
    }
    else {
	wpta = mem_wpt;
    }
    
    /*
     * Go over all the register watchpoints and check if they are active.
     * If so, the memory value is read and masked. Then according to the 
     * watchpoint type, the value is compared to the low and high limits. 
     * If triggered, a message is written.
     */

    for (i = 0; i < WPT_NUM; i++) {
        if (wpta[i].active) {
            cur_wpt_triggered = TRUE;
	    if (arg_type == 'R') {
		get_reg_val__(wpta[i].reg, value);
	    }
	    else {
		value[1] = 0;
		mem_read__(wpta[i].width, wpta[i].addr, value);
	    }
            value[0] &= wpta[i].mask_value[0];
            value[1] &= wpta[i].mask_value[1];
            switch (wpta[i].type) {
                case UNTIL:
                    if ((quad_compare__(value,wpta[i].low_value) == (-1)) 
                        OR
                    (quad_compare__(value, wpta[i].high_value) == 1)){
                            cur_wpt_triggered = FALSE;
                    }
                    break;
                case WHILE:
                    if ((quad_compare__(value,wpta[i].low_value) != (-1))
                        AND
                    (quad_compare__(value, wpta[i].high_value) != 1)){
                        cur_wpt_triggered = FALSE;
                    }
            }
            if (cur_wpt_triggered) {
                /* 
                 * @old_spec@
                 * ADD Test if watchpoint num is WPT_NUM - 1 it is used
                 * to emulate old specs  STEP WHILE/UNTIL commands. 
                 * if so emit "B TRC" and delete the watchpoint
                 */
                if (i == WPT_NUM - 1) {
                    write_message__( step_ended__);
		    wpta[i].active = FALSE;
                    active_wpt__ = FALSE;
                }
                else {
                    strcpy(line, "W ");
		    line[2] = arg_type;
                    bin_to_hex__( i, &line[3], 'D');
                    cur_char = strlen(line);
                    line[cur_char] = ' ';
                    quad_to_hex__( value, &line[cur_char+1]);
                    write_message__( line);
                }
                return TRUE;
            }
        } /* if (wpta[i].active) */
    } /* for (i = 0; i <= WPT_NUM; i++) */
    return FALSE;

} /* check_wpt_array */


/*^L*/
#ifdef NEW_SPEC
/*-----------------------------------------------------------------------------
 *
 *                    Bc_decode__(cmd, response)
 *
 * This function decodes the breakpoint create command.
 *
 *---------------------------------------------------------------------------*/

public void bc_decode__(cmd, response)
    str      cmd, response;
{ 
    boolean  err;
    unsigned bpt_num, len, cur_char;
    s_str    hex_addr, hex_bpt_num;

    response[0] = '\0';

    /*
     * Get the breakpoint number
     */

    cur_char = 4;
    get_first_arg__(&cmd[cur_char], hex_bpt_num, &len, S_SIZE,
                    /* accept null arg = */ FALSE);
    cur_char += len;
    hex_to_bin__( hex_bpt_num, &bpt_num, 'D');
    if (cmd[cur_char] == ' ') {
        cur_char++;
    }
    if (cmd[cur_char] != ',') {
	ERROR(e_syntax__);
    }
    
    /*
     * Get the address
     */

    get_first_arg__(&cmd[cur_char], hex_addr, &len, S_SIZE,
                   /* accept null arg */ FALSE);
    cur_char += len;

    /*
     * Check the breakpoint kind
     */

    switch (cmd[3]) {
#ifdef MMU_SUPPORT
        case 'H':
            hw_bpt_create(bpt_num, hex_addr, &cmd[cur_char]);
#endif
        case 'S':
            sw_bpt_create(bpt_num, hex_addr, &cmd[cur_char]);
        default :
            ERROR( e_syntax__);
    }

} /* bc_decode__ */
#endif /* NEW_SPEC */
/*^L*/
/*-----------------------------------------------------------------------------
 *
 *             Sw_bpt_create(bpt_num, hex_addr, flags)
 *
 * This function executes the software breakpoint create command.
 *
 *---------------------------------------------------------------------------*/

private void sw_bpt_create(bpt_num, hex_addr, flags)
    unsigned bpt_num;
    str      hex_addr, flags;
{ 
    unsigned  len, count;
    address  addr;
    boolean  count_specified,err;

    /*
     * Check if the breakpoint number requested is legal
     */

    if (bpt_num > SW_BPT_NUM - 1) {
	ERROR(e_syntax__);
    }

    hex_to_bin__(hex_addr, &addr, 'D');
    /*
     * Get the count & condition options
     */

#ifdef OLD
    get_count_flag(&count, flags, &count_specified);
#endif

    get_bpt_options(flags, bpt_num);

    /*
     * Activate the breakpoint
     */

    sw_bpt[bpt_num].active          = TRUE;
    sw_bpt[bpt_num].addr            = addr;

#ifdef OLD
    sw_bpt[bpt_num].count_specified = count_specified;
    sw_bpt[bpt_num].orig_count      = count;
    sw_bpt[bpt_num].cur_count       = count;
#endif
} /* sw_bpt_create */

/*^L*/
#ifdef NEW_SPEC
/*-----------------------------------------------------------------------------
 *
 *                    Bp_decode__(cmd, response)
 *
 * This function decodes the breakpoint print command.
 *
 *---------------------------------------------------------------------------*/

public void bp_decode__(cmd, response)
    str      cmd, response;
{ 
    boolean  err;
    unsigned bpt_num, len;
    s_str    hex_bpt_num;
    l_str    bc_cmd;

    response[0] = '\0';

    /*
     * Get the breakpoint number
     */

    get_first_arg__(&cmd[4], hex_bpt_num, &len, S_SIZE,
                   /* accept null arg */ FALSE);
    if (strlen(cmd) > len+4) {
        ERROR(e_syntax__);
    }
    hex_to_bin__( hex_bpt_num, &bpt_num, 'D');

    /*
     * Check the breakpoint kind and execute the command
     */

    switch (cmd[3]) {
#ifdef        MMU_SUPPORT
        case 'H':
            hw_bpt_print(bpt_num, response);
#endif
        case 'S':
            sw_bpt_print(bpt_num, response);
        default :
            ERROR(e_syntax__);
    }

} /* bp_decode__ */
#endif  /* NEW_SPEC */
/*^L*/
#ifdef NEW_SPEC
/*-----------------------------------------------------------------------------
 *
 *             Sw_bpt_print(bpt_num, bc_cmd)
 *
 * This function receives a software brakpoint number and returns the command
 * which created it.
 *
 *---------------------------------------------------------------------------*/

private void sw_bpt_print(bpt_num, bc_cmd)
    unsigned bpt_num;
    str      bc_cmd;
{
    unsigned cur_char;
    s_str    hex_bpt_num, hex_addr, hex_count;

    /*
     * Check if the breakpoint number requested is legal, and if it's active.
     */

    if (bpt_num > SW_BPT_NUM - 1) {
        ERROR(e_syntax__);
    }

    if (NOT sw_bpt[bpt_num].active) {
        ERROR(e_bpt_undefined__);
    }

    /*
     * Start building the 'command'.
     */

    strcpy(bc_cmd, "BC S");
    bin_to_hex__( bpt_num, hex_bpt_num, 'D');
    strcpy(&bc_cmd[4], hex_bpt_num);
    cur_char = strlen(bc_cmd);
    bc_cmd[cur_char] = ',';
    cur_char++;

    /*
     * Add the address
     */

    bin_to_hex__( sw_bpt[bpt_num].addr, hex_addr, 'D');
    strcpy(&bc_cmd[cur_char], hex_addr);
    cur_char += strlen(hex_addr);

    /*
     * Add the flags
     */

    if (sw_bpt[bpt_num].count_specified) {
        bin_to_hex__( sw_bpt[bpt_num].orig_count, hex_count, 'D');
        strcpy(&bc_cmd[cur_char], " C=");
        cur_char += 3;
        strcpy(&bc_cmd[cur_char], hex_count);
    }

} /* sw_bpt_print */
#endif  /* NEW_SPEC */
/*^L*/
#ifdef NEW_SPEC 
/*-----------------------------------------------------------------------------
 *
 *                    Bd_decode__(cmd, response)
 *
 * This function decodes the breakpoint delete command.
 *
 *---------------------------------------------------------------------------*/

public void bd_decode__(cmd, response)
    str      cmd, response;
{ 
    boolean  err;
    unsigned bpt_num, len;
    s_str    hex_bpt_num;

    /*
     * Get the breakpoint number
     */

    get_first_arg__(&cmd[4], hex_bpt_num, &len, S_SIZE,
                   /* accept null arg */ FALSE);
    if (strlen(cmd) > len+4) {
        ERROR(e_syntax__);
    }
    hex_to_bin__( hex_bpt_num, &bpt_num, 'D');

    /*
     * Check the breakpoint kind and execute the command
     */

    switch (cmd[3]) {
#ifdef        MMU_SUPPORT
        case 'H':
            hw_bpt_delete(bpt_num);
#endif
        case 'S':
            sw_bpt_delete(bpt_num);
        default :
            ERROR(e_syntax__);
    }

} /* bd_decode__ */

#endif NEW_SPEC



/*-----------------------------------------------------------------------------
 *
 *             Sw_bpt_delete(bpt_num)
 *
 * This function deletes the software breakpoint requested.
 *
 *---------------------------------------------------------------------------*/

private void sw_bpt_delete(bpt_num)
    unsigned bpt_num;
{

    /*
     * Check if the breakpoint number requested is legal, and if it's active.
     */

    if (bpt_num > SW_BPT_NUM - 1) {
        ERROR(e_syntax__);
    }

    /*
     * Delete the breakpoint
     */

    sw_bpt[bpt_num].active = FALSE;
    sw_bpt[bpt_num].count_specified = FALSE;

} /* sw_bpt_delete */
/*^L*/
/*-----------------------------------------------------------------------------
 *
 *               Cbp_decode__(cmd, response)
 *
 * This function decodes the Change break point command of the old monitors
 * spec. It translate it to break point create of the new spec.
 *
 *---------------------------------------------------------------------------*/
 
public void cbp_decode__(cmd, response)
   str              cmd, response;
{
   s_str   hex_addr,bpt_name;
   unsigned bpt_num,len,cur_char,addr;
   boolean err;


    /*
     * Get the breakpoint number
     */
   cur_char = 1;
   get_first_arg__(&cmd[cur_char], bpt_name, &len,S_SIZE,
                  /* accept null arg */ FALSE);
    cur_char += (len + 1);
    hex_to_bin__( &bpt_name[2], &bpt_num, 'D');
    if (bpt_num > SW_BPT_NUM - 1) {
	ERROR(e_syntax__);
    }
    /*
     * Skip the "=" sign
     */
    if (cmd[cur_char] == '=') {
        cur_char ++;
    }
    /*
     * Get breakpoint address
     */
    get_first_arg__(&cmd[cur_char], hex_addr, &len,S_SIZE,
                  /* accept null arg */ FALSE);
    hex_to_bin__( hex_addr, &addr, 'D');
#   if  (CORE_TYPE == CG)
    /*
     * On CG core address space is 24 bit
     */
    addr &= 0xffffff;
#   endif
     /*
      * Find if to create or clear breakpoint
      */
    if (addr == 0){
        sw_bpt_delete (bpt_num);
    }
    else {
        sw_bpt_create(bpt_num, hex_addr, &cmd[cur_char + len]);
    }
} /* cbp_decode__ */


/*-----------------------------------------------------------------------------
 *
 *                    Pbp_decode__(cmd, response)
 *
 * This function decode and implement the old spec print breakpoint command.
 *
 *---------------------------------------------------------------------------*/
public void pbp_decode__(cmd, response)
    str        cmd, response;
{
    unsigned cur_char,bpt_num,len;
    s_str    bpt_name,hex_addr;
    boolean  err;
    
    /*
     * Get breakpoint number
     */
    get_first_arg__(&cmd[3], bpt_name, &len,S_SIZE,
                  /* accept null arg */ FALSE);
    hex_to_bin__( bpt_name, &bpt_num, 'D');
    if (bpt_num > SW_BPT_NUM - 1){
	ERROR(e_syntax__);
    }
    /*
     * For none active breakpoint return "= 0"
     */
    if (NOT sw_bpt[bpt_num].active){
        strcpy(response, "= 0");
        return;
    }
    bin_to_hex__( sw_bpt[bpt_num].addr, hex_addr, 'D');
    strcpy(response, "= ");
    strcpy(&response[2], hex_addr);

    if (sw_bpt[bpt_num].count_specified) {
	strcat(response, " C= ");
	bin_to_hex__( sw_bpt[bpt_num].cur_count,  hex_addr,  'D');
	strcat(response, hex_addr);
    }

    if (sw_bpt[bpt_num].wpt.active) {
	wpt_entry  * wpt= &(sw_bpt[bpt_num].wpt);

	if (wpt->type == UNTIL)
	    	strcat(response,  " U= ");
	else
	    	strcat(response,  " W= ");

	if (wpt->reg != NULL) {
		strcat(response, wpt->reg->name);
	}
	else {
		bin_to_hex__(wpt->addr,   hex_addr,   'D');
		strcat(response, hex_addr);
	}

	strcat(response,   " ");
	quad_to_hex__(wpt->low_value, hex_addr);
	strcat(response,  hex_addr);

	strcat(response,   " ");
	quad_to_hex__(wpt->high_value, hex_addr);
	strcat(response,  hex_addr);

	if (wpt->mask_specified) {
		strcat(response,   " ");
		quad_to_hex__(wpt->mask_value, hex_addr);
		strcat(response,  hex_addr);
	}
    }

} /* pbp_decode__ */
    
/*^L*/
#ifdef NEW_SPEC
/*-----------------------------------------------------------------------------
 *
 *                    Wc_decode__(cmd, response)
 *
 * This function decodes the watchpoint create command.
 *
 *---------------------------------------------------------------------------*/

public void wc_decode__(cmd, response)
    str      cmd, response;
{ 
    boolean  err;
    unsigned wpt_num, len, cur_char;
    s_str    hex_addr, hex_wpt_num;

    response[0] = '\0';

    /*
     * Get the watchpoint number
     */

    cur_char = 4;
    get_first_arg__(&cmd[cur_char], hex_wpt_num, &len, S_SIZE,
                   /* accept null arg */ FALSE);
    cur_char += len;
    hex_to_bin__( hex_wpt_num, &wpt_num, 'D');
    if (cmd[cur_char] == ' ') {
        cur_char++;
    }
    if (cmd[cur_char] != ',') {
        ERROR(e_syntax__);
    }
    
    /*
     * Get the address/reg
     */

    get_first_arg__(&cmd[cur_char], hex_addr, &len, S_SIZE,
                   /* accept null arg */ FALSE);
    cur_char += len;

    /*
     * Check the watchpoint kind
     */

    switch (cmd[3]) {
        case 'M':
            mem_wpt_create(wpt_num, hex_addr, &cmd[cur_char]);
        case 'R':
            reg_wpt_create(wpt_num, hex_addr, &cmd[cur_char]);
        default :
            ERROR(e_syntax__);
    }

} /* wc_decode__ */
#endif /* NEW_SPEC */
/*^L*/
#ifdef NEW_SPEC
/*-----------------------------------------------------------------------------
 *
 *             Mem_wpt_create(wpt_num, hex_addr, flags)
 *
 * This function executes the memory watchpoint create command.
 *
 *---------------------------------------------------------------------------*/

private void mem_wpt_create(wpt_num, hex_addr, flags)
    unsigned  wpt_num;
    str       hex_addr, flags;
{ 
    unsigned  len, cur_char;
    boolean   err;
    wpt_entry wpt_flags;
    s_str     width_char;

    /*
     * Check if the watchpoint number requested is legal
     */

    if (wpt_num > WPT_NUM - 1) {
        ERROR(e_syntax__);
    }

    /*
     * Translate the addresses to binary. 
     */
    hex_to_bin__( hex_addr, &wpt_flags.addr, 'D');

    /*
     * Get the low and high limits and the watchpoint type
     */
    get_wpt_flags(wpt_flags, flags, &cur_char, 8);

    /*
     * Get the width
     */

    get_first_arg__(&flags[cur_char], width_char, &len, S_SIZE,
                   /* accept null arg */ FALSE);
    if (strlen(width_char) > 1) {
        ERROR(e_syntax__);
    }
    cur_char += len;
    if (strchr("BWD", width_char[0]) == (char *) NULL) {
        ERROR(e_syntax__);
    }
    wpt_flags.width = width_char[0];

    /*
     * Get the count flag
     */

    get_count_flag(&wpt_flags.orig_count, flags, &wpt_flags.count_specified);
    wpt_flags.cur_count = wpt_flags.orig_count;

    /*
     * Give unspecified parameters their default values.
     * Activate the watchpoint, and signal that there is an active watchpoint.
     */

    give_mem_wpt_default_values(wpt_flags);
    mem_wpt[wpt_num] = wpt_flags;
    mem_wpt[wpt_num].active = TRUE;
    active_wpt__ = TRUE;

} /* mem_wpt_create */
#endif /* NEW_SPEC */
/*^L*/
#ifdef NEW_SPEC
/*-----------------------------------------------------------------------------
 *
 *             Reg_wpt_create(wpt_num, reg_name, flags)
 *
 * This function executes the register watchpoint create command.
 *
 *---------------------------------------------------------------------------*/

private void reg_wpt_create(wpt_num, reg_name, flags)
    unsigned  wpt_num;
    str       reg_name, flags;
{ 
    unsigned  cur_char;
    boolean   found;
    wpt_entry wpt_flags;

    /*
     * Check if the watchpoint number requested is legal
     */

    if (wpt_num > WPT_NUM - 1) {
        ERROR(e_syntax__);
    }

    /*
     * Translate the register name to enumerated. 
     */

    reg_name_to_enum__(&wpt_flags.reg, reg_name, &found);
    if (NOT found) {
        ERROR(e_syntax__);
    }

    /*
     * Get the low and high limits and the watchpoint type
     */

    if ((wpt_flags.reg >= L0) AND (wpt_flags.reg <= L7)) {
        get_wpt_flags(wpt_flags, flags, &cur_char, 16);
    }
    else {
        get_wpt_flags(wpt_flags, flags, &cur_char, 8);
    }

    /*
     * Get the count flag
     */

    get_count_flag(&wpt_flags.orig_count, flags, &wpt_flags.count_specified);
    wpt_flags.cur_count = wpt_flags.orig_count;

    /*
     * Give unspecified parameters their default values.
     * Activate the watchpoint, and signal that there is an active watchpoint.
     */

    give_reg_wpt_default_values(wpt_flags);
    reg_wpt[wpt_num] = wpt_flags;
    reg_wpt[wpt_num].active = TRUE;
    active_wpt__ = TRUE;

} /* reg_wpt_create */
#endif /* NEW_SPEC */
/*^L*/
#ifdef NEW_SPEC
/*-----------------------------------------------------------------------------
 *
 *          Get_wpt_flags(wpt_flags, flags, cur_char, value_len)
 *
 * This function checks which of the low, high, mask and type flags were
 * specified in flags. The result and value of each flag is returned in
 * wpt_flags. Cur_char will point to the first character after these flags.
 * Value_len specifies the maximum legal length of the value.
 *
 *---------------------------------------------------------------------------*/

private void get_wpt_flags(wpt_flags, flags, cur_char, value_len)
    wpt_entry wpt_flags;
    str       flags;
    unsigned  *cur_char;
    unsigned  value_len;
{ 
    unsigned  type_pos, len;
    s_str     flag;
    boolean   err;

    *cur_char = 0;
    wpt_flags.low_specified  = FALSE;
    wpt_flags.high_specified = FALSE;
    wpt_flags.mask_specified = FALSE;

    /*
     * Find the position of the type flag ('U' or 'W'). There must be one and 
     * only one type flag.
     */

    /*
     *        type_pos = strcspn(flags, "UW");
     */
    for(type_pos = 0; strchr("UW",flags[type_pos])  == (char *) NULL; 
        type_pos++)
        ;
    if (type_pos == strlen(flags)) {
        ERROR(e_syntax__);
    }

    /*
     * Check if low limit was specified
     */

    get_wpt_low(wpt_flags, flags, cur_char, value_len, type_pos);
    if (NOT wpt_flags.low_specified) {
        return;
    }

    /*
     * Check if high limit was specified
     */

    get_wpt_high(wpt_flags, flags, cur_char, value_len, type_pos);
    if (NOT wpt_flags.high_specified) {
        return;
    }

    /*
     * Check if mask was specified
     */

    get_wpt_mask(wpt_flags, flags, cur_char, value_len, type_pos);
    if (NOT wpt_flags.mask_specified) {
        return;
    }

    /*
     * Check if type was specified
     */

    get_first_arg__(&flags[*cur_char], flag, &len, S_SIZE,
                   /* accept null arg */ TRUE);
    *cur_char += len;

    check_wpt_type(wpt_flags, flag);

} /* get_wpt_flags */
#endif /* NEW_SPEC */
/*^L*/
#ifdef NEW_SPEC
/*-----------------------------------------------------------------------------
 *
 *    Get_wpt_low(wpt_flags, flags, cur_char, value_len, type_pos)
 *
 * This function checks if the low flag was specified in flags. The result and
 * value are returned in wpt_flags. Cur_char will point to the first character
 * after the flag.
 * Value_len specifies the maximum legal length of the value.
 *
 *---------------------------------------------------------------------------*/

private void get_wpt_low(wpt_flags, flags,cur_char,value_len,type_pos)
    wpt_entry wpt_flags;
    str       flags;
    unsigned  *cur_char;
    unsigned  value_len, type_pos;
{ 
    unsigned  len;
    s_str     flag;
    boolean   err;

    get_first_arg__(&flags[*cur_char], flag, &len, S_SIZE,
                   /* accept null arg */ TRUE);
    if (strlen(flag) > value_len) {
        ERROR(e_syntax__);
    }
    *cur_char += len;

    if (*cur_char > type_pos) {
        check_wpt_type(wpt_flags, flag);
        return;
    }

    if (len == 0) {
        return;
    }

    wpt_flags.low_specified = TRUE;

    hex_to_quad__( flag, wpt_flags.low_value);
} /* get_wpt_low */





/*-----------------------------------------------------------------------------
 *
 *    Get_wpt_high(wpt_flags, flags, cur_char, value_len, type_pos)
 *
 * This function checks if the high flag was specified in flags. The result and
 * value are returned in wpt_flags. Cur_char will point to the first character
 * after the flag.
 * Value_len specifies the maximum legal length of the value.
 *
 *---------------------------------------------------------------------------*/

private void get_wpt_high(wpt_flags,flags,cur_char,value_len,type_pos)
    wpt_entry wpt_flags;
    str       flags;
    unsigned  *cur_char;
    unsigned  value_len, type_pos;
{ 
    unsigned  len;
    s_str     flag;
    boolean   err;

    get_first_arg__(&flags[*cur_char], flag, &len, S_SIZE,
                   /* accept null arg */ TRUE);
    if (strlen(flag) > value_len) {
        ERROR(e_syntax);
    }
    *cur_char += len;

    if (*cur_char > type_pos) {
        check_wpt_type(wpt_flags, flag);
        return;
    }

    if (len == 0) {
        return;
    }

    wpt_flags.high_specified = TRUE;

    hex_to_quad__( flag, wpt_flags.high_value);
} /* get_wpt_high */
#endif /* NEW_SPEC */
/*^L*/
#ifdef NEW_SPEC
/*-----------------------------------------------------------------------------
 *
 *    Get_wpt_mask(wpt_flags, flags, cur_char, value_len, type_pos)
 *
 * This function checks if the mask flag was specified in flags. The result and
 * value are returned in wpt_flags. Cur_char will point to the first character
 * after the flag.
 * Value_len specifies the maximum legal length of the value.
 *
 *---------------------------------------------------------------------------*/

private void get_wpt_mask(wpt_flags,flags,cur_char,value_len,type_pos)
    wpt_entry wpt_flags;
    str       flags;
    unsigned  *cur_char;
    unsigned  value_len, type_pos;
{ 
    unsigned  len;
    s_str     flag;
    boolean   err;

    get_first_arg__(&flags[*cur_char], flag, &len, S_SIZE,
                   /* accept null arg */ TRUE);
    if (strlen(flag) > value_len) {
	ERROR(e_syntax__);
    }
    *cur_char += len;

    if (*cur_char > type_pos) {
        check_wpt_type(wpt_flags, flag);
        return;
    }

    if (len == 0) {
        return;
    }

    wpt_flags.mask_specified = TRUE;

    hex_to_quad__( flag, wpt_flags.mask_value);
} /* get_wpt_mask */





/*-----------------------------------------------------------------------------
 *
 *         Check_wpt_type(wpt_flags, flag)
 *
 * This function checks if the flag is a legal type flag and gets its value.
 *
 *---------------------------------------------------------------------------*/

private void check_wpt_type(wpt_flags, flag)
    wpt_entry wpt_flags;
    str       flag;
{ 

    if (strlen(flag) > 1) {
        ERROR(e_syntax__);
    }

    switch (flag[0]) {
        case 'U':
            wpt_flags.type = UNTIL;
            return;
        case 'W':
            wpt_flags.type = WHILE;
            return;
        default:
            ERROR(e_syntax__);
    }

} /* check_wpt_type */
#endif /* NEW_SPEC */
/*^L*/
#ifdef NEW_SPEC
/*-----------------------------------------------------------------------------
 *
 *                  Give_mem_wpt_default_values(wpt_flags)
 *
 * This function gives default values to the memory watchpoint flags which 
 * weren't specified. 
 *
 *---------------------------------------------------------------------------*/

private void give_mem_wpt_default_values(wpt_flags)
    wpt_entry wpt_flags;
{
    if (NOT wpt_flags.low_specified) {
        mem_read__(wpt_flags.width, wpt_flags.addr, wpt_flags.low_value);
    }
    if (NOT wpt_flags.high_specified) {
        wpt_flags.high_value[0] = wpt_flags.low_value[0];
    }
    if (NOT wpt_flags.mask_specified) {
        wpt_flags.mask_value[0] = MAX_UINT;
    }

    /*
     * Ajust the values according to the width. No need to ajust in double word
     */

    switch (wpt_flags.width) {
        case 'B':
            wpt_flags.low_value[0]  &= MAX_UBYTE;
            wpt_flags.high_value[0] &= MAX_UBYTE;
            wpt_flags.mask_value[0] &= MAX_UBYTE;
            break;
        case 'W':
            wpt_flags.low_value[0]  &= MAX_UWORD;
            wpt_flags.high_value[0] &= MAX_UWORD;
            wpt_flags.mask_value[0] &= MAX_UWORD;
    }

} /* give_mem_wpt_default_values */





/*-----------------------------------------------------------------------------
 *
 *            Give_reg_wpt_default_values(wpt_flags)
 *
 * This function gives default values to the register watchpoint flags which 
 * weren't specified.
 *
 *---------------------------------------------------------------------------*/

private void give_reg_wpt_default_values(wpt_flags)
    wpt_entry wpt_flags;
{
    if (NOT wpt_flags.low_specified) {
        reg_read(wpt_flags.reg, wpt_flags.low_value);
    }
    if (NOT wpt_flags.high_specified) {
        wpt_flags.high_value[0] = wpt_flags.low_value[0];
        wpt_flags.high_value[1] = wpt_flags.low_value[1];
    }
    if (NOT wpt_flags.mask_specified) {
        wpt_flags.mask_value[0] = MAX_UINT;
        wpt_flags.mask_value[1] = MAX_UINT;
    }

} /* give_reg_wpt_default_values */
#endif /* NEW_SPEC */
/*^L*/
#ifdef NEW_SPEC
/*-----------------------------------------------------------------------------
 *
 *                    Wp_decode__(cmd, response)
 *
 * This function decodes the watchpoint print command.
 *
 *---------------------------------------------------------------------------*/

public void wp_decode__(cmd, response)
    str      cmd, response;
{ 
    boolean  err;
    unsigned wpt_num, len;
    s_str    hex_wpt_num;

    response[0] = '\0';

    /*
     * Get the watchpoint number
     */

    get_first_arg__(&cmd[4], hex_wpt_num, &len, S_SIZE,
                   /* accept null arg */ FALSE);
    if (strlen(cmd) > len+4) {
	ERROR(e_syntax__);
    }
    hex_to_bin__( hex_wpt_num, &wpt_num, 'D');

    /*
     * Check the watchpoint kind and execute the command
     */

    switch (cmd[3]) {
        case 'M':
            mem_wpt_print(wpt_num,  response);
        case 'R':
            reg_wpt_print(wpt_num,  response);
        default :
            ERROR(e_syntax__);
    }

} /* wp_decode__ */
#endif /* NEW_SPEC */
/*^L*/
#ifdef NEW_SPEC
/*-----------------------------------------------------------------------------
 *
 *             Mem_wpt_print(wpt_num, wc_cmd)
 *
 * This function receives a memory watchpoint number and returns the command
 * which created it.
 *
 *---------------------------------------------------------------------------*/

private void mem_wpt_print(wpt_num, wc_cmd)
    unsigned wpt_num;
    str      wc_cmd;
{
    unsigned cur_char;
    s_str    hex_addr;

    /*
     * Check if the watchpoint number requested is legal, and if it's active.
     */

    if (wpt_num > WPT_NUM - 1) {
        ERROR(e_syntax__);
    }

    if (NOT mem_wpt[wpt_num].active) {
        ERROR(e_wpt_undefined__);
    }

    /*
     * Start building the 'command'.
     */

    strcpy(wc_cmd, "WC M");
    bin_to_hex__( wpt_num, &wc_cmd[4], 'D');
    cur_char = strlen(wc_cmd);
    wc_cmd[cur_char] = ',';
    cur_char++;

    /*
     * Add the address
     */

    bin_to_hex__( mem_wpt[wpt_num].addr, hex_addr, 'D');
    strcpy(&wc_cmd[cur_char], hex_addr);
    cur_char += strlen(hex_addr);

    /*
     * Add the flags and width
     */

    wp_add_flags(mem_wpt[wpt_num], wc_cmd, TRUE, cur_char);

} /* mem_wpt_print */
#endif /* NEW_SPEC */
/*^L*/
#ifdef NEW_SPEC
/*-----------------------------------------------------------------------------
 *
 *             Reg_wpt_print(wpt_num, wc_cmd)
 *
 * This function receives a register watchpoint number and returns the command
 * which created it.
 *
 *---------------------------------------------------------------------------*/

private void reg_wpt_print(wpt_num, wc_cmd)
    unsigned wpt_num;
    str      wc_cmd;
{
    unsigned cur_char;
    s_str    reg_name;

    /*
     * Check if the watchpoint number requested is legal, and if it's active.
     */

    if (wpt_num > WPT_NUM - 1) {
        ERROR(e_syntax__);
    }

    if (NOT reg_wpt[wpt_num].active) {
        ERROR(e_wpt_undefined__);
    }

    /*
     * Start building the 'command'.
     */

    strcpy(wc_cmd, "WC R");
    bin_to_hex__( wpt_num, &wc_cmd[4], 'D');
    cur_char = strlen(wc_cmd);
    wc_cmd[cur_char] = ',';
    cur_char++;

    /*
     * Add the register name
     */

    reg_enum_to_name__(reg_name, reg_wpt[wpt_num].reg);
    strcpy(&wc_cmd[cur_char], reg_name);
    cur_char = strlen(wc_cmd);

    /*
     * Add the flags 
     */

    wp_add_flags(reg_wpt[wpt_num], wc_cmd, FALSE, cur_char);

} /* reg_wpt_print */
#endif /* NEW_SPEC */
/*^L*/
#ifdef NEW_SPEC
/*-----------------------------------------------------------------------------
 *
 *              Wp_add_flags(wpt_flags, wc_cmd, mem_wc, cur_char)
 *
 * This function receives a watchpoint structure and the begining of the 
 * command which created it. It adds the low, high and mask flags to the 
 * creation command. If mem_wc = TRUE it also adds the width flag.
 * The count flag is added last.
 * Cur_char is the current position in the creation command line.
 *
 *---------------------------------------------------------------------------*/

private void wp_add_flags(wpt_flags, wc_cmd, mem_wc, cur_char)
    wpt_entry wpt_flags;
    str       wc_cmd;
    boolean   mem_wc;
    unsigned  cur_char;
{
    s_str     hex_value;

    if (wpt_flags.low_specified) {
        if (mem_wc){
            bin_to_hex__( wpt_flags.low_value[0], hex_value, 'D');
        }
        else {
            quad_to_hex__( wpt_flags.low_value, hex_value);
        }
        strcpy(&wc_cmd[cur_char], " ");
        strcpy(&wc_cmd[cur_char+1], hex_value);
        cur_char = strlen(wc_cmd);
    }

    if (wpt_flags.high_specified) {
        if (mem_wc){
            bin_to_hex__( wpt_flags.high_value[0], hex_value, 'D');
        }
        else {
            quad_to_hex__( wpt_flags.high_value, hex_value);
        }
        strcpy(&wc_cmd[cur_char], " ");
        strcpy(&wc_cmd[cur_char+1], hex_value);
        cur_char = strlen(wc_cmd);
    }

    if (wpt_flags.mask_specified) {
        if (mem_wc){
            bin_to_hex__( wpt_flags.mask_value[0], hex_value, 'D');
        }
        else {
            quad_to_hex__( wpt_flags.mask_value, hex_value);
        }
        strcpy(&wc_cmd[cur_char], " ");
        strcpy(&wc_cmd[cur_char+1], hex_value);
        cur_char = strlen(wc_cmd);
    }

    if (mem_wc) {
        wc_cmd[cur_char] = wpt_flags.width;
        cur_char++;
        wc_cmd[cur_char] = '\0';
    }

    if (wpt_flags.count_specified) {
        bin_to_hex__( wpt_flags.orig_count, hex_value, 'D');
        strcpy(&wc_cmd[cur_char], " C=");
        cur_char += 3;
        strcpy(&wc_cmd[cur_char], hex_value);
    }

} /* wp_add_flags */
#endif /* NEW_SPEC */
/*^L*/
#ifdef NEW_SPEC
/*-----------------------------------------------------------------------------
 *
 *                    Wd_decode__(cmd, response)
 *
 * This function decodes the watchpoint delete command.
 *
 *---------------------------------------------------------------------------*/

public void wd_decode__(cmd, response)
    str      cmd, response;
{ 
    boolean  err;
    unsigned wpt_num, len, i;
    s_str    hex_wpt_num;

    /*
     * Get the watchpoint number
     */

    get_first_arg__(&cmd[4], hex_wpt_num, &len, S_SIZE,
                   /* accept null arg */ FALSE);
    if (strlen(cmd) > len+4) {
	ERROR(e_syntax__);
    }
    hex_to_bin__( hex_wpt_num, &wpt_num, 'D');

    /*
     * Check the watchpoint kind and execute the command
     */

    switch (cmd[3]) {
        case 'M':
            mem_wpt_delete(wpt_num);
        case 'R':
            reg_wpt_delete(wpt_num);
        default :
            ERROR(e_syntax__);
    }

    /*
     * Check if there still is an active watchpoint
     */

    for (i = 0; i < WPT_NUM; i++) {
        if (mem_wpt[i].active) {
            return;
        }
    }
    for (i = 0; i < WPT_NUM; i++) {
        if (reg_wpt[i].active) {
            return;
        }
    }

    active_wpt__ = FALSE;

} /* wd_decode__ */
#endif /* NEW_SPEC */
/*^L*/
#ifdef NEW_SPEC
/*-----------------------------------------------------------------------------
 *
 *                 Mem_wpt_delete(wpt_num)
 *
 * This function deletes the memory watchpoint requested.
 *
 *---------------------------------------------------------------------------*/

private void mem_wpt_delete(wpt_num)
    unsigned wpt_num;
{

    /*
     * Check if the watchpoint number requested is legal, and if it's active.
     */

    if (wpt_num > WPT_NUM - 1) {
        ERROR(e_syntax__);
    }

    if (NOT mem_wpt[wpt_num].active) {
        ERROR(e_wpt_undefined__);
    }

    /*
     * Delete the watchpoint
     */

    mem_wpt[wpt_num].active = FALSE;

} /* mem_wpt_delete */





/*-----------------------------------------------------------------------------
 *
 *                 Reg_wpt_delete(wpt_num)
 *
 * This function deletes the register watchpoint requested.
 *
 *---------------------------------------------------------------------------*/

private void reg_wpt_delete(wpt_num)
    unsigned wpt_num;
{

    /*
     * Check if the watchpoint number requested is legal, and if it's active.
     */

    if (wpt_num > WPT_NUM - 1) {
        ERROR(e_syntax__);
    }

    if (NOT reg_wpt[wpt_num].active) {
        ERROR(e_wpt_undefined__);
    }

    /*
     * Delete the watchpoint
     */

    reg_wpt[wpt_num].active = FALSE;

} /* mem_wpt_delete */
#endif /* NEW_SPEC */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *        Get_count_flag(count, flags, count_specified);
 *
 * This function checks flags to see if it contains a legal count flag. If so,
 * it returns the count and signals it is specified. If flags is empty a 
 * default 1 is returned.
 *
 *---------------------------------------------------------------------------*/

private int get_count_flag(count, flags, count_specified)
    unsigned *count;
    str      flags;
    boolean  *count_specified;
{ 
    unsigned cur_char, len;
    s_str    count_flag, hex_count;
    boolean  err;

    /*
     * Check if count was specified
     */

    if (flags[0] == '\0') {
        *count = 1;
        *count_specified = FALSE;
        return 0;
    }
    /*
     * Get the count flag
     */
    cur_char = 0;
    if (flags[cur_char] == ' ') {
        cur_char++;
    }
    switch (flags[cur_char]) {
	case 'C':
		cur_char++;
		break;
	case 'U':
	case 'W':
		*count = 1;
		*count_specified = FALSE;
		return 0;
	default:
		ERROR(e_syntax__);
    }

    if (flags[cur_char] == ' ') {
        cur_char++;
    }
    if (flags[cur_char] != '=') {
        ERROR(e_syntax__);
    }
    cur_char++;

    get_first_arg__(&flags[cur_char], hex_count, &len, S_SIZE,
                   /* accept null arg */ FALSE);

    hex_to_bin__( hex_count, count, 'D');

    *count_specified = TRUE;

    return cur_char + len;
} /* get_count_flag */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *        Get_bpt_options(flags,  bpt_num);
 *
 * This function parse the create breakpoint command options.
 * The syntax for this command is :
 *          CBPn1 =  addr    [C=n2]     [{WU}=var x1 x2 x3]
 *
 *      where :
 *          n1 is the breakpoint number 2-f
 *          n2 is the ignore counter 0 - 2^16
 *	    U mean ignore breakpoint until condition
 *	    W mean ignore breakpoint while condition
 *          var is  {M{B|W|D} addr | reg | sreg}
 *          x1  is the lower bound
 *          x2  is the upper bound
 *          x3  is a mask
 *
 *
 * Note that,  the order of the options is significant. The C option
 
 * flags is a pointer to the first option in the user command string.
 *---------------------------------------------------------------------------*/

private void get_bpt_options(flags,   bpt_num)
    str      flags;
    unsigned bpt_num;
{
    unsigned cur_char, len;
    s_str    var_name, hex_str;
    wpt_entry *wpt_ptr;


    /*
     * First get the COUNT option
     */
    cur_char = get_count_flag(&(sw_bpt[bpt_num].orig_count),  flags,  
				&(sw_bpt[bpt_num].count_specified));

    sw_bpt[bpt_num].cur_count = sw_bpt[bpt_num].orig_count;


    wpt_ptr = &(sw_bpt[bpt_num].wpt);

    /*
     * Check if condition was specified
     */
    if (flags[cur_char] == ' ') {
        cur_char++;
    }
    
    switch (flags[cur_char]) {
	case '\0':
	    wpt_ptr -> active = FALSE;
            return;
	case 'U':
	    wpt_ptr ->type = UNTIL;
	    break;
	case 'W':
	    wpt_ptr ->type = WHILE;
	    break;
    }

    cur_char++;
    if (flags[cur_char] == ' ') {
        cur_char++;
    }
    if (flags[cur_char] != '=') {
	ERROR(e_syntax__);
    }
    cur_char++;


    /*
     * Now get the Expression condition option
     */

    get_first_arg__(&flags[cur_char],  var_name,  &len,  S_SIZE, 
                   /* accept null arg */ FALSE);
    cur_char += len;
    /*
     * Check memory or register watchpoint
     */

    if ((var_name[0] == 'M') AND
        (strchr("BWD",  var_name[1]) != (char *) NULL) ){
        get_first_arg__(&flags[cur_char],  hex_str,  &len,  S_SIZE, 
                   /* accept null arg */ FALSE);
        cur_char += len;
        hex_to_bin__(hex_str,  &wpt_ptr -> addr,  'D');
        wpt_ptr -> width = var_name[1];
	wpt_ptr -> reg = NULL;
    }
    else{
        wpt_ptr -> reg = search_reg_tab__(var_name);
        if (wpt_ptr -> reg == NULL){
            ERROR(e_syntax__);
        }
	wpt_ptr->addr = 0;
    }

    /*
     * Get the expression lower bound, Upper bound & Mask
     */
    get_first_arg__(&flags[cur_char],  hex_str,  &len,  S_SIZE, 
                   /* accept null arg */ FALSE);
    hex_to_quad__( hex_str,  wpt_ptr -> low_value);
    cur_char += len;
    get_first_arg__(&flags[cur_char],  hex_str,  &len,  S_SIZE, 
                   /* accept null arg */ FALSE);
    hex_to_quad__( hex_str,  wpt_ptr -> high_value);
    cur_char += len;

    get_first_arg__(&flags[cur_char],  hex_str,  &len,  S_SIZE, 
                   /* accept null arg */ TRUE);
    if (len == 0) {
	wpt_ptr ->mask_specified = FALSE;
    }
    else {
	wpt_ptr ->mask_specified = TRUE;
    	hex_to_quad__( hex_str,  wpt_ptr -> mask_value);
    }
    wpt_ptr -> active = TRUE;
}


/*^L*/
/*----------------------------------------------------------------------------
 *
 *                 Sw_decode__(cmd, response)
 *
 * This function decodes the step while command for the @old_spec@.
 * It uses last entry of mem_wpt / reg_wpt.
 *
 *---------------------------------------------------------------------------*/
 
public void sw_decode__(cmd, response)
    str             cmd, response;
{
    unsigned cur_char,len;
    boolean  err,found;
    s_str    var_name,hex_str;
    quad_word low_value,high_value,mask_value;
    wpt_entry *wpt_ptr;
    
    cur_char = 2;
    get_first_arg__(&cmd[cur_char], var_name, &len, S_SIZE,
                   /* accept null arg */ FALSE);
    cur_char += len;
    /*
     * Check memory or register watchpoint 
     */
    if ((var_name[0] == 'M') AND 
        (strchr("BWD", var_name[1]) != (char *) NULL) ){
        wpt_ptr = &mem_wpt[WPT_NUM - 1];
        get_first_arg__(&cmd[cur_char], hex_str, &len, S_SIZE,
                   /* accept null arg */ FALSE);
        cur_char += len;
        hex_to_bin__(hex_str, &wpt_ptr -> addr, 'D');
        wpt_ptr -> width = var_name[1];
    }
    else{
        wpt_ptr = &reg_wpt[WPT_NUM -1];
	wpt_ptr -> reg = search_reg_tab__(var_name);
        if (wpt_ptr -> reg == NULL){
            ERROR(e_syntax__);
        }
    }
    get_first_arg__(&cmd[cur_char], hex_str, &len, S_SIZE,
                   /* accept null arg */ FALSE);
    hex_to_quad__( hex_str, wpt_ptr -> low_value);
    cur_char += len;
    get_first_arg__(&cmd[cur_char], hex_str, &len, S_SIZE,
                   /* accept null arg */ FALSE);
    hex_to_quad__( hex_str, wpt_ptr -> high_value);
    cur_char += len;
    get_first_arg__(&cmd[cur_char], hex_str, &len, S_SIZE,
                   /* accept null arg */ FALSE);
    hex_to_quad__( hex_str, wpt_ptr -> mask_value);
    switch (cmd[1]){
        case 'U': 
            wpt_ptr -> type = UNTIL;
            break;
        case 'W':
            wpt_ptr -> type = WHILE;
            break;
        default :
            ERROR(e_syntax__);
            return;
    }
    wpt_ptr -> orig_count = 1;
    wpt_ptr -> cur_count  = 1;
    wpt_ptr -> active = TRUE;
    active_wpt__ = TRUE;
    return_to_user__(FALSE);
}



/*----------------------------------------------------------------------------
 *
 *                      Stop_sw__()
 * 
 * This function turns off the watchpoints that are used to implement the
 * step while/until of the old monitor.
 * If the function finds an active watch point used for the old commands it 
 * turn off active_wpt__. This mean that the monitor can't work with a command
 * mixture of SW/SU and new spec WC command.
 * To allow the monitor to work with this mixture a test on the other 
 * watchpoint should be added.
 * 
 *---------------------------------------------------------------------------*/

public void stop_sw__()
{
    if (mem_wpt[WPT_NUM - 1].active OR reg_wpt[WPT_NUM - 1].active ) {
	mem_wpt[WPT_NUM - 1].active = FALSE;
	reg_wpt[WPT_NUM - 1].active = FALSE;
	active_wpt__ = FALSE;
    }
}

/*----------------------------------------------------------------------------
 *
 *                      check_bpt_condition(bpt_num)
 *
 *	The function return TRUE if the monitor should resume the program
 *	execution and FALSE otherwise.
 *	The function first evaluates the expression condition.
 *	If the expression is evaluated to TRUE the program execution should
 *	be resumed and the function return TRUE.
 *	Next the breakpointer is examined. If it is set and it is greater than
 *	one it is decremented by one. In this case the function return TRUE
 *	to resume the program execution.
 *---------------------------------------------------------------------------*/

private int check_bpt_condition(bpt_num)
unsigned bpt_num;
{
    if (sw_bpt[bpt_num].wpt.active) {
	quad_word value;
	wpt_entry *wpt = &(sw_bpt[bpt_num].wpt);

	if (wpt->reg) {
	    get_reg_val__(wpt->reg,  value);
	}
	else {
	    value[1] = 0;
            mem_read__(wpt->width,  wpt->addr,  value);
        }
	if (wpt->mask_specified) {
            value[0] &= wpt->mask_value[0];
            value[1] &= wpt->mask_value[1];
	}

        switch (wpt->type) {
            case UNTIL:
                if ((quad_compare__(value, wpt->low_value) == (-1)) OR
                	(quad_compare__(value,  wpt->high_value) == 1)){
                    return TRUE;
                }
                break;
            case WHILE:
                if ((quad_compare__(value, wpt->low_value) != (-1)) AND
                	(quad_compare__(value,  wpt->high_value) != 1)){
                    return TRUE;
                }
        }
    }
    if (sw_bpt[bpt_num].count_specified) {
	if (sw_bpt[bpt_num].cur_count > 1) {
		sw_bpt[bpt_num].cur_count--;
		return TRUE;
	}
    }
    return FALSE;
}

#ifdef DSPM_SUPPORT

#define DSPM_BPT_NUM 16
#define DSPM_INST_TYPE	unsigned short
#define DSPM_INST_SIZE	'W'
#define DSPM_BPT_OPCODE 0x14	/* Most significant 5 bits of the DSPM BPT */

#define DSPM_BPT(i) (unsigned short) ((DSPM_BPT_OPCODE << 11) + i)

#define DSPM_CMD_OPCODE(w)   ((w & 0xf800) >> 11) /* Most significant 5 bits */
#define DSPM_CMD_ARGS(w)     (w & 0x07ff)	/* Least significant 11 bits */

#define IN_DSPM_RAM(addr)   ((addr >= DSPM_RAM_BASE) && (addr < DSPM_RAM_BASE + DSPM_RAM_SIZE))

/*
 * The software breakpoint array
 */

typedef struct {
        boolean		 active;
        short		 *addr;
        DSPM_INST_TYPE   contents;
} dspm_bpt_entry;

private dspm_bpt_entry  dspm_bpt[DSPM_BPT_NUM] = {{0}}; /* force to data section */

public boolean dspm_nmi__ = FALSE;
public short   clptr__  = 0;
public short   nmistat__  = 0;


/*^L*/
/*-----------------------------------------------------------------------------
 *
 *               Cdbp_decode__(cmd, response)
 *
 * This function decodes the Change DSPM break point command.
 *
 *---------------------------------------------------------------------------*/
 
public void cdbp_decode__(cmd, response)
   str              cmd, response;
{
   s_str   hex_addr,bpt_name;
   unsigned bpt_num,len,cur_char,addr;
   boolean err;


    /*
     * Get the breakpoint number
     */
   cur_char = 1;
   get_first_arg__(&cmd[cur_char], bpt_name, &len,S_SIZE,
                  /* accept null arg */ FALSE);
    cur_char += (len + 1);
    hex_to_bin__( &bpt_name[3], &bpt_num, 'D');
    if (bpt_num > DSPM_BPT_NUM - 1) {
	ERROR(e_syntax__);
    }
    /*
     * Skip the "=" sign
     */
    if (cmd[cur_char] == '=') {
        cur_char ++;
    }
    /*
     * Get breakpoint address
     */
    get_first_arg__(&cmd[cur_char], hex_addr, &len,S_SIZE,
                  /* accept null arg */ FALSE);
    hex_to_bin__( hex_addr, &addr, 'D');

    /*
     * Find if to create or clear breakpoint
     */
    if (addr == 0){
	dspm_bpt[bpt_num].active = FALSE;
    }
    else {
	dspm_bpt[bpt_num].active          = TRUE;
	dspm_bpt[bpt_num].addr            = (short *) addr;
    }
} /* cbp_decode__ */


/*-----------------------------------------------------------------------------
 *
 *                    Pdbp_decode__(cmd, response)
 *
 * This function decode and implement the DSPM print breakpoint command.
 *
 *---------------------------------------------------------------------------*/
public void pdbp_decode__(cmd, response)
    str        cmd, response;
{
    unsigned bpt_num,len;
    s_str    bpt_name,hex_addr;
    
    /*
     * Get breakpoint number
     */
    get_first_arg__(&cmd[4], bpt_name, &len,S_SIZE,
                  /* accept null arg */ FALSE);
    hex_to_bin__( bpt_name, &bpt_num, 'D');
    if (bpt_num > DSPM_BPT_NUM - 1){
	ERROR(e_syntax__);
    }
    /*
     * For none active breakpoint return "= 0"
     */
    if (NOT dspm_bpt[bpt_num].active){
        strcpy(response, "= 0");
        return;
    }
    bin_to_hex__( dspm_bpt[bpt_num].addr, hex_addr, 'D');
    strcpy(response, "= ");
    strcpy(&response[2], hex_addr);

} /* pdbp_decode__ */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *                       Remove_dspm_bpt__()
 *
 * This function removes the DSPM breakpoints upon return to monitor time.
 * First restore the instruction of the current triggered breakpoint and
 * then restore all the other breakpoints instruction.
 * Note, that if the DSPM program is copied from external RAM to internal RAM
 * in runtime, the instructions in the DSPM RAM are not restored.
 *
 *---------------------------------------------------------------------------*/

public void remove_dspm_bpt__()
{
    int      i;
    boolean  available;

    /*
     * First restore the instruction on the current DSPM breakpoint.
     * Restore it both in the DSPM RAM & in the external RAM
     */

    for (i = 0; i < DSPM_BPT_NUM; i++) {
        if (dspm_bpt[i].active) {
            mem_write__(DSPM_INST_SIZE,  dspm_bpt[i].addr, 
						dspm_bpt[i].contents, TRUE);
            invalidate_cache__('I', FALSE, "", dspm_bpt[i].addr, &available);
        }
    }

} /* remove_dspm_bpt__ */



/*----------------------------------------------------------------------------
 *
 *               Place_back_dspm_bpt__()
 *
 * This function restores the DSPM breakpoints before return to the user
 * program.  
 *
 *---------------------------------------------------------------------------*/
public void place_back_dspm_bpt__()
{
    int      i;
    boolean  available;
    unsigned short instr;
    
    for (i = DSPM_BPT_NUM - 1; i >= 0; i--) {
        if (dspm_bpt[i].active) {
            mem_read__(DSPM_INST_SIZE, dspm_bpt[i].addr, &instr);
	    if (instr != DSPM_BPT(i)) {
	        dspm_bpt[i].contents = instr;
		mem_write__(DSPM_INST_SIZE, dspm_bpt[i].addr, DSPM_BPT(i), 
								TRUE);
		invalidate_cache__('I', FALSE, "", dspm_bpt[i].addr, 
								&available);
	    }

        }
    }

} /* place_back_dspm_bpt__ */

/*----------------------------------------------------------------------------
 *
 *               Check_dspm_bpt__(message)
 *
 * This function checks if we just executed Known DSPM breakpoint.
 * It returns TRUE if yes and FALSE if not.
 * If we did executed known breakpoint, the BPT is replaced with the 
 * orginal instruction.
 * The function also update the clptr__ variable to point to the previous
 * DSPM instruction.
 *
 *---------------------------------------------------------------------------*/
public int check_dspm_bpt__(message)
str message;
{
    unsigned clptr_abs_addr;
    unsigned short  inst;
    unsigned bpt_num;
    boolean  available;

    clptr__ = CLPTR_REG;
    clptr__ -= 1;	 /* Update clptr__ to point to the previous inst.*/

    clptr_abs_addr = DSPM_RAM_BASE + (2 * clptr__) ;
    inst = *((unsigned short *) clptr_abs_addr);

    /*
     * Check that:
     * 1. It is DSPM breakpoint opcode
     * 2. This breakpoint is active
     *
     * If so, disactivate this breakpoint.
     */
    if (DSPM_CMD_OPCODE(inst) == DSPM_BPT_OPCODE) {
	    bpt_num = DSPM_CMD_ARGS(inst);
	    if (bpt_num < DSPM_BPT_NUM) {
		    if (dspm_bpt[bpt_num].active) {
			    dspm_nmi__ = TRUE;
			    dspm_bpt[bpt_num].active = FALSE;
			    /*
			     * Remove the BPT from internal DSPM RAM
			     */
			    mem_write__(DSPM_INST_SIZE,  clptr_abs_addr, 
					dspm_bpt[bpt_num].contents, TRUE);
			    invalidate_cache__('I', FALSE, "", clptr_abs_addr,
						&available);
			    /*
			     * Remove the BPT from external RAM
			     */
			    if (clptr_abs_addr != (unsigned) dspm_bpt[bpt_num].addr) {
				mem_write__(DSPM_INST_SIZE, dspm_bpt[bpt_num].addr, 
					dspm_bpt[bpt_num].contents, TRUE);
				invalidate_cache__('I', FALSE, "",
				    dspm_bpt[bpt_num].addr, &available);
			    }
/*
			    strcpy(message, "BD ");
			    bin_to_hex__( bpt_num, &message[3], 'B');
*/
			    strcpy(message, e_non_cmon_bpt__);
			    return TRUE;
		    }
	    }
    }

    return FALSE;
}


/*----------------------------------------------------------------------------
 *
 *               Check_nmi__(message)
 *
 * This function is called upon NMI in monitor or user time.
 * It checks the NMI source and acts according to it. The function returns
 * the message that should be printed to the User.
 *
 * When a DSPM software breakpoint is reached, the DSPM execution is stopped
 * and the core enters the monitor NMI handler.
 * Here we check the source of the NMI by reading the DSPM NMISTAT 
 * register.
 * The NMISTAT register holds the status of the pending NMI request.
 *
 * If the NMI source is an external request to the DSPM (EXT bit is set)
 * we report as usual on the NMI and we enter the main loop.
 *
 * If the NMI source is an attempt of the core to access the DSPM while it
 * is running (ERR bit is set), we report an error message and 
 * we enters the main loop.
 *
 * If the NMI source is an attempt to execute undefined DSPM instruction
 * (UND bit set) , we check if it is known software breakpoints.
 * If it is software breakpoint, we return the original DSPM 
 * instruction and we enter the main loop. If not, we report about 
 * undefined DSPM instruction and we enter the main loop.
 *---------------------------------------------------------------------------*/
public void check_nmi__(message)
str message;
{
    nmistat__ = NMISTAT_REG;
    if (BIT_ON(0, nmistat__)) {
	if (exec_mode__ == MON_TIME) {
	    strcpy(message, nmi_message__);  /* External NMI in monitor time */
	}
	else {
	    strcpy(message, e_nmi__);  /* External NMI in user time*/
	}
    } 
    if (BIT_ON(2, nmistat__)) {
        strcpy(message, e_dspm_err__);  /* ERR bit is set */
    } 
    if (BIT_ON(1, nmistat__)) {
        if ( check_dspm_bpt__(message)) {
    	    remove_dspm_bpt__();
        }
        else {
    	    strcpy(message, e_nmi__);
        }
    } 
}

#endif /* DSPM SUPPORT */
