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