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