initial
[fpgammix.git] / workloads / keyboard / test-keyboard.c
blob34b4745c8a8fe2d6f9457a0c946d0543dacd8f91
1 #include "stdio.h"
2 #include "fb-io.h"
4 // Debugging or not
5 #define D 1
7 // Missing map entries for special keys, like F1..F12, Cursor up, etc.
8 char *keyboard_map[256] = {
9 [0x76] = "\e",
11 // Numeric row
12 [0x0E] = "`~",
13 [0x16] = "1!",
14 [0x1E] = "2@",
15 [0x26] = "3#",
16 [0x25] = "4$",
17 [0x2E] = "5%",
18 [0x36] = "6^",
19 [0x3D] = "7&",
20 [0x3E] = "8*",
21 [0x46] = "9(",
22 [0x45] = "0)",
23 [0x4E] = "-_",
24 [0x55] = "=+",
25 [0x66] = "\b",
27 // Tab row
28 [0x0D] = "\t",
29 [0x15] = "qQ",
30 [0x1D] = "wW",
31 [0x24] = "eE",
32 [0x2D] = "rR",
33 [0x2C] = "tT",
34 [0x35] = "yY",
35 [0x3C] = "uU",
36 [0x43] = "iI",
37 [0x44] = "oO",
38 [0x4D] = "pP",
39 [0x54] = "[{",
40 [0x5B] = "]}",
41 [0x5D] = "\\|",
43 // CapsLock row
44 // 0x58 = CapsLock
45 [0x1c] = "aA",
46 [0x1b] = "sS",
47 [0x23] = "dD",
48 [0x2b] = "fF",
49 [0x34] = "gG",
50 [0x33] = "hH",
51 [0x3b] = "jJ",
52 [0x42] = "kK",
53 [0x4b] = "lL",
54 [0x4c] = ";:",
55 [0x52] = "'\"",
56 [0x5a] = "\n",
59 // Shift row
60 // 0x12 = Shift_L
61 [0x1a] = "zZ",
62 [0x22] = "xX",
63 [0x21] = "cC",
64 [0x2a] = "vV",
65 [0x32] = "bB",
66 [0x31] = "nN",
67 [0x3a] = "mM",
68 [0x41] = ",<",
69 [0x49] = ".>",
70 [0x4a] = "/?",
71 // 0x59 Shift_R
73 // Control row
74 // 0x14 = Ctrl_L
75 // 0x11 = Alt_L
76 [0x29] = " ",
77 // 0xE0 0x11 = Alt_R
78 // 0xE0 0x14 = Ctrl_R
81 /* Keycode fifo */
82 #define FIFO_SIZE 256
83 unsigned char keycode_fifo[FIFO_SIZE];
84 volatile uint64_t fifo_wp = 0, fifo_rp = 0;
86 void
87 interrupthandler(int id)
89 if (id == 40) {
90 unsigned keycode = MMIX_IOSPACE[MMIX_IO_KEYBOARD];
91 MMIX_IOSPACE[MMIX_IO_KEYBOARD] = 0;
92 keycode_fifo[fifo_wp++] = keycode;
93 fifo_wp &= FIFO_SIZE - 1;
94 MMIX_IOSPACE[MMIX_IO_S7_0_OUT] = ~fifo_wp;
95 MMIX_IOSPACE[MMIX_IO_S7_1_OUT] = ~fifo_rp;
100 static int kbRelease_on = 0;
101 static int kbExtended_on = 0;
102 static int kbCapsLock_on = 0;
103 static int kbShift_on = 0;
104 static int kbCtrl_on = 0; // XXX Isn't really implemented yet
105 static int kbAlt_on = 0; // XXX Isn't implemented yet
107 unsigned check_keyboard(void)
109 char *translation, ch = 0;
110 if (fifo_rp != fifo_wp) {
112 unsigned keycode = keycode_fifo[fifo_rp++];
113 fifo_rp &= FIFO_SIZE - 1;
115 if(D)mmix_printf("keycode: %8x ", keycode);
117 if (keycode >> 8)
118 if(D)mmix_printf("OVERFLOW: %16x ", keycode);
120 //fb_puthex(2,keycode);
121 //fb_putchar(' ');
123 // Ctrl_R: E0 11 E0 F0 11
124 // Shift: 12 F0 12
125 switch (keycode) {
126 case 0xE0: kbExtended_on = 1; break;
127 case 0xF0: kbRelease_on = 1;
128 // fb_puts("RelOn ");
129 return 0; /* As to not clear extended */
130 case 0x58: kbCapsLock_on ^= !kbRelease_on; break;
131 case 0x12:
132 case 0x59: kbShift_on = !kbRelease_on;
134 fb_puts("Shift ");
135 fb_putchar(" o"[kbShift_on]);
136 fb_putchar(" R"[kbRelease_on]);
137 fb_putchar(' ');
139 break;
141 case 0x11: kbCtrl_on = !kbRelease_on; break;
142 default:
144 fb_putchar('<');
145 fb_puthex(2,keycode);
146 fb_putchar(',');
147 fb_puthex(1,kbRelease_on);
148 fb_putchar(',');
149 fb_puthex(1,kbShift_on);
150 fb_putchar(',');
151 fb_puthex(1,kbExtended_on);
152 fb_putchar('>');
155 translation = keyboard_map[keycode];
157 if (translation && !kbRelease_on) {
158 //fb_putchar(translation[0]);
159 //fb_putchar(" o"[kbShift_on]);
160 //fb_putchar(' ');
162 ch = translation[0];
163 if ((kbCapsLock_on ^ kbShift_on) && translation[1]) {
164 ch = translation[1];
167 break;
170 if (keycode != 0xE0)
171 kbExtended_on = 0;
172 if (keycode != 0xF0)
173 kbRelease_on = 0;
177 if (ch)
178 if(D)mmix_printf("got %d\n", ch);
179 return ch;
182 char read_keyboard(void)
184 char ch;
186 do {
187 ch = check_keyboard();
188 } while (ch == 0);
190 return ch;
194 Key numbers: Tck: 30-50us, Tsu: 5-25us, Thld: 5-25us
197 // <parity> <b7> ... <b0>
198 void send_keyboard(long sh, unsigned data_with_parity)
200 unsigned long i = -1;
202 #define set_data_clk(d,c) ({MMIX_IOSPACE[23] = (0xF & (((c) << 1) | (d)) << sh);})
203 #define get_data() ((MMIX_IOSPACE[23] >> sh) & 1)
204 #define get_clk() ((MMIX_IOSPACE[23] >> (sh+1)) & 1)
206 #define WAIT_UNTIL(cond) \
207 ({ for (;!(cond);) \
208 if (timeout <= now()){\
209 mmix_printf("\nTimed out waiting for " #cond " in line %d ", __LINE__); \
210 mmix_printf("(i == %d)", i); \
211 return; }})
212 #define ms * (FREQUENCY / 1000)
214 unsigned long parity = 1;
215 long timeout;
217 /* The device always generates the clock signal */
219 /* First, Request-to-Send */
221 set_data_clk(1,0); // Communication Inhibited
222 wait_us(100); // Wait at least 100 us
223 set_data_clk(0,0); // Bring the data line low
224 //wait_us(2);
225 set_data_clk(0,1); // Host Request-to-Send (includes start bit)
227 timeout = now() + 15 ms;
229 // Wait for low clock
230 WAIT_UNTIL(get_clk() == 0);
232 timeout = now() + 20 ms;
234 for (i = 1; i <= 8; ++i) {
236 //wait_us(5);
237 set_data_clk(data_with_parity & 1, 1);
238 parity ^= data_with_parity & 1;
239 data_with_parity >>= 1;
241 // Wait for clock to go high
242 WAIT_UNTIL(get_clk() == 1);
243 // Wait for low clock
244 WAIT_UNTIL(get_clk() == 0);
247 // Parity
249 //wait_us(5);
250 set_data_clk(parity, 1);
252 WAIT_UNTIL(get_clk() == 1);
254 set_data_clk(1, 1); // Release the data line (9)
255 // Wait for data low (10)
257 WAIT_UNTIL(get_data() == 0);
258 // Wait for clock low (11)
259 WAIT_UNTIL(get_clk() == 0);
261 // Wait for release (12)
262 WAIT_UNTIL(get_clk() == 1 && get_data() == 1);
264 #if 0
265 if (0)
266 if (((MMIX_IOSPACE[23] >> 1) & 1) != 0) {
267 mmix_printf("Keyboard didn't acknowledge!\n", 0);
268 } else
269 mmix_printf("Done!\n", 0);
271 // Clear out cruft from buffer
272 // MMIX_IOSPACE[MMIX_IO_KEYBOARD] = 0;
273 #endif
276 extern void interruptvector(void);
278 long last;
280 long read_mouse_scancode(void)
282 long timeout = now() + 20 ms;
284 for (; now() < timeout;)
285 if (fifo_rp != fifo_wp) {
286 unsigned keycode = keycode_fifo[fifo_rp++];
287 fifo_rp &= FIFO_SIZE - 1;
288 last = now();
289 // if (keycode & 0xFF00)
290 // mmix_printf("Overflow? %4x ", keycode);
291 return keycode;
293 return -1;
296 long x_pos = 16 * 640 / 2;
297 long y_pos = 16 * 480 / 2;
298 long buttons = 0;
300 int check_mouse(void)
302 long buttons_and_more;
303 long x_delta, y_delta;
305 buttons_and_more = read_mouse_scancode();
306 if (buttons_and_more < 0 || (~buttons_and_more & 8)) {
307 if (buttons_and_more != -1)
308 mmix_printf("dropping <%4x> ", buttons_and_more);
309 return 0;
311 x_delta = read_mouse_scancode();
312 if (x_delta < 0) {
313 //mmix_printf("timeout2 ", 0);
314 return 0;
316 y_delta = read_mouse_scancode();
317 if (y_delta < 0) {
318 //mmix_printf("timeout3 ", 0);
319 return 0;
322 // buttons_and_more =
323 // Yoverflow Xoverflow Ysign Xsign 1 M_B R_B L_B
324 if (buttons_and_more & 0x10) x_delta = x_delta - 256;
325 if (buttons_and_more & 0x20) y_delta = y_delta - 256;
327 x_pos += x_delta;
328 if (x_pos < 0) x_pos = 0;
329 else if (x_pos >= 16 * 640) x_pos = 16 * 640 - 1;
331 y_pos -= y_delta;
332 if (y_pos < 0) y_pos = 0;
333 else if (y_pos >= 16 * 480) x_pos = 16 * 480 - 1;
335 buttons = buttons_and_more & 7;
337 return 1;
340 void undraw(uint64_t x, uint64_t y)
342 static uint32_t * const fb = (uint32_t *) (128 * 1024);
344 if (x < 640 && y < 480)
345 fb[y * 20 + (x >> 5)] &= ~(0x80000000 >> (x & 31));
348 void draw(uint64_t x, uint64_t y)
350 static uint32_t * const fb = (uint32_t *) (128 * 1024);
352 if (x < 640 && y < 480)
353 fb[y * 20 + (x >> 5)] |= 0x80000000 >> (x & 31);
356 void inline xdraw(uint64_t x, uint64_t y)
358 static uint32_t * const fb = (uint32_t *) (128 * 1024);
360 if (x < 640 && y < 480)
361 fb[y * 20 + (x >> 5)] ^= 0x80000000 >> (x & 31);
364 void xdraw_vline(uint64_t x, uint64_t y, int64_t len)
366 static uint32_t * const fb = (uint32_t *) (128 * 1024);
367 uint32_t mask;
368 uint32_t *p;
370 if (640 <= x || 480 <= y || len <= 0)
371 return;
373 if (480 <= y + len)
374 len = 480 - y;
376 p = fb + 20 * y + (x >> 5);
377 mask = 0x80000000 >> (x & 31);
379 switch (len & 3) {
380 case 3: *p ^= mask, p += 20;
381 case 2: *p ^= mask, p += 20;
382 case 1: *p ^= mask, p += 20;
383 case 0: ;
386 len &= ~3;
388 for (; len; len -= 4, p += 80) {
389 p[0] ^= mask;
390 p[20] ^= mask;
391 p[40] ^= mask;
392 p[60] ^= mask;
396 void xdraw_hline(uint64_t x, uint64_t y, int64_t len)
398 static uint64_t * const fb = (uint64_t *) (128 * 1024);
399 uint64_t mask;
400 uint64_t *p, *p_end;
402 if (640 <= x || 480 <= y || len <= 0)
403 return;
405 if (640 <= x + len)
406 len = 640 - x;
407 p = fb + 10 * y + (x >> 6);
409 if ((x & ~63) == ((x + len - 1) & ~63)) {
410 // head & tail (special case for speed)
411 // | __XXX___ |
413 // | __XXXXXX |
414 mask = ~0UL >> (x & 63);
416 // | XXXXX___ |
417 mask &= (1L << 63) >> ((x + len - 1) & 63);
418 *p ^= mask;
419 } else {
420 // head body tail
421 // | ___XXXXX | XXXXXXX | ... | XXXXXX | XXXXX___ |
424 // | __XXXXXX |
425 *p++ ^= ~0UL >> (x & 63);
426 len -= 64 - (x & 63);
427 x += 64 - (x & 63);
429 // | XXXXXX| ... | XXXXXX|
430 p_end = p + (len >> 6);
431 for (; p != p_end;)
432 *p++ ^= ~0UL;
433 x += 64 * (len >> 6);
434 len -= 64 * (len >> 6);
436 // | XXXXX___ |
437 if (len) {
438 mask = (1L << 63) >> ((x + len - 1) & 63);
439 *p++ ^= mask;
447 main()
449 int64_t n, round;
451 fb_clear();
453 for (round = 0; round < 16; ++round) {
454 for (n = 1; n < 256; ++n) {
455 xdraw_hline(128-round,round+128+n,n);
459 mmix_printf("In test keyboard\n", 0);
461 //stdout = 1; // Frame buffer from here on
463 mmix_printf("Hello! Is this thing on? ", 0);
465 #if 1
466 //wait_ms(2000);
467 //mmix_printf("Enabling interrupts ", 0);
469 setInterruptVector((long)interruptvector);
470 setInterval(800);
471 setIntrMask(~0);
472 //wait_ms(2000);
473 #endif
475 // Enable keyboard and mouse (0x00)
476 // Enable input (0x0F)
477 MMIX_IOSPACE[MMIX_IO_KEYBOARD] = 0;
478 MMIX_IOSPACE[23] = 0x0F;
480 y_pos = 0;
481 for (x_pos = 30; x_pos < 600; ++x_pos) {
482 draw(x_pos, y_pos);
483 y_pos += (x_pos & 10) ? 1 : -1;
486 #define check_kbd() ({\
487 if (fifo_rp != fifo_wp) { \
488 unsigned keycode = keycode_fifo[fifo_rp++]; \
489 fifo_rp &= FIFO_SIZE - 1; \
490 mmix_printf("%2x", keycode); }})
492 x_pos = 16 * 640 / 2 ; y_pos = 16 * 480 / 2;
494 xdraw_hline(0, y_pos / 16, 640);
495 xdraw_vline(x_pos / 16, 0, 480);
497 for (;;) {
498 long sw;
499 mmix_printf("\nready> ", 0);
500 do {
501 long old_x = x_pos, old_y = y_pos;
502 sw = get_switches();
503 if (check_mouse()) {
504 if ( x_pos / 16 != old_x / 16
505 || y_pos / 16 != old_y / 16
506 || buttons) {
507 // Remove cursor
508 xdraw_hline(0, old_y / 16, 640);
509 xdraw_vline(old_x / 16, 0, 480);
511 if (buttons & 1)
512 draw(x_pos / 16, y_pos / 16);
513 else if (buttons & 2)
514 undraw(x_pos / 16, y_pos / 16);
516 // Draw cursor
517 xdraw_hline(0, y_pos / 16, 640);
518 xdraw_vline(x_pos / 16, 0, 480);
520 #if 0
521 mmix_printf("(%d,", x_pos);
522 mmix_printf("%d) ", y_pos);
523 if (buttons & 1) mmix_printf("L", 0);
524 if (buttons & 2) mmix_printf("R", 0);
525 if (buttons & 4) mmix_printf("M", 0);
526 mmix_printf(" \r", 0);
527 #endif
529 } while (!sw);
530 while (get_switches())
531 check_kbd();
533 if (sw & 1) {
534 mmix_printf("Sending reset\n", 0);
535 send_keyboard(0, 0xFF);
536 read_mouse_scancode();
537 read_mouse_scancode();
539 send_keyboard(0, 0xFF);
540 read_mouse_scancode();
541 read_mouse_scancode();
543 send_keyboard(0, 0xF3);
544 send_keyboard(0, 200);
546 send_keyboard(0, 0xF3);
547 send_keyboard(0, 100);
549 send_keyboard(0, 0xF3);
550 send_keyboard(0, 50);
552 send_keyboard(0, 0xF2);
553 read_mouse_scancode();
555 send_keyboard(0, 0xF3);
556 send_keyboard(0, 10);
558 send_keyboard(0, 0xE8);
559 send_keyboard(0, 1);
561 send_keyboard(0, 0xE6);
563 send_keyboard(0, 0xF3);
564 send_keyboard(0, 40);
566 send_keyboard(0, 0xF4);
567 } else if (sw & 2) {
568 /* mmix_printf("Flashing LEDs\n", 0);
569 for (sw = 200; --sw;) {
570 send_keyboard(0, 0xED);
571 send_keyboard(0, led);
573 led = (led == 4) ? 1 : led << 1;
574 wait_ms(100);
577 x_pos = 640 / 2;
578 y_pos = 480 / 2;
579 draw(x_pos + 1, y_pos);
580 draw(x_pos - 1, y_pos);
581 draw(x_pos, y_pos + 1);
582 draw(x_pos, y_pos - 1);
583 } else if (sw & 4) {
584 fb_clear();
585 } else if (sw & 8) {
586 mmix_printf("Mouse on\n", 0);
587 send_keyboard(0, 0xF6);
590 #if 0
591 for (;;) {
592 char ch = read_keyboard();
593 if (ch == 't') {
594 mmix_printf("Ok, as you wish. Launching test\n", 0);
596 send_keyboard(0xFF + 0x100); // Reset
597 } else if (ch == 's') {
598 send_keyboard(0xED + 0x100);
599 send_keyboard(0x02 + 0x000);
600 } else if (ch == 'c') {
601 fb_clear();
602 } else if (ch != '\b' || stdout == 0)
603 mmix_putchar(ch);
604 else {
605 fb_gotoxy(fb_io_x-1,fb_io_y);
606 mmix_putchar(' ');
607 fb_gotoxy(fb_io_x-1,fb_io_y);
610 #endif