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