#include <u.h>
#include <libc.h>
#include <bio.h>
enum
{
Doff= 4, /* offset into Cpline.bytes of data */
Memsize= 1<<16, /* max size of 186 memory */
};
int dump, image, noload, nostart;
typedef struct
{
int type;
int dlen;
ulong addr;
uchar bytes[256+4];
uchar csum;
} Cpline;
char* rdcpline(Biobuf*, Cpline*);
void clearmem(int);
void
usage(void)
{
fprint(2, "usage: %s [-0123] file\n", argv0);
exits("usage");
}
static void
loadimage(char* file, int mfd)
{
uchar buf[256];
int fd, n, r;
if((fd = open(file, OREAD)) < 0)
sysfatal("opening %s: %r", file);
seek(mfd, 0, 0);
do{
n = read(fd, buf, sizeof(buf));
if(n < 0)
sysfatal("read %s: %r", file);
if(n > 0)
if((r = write(mfd, buf, n)) != n)
sysfatal("write %s: %d != %d: %r", file, n, r);
}while(n > 0);
close(fd);
}
static void
loadhex(char* file, int mfd)
{
int done;
Cpline c;
Biobuf *b;
char *err;
ulong addr, seg;
int lineno;
uchar buf[1024];
b = Bopen(file, OREAD);
if(b == 0)
sysfatal("opening %s: %r", file);
lineno = 1;
seg = 0;
for(done = 0; !done; lineno++){
err = rdcpline(b, &c);
if(err)
sysfatal("%s line %d: %s", file, lineno, err);
switch(c.type){
case 0: /* data */
addr = seg + c.addr;
if(addr + c.dlen > Memsize)
sysfatal("addr out of range: %lux-%lux", addr, addr+c.dlen);
if(seek(mfd, addr, 0) < 0)
sysfatal("seeking to %lud: %r", addr);
if(write(mfd, c.bytes+Doff, c.dlen) != c.dlen)
sysfatal("writing: %r");
if(seek(mfd, addr, 0) < 0)
sysfatal("seeking to %lud: %r", addr);
if(read(mfd, buf, c.dlen) != c.dlen)
sysfatal("reading: %r");
if(memcmp(buf, c.bytes+Doff, c.dlen) != 0)
print("readback error at %lux\n", addr);
if(dump)
print("%8.8lux: %d\n", addr, c.dlen);
break;
case 1: /* termination */
done = 1;
break;
case 2: /* segment */
seg = ((c.bytes[Doff]<<8) | c.bytes[Doff+1]) <<4;
if(seg >= Memsize)
sysfatal("seg out of range: %lux", seg);
if(dump)
print("seg %8.8lux\n", seg);
break;
default: /* ignore */
if(dump)
print("bad type %d\n", c.type);
break;
}
}
Bterm(b);
}
void
main(int argc, char **argv)
{
int unit;
int cfd, mfd;
char file[128];
unit = 0;
ARGBEGIN{
case 'd':
dump = 1;
break;
case 'i':
image = 1;
break;
case 'n':
noload = 1;
break;
case 's':
nostart = 1;
break;
case '0':
unit = 0;
break;
case '1':
unit = 1;
break;
case '2':
unit = 2;
break;
case '3':
unit = 3;
break;
}ARGEND;
if(argc == 0)
usage();
if(noload == 0){
sprint(file, "#G/astar%dctl", unit);
cfd = open(file, ORDWR);
if(cfd < 0)
sysfatal("opening %s", file);
sprint(file, "#G/astar%dmem", unit);
mfd = open(file, ORDWR);
if(mfd < 0)
sysfatal("opening %s", file);
if(write(cfd, "download", 8) != 8)
sysfatal("requesting download: %r");
} else {
cfd = -1;
mfd = create("/tmp/astarmem", ORDWR, 0664);
if(mfd < 0)
sysfatal("creating /tmp/astarmem: %r");
}
if(image)
loadimage(argv[0], mfd);
else{
/* zero out the memory */
clearmem(mfd);
loadhex(argv[0], mfd);
}
close(mfd);
if(noload == 0 && nostart == 0)
if(write(cfd, "run", 3) != 3)
sysfatal("requesting run: %r");
close(cfd);
exits(0);
}
void
clearmem(int fd)
{
char buf[4096];
char buf2[4096];
int i, n;
memset(buf, 0, sizeof buf);
for(i = 0; i < Memsize; i += n){
if(seek(fd, i, 0) < 0)
sysfatal("seeking to %ux: %r", i);
n = write(fd, buf, sizeof buf);
if(n <= 0)
break;
if(seek(fd, i, 0) < 0)
sysfatal("seeking to %ux: %r", i);
n = read(fd, buf2, sizeof buf2);
if(n <= 0)
break;
if(memcmp(buf, buf2, sizeof buf) != 0)
print("error zeroing mem at %ux\n", i);
}
print("zero'd %d bytes\n", i);
}
int
hex(char c)
{
if(c <= '9' && c >= '0')
return c - '0';
if(c <= 'f' && c >= 'a')
return (c - 'a') + 10;
if(c <= 'F' && c >= 'A')
return (c - 'A') + 10;
return -1;
}
char*
rdcpline(Biobuf *b, Cpline *cpl)
{
char *cp, *ep, *p;
uchar *up;
uchar csum;
int c;
cp = Brdline(b, '\n');
if(cp == 0)
return "early eof";
ep = cp + Blinelen(b);
if(*cp++ != ':')
return "bad load line";
csum = 0;
up = cpl->bytes;
for(p = cp; p < ep;){
c = hex(*p++)<<4;
c |= hex(*p++);
if(c < 0)
break;
csum += c;
*up++ = c;
}
cpl->csum = csum;
if(csum != 0){
fprint(2, "checksum %ux\n", csum);
return "bad checksum";
}
cpl->dlen = cpl->bytes[0];
if(cpl->dlen + 5 != up - cpl->bytes){
fprint(2, "%d %ld\n", cpl->dlen + 5, up - cpl->bytes);
return "bad data length";
}
cpl->addr = (cpl->bytes[1]<<8) | cpl->bytes[2];
cpl->type = cpl->bytes[3];
return 0;
}
|