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