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