Software support for the new TMU
[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 <cffat.h>
24 #include <system.h>
25 #include <math.h>
26 #include <irq.h>
27 #include <board.h>
28 #include <hw/pfpu.h>
29 #include <hw/tmu.h>
30 #include <hw/sysctl.h>
31 #include <hw/gpio.h>
32 #include <hw/interrupts.h>
33
34 #include <hal/vga.h>
35 #include <hal/snd.h>
36 #include <hal/tmu.h>
37 #include <hal/time.h>
38 #include <hal/brd.h>
39
40 #include "line.h"
41 #include "wave.h"
42 #include "rpipe.h"
43 #include "cpustats.h"
44 #include "shell.h"
45 #include "ui.h"
46
47 #define NUMBER_OF_BYTES_ON_A_LINE 16
48 static void dump_bytes(unsigned int *ptr, int count, unsigned addr)
49 {
50         char *data = (char *)ptr;
51         int line_bytes = 0, i = 0;
52
53         putsnonl("Memory dump:");
54         while(count > 0){
55                 line_bytes =
56                         (count > NUMBER_OF_BYTES_ON_A_LINE)?
57                                 NUMBER_OF_BYTES_ON_A_LINE : count;
58
59                 printf("\n0x%08x  ", addr);
60                 for(i=0;i<line_bytes;i++)
61                         printf("%02x ", *(unsigned char *)(data+i));
62
63                 for(;i<NUMBER_OF_BYTES_ON_A_LINE;i++)
64                         printf("   ");
65
66                 printf(" ");
67
68                 for(i=0;i<line_bytes;i++) {
69                         if((*(data+i) < 0x20) || (*(data+i) > 0x7e))
70                                 printf(".");
71                         else
72                                 printf("%c", *(data+i));
73                 }
74
75                 for(;i<NUMBER_OF_BYTES_ON_A_LINE;i++)
76                         printf(" ");
77
78                 data += (char)line_bytes;
79                 count -= line_bytes;
80                 addr += line_bytes;
81         }
82         printf("\n");
83 }
84
85 static void mr(char *startaddr, char *len)
86 {
87         char *c;
88         unsigned *addr;
89         unsigned length;
90
91         if(*startaddr == 0) {
92                 printf("mr <address> [length]\n");
93                 return;
94         }
95         addr = (unsigned *)strtoul(startaddr, &c, 0);
96         if(*c != 0) {
97                 printf("incorrect address\n");
98                 return;
99         }
100         if(*len == 0) {
101                 length = 1;
102         } else {
103                 length = strtoul(len, &c, 0);
104                 if(*c != 0) {
105                         printf("incorrect length\n");
106                         return;
107                 }
108         }
109
110         dump_bytes(addr, length, (unsigned)addr);
111 }
112
113 static void mw(char *addr, char *value, char *count)
114 {
115         char *c;
116         unsigned *addr2;
117         unsigned value2;
118         unsigned count2;
119         unsigned i;
120
121         if((*addr == 0) || (*value == 0)) {
122                 printf("mw <address> <value>\n");
123                 return;
124         }
125         addr2 = (unsigned *)strtoul(addr, &c, 0);
126         if(*c != 0) {
127                 printf("incorrect address\n");
128                 return;
129         }
130         value2 = strtoul(value, &c, 0);
131         if(*c != 0) {
132                 printf("incorrect value\n");
133                 return;
134         }
135         if(*count == 0) {
136                 count2 = 1;
137         } else {
138                 count2 = strtoul(count, &c, 0);
139                 if(*c != 0) {
140                         printf("incorrect count\n");
141                         return;
142                 }
143         }
144         for (i=0;i<count2;i++) *addr2++ = value2;
145 }
146
147 static int lscb(const char *filename, const char *longname, void *param)
148 {
149         printf("%12s [%s]\n", filename, longname);
150         return 1;
151 }
152
153 static void ls()
154 {
155         cffat_init();
156         cffat_list_files(lscb, NULL);
157         cffat_done();
158 }
159
160 static void render(const char *filename)
161 {
162         if(*filename == 0) {
163                 printf("render <filename>\n");
164                 return;
165         }
166
167         ui_render_from_file(filename);
168 }
169
170 static void spam()
171 {
172         spam_enabled = !spam_enabled;
173         if(spam_enabled)
174                 printf("Advertising enabled\n");
175         else
176                 printf("Advertising disabled\n");
177 }
178
179 static void stats()
180 {
181         int hours, mins, secs;
182         struct timestamp ts;
183
184         time_get(&ts);
185         secs = ts.sec;
186         mins = secs/60;
187         secs -= mins*60;
188         hours = mins/60;
189         mins -= hours*60;
190         printf("Uptime: %02d:%02d:%02d  FPS: %d  CPU:%3d%%\n", hours, mins, secs,
191                 rpipe_fps(),
192                 cpustats_load());
193 }
194
195 static void help()
196 {
197         puts("Milkymist demo firmware\n");
198         puts("Available commands :");
199         puts("mr         - read address space");
200         puts("mw         - write address space");
201         puts("flush      - flush FML bridge cache");
202         puts("ls         - list files on the memory card");
203         puts("render     - start rendering a preset");
204         puts("stop       - stop renderer");
205         puts("spam       - start/stop advertising");
206         puts("stats      - print system stats");
207         puts("reboot     - system reset");
208 }
209
210 static void loadpic(const char *filename)
211 {
212         int size;
213         
214         if(*filename == 0) {
215                 printf("loadpic <filename>\n");
216                 return;
217         }
218
219         if(!cffat_init()) return;
220         if(!cffat_load(filename, (void *)vga_backbuffer, vga_hres*vga_vres*2, &size)) return;
221         cffat_done();
222
223         vga_swap_buffers();
224 }
225
226 /*
227  * Low-level PFPU test, bypassing driver.
228  * This test should only be run when the driver task queue
229  * is empty.
230  */
231 static void pfputest()
232 {
233         unsigned int mesh[128][128];
234         unsigned int *pfpu_regs = (unsigned int *)CSR_PFPU_DREGBASE;
235         unsigned int *pfpu_code = (unsigned int *)CSR_PFPU_CODEBASE;
236         int x, y;
237         int timeout;
238         unsigned int oldmask;
239
240         /* Do not let the driver get our interrupt */
241         oldmask = irq_getmask();
242         irq_setmask(oldmask & (~IRQ_PFPU));
243
244         for(y=0;y<128;y++)
245                 for(x=0;x<128;x++)
246                         mesh[y][x] = 0xdeadbeef;
247
248         CSR_PFPU_MESHBASE = (unsigned int)mesh;
249         //CSR_PFPU_HMESHLAST = 6;
250         //CSR_PFPU_VMESHLAST = 9;
251
252         CSR_PFPU_HMESHLAST = 11;
253         CSR_PFPU_VMESHLAST = 9;
254
255         pfpu_regs[3] = 0x41300000;
256         pfpu_regs[4] = 0x41100000;
257
258         pfpu_code[ 0] = 0x00000300;
259         pfpu_code[ 1] = 0x00040300;
260         pfpu_code[ 2] = 0x00000000;
261         pfpu_code[ 3] = 0x00000003;
262         pfpu_code[ 4] = 0x00000004;
263         pfpu_code[ 5] = 0x000c2080;
264         pfpu_code[ 6] = 0x00000000;
265         pfpu_code[ 7] = 0x00000000;
266         pfpu_code[ 8] = 0x00000000;
267         pfpu_code[ 9] = 0x0000007f;
268
269         /*printf("Program:\n");
270         for(x=0;x<10;x++)
271                 printf("%08x ", pfpu_code[x]);
272         printf("\n");*/
273
274         CSR_PFPU_CTL = PFPU_CTL_START;
275         printf("Waiting for PFPU...\n");
276         timeout = 30;
277         do {
278                 printf("%08x vertices:%d collisions:%d strays:%d dma:%d pc:%04x\n",
279                         CSR_PFPU_CTL, CSR_PFPU_VERTICES, CSR_PFPU_COLLISIONS, CSR_PFPU_STRAYWRITES, CSR_PFPU_DMAPENDING, 4*CSR_PFPU_PC);
280         } while((timeout--) && (CSR_PFPU_CTL & PFPU_CTL_BUSY));
281         if(timeout > 0)
282                 printf("OK\n");
283         else
284                 printf("Timeout\n");
285
286         asm volatile( /* Invalidate Level-1 data cache */
287                 "wcsr DCC, r0\n"
288                 "nop\n"
289         );
290
291         printf("Result:\n");
292         for(y=0;y<10;y++) {
293                 for(x=0;x<12;x++)
294                         printf("%08x ", mesh[y][x]);
295                 printf("\n");
296         }
297
298         printf("Program:\n");
299         for(x=0;x<10;x++)
300                 printf("%08x ", pfpu_code[x]);
301         printf("\n");
302
303         CSR_PFPU_CTL = 0; /* Ack interrupt */
304         irq_ack(IRQ_PFPU);
305         irq_setmask(oldmask);
306 }
307
308 static void tmutest_callback(struct tmu_td *td)
309 {
310         int *complete;
311         complete = (int *)td->user;
312         *complete = 1;
313 }
314
315 static void tmutest()
316 {
317         int x, y;
318         struct tmu_vertex srcmesh[TMU_MESH_MAXSIZE][TMU_MESH_MAXSIZE];
319         struct tmu_td td;
320         volatile int complete;
321
322         for(y=0;y<=32;y++)
323                 for(x=0;x<=32;x++) {
324                         srcmesh[y][x].x = (5*x) << TMU_FIXEDPOINT_SHIFT;
325                         srcmesh[y][x].y = (7*y) << TMU_FIXEDPOINT_SHIFT;
326                 }
327
328         td.flags = 0;
329         td.hmeshlast = 32;
330         td.vmeshlast = 32;
331         td.brightness = TMU_BRIGHTNESS_MAX;
332         td.chromakey = 0;
333         td.vertices = &srcmesh[0][0];
334         td.texfbuf = vga_frontbuffer;
335         td.texhres = vga_hres;
336         td.texvres = vga_vres;
337         td.texhmask = TMU_MASK_FULL;
338         td.texvmask = TMU_MASK_FULL;
339         td.dstfbuf = vga_backbuffer;
340         td.dsthres = vga_hres;
341         td.dstvres = vga_vres;
342         td.dsthoffset = 0;
343         td.dstvoffset = 0;
344         td.dstsquarew = vga_hres/32;
345         td.dstsquareh = vga_vres/32;
346         
347         td.callback = tmutest_callback;
348         td.user = (void *)&complete;
349
350         complete = 0;
351         tmu_submit_task(&td);
352         while(!complete);
353         vga_swap_buffers();
354 }
355
356 static short audio_buffer1[SND_MAX_NSAMPLES*2];
357 static short audio_buffer2[SND_MAX_NSAMPLES*2];
358 static short audio_buffer3[SND_MAX_NSAMPLES*2];
359 static short audio_buffer4[SND_MAX_NSAMPLES*2];
360
361 static void record_callback(short *buffer, void *user)
362 {
363         snd_play_refill(buffer);
364 }
365
366 static void play_callback(short *buffer, void *user)
367 {
368         snd_record_refill(buffer);
369 }
370
371 static void echo()
372 {
373         if(snd_play_active()) {
374                 snd_record_stop();
375                 snd_play_stop();
376                 printf("Digital Echo demo stopped\n");
377         } else {
378                 int i;
379
380                 snd_play_empty();
381                 for(i=0;i<AC97_MAX_DMASIZE/2;i++) {
382                         audio_buffer1[i] = 0;
383                         audio_buffer2[i] = 0;
384                 }
385                 snd_play_refill(audio_buffer1);
386                 snd_play_refill(audio_buffer2);
387                 snd_play_start(play_callback, SND_MAX_NSAMPLES, NULL);
388
389                 snd_record_empty();
390                 snd_record_refill(audio_buffer3);
391                 snd_record_refill(audio_buffer4);
392                 snd_record_start(record_callback, SND_MAX_NSAMPLES, NULL);
393                 printf("Digital Echo demo started\n");
394         }
395 }
396
397 static char *get_token(char **str)
398 {
399         char *c, *d;
400
401         c = (char *)strchr(*str, ' ');
402         if(c == NULL) {
403                 d = *str;
404                 *str = *str+strlen(*str);
405                 return d;
406         }
407         *c = 0;
408         d = *str;
409         *str = c+1;
410         return d;
411 }
412
413 static void do_command(char *c)
414 {
415         char *command, *param1, *param2, *param3;
416
417         command = get_token(&c);
418         param1 = get_token(&c);
419         param2 = get_token(&c);
420         param3 = get_token(&c);
421
422         if(strcmp(command, "mr") == 0) mr(param1, param2);
423         else if(strcmp(command, "mw") == 0) mw(param1, param2, param3);
424         else if(strcmp(command, "ls") == 0) ls();
425         else if(strcmp(command, "flush") == 0) flush_bridge_cache();
426         else if(strcmp(command, "render") == 0) render(param1);
427         else if(strcmp(command, "stop") == 0) ui_render_stop();
428         else if(strcmp(command, "spam") == 0) spam();
429         else if(strcmp(command, "stats") == 0) stats();
430         else if(strcmp(command, "reboot") == 0) reboot();
431         else if(strcmp(command, "help") == 0) help();
432
433         /* Test functions and hacks */
434         else if(strcmp(command, "loadpic") == 0) loadpic(param1);
435         else if(strcmp(command, "pfputest") == 0) pfputest();
436         else if(strcmp(command, "tmutest") == 0) tmutest();
437         else if(strcmp(command, "echo") == 0) echo();
438
439         else if(strcmp(command, "") != 0) printf("Command not found: '%s'\n", command);
440 }
441
442 static char command_buffer[64];
443 static unsigned int command_index;
444
445 static void prompt()
446 {
447         putsnonl("\e[1m% \e[0m");
448 }
449
450 void shell_init()
451 {
452         prompt();
453         command_index = 0;
454 }
455
456 void shell_input(char c)
457 {
458         cpustats_enter();
459         switch(c) {
460                 case 0x7f:
461                 case 0x08:
462                         if(command_index > 0) {
463                                 command_index--;
464                                 putsnonl("\x08 \x08");
465                         }
466                         break;
467                 case '\r':
468                 case '\n':
469                         command_buffer[command_index] = 0x00;
470                         putsnonl("\n");
471                         command_index = 0;
472                         do_command(command_buffer);
473                         prompt();
474                         break;
475                 default:
476                         if(command_index < (sizeof(command_buffer)-1)) {
477                                 writechar(c);
478                                 command_buffer[command_index] = c;
479                                 command_index++;
480                         }
481                         break;
482         }
483         cpustats_leave();
484 }