summaryrefslogtreecommitdiff
path: root/appl/cmd/rdp.b
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/cmd/rdp.b
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/cmd/rdp.b')
-rw-r--r--appl/cmd/rdp.b1230
1 files changed, 1230 insertions, 0 deletions
diff --git a/appl/cmd/rdp.b b/appl/cmd/rdp.b
new file mode 100644
index 00000000..80e25f20
--- /dev/null
+++ b/appl/cmd/rdp.b
@@ -0,0 +1,1230 @@
+implement Rdp;
+include "sys.m";
+ sys: Sys;
+ print, sprint: import sys;
+include "draw.m";
+include "string.m";
+ str: String;
+
+df_port: con "/dev/eia0";
+df_bps: con 38400;
+
+Rdp: module
+{
+ init: fn(nil: ref Draw->Context, arg: list of string);
+};
+
+dfd: ref sys->FD;
+cfd: ref sys->FD;
+ifd: ref sys->FD;
+pifd: ref sys->FD;
+p_isopen := 0;
+
+R_R15: con 15;
+R_PC: con 16;
+R_CPSR: con 17;
+R_SPSR: con 18;
+NREG: con 19;
+
+debug := 0;
+nocr := 0;
+tmode := 0;
+# echar := 16r1c; # ctrl-\
+echar := 16r1d; # ctrl-] (because Tk grabs the ctrl-\ )
+
+bint(x: int): array of byte
+{
+ b := array[4] of byte;
+ b[0] = byte x;
+ b[1] = byte (x>>8);
+ b[2] = byte (x>>16);
+ b[3] = byte (x>>24);
+ return b;
+}
+
+intb(b: array of byte): int
+{
+ return int b[0] | (int b[1] << 8)
+ | (int b[2] << 16) | (int b[3] << 24);
+}
+
+
+statusmsg(n: int): string
+{
+ m: string;
+ case n {
+ 0 => m = nil;
+ 1 => m = "Reset";
+ 2 => m = "Undefined instruction";
+ 3 => m = "Software interrupt";
+ 4 => m = "Prefetch abort";
+ 5 => m = "Data abort";
+ 6 => m = "Address exception";
+ 7 => m = "IRQ";
+ 8 => m = "FIQ";
+ 9 => m = "Error";
+ 10 => m = "Branch Through 0";
+ 253 => m = "Insufficient privilege";
+ 254 => m = "Unimplemented message";
+ 255 => m = "Undefined message";
+ * => m = sprint("Status %d", n);
+ }
+ return m;
+}
+
+sdc: chan of (array of byte, int);
+scc: chan of int;
+
+serinp()
+{
+ b: array of byte = nil;
+ save: array of byte = nil;
+ x := 0;
+ for(;;) {
+ m := <- scc;
+ if(m == 0) {
+ save = b[0:x];
+ continue;
+ }
+ b = nil;
+ t: int;
+ do {
+ alt {
+ m = <- scc =>
+ if(m == 0)
+ print("<strange error>\n");
+ b = nil;
+ * =>
+ ;
+ }
+ if(b == nil) {
+ if(m >= 0)
+ t = m;
+ else
+ t = -m;
+ x = 0;
+ b = array[t] of byte;
+ }
+ if(save != nil) {
+ r := len save;
+ if(r > (t-x))
+ r = t-x;
+ b[x:] = save[0:r];
+ save = save[r:];
+ if(len save == 0)
+ save = nil;
+ x += r;
+ continue;
+ }
+ r := sys->read(dfd, b[x:], t-x);
+ if(r < 0)
+ sdc <-= (array of byte sprint("fail:%r"), -1);
+ if(r == 0)
+ sdc <-= (array of byte "fail:hangup", -1);
+ if(debug) {
+ if(r == 1)
+ print("<%ux>", int b[x]);
+ else
+ print("<%ux,%ux...(%d)>", int b[x], int b[x+1], r);
+ }
+ x += r;
+ } while(m >= 0 && x < t);
+ sdc <-= (b, x);
+ }
+}
+
+
+sreadn(n: int): array of byte
+{
+ b: array of byte;
+ if(n == 0)
+ return array[0] of byte;
+ scc <-= n;
+ (b, n) = <- sdc;
+ if(n < 0)
+ raise string b;
+ return b[0:n];
+}
+
+
+# yes, it's kind of a hack...
+fds := array[32] of ref Sys->FD;
+
+oscmd()
+{
+ arg := array[4] of int;
+ buf := array[4] of array of byte;
+ b := sreadn(5);
+ op := intb(b[:4]);
+ argd := int b[4];
+ for(i := 0; i<4; i++) {
+ t := (argd >> (i*2))&3;
+ case t {
+ 0 => ;
+ 1 =>
+ arg[i] = int sreadn(1)[0];
+ 2 =>
+ arg[i] = intb(sreadn(4));
+ 3 =>
+ c := int sreadn(1)[0];
+ if(c < 255) {
+ buf[i] = array[c] of byte;
+ if(c <= 32) {
+ buf[i][0:] = sreadn(c);
+ } else
+ arg[i] = intb(sreadn(4));
+ } else {
+ b: array of byte;
+ b = sreadn(8);
+ c = intb(b[:4]);
+ arg[i] = intb(b[4:8]);
+ buf[i] = array[c] of byte;
+ }
+ }
+ }
+ for(i = 0; i<4; i++)
+ if(buf[i] != nil && len buf[i] > 32)
+ rdi_read(arg[i], buf[i], len buf[i]);
+
+ r := 0;
+ case op {
+ 0 or 2 => ;
+ * =>
+ out("");
+ }
+ case op {
+ 0 =>
+ if(debug)
+ print("SWI_WriteC(%d)\n", arg[0]);
+ out(string byte arg[0]);
+ 2 =>
+ if(debug)
+ print("SWI_Write0(<%d>)\n", len buf[0]);
+ out(string buf[0]);
+ 4 =>
+ if(debug)
+ print("SWI_ReadC()\n");
+ sys->read(ifd, b, 1);
+ r = int b[0];
+ 16r66 =>
+ fname := string buf[0];
+ if(debug)
+ print("SWI_Open(%s, %d)\n", fname, arg[1]);
+ fd: ref Sys->FD;
+ case arg[1] {
+ 0 or 1 =>
+ fd = sys->open(fname, Sys->OREAD);
+ 2 or 3 =>
+ fd = sys->open(fname, Sys->ORDWR);
+ 4 or 5 =>
+ fd = sys->open(fname, Sys->OWRITE);
+ if(fd == nil)
+ fd = sys->create(fname, Sys->OWRITE, 8r666);
+ 6 or 7 =>
+ fd = sys->open(fname, Sys->OWRITE|Sys->OTRUNC);
+ if(fd == nil)
+ fd = sys->create(fname, Sys->OWRITE, 8r666);
+ 8 or 9 =>
+ fd = sys->open(fname, Sys->OWRITE);
+ if(fd == nil)
+ fd = sys->create(fname, Sys->OWRITE, 8r666);
+ else
+ sys->seek(fd, big 0, Sys->SEEKEND);
+ 10 or 11 =>
+ fd = sys->open(fname, Sys->ORDWR);
+ if(fd == nil)
+ fd = sys->create(fname, Sys->ORDWR, 8r666);
+ else
+ sys->seek(fd, big 0, Sys->SEEKEND);
+ }
+ if(fd != nil) {
+ r = fd.fd;
+ if(r >= len fds) {
+ print("<fd %d out of range 1-%d>\n", r, len fds);
+ r = 0;
+ } else
+ fds[r] = fd;
+ }
+ 16r68 =>
+ if(debug)
+ print("SWI_Close(%d)\n", arg[0]);
+ if(arg[0] <= 0 || arg[0] >= len fds)
+ r = -1;
+ else {
+ if(fds[arg[0]] != nil)
+ fds[arg[0]] = nil;
+ else
+ r = -1;
+ }
+ 16r69 =>
+ if(debug)
+ print("SWI_Write(%d, <%d>)\n", arg[0], len buf[1]);
+ if(arg[0] <= 0 || arg[0] >= len fds)
+ r = -1;
+ else
+ r = sys->write(fds[arg[0]], buf[1], len buf[1]);
+ r = arg[2]-r;
+ 16r6a =>
+ if(debug)
+ print("SWI_Read(%d, 0x%ux, %d)\n", arg[0], arg[1], arg[2]);
+ if(arg[0] <= 0 || arg[0] >= len fds)
+ r = -1;
+ else {
+ d := array[arg[2]] of byte;
+ r = sys->read(fds[arg[0]], d, arg[2]);
+ if(r > 0)
+ rdi_write(d, arg[1], r);
+ }
+ r = arg[2]-r;
+ 16r6b =>
+ if(debug)
+ print("SWI_Seek(%d, %d)\n", arg[0], arg[1]);
+ if(arg[0] <= 0 || arg[0] >= len fds)
+ r = -1;
+ else
+ r = int sys->seek(fds[arg[0]], big arg[1], 0);
+ 16r6c =>
+ if(debug)
+ print("SWI_Flen(%d)\n", arg[0]);
+ if(arg[0] <= 0 || arg[0] >= len fds)
+ r = -1;
+ else {
+ d: Sys->Dir;
+ (r, d) = sys->fstat(fds[arg[0]]);
+ if(r >= 0)
+ r = int d.length;
+ }
+ 16r6e =>
+ if(debug)
+ print("SWI_IsTTY(%d)\n", arg[0]);
+ r = 0; # how can we detect if it's a TTY?
+ * =>
+ print("unsupported: SWI 0x%ux\n", op);
+ }
+ b = array[6] of byte;
+ b[0] = byte 16r13;
+ if(debug)
+ print("r0=%d\n", r);
+ if(r >= 0 && r <= 16rff) {
+ b[1] = byte 1;
+ b[2] = byte r;
+ sys->write(dfd, b, 3);
+ } else {
+ b[1] = byte 2;
+ b[2:] = bint(r);
+ sys->write(dfd, b, 6);
+ }
+}
+
+
+terminal()
+{
+ b := array[1024] of byte;
+ c := 3; # num of invalid chars before resetting
+ tmode = 1;
+ for(;;) {
+ n: int;
+ b: array of byte;
+ alt {
+ scc <-= -8192 =>
+ (b, n) = <- sdc;
+ (b, n) = <- sdc =>
+ ;
+ }
+ if(n < 0)
+ raise string b;
+ c -= out(string b[:n]);
+ if(c < 0) {
+ scc <-= 0;
+ raise "rdp:tmode";
+ }
+ if(!tmode) {
+ return;
+ }
+ }
+}
+
+getreply(n: int): (array of byte, int)
+{
+ loop: for(;;) {
+ c := int sreadn(1)[0];
+ case c {
+ 16r21 =>
+ oscmd();
+ 16r7f =>
+ raise "rdp:reset";
+ 16r5f =>
+ break loop;
+ * =>
+ print("<%ux?>", c);
+ scc <-= 0;
+ raise "rdp:tmode";
+ }
+ }
+ b := sreadn(n+1);
+ s := int b[n];
+ if(s != 0) {
+ out("");
+ print("[%s]\n", statusmsg(s));
+ }
+ return (b[:n], s);
+}
+
+outstr: string;
+tpid: int;
+
+timeout(t: int, c: chan of int)
+{
+ tpid = sys->pctl(0, nil);
+ if(t > 0)
+ sys->sleep(t);
+ c <-= 0;
+ tpid = 0;
+}
+
+bsc: chan of string;
+
+bufout()
+{
+ buf := "";
+ tc := chan of int;
+ n: int;
+ s: string;
+ for(;;) {
+ alt {
+ n = <- tc =>
+ print("%s", buf);
+ buf = "";
+ s = <- bsc =>
+ #if(tpid) {
+ # kill(tpid);
+ # tpid = 0;
+ #}
+ if((len buf+len s) >= 1024) {
+ print("%s", buf);
+ buf = s;
+ }
+ if(s == "" || debug) {
+ print("%s", buf);
+ buf = "";
+ } else {
+ buf += s;
+ if(tpid == 0)
+ spawn timeout(300, tc);
+ }
+ }
+ }
+}
+
+out(s: string): int
+{
+ if(bsc == nil) {
+ bsc = chan of string;
+ spawn bufout();
+ }
+ c := 0;
+ if(nocr || tmode) {
+ n := "";
+ for(i:=0; i<len s; i++) {
+ if(!(nocr && s[i] == '\r'))
+ n[len n] = s[i];
+ if(s[i] >= 16r7f)
+ c++;
+ }
+ bsc <-= n;
+ } else
+ bsc <-= s;
+ return c;
+}
+
+reset(r: int)
+{
+ out("");
+ if(debug)
+ print("reset(%d)\n", r);
+ p_isopen = 0;
+ b := array of byte sprint("b9600");
+ sys->write(cfd, b, len b);
+ if(r) {
+ b[0] = byte 127;
+ sys->write(dfd, b, 1);
+ print("<sending reset>");
+ }
+ ok := 0;
+ s := "";
+ for(;;) {
+ n: int;
+ b: array of byte;
+ scc <-= -8192;
+ (b, n) = <- sdc;
+ if(n < 0)
+ raise string b;
+ for(i := 0; i<n; i++) {
+ if(b[i] == byte 127) {
+ if(!ok)
+ print("\n");
+ ok = 1;
+ s = "";
+ continue;
+ }
+ if(b[i] == byte 0) {
+ if(ok && i == n-1) {
+ out(s);
+ out("");
+ return;
+ } else {
+ s = "";
+ continue;
+ }
+ }
+ if(b[i] < byte 127)
+ s += string b[i:i+1];
+ else
+ ok = 0;
+ }
+ }
+}
+
+sa1100_reset()
+{
+ rdi_write(bint(1), int 16r90030000, 4);
+}
+
+setbps(bps: int)
+{
+ # for older Emu's using setserial hacks...
+ if(bps > 38400)
+ sys->write(cfd, array of byte "b38400", 6);
+
+ out("");
+ print("<bps=%d>\n", bps);
+ b := array of byte sprint("b%d", bps);
+ if(sys->write(cfd, b, len b) != len b)
+ print("setbps failed: %r\n");
+}
+
+rdi_open(bps: int)
+{
+ if(debug)
+ print("rdi_open(%d)\n", bps);
+ b := array[7] of byte;
+ usehack := 0;
+ if(!p_isopen) {
+ b[0] = byte 0;
+ b[1] = byte (0 | (1<<1));
+ b[2:] = bint(0);
+ case bps {
+ 9600 => b[6] = byte 1;
+ 19200 => b[6] = byte 2;
+ 38400 => b[6] = byte 3;
+ # 57600 => b[6] = byte 4;
+ # 115200 => b[6] = byte 5;
+ # 230400 => b[6] = byte 6;
+ * =>
+ b[6] = byte 1;
+ usehack = 1;
+ }
+ sys->write(dfd, b, 7);
+ getreply(0);
+ p_isopen = 1;
+ if(usehack)
+ sa1100_setbps(bps);
+ else
+ setbps(bps);
+ }
+}
+
+rdi_close()
+{
+ if(debug)
+ print("rdi_close()\n");
+ b := array[1] of byte;
+ if(p_isopen) {
+ b[0] = byte 1;
+ sys->write(dfd, b, 1);
+ getreply(0);
+ p_isopen = 0;
+ }
+}
+
+rdi_cpuread(reg: array of int, mask: int)
+{
+ if(debug)
+ print("rdi_cpuread(..., 0x%ux)\n", mask);
+ n := 0;
+ for(i := 0; i<NREG; i++)
+ if(mask&(1<<i))
+ n += 4;
+ b := array[6+n] of byte;
+ b[0] = byte 4;
+ b[1] = byte 255; # current mode
+ b[2:] = bint(mask);
+ sys->write(dfd, b, 6);
+ (b, nil) = getreply(n);
+ n = 0;
+ for(i = 0; i<NREG; i++)
+ if(mask&(1<<i)) {
+ reg[i] = intb(b[n:n+4]);
+ n += 4;
+ }
+}
+
+rdi_cpuwrite(reg: array of int, mask: int)
+{
+ if(debug)
+ print("rdi_cpuwrite(..., 0x%ux)\n", mask);
+ n := 0;
+ for(i := 0; i<32; i++)
+ if(mask&(1<<i))
+ n += 4;
+ b := array[6+n] of byte;
+ b[0] = byte 5;
+ b[1] = byte 255; # current mode
+ b[2:] = bint(mask);
+ n = 6;
+ for(i = 0; i<32; i++)
+ if(mask&(1<<i)) {
+ b[n:] = bint(reg[i]);
+ n += 4;
+ }
+ sys->write(dfd, b, n);
+ getreply(0);
+}
+
+dump(b: array of byte, n: int)
+{
+ for(i := 0; i<n; i++)
+ print(" %d: %2.2ux\n", i, int b[i]);
+}
+
+rdi_read(addr: int, b: array of byte, n: int): int
+{
+ if(debug)
+ print("rdi_read(0x%ux, ..., 0x%ux)\n", addr, n);
+ if(n == 0)
+ return 0;
+ sb := array[9] of byte;
+ sb[0] = byte 2;
+ sb[1:] = bint(addr);
+ sb[5:] = bint(n);
+ sys->write(dfd, sb, 9);
+ (b[0:], nil) = getreply(n);
+ # if error, need to read count of bytes transferred
+ return n;
+}
+
+rdi_write(b: array of byte, addr: int, n: int): int
+{
+ if(debug)
+ print("rdi_write(..., 0x%ux, 0x%ux)\n", addr, n);
+ if(n == 0)
+ return 0;
+ sb := array[9+n] of byte;
+ sb[0] = byte 3;
+ sb[1:] = bint(addr);
+ sb[5:] = bint(n);
+ sb[9:] = b[:n];
+ sys->write(dfd, sb, 9);
+ x := 0;
+ while(n) {
+ q := n;
+ if(q > 8192)
+ q = 8192;
+ r := sys->write(dfd, b[x:], q);
+ if(debug)
+ print("rdi_write: r=%d ofs=%d n=%d\n", r, x, n);
+ if(r < 0)
+ raise "fail:hangup";
+ x += r;
+ n -= r;
+ }
+ getreply(0);
+ return n;
+}
+
+rdi_execute()
+{
+ if(debug)
+ print("rdi_execute()\n");
+ sb := array[2] of byte;
+ sb[0] = byte 16r10;
+ sb[1] = byte 0;
+ sys->write(dfd, sb, 2);
+ getreply(0);
+ out("");
+}
+
+rdi_info(n: int, arg: int)
+{
+ sb := array[9] of byte;
+ sb[0] = byte 16r12;
+ sb[1:] = bint(n);
+ sb[5:] = bint(arg);
+ sys->write(dfd, sb, 9);
+ getreply(0);
+}
+
+
+regdump()
+{
+ out("");
+ reg := array[NREG] of int;
+ # rdi_cpuread(reg, 16rffff|(1<<R_PC)|(1<<R_CPSR)|(1<<R_SPSR));
+ rdi_cpuread(reg, 16rffff|(1<<R_PC)|(1<<R_CPSR));
+ for(i := 0; i < 16; i += 4)
+ print(" r%-2d=%8.8ux r%-2d=%8.8ux r%-2d=%8.8ux r%-2d=%8.8ux\n",
+ i, reg[i], i+1, reg[i+1],
+ i+2, reg[i+2], i+3, reg[i+3]);
+ print(" pc=%8.8ux psr=%8.8ux\n",
+ reg[R_PC], reg[R_CPSR]);
+}
+
+printable(b: array of byte): string
+{
+ s := "";
+ for(i := 0; i < len b; i++)
+ if(b[i] >= byte ' ' && b[i] <= byte 126)
+ s += string b[i:i+1];
+ else
+ s += ".";
+ return s;
+}
+
+examine(a: int, n: int)
+{
+ b := array[4] of byte;
+ for(i := 0; i<n; i++) {
+ rdi_read(a, b, 4);
+ print("0x%8.8ux: 0x%8.8ux \"%s\"\n", a, intb(b), printable(b));
+ a += 4;
+ }
+}
+
+atoi(s: string): int
+{
+ b := 10;
+ if(len s < 1)
+ return 0;
+ if(s[0] == '0') {
+ b = 8;
+ s = s[1:];
+ if(len s < 1)
+ return 0;
+ if(s[0] == 'x' || s[0] == 'X') {
+ b = 16;
+ s = s[1:];
+ }
+ }
+ n: int;
+ (n, nil) = str->toint(s, b);
+ return n;
+}
+
+regnum(s: string): int
+{
+ if(len s < 2)
+ return -1;
+ if(s[0] == 'r' && s[1] >= '0' && s[1] <= '9')
+ return atoi(s[1:]);
+ case s {
+ "pc" => return R_PC;
+ "cpsr" or "psr" => return R_CPSR;
+ "spsr" => return R_SPSR;
+ * => return -1;
+ }
+}
+
+cmdhelp()
+{
+ print(" e <addr> [<count>] - examine memory\n");
+ print(" d <addr> [<value>...] - deposit values in memory\n");
+ print(" get <file> <addr> - read file into memory at addr\n");
+ print(" load <file> - load AIF file and set the PC\n");
+ print(" r - print all registers\n");
+ print(" <reg>=<val> - set register value\n");
+ print(" sb - run builtin sboot (pc=0x40; g)\n");
+ print(" reset - trigger SA1100 software reset\n");
+ print(" bps <speed> - change bps rate (SA1100 only)\n");
+ print(" q - quit\n");
+}
+
+cmdmode()
+{
+ b := array[1024] of byte;
+ for(;;) {
+ print("rdp: ");
+ r := sys->read(ifd, b, len b);
+ if(r < 0)
+ raise sprint("fail:%r");
+ if(r == 0 || (r == 1 && b[0] == byte 4))
+ break;
+ n: int;
+ a: list of string;
+ (n, a) = sys->tokenize(string b[0:r], " \t\n=");
+ if(n < 1)
+ continue;
+ case hd a {
+ "sb" =>
+ sbmode();
+ rdi_execute();
+ "q" or "quit" =>
+ return;
+ "r" or "reg" =>
+ regdump();
+ "get" or "getfile" or "l" or "load" =>
+ {
+ if((hd a)[0] == 'l')
+ aifload(hd tl a, -1);
+ else
+ aifload(hd tl a, atoi(hd tl tl a));
+ }exception e{
+ "fail:*" =>
+ print("error: %s\n", e[5:]);
+ continue;
+ }
+ "g" or "go" =>
+ rdi_execute();
+ "reset" =>
+ sa1100_reset();
+ "e" =>
+ a = tl a;
+ x := atoi(hd a);
+ n = 1;
+ a = tl a;
+ if(a != nil)
+ n = atoi(hd a);
+ examine(x, n);
+ "d" =>
+ a = tl a;
+ x := atoi(hd a);
+ for(i := 2; i<n; i++) {
+ a = tl a;
+ rdi_write(bint(atoi(hd a)), x, 4);
+ x += 4;
+ }
+ "info" =>
+ a = tl a;
+ rdi_info(16r180, atoi(hd a));
+ "bps" =>
+ sa1100_setbps(atoi(hd tl a));
+ "help" or "?" =>
+ cmdhelp();
+ * =>
+ if((rn := regnum(hd a)) > -1) {
+ reg := array[NREG] of int;
+ reg[rn] = atoi(hd tl a);
+ rdi_cpuwrite(reg, 1<<rn);
+ } else
+ print("?\n");
+ }
+ }
+}
+
+sbmode()
+{
+ if(debug)
+ print("sbmode()\n");
+ reg := array[NREG] of int;
+ reg[R_PC] = 16r40;
+ rdi_cpuwrite(reg, 1<<R_PC);
+}
+
+sbmodeofs(ofs: int)
+{
+ if(debug)
+ print("sbmode(0x%ux)\n", ofs);
+ reg := array[NREG] of int;
+ reg[0] = ofs;
+ reg[R_PC] = 16r48;
+ rdi_cpuwrite(reg, (1<<0)|(1<<R_PC));
+}
+
+inp: string = "";
+
+help: con "(q)uit, (i)nt, (b)reak, !c(r), !(l)ine, !(t)erminal, (s<bps>), (.)cont, (!cmd)\n";
+
+menu(fi: ref Sys->FD)
+{
+ w := israw;
+ if(israw)
+ raw(0);
+mloop: for(;;) {
+ out("");
+ print("rdp> ");
+ b := array[256] of byte;
+ r := sys->read(fi, b, len b);
+ case int b[0] {
+ 'q' =>
+ killgrp();
+ exit;
+ 'i' =>
+ b[0] = byte 16r18;
+ sys->write(dfd, b[0:1], 1);
+ break mloop;
+ 'b' =>
+ sys->write(cfd, array of byte "k", 1);
+ break mloop;
+ '!' =>
+ cmd := string b[1:r-1];
+ print("!%s\n", cmd);
+ # system(cmd)
+ print("!\n");
+ break mloop;
+ 'l' =>
+ w = !w;
+ break mloop;
+ 'r' =>
+ nocr = !nocr;
+ break mloop;
+ 'd' =>
+ debug = !debug;
+ break mloop;
+ 't' =>
+ sys->write(pifd, array[] of { byte 4 }, 1);
+ sdc <-= (array of byte "rdp:tmode", -1);
+ break mloop;
+ '.' =>
+ break mloop;
+ 's' =>
+ bps := atoi(string b[1:r-1]);
+ setbps(bps);
+ * =>
+ print(help);
+ continue;
+ }
+ }
+ if(israw != w)
+ raw(w);
+}
+
+
+input()
+{
+ fi := sys->fildes(0);
+ b := array[1024] of byte;
+iloop: for(;;) {
+ r := sys->read(fi, b, len b);
+ if(r < 0) {
+ print("stdin: %r");
+ killgrp();
+ exit;
+ }
+ for(i:=0; i<r; i++) {
+ if(b[i] == byte echar) {
+ menu(fi);
+ continue iloop;
+ }
+ }
+ if(r == 0) {
+ b[0] = byte 4; # ctrl-d
+ r = 1;
+ }
+ if(tmode)
+ sys->write(dfd, b, r);
+ else
+ sys->write(pifd, b, r);
+ }
+}
+
+ccfd: ref Sys->FD;
+israw := 0;
+
+raw(on: int)
+{
+ if(ccfd == nil) {
+ ccfd = sys->open("/dev/consctl", Sys->OWRITE);
+ if(ccfd == nil) {
+ print("/dev/consctl: %r\n");
+ return;
+ }
+ }
+ if(on)
+ sys->fprint(ccfd, "rawon");
+ else
+ sys->fprint(ccfd, "rawoff");
+ israw = on;
+}
+
+killgrp()
+{
+ pid := sys->pctl(0, nil);
+ f := "/prog/"+string pid+"/ctl";
+ fd := sys->open(f, Sys->OWRITE);
+ if(fd == nil)
+ print("%s: %r\n", f);
+ else
+ sys->fprint(fd, "killgrp");
+}
+
+kill(pid: int)
+{
+ f := "/prog/"+string pid+"/ctl";
+ fd := sys->open(f, Sys->OWRITE);
+ if(fd == nil)
+ print("%s: %r\n", f);
+ else
+ sys->fprint(fd, "kill");
+}
+
+
+# Code for switching to previously unsupported bps rates:
+
+##define UTCR1 0x4
+##define UTCR2 0x8
+##define UTCR3 0xc
+##define UTDR 0x14
+##define UTSR0 0x1c
+##define UTSR1 0x20
+#
+#TEXT _startup(SB), $-4
+# MOVW $0x80000000,R2
+# ORR $0x00050000,R2
+#
+# MOVW $0, R1
+# MOVW R1, UTDR(R2) /* send ack */
+#
+#wait:
+# MOVW UTSR1(R2), R1
+# TST $1, R1 /* TBY */
+# BNE wait
+#
+# MOVW $0x90000000,R3
+# ORR $0x00000010,R3
+# MOVW (R4),R1
+# ADD $0x5a000,R1 /* 100 ms */
+#delay1:
+# MOVW (R3),R1
+# SUB.S $0x5a000, R1 /* 100 ms */
+# BLO delay1
+#
+# MOVW UTCR3(R2), R5 /* save utcr3 */
+# MOVW $0, R1
+# MOVW R1, UTCR3(R2) /* disable xmt/rcv */
+#
+# MOVW R0, R1
+# AND $0xff, R1
+# MOVW R1, UTCR2(R2)
+# MOVW R0 >> 8, R1
+# MOVW R1, UTCR1(R2)
+#
+# MOVW $0xff, R1
+# MOVW R1, UTSR0(R2) /* clear sticky bits */
+#
+# MOVW $3, R1
+# MOVW R1, UTCR3(R2) /* enable xmt/rcv */
+#
+# MOVW $0, R0
+#sync:
+# MOVW R0, UTDR(R2) /* send sync char */
+#syncwait:
+# MOVW UTSR1(R2), R1
+# TST $1, R1 /* TBY */
+# BNE syncwait
+# TST $2, R1 /* RNE */
+# BEQ sync
+# MOVW UTDR(R2), R0
+# MOVW R0, UTDR(R2) /* echo rcvd char */
+#
+# MOVW $0xff, R1
+# MOVW R1, UTSR0(R2) /* clear sticky bits */
+# MOVW R5, UTCR3(R2) /* re-enable xmt/rcv and interrupts */
+#
+# WORD $0xef000011 /* exit */
+
+
+bpscode := array[] of {
+ 16re3a22102, 16re3822805, 16re3a11000, 16re5821014,
+ 16re5921020, 16re3110001, big 16r1afffffc, 16re3a33209,
+ 16re3833010, 16re5941000, 16re2811a5a, 16re5931000,
+ 16re2511a5a, big 16r3afffffc, 16re592500c, 16re3a11000,
+ 16re582100c, 16re1a11000, 16re20110ff, 16re5821008,
+ 16re1a11420, 16re5821004, 16re3a110ff, 16re582101c,
+ 16re3a11003, 16re582100c, 16re3a00000, 16re5820014,
+ 16re5921020, 16re3110001, big 16r1afffffc, 16re3110002,
+ big 16r0afffff9, 16re5920014, 16re5820014, 16re3a110ff,
+ 16re582101c, 16re582500c, 16ref000011,
+};
+
+sa1100_setbps(bps: int)
+{
+ print("<sa1100_setbps %d>", bps);
+ nb := len bpscode*4;
+ b := array[nb] of byte;
+ for(i := 0; i < len bpscode; i++)
+ b[i*4:] = bint(int bpscode[i]);
+ rdi_write(b, 16r8080, nb);
+ reg := array[NREG] of int;
+ d := (3686400/(bps*16))-1;
+ reg[0] = d;
+ reg[R_PC] = 16r8080;
+ rdi_cpuwrite(reg, (1<<0)|(1<<R_PC));
+ sb := array[2] of byte;
+ sb[0] = byte 16r10;
+ sb[1] = byte 0;
+ sys->write(dfd, sb, 2);
+ rb := sreadn(1);
+ setbps(bps);
+ do rb = sreadn(1);
+ while(rb[0] != byte 0);
+ sb[0] = byte 16rff;
+ sys->write(dfd, sb, 1);
+ do rb = sreadn(1);
+ while(rb[0] != sb[0]);
+ getreply(0);
+}
+
+aifload(fname: string, adr: int)
+{
+ out("");
+ if(adr < 0)
+ print("<aifload %s>\n", fname);
+ fd := sys->open(fname, Sys->OREAD);
+ if(fd == nil)
+ raise sprint("fail:%s:%r", fname);
+ d: Sys->Dir;
+ (nil, d) = sys->fstat(fd);
+ b := array[int d.length] of byte;
+ sys->read(fd, b, len b);
+ if(adr < 0) {
+ if(len b < 128)
+ raise sprint("fail:%s:not aif", fname);
+ tsize := intb(b[20:24]);
+ dsize := intb(b[24:28]);
+ bsize := intb(b[32:36]);
+ tbase := intb(b[40:44]);
+ dbase := intb(b[52:56]);
+ print("%ux/%ux: %ux+%ux+%ux\n", tbase, dbase, tsize, dsize, bsize);
+ rdi_write(b, tbase, tsize+dsize);
+ reg := array[NREG] of int;
+ reg[R_PC] = tbase+8;
+ rdi_cpuwrite(reg, 1<<R_PC);
+ } else
+ rdi_write(b, adr, int d.length);
+}
+
+
+init(nil: ref Draw->Context, argv: list of string)
+{
+ sys = load Sys Sys->PATH;
+ str = load String String->PATH;
+
+ sys->pctl(Sys->NEWPGRP, nil);
+
+ port := df_port;
+ bps := df_bps;
+ usecmdmode := 0;
+ ofs := -1;
+ prog: string = nil;
+
+ argv = tl argv;
+ while(argv != nil) {
+ a := hd argv;
+ argv = tl argv;
+ if(len a >= 2 && a[0] == '-')
+ case a[1] {
+ 'c' =>
+ usecmdmode = 1;
+ 'O' =>
+ ofs = atoi(a[2:]);
+ 'd' =>
+ debug = 1;
+ 'p' =>
+ port = a[2:];
+ 's' =>
+ bps = atoi(a[2:]);
+ 'r' =>
+ nocr = 1;
+ 'l' =>
+ raw(1);
+ 'e' =>
+ if(a[2] == '^')
+ echar = a[3]&16r1f;
+ else
+ echar = a[2];
+ 't' =>
+ tmode = 1;
+ 'h' =>
+ print("usage: rdp [-crdlht] [-e<c>] [-O<ofs>] [-p<port>] [-s<bps>] [prog]\n");
+ return;
+ * =>
+ print("invalid option: %s\n", a);
+ return;
+ }
+ else
+ prog = a;
+ }
+
+ print("rdp 0.17 (port=%s, bps=%d)\n", port, bps);
+ dfd = sys->open(port, Sys->ORDWR);
+ if(dfd == nil) {
+ sys->print("open %s failed: %r\n", port);
+ return;
+ }
+ cfd = sys->open(port+"ctl", Sys->OWRITE);
+ if(cfd == nil)
+ sys->print("warning: open %s failed: %r\n", port+"ctl");
+
+ pfd := array[2] of ref Sys->FD;
+ sys->pipe(pfd);
+ ifd = pfd[1];
+ pifd = pfd[0];
+ (scc, sdc) = (chan of int, chan of (array of byte, int));
+ spawn serinp();
+ spawn input();
+ r := 1;
+ {
+ if(tmode)
+ terminal();
+ reset(r);
+ if(!p_isopen) {
+ rdi_open(bps);
+ rdi_info(16r180, (1<<0)|(1<<1)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8));
+ }
+ # print("\n<connection established>\n");
+ print("\n<contact has been made>\n");
+ if(usecmdmode) {
+ cmdmode();
+ } else {
+ if(prog != nil)
+ aifload(prog, -1);
+ else if(ofs != -1)
+ sbmodeofs(ofs);
+ else
+ sbmode();
+ reg := array[NREG] of int;
+ # rdi_cpuread(reg, (1<<R_PC)|(1<<R_CPSR));
+ # print("<execute at %ux; cpsr=%ux>\n", reg[R_PC], reg[R_CPSR]);
+ rdi_cpuread(reg, (1<<R_PC));
+ print("<execute at %ux>\n", reg[R_PC]);
+ rdi_execute();
+ }
+ rdi_close();
+
+ # Warning: this will make Linux emu crash...
+ killgrp();
+ }exception e{
+ "fail:*" =>
+ if(israw)
+ raw(0);
+ killgrp();
+ raise e;
+ "rdp:*" =>
+ out("");
+ if(debug)
+ print("<exception: %s>\n", e);
+ case e {
+ "rdp:error" => ;
+ "rdp:tmode" =>
+ tmode = !tmode;
+ if(tmode)
+ print("<terminal mode>\n");
+ else
+ print("<rdp mode>\n");
+ "rdp:reset" =>
+ r = 0;
+ * =>
+ r = 1;
+ }
+ }
+}
+