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("\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) sys->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, 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, 0, Sys->SEEKEND); } if(fd != nil) { r = fd.fd; if(r >= len fds) { print("\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 = sys->seek(fds[arg[0]], 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 = 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) sys->raise(string b); c -= out(string b[:n]); if(c < 0) { scc <-= 0; sys->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 => sys->raise("rdp:reset"); 16r5f => break loop; * => print("<%ux?>", c); scc <-= 0; sys->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= 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(""); } ok := 0; s := ""; for(;;) { n: int; b: array of byte; scc <-= -8192; (b, n) = <- sdc; if(n < 0) sys->raise(string b); for(i := 0; i 38400) sys->write(cfd, array of byte "b38400", 6); out(""); print("\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; iwrite(dfd, b, 6); (b, nil) = getreply(n); n = 0; for(i = 0; iwrite(dfd, b, n); getreply(0); } dump(b: array of byte, n: int) { for(i := 0; iwrite(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) sys->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<= 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; itoint(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 [] - examine memory\n"); print(" d [...] - deposit values in memory\n"); print(" get - read file into memory at addr\n"); print(" load - load AIF file and set the PC\n"); print(" r - print all registers\n"); print(" = - set register value\n"); print(" sb - run builtin sboot (pc=0x40; g)\n"); print(" reset - trigger SA1100 software reset\n"); print(" bps - 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) sys->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" => e: ref Sys->Exception; if(sys->rescue("fail:*", e)) { sys->rescued(Sys->ONCE, nil); print("error: %s\n", e.name[5:]); continue; } if((hd a)[0] == 'l') aifload(hd tl a, -1); else aifload(hd tl a, atoi(hd tl tl a)); "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 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<), (.)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; iwrite(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("", 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<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("\n", fname); fd := sys->open(fname, Sys->OREAD); if(fd == nil) sys->raise(sprint("fail:%s:%r", fname)); d: Sys->Dir; (nil, d) = sys->fstat(fd); b := array[d.length] of byte; sys->read(fd, b, d.length); if(adr < 0) { if(len b < 128) sys->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<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(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] [-O] [-p] [-s] [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(); e := ref Sys->Exception; if(sys->rescue("fail:*", e)) { if(israw) raw(0); killgrp(); sys->raise(e.name); } r := 1; if(sys->rescue("rdp:*", e)) { out(""); if(debug) print("\n", e.name); sys->rescued(Sys->ACTIVE, nil); case e.name { "rdp:error" => ; "rdp:tmode" => tmode = !tmode; if(tmode) print("\n"); else print("\n"); "rdp:reset" => r = 0; * => 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\n"); print("\n\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<\n", reg[R_PC], reg[R_CPSR]); rdi_cpuread(reg, (1<\n", reg[R_PC]); rdi_execute(); } rdi_close(); # Warning: this will make Linux emu crash... killgrp(); }