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