xref: /inferno-os/appl/cmd/rdp.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1implement Rdp;
2include "sys.m";
3	sys: Sys;
4	print, sprint: import sys;
5include "draw.m";
6include "string.m";
7	str: String;
8
9df_port: con "/dev/eia0";
10df_bps: con 38400;
11
12Rdp: module
13{
14	init:	fn(nil: ref Draw->Context, arg: list of string);
15};
16
17dfd: ref sys->FD;
18cfd: ref sys->FD;
19ifd: ref sys->FD;
20pifd: ref sys->FD;
21p_isopen := 0;
22
23R_R15: con 15;
24R_PC: con 16;
25R_CPSR: con 17;
26R_SPSR: con 18;
27NREG: con 19;
28
29debug := 0;
30nocr := 0;
31tmode := 0;
32# echar := 16r1c;		# ctrl-\
33echar := 16r1d;		# ctrl-]  (because Tk grabs the ctrl-\ )
34
35bint(x: int): array of byte
36{
37	b := array[4] of byte;
38	b[0] = byte x;
39	b[1] = byte (x>>8);
40	b[2] = byte (x>>16);
41	b[3] = byte (x>>24);
42	return b;
43}
44
45intb(b: array of byte): int
46{
47	return int b[0] | (int b[1] << 8)
48		| (int b[2] << 16) | (int b[3] << 24);
49}
50
51
52statusmsg(n: int): string
53{
54	m: string;
55	case n {
56	0 => 	m = nil;
57	1 =>	m = "Reset";
58	2 =>	m = "Undefined instruction";
59	3 =>	m = "Software interrupt";
60	4 =>	m = "Prefetch abort";
61	5 =>	m = "Data abort";
62	6 =>	m = "Address exception";
63	7 =>	m = "IRQ";
64	8 =>	m = "FIQ";
65	9 =>	m = "Error";
66	10 =>	m = "Branch Through 0";
67	253 =>	m = "Insufficient privilege";
68	254 =>	m = "Unimplemented message";
69	255 =>	m = "Undefined message";
70	* =>	m = sprint("Status %d", n);
71	}
72	return m;
73}
74
75sdc: chan of (array of byte, int);
76scc: chan of int;
77
78serinp()
79{
80	b: array of byte = nil;
81	save: array of byte = nil;
82	x := 0;
83	for(;;) {
84		m := <- scc;
85		if(m == 0) {
86			save = b[0:x];
87			continue;
88		}
89		b = nil;
90		t: int;
91		do {
92			alt {
93			m = <- scc =>
94				if(m == 0)
95					print("<strange error>\n");
96				b = nil;
97			* =>
98				;
99			}
100			if(b == nil) {
101				if(m >= 0)
102					t = m;
103				else
104					t = -m;
105				x = 0;
106				b = array[t] of byte;
107			}
108			if(save != nil) {
109				r := len save;
110				if(r > (t-x))
111					r = t-x;
112				b[x:] = save[0:r];
113				save = save[r:];
114				if(len save == 0)
115					save = nil;
116				x += r;
117				continue;
118			}
119			r := sys->read(dfd, b[x:], t-x);
120			if(r < 0)
121				sdc <-= (array of byte sprint("fail:%r"), -1);
122			if(r == 0)
123				sdc <-= (array of byte "fail:hangup", -1);
124			if(debug) {
125				if(r == 1)
126					print("<%ux>", int b[x]);
127				else
128					print("<%ux,%ux...(%d)>", int b[x], int b[x+1], r);
129			}
130			x += r;
131		} while(m >= 0 && x < t);
132		sdc <-= (b, x);
133	}
134}
135
136
137sreadn(n: int): array of byte
138{
139	b: array of byte;
140	if(n == 0)
141		return array[0] of byte;
142	scc <-= n;
143	(b, n) = <- sdc;
144	if(n < 0)
145		raise string b;
146	return b[0:n];
147}
148
149
150# yes, it's kind of a hack...
151fds := array[32] of ref Sys->FD;
152
153oscmd()
154{
155	arg := array[4] of int;
156	buf := array[4] of array of byte;
157	b := sreadn(5);
158	op := intb(b[:4]);
159	argd := int b[4];
160	for(i := 0; i<4; i++) {
161		t := (argd >> (i*2))&3;
162		case t {
163		0 =>	;
164		1 =>
165			arg[i] = int sreadn(1)[0];
166		2 =>
167			arg[i] = intb(sreadn(4));
168		3 =>
169			c := int sreadn(1)[0];
170			if(c < 255) {
171				buf[i] = array[c] of byte;
172				if(c <= 32) {
173					buf[i][0:] = sreadn(c);
174				} else
175					arg[i] = intb(sreadn(4));
176			} else {
177				b: array of byte;
178				b = sreadn(8);
179				c = intb(b[:4]);
180				arg[i] = intb(b[4:8]);
181				buf[i] = array[c] of byte;
182			}
183		}
184	}
185	for(i = 0; i<4; i++)
186		if(buf[i] != nil && len buf[i] > 32)
187			rdi_read(arg[i], buf[i], len buf[i]);
188
189	r := 0;
190	case op {
191	0 or 2 => ;
192	* =>
193		out("");
194	}
195	case op {
196	0 =>
197		if(debug)
198			print("SWI_WriteC(%d)\n", arg[0]);
199		out(string byte arg[0]);
200	2 =>
201		if(debug)
202			print("SWI_Write0(<%d>)\n", len buf[0]);
203		out(string buf[0]);
204	4 =>
205		if(debug)
206			print("SWI_ReadC()\n");
207		sys->read(ifd, b, 1);
208		r = int b[0];
209	16r66 =>
210		fname := string buf[0];
211		if(debug)
212			print("SWI_Open(%s, %d)\n", fname, arg[1]);
213		fd: ref Sys->FD;
214		case arg[1] {
215		0 or 1 =>
216			fd = sys->open(fname, Sys->OREAD);
217		2 or 3 =>
218			fd = sys->open(fname, Sys->ORDWR);
219		4 or 5 =>
220			fd = sys->open(fname, Sys->OWRITE);
221			if(fd == nil)
222				fd = sys->create(fname, Sys->OWRITE, 8r666);
223		6 or 7 =>
224			fd = sys->open(fname, Sys->OWRITE|Sys->OTRUNC);
225			if(fd == nil)
226				fd = sys->create(fname, Sys->OWRITE, 8r666);
227		8 or 9 =>
228			fd = sys->open(fname, Sys->OWRITE);
229			if(fd == nil)
230				fd = sys->create(fname, Sys->OWRITE, 8r666);
231			else
232				sys->seek(fd, big 0, Sys->SEEKEND);
233		10 or 11 =>
234			fd = sys->open(fname, Sys->ORDWR);
235			if(fd == nil)
236				fd = sys->create(fname, Sys->ORDWR, 8r666);
237			else
238				sys->seek(fd, big 0, Sys->SEEKEND);
239		}
240		if(fd != nil) {
241			r = fd.fd;
242			if(r >= len fds) {
243				print("<fd %d out of range 1-%d>\n", r, len fds);
244				r = 0;
245			} else
246				fds[r] = fd;
247		}
248	16r68 =>
249		if(debug)
250			print("SWI_Close(%d)\n", arg[0]);
251		if(arg[0] <= 0 || arg[0] >= len fds)
252			r = -1;
253		else {
254			if(fds[arg[0]] != nil)
255				fds[arg[0]] = nil;
256			else
257				r = -1;
258		}
259	16r69 =>
260		if(debug)
261			print("SWI_Write(%d, <%d>)\n", arg[0], len buf[1]);
262		if(arg[0] <= 0 || arg[0] >= len fds)
263			r = -1;
264		else
265			r = sys->write(fds[arg[0]], buf[1], len buf[1]);
266		r = arg[2]-r;
267	16r6a =>
268		if(debug)
269			print("SWI_Read(%d, 0x%ux, %d)\n", arg[0], arg[1], arg[2]);
270		if(arg[0] <= 0 || arg[0] >= len fds)
271			r = -1;
272		else {
273			d := array[arg[2]] of byte;
274			r = sys->read(fds[arg[0]], d, arg[2]);
275			if(r > 0)
276				rdi_write(d, arg[1], r);
277		}
278		r = arg[2]-r;
279	16r6b =>
280		if(debug)
281			print("SWI_Seek(%d, %d)\n", arg[0], arg[1]);
282		if(arg[0] <= 0 || arg[0] >= len fds)
283			r = -1;
284		else
285			r = int sys->seek(fds[arg[0]], big arg[1], 0);
286	16r6c =>
287		if(debug)
288			print("SWI_Flen(%d)\n", arg[0]);
289		if(arg[0] <= 0 || arg[0] >= len fds)
290			r = -1;
291		else {
292			d: Sys->Dir;
293			(r, d) = sys->fstat(fds[arg[0]]);
294			if(r >= 0)
295				r = int d.length;
296		}
297	16r6e =>
298		if(debug)
299			print("SWI_IsTTY(%d)\n", arg[0]);
300		r = 0;	# how can we detect if it's a TTY?
301	* =>
302		print("unsupported: SWI 0x%ux\n", op);
303	}
304	b = array[6] of byte;
305	b[0] = byte 16r13;
306	if(debug)
307		print("r0=%d\n", r);
308	if(r >= 0 && r <= 16rff) {
309		b[1] = byte 1;
310		b[2] = byte r;
311		sys->write(dfd, b, 3);
312	} else {
313		b[1] = byte 2;
314		b[2:] = bint(r);
315		sys->write(dfd, b, 6);
316	}
317}
318
319
320terminal()
321{
322	b := array[1024] of byte;
323	c := 3;	# num of invalid chars before resetting
324	tmode = 1;
325	for(;;) {
326		n: int;
327		b: array of byte;
328		alt {
329		scc <-= -8192 =>
330			(b, n) = <- sdc;
331		(b, n) = <- sdc =>
332			;
333		}
334		if(n < 0)
335			raise string b;
336		c -= out(string b[:n]);
337		if(c < 0) {
338			scc <-= 0;
339			raise "rdp:tmode";
340		}
341		if(!tmode) {
342			return;
343		}
344	}
345}
346
347getreply(n: int): (array of byte, int)
348{
349	loop: for(;;) {
350		c := int sreadn(1)[0];
351		case c {
352		16r21 =>
353			oscmd();
354		16r7f =>
355			raise "rdp:reset";
356		16r5f =>
357			break loop;
358		* =>
359			print("<%ux?>", c);
360			scc <-= 0;
361			raise "rdp:tmode";
362		}
363	}
364	b := sreadn(n+1);
365	s := int b[n];
366	if(s != 0) {
367		out("");
368		print("[%s]\n", statusmsg(s));
369	}
370	return (b[:n], s);
371}
372
373outstr: string;
374tpid: int;
375
376timeout(t: int, c: chan of int)
377{
378	tpid = sys->pctl(0, nil);
379	if(t > 0)
380		sys->sleep(t);
381	c <-= 0;
382	tpid = 0;
383}
384
385bsc: chan of string;
386
387bufout()
388{
389	buf := "";
390	tc := chan of int;
391	n: int;
392	s: string;
393	for(;;) {
394		alt {
395		n = <- tc =>
396			print("%s", buf);
397			buf = "";
398		s = <- bsc =>
399			#if(tpid) {
400			#	kill(tpid);
401			#	tpid = 0;
402			#}
403			if((len buf+len s) >= 1024) {
404				print("%s", buf);
405				buf = s;
406			}
407			if(s == "" || debug) {
408				print("%s", buf);
409				buf = "";
410			} else {
411				buf += s;
412				if(tpid == 0)
413					spawn timeout(300, tc);
414			}
415		}
416	}
417}
418
419out(s: string): int
420{
421	if(bsc == nil) {
422		bsc = chan of string;
423		spawn bufout();
424	}
425	c := 0;
426	if(nocr || tmode) {
427		n := "";
428		for(i:=0; i<len s; i++) {
429			if(!(nocr && s[i] == '\r'))
430				n[len n] = s[i];
431			if(s[i] >= 16r7f)
432				c++;
433		}
434		bsc <-= n;
435	} else
436		bsc <-= s;
437	return c;
438}
439
440reset(r: int)
441{
442	out("");
443	if(debug)
444		print("reset(%d)\n", r);
445	p_isopen = 0;
446	b := array of byte sprint("b9600");
447	sys->write(cfd, b, len b);
448	if(r) {
449		b[0] = byte 127;
450		sys->write(dfd, b, 1);
451		print("<sending reset>");
452	}
453	ok := 0;
454	s := "";
455	for(;;) {
456		n: int;
457		b: array of byte;
458		scc <-= -8192;
459		(b, n) = <- sdc;
460		if(n < 0)
461			raise string b;
462		for(i := 0; i<n; i++) {
463			if(b[i] == byte 127) {
464				if(!ok)
465					print("\n");
466				ok = 1;
467				s = "";
468				continue;
469			}
470			if(b[i] == byte 0) {
471				if(ok && i == n-1) {
472					out(s);
473					out("");
474					return;
475				} else {
476					s = "";
477					continue;
478				}
479			}
480			if(b[i] < byte 127)
481				s += string b[i:i+1];
482			else
483				ok = 0;
484		}
485	}
486}
487
488sa1100_reset()
489{
490	rdi_write(bint(1), int 16r90030000, 4);
491}
492
493setbps(bps: int)
494{
495	# for older Emu's using setserial hacks...
496	if(bps > 38400)
497		sys->write(cfd, array of byte "b38400", 6);
498
499	out("");
500	print("<bps=%d>\n", bps);
501	b := array of byte sprint("b%d", bps);
502	if(sys->write(cfd, b, len b) != len b)
503		print("setbps failed: %r\n");
504}
505
506rdi_open(bps: int)
507{
508	if(debug)
509		print("rdi_open(%d)\n", bps);
510	b := array[7] of byte;
511	usehack := 0;
512	if(!p_isopen) {
513		b[0] = byte 0;
514		b[1] = byte (0 | (1<<1));
515		b[2:] = bint(0);
516		case bps {
517		9600 => b[6] = byte 1;
518		19200 => b[6] = byte 2;
519		38400 => b[6] = byte 3;
520		# 57600 => b[6] = byte 4;
521		# 115200 => b[6] = byte 5;
522		# 230400 => b[6] = byte 6;
523		* =>
524			b[6] = byte 1;
525			usehack = 1;
526		}
527		sys->write(dfd, b, 7);
528		getreply(0);
529		p_isopen = 1;
530		if(usehack)
531			sa1100_setbps(bps);
532		else
533			setbps(bps);
534	}
535}
536
537rdi_close()
538{
539	if(debug)
540		print("rdi_close()\n");
541	b := array[1] of byte;
542	if(p_isopen) {
543		b[0] = byte 1;
544		sys->write(dfd, b, 1);
545		getreply(0);
546		p_isopen = 0;
547	}
548}
549
550rdi_cpuread(reg: array of int, mask: int)
551{
552	if(debug)
553		print("rdi_cpuread(..., 0x%ux)\n", mask);
554	n := 0;
555	for(i := 0; i<NREG; i++)
556		if(mask&(1<<i))
557			n += 4;
558	b := array[6+n] of byte;
559	b[0] = byte 4;
560	b[1] = byte 255;	# current mode
561	b[2:] = bint(mask);
562	sys->write(dfd, b, 6);
563	(b, nil) = getreply(n);
564	n = 0;
565	for(i = 0; i<NREG; i++)
566		if(mask&(1<<i)) {
567			reg[i] = intb(b[n:n+4]);
568			n += 4;
569		}
570}
571
572rdi_cpuwrite(reg: array of int, mask: int)
573{
574	if(debug)
575		print("rdi_cpuwrite(..., 0x%ux)\n", mask);
576	n := 0;
577	for(i := 0; i<32; i++)
578		if(mask&(1<<i))
579			n += 4;
580	b := array[6+n] of byte;
581	b[0] = byte 5;
582	b[1] = byte 255;	# current mode
583	b[2:] = bint(mask);
584	n = 6;
585	for(i = 0; i<32; i++)
586		if(mask&(1<<i)) {
587			b[n:] = bint(reg[i]);
588			n += 4;
589		}
590	sys->write(dfd, b, n);
591	getreply(0);
592}
593
594dump(b: array of byte, n: int)
595{
596	for(i := 0; i<n; i++)
597		print(" %d: %2.2ux\n", i, int b[i]);
598}
599
600rdi_read(addr: int, b: array of byte, n: int): int
601{
602	if(debug)
603		print("rdi_read(0x%ux, ..., 0x%ux)\n", addr, n);
604	if(n == 0)
605		return 0;
606	sb := array[9] of byte;
607	sb[0] = byte 2;
608	sb[1:] = bint(addr);
609	sb[5:] = bint(n);
610	sys->write(dfd, sb, 9);
611	(b[0:], nil) = getreply(n);
612	# if error, need to read count of bytes transferred
613	return n;
614}
615
616rdi_write(b: array of byte, addr: int, n: int): int
617{
618	if(debug)
619		print("rdi_write(..., 0x%ux, 0x%ux)\n", addr, n);
620	if(n == 0)
621		return 0;
622	sb := array[9+n] of byte;
623	sb[0] = byte 3;
624	sb[1:] = bint(addr);
625	sb[5:] = bint(n);
626	sb[9:] = b[:n];
627	sys->write(dfd, sb, 9);
628	x := 0;
629	while(n) {
630		q := n;
631		if(q > 8192)
632			q = 8192;
633		r := sys->write(dfd, b[x:], q);
634		if(debug)
635			print("rdi_write: r=%d ofs=%d n=%d\n", r, x, n);
636		if(r < 0)
637			raise "fail:hangup";
638		x += r;
639		n -= r;
640	}
641	getreply(0);
642	return n;
643}
644
645rdi_execute()
646{
647	if(debug)
648		print("rdi_execute()\n");
649	sb := array[2] of byte;
650	sb[0] = byte 16r10;
651	sb[1] = byte 0;
652	sys->write(dfd, sb, 2);
653	getreply(0);
654	out("");
655}
656
657rdi_info(n: int, arg: int)
658{
659	sb := array[9] of byte;
660	sb[0] = byte 16r12;
661	sb[1:] = bint(n);
662	sb[5:] = bint(arg);
663	sys->write(dfd, sb, 9);
664	getreply(0);
665}
666
667
668regdump()
669{
670	out("");
671	reg := array[NREG] of int;
672	# rdi_cpuread(reg, 16rffff|(1<<R_PC)|(1<<R_CPSR)|(1<<R_SPSR));
673	rdi_cpuread(reg, 16rffff|(1<<R_PC)|(1<<R_CPSR));
674	for(i := 0; i < 16; i += 4)
675		print("  r%-2d=%8.8ux  r%-2d=%8.8ux  r%-2d=%8.8ux  r%-2d=%8.8ux\n",
676			i, reg[i], i+1, reg[i+1],
677			i+2, reg[i+2], i+3, reg[i+3]);
678	print("   pc=%8.8ux  psr=%8.8ux\n",
679			reg[R_PC], reg[R_CPSR]);
680}
681
682printable(b: array of byte): string
683{
684	s := "";
685	for(i := 0; i < len b; i++)
686		if(b[i] >= byte ' ' && b[i] <= byte 126)
687			s += string b[i:i+1];
688		else
689			s += ".";
690	return s;
691}
692
693examine(a: int, n: int)
694{
695	b := array[4] of byte;
696	for(i := 0; i<n; i++) {
697		rdi_read(a, b, 4);
698		print("0x%8.8ux: 0x%8.8ux  \"%s\"\n", a, intb(b), printable(b));
699		a += 4;
700	}
701}
702
703atoi(s: string): int
704{
705	b := 10;
706	if(len s < 1)
707		return 0;
708	if(s[0] == '0') {
709		b = 8;
710		s = s[1:];
711		if(len s < 1)
712			return 0;
713		if(s[0] == 'x' || s[0] == 'X') {
714			b = 16;
715			s = s[1:];
716		}
717	}
718	n: int;
719	(n, nil) = str->toint(s, b);
720	return n;
721}
722
723regnum(s: string): int
724{
725	if(len s < 2)
726		return -1;
727	if(s[0] == 'r' && s[1] >= '0' && s[1] <= '9')
728		return atoi(s[1:]);
729	case s {
730	"pc" => return R_PC;
731	"cpsr" or "psr" => return R_CPSR;
732	"spsr" => return R_SPSR;
733	* => return -1;
734	}
735}
736
737cmdhelp()
738{
739	print("	e <addr> [<count>]  - examine memory\n");
740	print("	d <addr> [<value>...]  - deposit values in memory\n");
741	print("	get <file> <addr>  - read file into memory at addr\n");
742	print("	load <file>  - load AIF file and set the PC\n");
743	print("	r  - print all registers\n");
744	print("	<reg>=<val>  - set register value\n");
745	print("	sb  - run builtin sboot (pc=0x40; g)\n");
746	print("	reset - trigger SA1100 software reset\n");
747	print("	bps <speed>  - change bps rate (SA1100 only)\n");
748	print("	q  - quit\n");
749}
750
751cmdmode()
752{
753	b := array[1024] of byte;
754	for(;;) {
755		print("rdp: ");
756		r := sys->read(ifd, b, len b);
757		if(r < 0)
758			raise sprint("fail:%r");
759		if(r == 0 || (r == 1 && b[0] == byte 4))
760			break;
761		n: int;
762		a: list of string;
763		(n, a) = sys->tokenize(string b[0:r], " \t\n=");
764		if(n < 1)
765			continue;
766		case hd a {
767		"sb" =>
768			sbmode();
769			rdi_execute();
770		"q" or "quit" =>
771			return;
772		"r" or "reg" =>
773			regdump();
774		"get" or "getfile" or "l" or "load" =>
775			{
776				if((hd a)[0] == 'l')
777					aifload(hd tl a, -1);
778				else
779					aifload(hd tl a, atoi(hd tl tl a));
780			}exception e{
781			"fail:*" =>
782				print("error: %s\n", e[5:]);
783				continue;
784			}
785		"g" or "go" =>
786			rdi_execute();
787		"reset" =>
788			sa1100_reset();
789		"e" =>
790			a = tl a;
791			x := atoi(hd a);
792			n = 1;
793			a = tl a;
794			if(a != nil)
795				n = atoi(hd a);
796			examine(x, n);
797		"d" =>
798			a = tl a;
799			x := atoi(hd a);
800			for(i := 2; i<n; i++) {
801				a = tl a;
802				rdi_write(bint(atoi(hd a)), x, 4);
803				x += 4;
804			}
805		"info" =>
806			a = tl a;
807			rdi_info(16r180, atoi(hd a));
808		"bps" =>
809			sa1100_setbps(atoi(hd tl a));
810		"help" or "?" =>
811			cmdhelp();
812		* =>
813			if((rn := regnum(hd a)) > -1) {
814				reg := array[NREG] of int;
815				reg[rn] = atoi(hd tl a);
816				rdi_cpuwrite(reg, 1<<rn);
817			} else
818				print("?\n");
819		}
820	}
821}
822
823sbmode()
824{
825	if(debug)
826		print("sbmode()\n");
827	reg := array[NREG] of int;
828	reg[R_PC] = 16r40;
829	rdi_cpuwrite(reg, 1<<R_PC);
830}
831
832sbmodeofs(ofs: int)
833{
834	if(debug)
835		print("sbmode(0x%ux)\n", ofs);
836	reg := array[NREG] of int;
837	reg[0] = ofs;
838	reg[R_PC] = 16r48;
839	rdi_cpuwrite(reg, (1<<0)|(1<<R_PC));
840}
841
842inp: string = "";
843
844help: con "(q)uit, (i)nt, (b)reak, !c(r), !(l)ine, !(t)erminal, (s<bps>), (.)cont, (!cmd)\n";
845
846menu(fi: ref Sys->FD)
847{
848	w := israw;
849	if(israw)
850		raw(0);
851mloop:	for(;;) {
852		out("");
853		print("rdp> ");
854		b := array[256] of byte;
855		r := sys->read(fi, b, len b);
856		case int b[0] {
857		'q' =>
858			killgrp();
859			exit;
860		'i' =>
861			b[0] = byte 16r18;
862			sys->write(dfd, b[0:1], 1);
863			break mloop;
864		'b' =>
865			sys->write(cfd, array of byte "k", 1);
866			break mloop;
867		'!' =>
868			cmd := string b[1:r-1];
869			print("!%s\n", cmd);
870			# system(cmd)
871			print("!\n");
872			break mloop;
873		'l' =>
874			w = !w;
875			break mloop;
876		'r' =>
877			nocr = !nocr;
878			break mloop;
879		'd' =>
880			debug = !debug;
881			break mloop;
882		't' =>
883			sys->write(pifd, array[] of { byte 4 }, 1);
884			sdc <-= (array of byte "rdp:tmode", -1);
885			break mloop;
886		'.' =>
887			break mloop;
888		's' =>
889			bps := atoi(string b[1:r-1]);
890			setbps(bps);
891		* =>
892			print(help);
893			continue;
894		}
895	}
896	if(israw != w)
897		raw(w);
898}
899
900
901input()
902{
903	fi := sys->fildes(0);
904	b := array[1024] of byte;
905iloop: 	for(;;) {
906		r := sys->read(fi, b, len b);
907		if(r < 0) {
908			print("stdin: %r");
909			killgrp();
910			exit;
911		}
912		for(i:=0; i<r; i++) {
913			if(b[i] == byte echar) {
914				menu(fi);
915				continue iloop;
916			}
917		}
918		if(r == 0) {
919			b[0] = byte 4;	# ctrl-d
920			r = 1;
921		}
922		if(tmode)
923			sys->write(dfd, b, r);
924		else
925			sys->write(pifd, b, r);
926	}
927}
928
929ccfd: ref Sys->FD;
930israw := 0;
931
932raw(on: int)
933{
934	if(ccfd == nil) {
935		ccfd = sys->open("/dev/consctl", Sys->OWRITE);
936		if(ccfd == nil) {
937			print("/dev/consctl: %r\n");
938			return;
939		}
940	}
941	if(on)
942		sys->fprint(ccfd, "rawon");
943	else
944		sys->fprint(ccfd, "rawoff");
945	israw = on;
946}
947
948killgrp()
949{
950	pid := sys->pctl(0, nil);
951	f := "/prog/"+string pid+"/ctl";
952	fd := sys->open(f, Sys->OWRITE);
953	if(fd == nil)
954		print("%s: %r\n", f);
955	else
956		sys->fprint(fd, "killgrp");
957}
958
959kill(pid: int)
960{
961	f := "/prog/"+string pid+"/ctl";
962	fd := sys->open(f, Sys->OWRITE);
963	if(fd == nil)
964		print("%s: %r\n", f);
965	else
966		sys->fprint(fd, "kill");
967}
968
969
970# Code for switching to previously unsupported bps rates:
971
972##define UTCR1	0x4
973##define UTCR2	0x8
974##define UTCR3	0xc
975##define UTDR	0x14
976##define UTSR0	0x1c
977##define UTSR1	0x20
978#
979#TEXT _startup(SB), $-4
980#	MOVW	$0x80000000,R2
981#	ORR	$0x00050000,R2
982#
983#	MOVW	$0, R1
984#	MOVW	R1, UTDR(R2)	/* send ack */
985#
986#wait:
987#	MOVW	UTSR1(R2), R1
988#	TST	$1, R1		/* TBY */
989#	BNE	wait
990#
991#	MOVW	$0x90000000,R3
992#	ORR	$0x00000010,R3
993#	MOVW	(R4),R1
994#	ADD	$0x5a000,R1	/* 100 ms */
995#delay1:
996#	MOVW	(R3),R1
997#	SUB.S	$0x5a000, R1	/* 100 ms */
998#	BLO	delay1
999#
1000#	MOVW	UTCR3(R2), R5	/* save utcr3 */
1001#	MOVW	$0, R1
1002#	MOVW	R1, UTCR3(R2)	/* disable xmt/rcv */
1003#
1004#	MOVW	R0, R1
1005#	AND	$0xff, R1
1006#	MOVW	R1, UTCR2(R2)
1007#	MOVW	R0 >> 8, R1
1008#	MOVW	R1, UTCR1(R2)
1009#
1010#	MOVW	$0xff, R1
1011#	MOVW	R1, UTSR0(R2)	/* clear sticky bits */
1012#
1013#	MOVW	$3, R1
1014#	MOVW	R1, UTCR3(R2)	/* enable xmt/rcv */
1015#
1016#	MOVW	$0, R0
1017#sync:
1018#	MOVW	R0, UTDR(R2)	/* send sync char */
1019#syncwait:
1020#	MOVW	UTSR1(R2), R1
1021#	TST	$1, R1		/* TBY */
1022#	BNE	syncwait
1023#	TST	$2, R1		/* RNE */
1024#	BEQ	sync
1025#	MOVW	UTDR(R2), R0
1026#	MOVW	R0, UTDR(R2)	/* echo rcvd char */
1027#
1028#	MOVW	$0xff, R1
1029#	MOVW	R1, UTSR0(R2)	/* clear sticky bits */
1030#	MOVW	R5, UTCR3(R2)	/* re-enable xmt/rcv and interrupts */
1031#
1032#	WORD	$0xef000011	/* exit */
1033
1034
1035bpscode := array[] of {
1036	16re3a22102, 16re3822805, 16re3a11000, 16re5821014,
1037	16re5921020, 16re3110001, big 16r1afffffc, 16re3a33209,
1038	16re3833010, 16re5941000, 16re2811a5a, 16re5931000,
1039	16re2511a5a, big 16r3afffffc, 16re592500c, 16re3a11000,
1040	16re582100c, 16re1a11000, 16re20110ff, 16re5821008,
1041	16re1a11420, 16re5821004, 16re3a110ff, 16re582101c,
1042	16re3a11003, 16re582100c, 16re3a00000, 16re5820014,
1043	16re5921020, 16re3110001, big 16r1afffffc, 16re3110002,
1044	big 16r0afffff9, 16re5920014, 16re5820014, 16re3a110ff,
1045	16re582101c, 16re582500c, 16ref000011,
1046};
1047
1048sa1100_setbps(bps: int)
1049{
1050	print("<sa1100_setbps %d>", bps);
1051	nb := len bpscode*4;
1052	b := array[nb] of byte;
1053	for(i := 0; i < len bpscode; i++)
1054		b[i*4:] = bint(int bpscode[i]);
1055	rdi_write(b, 16r8080, nb);
1056	reg := array[NREG] of int;
1057	d := (3686400/(bps*16))-1;
1058	reg[0] = d;
1059	reg[R_PC] = 16r8080;
1060	rdi_cpuwrite(reg, (1<<0)|(1<<R_PC));
1061	sb := array[2] of byte;
1062	sb[0] = byte 16r10;
1063	sb[1] = byte 0;
1064	sys->write(dfd, sb, 2);
1065	rb := sreadn(1);
1066	setbps(bps);
1067	do rb = sreadn(1);
1068	while(rb[0] != byte 0);
1069	sb[0] = byte 16rff;
1070	sys->write(dfd, sb, 1);
1071	do rb = sreadn(1);
1072	while(rb[0] != sb[0]);
1073	getreply(0);
1074}
1075
1076aifload(fname: string, adr: int)
1077{
1078	out("");
1079	if(adr < 0)
1080		print("<aifload %s>\n", fname);
1081	fd := sys->open(fname, Sys->OREAD);
1082	if(fd == nil)
1083		raise sprint("fail:%s:%r", fname);
1084	d: Sys->Dir;
1085	(nil, d) = sys->fstat(fd);
1086	b := array[int d.length] of byte;
1087	sys->read(fd, b, len b);
1088	if(adr < 0) {
1089		if(len b < 128)
1090			raise sprint("fail:%s:not aif", fname);
1091		tsize := intb(b[20:24]);
1092		dsize := intb(b[24:28]);
1093		bsize := intb(b[32:36]);
1094		tbase := intb(b[40:44]);
1095		dbase := intb(b[52:56]);
1096		print("%ux/%ux: %ux+%ux+%ux\n", tbase, dbase, tsize, dsize, bsize);
1097		rdi_write(b, tbase, tsize+dsize);
1098		reg := array[NREG] of int;
1099		reg[R_PC] = tbase+8;
1100		rdi_cpuwrite(reg, 1<<R_PC);
1101	} else
1102		rdi_write(b, adr, int d.length);
1103}
1104
1105
1106init(nil: ref Draw->Context, argv: list of string)
1107{
1108	sys = load Sys Sys->PATH;
1109	str = load String String->PATH;
1110
1111	sys->pctl(Sys->NEWPGRP, nil);
1112
1113	port := df_port;
1114	bps := df_bps;
1115	usecmdmode := 0;
1116	ofs := -1;
1117	prog: string = nil;
1118
1119	argv = tl argv;
1120	while(argv != nil) {
1121		a := hd argv;
1122		argv = tl argv;
1123		if(len a >= 2 && a[0] == '-')
1124			case a[1] {
1125			'c' =>
1126				usecmdmode = 1;
1127			'O' =>
1128				ofs = atoi(a[2:]);
1129			'd' =>
1130				debug = 1;
1131			'p' =>
1132				port = a[2:];
1133			's' =>
1134				bps = atoi(a[2:]);
1135			'r' =>
1136				nocr = 1;
1137			'l' =>
1138				raw(1);
1139			'e' =>
1140				if(a[2] == '^')
1141					echar = a[3]&16r1f;
1142				else
1143					echar = a[2];
1144			't' =>
1145				tmode = 1;
1146			'h' =>
1147				print("usage: rdp [-crdlht] [-e<c>] [-O<ofs>] [-p<port>] [-s<bps>] [prog]\n");
1148				return;
1149			* =>
1150				print("invalid option: %s\n", a);
1151				return;
1152			}
1153		else
1154			prog = a;
1155	}
1156
1157	print("rdp 0.17 (port=%s, bps=%d)\n", port, bps);
1158	dfd = sys->open(port, Sys->ORDWR);
1159	if(dfd == nil) {
1160		sys->print("open %s failed: %r\n", port);
1161		return;
1162	}
1163	cfd = sys->open(port+"ctl", Sys->OWRITE);
1164	if(cfd == nil)
1165		sys->print("warning: open %s failed: %r\n", port+"ctl");
1166
1167	pfd := array[2] of ref Sys->FD;
1168	sys->pipe(pfd);
1169	ifd = pfd[1];
1170	pifd = pfd[0];
1171	(scc, sdc) = (chan of int, chan of (array of byte, int));
1172	spawn serinp();
1173	spawn input();
1174	r := 1;
1175	{
1176		if(tmode)
1177			terminal();
1178		reset(r);
1179		if(!p_isopen) {
1180			rdi_open(bps);
1181			rdi_info(16r180, (1<<0)|(1<<1)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8));
1182		}
1183		# print("\n<connection established>\n");
1184		print("\n<contact has been made>\n");
1185		if(usecmdmode) {
1186			cmdmode();
1187		} else {
1188			if(prog != nil)
1189				aifload(prog, -1);
1190			else if(ofs != -1)
1191				sbmodeofs(ofs);
1192			else
1193				sbmode();
1194			reg := array[NREG] of int;
1195			# rdi_cpuread(reg, (1<<R_PC)|(1<<R_CPSR));
1196			# print("<execute at %ux; cpsr=%ux>\n", reg[R_PC], reg[R_CPSR]);
1197			rdi_cpuread(reg, (1<<R_PC));
1198			print("<execute at %ux>\n", reg[R_PC]);
1199			rdi_execute();
1200		}
1201		rdi_close();
1202
1203		# Warning: this will make Linux emu crash...
1204		killgrp();
1205	}exception e{
1206	"fail:*" =>
1207		if(israw)
1208			raw(0);
1209		killgrp();
1210		raise e;
1211	"rdp:*" =>
1212		out("");
1213		if(debug)
1214			print("<exception: %s>\n", e);
1215		case e {
1216		"rdp:error" =>	;
1217		"rdp:tmode" =>
1218			tmode = !tmode;
1219			if(tmode)
1220				print("<terminal mode>\n");
1221			else
1222				print("<rdp mode>\n");
1223		"rdp:reset" =>
1224			r = 0;
1225		* =>
1226			r = 1;
1227		}
1228	}
1229}
1230
1231