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