change includes to use new csr base address
[mw/milkymist.git] / software / demo / shell.c
1 /*
2  * Milkymist VJ SoC (Software)
3  * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, version 3 of the License.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <console.h>
22 #include <uart.h>
23 #include <blockdev.h>
24 #include <fatfs.h>
25 #include <system.h>
26 #include <math.h>
27 #include <irq.h>
28 #include <board.h>
29 #include <hw/pfpu.h>
30 #include <hw/tmu.h>
31 #include <hw/sysctl.h>
32 #include <hw/gpio.h>
33 #include <hw/interrupts.h>
34 #include <hw/minimac.h>
35 #include <hw/bt656cap.h>
36 #include <hw/rc5.h>
37 #include <hw/midi.h>
38
39 #include <hal/vga.h>
40 #include <hal/snd.h>
41 #include <hal/tmu.h>
42 #include <hal/time.h>
43 #include <hal/brd.h>
44 #include <hal/vin.h>
45
46 #include "line.h"
47 #include "wave.h"
48 #include "rpipe.h"
49 #include "cpustats.h"
50 #include "memstats.h"
51 #include "shell.h"
52 #include "renderer.h"
53
54 #define NUMBER_OF_BYTES_ON_A_LINE 16
55 static void dump_bytes(unsigned int *ptr, int count, unsigned addr)
56 {
57         char *data = (char *)ptr;
58         int line_bytes = 0, i = 0;
59
60         putsnonl("Memory dump:");
61         while(count > 0){
62                 line_bytes =
63                         (count > NUMBER_OF_BYTES_ON_A_LINE)?
64                                 NUMBER_OF_BYTES_ON_A_LINE : count;
65
66                 printf("\n0x%08x  ", addr);
67                 for(i=0;i<line_bytes;i++)
68                         printf("%02x ", *(unsigned char *)(data+i));
69
70                 for(;i<NUMBER_OF_BYTES_ON_A_LINE;i++)
71                         printf("   ");
72
73                 printf(" ");
74
75                 for(i=0;i<line_bytes;i++) {
76                         if((*(data+i) < 0x20) || (*(data+i) > 0x7e))
77                                 printf(".");
78                         else
79                                 printf("%c", *(data+i));
80                 }
81
82                 for(;i<NUMBER_OF_BYTES_ON_A_LINE;i++)
83                         printf(" ");
84
85                 data += (char)line_bytes;
86                 count -= line_bytes;
87                 addr += line_bytes;
88         }
89         printf("\n");
90 }
91
92 static void mr(char *startaddr, char *len)
93 {
94         char *c;
95         unsigned *addr;
96         unsigned length;
97
98         if(*startaddr == 0) {
99                 printf("mr <address> [length]\n");
100                 return;
101         }
102         addr = (unsigned *)strtoul(startaddr, &c, 0);
103         if(*c != 0) {
104                 printf("incorrect address\n");
105                 return;
106         }
107         if(*len == 0) {
108                 length = 1;
109         } else {
110                 length = strtoul(len, &c, 0);
111                 if(*c != 0) {
112                         printf("incorrect length\n");
113                         return;
114                 }
115         }
116
117         dump_bytes(addr, length, (unsigned)addr);
118 }
119
120 static void mw(char *addr, char *value, char *count)
121 {
122         char *c;
123         unsigned *addr2;
124         unsigned value2;
125         unsigned count2;
126         unsigned i;
127
128         if((*addr == 0) || (*value == 0)) {
129                 printf("mw <address> <value>\n");
130                 return;
131         }
132         addr2 = (unsigned *)strtoul(addr, &c, 0);
133         if(*c != 0) {
134                 printf("incorrect address\n");
135                 return;
136         }
137         value2 = strtoul(value, &c, 0);
138         if(*c != 0) {
139                 printf("incorrect value\n");
140                 return;
141         }
142         if(*count == 0) {
143                 count2 = 1;
144         } else {
145                 count2 = strtoul(count, &c, 0);
146                 if(*c != 0) {
147                         printf("incorrect count\n");
148                         return;
149                 }
150         }
151         for(i=0;i<count2;i++) *addr2++ = value2;
152 }
153
154 static int lscb(const char *filename, const char *longname, void *param)
155 {
156         printf("%12s [%s]\n", filename, longname);
157         return 1;
158 }
159
160 static void ls()
161 {
162         if(!fatfs_init(BLOCKDEV_FLASH, 0)) return;
163         fatfs_list_files(lscb, NULL);
164         fatfs_done();
165 }
166
167 static void edid()
168 {
169         char buf[256];
170
171         if(!vga_read_edid(buf)) {
172                 printf("Failed to read EDID\n");
173                 return;
174         }
175         dump_bytes((unsigned int *)buf, 256, 0);
176 }
177
178 static void render(const char *filename)
179 {
180         char buffer[8192];
181         int size;
182
183         if(*filename == 0) {
184                 printf("render <filename>\n");
185                 return;
186         }
187
188         if(!fatfs_init(BLOCKDEV_FLASH, 0)) return;
189         if(!fatfs_load(filename, buffer, sizeof(buffer), &size)) return;
190         fatfs_done();
191         buffer[size] = 0;
192
193         renderer_start(buffer);
194 }
195
196 static void stats()
197 {
198         int hours, mins, secs;
199         struct timestamp ts;
200         unsigned int amat;
201         unsigned int netbw;
202         unsigned int occupancy;
203
204         time_get(&ts);
205         secs = ts.sec;
206         mins = secs/60;
207         secs -= mins*60;
208         hours = mins/60;
209         mins -= hours*60;
210         printf("Uptime: %02d:%02d:%02d  FPS: %d  CPU:%3d%%\n", hours, mins, secs,
211                 rpipe_fps(),
212                 cpustats_load());
213
214         amat = memstat_amat();
215         netbw = memstat_net_bandwidth();
216         occupancy = memstat_occupancy();
217         if(occupancy != 0) {
218                 printf("Net memory bandwidth : %d Mbps\n", netbw);
219                 printf("Memory bus occupancy : %d%%\n", occupancy);
220                 printf("Avg. mem. access time: %d.%02d cycles\n", amat/100, amat%100);
221         }
222 }
223
224 static void help()
225 {
226         puts("Milkymist demo firmware\n");
227         puts("Available commands:");
228         puts("ls         - list files on the memory card");
229         puts("render     - start rendering a patch");
230         puts("irender    - input patch equations interactively");
231         puts("stop       - stop renderer");
232         puts("stats      - print system stats");
233         puts("reboot     - system reset");
234 }
235
236 static void cpucfg()
237 {
238         unsigned long cpu_cfg;
239         
240         __asm__ volatile(
241                 "rcsr %0, cfg\n\t"
242                 : "=r"(cpu_cfg)
243         );
244         printf("CPU config word: 0x%08x\n", cpu_cfg);
245         printf("Options: ");
246         if(cpu_cfg & 0x001) printf("M ");
247         if(cpu_cfg & 0x002) printf("D ");
248         if(cpu_cfg & 0x004) printf("S ");
249         if(cpu_cfg & 0x008) printf("X ");
250         if(cpu_cfg & 0x010) printf("U ");
251         if(cpu_cfg & 0x020) printf("CC ");
252         if(cpu_cfg & 0x040) printf("DC ");
253         if(cpu_cfg & 0x080) printf("IC ");
254         if(cpu_cfg & 0x100) printf("G ");
255         if(cpu_cfg & 0x200) printf("H ");
256         if(cpu_cfg & 0x400) printf("R ");
257         if(cpu_cfg & 0x800) printf("J ");
258         printf("\n");
259         printf("IRQs: %d\n", (cpu_cfg >> 12) & 0x3F);
260         printf("Breakpoints: %d\n", (cpu_cfg >> 18) & 0x0F);
261         printf("Watchpoints: %d\n", (cpu_cfg >> 22) & 0x0F);
262         printf("CPU revision: %d\n", cpu_cfg >> 26);
263 }
264
265 static void loadpic(const char *filename)
266 {
267         int size;
268         
269         if(*filename == 0) {
270                 printf("loadpic <filename>\n");
271                 return;
272         }
273
274         if(!fatfs_init(BLOCKDEV_FLASH, 0)) return;
275         if(!fatfs_load(filename, (void *)vga_backbuffer, vga_hres*vga_vres*2, &size)) return;
276         fatfs_done();
277
278         vga_swap_buffers();
279 }
280
281 static void checker()
282 {
283         int x, y;
284
285         for(y=0;y<vga_vres;y++)
286                 for(x=0;x<vga_hres;x++)
287                         if((x/4+y/4) & 1)
288                                 vga_backbuffer[y*vga_hres+x] = 0x0000;
289                         else
290                                 vga_backbuffer[y*vga_hres+x] = 0xffff;
291         vga_swap_buffers();
292 }
293
294 /*
295  * Low-level PFPU test, bypassing driver.
296  * This test should only be run when the driver task queue
297  * is empty.
298  */
299 static struct tmu_vertex mesh[128][128] __attribute__((aligned(8)));
300 static void pfputest()
301 {
302         unsigned int *pfpu_regs = (unsigned int *)CSR_PFPU_DREGBASE;
303         unsigned int *pfpu_code = (unsigned int *)CSR_PFPU_CODEBASE;
304         int x, y;
305         int timeout;
306         unsigned int oldmask;
307
308         /* Do not let the driver get our interrupt */
309         oldmask = irq_getmask();
310         irq_setmask(oldmask & (~IRQ_PFPU));
311
312         for(y=0;y<128;y++)
313                 for(x=0;x<128;x++) {
314                         mesh[y][x].x = 0xdeadbeef;
315                         mesh[y][x].y = 0xdeadbeef;
316                 }
317
318         CSR_PFPU_MESHBASE = (unsigned int)&mesh;
319         //CSR_PFPU_HMESHLAST = 6;
320         //CSR_PFPU_VMESHLAST = 9;
321
322         CSR_PFPU_HMESHLAST = 11;
323         CSR_PFPU_VMESHLAST = 9;
324
325         pfpu_regs[3] = 0x41300000;
326         pfpu_regs[4] = 0x41100000;
327
328         pfpu_code[ 0] = 0x00000300;
329         pfpu_code[ 1] = 0x00040300;
330         pfpu_code[ 2] = 0x00000000;
331         pfpu_code[ 3] = 0x00000003;
332         pfpu_code[ 4] = 0x00000004;
333         pfpu_code[ 5] = 0x000c2080;
334         pfpu_code[ 6] = 0x00000000;
335         pfpu_code[ 7] = 0x00000000;
336         pfpu_code[ 8] = 0x00000000;
337         pfpu_code[ 9] = 0x00000005;
338         pfpu_code[10] = 0x00142b80;
339
340         CSR_PFPU_CTL = PFPU_CTL_START;
341         printf("Waiting for PFPU...\n");
342         timeout = 30;
343         do {
344                 printf("%08x vertices:%d collisions:%d strays:%d last:%08x pc:%04x\n",
345                         CSR_PFPU_CTL, CSR_PFPU_VERTICES, CSR_PFPU_COLLISIONS, CSR_PFPU_STRAYWRITES, CSR_PFPU_LASTDMA, 4*CSR_PFPU_PC);
346         } while((timeout--) && (CSR_PFPU_CTL & PFPU_CTL_BUSY));
347         if(timeout > 0)
348                 printf("OK\n");
349         else
350                 printf("Timeout\n");
351
352         asm volatile( /* Invalidate Level-1 data cache */
353                 "wcsr DCC, r0\n"
354                 "nop\n"
355         );
356
357         printf("Result:\n");
358         for(y=0;y<10;y++) {
359                 for(x=0;x<12;x++)
360                         printf("%08x ", mesh[y][x].x);
361                 printf("\n");
362         }
363         printf("\n");
364         for(y=0;y<10;y++) {
365                 for(x=0;x<12;x++)
366                         printf("%08x ", mesh[y][x].y);
367                 printf("\n");
368         }
369
370         printf("Program:\n");
371         for(x=0;x<11;x++)
372                 printf("%08x ", pfpu_code[x]);
373         printf("\n");
374
375         CSR_PFPU_CTL = 0; /* Ack interrupt */
376         irq_ack(IRQ_PFPU);
377         irq_setmask(oldmask);
378 }
379
380 static void tmutest_callback(struct tmu_td *td)
381 {
382         int *complete;
383         complete = (int *)td->user;
384         *complete = 1;
385 }
386
387 static void tmutest()
388 {
389         int x, y;
390         static struct tmu_vertex srcmesh[TMU_MESH_MAXSIZE][TMU_MESH_MAXSIZE] __attribute__((aligned(8)));
391         struct tmu_td td;
392         volatile int complete;
393
394         for(y=0;y<=32;y++)
395                 for(x=0;x<=32;x++) {
396                         srcmesh[y][x].x = (10*x) << TMU_FIXEDPOINT_SHIFT;
397                         srcmesh[y][x].y = (7*y) << TMU_FIXEDPOINT_SHIFT;
398                 }
399
400         td.flags = 0;
401         td.hmeshlast = 32;
402         td.vmeshlast = 32;
403         td.brightness = TMU_BRIGHTNESS_MAX;
404         td.chromakey = 0;
405         td.vertices = &srcmesh[0][0];
406         td.texfbuf = vga_frontbuffer;
407         td.texhres = vga_hres;
408         td.texvres = vga_vres;
409         td.texhmask = TMU_MASK_FULL;
410         td.texvmask = TMU_MASK_FULL;
411         td.dstfbuf = vga_backbuffer;
412         td.dsthres = vga_hres;
413         td.dstvres = vga_vres;
414         td.dsthoffset = 0;
415         td.dstvoffset = 0;
416         td.dstsquarew = vga_hres/32;
417         td.dstsquareh = vga_vres/32;
418         td.alpha = TMU_ALPHA_MAX;
419         
420         td.callback = tmutest_callback;
421         td.user = (void *)&complete;
422
423         complete = 0;
424         flush_bridge_cache();
425         tmu_submit_task(&td);
426         while(!complete);
427         vga_swap_buffers();
428 }
429
430 static void tmubench()
431 {
432         unsigned int oldmask;
433         int i;
434         int zoom;
435         int x, y;
436         static struct tmu_vertex srcmesh[TMU_MESH_MAXSIZE][TMU_MESH_MAXSIZE] __attribute__((aligned(8)));
437         static unsigned short int texture[512*512] __attribute__((aligned(16)));
438         struct tmu_td td;
439         volatile int complete;
440         unsigned int t;
441         int hits, reqs;
442
443         /* Disable slowout */
444         oldmask = irq_getmask();
445         irq_setmask(oldmask & (~IRQ_TIMER1));
446         uart_force_sync(1);
447         
448         for(i=0;i<512*512;i++)
449                 texture[i] = i;
450         flush_bridge_cache();
451
452         for(zoom=0;zoom<16*64*2;zoom++) {
453                 for(y=0;y<=32;y++)
454                         for(x=0;x<=32;x++) {
455                                 srcmesh[y][x].x = zoom*x;
456                                 srcmesh[y][x].y = zoom*y;
457                         }
458
459                 td.flags = 0;
460                 td.hmeshlast = 32;
461                 td.vmeshlast = 32;
462                 td.brightness = TMU_BRIGHTNESS_MAX;
463                 td.chromakey = 0;
464                 td.vertices = &srcmesh[0][0];
465                 td.texfbuf = texture;
466                 td.texhres = 512;
467                 td.texvres = 512;
468                 td.texhmask = 0x7FFF;
469                 td.texvmask = 0x7FFF;
470                 td.dstfbuf = vga_backbuffer;
471                 td.dsthres = vga_hres;
472                 td.dstvres = vga_vres;
473                 td.dsthoffset = 0;
474                 td.dstvoffset = 0;
475                 td.dstsquarew = vga_hres/32;
476                 td.dstsquareh = vga_vres/32;
477                 td.alpha = TMU_ALPHA_MAX;
478
479                 td.callback = tmutest_callback;
480                 td.user = (void *)&complete;
481
482                 complete = 0;
483                 CSR_TIMER1_CONTROL = 0;
484                 CSR_TIMER1_COUNTER = 0;
485                 CSR_TIMER1_COMPARE = 0xffffffff;
486                 CSR_TIMER1_CONTROL = TIMER_ENABLE;
487                 tmu_submit_task(&td);
488                 while(!complete);
489                 t = CSR_TIMER1_COUNTER;
490                 hits = CSR_TMU_HIT_A + CSR_TMU_HIT_B + CSR_TMU_HIT_C + CSR_TMU_HIT_D;
491                 reqs = CSR_TMU_REQ_A + CSR_TMU_REQ_B + CSR_TMU_REQ_C + CSR_TMU_REQ_D;
492                 printf("%d,%d,%d\n", t, hits, reqs);
493                 vga_swap_buffers();
494         }
495
496         irq_ack(IRQ_TIMER1);
497         irq_setmask(oldmask);
498         uart_force_sync(0);
499 }
500
501 static short audio_buffer1[SND_MAX_NSAMPLES*2];
502 static short audio_buffer2[SND_MAX_NSAMPLES*2];
503 static short audio_buffer3[SND_MAX_NSAMPLES*2];
504 static short audio_buffer4[SND_MAX_NSAMPLES*2];
505
506 static void record_callback(short *buffer, void *user)
507 {
508         snd_play_refill(buffer);
509 }
510
511 static void play_callback(short *buffer, void *user)
512 {
513         snd_record_refill(buffer);
514 }
515
516 static void echo()
517 {
518         if(snd_play_active()) {
519                 snd_record_stop();
520                 snd_play_stop();
521                 printf("Digital Echo demo stopped\n");
522         } else {
523                 int i;
524
525                 snd_play_empty();
526                 for(i=0;i<AC97_MAX_DMASIZE/2;i++) {
527                         audio_buffer1[i] = 0;
528                         audio_buffer2[i] = 0;
529                 }
530                 snd_play_refill(audio_buffer1);
531                 snd_play_refill(audio_buffer2);
532                 snd_play_start(play_callback, SND_MAX_NSAMPLES, NULL);
533
534                 snd_record_empty();
535                 snd_record_refill(audio_buffer3);
536                 snd_record_refill(audio_buffer4);
537                 snd_record_start(record_callback, SND_MAX_NSAMPLES, NULL);
538                 printf("Digital Echo demo started\n");
539         }
540 }
541
542 static void readv(char *addr)
543 {
544         unsigned char a;
545         char *c;
546
547         if(*addr == 0) {
548                 printf("readv <address>\n");
549                 return;
550         }
551         a = strtoul(addr, &c, 0);
552         if(*c != 0) {
553                 printf("incorrect address\n");
554                 return;
555         }
556
557         printf("%02x\n", vin_read_reg(a));
558 }
559
560 static void writev(char *addr, char *value)
561 {
562         unsigned char a, v;
563         char *c;
564
565         if((*addr == 0)||(*value == 0)) {
566                 printf("writev <address> <value>\n");
567                 return;
568         }
569         a = strtoul(addr, &c, 0);
570         if(*c != 0) {
571                 printf("incorrect address\n");
572                 return;
573         }
574         v = strtoul(value, &c, 0);
575         if(*c != 0) {
576                 printf("incorrect value\n");
577                 return;
578         }
579
580         vin_write_reg(a, v);
581 }
582
583 static short vbuffer[720*288] __attribute__((aligned(32)));
584
585 static void testv()
586 {
587         
588         int x, y;
589         
590         irq_ack(IRQ_VIDEOIN);
591         CSR_BT656CAP_BASE = (unsigned int)vbuffer;
592         CSR_BT656CAP_FILTERSTATUS = BT656CAP_FILTERSTATUS_FIELD1;
593         printf("wait1 %d\n", CSR_TIMER0_COUNTER);
594         while(!irq_pending() && IRQ_VIDEOIN);
595         irq_ack(IRQ_VIDEOIN);
596         printf("wait2 %d\n", CSR_TIMER0_COUNTER);
597         while(!irq_pending() && IRQ_VIDEOIN);
598         irq_ack(IRQ_VIDEOIN);
599         CSR_BT656CAP_FILTERSTATUS = 0;
600         printf("wait3 %d\n", CSR_TIMER0_COUNTER);
601         while(CSR_BT656CAP_FILTERSTATUS & BT656CAP_FILTERSTATUS_INFRAME);
602         printf("done %d\n", CSR_TIMER0_COUNTER);
603         printf("nbursts=%d/%d\n", CSR_BT656CAP_DONEBURSTS, CSR_BT656CAP_MAXBURSTS);
604         flush_bridge_cache();
605         for(y=0;y<288;y++)
606                 for(x=0;x<640;x++)
607                         vga_frontbuffer[640*y+x] = vbuffer[720*y+x];
608         flush_bridge_cache();
609 }
610
611 static void irtest()
612 {
613         unsigned int r;
614         
615         irq_ack(IRQ_IR);
616         while(!readchar_nonblock()) {
617                 if(irq_pending() & IRQ_IR) {
618                         r = CSR_RC5_RX;
619                         irq_ack(IRQ_IR);
620                         printf("%04x - fld:%d ctl:%d sys:%d cmd:%d\n", r,
621                                 (r & 0x1000) >> 12,
622                                 (r & 0x0800) >> 11,
623                                 (r & 0x07c0) >> 6,
624                                 r & 0x003f);
625                         
626                 }
627         }
628 }
629
630 static void midiprint()
631 {
632         unsigned int r;
633         if(irq_pending() & IRQ_MIDIRX) {
634                 r = CSR_MIDI_RXTX;
635                 irq_ack(IRQ_MIDIRX);
636                 printf("RX: %02x\n", r);
637         }
638 }
639
640 static void midirx()
641 {
642         irq_ack(IRQ_MIDIRX);
643         while(!readchar_nonblock()) midiprint();
644 }
645
646 static void midisend(int c)
647 {
648         printf("TX: %02x\n", c);
649         CSR_MIDI_RXTX = c;
650         while(!(irq_pending() & IRQ_MIDITX));
651         printf("TX done\n");
652         irq_ack(IRQ_MIDITX);
653         midiprint();
654 }
655
656 static void miditx(char *note)
657 {
658         int note2;
659         char *c;
660         
661         if(*note == 0) {
662                 printf("miditx <note>\n");
663                 return;
664         }
665         note2 = (unsigned *)strtoul(note, &c, 0);
666         if(*c != 0) {
667                 printf("incorrect note\n");
668                 return;
669         }
670         
671         //midisend(0x90);
672         midisend(note2);
673         //midisend(0x22);
674 }
675
676 static char *get_token(char **str)
677 {
678         char *c, *d;
679
680         c = (char *)strchr(*str, ' ');
681         if(c == NULL) {
682                 d = *str;
683                 *str = *str+strlen(*str);
684                 return d;
685         }
686         *c = 0;
687         d = *str;
688         *str = c+1;
689         return d;
690 }
691
692 static int irender;
693
694 static void do_command(char *c)
695 {
696         if(irender) {
697                 if(*c == 0) {
698                         irender = 0;
699                         renderer_idone();
700                 } else
701                         renderer_iinput(c);
702         } else {
703                 char *command, *param1, *param2, *param3;
704
705                 command = get_token(&c);
706                 param1 = get_token(&c);
707                 param2 = get_token(&c);
708                 param3 = get_token(&c);
709
710                 if(strcmp(command, "mr") == 0) mr(param1, param2);
711                 else if(strcmp(command, "mw") == 0) mw(param1, param2, param3);
712                 else if(strcmp(command, "ls") == 0) ls();
713                 else if(strcmp(command, "flush") == 0) flush_bridge_cache();
714                 else if(strcmp(command, "edid") == 0) edid();
715                 else if(strcmp(command, "render") == 0) render(param1);
716                 else if(strcmp(command, "irender") == 0) {
717                         renderer_istart();
718                         irender = 1;
719                 } else if(strcmp(command, "stop") == 0) renderer_stop();
720                 else if(strcmp(command, "stats") == 0) stats();
721                 else if(strcmp(command, "reboot") == 0) reboot();
722                 else if(strcmp(command, "help") == 0) help();
723
724                 /* Test functions and hacks */
725                 else if(strcmp(command, "cpucfg") == 0) cpucfg();
726                 else if(strcmp(command, "loadpic") == 0) loadpic(param1);
727                 else if(strcmp(command, "checker") == 0) checker();
728                 else if(strcmp(command, "pfputest") == 0) pfputest();
729                 else if(strcmp(command, "tmutest") == 0) tmutest();
730                 else if(strcmp(command, "tmubench") == 0) tmubench();
731                 else if(strcmp(command, "echo") == 0) echo();
732                 else if(strcmp(command, "testv") == 0) testv();
733                 else if(strcmp(command, "readv") == 0) readv(param1);
734                 else if(strcmp(command, "writev") == 0) writev(param1, param2);
735                 else if(strcmp(command, "irtest") == 0) irtest();
736                 else if(strcmp(command, "midirx") == 0) midirx();
737                 else if(strcmp(command, "miditx") == 0) miditx(param1);
738
739                 else if(strcmp(command, "") != 0) printf("Command not found: '%s'\n", command);
740         }
741 }
742
743 static char command_buffer[512];
744 static unsigned int command_index;
745
746 static void prompt()
747 {
748         if(irender)
749                 putsnonl("\e[1mpatch% \e[0m");
750         else
751                 putsnonl("\e[1m% \e[0m");
752 }
753
754 void shell_init()
755 {
756         prompt();
757         command_index = 0;
758         irender = 0;
759 }
760
761 void shell_input(char c)
762 {
763         cpustats_enter();
764         switch(c) {
765                 case 0x7f:
766                 case 0x08:
767                         if(command_index > 0) {
768                                 command_index--;
769                                 putsnonl("\x08 \x08");
770                         }
771                         break;
772                 case '\r':
773                 case '\n':
774                         command_buffer[command_index] = 0x00;
775                         putsnonl("\n");
776                         command_index = 0;
777                         do_command(command_buffer);
778                         prompt();
779                         break;
780                 default:
781                         if(command_index < (sizeof(command_buffer)-1)) {
782                                 writechar(c);
783                                 command_buffer[command_index] = c;
784                                 command_index++;
785                         }
786                         break;
787         }
788         cpustats_leave();
789 }