273bbecf473a0a89380f291915f3945e529254bc
[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 /*
211  * Low-level PFPU test, bypassing driver.
212  * This test should only be run when the driver task queue
213  * is empty.
214  */
215 static void pfputest()
216 {
217         unsigned int mesh[128][128];
218         unsigned int *pfpu_regs = (unsigned int *)CSR_PFPU_DREGBASE;
219         unsigned int *pfpu_code = (unsigned int *)CSR_PFPU_CODEBASE;
220         int x, y;
221         int timeout;
222         unsigned int oldmask;
223
224         /* Do not let the driver get our interrupt */
225         oldmask = irq_getmask();
226         irq_setmask(oldmask & (~IRQ_PFPU));
227
228         for(y=0;y<128;y++)
229                 for(x=0;x<128;x++)
230                         mesh[y][x] = 0xdeadbeef;
231
232         CSR_PFPU_MESHBASE = (unsigned int)mesh;
233         //CSR_PFPU_HMESHLAST = 6;
234         //CSR_PFPU_VMESHLAST = 9;
235
236         CSR_PFPU_HMESHLAST = 11;
237         CSR_PFPU_VMESHLAST = 9;
238
239         pfpu_regs[3] = 0x41300000;
240         pfpu_regs[4] = 0x41100000;
241
242         pfpu_code[ 0] = 0x00000300;
243         pfpu_code[ 1] = 0x00040300;
244         pfpu_code[ 2] = 0x00000000;
245         pfpu_code[ 3] = 0x00000003;
246         pfpu_code[ 4] = 0x00000004;
247         pfpu_code[ 5] = 0x000c2080;
248         pfpu_code[ 6] = 0x00000000;
249         pfpu_code[ 7] = 0x00000000;
250         pfpu_code[ 8] = 0x00000000;
251         pfpu_code[ 9] = 0x0000007f;
252
253         /*printf("Program:\n");
254         for(x=0;x<10;x++)
255                 printf("%08x ", pfpu_code[x]);
256         printf("\n");*/
257
258         CSR_PFPU_CTL = PFPU_CTL_START;
259         printf("Waiting for PFPU...\n");
260         timeout = 30;
261         do {
262                 printf("%08x vertices:%d collisions:%d strays:%d dma:%d pc:%04x\n",
263                         CSR_PFPU_CTL, CSR_PFPU_VERTICES, CSR_PFPU_COLLISIONS, CSR_PFPU_STRAYWRITES, CSR_PFPU_DMAPENDING, 4*CSR_PFPU_PC);
264         } while((timeout--) && (CSR_PFPU_CTL & PFPU_CTL_BUSY));
265         if(timeout > 0)
266                 printf("OK\n");
267         else
268                 printf("Timeout\n");
269
270         asm volatile( /* Invalidate Level-1 data cache */
271                 "wcsr DCC, r0\n"
272                 "nop\n"
273         );
274
275         printf("Result:\n");
276         for(y=0;y<10;y++) {
277                 for(x=0;x<12;x++)
278                         printf("%08x ", mesh[y][x]);
279                 printf("\n");
280         }
281
282         printf("Program:\n");
283         for(x=0;x<10;x++)
284                 printf("%08x ", pfpu_code[x]);
285         printf("\n");
286
287         CSR_PFPU_CTL = 0; /* Ack interrupt */
288         irq_ack(IRQ_PFPU);
289         irq_setmask(oldmask);
290 }
291
292 static void tmutest_callback(struct tmu_td *td)
293 {
294         int *complete;
295         complete = (int *)td->user;
296         *complete = 1;
297 }
298
299 static void tmutest()
300 {
301         int x, y;
302         struct tmu_vertex srcmesh[TMU_MESH_MAXSIZE][TMU_MESH_MAXSIZE];
303         struct tmu_vertex dstmesh[TMU_MESH_MAXSIZE][TMU_MESH_MAXSIZE];
304         struct tmu_td td;
305         volatile int complete;
306
307         for(y=0;y<=24;y++)
308                 for(x=0;x<=32;x++) {
309                         srcmesh[y][x].x = 30*x;
310                         srcmesh[y][x].y = 30*y;
311                 
312                         dstmesh[y][x].x = 20*x;
313                         dstmesh[y][x].y = 20*y;
314                 }
315
316         td.hmeshlast = 32;
317         td.vmeshlast = 24;
318         td.brightness = TMU_BRIGHTNESS_MAX;
319         td.srcmesh = &srcmesh[0][0];
320         td.srcfbuf = vga_frontbuffer;
321         td.srchres = vga_hres;
322         td.srcvres = vga_vres;
323         td.dstmesh = &dstmesh[0][0];
324         td.dstfbuf = vga_backbuffer;
325         td.dsthres = vga_hres;
326         td.dstvres = vga_vres;
327         
328         td.profile = 1;
329         td.callback = tmutest_callback;
330         td.user = (void *)&complete;
331
332         complete = 0;
333         tmu_submit_task(&td);
334         while(!complete);
335         vga_swap_buffers();
336 }
337
338 static short audio_buffer1[SND_MAX_NSAMPLES*2];
339 static short audio_buffer2[SND_MAX_NSAMPLES*2];
340 static short audio_buffer3[SND_MAX_NSAMPLES*2];
341 static short audio_buffer4[SND_MAX_NSAMPLES*2];
342
343 static void record_callback(short *buffer, void *user)
344 {
345         snd_play_refill(buffer);
346 }
347
348 static void play_callback(short *buffer, void *user)
349 {
350         snd_record_refill(buffer);
351 }
352
353 static void echo()
354 {
355         if(snd_play_active()) {
356                 snd_record_stop();
357                 snd_play_stop();
358                 printf("Digital Echo demo stopped\n");
359         } else {
360                 int i;
361
362                 snd_play_empty();
363                 for(i=0;i<AC97_MAX_DMASIZE/2;i++) {
364                         audio_buffer1[i] = 0;
365                         audio_buffer2[i] = 0;
366                 }
367                 snd_play_refill(audio_buffer1);
368                 snd_play_refill(audio_buffer2);
369                 snd_play_start(play_callback, SND_MAX_NSAMPLES, NULL);
370
371                 snd_record_empty();
372                 snd_record_refill(audio_buffer3);
373                 snd_record_refill(audio_buffer4);
374                 snd_record_start(record_callback, SND_MAX_NSAMPLES, NULL);
375                 printf("Digital Echo demo started\n");
376         }
377 }
378
379 static char *get_token(char **str)
380 {
381         char *c, *d;
382
383         c = (char *)strchr(*str, ' ');
384         if(c == NULL) {
385                 d = *str;
386                 *str = *str+strlen(*str);
387                 return d;
388         }
389         *c = 0;
390         d = *str;
391         *str = c+1;
392         return d;
393 }
394
395 static void do_command(char *c)
396 {
397         char *command, *param1, *param2, *param3;
398
399         command = get_token(&c);
400         param1 = get_token(&c);
401         param2 = get_token(&c);
402         param3 = get_token(&c);
403
404         if(strcmp(command, "mr") == 0) mr(param1, param2);
405         else if(strcmp(command, "mw") == 0) mw(param1, param2, param3);
406         else if(strcmp(command, "ls") == 0) ls();
407         else if(strcmp(command, "flush") == 0) flush_bridge_cache();
408         else if(strcmp(command, "render") == 0) render(param1);
409         else if(strcmp(command, "stop") == 0) ui_render_stop();
410         else if(strcmp(command, "spam") == 0) spam();
411         else if(strcmp(command, "stats") == 0) stats();
412         else if(strcmp(command, "reboot") == 0) reboot();
413         else if(strcmp(command, "help") == 0) help();
414
415         /* Test functions and hacks */
416         else if(strcmp(command, "pfputest") == 0) pfputest();
417         else if(strcmp(command, "tmutest") == 0) tmutest();
418         else if(strcmp(command, "echo") == 0) echo();
419
420         else if(strcmp(command, "") != 0) printf("Command not found: '%s'\n", command);
421 }
422
423 static char command_buffer[64];
424 static unsigned int command_index;
425
426 static void prompt()
427 {
428         putsnonl("\e[1m% \e[0m");
429 }
430
431 void shell_init()
432 {
433         prompt();
434         command_index = 0;
435 }
436
437 void shell_input(char c)
438 {
439         cpustats_enter();
440         switch(c) {
441                 case 0x7f:
442                 case 0x08:
443                         if(command_index > 0) {
444                                 command_index--;
445                                 putsnonl("\x08 \x08");
446                         }
447                         break;
448                 case '\r':
449                 case '\n':
450                         command_buffer[command_index] = 0x00;
451                         putsnonl("\n");
452                         command_index = 0;
453                         do_command(command_buffer);
454                         prompt();
455                         break;
456                 default:
457                         if(command_index < (sizeof(command_buffer)-1)) {
458                                 writechar(c);
459                                 command_buffer[command_index] = c;
460                                 command_index++;
461                         }
462                         break;
463         }
464         cpustats_leave();
465 }