implement some more of the keyboard controller

Wed, 09 Feb 2011 15:03:31 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Wed, 09 Feb 2011 15:03:31 +0000
changeset 80
9581358e92b0
parent 79
674226015c8a
child 81
6484b646bc31

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