~alexandre-hardy/linuxjoymap/linuxjoymap

« back to all changes in this revision

Viewing changes to vm.c

  • Committer: Alexandre Hardy
  • Date: 2009-07-17 09:20:57 UTC
  • Revision ID: ah@zenwalk-20090717092057-oxa4o16isawqa7ue
Initial creation of project

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Fake joystick driver for Linux
 
3
 * by Alexandre Hardy 
 
4
 */
 
5
 
 
6
/*
 
7
 * This program is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; either version 2 of the License, or
 
10
 * (at your option) any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
20
 */
 
21
 
 
22
#include <stdlib.h>
 
23
#include <stdio.h>
 
24
#include <string.h>
 
25
#include <linux/input.h>
 
26
#include "program.h"
 
27
#include "mapper.h"
 
28
 
 
29
#define INTERVAL        50
 
30
#define STACK_SIZE      1024
 
31
#define MAX_THREADS     8
 
32
 
 
33
#define debug(...)
 
34
//#define debug printf
 
35
 
 
36
static int installed=0;
 
37
 
 
38
static int timestamp=0;
 
39
static int executing=0;
 
40
 
 
41
//controller variables
 
42
static __s16 code_analog[64];
 
43
//controller variables
 
44
static __u8 code_bit[128];
 
45
//controller variables
 
46
static __s16 js_analog[16][64];
 
47
//controller variables
 
48
static __u8 js_bit[16][128];
 
49
static __s16 currentmode=0;
 
50
static __s16 firstscan=1;
 
51
static __s16 clocktick=1;
 
52
static __s16 xrel=0;
 
53
static __s16 yrel=0;
 
54
static __s16 zrel=0;
 
55
static __u8 code[MAX_CODE_SIZE];
 
56
//registers inaccessible to user
 
57
//allocated by compiler
 
58
static int status=0;            //0 = no valid program 1=valid program
 
59
static struct code_context {
 
60
        unsigned int ip;
 
61
        int registers[256]; //general purpose registers
 
62
        int sp;
 
63
        int stack[STACK_SIZE];
 
64
        int active; //is this thread active
 
65
} code_threads[MAX_THREADS];
 
66
 
 
67
//for each instruction, does it have an operand
 
68
static char has_operand[]={
 
69
        0, /* HALT */
 
70
        1, /* JZ */
 
71
        1, /* JUMP */
 
72
        1, /* JUMPREL */
 
73
        0, /* ADD */
 
74
        0, /* SUB */
 
75
        0, /* MUL */
 
76
        0, /* DIV */
 
77
        0, /* LT */
 
78
        0, /* LE */
 
79
        0, /* GT */
 
80
        0, /* GE */
 
81
        0, /* EQ */
 
82
        0, /* NEQ */
 
83
        0, /* AND */
 
84
        0, /* OR */
 
85
        0, /* NOT */
 
86
        1, /* PUSH */
 
87
        1, /* POP */
 
88
        1, /* DEC */
 
89
        1, /* INC */
 
90
        0, /* KEY */
 
91
        0, /* SIGNAL */
 
92
        1, /* THREAD handles its own arguments */
 
93
        0, /* YIELD */
 
94
        0, /* NEG */
 
95
        1, /* JOIN */
 
96
        1, /* PUSHA */
 
97
        1, /* POPA */
 
98
        1, /* DECA */
 
99
        1, /* INCA */
 
100
};
 
101
 
 
102
struct code_context *code_thread;
 
103
 
 
104
void code_button(int code, int value);
 
105
void code_axis(int axis, int value);
 
106
void execute_script(void);
 
107
 
 
108
void code_notify_button(int js, int key, int value) {
 
109
        if ((js>=0)&&(js<16)) 
 
110
        if ((key-BTN_JOYSTICK>=0)&&(key-BTN_JOYSTICK<128)) {
 
111
                if (js_bit[js][key-BTN_JOYSTICK]!=value) {
 
112
                        js_bit[js][key-BTN_JOYSTICK]=value;
 
113
                        execute_script();       
 
114
                }
 
115
        }
 
116
}
 
117
 
 
118
void code_notify_axis(int js, int axis, int value) {
 
119
        if ((js>=0)&&(js<16)) 
 
120
        if ((axis>=0)&&(axis<64)) {
 
121
                if (js_analog[js][axis]!=value) {
 
122
                        js_analog[js][axis]=value;
 
123
                        execute_script();       
 
124
                }
 
125
        }
 
126
}
 
127
 
 
128
void code_set_program(struct program_code *program) {
 
129
        if (program==NULL) {
 
130
                status=0;
 
131
                return;
 
132
        }
 
133
        if (program->program!=PROGRAM_CODE) return;
 
134
        memcpy(code, program->code, MAX_CODE_SIZE);
 
135
        firstscan=1;
 
136
        currentmode=0;
 
137
        timestamp=0;
 
138
        status=1;
 
139
}
 
140
 
 
141
void code_reset(void) {
 
142
        int i, j;
 
143
        for (i=0; i<MAX_THREADS; i++) {
 
144
                for (j=0; j<256; j++) {
 
145
                         code_threads[i].registers[j]=0;
 
146
                }
 
147
                code_threads[i].active=0;
 
148
        }
 
149
        code_threads[0].active=1;
 
150
        for (i=0; i<64; i++) {
 
151
                code_analog[i]=0;
 
152
        }
 
153
        for (i=0; i<128; i++) {
 
154
                code_bit[i]=0;
 
155
        }
 
156
        firstscan=1;
 
157
        currentmode=0;
 
158
        timestamp=0;
 
159
}
 
160
 
 
161
static void push(int x) {
 
162
        if (code_thread->sp<STACK_SIZE) code_thread->stack[code_thread->sp++]=x;
 
163
}
 
164
 
 
165
static int pop(void) {
 
166
        if (code_thread->sp<=0) return 0;
 
167
        else return code_thread->stack[--code_thread->sp];
 
168
}
 
169
 
 
170
static int get_value(int address, int type, int array) {
 
171
        int js;
 
172
        int ofs=0;
 
173
        if (array)
 
174
                ofs=code_thread->registers[OFSREG];
 
175
        switch (type) {
 
176
                case GP:
 
177
                        if (address+ofs==FIRSTSCAN) return firstscan;
 
178
                        if (address+ofs==CLOCKTICK) return clocktick;   
 
179
                        if (address+ofs==XREL) return xrel;                     
 
180
                        if (address+ofs==YREL) return yrel;                     
 
181
                        if (address+ofs==ZREL) return zrel;                     
 
182
                        if (address+ofs==TIMESTAMP) return timestamp;//jiffies_to_msecs(jiffies);       
 
183
                        if (address+ofs==CURRENTMODE) return currentmode;       
 
184
                        if ((address+ofs>=0)&&(address+ofs<256))
 
185
                                return code_thread->registers[address+ofs];
 
186
                        else
 
187
                                return 0;
 
188
                case CODEA:
 
189
                        if ((address+ofs>=0)&&(address+ofs<64))
 
190
                                return code_analog[address+ofs];
 
191
                        else
 
192
                                return 0;
 
193
                case CODEB:
 
194
                        if ((address+ofs>=0)&&(address+ofs<128))
 
195
                                return code_bit[address+ofs];
 
196
                        else
 
197
                                return 0;
 
198
                case JS:
 
199
                        js=(address&0x0F00)>>8;
 
200
                        type=address&0xF000;
 
201
                        address=address&0x00FF;
 
202
                        if (type==0) {  
 
203
                                if ((address+ofs>=0)&&(address+ofs<128))
 
204
                                        return js_bit[js][address+ofs];
 
205
                                else
 
206
                                        return 0;
 
207
                        } else {
 
208
                                if ((address+ofs>=0)&&(address+ofs<64))
 
209
                                        return js_analog[js][address+ofs];
 
210
                                else
 
211
                                        return 0;
 
212
                        }
 
213
                case CONST:
 
214
                        return address;
 
215
                default:
 
216
                        return 0;
 
217
        }
 
218
}
 
219
 
 
220
static void set_value(int address, int type, int value, int array) {
 
221
        int ofs=0;
 
222
        if (array)
 
223
                ofs=code_thread->registers[OFSREG];
 
224
        switch (type) {
 
225
                case GP:
 
226
                        if (address==XREL) xrel=value;                  
 
227
                        if (address==YREL) yrel=value;                  
 
228
                        if (address==ZREL) zrel=value;                  
 
229
                        if (address==CURRENTMODE) currentmode=value;    
 
230
                        if ((address+ofs>=0)&&(address+ofs<256))
 
231
                                code_thread->registers[address+ofs]=value;      
 
232
                        break;
 
233
                case CODEA:
 
234
                        if ((address+ofs>=0)&&(address+ofs<64))
 
235
                                code_axis(address+ofs, value);
 
236
                        break;
 
237
                case CODEB:
 
238
                        if ((address+ofs>=0)&&(address+ofs<128))
 
239
                                code_button(address+ofs, value);
 
240
                        break;
 
241
                case JS:
 
242
                case CONST:
 
243
                        break;
 
244
                default:
 
245
                        break;
 
246
        }
 
247
}
 
248
 
 
249
static int instr_exec=0;
 
250
 
 
251
static void execute_script_thread(struct code_context *new_thread, unsigned int new_ip, unsigned int retip);
 
252
void execute_script(void) {
 
253
        if (executing) return;
 
254
        executing=1;
 
255
        code_thread=&code_threads[0];
 
256
        code_thread->ip=0;
 
257
        code_thread->sp=0;
 
258
        code_thread->active=1;
 
259
        instr_exec=0;
 
260
        debug("\n\nstart thread\n");
 
261
        debug("timestamp %d\n", timestamp);
 
262
        execute_script_thread(code_thread,0,MAX_CODE_SIZE);
 
263
        firstscan=0;
 
264
        clocktick=0;
 
265
        executing=0;
 
266
}
 
267
 
 
268
static void execute_script_thread(struct code_context *new_thread, unsigned int new_ip, unsigned int retip) {
 
269
        int address=0, array=0;
 
270
        int type;
 
271
        int task;
 
272
        int st;
 
273
        int p1, p2;
 
274
        int value=0;
 
275
        unsigned int thread_start;
 
276
        unsigned int thread_exit;
 
277
        if (status!=1) return;
 
278
        if (!new_thread->active) {
 
279
                debug("Activating thread\n");
 
280
                *new_thread=*code_thread;
 
281
                new_thread->ip=new_ip;
 
282
                //code_thread->ip=retip;
 
283
                code_thread=new_thread;
 
284
                new_thread->active=1;
 
285
        } else {
 
286
                code_thread=new_thread;
 
287
        }
 
288
        while ((code_thread->ip<MAX_CODE_SIZE)&&(instr_exec<100000)) {
 
289
                task=code[code_thread->ip++];
 
290
                if (task>=PUSHA) array=1;
 
291
                else array=0;
 
292
                type=task >> 5;
 
293
                task=task&31;
 
294
                if ((task>=0)&&(task<=INCA))
 
295
                if (has_operand[task]) {
 
296
                        address=*((unsigned short *)(code+code_thread->ip));
 
297
                        value=get_value(address, type, array);
 
298
                        code_thread->ip+=2;
 
299
                        debug("Got operand %d address=%d type=%d\n",value, address, type);
 
300
                }
 
301
                instr_exec++;
 
302
                switch (task) {
 
303
                        case HALT:
 
304
                                debug("HALT\n");
 
305
                                code_thread->ip=MAX_CODE_SIZE+1;
 
306
                                code_thread->active=0;
 
307
                                break;
 
308
                        case JZ:
 
309
                                debug("JZ\n");
 
310
                                st=pop();
 
311
                                if (st==0) code_thread->ip=value;
 
312
                                break;  
 
313
                        case JUMP:
 
314
                                debug("JUMP\n");
 
315
                                code_thread->ip=value;
 
316
                                break;
 
317
                        case JUMPREL:
 
318
                                debug("JUMPREL\n");
 
319
                                code_thread->ip+=value;
 
320
                                break;
 
321
                        case ADD:
 
322
                                debug("ADD\n");
 
323
                                p1=pop(); 
 
324
                                p2=pop(); 
 
325
                                push(p2+p1);
 
326
                                break;
 
327
                        case SUB:
 
328
                                debug("SUB\n");
 
329
                                p1=pop(); 
 
330
                                p2=pop(); 
 
331
                                push(p2-p1);
 
332
                                break;
 
333
                        case MUL:
 
334
                                debug("MUL\n");
 
335
                                p1=pop(); 
 
336
                                p2=pop(); 
 
337
                                push(p2*p1);
 
338
                                break;
 
339
                        case DIV:
 
340
                                debug("DIV\n");
 
341
                                p1=pop(); 
 
342
                                p2=pop(); 
 
343
                                push(p2/p1);
 
344
                                break;
 
345
                        case LT:
 
346
                                debug("LT\n");
 
347
                                p1=pop(); 
 
348
                                p2=pop(); 
 
349
                                push((p2<p1)?1:0);
 
350
                                break;
 
351
                        case LE:
 
352
                                debug("LE\n");
 
353
                                p1=pop(); 
 
354
                                p2=pop(); 
 
355
                                push((p2<=p1)?1:0);
 
356
                                break;
 
357
                        case GT:
 
358
                                debug("GT\n");
 
359
                                p1=pop(); 
 
360
                                p2=pop(); 
 
361
                                push((p2>p1)?1:0);
 
362
                                break;
 
363
                        case GE:
 
364
                                debug("GE\n");
 
365
                                p1=pop(); 
 
366
                                p2=pop(); 
 
367
                                push((p2>=p1)?1:0);
 
368
                                break;
 
369
                        case EQ:
 
370
                                debug("EQ\n");
 
371
                                p1=pop(); 
 
372
                                p2=pop(); 
 
373
                                push((p2==p1)?1:0);
 
374
                                break;
 
375
                        case NEQ:
 
376
                                debug("NEQ\n");
 
377
                                p1=pop(); 
 
378
                                p2=pop(); 
 
379
                                push((p2!=p1)?1:0);
 
380
                                break;
 
381
                        case AND:
 
382
                                debug("AND\n");
 
383
                                p1=pop(); 
 
384
                                p2=pop(); 
 
385
                                push((p2&&p1)?1:0);
 
386
                                break;
 
387
                        case OR:
 
388
                                debug("OR\n");
 
389
                                p1=pop(); 
 
390
                                p2=pop(); 
 
391
                                push((p2||p1)?1:0);
 
392
                                break;
 
393
                        case NOT:
 
394
                                debug("NOT\n");
 
395
                                p1=pop(); 
 
396
                                push((!p1)?1:0);
 
397
                                break;
 
398
                        case NEG:
 
399
                                debug("NEG\n");
 
400
                                p1=pop(); 
 
401
                                push(-p1);
 
402
                                break;
 
403
                        case PUSH:
 
404
                                debug("PUSH %d\n", value);
 
405
                                push(value);
 
406
                                break;
 
407
                        case POP:
 
408
                                value=pop();
 
409
                                debug("POP %d\n", value);
 
410
                                set_value(address, type, value, 0);
 
411
                                break;
 
412
                        case DEC:
 
413
                                debug("DEC\n");
 
414
                                set_value(address, type, value-1, 0);
 
415
                                break;
 
416
                        case INC:
 
417
                                debug("INC\n");
 
418
                                set_value(address, type, value+1, 0);
 
419
                                break;
 
420
                        case PUSHA:
 
421
                                debug("PUSHA %d\n", value);
 
422
                                push(value);
 
423
                                break;
 
424
                        case POPA:
 
425
                                value=pop();
 
426
                                debug("POPA %d\n", value);
 
427
                                set_value(address, type, value, 1);
 
428
                                break;
 
429
                        case DECA:
 
430
                                debug("DECA\n");
 
431
                                set_value(address, type, value-1, 1);
 
432
                                break;
 
433
                        case INCA:
 
434
                                debug("INCA\n");
 
435
                                set_value(address, type, value+1, 1);
 
436
                                break;
 
437
                        case KEY:
 
438
                                p2=pop();
 
439
                                p1=pop();
 
440
                                debug("KEY %d %d\n", p1, p2);
 
441
                                press_key(p1, p2);
 
442
                                break;
 
443
                        case SIGNAL:
 
444
                                debug("SIGNAL\n");
 
445
                                value=pop();
 
446
                                push_signal(value);
 
447
                                break;
 
448
                        case THREAD: //context switch, value is new thread, two constant jump targets
 
449
                                //thread_start=*((unsigned short *)(code+code_thread->ip));
 
450
                                //code_thread->ip+=2;
 
451
                                debug("THREAD %d\n", value);
 
452
                                thread_exit=*((unsigned short *)(code+code_thread->ip));
 
453
                                code_thread->ip+=2;
 
454
                                thread_start=code_thread->ip;
 
455
                                if ((value>0)&&(value<MAX_THREADS)) {
 
456
                                        execute_script_thread(&code_threads[value], thread_start, thread_exit);
 
457
                                        code_thread=new_thread;
 
458
                                        code_thread->ip=thread_exit;
 
459
                                } else {
 
460
                                        debug("Not a valid thread\n");
 
461
                                        code_thread=new_thread;
 
462
                                        code_thread->ip=thread_exit;
 
463
                                }
 
464
                                break;
 
465
                        case YIELD:
 
466
                                debug("YIELD\n");
 
467
                                return;
 
468
                                break;
 
469
                        case JOIN: //stop thread
 
470
                                debug("JOIN %d\n", value);
 
471
                                if ((value>0)&&(value<MAX_THREADS)) {
 
472
                                        code_thread[value].active=0;
 
473
                                }
 
474
                                break;
 
475
                }
 
476
        }
 
477
}
 
478
 
 
479
int mapper_code_install(void) {
 
480
        int i, j;
 
481
        if (installed) return 0;
 
482
 
 
483
        for (j=0; j<16; j++) {
 
484
                for (i=0; i<64; i++) {
 
485
                        js_analog[j][i]=0;
 
486
                }       
 
487
                for (i=0; i<128; i++) {
 
488
                        js_bit[j][i]=0;
 
489
                }
 
490
        }
 
491
 
 
492
        installed=1;
 
493
        code_reset();
 
494
        return 0;
 
495
}
 
496
 
 
497
int mapper_code_uninstall(void) {
 
498
        if (installed) {
 
499
                installed=0;
 
500
        }
 
501
        return 0;
 
502
}
 
503
 
 
504
void code_button(int code, int value) {
 
505
        if (!installed) return;
 
506
        if (value!=code_bit[code]) {
 
507
                press_joy_button(255, BTN_JOYSTICK+code, value);
 
508
                code_bit[code]=value;
 
509
        }
 
510
}
 
511
 
 
512
void code_axis(int axis, int value) {
 
513
        if (!installed) return;
 
514
        if (value!=code_analog[axis]) {
 
515
                set_joy_axis(255, axis, value);
 
516
                code_analog[axis]=value;
 
517
        }
 
518
}
 
519
 
 
520
#define INTERVAL 50
 
521
void program_run() {
 
522
        timestamp+=INTERVAL;
 
523
        clocktick=1;
 
524
 
 
525
        debug("timertick %d\n", timestamp);
 
526
        execute_script();
 
527
}
 
528