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