/************************************************
Monitor LPC2478
Comandos e funcoes utilitarias
Marcos A. Stemmer
*************************************************/
#include <arch/nxp/lpc24xx.h>
#include "monarm.h"
extern unsigned int cpuclock;

void U0puts(char *s)
{
while(*s) U0putchar(*s++);
}

/* Le uma linha de texto. n=numero maximo de letras */
int GetStr(char *s, int n)
{
int i;
char c;
i=0;
do	{
	c=U0getchar();
	if(c==0x7f) c=8;
	if(c==8){
		if(i)	{
			U0putchar(c); i--;
			U0putchar(' '); U0putchar(8);
			}
		}
	else	{
		s[i++]=c; 
		U0putchar(c);
		}
	if(c=='\x1b'){
		*s='\0';
		return 1;
		}
	} while(c!=10 && c!=13 && i < n);
//if(c==13) U0putchar('\n');
s[i]=0;
return 0;
}

int dig2ascii(int c)
{
c = '0' + (c & 0xf);
if(c > '9') c+='A'-'9'-1;
return (c);
}

void PrByte(int c)
{
U0putchar(dig2ascii(c >> 4));
U0putchar(dig2ascii(c));
}

void LCDprbyte(int c)
{
LCDputchar(dig2ascii(c >> 4));
LCDputchar(dig2ascii(c));
}

/* Pega um numero na base radix */
unsigned long getnum(char *str, int radix)
{
int x;
int d;
x=0;
do	{
	d = *str++;
	if(d < '0') break;
	if(d > '9') {
		d &= 0xdf;
		if(d < 'A') break;
		d -= ('A'-'9' -1);
		}
	d-='0';
	if(d >= radix) break;
	x = x*radix + d;
	} while(1);
return x;
}

/* Le um digito hexadecimal */
int ledig()
{
int d;
d=U0getchar();
if(d>'9') {
	d &= 0xdf;
	d -= ('A'-'9' -1);
	}
d-='0';
if(d<0 || d>15) d=-8000;
return d;
}

int lebyte()
{
return (ledig() << 4)+ledig();
}
/*
Le dados em formato hexadecimal da Intel
Envia um caractere de resposta no final de cada linha
'.' (Ponto) significa linha OK
'E' Erro de ckecksum
'*' Erro de sintaxe (não entendi nada) 
	O transmissor deve parar de transmitir quando recebe '*'
0x40000000	RAM Interna
0x80000000	Flash externa
0x81000000	RAM Externa
*/
int lehex(unsigned long base)
{
unsigned char buf[32];
unsigned int addr;
unsigned char *pc;
int chksum, k, n, c;
int flag;
do	{
	n=lebyte();
	chksum=n;
	if(n<0) { U0putchar('*'); continue; }
	c=lebyte();
	if(c<0) { U0putchar('*'); continue; }
	chksum+=c;
	addr = (c << 8);
	c=lebyte();
	chksum+=c;
	addr |= c;
	flag=lebyte();
	if(flag==4) {
		c=lebyte();
		chksum+=c;
		base= c << 24;
		c=lebyte();
		chksum+=c;
		base |= c << 16;
		n-=2;
		}
	pc = (unsigned char *)(base+addr);
	if(n > 32 || n < 0) { U0putchar('*'); break; }
	for(k=0; k<n; k++) {
		c = lebyte();
		chksum+=c;
		if(!flag) buf[k] = c;
		}
	chksum+=lebyte()+flag;
	if(chksum < 0) { U0putchar('*'); break; }
	for(k=0; k<n; k++) pc[k]=buf[k];
	U0putchar(chksum & 0xff? 'E':'.');
	if(flag==1) break;
	do n=U0getchar(); while(n=='\n' || n=='\r' || n==' ' || n=='\t');
	} while(n==':');
return chksum;
}

int carrega(void)
{
union address ad;
int numbytes, k;
do	{
	while(!(U0LSR & RXDREADY));
	ad.w=(U0RBR & 0xff);
	while(!(U0LSR & RXDREADY));
	ad.w |= ((U0RBR & 0xff) << 8);
	while(!(U0LSR & RXDREADY));
	ad.w |= ((U0RBR & 0xff) << 16);
	while(!(U0LSR & RXDREADY));
	ad.w |= ((U0RBR & 0xff) << 24);
	while(!(U0LSR & RXDREADY));
	numbytes = (U0RBR & 0xff);
	while(!(U0LSR & RXDREADY));
	numbytes |= ((U0RBR & 0xff) << 8);
	for(k=0; k<numbytes; k++){
		while(!(U0LSR & RXDREADY));
		ad.p[k] = U0RBR;
		//U0putchar(ad.p[k]);
		}
	U0putchar('.');
	while(!(U0LSR & RXDREADY));
	} while(U0RBR == 0x7f);
/*
U0puts("\nA = ");
prword(ad.w);
U0puts(" n = ");
prword(numbytes);
U0putchar('\n');*/
return 0;
}

unsigned long getaddress()
{
char buf[32];
U0puts(" Address=0x");
GetStr(buf,32);
if(*buf < ' ') return 0xbfffffff;
return getnum(buf,16);
}

/* Escreve um numero como 8 digitos hexadecimais */
void prword(unsigned int w)
{
PrByte(w >> 24); PrByte(w >> 16);
PrByte(w >> 8); PrByte(w);
U0putchar(':');
}

/* Escreve os bytes da memoria em hexadecimal */
void dump()
{
union address ad;
int i, c;
U0puts("Dump:");
ad.w=getaddress();
if(ad.w==0xbfffffff) return;
do	{
	prword(ad.w);
	for(i=0; i<16; i++) {
		U0putchar(' ');
		PrByte(ad.p[i]);
		}
	U0puts("   ");
	for(i=0; i<16; i++) {
		c=ad.p[i];
		U0putchar(c < ' ' || (c > 0x7f && c<0xa0)? '.':c);
		}
	ad.w += 16;
	U0puts("\r\n");
	} while(U0getchar()!=0x1b);
}

/* Escreve bytes na memoria */
void escreve_mem()
{
volatile union address ad;
char buf[32];
U0puts("Memory Set:");
ad.w=getaddress();
if(ad.w==0xbfffffff) return;
do	{
	prword(ad.w);
	PrByte(*(ad.p)); U0putchar(' ');
	if(GetStr(buf,32)) break;
	if(!(*buf)) return;
	if(*buf >= '0') *ad.p = getnum(buf,16);
	U0puts("========> ");
	PrByte(*(ad.p));
	U0puts("\r\n");
	ad.w++;
	} while(1);
}

/* Escreve palavras de 32 bits na memoria */
void escreve_word()
{
volatile union address ad;
char buf[32];
U0puts("Word Set:");
ad.w=getaddress();
if(ad.w==0xbfffffff) return;
ad.w &= -4;
do	{
	prword(ad.w); U0putchar(' ');
	prword(*(ad.pw)); U0putchar(' ');
	if(GetStr(buf,32)) break;
	if(!(*buf)) return;
	if(*buf >= '0') {
		*ad.pw = getnum(buf,16);
		U0puts("========> ");
		prword(*(ad.pw));
		U0puts("\r\n");
		ad.pw++;
		}
	} while(1);
}

/* Copia bytes da memoria */
void copy(int cp)
{
union address af, ad;
int i, n;
char buf[32];
U0puts(cp? "Copia de": "Compara");
af.w=getaddress();
//if(ad.w==0xbfffffff) return;
U0puts(cp?"para":"com");
ad.w=getaddress();
//if(ad.w==0xbfffffff) return;
U0puts("Numero de bytes (hex)=");
if(GetStr(buf,16)) return;
n=getnum(buf,16);
if(cp)for(i=0; i < n; i++) ad.p[i] = af.p[i];
while(n--) {
	if(*ad.p != *af.p) {
		U0puts("Erro em Fonte 0x");
		prword(af.w);
		PrByte(*af.p);
		U0puts(" Dest 0x");
		prword(ad.w);
		PrByte(*ad.p);
		return;
		}
	ad.p++;
	af.p++;
	};
U0puts("OK");
}

/* Ececuta um programa no endereco especificado */
void execute()
{
union address ad;
U0puts("Execute:");
ad.w=getaddress();
if(ad.w==0xbfffffff) return;
(ad.f)();
}

/* Escreve 2 digitos decimais */
void pr2dec(int x)
{
U0putchar((x / 10) + '0');
U0putchar((x % 10) + '0');
}

/* Escreve um numero decimal */
void escreve_num(int num)
{
char digs[16];
int nd=0;
if(num<0) { U0putchar('-'); num=-num; }
do	{
	digs[nd++]= (num % 10) + '0';
	num /= 10;
	} while(num);
while(nd--) U0putchar(digs[nd]);
}
