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