initial
[fpgammix.git] / workloads / keyboard / draw.c
blobf931ae20d3e9905b41accec270a813682e49d34d
1 #include "stdio.h"
2 #include "fb-io.h"
5 #define RATE 11250
6 #include "../audio/newgame-sound.c"
8 unsigned char *next_sample;
9 unsigned char *stop_sound;
13 // Debugging or not
14 #define D 0
16 // Missing map entries for special keys, like F1..F12, Cursor up, etc.
17 char *keyboard_map[256] = {
18 [0x76] = "\e",
20 // Numeric row
21 [0x0E] = "`~",
22 [0x16] = "1!",
23 [0x1E] = "2@",
24 [0x26] = "3#",
25 [0x25] = "4$",
26 [0x2E] = "5%",
27 [0x36] = "6^",
28 [0x3D] = "7&",
29 [0x3E] = "8*",
30 [0x46] = "9(",
31 [0x45] = "0)",
32 [0x4E] = "-_",
33 [0x55] = "=+",
34 [0x66] = "\b",
36 // Tab row
37 [0x0D] = "\t",
38 [0x15] = "qQ",
39 [0x1D] = "wW",
40 [0x24] = "eE",
41 [0x2D] = "rR",
42 [0x2C] = "tT",
43 [0x35] = "yY",
44 [0x3C] = "uU",
45 [0x43] = "iI",
46 [0x44] = "oO",
47 [0x4D] = "pP",
48 [0x54] = "[{",
49 [0x5B] = "]}",
50 [0x5D] = "\\|",
52 // CapsLock row
53 // 0x58 = CapsLock
54 [0x1c] = "aA",
55 [0x1b] = "sS",
56 [0x23] = "dD",
57 [0x2b] = "fF",
58 [0x34] = "gG",
59 [0x33] = "hH",
60 [0x3b] = "jJ",
61 [0x42] = "kK",
62 [0x4b] = "lL",
63 [0x4c] = ";:",
64 [0x52] = "'\"",
65 [0x5a] = "\n",
68 // Shift row
69 // 0x12 = Shift_L
70 [0x1a] = "zZ",
71 [0x22] = "xX",
72 [0x21] = "cC",
73 [0x2a] = "vV",
74 [0x32] = "bB",
75 [0x31] = "nN",
76 [0x3a] = "mM",
77 [0x41] = ",<",
78 [0x49] = ".>",
79 [0x4a] = "/?",
80 // 0x59 Shift_R
82 // Control row
83 // 0x14 = Ctrl_L
84 // 0x11 = Alt_L
85 [0x29] = " ",
86 // 0xE0 0x11 = Alt_R
87 // 0xE0 0x14 = Ctrl_R
90 /* Keycode fifo */
91 #define FIFO_SIZE 256
92 unsigned char keycode_fifo[FIFO_SIZE], mousecode_fifo[FIFO_SIZE];
93 volatile uint64_t kfifo_wp = 0, kfifo_rp = 0, mfifo_wp = 0, mfifo_rp = 0;
95 void
96 interrupthandler(int id)
98 if (id == 7) {
99 setInterval(FREQUENCY / 11250 - 100);
101 if (next_sample != stop_sound) {
102 DAC_both = *next_sample++ << 8;
104 } else if (id == 40) {
105 unsigned keycode = MMIX_IOSPACE[MMIX_IO_KEYBOARD];
106 MMIX_IOSPACE[MMIX_IO_KEYBOARD] = 0;
107 keycode_fifo[kfifo_wp++] = keycode;
108 kfifo_wp &= FIFO_SIZE - 1;
109 MMIX_IOSPACE[MMIX_IO_S7_0_OUT] = ~kfifo_wp;
110 MMIX_IOSPACE[MMIX_IO_S7_1_OUT] = ~kfifo_rp;
111 } else if (id == 41) {
112 unsigned mousecode = MMIX_IOSPACE[MMIX_IO_MOUSE];
113 MMIX_IOSPACE[MMIX_IO_MOUSE] = 0;
114 mousecode_fifo[mfifo_wp++] = mousecode;
115 mfifo_wp &= FIFO_SIZE - 1;
116 MMIX_IOSPACE[MMIX_IO_S7_0_OUT] = ~mfifo_wp;
117 MMIX_IOSPACE[MMIX_IO_S7_1_OUT] = ~mfifo_rp;
122 static int kbRelease_on = 0;
123 static int kbExtended_on = 0;
124 static int kbCapsLock_on = 0;
125 static int kbShift_on = 0;
126 static int kbCtrl_on = 0; // XXX Isn't really implemented yet
127 static int kbAlt_on = 0; // XXX Isn't implemented yet
129 unsigned check_keyboard(void)
131 char *translation, ch = 0;
132 if (kfifo_rp != kfifo_wp) {
134 unsigned keycode = keycode_fifo[kfifo_rp++];
135 kfifo_rp &= FIFO_SIZE - 1;
137 if(D)mmix_printf("keycode: %8x ", keycode);
139 if (keycode >> 8)
140 if(D)mmix_printf("OVERFLOW: %16x ", keycode);
142 //fb_puthex(2,keycode);
143 //fb_putchar(' ');
145 // Ctrl_R: E0 11 E0 F0 11
146 // Shift: 12 F0 12
147 switch (keycode) {
148 case 0xE0: kbExtended_on = 1; break;
149 case 0xF0: kbRelease_on = 1;
150 // fb_puts("RelOn ");
151 return 0; /* As to not clear extended */
152 case 0x58: kbCapsLock_on ^= !kbRelease_on; break;
153 case 0x12:
154 case 0x59: kbShift_on = !kbRelease_on;
156 fb_puts("Shift ");
157 fb_putchar(" o"[kbShift_on]);
158 fb_putchar(" R"[kbRelease_on]);
159 fb_putchar(' ');
161 break;
163 case 0x11: kbCtrl_on = !kbRelease_on; break;
164 default:
166 fb_putchar('<');
167 fb_puthex(2,keycode);
168 fb_putchar(',');
169 fb_puthex(1,kbRelease_on);
170 fb_putchar(',');
171 fb_puthex(1,kbShift_on);
172 fb_putchar(',');
173 fb_puthex(1,kbExtended_on);
174 fb_putchar('>');
177 translation = keyboard_map[keycode];
179 if (translation && !kbRelease_on) {
180 //fb_putchar(translation[0]);
181 //fb_putchar(" o"[kbShift_on]);
182 //fb_putchar(' ');
184 ch = translation[0];
185 if ((kbCapsLock_on ^ kbShift_on) && translation[1]) {
186 ch = translation[1];
189 break;
192 if (keycode != 0xE0)
193 kbExtended_on = 0;
194 if (keycode != 0xF0)
195 kbRelease_on = 0;
199 if (ch)
200 if(D)mmix_printf("got %d\n", ch);
201 return ch;
204 char read_keyboard(void)
206 char ch;
208 do {
209 ch = check_keyboard();
210 } while (ch == 0);
212 return ch;
216 Key numbers: Tck: 30-50us, Tsu: 5-25us, Thld: 5-25us
219 // <parity> <b7> ... <b0>
220 void send_ps2(unsigned sh, unsigned data_with_parity)
222 unsigned long i = -1;
224 #define set_data_clk(d,c) ({MMIX_IOSPACE[MMIX_IO_PS2_RAW] = 0xF & (((c << 1) | (d)) << sh);})
225 #define get_data() ((MMIX_IOSPACE[MMIX_IO_PS2_RAW] >> sh) & 1)
226 #define get_clk() ((MMIX_IOSPACE[MMIX_IO_PS2_RAW] >> (sh+1)) & 1)
228 #define WAIT_UNTIL(cond) \
229 ({ for (;!(cond);) \
230 if (timeout <= now()){\
231 mmix_printf("\nTimed out waiting for " #cond " in line %d ", __LINE__); \
232 mmix_printf("(i == %d)", i); \
233 return; }})
234 #define ms * (FREQUENCY / 1000)
236 unsigned long parity = 1;
237 long timeout;
239 /* The device always generates the clock signal */
241 /* First, Request-to-Send */
243 set_data_clk(1,0); // Communication Inhibited
244 wait_us(100); // Wait at least 100 us
245 set_data_clk(0,0); // Bring the data line low
246 //wait_us(2);
247 set_data_clk(0,1); // Host Request-to-Send (includes start bit)
249 timeout = now() + 15 ms;
251 // Wait for low clock
252 WAIT_UNTIL(get_clk() == 0);
254 timeout = now() + 20 ms;
256 for (i = 1; i <= 8; ++i) {
258 //wait_us(5);
259 set_data_clk(data_with_parity & 1, 1);
260 parity ^= data_with_parity & 1;
261 data_with_parity >>= 1;
263 // Wait for clock to go high
264 WAIT_UNTIL(get_clk() == 1);
265 // Wait for low clock
266 WAIT_UNTIL(get_clk() == 0);
269 // Parity
271 //wait_us(5);
272 set_data_clk(parity, 1);
274 WAIT_UNTIL(get_clk() == 1);
276 set_data_clk(1, 1); // Release the data line (9)
277 // Wait for data low (10)
279 WAIT_UNTIL(get_data() == 0);
280 // Wait for clock low (11)
281 WAIT_UNTIL(get_clk() == 0);
283 // Wait for release (12)
284 WAIT_UNTIL(get_clk() == 1 && get_data() == 1);
286 #if 0
287 if (0)
288 if (((MMIX_IOSPACE[MMIX_IO_PS2_RAW] >> 1) & 1) != 0) {
289 mmix_printf("Keyboard didn't acknowledge!\n", 0);
290 } else
291 mmix_printf("Done!\n", 0);
293 // Clear out cruft from buffer
294 // MMIX_IOSPACE[MMIX_IO_KEYBOARD] = 0;
295 #endif
298 void send_keyboard(unsigned data) {send_ps2(0, data);}
299 void send_mouse(unsigned data) {send_ps2(2, data);}
301 extern void interruptvector(void);
303 long last;
305 long read_mouse_scancode(long wait)
307 long timeout = now() + wait;
309 for (; now() < timeout;)
310 if (mfifo_rp != mfifo_wp) {
311 unsigned mousecode = mousecode_fifo[mfifo_rp++];
312 mfifo_rp &= FIFO_SIZE - 1;
313 last = now();
314 if (mousecode & 0xFF00)
315 mmix_printf("Overflow? %4x ", mousecode);
316 return mousecode;
318 return -1;
321 long x_pos = 16 * 640 / 2;
322 long y_pos = 16 * 480 / 2;
323 long buttons = 0;
325 int check_mouse(void)
327 long buttons_and_more;
328 long x_delta, y_delta;
330 buttons_and_more = read_mouse_scancode(30 ms);
331 if (buttons_and_more < 0 || (~buttons_and_more & 8)) {
332 if (buttons_and_more != -1)
333 fb_cursor_off(), mmix_printf("dropping <%4x> ", buttons_and_more),
334 fb_cursor_on();
335 return 0;
337 x_delta = read_mouse_scancode(100 ms);
338 if (x_delta < 0) {
339 //mmix_printf("timeout2 ", 0);
340 return 0;
342 y_delta = read_mouse_scancode(100 ms);
343 if (y_delta < 0) {
344 //mmix_printf("timeout3 ", 0);
345 return 0;
348 // buttons_and_more =
349 // Yoverflow Xoverflow Ysign Xsign 1 M_B R_B L_B
350 if (buttons_and_more & 0x10) x_delta = x_delta - 256;
351 if (buttons_and_more & 0x20) y_delta = y_delta - 256;
353 x_pos += x_delta;
354 if (x_pos < 0) x_pos = 0;
355 else if (x_pos >= 16 * 640) x_pos = 16 * 640 - 1;
357 y_pos -= y_delta;
358 if (y_pos < 0) y_pos = 0;
359 else if (y_pos >= 16 * 480) y_pos = 16 * 480 - 1;
361 buttons = buttons_and_more & 7;
363 return 1;
366 void service_keyboard(void)
368 char ch = check_keyboard();
369 if (ch) {
370 fb_cursor_off();
371 if (ch == 8 && fb_io_x) {
372 fb_io_x--;
373 mmix_putchar(' ');
374 fb_io_x--;
375 } else
376 mmix_putchar(ch);
377 fb_cursor_on();
381 void undraw(uint64_t x, uint64_t y)
383 static uint32_t * const fb = (uint32_t *) (128 * 1024);
385 if (x < 640 && y < 480)
386 fb[y * 20 + (x >> 5)] &= ~(0x80000000 >> (x & 31));
389 void draw(uint64_t x, uint64_t y)
391 static uint32_t * const fb = (uint32_t *) (128 * 1024);
393 if (x < 640 && y < 480)
394 fb[y * 20 + (x >> 5)] |= 0x80000000 >> (x & 31);
397 void inline xdraw(uint64_t x, uint64_t y)
399 static uint32_t * const fb = (uint32_t *) (128 * 1024);
401 if (x < 640 && y < 480)
402 fb[y * 20 + (x >> 5)] ^= 0x80000000 >> (x & 31);
405 void xdraw_vline(uint64_t x, uint64_t y, int64_t len)
407 static uint32_t * const fb = (uint32_t *) (128 * 1024);
408 uint32_t mask;
409 uint32_t *p;
411 if (640 <= x || 480 <= y || len <= 0)
412 return;
414 if (480 <= y + len)
415 len = 480 - y;
417 p = fb + 20 * y + (x >> 5);
418 mask = 0x80000000 >> (x & 31);
420 switch (len & 3) {
421 case 3: *p ^= mask, p += 20;
422 case 2: *p ^= mask, p += 20;
423 case 1: *p ^= mask, p += 20;
424 case 0: ;
427 len &= ~3;
429 for (; len; len -= 4, p += 80) {
430 p[0] ^= mask;
431 p[20] ^= mask;
432 p[40] ^= mask;
433 p[60] ^= mask;
437 void xdraw_hline(uint64_t x, uint64_t y, int64_t len)
439 static uint64_t * const fb = (uint64_t *) (128 * 1024);
440 uint64_t mask;
441 uint64_t *p, *p_end;
443 if (640 <= x || 480 <= y || len <= 0)
444 return;
446 if (640 <= x + len)
447 len = 640 - x;
448 p = fb + 10 * y + (x >> 6);
450 if ((x & ~63) == ((x + len - 1) & ~63)) {
451 // head & tail (special case for speed)
452 // | __XXX___ |
454 // | __XXXXXX |
455 mask = ~0UL >> (x & 63);
457 // | XXXXX___ |
458 mask &= (1L << 63) >> ((x + len - 1) & 63);
459 *p ^= mask;
460 } else {
461 // head body tail
462 // | ___XXXXX | XXXXXXX | ... | XXXXXX | XXXXX___ |
465 // | __XXXXXX |
466 *p++ ^= ~0UL >> (x & 63);
467 len -= 64 - (x & 63);
468 x += 64 - (x & 63);
470 // | XXXXXX| ... | XXXXXX|
471 p_end = p + (len >> 6);
472 for (; p != p_end;)
473 *p++ ^= ~0UL;
474 x += 64 * (len >> 6);
475 len -= 64 * (len >> 6);
477 // | XXXXX___ |
478 if (len) {
479 mask = (1L << 63) >> ((x + len - 1) & 63);
480 *p++ ^= mask;
486 void play(unsigned char *sound, unsigned length)
488 next_sample = sound;
489 stop_sound = sound + length;
492 void xdraw_mouse(unsigned long x_pos, unsigned long y_pos)
494 xdraw_hline(x_pos/16-10, y_pos/16, 20);
495 xdraw_vline(x_pos/16, y_pos/16-10, 20);
500 main()
502 int64_t n, round;
504 fb_clear();
506 play(blob, 0);
508 for (round = 0; round < 16; ++round) {
509 for (n = 1; n < 256; ++n) {
510 xdraw_hline(128-round,round+128+n,n);
514 mmix_printf("In test keyboard\n", 0);
516 stdout = 1; // Frame buffer from here on
518 mmix_printf("Hello! Is this thing on? ", 0);
520 #if 1
521 //wait_ms(2000);
522 //mmix_printf("Enabling interrupts ", 0);
524 setInterruptVector((long)interruptvector);
525 setInterval(800);
526 setIntrMask(~0);
527 //wait_ms(2000);
528 #endif
530 play(blob, sizeof(blob));
532 // Enable keyboard and mouse (0x00)
533 // Enable input (0x0F)
534 MMIX_IOSPACE[MMIX_IO_KEYBOARD] = 0;
535 MMIX_IOSPACE[MMIX_IO_MOUSE] = 0;
536 MMIX_IOSPACE[MMIX_IO_PS2_RAW] = 0x0F;
538 y_pos = 0;
539 for (x_pos = 30; x_pos < 600; ++x_pos) {
540 draw(x_pos, y_pos);
541 y_pos += (x_pos & 10) ? 1 : -1;
544 x_pos = 16 * 640 / 2 ; y_pos = 16 * 480 / 2;
546 // xdraw_hline(0, y_pos / 16, 640);
547 // xdraw_vline(x_pos / 16, 0, 480);
549 fb_cursor_on();
551 for (;;) {
552 long sw;
554 xdraw_mouse(x_pos, y_pos);
556 do {
557 long old_x = x_pos, old_y = y_pos;
558 service_keyboard();
559 sw = get_switches();
560 if (check_mouse()) {
561 if ((buttons & 2) && x_pos == 0 && y_pos == 0)
562 play(blob, sizeof(blob));
564 if ( x_pos / 16 != old_x / 16
565 || y_pos / 16 != old_y / 16
566 || buttons) {
567 // Remove cursor
568 xdraw_mouse(old_x, old_y);
570 if (buttons & 1)
571 draw(x_pos/16, y_pos/16);
572 else if (buttons & 2)
573 undraw(x_pos/16, y_pos/16);
575 // Draw cursor
576 xdraw_mouse(x_pos, y_pos);
579 } while (!sw);
581 xdraw_mouse(x_pos, y_pos);
583 while (get_switches());
585 if (sw & 1) {
586 mmix_printf("Sending reset\n", 0);
587 send_mouse(0xFF);
588 read_mouse_scancode(10 ms);
589 read_mouse_scancode(10 ms);
591 send_mouse(0xFF);
592 read_mouse_scancode(10 ms);
593 read_mouse_scancode(10 ms);
595 send_mouse(0xF3);
596 send_mouse(200);
598 send_mouse(0xF3);
599 send_mouse(100);
601 send_mouse(0xF3);
602 send_mouse( 50);
604 send_mouse(0xF2);
605 read_mouse_scancode(10 ms);
607 send_mouse(0xF3);
608 send_mouse( 10);
610 send_mouse(0xE8);
611 send_mouse( 1);
613 send_mouse(0xE6);
615 send_mouse(0xF3);
616 send_mouse(40);
618 send_mouse(0xF4);
619 } else if (sw & 2) {
620 int led = 1;
621 fb_cursor_off();
622 mmix_printf("Flashing LEDs\n", 0);
623 fb_cursor_on();
624 for (sw = 20; --sw;) {
625 cursor_flip();
626 send_keyboard(0xED);
627 send_keyboard(led);
629 led = (led == 4) ? 1 : led << 1;
630 wait_ms(100);
633 x_pos = 640 / 2;
634 y_pos = 480 / 2;
635 draw(x_pos + 1, y_pos);
636 draw(x_pos - 1, y_pos);
637 draw(x_pos, y_pos + 1);
638 draw(x_pos, y_pos - 1);
639 play(blob, sizeof(blob));
640 } else if (sw & 4) {
641 fb_clear();
643 } else if (sw & 8) {
644 fb_cursor_off();
645 mmix_printf("Mouse on\n", 0);
646 fb_cursor_on();
647 send_mouse(0xF6);