Wed, 09 Feb 2011 15:03:31 +0000
implement some more of the keyboard controller
src/keyboard.c | file | annotate | diff | revisions | |
src/keyboard.h | file | annotate | diff | revisions | |
src/main.c | file | annotate | diff | revisions | |
src/state.c | file | annotate | diff | revisions | |
src/state.h | file | annotate | diff | revisions |
1.1 diff -r 674226015c8a -r 9581358e92b0 src/keyboard.c 1.2 --- a/src/keyboard.c Wed Dec 29 09:06:17 2010 +0000 1.3 +++ b/src/keyboard.c Wed Feb 09 15:03:31 2011 +0000 1.4 @@ -1,4 +1,6 @@ 1.5 +#include <stdbool.h> 1.6 #include "SDL.h" 1.7 +#include "keyboard.h" 1.8 1.9 /** 1.10 * Key map -- a mapping from SDLK_xxx constants to scancodes and vice versa. 1.11 @@ -126,19 +128,96 @@ 1.12 // { SDLK_, 1, 0x7f }, // Dlete 1.13 }; 1.14 1.15 -/** 1.16 - * List of key states 1.17 - */ 1.18 -int keystate[0x80]; 1.19 - 1.20 -void keyboard_init(void) 1.21 +void keyboard_init(KEYBOARD_STATE *ks) 1.22 { 1.23 // Set all key states to "not pressed" 1.24 - for (int i=0; i<(sizeof(keystate)/sizeof(keystate[0])); i++) { 1.25 - keystate[i] = 0; 1.26 + for (int i=0; i<(sizeof(ks->keystate)/sizeof(ks->keystate[0])); i++) { 1.27 + ks->keystate[i] = 0; 1.28 + } 1.29 + 1.30 + // Reset the R/W pointers and length 1.31 + ks->readp = ks->writep = ks->buflen = 0; 1.32 +} 1.33 + 1.34 +void keyboard_event(KEYBOARD_STATE *ks, SDL_Event *ev) 1.35 +{ 1.36 + // event handler -- handles SDL events 1.37 +} 1.38 + 1.39 +void keyboard_scan(KEYBOARD_STATE *ks) 1.40 +{ 1.41 + // if buffer empty, do a keyboard scan 1.42 + if (ks->buflen == 0) { 1.43 + for (int i=0; i<(sizeof(ks->keystate)/sizeof(ks->keystate[0])); i++) { 1.44 + if (ks->keystate[i]) { 1.45 + ks->buffer[ks->writep] = i; 1.46 + ks->writep = (ks->writep + 1) % KEYBOARD_BUFFER_SIZE; 1.47 + } 1.48 + } 1.49 } 1.50 } 1.51 1.52 -void keyboard_event(SDL_Event *ev) 1.53 +bool keyboard_get_irq(KEYBOARD_STATE *ks) 1.54 +{ 1.55 + bool irq_status = false; 1.56 + 1.57 + // Conditions which may cause an IRQ :- 1.58 + // Read Data Reg has data and RxIRQ enabled 1.59 + if (ks->rxie) 1.60 + if (ks->buflen > 0) irq_status = true; 1.61 + 1.62 + // Transmit Data Reg empty and TxIRQ enabled 1.63 +// if (ks->txie) 1.64 + 1.65 + // DCD set and RxIRQ enabled 1.66 +// 1.67 + 1.68 + // returns interrupt status -- i.e. is there data in the buffer? 1.69 + return irq_status; 1.70 +} 1.71 + 1.72 +uint8_t keyboard_read(KEYBOARD_STATE *ks, uint8_t addr) 1.73 { 1.74 + if ((addr & 1) == 0) { 1.75 + // Status register -- RS=0, read 1.76 + return 1.77 + (ks->buflen > 0) ? 1 : 0 + // SR0: a new character has been received 1.78 + 0 + // SR1: Transmitter Data Register Empty 1.79 + 0 + // SR2: Data Carrier Detect 1.80 + 0 + // SR3: Clear To Send 1.81 + 0 + // SR4: Framing Error 1.82 + 0 + // SR5: Receiver Overrun 1.83 + 0 + // SR6: Parity Error 1.84 + (keyboard_get_irq(ks)) ? 0x80 : 0; // SR7: IRQ status 1.85 + } else { 1.86 + // return data, pop off the fifo 1.87 + uint8_t x = ks->buffer[ks->readp]; 1.88 + ks->readp = (ks->readp + 1) % KEYBOARD_BUFFER_SIZE; 1.89 + return x; 1.90 + } 1.91 } 1.92 + 1.93 +void keyboard_write(KEYBOARD_STATE *ks, uint8_t addr, uint8_t val) 1.94 +{ 1.95 + if ((addr & 1) == 0) { 1.96 + // write to control register 1.97 + // transmit intr enabled when CR6,5 = 01 1.98 + // receive intr enabled when CR7 = 1 1.99 + 1.100 + // CR0,1 = divider registers. When =11, do a software reset 1.101 + if ((val & 3) == 3) { 1.102 + ks->readp = ks->writep = ks->buflen = 0; 1.103 + } 1.104 + 1.105 + // Ignore CR2,3,4 (word length)... 1.106 + 1.107 + // CR5,6 = Transmit Mode 1.108 + ks->txie = (val & 0x60)==0x20; 1.109 + 1.110 + // CR7 = Receive Interrupt Enable 1.111 + ks->rxie = (val & 0x80)==0x80; 1.112 + } else { 1.113 + // Write command to KBC -- TODO! 1.114 + } 1.115 +} 1.116 +
2.1 diff -r 674226015c8a -r 9581358e92b0 src/keyboard.h 2.2 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.3 +++ b/src/keyboard.h Wed Feb 09 15:03:31 2011 +0000 2.4 @@ -0,0 +1,56 @@ 2.5 +#ifndef _KEYBOARD_H 2.6 +#define _KEYBOARD_H 2.7 + 2.8 +#include "SDL.h" 2.9 + 2.10 +/// Keyboard buffer size in bytes 2.11 +#define KEYBOARD_BUFFER_SIZE 256 2.12 + 2.13 +typedef struct { 2.14 + /// Key states 2.15 + int keystate[0x80]; 2.16 + 2.17 + /// Keyboard buffer 2.18 + char buffer[KEYBOARD_BUFFER_SIZE]; 2.19 + 2.20 + /// Read pointer 2.21 + size_t readp; 2.22 + 2.23 + /// Write pointer 2.24 + size_t writep; 2.25 + 2.26 + /// Number of bytes in keyboard buffer 2.27 + size_t buflen; 2.28 + 2.29 + /// Transmit Interrupt Enable 2.30 + bool txie; 2.31 + /// Receive Interrupt Enable 2.32 + bool rxie; 2.33 +} KEYBOARD_STATE; 2.34 + 2.35 +/** 2.36 + * Initialise a keyboard state block. 2.37 + * 2.38 + * Call this once when the keyboard is added to the emulation. 2.39 + */ 2.40 +void keyboard_init(KEYBOARD_STATE *ks); 2.41 + 2.42 +/** 2.43 + * SDL_Event delegation routine. 2.44 + * 2.45 + * Call this when an SDL keyup or keydown event is received. 2.46 + */ 2.47 +void keyboard_event(KEYBOARD_STATE *ks, SDL_Event *ev); 2.48 + 2.49 +/** 2.50 + * Keyboard scan routine. 2.51 + * 2.52 + * Call this periodically to scan the keyboard. 60 times/sec should be fine. 2.53 + */ 2.54 +void keyboard_scan(KEYBOARD_STATE *ks); 2.55 + 2.56 +bool keyboard_get_irq(KEYBOARD_STATE *ks); 2.57 +uint8_t keyboard_read(KEYBOARD_STATE *ks, uint8_t addr); 2.58 +void keyboard_write(KEYBOARD_STATE *ks, uint8_t addr, uint8_t val); 2.59 + 2.60 +#endif
3.1 diff -r 674226015c8a -r 9581358e92b0 src/main.c 3.2 --- a/src/main.c Wed Dec 29 09:06:17 2010 +0000 3.3 +++ b/src/main.c Wed Feb 09 15:03:31 2011 +0000 3.4 @@ -123,6 +123,10 @@ 3.5 SDL_Event event; 3.6 while (SDL_PollEvent(&event)) 3.7 { 3.8 + if ((event.type == SDL_KEYDOWN) || (event.type == SDL_KEYUP)) { 3.9 + keyboard_event(&state.kbd, &event); 3.10 + } 3.11 + 3.12 switch (event.type) { 3.13 case SDL_QUIT: 3.14 // Quit button tagged. Exit. 3.15 @@ -341,6 +345,8 @@ 3.16 // Refresh the screen 3.17 refreshScreen(screen); 3.18 // TODO: trigger periodic interrupt (if enabled) 3.19 + // scan the keyboard 3.20 + keyboard_scan(&state.kbd); 3.21 // decrement clock cycle counter, we've handled the intr. 3.22 clock_cycles -= CLOCKS_PER_60HZ; 3.23 }
4.1 diff -r 674226015c8a -r 9581358e92b0 src/state.c 4.2 --- a/src/state.c Wed Dec 29 09:06:17 2010 +0000 4.3 +++ b/src/state.c Wed Feb 09 15:03:31 2011 +0000 4.4 @@ -3,6 +3,7 @@ 4.5 #include <malloc.h> 4.6 #include <stdio.h> 4.7 #include "wd279x.h" 4.8 +#include "keyboard.h" 4.9 #include "state.h" 4.10 4.11 int state_init(size_t base_ram_size, size_t exp_ram_size) 4.12 @@ -92,6 +93,8 @@ 4.13 4.14 // Initialise the disc controller 4.15 wd2797_init(&state.fdc_ctx); 4.16 + // Initialise the keyboard controller 4.17 + keyboard_init(&state.kbd); 4.18 4.19 return 0; 4.20 }
5.1 diff -r 674226015c8a -r 9581358e92b0 src/state.h 5.2 --- a/src/state.h Wed Dec 29 09:06:17 2010 +0000 5.3 +++ b/src/state.h Wed Feb 09 15:03:31 2011 +0000 5.4 @@ -5,6 +5,7 @@ 5.5 #include <stdint.h> 5.6 #include <stdbool.h> 5.7 #include "wd279x.h" 5.8 +#include "keyboard.h" 5.9 5.10 // Maximum size of the Boot PROMs. Must be a binary power of two. 5.11 #define ROM_SIZE 32768 5.12 @@ -70,6 +71,9 @@ 5.13 5.14 /// Floppy disc controller context 5.15 WD2797_CTX fdc_ctx; 5.16 + 5.17 + /// Keyboard controller context 5.18 + KEYBOARD_STATE kbd; 5.19 } S_state; 5.20 5.21 // Global emulator state. Yes, I know global variables are evil, please don't