%{
/* @#Copyright:
 * Copyright (c) 1997, Rolf Fiedler. .
 * Copyright (c) 1999-2000, Brett Wuth.
 */
/* @#License:
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/* File:	bdm_mon.lex (BDM Monitor)
 * Purpose:
 * Author:	Rolf Fielder
 * Created:
 *
 * Initials:
 *	BCW - Brett Wuth
 *		@#[ContactWuth:
 *		Phone: +1 403 627-2460
 *		E-mail: support@castrov.cuug.ab.ca, wuth@acm.org]
 *
 * HISTORY:
 * $Log: bdmmon.l,v $
 * Revision 1.3  2005/10/24 01:32:21  cjohns
 * Removed warnings when built with gcc 4.x
 *
 * Revision 1.2  2004/01/08 14:16:17  codewiz
 * Avoid duplicate definition of TRUE/FALSE. Remove trailing whitespace.
 *
 * Revision 1.1  2003/12/29 22:19:11  codewiz
 * Move bdmmon and bdmflash to m68k/utils.
 *
 * Revision 1.1  2003/06/03 15:42:04  codewiz
 * Import userland tools from bdm-fiedler
 *
 * Revision 1.7  2000/09/19 00:28:29  wuth
 * cleanly use Fiedler's bdm driver; bdm_mon detects flash errors
 *
 * Revision 1.6  2000/08/03 06:29:18  wuth
 * MultiProject Sync; Support Micron-style flash; Report flash model
 *
 * Revision 1.5  2000/04/20 04:56:23  wuth
 * GPL.  Abstract flash interface.
 *
 * Revision 1.4  2000/03/28 20:24:42  wuth
 * Break out flash code into separate executable.  Make run under Chris Johns BDM driver.
 *
 * Revision 1.3  2000/03/27 22:05:24  wuth
 * Add memory dump to file.
 *
 * Revision 1.2  1999/07/05 22:09:50  wuth
 * Abort if can't sync BDM.  Work with Am29F800 flash.
 */

#include <BDMFlash.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define REG_NAMES
#include "bdmops.h"

#ifndef TRUE
# define TRUE -1
# define FALSE 0
#endif

void print_status(void);

char help[]=
	" commands of the monitor:\n\n"
	" RReg - show all registers\n"
	" WReg reg_name value\n"
	" md start-addr length - show memory dump\n"
	" mf start-addr length long-word - fill memory\n"
	" me from - memory edit\n"
	" mw start-addr length file - dump memory into file\n"
	" up start-addr file - load contents of file up\n"
	" DOwn start-addr length file - load down and write to file\n"
	" stop - stop processor\n"
	" Step - step processor\n"
	" reset - reset processor\n"
	" restart - reset in freeze\n"
	" Run - resume execution\n"
	" flash_config base NumParallelChips ChipWidthBytes - configure flash memory\n"
	" erase - erase whole flash rom\n"
	" flash addr file - program flash from file\n"
	" watch from-addr to_addr - set address breakpoint\n"
	" trigger value mask - set data breakpoint\n"
	" Break addr mask - set PC breakpoint\n"
	" clear - clear all breakpoints\n"
	" source file - read commands from file\n"
	" poke.X addr valie - set memory to val\n"
	" BackTrace - show stack-backtrace (use maxstack first)\n"
	" maxstack - set maximum stack value\n"
	" Wait - wait for target to hit breakpoint\n"
	" query - query target status\n"
	" loop addr count - test bdm access to target\n"
	" Help - show this screen\n"
	" exit/Quit - leace monitor\n"
	" <enter> - repeat last command\n";

struct token {
    char name[8];
    int number;
};

int tokenize(char * str, char *args[])
{
    int n=0;
    static char argv_buf[1024];
    char *string;

    strcpy(&argv_buf[0], str);
    string=&argv_buf[0];

    while(1) {
	while(*string==' ' || *string=='\t' || *string=='\n') {
	    if(*string == '\0') {
		args[n]=0;
		return n;
	    }
	    string++;
	}
	args[n++]=string;
	while(*string!=' ' && *string!='\t' && *string!='\n') {
	    if(*string == '\0') {
		args[n]=0;
		return n;
	    }
	    string++;
	}
	*string++='\0';
    }
}

int find_token(char *string, struct token array[])
{
    char *x;
    int n;

    x=string;
    while(*x) {
	*x=toupper(*x);
	x++;
    }
    while(array[n].name[0]) {
	if(strcmp(string, array[n].name) == 0) {
	    return array[n].number;
	}
	n++;
    }
}

int mem_dump(unsigned long from, int count)
{
    int error, i, read;
    unsigned char buffer[256], line[17];

    error=0;
    while(count) {
        if(error) break;
        if(count>256) read=256;
	else read=count;
        if(bdm_read_mem(from, buffer, read)<0) {
	    error=1;
	    printf("Bus error or target disconnected.\n");
	    break;
	};
	for(i=0; i<read; i++) {
	    if(i%16==0) {
        strcpy((char*)line, "                ");
	        printf("%08x: ", from);
	    }
	    printf("%02x ", buffer[i]);
	    if(buffer[i]<' ' || buffer[i]>0x7f) {
	        line[i%16]='.';
	    } else {
	        line[i%16]=buffer[i];
	    }
	    if(i%16==15) {
	        printf(" * %s *\n", line);
	    }
	    from++;
	}
	count-=read;
	if(count) {
	    printf("press enter to continue...\n");
	    getchar();
	} else {
	    if(i%16 != 15) printf("\n");
	}
    }
    return error;
}


/* Write memory image to a file */
static
int
mem_write(unsigned long from, unsigned long count, FILE *file )
{
    int error, i, read;
    unsigned char buffer[256], line[17];

    error=0;
    while(count) {
        if(error) break;
        if(count>256) read=256;
	else read=count;
        if(bdm_read_mem(from, buffer, read)<0) {
	    error=1;
	    printf("Bus error or target disconnected.\n");
	    break;
	};
	for(i=0; i<read; i++) {
	    fputc( buffer[i], file );
	    from++;
	}
	count-=read;
    }
    return error;
}


static unsigned char buffer[1024];

void store_line(void)
{
  strcpy((char*) buffer, yytext);
/*    printf("last line was: %s\n", buffer); */
}

int no_prompt=FALSE;
void prompt(void)
{
    if(!no_prompt) {
        store_line();
        printf("> ");
    }
}

static unsigned long me_addr=0, addr=0, len=0x10, maxstack=0;
static int flash_ok=0;
static int BDMHandle = -1;

%}
%array
%option noyywrap

%x EDIT 

REGNAME (([%][A-Za-z])|([G-Zg-z]))[0-9A-Z_a-z]*
DIGIT [0-9]
NUMBER [0-9]+
HEXN 0x[0-9A-Fa-f]+
SRECORD S[0-9]([0-9A-F][0-9A-F])+
VALUE ((0x)?[0-9A-Fa-f]+)
TOKEN [A-Za-z][0-9A-Z_a-z]*
FILENAME [!-~]+
WS [ \t]
RREG (rreg|RREG|Rreg|rr|RR|Rr)
WREG (wreg|WREG|Wreg|wr|WR|Wr)
MD (md|MD|Md)
MF (mf|MF|Mf)
ME (me|ME|Me)
MW (mw|MW|Mw)
UP (up|UP|Up)
DOWN (down|DOWN|Down|do|DO|Do)
RUN (run|RUN|Run|R|r)
STOP (stop|STOP|Stop)
STEP (step|STEP|Step|S|s)
RESET (reset|RESET|Reset)
RESTART (restart|RESTART|Restart)
FLASHCONFIG (flash_config|FLASH_CONFIG|Flash_config)
ERASE (erase|ERASE|Erase)
FLASH (flash|FLASH|Flash)
MAXSTACK (maxstack|MAXSTACK|Maxstack)
BACKTRACE (backtrace|BACKTRACE|Backtrace|BT|bt|Bt)
WATCH (watch|WATCH|Watch)
TRIGGER (trigger|TRIGGER|Trigger)
BREAK (break|BREAK|Break|B|b)
CLEAR (clear|CLEAR|Clear|C|c)
WAIT (wait|WAIT|Wait|W|w)
QUERY (query|QUERY|Query|QU|qu)
SOURCE (source|SOURCE|Source)
POKE (poke|POKE|Poke)
HELP (help|HELP|Help|h|H)
LOOP (loop|LOOP|Loop)
FOO (foo)
EXIT (exit|EXIT|Exit|quit|QUIT|Quit|Q|q)

%%
{WS}*{HELP}{WS}*\n {
    printf("%s", help);
    prompt();
}

{WS}*{RREG}{WS}+{REGNAME}{WS}*\n {
    char *args[20];
    int i;
    unsigned long j;

    bdm_stop();
    tokenize(yytext, args);
    j=0;
    if(args[1][0] == '%') args[1]++; /* skip optional % */
    for(i=0; i<strlen(args[1]); i++) {
        args[1][i]=toupper(args[1][i]);
    }
    for(i=0; strlen(reg_names[i].name); i++) {
        if(strcmp(args[1], reg_names[i].name)==0)
	    break;
    }
    if(!strlen(reg_names[i].name)) {
        printf("ERROR\n");
    } else {
	bdm_read_reg(reg_names[i].id, &j);
	printf("%8s=0x%08x\n", reg_names[i].name, j);
    }
    prompt();
}

{WS}*{RREG}{WS}*\n {
    int i, n;
    unsigned long j;

    bdm_stop();
    for(i=0; i<=REG_CSR; i++) {
        bdm_read_reg(i, &j);
	for(n=0; strlen(reg_names[n].name); n++) {
	    if(reg_names[n].id == i)
		break;
	}
	printf("%8s=%08x ", reg_names[n].name, j);
	if(i%4==3) printf("\n");
    }
    if(i%4!=3) printf("\n");
    prompt();
}
    
{WS}*{WREG}{WS}+{REGNAME}{WS}+{VALUE}{WS}*\n {
    char *args[20];
    int i;
    unsigned long j;

    bdm_stop();
    tokenize(yytext, args);
    j=0;
    if(sscanf(args[2], "%x", &j) != 1) {
	printf("ERROR\n");
    } else {
        if(args[1][0] == '%') args[1]++; /* skip optional % */
	for(i=0; i<strlen(args[1]); i++) {
	    args[1][i]=toupper(args[1][i]);
	}
	for(i=0; strlen(reg_names[i].name); i++) {
	    if(strcmp(args[1], reg_names[i].name)==0)
		break;
	}
	if(!strlen(reg_names[i].name)) {
	    printf("ERROR\n");
	} else {
	    printf("Writing 0x%08x to %s.\n", j, reg_names[i].name);
	    i = reg_names[i].id;
	    bdm_write_reg(i, &j);
	}
    }
    prompt();
}

{WS}*{MD}{WS}+{VALUE}{WS}+{VALUE}{WS}*\n {
    char *args[20];
    int i, error;

    tokenize(yytext, args);
    error=0;
    if(sscanf(args[1], "%x", &addr) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if(sscanf(args[2], "%x", &len) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if(!error) {
        mem_dump(addr, len);
    }
    prompt();
}

{WS}*{MD}{WS}*\n {
    addr+=len;
    mem_dump(addr, len);
    prompt();
}

{WS}*{MW}{WS}+{VALUE}{WS}+{VALUE}{WS}+{FILENAME}{WS}*\n {
    char *args[20];
    int i, error;
    FILE *file;

    tokenize(yytext, args);
    error=0;
    if(sscanf(args[1], "%x", &addr) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if(sscanf(args[2], "%x", &len) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if((file=fopen(args[3], "w")) == NULL) {
	printf("ERROR opening file %s\n", args[3]);
	error=1;
    }
    if(!error) {
        mem_write(addr, len, file);
	fclose( file );
    }
    prompt();
}

{WS}*{MF}{WS}+{VALUE}{WS}+{VALUE}{WS}+{VALUE}{WS}*\n {
    unsigned long buf[1024/4];
    char *args[20];
    int error, i;
    unsigned long addr, val, len;
    tokenize(yytext, args);

    error=0;
    if(sscanf(args[1], "%x", &addr) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if(sscanf(args[2], "%x", &len) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if(sscanf(args[3], "%x", &val) != 1) {
	printf("ERROR\n");
	error=1;
    }
    for(i=0; i<1024/4; i++)
	buf[i]=val;
    while(len>=1024) {
	if(bdm_write_mem(addr, (unsigned char*)buf, 1024)<0) {
	    error=1;
	    printf("Bus error or target disconnected.\n");
	    len=0;
	    break;
	}
	len-=1024;
	addr+=1024;
    }
    if(len) {
        if(bdm_write_mem(addr, (unsigned char*)buf, len)<0) {
            error=1;
	    printf("Bus error or target disconnected.\n");
	}
    }
    prompt();
}

{WS}*{ME}{WS}+{VALUE}{WS}*\n {
    char *args[20];
    unsigned char x;
    tokenize(yytext, args);
    if(sscanf(args[1], "%x", &me_addr)!=1) {
	printf("ERROR\n> ");
    } else {
	if(bdm_read_mem(me_addr, &x, 1)<0) {
	    printf("Bus error or target disconnected.\n> ");
	} else {
	    printf("%08x: %02x = ", me_addr, x);
	    BEGIN(EDIT);
	}
    }
    store_line();
}

<EDIT>{WS}*{VALUE}{WS}*\n {
    char *args[20];
    unsigned long value;
    unsigned char x;
    tokenize(yytext, args);
    if(sscanf(args[0], "%x", &value)!=1) {
	printf("ERROR\n> ");
    } else {
	x = (unsigned char)(0xff & value);
	if(bdm_write_mem(me_addr++, &x, 1)<0) {
	    printf("Bus error or target disconnected.\n> ");
	    BEGIN(INITIAL);
	} else {
	    if(bdm_read_mem(me_addr, &x, 1)<0) {
		printf("Bus error or target disconnected.\n> ");
		BEGIN(INITIAL);
	    } else {
		printf("%08x: %02x = ", me_addr, x);
	    }
	}
    }
}

<EDIT>. {
}

<EDIT>\n {
    printf("\n> ");
    BEGIN(INITIAL);
}

{WS}*{POKE}\.[bwlBWL]?{WS}+{VALUE}{WS}+{VALUE}{WS}*\n {
    char *args[20];
    int size;
    unsigned long addr, tmp;
    unsigned char value[4];

    tokenize(yytext, args);
    if(strlen(args[0]) != 6) goto error;
    switch(args[0][5]) {
        case 'b': case 'B': size = 1; break;
        case 'w': case 'W': size = 2; break;
        case 'l': case 'L': size = 4; break;
        default: goto error;
    }
    if(sscanf(args[1], "%x", &addr) != 1 || (addr & (size-1)) != 0) goto error;
    if(sscanf(args[2], "%x", &tmp ) != 1) goto error;
    switch(size) {
        case 1:
            value[0] = (tmp>> 0) & 0xFF;
	    break;
        case 2:
            value[0] = (tmp>> 8) & 0xFF;
	    value[1] = (tmp>> 0) & 0xFF;
	    break;
        case 4:
            value[0] = (tmp>>24) & 0xFF;
	    value[1] = (tmp>>16) & 0xFF;
	    value[2] = (tmp>> 8) & 0xFF;
	    value[3] = (tmp>> 0) & 0xFF;
	    break;
        default:
            goto error;
    }
    if(bdm_write_mem(addr, value, size) != size) {
      error:
        printf( "ERROR\n" );
    } else {
#if 0
        printf( "poking %x %x %d\n", addr, tmp, size );
#endif
    }
    prompt();
}

{SRECORD}(\r)?\n {
    unsigned char buffer[1024];
    int slen = 0, doff, i, rpc = 0;
    unsigned long addr = 0xDEADBEEF;
    int error = 0;
    switch(yytext[1]) {
      case '0':			/* title record: ignore it */
          rpc   = 0;
	  doff  = 0;
	  slen  = 0;
	  break;
      case '1':                   /* 2 byte address... */
          error = (2 != sscanf(yytext, "S1%2x%4lx", &slen, &addr));
	  rpc   = 0;
	  doff  = 4 + 4;
	  slen -= 2 + 1;
	  break;
      case '2':                   /* 3 byte address... */
          error = (2 != sscanf(yytext, "S2%2x%6lx", &slen, &addr));
	  rpc   = 0;
	  doff  = 4 + 6;
	  slen -= 3 + 1;
	  break;
      case '3':			/* 4 byte address... */
          error = (2 != sscanf(yytext, "S3%2x%8lx", &slen, &addr));
	  rpc   = 0;
	  doff  = 4 + 8;
	  slen -= 4 + 1;
	  break;
      case '7':			/* 4 byte address */
          error = (2 != sscanf(yytext, "S7%2x%8lx", &slen, &addr));
	  rpc   = 1;
	  doff  = 4 + 8;
	  slen -= 4 + 1;
	  break;
      case '8':			/* 3 byte address */
          error = (2 != sscanf(yytext, "S8%2x%6lx", &slen, &addr));
	  rpc   = 1;
	  doff  = 4 + 6;
	  slen -= 3 + 1;
	  break;
      case '9':			/* 2 byte address */
          error = (2 != sscanf(yytext, "S9%2x%4lx", &slen, &addr));
	  rpc   = 1;
	  doff  = 4 + 4;
	  slen -= 2 + 1;
	  break;
      default:
          error = 1;
	  break;
    }
    if(!error && !rpc) {
        for( i = 0; i < slen; i++ ) {
            int b;
	    if(sscanf( yytext+doff+2*i, "%2x", &b ) != 1) {
	        error = 1;
		break;
            }
	    buffer[i] = b;
        }
    }
    if(error) {
        printf( "bad srecord: S%c\n", yytext[1] );
    } else if(rpc == 1) {
        bdm_stop();
	bdm_write_reg( REG_RPC, &addr );
    } else if(slen > 0) {
#if 0
        if(bdm_write_mem(addr, buffer, slen)<0)
	    printf("Bus error or target disconnected.\n> ");
#elif 1
        i = 0;
	while(!error && i < slen && (addr+i) & 3) {
            error = (bdm_write_mem(addr+i, buffer+i, 1)<0);
	    i++;
	}
	if(!error && (slen-i) >= 4) {
	    error = (bdm_write_mem(addr+i, buffer+i, (slen-i) & ~3)<0);
	    i += (slen-i) & ~3;
	}
	while(!error && i < slen) {
	    error = (bdm_write_mem(addr+i, buffer+i, 1)<0);
	    i++;
	}
	if(error) printf("Bus error or target disconnected.\n> ");
#else
        for(i = 0; i < slen; i++) {
	    if((bdm_write_mem(addr+i, buffer+i, 1)<0)) {
	        printf("Bus error or target disconnected.\n> ");
		break;
	    }
	}
#endif
    }
    prompt();
}

{WS}*{SOURCE}{WS}+{FILENAME}{WS}*\n {
    char buffer[1024];
    char *args[20];
    FILE *file, *oldin;
    int error, i;
    tokenize(yytext, args);
    error=0;
    if((file=fopen(args[1], "r")) == NULL) {
	printf("ERROR opening file %s\n", args[1]);
	error=1;
    }
    if(!error) {
        no_prompt = TRUE;
	oldin = yyin;
	yyin = file;
	yylex();
	yyrestart(yyin = oldin);
	no_prompt = FALSE;
	fclose(file);
    }
    prompt();
}

{WS}*{UP}{WS}+{VALUE}{WS}+{FILENAME}{WS}*\n {
    unsigned char buffer[1024];
    FILE *file;
    char *args[20];
    int error, i;
    unsigned long addr;
    tokenize(yytext, args);
    error=0;
    if(sscanf(args[1], "%x", &addr) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if((file=fopen(args[2], "r")) == NULL) {
	printf("ERROR opening file %s\n", args[2]);
	error=1;
    }
    if(!error) {
	printf("Uploading file %s.\n", args[2]);
	while(1) {
	    i=fread(buffer, 1, 1024, file);
	    if(bdm_write_mem(addr, buffer, i)<0) {
		printf("Bus error or target disconnected.\n> ");
		break;
	    }
	    if(i==0) break;
	    addr+=i;
	}
    }
    fclose(file);
    prompt();
}

{WS}*{DOWN}{WS}+{VALUE}{WS}+{VALUE}{WS}+{FILENAME}{WS}*\n {
    unsigned char buffer[1024];
    FILE *file;
    char *args[20];
    int error, i;
    unsigned long addr, len;
    tokenize(yytext, args);
    error=0;
    if(sscanf(args[1], "%x", &addr) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if(sscanf(args[2], "%x", &len) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if((file=fopen(args[3], "w")) == NULL) {
	printf("ERROR opening file %s for writing.\n", args[3]);
	error=1;
    }
    if(!error) {
	printf("Downloading file %s.\n", args[3]);
	while(len>1024) {
	    if(bdm_read_mem(addr, buffer, 1024)<0) {
		printf("Bus error or target disconnected.\n> ");
		error = 1;
		break;
	    }
	    i=fwrite(buffer, 1, 1024, file);
	    if(i!=1024) {
		printf("Error writing file.\n> ");
		error = 1;
		break;
	    }
	    addr+=1024;
	    len-=1024;
	}
	if(!error) {
	    if(bdm_read_mem(addr, buffer, len)<0) {
		printf("Bus error or target disconnected.\n> ");
		error = 1;
		break;
	    }
	    if(!error) {
		i=fwrite(buffer, 1, len, file);
		if(i!=len) {
		    printf("Error writing file.\n> ");
		    error = 1;
		    break;
		}
	    }
	}
    }
    fclose(file);
    prompt();
}

{WS}*{STEP}{WS}*\n {
    int i, n;
    unsigned long j;

    bdm_step();
    for(i=0; i<10000; i++) j++; /* wait for step */
    for(i=0; i<=REG_CSR; i++) {
        bdm_read_reg(i, &j);
	for(n=0; strlen(reg_names[n].name); n++) {
	    if(reg_names[n].id == i)
		break;
	}
	printf("%8s=%08x ", reg_names[n].name, j);
	if(i%4==3) printf("\n");
    }
    if(i%4!=3) printf("\n");
    prompt();
}
{WS}*{STOP}{WS}*\n {
    bdm_stop();
    prompt();
}

{WS}*{RUN}{WS}*\n {
    bdm_run();
    prompt();
}

{WS}*{RESET}{WS}*\n {
    bdm_reset();
    prompt();
}

{WS}*{RESTART}{WS}*\n {
    bdm_restart();
    prompt();
}

{WS}*{FLASHCONFIG}{WS}+{VALUE}{WS}+{VALUE}{WS}+{VALUE}{WS}*\n {
    char *args[20];
    int error, i;
    unsigned int addr, NumParallelChips, ChipWidthBytes;
    tokenize(yytext, args);
    error=0;
    if(sscanf(args[1], "%x", &addr) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if(sscanf(args[2], "%x", &NumParallelChips) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if(sscanf(args[3], "%x", &ChipWidthBytes) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if(!error) {
        printf( "FLASH-ROM @ 0x%x, %d parallel chip(s) each %d byte(s) wide.\n", 
	        addr, 
		NumParallelChips,
		ChipWidthBytes );
	BDMFlashConfigSet( BDMHandle, addr, NumParallelChips, ChipWidthBytes );
	flash_ok=1;
    }
    printf("\n");
    prompt();
}

{WS}*{FLASH}{WS}+{VALUE}{WS}+{FILENAME}{WS}*\n {
    unsigned char buffer[1024];
    FILE *file;
    char *args[20];
    int error, i;
    unsigned long addr;
    tokenize(yytext, args);
    error=0;
    if(sscanf(args[1], "%x", &addr) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if((file=fopen(args[2], "r")) == NULL) {
	printf("ERROR opening file %s\n", args[2]);
	error=1;
    }
    if(!flash_ok) {
        printf("Please configure flash memory first!");
	error=1;
    }
    if(!error) {
        bdm_stop();
	printf("Programming FLASH-ROM from file %s.\n", args[2]);
	while(1) {
	    i=fread(buffer, 1, 1024, file);
	    if(BDMFlashWrite( addr, buffer, i )!= FlashErrorOkay_c) {
		printf("Bus error or target disconnected.\n"
		       "Successfully wrote up to address 0x%08lx.\n"
		       "Failure was during following 1024 byte block.\n"
		       "> ",
		       addr );
		break;
	    }
	    if(i==0) break;
	    printf("."); fflush(stdout);
	    addr+=i;
	}
    }
    printf("\n");
    fclose(file);
    prompt();
}

{WS}*{ERASE}{WS}*\n {
    if(!flash_ok) {
        printf("Please configure flash memory first!\n");
    } else {
        bdm_stop();
        BDMFlashErase();
    }
    prompt();
}

{WS}*{MAXSTACK}{WS}+{VALUE}{WS}*\n {
    char *args[20];
    int error, i;
    unsigned int val;
    tokenize(yytext, args);
    error=0;
    if(sscanf(args[1], "%x", &val) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if(!error) {
        printf("maximum stack position is 0x%08lx.\n", val);
        maxstack=val;
    }
    printf("\n");
    prompt();
}

{WS}*{BACKTRACE}{WS}*\n {
     unsigned long a7, mem, buf;
     bdm_read_reg(REG_A7, &a7);
     printf("Stack is at 0x%08lx\n", a7);
     for(mem=a7; mem<maxstack && mem<a7+4*16; mem+=4) {
         if(bdm_read_mem(mem, (unsigned char *)&buf, 4)<0) {
	     printf("Bus error or target disconnected.\n");
	     break;
	 } else {
	     printf("\t0x%08lx\n", ntohl(buf));
	 }
     }
     prompt(); 
}

{WS}*{BREAK}{WS}+{VALUE}{WS}+{VALUE}{WS}*\n {
    int error;
    unsigned long addr, mask;
    char *args[20];

    bdm_stop();
    tokenize(yytext, args);
    error=0;
    if(sscanf(args[1], "%x", &addr) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if(sscanf(args[2], "%x", &mask) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if(!error) {
        bdm_set_pc_bp(addr, mask);
    } else {
        printf("ERROR\n");
    }
    prompt();
}

{WS}*{WATCH}{WS}+{VALUE}{WS}+{VALUE}{WS}*\n {
    int error;
    unsigned long from, to;
    char *args[20];

    bdm_stop();
    tokenize(yytext, args);
    error=0;
    if(sscanf(args[1], "%x", &from) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if(sscanf(args[2], "%x", &to) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if(!error) {
        bdm_set_addr_bp(from, to);
    } else {
        printf("ERROR\n");
    }
    prompt();
}

{WS}*{TRIGGER}{WS}+{VALUE}{WS}+{VALUE}{WS}*\n {
    int error;
    unsigned long value, mask;
    char *args[20];

    bdm_stop();
    tokenize(yytext, args);
    error=0;
    if(sscanf(args[1], "%x", &value) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if(sscanf(args[2], "%x", &mask) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if(!error) {
        bdm_set_data_bp(value, mask);
    } else {
        printf("ERROR\n");
    }
    prompt();
}

{WS}*{CLEAR}{WS}*\n {
    bdm_stop();
    bdm_clear_pc_bp();
    bdm_clear_data_bp();
    bdm_clear_addr_bp();
    prompt();
}

{WS}*{WAIT}{WS}*\n {
    bdm_wait();
    print_status();
    prompt();
}

{WS}*{LOOP}{WS}+{VALUE}{WS}+{VALUE}{WS}*\n {
    unsigned char buffer[256];
    int i, error;
    unsigned long addr, len;
    char *args[20];

    bdm_stop();
    tokenize(yytext, args);
    error=0;
    if(sscanf(args[1], "%x", &addr) != 1) {
	printf("ERROR\n");
	error=1;
    }
    if(sscanf(args[2], "%x", &len) != 1) {
	printf("ERROR\n");
	error=1;
    }
    for(; len>0; len--) {
        if(bdm_read_mem(addr, buffer, 16)<0) {
            /* report error and clear buffer */
            printf("\nBus error or target disconnected.\n");
	    fflush(stdout);
	    for(i=0; i<16; i++) {
		buffer[i] = 0;
            }
	} else {
	    for(i=0; i<16; i++) {
		if(i%16==0) printf("\r%08x: ", addr);
		printf("%02x ", buffer[i]);
		if(i%16==15) printf("\r");
		/* addr++; */
	    }
	    fflush(stdout);
	}
    }
    printf("\n");
    prompt();
}

{WS}*{QUERY}{WS}*\n {
    print_status();
    prompt();
}

{WS}*{EXIT}{WS}*\n {
    printf("BYE\n");
    bdm_release(0);
    exit(0);
}

.+\n {
    printf("ERROR: %s\n> ", yytext);
}

\n {
    int i;
/*    printf("Empty line, last line was: %s\n", buffer); */
    for(i=strlen((char*)buffer)-1; i>=0; i--) {
        unput(buffer[i]);
    }
    buffer[0]=0;
}

%%
#define USAGE "Usage: %s [-f file] [/dev/bdmx]\n"

int main(int argc, char **argv, char **envp)
{
    int base, i, dev, file;
    char *filename, default_file[]="stdin";
    char *devicename, default_device[]="/dev/bdm0";

    filename = default_file;
    devicename = default_device;
    dev = 0;
    file = 0;

    for(i=1; i<argc; i++) {
        if(!strcmp(argv[i], "-f")) {
	    if(!file) {
	        i++;
	        if(i==argc) {
	            fprintf(stderr, USAGE, argv[0]);
		    return -1;
	        }
		filename = argv[i];
		file = -1;
	    } else {
	        fprintf(stderr, USAGE, argv[0]);
		return -1;
	    }
	} else {
	    if(!dev) {
	        devicename = argv[i];
		dev = -1;
	    } else {
	        fprintf(stderr, USAGE, argv[0]);
		return -1;
	    }
	}
    }

    if((BDMHandle = bdm_init(devicename))<0) {
        fprintf(stderr, "Problem opening bdm device.\n");
        return -1;
    }

    if(strcmp(filename, default_file)) {
	yyin = fopen(filename, "r");
	if(!yyin) {
	    fprintf(stderr, 
		    " %s: Can't open file %s for reading.\n",
		    argv[0], argv[1]);
	    return -1;
	}
    } else {
	yyin = stdin;
    }

    print_status();
    printf("> ");
    yylex();
    return 0;
}

void print_status(void)
{
    int x;

    x=bdm_query_status();
    if(x<0) {
        printf("ERROR\n");
    } else {
        if(x & BDM_STAT_BKPT) printf("Processor halted due to BDM.\n");
        if(x & BDM_STAT_HALT) printf("Processor halted due to HALT insn.\n");
        if(x & BDM_STAT_TRG) printf("Processor halted due to TRIGGER.\n");
        if(x & BDM_STAT_FOF) printf("Processor halted due to fault on fault.\n");
        if(x & BDM_STAT_WAIT1) printf("Processor waiting for level 1 trigger.\n");
        if(x & BDM_STAT_TRIG1) printf("Processor hit level 1 trigger.\n");
        if(x & BDM_STAT_WAIT2) printf("Processor waiting for level 2 trigger.\n");
        if(x & BDM_STAT_TRIG2) printf("Processor hit level 2 trigger.\n");
        if(x & BDM_STAT_SSM) printf("Processor single stepping.\n");
        if(x & BDM_STAT_RESET) printf("Processor is held in reset.\n");
        if(x & BDM_STAT_NOPWR) printf("Processor has no power.\n");
        if(x & BDM_STAT_PSTHALT) printf("Processor has posted PST=HALT.\n");
        if(x & BDM_STAT_NC) printf("No target connected.\n");
	if(x==0) printf("Processor running.\n");
    }
}
